Surfingkeys is another Chrome/Firefox extension that provides keyboard-based navigation and control of the web in the spirit of the VIM editor. But it's not for VIM users only, it's for anyone who just needs some more shortcuts to his own functions.
Surfingkeys is created with all settings described in Javascript, so it's easy for anyone to map any keystrokes to his own defined Javascript function. For example,
mapkey('<Ctrl-y>', 'Show me the money', function() {
Front.showPopup('a well-known phrase uttered by characters in the 1996 film Jerry Maguire (Escape to close).');
});
Surfingkeys works for Firefox(above 57) since 0.9.15, with below features as exceptions:
- Sync settings across devices for same account
- Proxy settings
- Markdown preview
Reference for editing your own settings.
- Feature list
- Quick start
- Follow links
- Surfingkeys modes
- Omnibar
- Search selected with
- Vim-like marks
- Switch tabs
- Commands
- Smooth scroll
- Session management
- Repeats action by pressing number before mapkey
- Hotkey to toggle Surfingkeys
- Proxy settings
- VIM editor
- Dot to repeat previous action
- Markdown preview
- Capture page
- Mermaid diagram generator
- PDF viewer
- Edit your own settings
- License
- All settings are set up within a javascript file, which makes it easy to create mapping to user customized function.
- A large cursor in visual mode, which makes visual mode better.
- Search selected with, which works in both normal mode and visual mode.
- Help messages are automatically generated for mappings.
*
to search word under cursor in visual mode.- Scroll actions like page up/down (
e
d
) work for not only top window but also scrollable DIV. w
to switch frames if there is.- Session management
- A versatile bookmark/url finder
- Count prefixes to repeat actions
- Use vim editor to edit input on page
- Dot to repeat previous action
sm
to preview markdown<Ctrl-Alt-d>
to open diagram tool- Emoji completion in insert mode
- Rich hints for keystroke
- Everything in Surfingkeys works for PDF
After you install the extension from Chrome Web Store or Firefox Add-ons, open a site you'd like. Then press ?
or u
to take a quick look on the default mappings first. Press Esc
to hide the usage popover.
Try some mappings described in the usage popover. For example, press e
to scroll a page up, d
to scroll a page down, se
to open settings page.
?
to show helpt
to search bookmarks/history/
to find in current pagef
to follow linksv
to toggle visual modeT
to switch tabs
Default hint characters for links are asdfgqwertzxcvb
, it quits when a non-hint key is pressed. Add below line to your settings to make it right hand:
Hints.characters = 'yuiophjklnm'; // for right hand
When hints are overlapped, press Shift
to flip them. Hold space
to hold hints temporarily, release space
to restore hints.
Hints are placed in center of target links, you could add below line in your settings to let them aligned left.
settings.hintAlign = "left";
There are three modes in Surfingkeys: normal, visual and insert.
When you open a page, it enters normal mode automatically. All mappings added with mapkey
work in this mode.
Press v
to toggle visual mode. You'll see an indicator at bottom of current page - Caret
or Range
, and a large cursor on page. The cursor is made large for visibility, as sometimes it's not easy for human to locate a normal cursor on a web page.
Caret
indicates that cursor is moved when you press jkhl, Range
indicates that you'll select text when moving cursor.
Now here is a small practice,
- press
v
you'll seeCaret
- use the VIM key bindings to move cursor to some where.
- press
v
again, you'll seeRange
. - use the VIM key bindings to select some text.
- press
sg
to see what will happen. - press
v
again to back to normal mode.
All mappings added with vmapkey
work in this mode, with some built-in mappings like those in VIM - j
k
h
l
b
w``0
$
etc.
zz
make cursor at center of window.f
forward to next char.F
backward to next char.;
repeat latest f, F.,
repeat latest f, F in opposite direction.
When focus is switched into any editable element by whatever means(i
hints or f
hints or mouse click), Insert mode is on.
All mappings added with imapkey
work in this mode.
Ctrl - i
to open vim editor to edit.Ctrl - '
to toggle quotes in an input element, this is useful for search engines like google.Ctrl-e
move the cursor to the end of the line.Ctrl-f
move the cursor to the beginning of the line.Ctrl-u
delete all entered characters before the cursor.Alt-b
move the cursor Backward 1 word.Alt-f
move the cursor Forward 1 word.Alt-w
delete a word backwards.Alt-d
delete a word forwards.
imap
and iunmap
for insert mode.
imap(',,', "<Esc>"); // press comma twice to leave current input box.
imap(';;', "<Ctrl-'>"); // press semicolon twice to toggle quote.
When user inputs a colon and 2(set by settings.startToShowEmoji
) characters such as :gr
in insert mode, Surfingkeys will try to find matched emoji, and list them out if there are some found.
If you want this feature disabled completely, use below settings:
iunmap(":");
If you'd like emoji suggestions popup as soon as you input colon, use below:
settings.startToShowEmoji = 0;
Find
is not actually a mode, it just another way to enter visual mode. Press /
to open find bar, which sits at almost the same position with Mode indicator, type something there. All occurrences of your input will be highlighted. Press Enter
to finish the finding, and you're in Caret
visual mode now, press n
to find next, N
to find previous.
Press Ctrl-Enter
to find exactly the whole word input, like with the input \bkeyword\b
.
The omnibar provides kinds of functions that need user input, for example,
- Open url(from both bookmarks and history) with
t
- Open bookmarks with
b
- Open search engines with
og
/ow
... - Open commands with
:
Enter
to open selected item and close omnibar.Ctrl-Enter
to open selected item, but keep omnibar open for more items to be opened.Shift-Enter
to open selected item in current tab and close omnibar. If you'd like to open in current tab by default, please usego
.Tab
to forward cycle through the candidates.Shift-Tab
to backward cycle through the candidates.Ctrl-.
to show results of next pageCtrl-,
to show results of previous pageCtrl-c
to copy all listed items
In omnibar opened with t
:
Ctrl - d
to delete from bookmark or history
In omnibar opened with b
:
Ctrl - Shift - <any letter>
to create vim-like global mark
cmap
could be used for Omnibar to change mappings, for example:
cmap('<Ctrl-n>', '<Tab>');
cmap('<Ctrl-p>', '<Shift-Tab>');
My favorite feature from when I was using Firefox. For both Firefox and Chrome, the extensions make it through context menu. Surfingkeys makes it through key mappings. By default, when you press sg
in normal mode, it will search selected text with google, if there is none selected, it will search text from system clipboard with google. In visual mode, it will search selected text with google.
The g
in sg
is a search alias for google, there are some other built-in search aliases -- like w
for bing. So press sw
to search selected with bing. Refer to Add search alias to omnibar to add your own search alias, especially those search engines for company inside.
Besides that, there is a sog
, to search selected text only in this site with google. For sog
, s
is the search_leader_key, o
is the only_this_site_key, g
is the search alias.
The search_leader_key s
plus captial alias G
will search selected with google interactively, all other search aliases and those you added through API addSearchAliasX
work in same way.
You can create vim-like marks by pressing m
, followed by a word character(a-z for local marks, others like 0-9 / A-Z for global marks), used as mark name. For example, if you press ma
on this page, you'll create a mark named a
which points to this page. Then pressing 'a
anywhere, you'll jump to this page.
In this way, the created mark always points to current URL. You can also create vim-like marks from the bookmarks. Try following steps:
- press
b
to open bookmarks. - type something to locate the URL you'd like to create vim-like mark for.
- press Ctrl, plus a mark name, such as
f
.
Then afterwards 'F
will open that URL directly.
This is very useful for those pages you access very frequently. om
to check out all the vim-like marks you have created.
By default, pressing T
will show all opened tabs in an overlay, then pressing the hint char, will switch to the related tab.
There is settings.tabsThreshold
here. When total of opened tabs exceeds settings.tabsThreshold
(default as 9), omnibar will be used for choosing tabs.
If you prefer to use omnibar always, use below mapping:
mapkey('<Space>', 'Choose a tab with omnibar', function() {
Front.openOmnibar({type: "Tabs"});
});
which works same as:
settings.tabsThreshold = 0;
The tabs are displayed in MRU order by default, either in omnibar or overlay. If you want them in natural order, use:
settings.tabsMRUOrder = false;
:
to open omnibar for commands, then you can execute any pre-defined there. The result will be displayed below the omnibar.
// create shortcuts for the command with different parameters
map('spa', ':setProxyMode always');
map('spb', ':setProxyMode byhost');
map('spd', ':setProxyMode direct');
Besides commands, you can also run javascript code.
Smooth scroll works for any scrollable element. It is on by defualt, to turn it off as below:
settings.smoothScroll = false;
j
/k
scrolls in one step with size as 70, you could change it as below:
settings.scrollStepSize = 140;
To create session in Chrome with Surfingkeys will save URLs for all tabs, and to open a session will open all the URLs of the session in different tab, so basically a session is a list of URLs, which has a name.
ZZ
will save all current tabs into a session namedLAST
then quit.ZR
will restore the session namedLAST
.ZQ
will just quit.
You can create multiple sessions with different names in command mode. Press :
to open omnibar for commands, then input:
createSession works
Surfingkeys will create a session named works
for you, to open the session with command input as:
openSession works
To list all your saved sessions:
listSession
To delete a session:
deleteSession works
If you need repeat some action several times, just press a number before mapkey, such as 3d
, which will scroll down 3 pages. Repeats also works for Tab navigation, for example, you're now on the 1st Tab, and you want to switch to the 4th Tab,
- press
3R
to achieve that 3E
will switch back to 1st Tab.
Another example to move one Tab, say, you're on the 12th Tab of 23 tabs.
11<<
will move current tab to beginning.10>>
will move current tab to end.
Usually, you need not count the number, you just prefix a large number such as 99<<
, if you want to move a tab to beginning or end.
By default, Alt-s
will toggle Surfingkeys for current site. When Surfingkeys is turned off, all mappings stop working except the hotkey. To change hotkey, use settings below:
map('<Ctrl-i>', '<Alt-s>'); // hotkey must be one keystroke with/without modifier, it can not be a sequence of keystrokes like `gg`.
When Surfingkeys is turned off on some site by Alt-s
, the status will be persisted in settings, for example,
"blacklist": {
"https://github.com": 1
},
Alt-s
once more will remove it from settings.blacklist. The data settings are not always presented in snippets, you could use yj
to dump all settings into clipboard, then paste it in your text editor to check out.
Another way to disable Surfingkeys is to use settings.blacklistPattern
, please refer to regex for disabling.
SwitchySharp is a great extension to switch proxy, but my use case with it is very simple,
- create a profile using PAC script.
- maintain site list in the PAC script, use proxy if the site being accessed is in the list.
- whenever I come into a site blocked by something, I add it to the list in PAC script.
- click the SwitchySharp icon to reload the profile.
- casually I click the SwitchySharp icon to switch profile between
direct
andpac_script
.
To avoid manually editing PAC script and reloading/switching profile by clicking SwitchySharp icon, I replaced SwitchySharp by integrating proxy settings into Surfingkeys, and provides related commands and shortcuts.
-
setProxy, to set proxy, some examples:
setProxy 192.168.1.100:8080 setProxy 127.0.0.1:1080 SOCKS5
-
setProxyMode, to set proxy mode, there are five modes: direct, byhost, always, system and clear.
direct Chrome will connect to all sites directly. byhost Chrome will only connect to sites added by `addProxySite` through proxy. always Chrome will connect to all sites through proxy. system Use proxy configuration taken from the operating system. clear Surfingkeys will not take control of proxy settings, this is the default mode.
-
addProxySite, removeProxySite, toggleProxySite, to make Chrome connect to site through proxy or not, examples:
addProxySite google.com,facebook.com,twitter.com
-
proxyInfo, to list proxy you set by
setProxy
, proxy mode you set bysetProxyMode
and sites you add/remove byaddProxySite
/removeProxySite
/toggleProxySite
. -
cp
, toggle proxy for current site. -
spa
, shortcut for:setProxyMode always
-
spb
, shortcut for:setProxyMode byhost
-
spc
, shortcut for:setProxyMode clear
-
spd
, shortcut for:setProxyMode direct
-
sps
, shortcut for:setProxyMode system
-
spi
, shortcut for:proxyInfo
Thanks ACE for the vim editor, Surfingkeys integrates ACE for the vim editor. The vim editor is used:
- to edit any input on html page
- to edit URL to open in new tab
- to edit settings
In normal mode, press capital I
, then use a hint letter to pick up a input box. A vim editor is opened for you to edit text. The vim editor is opened in slightly different way for <input>
, <textarea>
, and <select>
elements.
For <input>
elements, the vim editor has only one line, and you use vim key bindings to edit your text. Then press Enter
or :w
to write your text back to the <input>
element.
For <textarea>
elements, the vim editor is opened in bigger size. After you complete your edits, press Ctrl-Enter
or :w
to write your text back to the <textarea>
element.
For <select>
elements, the vim editor is again opened in bigger size. Instead of editing the text, search for the desired option and jump to the line, then press Enter
to select it. This is handy for <select>
elements which have lots of options.
Esc
or :q
to quit vim editor without writing text back.
Tab
completion works with all words on current page, Space
to choose a match from popup.
If you enter insert mode with i
or mouse click, you will edit your input in normal way. You could also open vim editor at that time by pressing Ctrl-i
.
Remember that in insert mode, press Ctrl-i
to open the vim editor.
su
to open vim editor to edit current URL, then Enter
or :w
to open the input URL, which works just like address bar with vim-binding keys.
Tab
completion works with all URLs from bookmark/history, Space
to choose a match from popup.
se
to open settings editor, :w
to save settings.
All keystrokes in normal mode are repeatable by dot, except those keystrokes mapped with repeatIgnore
as true
, for example,
mapkey('e', '#2Scroll a page up', function() {
Normal.scroll("pageUp");
}, {repeatIgnore: true});
Then .
will not repeat action to page up, even e
is just pressed.
- copy your markdown source into clipboard.
sm
to open markdown preview, which will preview markdown from clipboard.- Then on the preview page, another
sm
will open vim editor to edit markdown source. :wq
to refresh preview.r
to reload markdown source from clipboard.
By default, Surfingkeys uses this markdown parser to preview markdown, if you'd like to use github markdown API to parse your markdown, please add below line to your settings:
settings.useLocalMarkdownAPI = false;
yg
to capture current page.yG
to capture current full page if it is scrollable.yS
to capture current scroll target.
Mermaid is a great tool to generate diagrams and flowcharts from text in a similar manner as markdown. Surfingkeys provides a simple frontend to generate diagrams from text in clipboard, and a vim editor to edit it.
Ctrl-Alt-d
to open it.
To make Surfingkeys work for PDF files, Surfingkeys integrates PDF viewer from the notable pdf.js. When a pdf file is opened in Chrome, the PDF viewer will be launched, and you could use everything from Surfingkeys then.
If you would like to use original pdf viewer provided by Chrome itself, use ;s
to toggle that.
Some functionalities are also available when you're using original pdf viewer, but some functionalities such as smooth scroll/visual mode etc won't be available.
mapkey(keystroke, help_string, action_code, [options])
parameter | explanation |
---|---|
keystroke | string, any keystroke to trigger the action |
help_string | string, a help message to describe the action, which will displayed in help opened by u . |
action_code | function, a Javascript function to be bound. If the function needs an argument, next pressed key will be fed to the function. |
options | object, properties listed below |
domain | regex[optional], a Javascript regex pattern to identify the domains that this mapping works, for example, /github\.com/i says that this mapping works only for github.com. |
repeatIgnore | boolean[optional], whether this keystroke will be repeat by dot command. |
Just an example to map one keystroke to different functions on different sites,
mapkey('zz', 'Choose a tab', function() {
Front.chooseTab();
}, {domain: /github\.com/i});
mapkey('zz', 'Show usage', function() {
Front.showUsage();
}, {domain: /google\.com/i});
mapkey in visual mode and omnibar bar.
vmapkey(keystroke, help_string, action_code, [options])
map(new_keystroke, old_keystroke, [domain_pattern], [new_annotation])
imap(new_keystroke, old_keystroke, [domain_pattern], [new_annotation])
vmap(new_keystroke, old_keystroke, [domain_pattern], [new_annotation])
cmap(new_keystroke, old_keystroke, [domain_pattern], [new_annotation])
parameter | explanation |
---|---|
new_keystroke | string, the new keystroke that will be used. |
old_keystroke | string, the existing keystroke that will be replaced, which means pressing it will not trigger any action. |
domain_pattern | regex[optional], a Javascript regex pattern to identify the domains that this mapping works. |
new_annotation | string[optional], use it instead of the annotation from old_keystroke if provided. |
Normal mode,
unmap(keystroke, [domain_pattern])
Insert mode,
iunmap(keystroke, [domain_pattern])
Visual mode,
vunmap(keystroke, [domain_pattern])
parameter | explanation |
---|---|
keystroke | string, the existing keystroke that will be removed. |
domain_pattern | regex[optional], a Javascript regex pattern to identify the domains that this settings works. |
unmapAllExcept(keystrokes, [domain_pattern])
parameter | explanation |
---|---|
keystrokes | array of string, the existing keystrokes that will be removed. |
domain_pattern | regex[optional], a Javascript regex pattern to identify the domains that this settings works. |
Example,
unmapAllExcept(['f', '/', '?']);
addSearchAlias(alias, prompt, search_url, suggestion_url, callback_to_parse_suggestion);
parameter | explanation |
---|---|
alias | one or several chars, used as search alias. When you input the string and press space in omnibar, it will switch to the related search engine. |
prompt | a string to tell you which search engine will be used for following search |
search_url | the URL for the search engine |
suggestion_url[optional] | omnibar will list out search suggestions from the engine, if you provide suggestion_url and callback_to_parse_suggestion |
callback_to_parse_suggestion[optional] | works with suggestion_url to provide search suggestion |
addSearchAliasX(alias, prompt, search_url, search_leader_key, suggestion_url, callback_to_parse_suggestion, only_this_site_key);
parameter | explanation |
---|---|
search_leader_key | one or several chars, used as search leader key, in case of that you would not like to use the default key s . |
only_this_site_key | one or several chars, used as only-this-site-key, in case of that you would not like to use the default key o . |
This version will create a mapping to search selected text with search_url
on pressing search_leader_key
followed by alias
, except that it adds search alias to omnibar as the normal version. For example, below line
addSearchAliasX('s', 'stackoverflow', 'http://stackoverflow.com/search?q=', 'o');
works like
addSearchAlias('s', 'stackoverflow', 'http://stackoverflow.com/search?q=');
mapkey('os', 'Search Selected with stackoverflow', function() {
searchSelectedWith("http://stackoverflow.com/search?q=");
});
vmapkey('os', 'Search Selected with stackoverflow', function() {
searchSelectedWith("http://stackoverflow.com/search?q=");
});
removeSearchAliasX(alias, search_leader_key, only_this_site_key);
Omnibar.listWords(<array of words>)
Omnibar.html(<any html snippets>)
To change style for link hints:
Hints.style('border: solid 3px #552a48; color:#efe1eb; background: initial; background-color: #552a48;');
To Change style for text hints:
Hints.style("border: solid 8px #C38A22;padding: 1px;background: #e39913", "text");
Change the style of the search marks and cursor:
Visual.style('marks', 'background-color: #89a1e2;');
Visual.style('cursor', 'background-color: #9065b7;');
aceVimMap(lhs, rhs, ctx)
For example,
aceVimMap('jk', '<Esc>', 'insert');
key | default value | explanation |
---|---|---|
Hints.characters | "asdfgqwertzxcvb" | The characters for generating hints. |
Hints.numericHints | false | Whether to use digit as hint label, if it is on, you could type text to filter links. |
Hints.scrollKeys | "0jkhlG$" | The keys that can be used to scroll page in hints mode. You need not change it unless that you have changed Hints.characters . |
settings.showModeStatus | false | Whether always to show mode status. |
settings.showProxyInStatusBar | false | Whether to show proxy info in status bar. |
settings.richHintsForKeystroke | 500 | Timeout(ms) to show rich hints for keystroke, 0 will disable rich hints. |
settings.useLocalMarkdownAPI | true | Whether to use chjj/marked to parse markdown, otherwise use github markdown API. |
settings.focusOnSaved | true | Whether to focus text input after quiting from vim editor. |
settings.omnibarMaxResults | 10 | How many results will be listed out each page for Omnibar. |
settings.omnibarPosition | "middle" | Where to position Omnibar. ["middle", "bottom"] |
settings.omnibarSuggestion | false | Show suggestion URLs |
settings.omnibarSuggestionTimeout | 200 | Timeout duration before Omnibar suggestion URLs are queried, in milliseconds. Helps prevent unnecessary HTTP requests and API rate-limiting. |
settings.focusFirstCandidate | false | Whether to focus first candidate of matched result in Omnibar. |
settings.tabsThreshold | 9 | When total of opened tabs exceeds the number, Omnibar will be used for choosing tabs. |
settings.hintsThreshold | 10000 | When total of regular clickable elements (a, button, select, input, textarea) exceeds this number, Surfingkeys will not show hints for other elements that are clickable. |
settings.clickableSelector | "" | Extra CSS selector to pick elements for hints mode, such as "*.jfk-button, *.goog-flat-menu-button". |
settings.clickablePat | /(https?|thunder|magnet)://\S+/ig | A regex to detect clickable links from text, you could use O to open them. |
settings.smoothScroll | true | Whether to use smooth scrolling when pressing keys like j /k /e /d to scroll page or elements. |
settings.modeAfterYank | "" | Which mode to fall back after yanking text in visual mode. Value could be one of ["", "Caret", "Normal"], default is "", which means no action after yank. |
settings.scrollStepSize | 70 | A step size for each move by j /k |
settings.scrollFriction | 0 | A force that is needed to start continuous scrolling after initial scroll step. A bigger number will cause a flicker after initial step, but help to keep the first step precise. |
settings.nextLinkRegex | /((>>|next)+)/i | A regex to match links that indiate next page. |
settings.prevLinkRegex | /((<<|prev(ious)?)+)/i | A regex to match links that indiate previous page. |
settings.hintAlign | "center" | Alignment of hints on their target elements. ["left", "center", "right"] |
settings.defaultSearchEngine | "g" | The default search engine used in Omnibar. |
settings.blacklistPattern | undefined | A regex to match the sites that will have Surfingkeys disabled. |
settings.focusAfterClosed | "right" | Which side of tab will be focused after current tab closed. ["left", "right"] |
settings.repeatThreshold | 99 | The maximum of actions to be repeated. |
settings.tabsMRUOrder | true | Whether to list opened tabs in order of most recently used beneath Omnibar. |
settings.historyMUOrder | true | Whether to list history in order of most used beneath Omnibar. |
settings.newTabPosition | 'default' | Where to new tab. ["left", "right", "first", "last", "default"] |
settings.interceptedErrors | [] | Indiates for which errors Surfingkeys will show error page, so that you could use Surfingkeys on those error pages. For example, ["*"] to show error page for all errors, or ["net::ERR_NAME_NOT_RESOLVED"] to show error page only for ERR_NAME_NOT_RESOLVED, please refer to net_error_list.h for complete error list. |
settings.startToShowEmoji | 2 | How many characters are needed after colon to show emoji suggestion. |
settings.language | undefined | The language of the usage popover, only "zh-CN" is added for now, PR for any other language is welcomed, please see l10n.json. |
settings.stealFocusOnLoad | true | Whether to prevent focus on input on page loaded, set to true by default so that we could use Surfingkeys directly after page loaded, otherwise we need press Esc to quit input. |
settings.enableAutoFocus | true | Whether to enable auto focus after mouse click on some widget. This is different with stealFocusOnLoad , which is only for the time of page loaded. For example, there is a hidden input box on a page, it is turned to visibile after user clicks on some other link. If you don't like the input to be focused when it's turned to visibile, you could set this to false. |
settings.theme | undefined | To change css of the Surfingkeys UI elements. |
settings.caseSensitive | false | Whether finding in page is case sensitive. |
settings.cursorAtEndOfInput | true | Whether to put cursor at end of input when entering an input box, by false to put the cursor where it was when focus was removed from the input. |
settings.theme = `
#sk_status, #sk_find {
font-size: 20pt;
}
}`;
The API documentation is currently a work in progress.
- jQuery, for clean coding.
- TRIE, finally replaced by my own simple implementation for less memory usage and better performance.
- ACE vim editor, for vim editor.
- markdown parser, for markdown parser.
- pdf.js, for pdf viewer.
- vimium, for the days without this extension.
- cVim, for the days without this extension.
MIT License