Home Vimlike Better Player Geek Browser One Dictionary

Vimlike

iPadOS 18.0 Safari has an issue that the focus does not move to the webpage when the tab is created or activated until the webpage gets the focus manually by the webpage touched / clicked, one of the arrow keys (up, down, left, or right) pressed, or tab key pressed.

Hence, shortcuts in websites using keyboard events of the webpage do not work (e.g. gmail shortcuts do not work). As Vimlike uses keyboard events of the webpage, Vimlike only works once the webpage gets the focus manually by the webpage touched / clicked, one of the arrow keys (up, down, left, or right) pressed, or tab key pressed as a workaround.

iPadOS 18.1 beta 4 has resolved the problem and Vimlike works fine.

Vimlike works fine with MacOS 15 Sequoia.

Introduction

VIMlike is Safari extension for the Vim-like keyboard experience. You can navigate a page and open a link with the keyboard shortcuts.

Screen Shot

Downloads

The latest version of Vimlike is available in AppStore:

Version History

v1.5.0

3 Aug 2024

v1.4.9

18 Mar 2024

v1.4.8

16 Mar 2024

v1.4.7

4 Mar 2024

v1.4.6

15 Jan 2024

v1.4.5

9 Jan 2024

v1.4.4

1 Oct 2023

v1.4.3

10 Sep 2023

v1.4.2

20 Jun 2023

v1.4.1

17 May 2023

v1.4.0

20 Nov 2022

v1.3.5

1 Nov 2022

v1.3.4

26 Sep 2022

v1.3.3

13 Sep 2022

v1.3.1

16 Aug 2022

v1.3.0

15 Aug 2022

v1.2.4

17 Jul 2022

v1.2.3

17 Jul 2022 • New command: ‘y y’ to copy the URL and ‘y t’ to duplicate the tab • Enhanced smooth scroll

v1.2.2

10 Jul 2022

v1.2.1

19 Jun 2022

v1.2.0

28 May 2022

v1.1.5

3 Feb 2022

v1.1.4

26 Dec 2021

v1.1.3

12 Dec 2021

v1.1.1

10 Oct 2021

v1.0

4 Oct 2021

Privacy Policy

Vimlike does NOT collect any of your data. The only data Vimlike stores are your settings. These are only saved locally. No one, other than you, has access to this data.

Because of the way Vimlike works, the Vimlike extension needs to have permission to access to the website. This is needed because Vimlike has to add javascript to manage keyboard shortcuts and links to the web page. However, Vimlike never use these permissions to actually read the websites you visit, or to access your browsing history.

Vimlike does not store any information about the websites you’re visiting. Not even locally on your device.

In Safari Preference, you can Allow or Deny the extensions to specific websites. In case you want to be extra cautious to certain websites, you can enable or disable Vimlike to the specific websites only.

Key Bindings

Cheatsheet (Default)

Screen Shot

