Better keyboard shortcut support

(NeedInfo from)



WebExtensions: General
2 years ago
7 days ago


(Reporter: krizsa, Unassigned, Mentored, NeedInfo)


(Blocks: 1 bug)

Firefox Tracking Flags

(Not tracked)


(Whiteboard: [triaged][design-decision-approved])



2 years ago
We'd like to support Vimperator-type functionality.


2 years ago
Blocks: 1215059
(In reply to Gabor Krizsanits [:krizsa :gabor] from comment #0)
> We'd like to support Vimperator-type functionality.

Is this equivalent to "Support chrome.commands"?  (See  If not, can you explain what might be different?

Comment 2

2 years ago
(In reply to Nick Alexander :nalexander from comment #1)
> (In reply to Gabor Krizsanits [:krizsa :gabor] from comment #0)
> Is this equivalent to "Support chrome.commands"?  (See
>  If not, can you explain
> what might be different?

It is not. Part of this bug is to figure out what are the missing features from chrome.commands. Obviously one huge draw back of chrome.commands are all the limitations it comes with. But Vimperator comes with extensibility as well, and I'm not sure their plugins can work with the current API which is manifest driven. So probably we will need something that can work dynamically and programmatically, supports more keys and in some cases even allows the default keybindings to be overwritten. Note that Vimperator is just one example, there are other popular extensions with rich keyboard shortcut story. The goal is to extend the chrome API or to design an alternative API if needed that makes it possible to support our already popular add-ons.


2 years ago
Flags: blocking-webextensions-


a year ago
Whiteboard: triaged
Whiteboard: triaged → [triaged][design-decision-needed]

Comment 3

10 months ago
Another Vimperator-like extension is VimFx[1]. (I'm the main developer of VimFx.) The idea of VimFx is to provide the vanilla Firefox experience, with a bunch of Vim-like keyboard shortcuts on top.

The biggest problems with chrome.commands for both extensions are:

1. chrome.commands only support keyboard shortcuts with modifiers (ctrl, alt, ctrl+alt), while Vimperator’s and VimFx’s shortcuts are mostly modifier-less. For example, pressing "t" could open a new tab.

2. Both add-ons have _tons_ of shortcuts and allows the user to add their own. There must be great default shortcuts, and all of them must be customizable.

The way VimFx works is basically like this (pseudo-JavaScript code):

> forEveryChromeWindow(window => {
>   window.addEventListener('keydown', event => {
>     const matchingCommand = getMatchingCommand(
>       previouslyEnteredKeys, event.key, event.code
>     )
>     if (
>       (isUIEvent(event) && isTextInputFocused(event)) ||
>       state.webpageContentTextInputHasFocus === true
>     ) {
>       // Usually, only Escape for blurring the current text input
>       // is allowed inside text inputs.
>       if (!isAllowedInTextInputs(matchingCommand.shortcut)) {
>         return // Allow typing in text inputs without triggering commands.
>       }
>     }
>     if (matchingCommand) {
>       event.preventDefault()
>       event.stopPropagation()
>     }
>   }, true)
> ) might do stuff like:

- Focusing or blurring the location bar
- Opening or closing the find bar
- Opening or closing a tab
- Switch to another tab
- Sending a message to a frame script for interaction with web page content

Note that another nice thing about dealing with keydown events in the UI process (rather than in frame scripts) is that the keyboard shortcuts remain responsive even if the content process is slow. Yay multi-process!

Chrome has the Vimium[1] extension, which is similar to Vimperator and VimFx. Vimium listens for keydown events in content scripts (there's nothing else available). People keep requesting the same features from Vimium, but there's nothing they can do, because the Chrome extension API does not allow them:

- Vimium can't focus or blur the location bar. Instead, they've built their own location bar. There are no APIs for dealing with the location bar. Even if they were, Vimium couldn't bind the Escape key to do the blurring when inside the location bar. You can be similarly "trapped" inside the dev tools, for instance.
- Vimium can't interact with the find bar. Instead, they've built their own.
- Vimium can't do anything on chrome:// tabs, new-tab-page tabs, or any tabs where Chrome decided not to allow extensions. This is especially bad when using the shortcut to focus the next tab. If you come across a disallowed tab, you get stuck there and can't move on (with Vimium shortcuts).

I'm interested in making VimFx a WebExtension. I'm fully aware that we might not be able to port _everything,_ and that's totally fine as long we can just get the basic features going. But I can't even get that far.

Here's an idea:

1. Provide a customizable key for blurring the current UI control and return focus to the page. VimFx users want this key to be Escape.
2. Provide a WebExtension API that lets the extension register a keydown handler callback, in a background script (that is, in the UI process).
3. Provide WebExtension APIs for doing basic interactions with the most common UI elements, such as focusing the location bar. This is a totally separate issue, so I won't mention it again below.

Details about the keydown handler callback:

- It is called on keydown, but Firefox chooses _which_ keydown events to provide.
- It is _not_ called when a UI element that can be typed into is focused, such as the location bar, some <select>-style dropdown or menus (because of access keys).
- It _is_ called _before_ Firefox's own keyboard shortcuts are handled, so that the extension gets the chance to override the default shortcuts.
- It _is_ called regardless of what page is in the current tab. That includes about: pages.
- It is called with a regular event object, but with and suchlike nulled out, as to not expose the UI.
- event.preventDefault should prevent default as expected.
- event.stopPropagation should stop the event from reaching the content page.

Note: VimFx currently has a keyup handler as well. All that is done there is:

- event.preventDefault() and event.stopPropagation() if those two methods were run in the corresponding keydown event.
- Keeping track of the currently held down modifier keys, for a UI thing. Nothing critical.

I'm sure that if the keydown proposal works out, we'll find a way to make keyup handling into it as well.

Simon: thanks so much for the detailing your use case(s).  That kind of breakdown is really useful when choosing what Firefox should support and when designing APIs.

andym, others: I want to make sure Simon's effort is incorporated into this work, whatever that means.  NI just to make sure you process it.
Flags: needinfo?(amckay)

Comment 5

9 months ago
Processed, thanks Simon.
Flags: needinfo?(amckay)
Priority: -- → P3

Comment 6

9 months ago
Marking as approved because I don't think anyone has any problems about this at a high level and it meets all the requirements for a new API
Component: WebExtensions: Untriaged → WebExtensions: General
Flags: blocking-webextensions-
Whiteboard: [triaged][design-decision-needed] → [triaged][design-decision-approved]

Comment 7

9 months ago
I’m so glad to hear that! Feel free send me all sorts of real use case questions you might get while designing the API :)

Comment 8

6 months ago
A quote from the Mozilla support page for Firefox keyboard shortcuts[1]:

"Note: Keyboard shortcuts can be customized using the Menu Wizard[2] extension."

Being able to customize the keyboard shortcuts is important for users who find it easier to use the keyboard than a mouse.

When Firefox switches to WebExtensions only, one of the following needs to be done (in addition to updating that link):

- Remove support for customizing Firefox's keyboard shortcuts. (That would be sad.)
- Bake keyboard shortcut customization into Firefox.
- Allow WebExtensions to customize Firefox keyboard shortcuts.

For the case of VimFx (mentioned in an above comment), it'd be nice if VimFx could trigger the default keyboard shortcut actions manually when a user has typed a VimFx shortcut.


Comment 9

6 months ago
Simon, would you be interested in trying to implement this?

Comment 10

6 months ago
Yes, I would. I've never worked on the Firefox code base before, and I have never written C++, but I could still try.

However, I'm not really sure what "this" means yet.

- What is acceptable in the WebExtensions philosophy? I wouldn't like this feature to be abused, and to become a common way that add-ons slow down Firefox at every key stroke.
- What are the needs from other add-ons than VimFx?
- Should we just start experimenting somewhere to make some sort of demo and see where things end up?

Comment 11

6 months ago
Depending exactly what you want to do you shouldn't need to write C++. But you can write an experiment completely in JS without having to compile Firefox. Some documentation and examples are here:

If that doesn't work, diving into Firefox might work, and again shouldn't be too bad depending upon what you want to do. If you do get to that, I recommend starting here:

Figuring out what "this" is the slightly harder part and for that, prototyping or throwing together some drafts in a wiki, gist or your favourite documentation tool might help.

The WebExtensions philosophy is focused on security, privacy, stability and performance. It's true that some APIs can be abused if a developer really wants to make a bad experience. But that's where we'll be able to help.

Two other add-ons that do commands:

Comment 12

6 months ago
Thanks! I'll try making an experiment in a few weeks.

Comment 13

6 months ago
Since my last comment, I’ve spent the most time thinking about API design and I have gone through several iterations. In the last few days I’ve arrived at something that I like and I think should work, and I have written it down. I then started trying to implement a WebExtension Experiment, but got stuck at even getting the Hello World example running.

Everything is available here:

- I’d very much appreciate feedback on what I’ve written about the proposed APIs!
- Help with getting the Hello World WebExtension Experiment running correctly would be awesome!
- Feel free to open issues on the above mentioned GitHub repository.

Comment 14

6 months ago
I also need dynamically and programmatically key registering. Thanks for your work Simon.

Comment 15

6 months ago
I’ve updated the proposal after some feedback. Check it out!

Croydon, would you mind telling what you need this feature for? I’d like to know that the proposed APIs actually do what you need.

Comment 16

6 months ago
According to your readme onKey.addListener, onKey.removeListener, onKey.hasListener and keyboard.onKey would do everything I need already :)

Comment 17

6 months ago
That looks great, Simon. I think it has the core functionality needed to enable useful keyboard driven addons.

Here is a collection of thougts I had. I like the simplicity of the current proposal, so I am okay with these being disregarded but I just raise them for the sake of consideration:

1. The proposal allows for single key event listeners and suggests building up multi-key shortcuts by having the addon track the state of keyboard input. Are you concerned about a user running more than one addon that uses this API at once? If one addon supports a two key shortcut "g r" and another supports an "r" shortcut, then pressing "g r" will trigger both since the first addon has no way to tell the second not to fire after the user presses "g". I guess because WebExtensions are isolated you will never be able to check globally for conflicts between shortcuts the way KeyConfig does.

2. I recently switched from Pentadactyl to VimFx and one thing I miss is the ability to assign non-modifier-key shortcuts for other addons. What about an API to send key events to the browser? browser.keyboardShortcutActions is proposed to handle this for builtin shortcuts, but for example to open the NoScript UI one has to press "C-S-s". One can change the particular combination in preferences but it has to use a modifier key. With Pentadactyl, I had this mapped to "n s". WebExtensions can't talk to each other directly in general, but if I could have an addon that catches "n s" and sends "C-S-s" to the browser that would be good enough.

3. One thing VimFx made me aware of is the GCLI (because I can't help hitting ":" coming from Pentadactyl). The GCLI seems pretty powerful, and I think some of Pentadactyl's features not available in a WebExtension could be done through custom GCLI commands (and I think the GCLI will still work after XUL is deprecated?). Having an API to send commands to the GCLI from a WebExtension would help with providing current Vimperator/Pentadactyl functionality because an addon could then map keyboard shortcuts to GCLI commands. (Or maybe this could kind of be done through 2 by for example mapping "s s" to the browser key events ":screenshort<Enter>" though that seems inefficient.

Comment 18

6 months ago
Thank you for you feedback, wsha.code!

1. No, I'm not at all worried about extension conflicts. Today, VimFx uses a very similar approach to the proposed `browser.keyboard.onKey` API, and it is very much possible that several extensions use the same approach as well. However, we've had zero issues regarding conflicts with other extensions when it comes to keyboard handling. I think that the only way conflicts can arise is if the user installs VimFx and Vimperator at the same time and expects that to work. Of course it won't, and people don't expect that in reality either. The `browser.keyboard` API is not for "mainstream consumption" by every other WebExtension. It's for extensions specifically dealing with keyboard shortcuts. I don't think it makes sense to install more than one such extension at a time. Other extensions will do just fine with the `browser.commands` API.

2. I think that Cross-extension messaging is the solution here: (also, this is a bit out of scope for this ticket)

3. Let's not talk about GCLI in this ticket. It is out of scope, and makes it harder to follow the comments.

Comment 19

6 months ago
The proposals are progressing nicely. I've now managed to implement part of the API as a WebExtension Experiment. Follow along here:

Comment 20

6 months ago
I think your stance on conflicts is reasonable. It might be worth warning the user that using more than one extension with the browser.keyboard preference can cause conflicts when the extension permissions are presented at install time.

Regarding cross-extension messaging, it's nice in theory, but I think in practice it won't be useful. For it to be useful, extension authors would have to go out of their way to create a public API for other extensions to use which I doubt they would do just so their shortcuts could be remapped.

Regarding the GCLI, I think it is out of scope of what you want to port VimFx to a WebExtension, and a more in depth discussion could take place on a separate issue, but I think it is worth mentioning in this issue since this issue was started as "support Vimperator working as a WebExtension".

Comment 21

5 months ago
Kris, as the author of pentadactyl, you know this area well. Any comment so far for Simon?
Flags: needinfo?(kmaglione+bmo)
Sorry, I'm busy trying to get things ready for the merge next week. I'll have more time to comment after Monday.

Comment 23

4 months ago
TL;DR: Turns out not much at all needs to be done – for VimFx's purposes (I'm dropping all other ambitions). What's needed is: One bug fix, and one new shortcut for the Commands API. No new APIs.

1. Fix bug 1338909.
2. Add "_focus_content_area" to the Commands API.

How did I come to the above conclusions? Read on.

I've made two important realizations:

- My proposed new APIs feel too complicated and too niche.
- Using only what WebExtensions already provide (regular old 'keydown' listeners in content scripts) works just fine 90% of the time.

The other 10% is not enough to motivate a new API. All that is needed is an escape hatch.

It turns out that the big part of the escape hatch already exists: Browser action popups. Such a popup:

- Can be opened in _any_ tab (unlike content scripts).
- Can capture 'keydown' events (like any old web page), and do whatever it wants with them.
- Can be opened with the Commands API. Shortcuts added via the Commands API can
  be executed in _any_ tab, and inside _any_ UI element (such as the location bar or the devtools).

I intend to use VimFx's browser action popup as a way to run VimFx shortcuts in tabs where content scripts aren't allowed, or if the web page makes VimFx's keyboard shortcuts unresponsive.

> "commands": {
>   "_execute_browser_action": {
>     "suggested_key": {
>       "default": "Ctrl+E"
>     }
>   }
> }

"Can't run a VimFx command, for some reason? Hit Ctrl+E first to "escape" into VimFx's popup."

To make this Ctrl+E idea work in practice, bug 1338909 needs to be resolved. That's a small bug, though.

There's one thing that cannot be done from a popup, though: Focusing web page elements. For example, VimFx's `gi` shortcut focuses the first text input it finds in a page. That can't be done from a popup, because there's no way to move focus from the popup back to the page. Right now, that either requires clicking inside the web page with the mouse, or pressing Tab or F6 a couple of times an hoping for the best. WebExtensions basically live and breathe inside the content area of the browser, but there's currently no sane way of getting back to that "world" using the keyboard.

That's why I propose this:

> "commands": {
>   "_focus_content_area": {
>     "suggested_key": {
>       "default": "Ctrl+Shift+E"
>     }
>   }
> }

- If the content area is already focused it is a no-op.
- Otherwise, the currently focused UI control is blurred and focus is moved to the content area. This means that you can use the arrow keys to scroll it, press `/` to quick find, and that content scripts can receive 'keydown' events etc.

(I'm not totally sold on Ctrl+Shift+E as the default VimFx shortcut, but that doesn't matter. People will want to be able to change it regardless.)


In summary:

1. Fixing bug 1338909 should be a no-brainer, especially since Chrome already works that way.
2. Regarding adding "_focus_content_area" to the Commands API – do you want me to open a new ticket for that?
The auto-focusing bug that needs fixing is tracked here now (I resolve the other as a dupe): bug 1324255
> commands: _focus_content_area

Couldn't you also implement this by listening for a custom command in a background script? When received in the background, it could send a message to a content script that does querySelector(...).focus()

Comment 26

4 months ago
Thanks for the idea for _focus_content_area, Kumar!

I tried it out, and couldn’t get the focus to move.

Here’s my test extension:

Here’s exactly what I did:

1. Went to
2. Focused the location bar.
3. Pressed Ctrl+Shift+E.

Results: The `<body>` and the google search input got red borders, but neither of them was focused.

(I also tried your workaround for getting a browser action popup focused, but it made no difference when I tested. You can try it with the same test extension, with the Ctrl+E shortcut.)

Ubuntu 16.04
Firefox Nightly 54.0a1 (2017-02-05) (64-bit)

Comment 27

4 months ago
Just a quick question cause i was hopping this new way to handle shortcuts to resolve my "issue" and i may need to fill another request now.

What about a way to add Commands outside the manifest.json? that way we can provide the users a way to customize the addon shortcuts in case of collision or just commodity/necessity.

Comment 28

4 months ago
Sergio, it seems like you are looking for bug 1303384.

Kumar, I now understand _why_ using `.focus()` in  a content script won't move the focus. Imagine a website doing `setInterval(() => { someInput.focus() }, 100)`. If that could "steal" the focus from the location bar, the website would effectively prevent the user from using the location bar at all (in that tab). The same restriction holds for content scripts (and malicious WebExtensions). The proposed _focus_content_area command, on the other hand, can only be invoked by the user explicitly pressing some keys on the keyboard.

Andy, what do you think about the _focus_content_area proposal?

Comment 29

4 months ago
I've opened bug 1341416 for _focus_content_area.

Comment 30

4 months ago
The API suggestions that Simon made earlier are a good fit for Vimperator, but the compromise with the browser action page is less suitable for that purpose.

What can I do to push this bug further? Do you want a concrete implementation or is an API definition sufficient (and then someone from Mozilla works on it, presumably)?

Comment 31

4 months ago
I do think this API is needed. My experience with Chrome extensions like cVim is that keyboard input using page scripts is unreliable. Key presses randomly don't work and I must either click on the page or reload it to get it to work again. By comparison Vimperator has been 100% reliable over the 6 or so years I've been using it.

Comment 32

4 months ago
Here's food for thought:

Vim-style extensions are all about modifierless shortcuts.

Firefox already has them. For example, `Space` to scroll down and `/` to open Quick Find. Neither of those conflict with typing spaces and slashes into text inputs – neither in UI elements nor in web page elements. They work in `about:` pages as well as in web pages.

So I guess the Commands API could be extended to tap into that system.

One notable difference, though, is that `Space` and `/` are `event.preventDefault()`:able by the web page, while Vim-style extension shortcuts typically aren't.

Also, some web sites don't bother calling `event.preventDefault()` for keys that don't usually do anything when pressed, such as A–Z.

I guess it'd be possible to let modifierless shortcuts decide if they are preventable or not. Just keep in mind that such shortcuts might conflict with "fancy text editors" on web pages. Determining if the currently focused element is "editable" is not easy:

Just brainstorming and leaving a comment here in case anyone wants to pick up the project of new keyboard APIs. :)

Comment 33

4 months ago
An extension of the commands API that allowed modifierless shortcuts, preventDefault, and the dynamic registration of those shortcuts (or just permitted us to hook every possible shortcut) seems OK for most commands, but the situation is a bit weird if you want to accept an arbitrary string as an argument to a command.

e.g. I want users to be able to type 'afoo' and to be redirected as if they'd clicked a 'href="foo"' link. If I want to capture 'foo' I either need to register commands for all the characters I think my user will press or I need to move the focus of the user to some element that I can addEventListener to.

That's possible, but seems a bit weird to me. It will also break on pages where we're not allowed to have content scripts unless we define some other UI element (a toolbar or a browser action, perhaps).

I think it's simpler and purer to just have an API that permits adding an eventListener to the root FF document.

Running `document.addEventListener("keydown", cb)` in the browser console basically gives me what I want (and what is described in comment #2). 

    browser.keyboard.addEventListener = function (cb) {
	document.addEventListener("keydown", Sanitiser(cb))

I imagine `Sanitiser` receiving the real event, wrapping it up in an Event-like object that hides the real event as a private variable and controls access with 'privileged' functions[0].

Douglas Crockford suggests that this is possible[0], but I'm not a seasoned enough JS hacker to know if there's some way around his 'privileged' functions or private variables.


Comment 34

4 months ago
Looks like `document` in the browser console refers to the first window only, so something a bit more sophisticated might be required in the implementation of the API, but hopefully not too hard.

Firefox developers: I'd really like this API to exist and I'm willing to work on it, but I don't know what help you need or want from the community. Please let me know how I can help :)
If you'd like to build a prototype for a new API, it is a well documented and pretty straight forward process (you won't need to build your own Firefox):
Oh, sorry for repeating what was already said. I wasn't caught up with the whole thread.

Comment 37

3 months ago
I'd like to work on a keyboard webextension API, but this bugzilla thread has died out and I haven't had a lot of luck on IRC. Would a mozillan, or someone else who knows about Firefox's internals be willing to chat to me a bit?

I especially want to know:
	1. If mozilla are still willing to include this API
	2. What security or other constraints I should work within
	3. Some technical stuff about event handling in Firefox.

I'd really like for someone to commit to meeting for half an hour or so on IRC or whatever other IM service suits. Mail me and we can arrange a time or whatever. I live on GMT/UTC, but stay up late.
Colin, can't you salvage parts of Simon's WE Experiment?

> I live on GMT/UTC, but stay up late.

You might need to contact folks in your evening hours, when it's daytime in the US.

Andy or Caitlin, since this API has been approved, can you please make sure Colin is receiving the required help to move a WE Experiment forward?
Flags: needinfo?(cneiman)
Flags: needinfo?(amckay)

Comment 39

3 months ago
Thanks for the ping, Colin and Kris have already chatted, but we are having a work week this week. So Kris and Colin are plan on talking about it next. But, its easy for us to forget things, so please ping us if the meeting doesn't happen.
Flags: needinfo?(amckay)
It looks like this is in progress, so I'm going to cancel the needinfo. If anything else is needed, please let me know!
Flags: needinfo?(cneiman)

Comment 41

2 months ago
Addons like Tree Style Tab or Tree Tabs that allow to collapse and expand tab trees need an ability to replace original shortcuts like Ctrl-Tab and Ctrl-Shift Tab. Why? Imagine that's a vertical tab bar:
[Parent tab in the collapsed tab tree]
   [child collapsed tab 1 (hidden)]
   [child collapsed tab 2 (hidden)]
[Standalone tab]

When [Parent tab in the collapsed tab tree] has focus and you press Ctrl-Tab, focus should move to the next visible tab on the tab bar, and that is [Standalone tab]. However, Ctrl-Tab by default will move focus to the next available tab on the tab bar, and that is [child collapsed tab 1 (hidden)].

Tree Tabs developer wrote a post about his problem here:
You need to log in before you can comment on or make changes to this bug.