Remap modifiers in Linux Desktop and Alacritty
Mac bindings in Linux, the ultimate solution
I’m used to macOS’s key binding, that means for a desktop environment, I want three things:
- Caps lock act as Control
- System bindings are on the Command key (ie, the Windows key), specifically, Command+C/V for copy/paste
- In the terminal emulator, Command+C/V works as usual, and Ctrl+C/V sends respective control codes, as usual
I’m a simple man, and this is all I want, but Thy Voice From Above hath spoken: “lol no think again”
Command+C/V for copy and paste
Remapping Caps lock to Control is easy and there are plenty tutorials online for it. However, there is absolutely no way to change the default bindings of copy/paste on a Linux desktop reliably. Because there is simply no unified configuration for the keybinding of copy & paste. Qt supports rebinding copy & paste and Gtk straight up doesn’t support it1. On top of that, applications bind their own keys and completely disregard the toolkit’s setting, except in some toolkit widgets they use, then you have different bindings within the same application.
The whole situation is pretty laughable, but live must go on. There are things like xkeysnail2 that literally intercepts every keystroke you type and translate them into other keys depending on the application currently in focus. It requires some nontrivial configuration and may or may not work reliably on X11, definitely doesn’t work on Wayland3, and I don’t know how do I feel about a Python program running as root, intercepting and translating every key I type. There are Rust alternatives, but I didn’t have much luck with those either.
The real way, the only good way, to do it is to just swap Control with Super (ie, Command) at X11 level. (Wayland picks it up so it works on Wayland too, or so I’m told). Since we also want to swap Caps lock and Control, we actually do a three-way swap:
- Super → Control
- Control → Caps lock
- Caps lock → Super
So now when you press Command+C, the application gets Control+C.
To actually swap the modifiers, we edit
/usr/share/X11/xkb/keycodes/evdev
and reboot—no adding command to X init or some config file or some other crap. You edit the file, reboot, and it works, and keeps working. I learned this from a StackExchange question.
Below are the exact edit you need to make in that file, and their effect:
To map Left Control (keycode 37) to Caps lock:
Change <CAPS> = 66
to <CAPS> =
37
To map Left Super (keycode 133) to Control:
Change <LCTL> = 37
to <LCTL>
133
To map Caps lock (keycode 66) to Left Super:
Change <LWIN> = 133
to <LWIN> =
66
If you use Emacs, you need to swap Super and Control back. Add this to your init.el:
(setq x-super-keysym 'ctrl) (setq x-ctrl-keysym 'super)
Command+C/V in terminal
Now Command+C/V works in normal applications, but in terminal, Caps lock+C/V (appears as Super+C/V) will not send control keys and Command+C/V (appears as Control+C/V) will not do what you want—again, you need to swap Super and Control back, as we did for Emacs.
I looked at every terminal emulator on Linux, and Alacritty is the only one that allows remapping modifier keys, has sane configuration so that I can actually configure the remap, and has sane dependencies.
You want to remap all Control+x keys to simply x, except for Control+C/V/F, etc, which are bind to actions like Copy, Paste, SearchForward. And you want to remap all Super+x keys to Control+x. In effect, you have:
- Command+C/V → Control+C/V → Copy/Paste
- Caps lock+C/V → Super+C/V → Control+C/V
To do that, add this to the beginning of ~/.config/alacritty/alacritty.yml:
key_bindings: - { key: At, mods: Control, chars: "@" } - { key: A, mods: Control, chars: "a" } - { key: B, mods: Control, chars: "b" } - { key: C, mods: Control, action: Copy } - { key: D, mods: Control, chars: "d" } - { key: E, mods: Control, chars: "e" } - { key: F, mods: Control, action: SearchForward } - { key: F, mods: Control, mode: ~Search, action: SearchForward } - { key: F, mods: Control|Shift, action: SearchBackward } - { key: F, mods: Control|Shift, mode: ~Search, action: SearchBackward } - { key: G, mods: Control, chars: "g" } - { key: H, mods: Control, chars: "h" } - { key: I, mods: Control, chars: "i" } - { key: J, mods: Control, chars: "j" } - { key: K, mods: Control, chars: "k" } - { key: L, mods: Control, chars: "l" } - { key: M, mods: Control, chars: "m" } - { key: N, mods: Control, action: CreateNewWindow } - { key: O, mods: Control, chars: "o" } - { key: P, mods: Control, chars: "p" } - { key: Q, mods: Control, action: Quit } - { key: R, mods: Control, chars: "r" } - { key: S, mods: Control, chars: "s" } - { key: T, mods: Control, chars: "t" } - { key: U, mods: Control, chars: "u" } - { key: V, mods: Control, action: Paste } - { key: W, mods: Control, action: Quit } - { key: X, mods: Control, chars: Cut } - { key: Y, mods: Control, chars: "y" } - { key: Z, mods: Control, chars: "z" } - { key: LBracket, mods: Control, chars: "[" } - { key: Backslash, mods: Control, chars: "\\" } - { key: RBracket, mods: Control, chars: "]" } - { key: Grave, mods: Control, chars: "^" } - { key: Underline, mods: Control, chars: "_" } - { key: At, mods: Super, chars: "\x00" } - { key: A, mods: Super, chars: "\x01" } - { key: B, mods: Super, chars: "\x02" } - { key: C, mods: Super, chars: "\x03" } - { key: D, mods: Super, chars: "\x04" } - { key: E, mods: Super, chars: "\x05" } - { key: F, mods: Super, chars: "\x06" } - { key: G, mods: Super, chars: "\x07" } - { key: H, mods: Super, chars: "\x08" } - { key: I, mods: Super, chars: "\x09" } - { key: J, mods: Super, chars: "\x0a" } - { key: K, mods: Super, chars: "\x0b" } - { key: L, mods: Super, chars: "\x0c" } - { key: M, mods: Super, chars: "\x0d" } - { key: N, mods: Super, chars: "\x0e" } - { key: O, mods: Super, chars: "\x0f" } - { key: P, mods: Super, chars: "\x10" } - { key: Q, mods: Super, chars: "\x11" } - { key: R, mods: Super, chars: "\x12" } - { key: S, mods: Super, chars: "\x13" } - { key: T, mods: Super, chars: "\x14" } - { key: U, mods: Super, chars: "\x15" } - { key: V, mods: Super, chars: "\x16" } - { key: W, mods: Super, chars: "\x17" } - { key: X, mods: Super, chars: "\x18" } - { key: Y, mods: Super, chars: "\x19" } - { key: Z, mods: Super, chars: "\x1a" } - { key: LBracket, mods: Super, chars: "\x1b" } - { key: Backslash, mods: Super, chars: "\x1c" } - { key: RBracket, mods: Super, chars: "\x1d" } - { key: Grave, mods: Super, chars: "\x1e" } - { key: Underline, mods: Super, chars: "\x1f" }
This configuration remaps all possible modifier keybindings available in a terminal environment4.
Conclusion
At this point you should be able to copy & paste with Command+C/V in every application and terminal, and use Caps lock as Control in Emacs and terminal, as it should be.