Key Command
k Scroll up
j Scroll down
h Scroll left
l Scroll right
u Half page up
d Half page down
g g Go to top of page
shift + g Go to bottom of page
f Toggle links
shift + f Toggle links (open a link in a new tab)
tab or n Toggle links / Move to next link or search result
shift + tab or shift + n Toggle links / Move to previous link or search result
esc or ` or
§ (configurable in Settings)
Back to Normal mode
shift + h Go back
shift + l Go forward
q Previous tab
w Next tab
t New tab
x Close tab
shift + z Reopen closed tab
y y Copy current URL to the clipboard
y t Duplicate current tab
r Reload tab
/ Search links
i Go to the first edit box
g 1g 9 Go to tab 1…9
g shift+4 Go to the last tab
shift + / Toggle shortcut help
a opening the link below the cursor
s opening the link below the cursor in a new tab
shift + r Reader mode
o Open Search Bar

Cheatsheet (+Control)

Screen Shot

Key Command
control + f Scroll up a page
control + b Scroll down a page
control + j Previous tab
control + k Next tab
control + i Insert mode (Shortcuts are disabled)
control + d Toggle dark mode
control + u Play video in a fullscreen
control + p Play video in a PIP (picture-in-picture)

Vimlike supports navigating the web pages with the keyboard. When you type tab or n, Vimlike shows link tags. You can type tab / n, or shift + tab / shift + n to move the focus to the next link or the previous link. And you press enter to open the link. Otherwise, type the tag code or number to open the link directly.

Shortcut / opens the console to type the text and find matching links. You can also type tab / n, or shift + tab / shift + n to move the focus to the next matching link or the previous matching link.

Screen Shot

Customization

Vimlike supports customizing the mapping of the keyboard shortcuts in Vimlike app. Please refer Customization Guide for details.

settings.map(key, COMMAND);
settings.map(key, COMMAND, {includes: url}); // mapping the key only for the url
settings.map(key, COMMAND, {excludes: url}); // mapping the key excluding the url

The parameter url can be array of strings and regular expressions. For example,

settings.map('space', VLCommand.HALF_PAGE_DOWN, {excludes: ['https://www.youtube.com/watch', 'https://www.netflix.com/watch/']});
settings.map('space', VLCommand.HALF_PAGE_DOWN, {includes: [/www\.google\.co.*\/search\?/g]});

Default Key Mapping

Following script is the default key mapping.

// Scroll
settings.map('j', VLCommand.SCROLL_DOWN);
settings.map('k', VLCommand.SCROLL_UP);
settings.map('h', VLCommand.SCROLL_LEFT);
settings.map('l', VLCommand.SCROLL_RIGHT);
settings.map('d', VLCommand.HALF_PAGE_DOWN);
settings.map('u', VLCommand.HALF_PAGE_UP);
settings.map('space', VLCommand.HALF_PAGE_DOWN, {excludes: ['https://www.youtube.com/watch', 'https://www.netflix.com/watch/']});
settings.map('shift+space', VLCommand.HALF_PAGE_UP);
settings.map('ctrl+f', VLCommand.PAGE_DOWN);
settings.map('ctrl+b', VLCommand.PAGE_UP);
//settings.map('g', VLCommand.SCROLL_TO_TOP); // deprecated
settings.map('g g', VLCommand.SCROLL_TO_TOP);
settings.map('shift+g', VLCommand.SCROLL_TO_BOTTOM);

// Normal mode
settings.map('f', VLCommand.ACTIVATE_LINK);
settings.map('shift+f', VLCommand.ACTIVATE_LINK_WITH_NEW_TAB);
settings.map('n', VLCommand.NEXT_LINK);
settings.map('shift+n', VLCommand.PREV_LINK);
settings.map('tab', VLCommand.NEXT_LINK);
settings.map('shift+tab', VLCommand.PREV_LINK);
settings.map('shift+h', VLCommand.GO_BACK);
settings.map('shift+l', VLCommand.GO_FORWARD);
settings.map('q', VLCommand.PREV_TAB);
settings.map('w', VLCommand.NEXT_TAB);
settings.map('ctrl+j', VLCommand.PREV_TAB);
settings.map('g shift+t', VLCommand.PREV_TAB);
settings.map('ctrl+k', VLCommand.NEXT_TAB);
settings.map('g t', VLCommand.NEXT_TAB);
settings.map('t', VLCommand.NEW_TAB);
settings.map('i', VLCommand.FOCUS_INPUT);
settings.map('slash', VLCommand.SHOW_CONSOLE);
settings.map('ctrl+i', VLCommand.INSERT_MODE);
settings.map('g 1', VLCommand.OPEN_TAB1);
settings.map('g 2', VLCommand.OPEN_TAB2);
settings.map('g 3', VLCommand.OPEN_TAB3);
settings.map('g 4', VLCommand.OPEN_TAB4);
settings.map('g 5', VLCommand.OPEN_TAB5);
settings.map('g 6', VLCommand.OPEN_TAB6);
settings.map('g 7', VLCommand.OPEN_TAB7);
settings.map('g 8', VLCommand.OPEN_TAB8);
settings.map('g 9', VLCommand.OPEN_TAB9);
settings.map('g shift+4', VLCommand.OPEN_LAST_TAB);
settings.map('g 0', VLCommand.OPEN_TAB1);
settings.map('x', VLCommand.CLOSE_TAB);
settings.map('ctrl+u', VLCommand.VIDEO_FULLSCREEN);
settings.map('ctrl+p', VLCommand.VIDEO_PIP);
settings.map('ctrl+d', VLCommand.DARK_MODE);
settings.map('r', VLCommand.RELOAD);
settings.map('?', VLCommand.TOGGLE_HELP);
settings.map('shift+slash', VLCommand.TOGGLE_HELP);
settings.map('/', VLCommand.SHOW_CONSOLE);
settings.map('y y', VLCommand.COPY_CURRENT_URL);
settings.map('y t', VLCommand.DUPLICATE_TAB);

Commands

ID Command
VLCommand.SCROLL_UP Scroll up
VLCommand.SCROLL_DOWN Scroll down
VLCommand.SCROLL_LEFT Scroll left
VLCommand.SCROLL_RIGHT Scroll right
VLCommand.HALF_PAGE_DOWN Half page up
VLCommand.HALF_PAGE_UP Half page down
VLCommand.SCROLL_TO_TOP Go to top of page
VLCommand.SCROLL_TO_BOTTOM Go to bottom of page
VLCommand.PAGE_UP Scroll up a page
VLCommand.PAGE_DOWN Scroll down a page
VLCommand.FOCUS_INPUT Go to the first edit box
VLCommand.NORMAL_MODE Normal mode
VLCommand.INSERT_MODE Insert mode (shortcuts are disabled)
VLCommand.TOGGLE_HELP Toggle shortcut help
VLCommand.DARK_MODE Toggle dark mode
VLCommand.GO_BACK Go back
VLCommand.GO_FORWARD Go forward
VLCommand.ACTIVATE_LINK Toggle links
VLCommand.ACTIVATE_LINK_WITH_NEW_TAB Activate link hints (open in a new tab)
VLCommand.NEXT_LINK Move to next link
VLCommand.PREV_LINK Move to previous link
VLCommand.SHOW_CONSOLE Search links
VLCommand.OPEN_SELECTED_LINK Open link
VLCommand.OPEN_SELECTED_LINK_IN_NEW_TAB Open link in a new tab
VLCommand.NEW_TAB New tab
VLCommand.PREV_TAB Previous tab
VLCommand.NEXT_TAB Next tab
VLCommand.CLOSE_TAB Close tab
VLCommand.OPEN_TAB1 Open tab 1
VLCommand.OPEN_TAB2 Open tab 2
VLCommand.OPEN_TAB3 Open tab 3
VLCommand.OPEN_TAB4 Open tab 4
VLCommand.OPEN_TAB5 Open tab 5
VLCommand.OPEN_TAB6 Open tab 6
VLCommand.OPEN_TAB7 Open tab 7
VLCommand.OPEN_TAB8 Open tab 8
VLCommand.OPEN_TAB9 Open tab 9
VLCommand.VIDEO_FULLSCREEN Play video in a fullscreen
VLCommand.VIDEO_PIP Play video in a PIP (picture-in-picture)
VLCommand.RELOAD Reload
VLCommand.COPY_CURRENT_URL Copy current URL to the clipboard
VLCommand.DUPLICATE_TAB Duplicate current tab

Keys

Vimlike uses Javascript KeyboardEvent.code for the keyboard command. Following table shows codes for the special keys.

Key Code
tab Tab
space Space
page up PageUp
page down PageDown
end End
home Home
ArrowLeft
ArrowUp
ArrowRight
ArrowDown
print screen PrintScreen
insert Insert
delete Delete
; Semicolon
= Equal
, Comma
- Minus
. Period
/ Slash
` Backquote
[ BracketLeft
\ Backslash
] BracketRight
' Quote

