Since the 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?
Super User is a question and answer site for computer enthusiasts and power users. It only takes a minute to sign up.
Sign up to join this communitySince the 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?
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.
browser.xul
was renamed to browser.xhtml
: userchrome.org/firefox-changes-userchrome-css.html#fx69
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:
#mainKeyset
To find menu actions that you can trigger with keyboard shortcuts
appMenu-settings-button
oncommand
attribute from the menu item, and use it as oncommand
attribute for the key tagor
#mainCommandSet
id
, and use it as command
(not oncommand
) attribute for the key tag.Defining keyboard shortcuts:
modifiers
attribute. You can use accel
(for Ctrl), shift
and alt
key
attributeSource for all of this: Reddit, u/aveyo, Restore Ctrl+Shift+B = Library by setting config.js
More details: Firefox Keyboard Shortcuts (Web Archive)
toolkit/modules/Services.jsm
was removed in Firefox 117 (changelog)
Oct 3 at 7:10
If you use macOS, you can customize any app’s shortcuts as long as they appear in the application menus. Instructions for macOS 13+
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.
Select App Shortcuts on the left, click the Add button, click the Application pop-up menu, then choose a specific app or All Applications.
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
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.
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.
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.
// -*- 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");
})();
// 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"
]
}
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.
#!/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
<?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>
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
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()
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.
If your intent is to change the shortcut of an extension, you can do so: https://support.mozilla.org/kb/manage-extension-shortcuts-firefox
- Click the (hamburger) menu button, click Add-ons and themes and select Extensions.
- Click the Tools for all add-ons cogwheel.
- Click Manage Extension Shortcuts in the menu.
You will see the shortcut options (if available) for your installed add-ons.
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.