patching firefox
in its vim configuration, it has the binds <M-j> and <M-k> to move forwards and backwards through the tabs it has open. it wanted to duplicate such keybindings in firefox.
in its naïveté, it believed this to be a thing one could do reasonably. it did not account for the fact that mozilla is mozilla, and has
somehow managed to make a web browser with no reasonable means of rebinding keys. it being natalie, it of course did not let this stop it.
it has found that mozilla's documentation really really sucks.[1] accordingly, figuring out how the hell to change keybinds was an exercise in repeated grepping. this process took more effort than any attempt to rebind keys reasonably should, and thus it is documenting the results of its numerous grep commands so as to aid those who may wish to avoid such mozillaisms in the future. it makes no claims as to the reliability or correctness of its appoach. also, the reader should probably just use some
browser plugin to change keybinds, unless they like compiling things.
what the fuck, mozilla?
firefox seems to define keybinds in fucking xhtml files that (sometimes!) get run through the c preprocessor. why this is is a mystery (it presumes this is some inherited trait from netscape or something) to this one, and it is probably best left that way,
lest this one become more afraid of computers. the way keybinds are defined within these xhtml documents is as a series of key elements. these are contained within a keyset element. as far as it can tell, keysets are used to define when specific keybinds should be active (eg. binding certain keys when a menu is open, which would otherwise be bound to different actions or unbound). important
attributes key elements may contain are enumerated below, as well as their presumed meaning.
key- the name of a key to bind (eg. "a").
keycode- the keycode of a key to bind (eg. "VK_ESCAPE").
modifiers- a comma seperated list of modifiers. accel is analogous to control (except for on the apple platform, in which case it is command).
data-l10n-id- name of the binding for localization. this sometimes defines keys or keycodes based off of data from a .ftl[2] file.
command- the name of a command (defined by a
commandelement) the binding will execute.
command elements are similary complex, however it has only found need to understand one attribute of theirs: id.
this attribute can be referenced by key elements to call that command (via the command attribute of the key element).
command behavior seems to be defined in javascript code, but it hasn't looked in to this as it has not found need to define new commands.
anyways, after some amount of random grepping, it found the following:
browser/base/content/browser-sets.inc
81: <command id="Browser:NextTab" />
accessible/tests/mochitest/events/test_selection.xhtml
22: function advanceTab(aTabsID, aDirection, aNextTabID)
25: new invokerChecker(EVENT_SELECTION, aNextTabID)
30: new invokerChecker(EVENT_HIDE, getAccessible(aNextTabID)),
31: new invokerChecker(EVENT_SHOW, aNextTabID)
43: return "advanceTab on " + prettyName(aTabsID) + " to " + prettyName(aNextTabID);
this is indeed the command to focus the next tab. it initially tried finding it by looking for its default keybinding (alt + pageup), but for some reason it coud not find this.
immediately below the NextTab command was the PrevTab command. accordingly, it simply added the following to the file this was found in, within <keyset id="mainKeyset">
<key id="key_prevTab" modifiers="alt" key="j" command="Browser:PrevTab"/>
<key id="key_nextTab" modifiers="alt" key="k" command="Browser:NextTab"/>
it doesn't think the id attributes are necessary, but other key elements had them, so it arbitrarily filled them in. it is worth noting that for rebinding other keys, it might be
more appropriate to edit whatever .ftl file they are defined in, rather than modifying the xhtml definition.
here is a patch if the reader is interested
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: natalie roentgen connolly <natalie+git@natalieee.net>
Date: Sun, 14 Sep 2025 02:17:51 -0700
Subject: [PATCH] rebind tab navigation keys
---
browser/base/content/browser-sets.inc | 2 ++
1 file changed, 2 insertions(+)
diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc
index 2e7654036647..9df4201f9e42 100644
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -164,6 +164,8 @@
modifiers="accel"
#endif
command="Tools:Downloads"/>
+ <key id="key_prevTab" modifiers="alt" key="j" command="Browser:PrevTab"/>
+ <key id="key_nextTab" modifiers="alt" key="k" command="Browser:NextTab"/>
<key id="key_openAddons" data-l10n-id="addons-shortcut" command="Tools:Addons" modifiers="accel,shift"/>
<key id="openFileKb" data-l10n-id="file-open-shortcut" command="Browser:OpenFile" modifiers="accel"/>
<key id="key_savePage" data-l10n-id="save-page-shortcut" command="Browser:SavePage" modifiers="accel"/>
--
2.50.1
hacking the css parser
since it was already patching firefox—and since it doesn't like rounded corners—it decided to remove the ability for border and border-corner radii css properties to be nonzero. this was really quite simple compared to figuring out how to modify keybinds, despite the fact that it doesn't know rust. the css parser is layed out much more comprehensibly than the ui code. it doesn't have much interesting to say about this part because of how simple it was.
here is another patch
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: natalie roentgen connolly <natalie+git@natalieee.net>
Date: Sun, 14 Sep 2025 02:27:55 -0700
Subject: [PATCH] force border and border-corner radii to be zero
---
.../style/values/specified/border.rs | 26 +++++++------------
1 file changed, 9 insertions(+), 17 deletions(-)
diff --git a/servo/components/style/values/specified/border.rs b/servo/components/style/values/specified/border.rs
index 68944339576c..f7f1b635119b 100644
--- a/servo/components/style/values/specified/border.rs
+++ b/servo/components/style/values/specified/border.rs
@@ -247,32 +247,24 @@ impl Parse for BorderImageSlice {
impl Parse for BorderRadius {
fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
+ _context: &ParserContext,
+ _input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
- let widths = Rect::parse_with(context, input, NonNegativeLengthPercentage::parse)?;
- let heights = if input.try_parse(|i| i.expect_delim('/')).is_ok() {
- Rect::parse_with(context, input, NonNegativeLengthPercentage::parse)?
- } else {
- widths.clone()
- };
-
Ok(GenericBorderRadius {
- top_left: BorderCornerRadius::new(widths.0, heights.0),
- top_right: BorderCornerRadius::new(widths.1, heights.1),
- bottom_right: BorderCornerRadius::new(widths.2, heights.2),
- bottom_left: BorderCornerRadius::new(widths.3, heights.3),
+ top_left: BorderCornerRadius::zero(),
+ top_right: BorderCornerRadius::zero(),
+ bottom_right: BorderCornerRadius::zero(),
+ bottom_left: BorderCornerRadius::zero(),
})
}
}
impl Parse for BorderCornerRadius {
fn parse<'i, 't>(
- context: &ParserContext,
- input: &mut Parser<'i, 't>,
+ _context: &ParserContext,
+ _input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
- Size2D::parse_with(context, input, NonNegativeLengthPercentage::parse)
- .map(GenericBorderCornerRadius)
+ Ok(GenericBorderCornerRadius::new(NonNegativeLengthPercentage::zero(), NonNegativeLengthPercentage::zero()))
}
}
--
2.50.1
it does so love what it has taken to calling "sharp firefox." all web browsers should be like this.
comments
as an anti-bot measure, in order for $VIEWER's comment to be stored on the server, $VIEWER MUST enter the commit hash of the current deployment found in the bottom right of the page footer. failure to do so will result in the comment being disregarded.
really wish the current state of every web browser wasn't either this or chromium :(