KeyboardEvent.code uses the key based on the QWERTY layout. Therefore, key bindings of some of the latin keyboards are different. For example, the code “z” represents for the Z key on a QWERTY layout keyboard, but the same code value also represents the Y key on German keyboards.

Website Specific Key Bindings and Script

Vimlike version 1.3.0 or above supports custom key binding and custom script for a specific website.

Examples

google.com

settings.map('bracketleft', function(vimlike) {
    vimlike.click('//a[@id="pnprev"]');
});

settings.map('bracketright', function(vimlike) {
    vimlike.click('//a[@id="pnnext"]');
});

youtube.com

// www.youtube.com
let watchUrls = ['https://www.youtube.com/watch', 'https://m.youtube.com/watch'];

// Go to Home
settings.map('g h', function(vimlike) {
    window.open("https://www.youtube.com", "_self");
});

// Go to Explorer
settings.map('g e', function(vimlike) {
    window.open("https://www.youtube.com/feed/explore", "_self");
});

// Go to Shorts
settings.map('g o', function(vimlike) {
    window.open("https://www.youtube.com/shorts", "_self");
});

// Go to Subscription
settings.map('g s', function(vimlike) {
    window.open("https://www.youtube.com/feed/subscriptions", "_self");
});

// Next track
settings.map('bracketright', function(vimlike) {
    let button = document.querySelector('a.ytp-next-button');
    
    if (button != null) {
        button.click();
    }
}, {includes: watchUrls});

// Skip ad
settings.map('s', function(vimlike) {
    if (document.querySelector('.ad-showing')) {
        const video = document.querySelector('video');
        if (video && video.duration) {
            video.currentTime = video.duration;
        }
    }

    const skip = document.querySelector('button.ytp-ad-skip-button');
    if (skip) {
        skip.click();
    }
    
    const close = document.querySelector('button.ytp-ad-overlay-close-button');
    if (close) {
        close.click();
    }
}, {includes: watchUrls});

settings.unmap('space');

instagram.com


// Go to Home
settings.map('g h', function(vimlike) {
    window.open("https://www.instagram.com", "_self");
});

// Go to Inbox
settings.map('g i', function(vimlike) {
    window.open("https://www.instagram.com/direct/inbox/", "_self");
});

// Go to Explorer
settings.map('g e', function(vimlike) {
    window.open("https://www.instagram.com/explore/", "_self");
});

// Close
settings.map('backslash', function(vimlike) {
    vimlike.click('//div[div/*[local-name()="svg" and @aria-label="Close"]]');
});

// Next
settings.map('bracketright', function(vimlike) {
    vimlike.click('//button[div/span/*[local-name()="svg" and @aria-label="Next"]]');
});

// Prev
settings.map('bracketleft', function(vimlike) {
    vimlike.click('//button[div/span/*[local-name()="svg" and @aria-label="Go back"]]');
});

amazon.com

// Go to next page
settings.map('bracketright', function(vimlike) {
    vimlike.click('//a[contains(@aria-label, "Go to next page")]');
});

// Go to previous page
settings.map('bracketleft', function(vimlike) {
    vimlike.click('//a[contains(@aria-label, "Go to previous page")]');
});