How To Map Caps Lock To Escape And Control On Fedora Via Caps2esc
Mapping caps lock to escape when pressed once and control when held makes a lot of sense. Many combinations become easier and more comfortable. More time spent on the home row leads to speedier Vim usage.
MacOS and Windows have plenty of support already by software such as Karabiner or AutoHotKey. When it comes to Linux/GNOME, XCape would be the comparable option. I tried it out for a couple of weeks, played with its configuration, and found that it didn't keep up.
Seeing as the main point of this rebinding is largely Vim-fu, making several quick keystrokes involving a change of mode has to work perfectly. Unfortunately, XCape frequently misses input causing minor confusion at best and leaving you making random incorrect keystrokes in Normal mode at worst.
I did locate an issue for this but it will take some time to fix. Luckily there is another option. caps2esc is a piece of software that sits closer to Linux's input layer than XCape. Trying it out, I have observed no lag issue and it does feel faster. If you're not used to compiling code from source, it's a little harder to install, but let me save you some time and show you how.
Building and Installing
Caps2esc depends on a second library called Interception Tools. You'll need to compile and install both.
cd ~/your/code/directory
git clone https://gitlab.com/interception/linux/tools interception_tools
git clone https://gitlab.com/interception/linux/plugins/caps2esc
Interception Tools needs some libraries. The readme indicates which ones and here's how to get them on Fedora:
sudo dnf install cmake yaml-cpp-devel libevdev-devel systemd-devel -y
Build each according to their readme. Run sudo make install
in each build directory and verify correct installation:
which udevmon
which caps2esc
Configure Interception Tools
Their readme provides a configuration example:
- JOB: "intercept -g $DEVNODE | y2z | x2y | uinput -d $DEVNODE"
DEVICE:
EVENTS:
EV_KEY: [KEY_X, KEY_Y]
The step in the pipeline where you see y2z
/ x2y
is the point where you plug caps2esc in. We also need to specify the keys to intercept -- KEY_CAPSLOCK
and KEY_ESC
. Create this file at something like /etc/caps2esc.yaml
:
- JOB: "intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE"
DEVICE:
EVENTS:
EV_KEY: [KEY_CAPSLOCK, KEY_ESC]
Daemonize Udevmon
Now you need to daemonize udevmon
. It's a service and ultimately what listens for caps lock input when fed your YAML config file. You'll add it to Systemd so that it will start on bootup and continously run in the background.
/etc/systemd/system/caps2esc.service
:
[Unit]
Description=caps2esc
[Service]
ExecStart=/usr/bin/nice -n -20 /usr/local/bin/udevmon -c /etc/caps2esc.yaml
[Install]
WantedBy=multi-user.target
With your newly added .service file, you should now be able to manage it via systemctl
:
sudo systemctl daemon-reload
sudo systemctl enable caps2esc # Start on bootup
sudo systemctl start caps2esc # Start now too
Now try pressing Caps + C. If you see it working the same way a Ctrl + C works in your terminal (goes to a new clear line), it's now working.
Repurpose your freed up keys
You have now freed up two convenient keys on your keyboard. You can experiment with remapping them to other useful functions. Looking at your escape key, it now behaves as Caps Lock so it still has toggling behavior. You can make it behave like a simple keypress by adding this to .bashrc
:
setxkbmap -option ctrl:nocaps # Unbind capslock (escape)
You can use xev
to show debug information about keyboard input. Note the keycode
:
xev -event keyboard
Bring its small window to the foreground and try pressing escape. You should see something like:
KeyPress event, serial 28, synthetic NO, window 0x5a00001,
root 0x14e, subw 0x0, time 15226248, (1188,694), root:(1233,803),
state 0x0, keycode 66 (keysym 0xffffff, VoidSymbol), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
With the correct keycode, you can remap it to something useful. For example, you could make your escape key run your nearest test. In .bashrc
:
xmodmap -e 'keycode 66=minus' # Rebind capslock (escape) to '-'
You can then remap hyphen to run Vim command :TestNearest
, assuming you're using vim-test
. In .vimrc
or init.vim
:
noremap - :w<CR>:TestNearest<CR>
As you can tell you can really get creative. You can do the same for your freed up Control_L
key, but tread carefully (read on).
See also a full list of keysyms that work with xmodmap
.
Opening links in new tabs
Before this remap, I didn't even realize how often I control + clicked on links in browsers and in my terminal emulator. Sadly that does not work with caps2esc. Without getting into browser extensions, we're left leaning on the right click context menu to open in a new tab, or shift + clicking to open them in a new window. Hoping the maintainer will eventually address the issue.
Crouching in games
If you are a gamer, caps lock likely won't feel natural. I found it behaved pretty squirrely depending on what you were trying to do. For that reason you may not want to remap your control key.
So that's where I'm at. Overall, more than worth it to remap. Your pinky will thank you.