Armaan Bhojwani

Custom Keymap

Last modified on Changelog.

I make some modifications to the default US keyboard layout to improve ergonomics.

The keyboard

On this page I’ll be talking just about the keyboard on my Dell XPS 13 9360. It’s a standard US laptop keyboard layout with a chiclet mechanism. I’ll have another page for the keymap on a separate, mechanical keyboard.

Caps lock

The main modification that I do is with the caps lock key. Caps lock is one of the least useful functions on the keyboard, but it occupies the most useful spot on the keyboard. Because of this, I remap caps lock to the two (!) keys that I use most, control and escape. Control I just use in normal keybindings (especially in Emacs), and escape I use a lot because I use Vi keybindings. These two keys by default are at the far ends of the keyboard, which makes no sense given how frequently they are used. In my setup, if I tap on the caps lock key, it acts as escape, but if I hold it, it acts as control. This lets me have two functions in one key, and because I never need to just tap control or hold escape, they do not interfere with each other. To make up for the lost caps lock functionality, I map the traditional control key to caps lock. In the end, I have a layout with a swapped caps lock and control key, and two escape keys.


I use two tools to implement this in X11, setxkbmap, which is a standard Xorg app, and xcape. I have the following commands run as part of an autostart script that runs whenever I enter Xorg:

setxkbmap -option "ctrl:swapcaps"
pkill xcape ; xcape

The first command just swaps control and caps lock. This is already a great improvement, but I still don’t have the escape functionality. This is where xcape comes into play. When run with the default option, xcape will do exactly what I need it to, making tapping the control key (which is now in the caps lock spot) execute escape. The pkill before it simply kills off any other running xcape processes, because if they stack, some odd behaviors can occur.


I use Vim bindings wherever I can. Unfortunately there are still some places where in order to have keyboard control, I need to use the arrow keys. This is highly inefficient for me because I need to move my whole right hand down to the arrow keys. As a solution, I bind Alt+Tab+{H,J,K,L} to left, down, up, and right. This makes it much easier for me to navigate programs like Firefox without needing to move my hand far from the home row. Alt+Tab isn’t the easiest to reach, however its the easiest binding that I could find that wouldn’t interfere with anything else, and I can chord it with my left hand, leaving my right hand for {H,J,K,L}.


I implement this in my window manager (Spectrwm)’s configuration file using the xdotool utility. xdotool is great for automating Xorg tasks like this. I have the following in my configuration:

program[h] = xdotool keyup h key --clearmodifiers Left
program[j] = xdotool keyup j key --clearmodifiers Down
program[k] = xdotool keyup k key --clearmodifiers Up
program[l] = xdotool keyup l key --clearmodifiers Right

bind[h] = Mod1 + Tab + h
bind[j] = Mod1 + Tab + j
bind[k] = Mod1 + Tab + k
bind[l] = Mod1 + Tab + l

Mod1 is equivalent to Alt here. Every time I hit Mod+Tab+{H,J,K,L}, it calls xdotool to clear all the modifiers and input the correct arrow key direction.

Hardware implementations

If you have a keyboard that uses QMK or similar firmware, this functionality can be baked right into the keyboard, which has the advantage of being plug and play on any system, and not requiring a daemon to run in the background. Because this is for my laptop, which uses proprietary firmware, I unfortunately cannot do that here.