Caps Lock as Escape and Control key
For the last few months I have been using Helix. As a modal editor, it depends a lot on the CTRL (Control) and ESC (Escape) keys. When I was using Emacs, I used to map Caps Lock to CTRL. But recently I knew it’s possible to map Caps Lock to work as ESC when tapped, and CTRL when long pressed with another key.
I use three keyboards:
- At home, I use Keychron V10 Max.
- At work, I use Keychron K3 Pro.
- And when I’m away from desk, I use the laptop keyboard.
Mapping the Keychron Keyboards
Both V10 Max and K3 Pro keyboards can be programmed by the Keychron Launcher. Both keyboards are programmed by QMK open source firmware. QMK provides a key called Mod-Tap. Keys mapped to Mod-Tap will work as modifier (e.g. Control, Shift, Alt) when held, and as regular keys when tapped.
In Keychron Launcher the Mod-Tap key is mapped using the Any key mapping (highlighted below):

The Caps Lock can be mapped to CTRL and ESC by setting Any to MT(MOD_LCTL, KC_ESC) or CTL_T(KC_ESC) (alias provided by QMK for convenience).
In QMK Docs there are other Mod-Tap keys that can be mapped.
Mapping the Laptop Keyboard
For the laptop keyboard, evremap (from the developer of the awesome WezTerm terminal) was the easiest option (basically followed the README):
-
Installed evremap.
-
Created
/etc/evremap.tomldevice_name = "AT Translated Set 2 keyboard" [[dual_role]] input = "KEY_CAPSLOCK" hold = ["KEY_LEFTCTRL"] tap = ["KEY_ESC"] -
Created the systemd service
/usr/lib/systemd/system/evremap.serviceto runevremapas daemon:[Service] WorkingDirectory=/ ExecStart=bash -c "/usr/local/bin/evremap remap /etc/evremap.toml -d 0" Restart=always [Install] WantedBy=multi-user.target -
Enabled the
evremap.servicesystemd service:systemctl daemon-reload systemctl enable evremap.service systemctl start evremap.service
As of this writing, a evremap process handles one keyboard device only. To map the Caps Lock in more than one keyboard, every one must have separate evremap process configured with separate evremap.toml file. Only the device_name parameter must be updated for every configuration file.