Friday 22 February 2019

Changing key bindings of Firefox Quantum with xdotools

Firefox does not allow to change its key bindings since the Quantum series. There are extensions for that but none of them work as it should be. E.g. on built-in pages like the homepage or the about:blank page or when the URL bar is focused these extensions fail. There have been bug tickets about this issue for half a year now but sadly Mozilla is not doing anything to make its browser as flexible as it used to be in its pre-Quantum versions.

I have read ideas about changing the contents of the omni.ja file but anything I did it broke Firefox. At the same time this is a very dirty way of getting the job done as we have to change the installed files of Firefox meaning that an update can ruin our changes.

After quite a long research I found an idea to change key bindings at OS level "tricking" Firefox to accept key presses. The process contains of two steps:
  1. We create a small shell script that checks if the active window is Firefox and if it is then it sends a key combination to it. Like that we can send a command (like "close tab", undo "close tab", etc. ) to the browser by sending Firefox's defined key combination ("ctrl+w", "ctrl+shift+t", etc. respectively) to the Firefox window. The commands and their key combinations can be checked under the Help menu of Firefox. The script uses xdotools to send the key combination.
  2. We assign a key binding in our window manager to run the script (i.e. send the given command to the browser). Like that we can set up our key bindings in OS (or WM) level independently of Firefox.
In practice the two steps:

1. Creating the script:
I have created the script called mozkey.sh that accepts a Firefox command as argument and sends the appropriate key combination to Firefox. You have to install xdotool for this script to work.
/home/$USER/bin/mozkey.sh:
windowname="Firefox Nightly"
#windowname="Mozilla Firefox"

commands=(
"closetab;ctrl+w"
"undoclosetab;ctrl+shift+t"
)

# We check if the active window is a FF one, if so we store its id
if windowid=$(xdotool search --name "$windowname" | grep $(xdotool getactivewindow))
then
    for i in ${commands[@]}
    do
        [[ "$1" == "${i%%;*}" ]] && xdotool key --window "$windowid" "${i#*;}"
    done
fi

The windowname variable contains a pattern that fits the Firefox browser window. You can use xprop and check the WM_NAME attribute or simply read the window name in your window title to determine a correct pattern. I have Firefox Nightly build installed and its name always contain the string "Firefox Nightly".

The script accepts "closetab" or "undoclosetab" as argument but you can edit it to your liking and add more commands to the array with a new line of "<commandname>;<Firefox default binding>".

Its usage is very simple, the script accepts one argument which is the command to be sent to Firefox:
mozkey.sh <command>

It sends the appropriate key combination to Firefox.
mozkey.sh closetab sends ctrl+w, hence closes the actual tab.
mozkey.sh undoclosetab sends ctrl+shift+t, hence reopenes the last closed tab.


The script does nothing if you run it from a terminal because it checks if the active window is Firefox and if it is not (like in this case your active window is your terminal) then does nothing.



2. Defining your bindings:

I have set up my Awesome WM keybindings to run the script like this:

Pressing ctrl+0 executes /home/$USER/bin/mozkey.sh closetab
Pressing ctrl+1 executes /home/$USER/bin/mozkey.sh undoclosetab

My appropriate Awesome WM config lines are:

.config/awesome/rc.lua:

    -- Firefox key hack
    awful.key({ "Control" }, "0", function () awful.spawn("/home/$USER/bin/mozkey.sh closetab") end),
    awful.key({ "Control" }, "1", function () awful.spawn("/home/$USER/bin/mozkey.sh undoclosetab") end),

If you use another window manager set your bindings according to its configuration.

Now, in a Firefox window I press ctrl+0 and it closes the tab. I press ctrl+1 and it reopens the last closed tab.

Possible issues:
 
The thing is new, I haven't tested it a lot. Its caveat can be conflicting bindings. If you want to use a WM key binding which already exists in Firefox for another function that might cause problems since Firefox will get two key combinations at the same time.

No comments:

Post a Comment