Motivation

When I was using a Macbook, after reading Modern Space Cadet by Steve Losh in 2014, I decided to apply some of the suggestions from that article. I first tried the Caps Lock mapping. Which is basically caps lock is acting as a Control key when pressed with another key and Escape when pressed alone. I liked that. After one week or so, I tried another suggestion from the same article: Better Shifting which is way more fun and efficient than my previous attempt. When pressed alone, left and right shift keys act as left and right brackets, respectively. (( and ))

Control keys and brackets are being used very frequently while coding. And in the long term, with these small mappings, my productivity increased dramatically. So, the first struggling thing for me after migrating to Linux was the lack of a tool like Karabiner Elements to enable complex modifications on your keyboard layout.

After a few attempts, I finally achieved the same functionality as my days in macOS. I am using some set of plugins/programs under the interception project. Let’s start:

Installing Programs

Here is the list of the required programs:

You can also find detailed instructions on the repositories to install and configure these programs.

Before start install these packages:

sudo apt install libboost-dev libudev-dev libyaml-cpp-dev libevdev-dev cmake build-essential

Note: If libboost-dev does not work on your case, try to install libboost-all-dev.

OK. I like to keep all related programs and config files under the same directory. So, create a container folder for config files and source codes:

cd # go home
mkdir -p .modern-space-cadet/src # create a src folder to clone and compile our programs
cd .modern-space-cadet/src

Now we are inside the src folder. Let’s clone our programs:

git clone https://gitlab.com/interception/linux/tools
git clone https://gitlab.com/interception/linux/plugins/dual-function-keys

First, install interception-tools package:

cd tools
mkdir build
cmake ..
make
sudo make install
cd ../../

Now, install dual-function-keys:

cd dual-function-keys
make && sudo make install

Config and Service Files

Create a udevmon.yaml file under /etc/:

sudo vim /etc/udevmon.yaml

paste below and save:

- JOB: "intercept -g $DEVNODE | dual-function-keys -c /home/ali/.modern-space-cadet/dual-function-keys.yaml | uinput -d $DEVNODE"
  DEVICE:
    EVENTS:
      EV_KEY: [KEY_LEFTSHIFT, KEY_RIGHTSHIFT, KEY_CAPSLOCK]

Do not forget to replace /home/ali/ part with your username.

If you would like to map or listen another keys other than shifts and caps lock, you should update the EV_KEY section.

Create a systemd service to make it persistent:

sudo vim /etc/systemd/system/udevmon.service

and paste below:

[Unit]
Description=udevmon
Wants=systemd-udev-settle.service
After=systemd-udev-settle.service

[Service]
ExecStart=/usr/bin/nice -n -20 /usr/local/bin/udevmon -c /etc/udevmon.yaml

[Install]
WantedBy=multi-user.target

Remember, we passed a config file to our udevmon program. Now create that file:

vim ~/.modern-space-cadet/dual-function-keys.yaml

Here we are defining our config to achieve the better shifting and Caps Lock mapping:

# https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
TIMING:
  TAP_MILLISEC: 200
  DOUBLE_TAP_MILLISEC: 0

MAPPINGS:
  - KEY: KEY_LEFTSHIFT
    TAP: [KEY_LEFTSHIFT, KEY_9]
    HOLD: KEY_LEFTSHIFT
  - KEY: KEY_RIGHTSHIFT
    TAP: [KEY_RIGHTSHIFT, KEY_0]
    HOLD: KEY_RIGHTSHIFT
  - KEY: KEY_CAPSLOCK
    TAP: KEY_ESC
    HOLD: KEY_LEFTCTRL

The URL in the first line is a link to event codes in Linux. I prefer to keep that as a reference in this config file. You can see string representations of all keys.

Finally enable udevmon service:

sudo systemctl enable --now udevmon
sudo systemctl start udevmon

Check the status of our service:

sudo systemctl status udevmon

Other Interception Plugins

There are a few official plugins under interception project. One of them is caps2esc:

You can have more control over Caps Lock and Esc key and the relation between those. Or, you can use this plugin and ignore the above configs if the only customization you want is swapping Caps Lock and Esc.

Keyboards

I also would like share some info about my keyboards. Although I mostly spend my time with my Thinkpad’s built-in keyboard after migrating to Linux, I do have 2 mechanical keyboards.

Keychron K2

Very nice keyboard. I bought it from Kickstarter. It has a 4000 mAh battery, I believe. I use it for a month with a single charge. It has Blue switches which is the most satisfying switch for me (“It is pure terrorism” my wife would say if you ask her.)

CM Storm Quickfire Stealth

My first mechanical keyboard. It is with brown switches. After 6 years, it is still working like day one. It is pretty heavy and solid. Not sure if the vendor still manufactures this device.

Thinkpad’s Keyboard

Ok, it is not a mechanical keyboard. But it has the closest satisfaction. No wonder why so many people are being a fan of this rock-solid machine.

Closing Words and Compatibility

Before dual-function-keys I was using xcape for better-shifting. And Gnome’s keyboard setting was there to remap the caps lock. But xcape is not under active development for a while and I had performance / stucking problems while using it. With dual-function-keys I can manage all my customization from one place. Which is basically the same thing as what Karabiner Elements does. (without a GUI, of course).

I have been using dual-function-keys for a month. And I can confirm that it is working on both Ubuntu (20.04, 20.10) and Fedora 33.

There was an issue on GTK-based apps when used under Wayland but it has been resolved thanks to the maintainer. Now it works under both X and Wayland without a glitch.

That’s it. Thanks for reading.