58

Since the Firefox 57 (Quantum) update all AddOns which allowed to change key bindings in Firefox seemed to have stopped working/being supported.

Is there a method to change the default key bindings in Firefox Quantum?

1

8 Answers 8

20

There is a way. It's not super official, but basically you can unpack browser/omni.ja, edit the keybindings in chrome/browser/content/browser/browser.xul, repack it, delete startup cache and it will work.

Alternatively, you can compile your own firefox and then you don't need to unpack the binary, if you consider unpacking and repacking more hacky, than building.

Another advantage of building is that you can store your modifications on top of the official sources in git and always rebase, like I do here: https://github.com/errge/gecko-dev/tree/gregzilla-patched-20181223

I advise you to first start with the binary option, because you will have working keyboard shortcuts in 20 minutes, instead of just being at the start of the mercurial clone procedure :)

Both of these methods are independent of any extensions/webextensions and will ALWAYS work, even in the location bar and even on protected pages (as you asked in the comments). So they will work better than remapping webextensions.

I have an article written up with all the details that may interest you: https://github.com/nilcons/firefox-hacks

If you have more questions, please report issues on github.

8
  • 5
    Welcome to Super User. Without actually providing the steps one must take, there is no answer in this post. Please edit your post to include this information, including the essential content of linked material. Commented Dec 23, 2018 at 21:15
  • Hey, thanks you! How this will effect the updates firefox gets? Do I have to rebuilr + reinstall firefox after each update? Or can I somehow setup a different update channel so it will fetch from my travis builds for example? That way I could mostly automate the process I hope.
    – Finn
    Commented Dec 27, 2018 at 15:00
  • 1
    If you are just after the keybindings (and not interested in compiling your own for other reasons), then I would use this part of the article: github.com/nilcons/firefox-hacks#binary-hacking-automated So basically I have this script as "patch-the-fox" and whenever I notice that firefox is not working correctly, I just start a shell, and run "patch-the-fox" and restart. Then it's good again for 2-3 weeks.
    – errge
    Commented Dec 28, 2018 at 15:40
  • 2
    browser.xul was renamed to browser.xhtml: userchrome.org/firefox-changes-userchrome-css.html#fx69
    – Hannes
    Commented Oct 20, 2019 at 22:03
  • 1
    @banan3'14 Hi there, I don't know about quitApplicationCmd, but the whole concept is still valid, I updated my article to contain the new solution (patch-the-fox): github.com/nilcons/…
    – errge
    Commented Jan 14, 2020 at 12:50
13
+200

You can change key bindings in Firefox with AutoConfig, without having to unpack and modify the Firefox binary.

Create a config-prefs.js and config.js file:

on Windows:

  • C:\Program Files\Mozilla Firefox\defaults\pref\config-prefs.js
  • C:\Program Files\Mozilla Firefox\defaults\pref\config.js

on macOS:

  • Firefox.app\Contents\Resources\config.js
  • Firefox.app\Contents\Resources\defaults\pref\config-prefs.js

on Linux:

  • /usr/lib/firefox/config.js
  • /usr/lib/firefox/browser/defaults/preferences/config-prefs.js

with the following content:

config-prefs.js:

pref("general.config.filename", "config.js");    
pref("general.config.obscure_value", 0);  
pref("general.config.sandbox_enabled", false);  

config.js:

try {
  let { classes: Cc, interfaces: Ci, manager: Cm  } = Components;
  const Services = globalThis.Services;
  const {SessionStore} = Components.utils.import('resource:///modules/sessionstore/SessionStore.jsm');
  function ConfigJS() { Services.obs.addObserver(this, 'chrome-document-global-created', false); }
  ConfigJS.prototype = {
    observe: function (aSubject) { aSubject.addEventListener('DOMContentLoaded', this, {once: true}); },
    handleEvent: function (aEvent) {
      let document = aEvent.originalTarget; let window = document.defaultView; let location = window.location;
      if (/^(chrome:(?!\/\/(global\/content\/commonDialog|browser\/content\/webext-panels)\.x?html)|about:(?!blank))/i.test(location.href)) {
        if (window._gBrowser) {

          // Place your keyboard shortcut changes here
          // ...
          // ...


        }
      }
    }
  };
  if (!Services.appinfo.inSafeMode) { new ConfigJS(); }
} catch(ex) {};

After modifying these files, you always have to go to about:support and run Clear startup cache, to restart the browser with the new config.

Some examples what you can do:

Put these snippets into config.js, where I wrote Place your keyboard shortcut changes here.

Remove an existing keyboard shortcut

// remove Ctrl-Shift-X, so that I can map it to 1Password in the 1Password app later
let keySwitchDirection = window.document.getElementById('key_switchTextDirection');
keySwitchDirection.remove();

Change an existing keyboard shortcut

