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:

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):

Any key in keychron launcher

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):

  1. Installed evremap.

  2. Created /etc/evremap.toml

    device_name = "AT Translated Set 2 keyboard"
    
    [[dual_role]]
    input = "KEY_CAPSLOCK"
    hold = ["KEY_LEFTCTRL"]
    tap = ["KEY_ESC"]
    
    
  3. Created the systemd service /usr/lib/systemd/system/evremap.service to run evremap as daemon:

    [Service]
    WorkingDirectory=/
    ExecStart=bash -c "/usr/local/bin/evremap remap /etc/evremap.toml -d 0"
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    
    
  4. Enabled the evremap.service systemd 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.