// remap Ctrl-J to downloads (removing it from focusing the browser bar)
let search2 = window.document.getElementById('key_search2')
search2.remove();
let openDownloads = window.document.getElementById('key_openDownloads')
openDownloads.setAttribute("modifiers", "accel");
openDownloads.setAttribute("key", "J");

Create a new keyboard shortcut

// create keyboard shortcut to Toolbar > Settings with Ctrl-,
let settingsKey = window.document.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'key');
settingsKey.setAttribute("id", "key_Settings");
settingsKey.setAttribute("modifiers", "accel,shift");
settingsKey.setAttribute("key", "U");
settingsKey.setAttribute("oncommand", "openPreferences()");
settingsKey.addEventListener('command', this, false);
mainKeyset.appendChild(settingsKey);

Something completely custom. (Firefox introduced the Shift-Ctrl-T as an universal undo (change set), so the example here is not necessary anymore. I'll leave it here to serve as an example for other customizations.)

// make Ctrl-Shift-T reopen last tab OR last window, depending on which one was closed last
let undoCloseTabKey = window.document.getElementById('key_undoCloseTab');
undoCloseTabKey.removeAttribute('command');
undoCloseTabKey.setAttribute('oncommand', 'undoCloseLastClosedTabOrWindow()');
undoCloseTabKey.addEventListener('command', this, false);

window.undoCloseLastClosedTabOrWindow = function() {
  // don't have any tabs to restore
  if (SessionStore.getClosedTabCount(window) == 0) {
    // we don't need to worry whether there are any windows to restore - undoCloseWindow does that for us
    window.undoCloseWindow();
  }

  // don't have any windows to restore
  else if (SessionStore.getClosedWindowCount() == 0) {
    // we don't need to worry whether there are any tabs to restore - undoCloseTab does that for us
    window.undoCloseTab();
  }

  // restore whichever was closed more recently
  else if (SessionStore.getClosedTabData(window)[0].closedAt > SessionStore.getClosedWindowData()[0].closedAt) {
    window.undoCloseTab();
  } else {
    window.undoCloseWindow();
  }
}

Instructions:

To find existing keyboard shortcuts:

  • Hamburger menu > More Tools > Browser Toolbox
  • In the Inspector, search for #mainKeyset
  • There, you see all assigned keyboard shortcuts

To find menu actions that you can trigger with keyboard shortcuts

  • Hamburger menu > More Tools > Browser Toolbox
  • Use the Inspector to find the element that you want to trigger with a keyboard shortcut, for example appMenu-settings-button
  • Take the oncommand attribute from the menu item, and use it as oncommand attribute for the key tag

or

  • Use the Inspector, search for #mainCommandSet
  • and take the commands's id, and use it as command (not oncommand) attribute for the key tag.

Defining keyboard shortcuts:

  • specify modifiers with the modifiers attribute. You can use accel (for Ctrl), shift and alt
  • specify the key itself with the key attribute

Source for all of this: Reddit, u/aveyo, Restore Ctrl+Shift+B = Library by setting config.js

More details: Firefox Keyboard Shortcuts (Web Archive)

6
  • 8
    This answer is exceptionally well written, and seems to describe the best method for compatibility and long-term use. This is not user friendly though, the price to pay for Mozilla not providing this elementary function, a choice I cannot understand.
    – mins
    Commented Apr 30, 2023 at 11:24
  • 1
    Note: for Firefox 117, the script needs to be slightly updated. toolkit/modules/Services.jsm was removed in Firefox 117 (changelog) Commented Oct 3, 2023 at 7:10
  • 1
    in my case the config.js file SHALL start with a commented line otherwise FF fails at loading it Commented Dec 9, 2023 at 21:13
  • I'm new here, but, using a modern version of Firefox, searching for #mainKeyset using the Inspector tab of the Web Developer Tools doesn't return anything. Anyone know of a way to do this using newer Firefox versions? Thank you!
    – Bink
    Commented Feb 8 at 20:22
  • 1
    @BenediktKöppel Thanks for chiming back! Looks like the Browser Toolbox does not appear by default and appears to need devtools.chrome.enabled and devtools.debugger.remote-enabled to be set to true for it to appear.
    – Bink
    Commented Feb 9 at 19:29
5

If you use macOS, you can customize any app’s shortcuts as long as they appear in the application menus. Instructions for macOS 13+

  1. On your Mac, choose  menu > System Settings, click Keyboard in the sidebar (you may need to scroll down), then click Keyboard Shortcuts on the right.

  2. Select App Shortcuts on the left, click the Add button, click the Application pop-up menu, then choose a specific app or All Applications.

  3. In the Menu Title field, type the menu command for which you want to create a shortcut, exactly as the command appears in the app

More details on Apple’s site: https://support.apple.com/guide/mac-help/create-keyboard-shortcuts-for-apps-mchlp2271/mac

0
4

Here's another working example with the latest version of Firefox at the time of this writing (113.0) based on @Benedikt Köppel's answer. For debugging it can be helpful to use the function Services.prompt.alert(null, "Title", "Message") (mentioned here), in addition to logs which can be found under Tools > Browser Tools > Browser Toolbox > Console with Error and Warnings enabled on the top right.

firefox.cfg
// -*- mode: javascript; -*- vim: set ft=javascript:
// See https://support.mozilla.org/en-US/kb/customizing-firefox-using-autoconfig
"use strict";

(() => {
  if (Services.appinfo.inSafeMode) {
    return;
  }

  const addressPattern = new RegExp(
    "^(chrome:(?!//(global/content/commonDialog)\\.xhtml)|about:(?!blank))"
  );

  Services.obs.addObserver(subject => {
    const namespaceID =
      "autoconfig_" + subject.crypto.randomUUID().replaceAll("-", "_");
    subject.addEventListener(
      "DOMContentLoaded",
      event => {
        const document = event.originalTarget;
        const window = document.defaultView;
        if (!addressPattern.test(window.location.href)) {
          return;
        }

        // To find a key code ID, go to Tools > Browser Toolbox in Firefox and
        // click on the web inspector, then search for "keycode". Or go to this
        // URL view-source:chrome://browser/content/browser.xhtml
        const keyReloadSkipCache = document.getElementById(
          "key_reload_skip_cache"
        );
        keyReloadSkipCache?.setAttribute("modifiers", "accel,alt");

        const keyToggleReaderMode = document.getElementById(
          "key_toggleReaderMode"
        );
        keyToggleReaderMode?.setAttribute("modifiers", "accel,shift");

        const keyScreenshot = document.getElementById("key_screenshot");
        keyScreenshot?.setAttribute("modifiers", "accel,shift,alt");

        const keyUndoCloseTab = document.getElementById("key_undoCloseTab");
        keyUndoCloseTab?.setAttribute("modifiers", "accel,shift");
        keyUndoCloseTab?.setAttribute("key", "T");

        const keyUndoCloseWindow = document.getElementById(
          "key_undoCloseWindow"
        );
        keyUndoCloseWindow?.setAttribute("modifiers", "accel,control,shift");
        keyUndoCloseWindow?.setAttribute("key", "T");

        const keyPrivateBrowsing = document.getElementById(
          "key_privatebrowsing"
        );
        keyPrivateBrowsing?.setAttribute("key", "N");

        // Prefer Unclutter over default reader view.
        // https://unclutter.lindylearn.io
        const toggleUnclutterCommand = namespaceID + "_toggleUnclutter";
        window[toggleUnclutterCommand] = () => {
          // From about:debugging#/runtime/this-firefox > Unclutter >
          // Extension ID.
          const extensionID = "8f8c4c52-216c-4c6f-aae0-c214a870d9d9";
          const keyUnclutter = window.document.querySelector(
            `#ext-keyset-id-_${extensionID}_ > key`
          );
          keyUnclutter?.dispatchEvent(new window.CustomEvent("command"));
        };

        const readerModeButton = document.getElementById("reader-mode-button");
        readerModeButton?.setAttribute(
          "onclick",
          toggleUnclutterCommand + "();"
        );
        const readerViewCommand = document.getElementById("View:ReaderView");
        readerViewCommand?.setAttribute(
          "oncommand",
          toggleUnclutterCommand + "();"
        );
      },
      { once: true }
    );
  }, "chrome-document-global-created");
})();
defaults/pref/autoconfig.js
// See https://support.mozilla.org/en-US/kb/customizing-firefox-using-autoconfig
pref("general.config.filename", "firefox.cfg");
pref("general.config.obscure_value", 0);
pref("general.config.sandbox_enabled", false);

I recommend running firefox.cfg (or config.js in the above answer) against Mozilla's ESLint plugin which shows warnings I could not find documented anywhere else. E.g., it gives this error when using Components.utils.import:

error  Please use ChromeUtils.import instead of Cu.import  mozilla/use-chromeutils-import
error  Use Cu rather than Components.utils                 mozilla/use-cc-etc

It can be installed via npm install eslint-plugin-mozilla --save-dev.

Here's an example .eslintrc.json:

{
  "extends": [
    "eslint:recommended",
    "plugin:mozilla/recommended"
  ],
  "plugins": [
    "mozilla"
  ]
}

macOS Persistent Installation

Unfortunately, since on macOS these files must be placed in the application bundle, they can get wiped after updates. This can be worked around by setting up a path watcher script using either Launchd or Hammerspoon.

firefox_apply_autoconfig
#!/bin/sh
set -o errexit -o nounset

FIREFOX_PATH="/Applications/Firefox.app"
FIREFOX_RESOURCES_PATH="$FIREFOX_PATH/Contents/Resources"

# Path to directory containing firefox.cfg and `defaults/autoconfig.js` (or
# equivalent).
AUTOCONFIG_DIR="/patch/to/autoconfig"

main() (
    if [ ! -d "$FIREFOX_PATH" ]; then
        echo "Application does not exist at $FIREFOX_PATH; aborting."
        exit 1
    fi

    cd "$FIREFOX_RESOURCES_PATH"
    mkdir -p ./defaults/pref
    cd "$AUTOCONFIG_DIR"
    find . -type f | while read -r file; do
        relpath="$(echo "$file" | cut -c3-)"
        target="$FIREFOX_RESOURCES_PATH/$relpath"
        source="$(realpath "$file")"
        rsync --archive "$source" "$target"
    done

    # Avoid macOS sandbox warning when Firefox is reinstalled about the app
    # bundle being modified.
    xattr -rd com.apple.quarantine /Applications/Firefox.app

    echo "Installed Firefox autoconfig files."
)

main
Launchd (Option 1)
com.superuser.firefox-apply-autoconfig.plist
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.superuser.firefox-apply-autoconfig</string>
    <key>Program</key>
    <string>/Users/username/Library/Application Support/com.superuser.launchd/firefox_apply_autoconfig</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Users/username/Library/Application Support/com.superuser.launchd/firefox_apply_autoconfig</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Applications/Firefox.app/Contents/Resources/</string>
    </array>
    <key>ProcessType</key>
    <string>Background</string>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
Installation

Then run something like this:

mkdir -p "/Users/username/Library/Application Support/com.superuser.launchd/"
chmod u+x ./firefox_apply_autoconfig
mv ./firefox_apply_autoconfig "/Users/username/Library/Application Support/com.superuser.launchd/"

launchctl bootstrap "gui/$(launchctl manageruid)" ./com.superuser.firefox-apply-autoconfig.plist
Hammerspoon (Option 2)
init.lua
local function applyFirefoxAutoConfig()
  hs.task.new(
    os.getenv("HOME")
    ..
    "/.config/hammerspoon/scripts/firefox_apply_autoconfig",
    nil
  ):start()
end

local watcher = hs.pathwatcher.new(
  "/Applications/Firefox.app/Contents/Resources/",
  applyFirefoxAutoConfig
):start()

applyFirefoxAutoConfig()

Caveats

general.config.sandbox_enabled must be set to false (default value) in order for ChromeUtils to be defined in the autoconfig file. See this comment.

2

I am not sure what kind of shortcuts you are after but there is a great extensions called Vimium FF that allows you to browse completely mouseless. This extensions offers a filter mechanism that allows you to decide in which websites the keybindings should work.

It is still in experimental stage, since it is a port from a Chrome extensions but I am using and did encounter any bug or problem.

The bindings follow the VIM bindings and should be natural if you are already familiar with those, otherwise, you can custumize them to your own taste.

2

EDIT: now removed From Firefox support: https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly :

Note: You can customize keyboard shortcuts for Firefox using the https://addons.mozilla.org/firefox/addon/saka-key/ extension.

I hope it is what you were looking for.

5
  • 4
    Thanks, unfortunately this extension is not so practical. If it would work, this one: github.com/mikecrittenden/shortkeys would be nice. But it seems like, Firefox is allowing websites to suppress the bindings, which is super annoying when your bindings only work on a few sites :(
    – Finn
    Commented Dec 18, 2017 at 10:33
  • 2
    Fully agree, they need to find a good workaround to fix it
    – Foxhole
    Commented Apr 28, 2018 at 15:04
  • 2
    Keyboard shortcut documentation has nothing to do with changing keybindings.
    – Tony
    Commented Sep 27, 2020 at 1:33
  • Firefox documentation on key bindings doesn't invite to use the extension mentioned in the answer, or they stopped for some reason.
    – mins
    Commented Apr 30, 2023 at 11:04
  • Thank you, I think it is now an outdated reply!
    – Foxhole
    Commented May 1, 2023 at 12:03
2

Benedikt's answer is very well written, but with one thing missing. The first line of config.js is ignored, starting on 1st line will eventually cause syntax error. So simply change it to something like this should do the trick.

// IMPORTANT: Start your code on the 2nd line
try {
...

This is mentioned in official document of AutoConfig and also https://github.com/xiaoxiaoflood/firefox-scripts, where the reddit post borrows idea from.

1

If your intent is to change the shortcut of an extension, you can do so: https://support.mozilla.org/kb/manage-extension-shortcuts-firefox

  1. Click the (hamburger) menu button, click Add-ons and themes and select Extensions.
  2. Click the Tools for all add-ons cogwheel.
  3. Click Manage Extension Shortcuts in the menu.

You will see the shortcut options (if available) for your installed add-ons.

Screenshot for Manage Extension Shortcuts

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .