GNU/Linux Keyboard Maps: xmodmap ================================ --- date: "2017-10-01" --- The modmap subsystem is part of the core [X11 protocol][xproto]. However, it has been replaced by the [X Keyboard (XKB) Extension][kbproto] to the protocol, which defines a facade that emulates the legacy modmap subsystem so that old programs still work---including those that manipulate the modmap directly! [xproto]: https://www.x.org/releases/current/doc/xproto/x11protocol.html [kbproto]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html For people who like to Keep It Stupid Simple, the XKB extension looks horribly complicated and gross---even ignoring protocol details, the configuration syntax is a monstrosity! There's no way to say something like "I'd like to remap Caps-Lock to be Control", you have to copy and edit the entire keyboard definition, which includes mucking with vector graphics of the physical keyboard layout! So it's very tempting to pretend that XKB doesn't exist, and it's still using modmap. However, this is a leaky abstraction; for instance: when running the `xmodmap` command to manipulate the modmap, if you have multiple keyboards plugged in, the result can depend on which keyboard you used to press "enter" after typing the command! Despite only existing as a compatibility shim today, I think it is important to understand the modmap subsystem to understand modern XKB. Conceptual overview ------------------- There are 3 fundamental tasks that the modmap subsystem performs: 1. `keyboard: map keycode -> keysym` 2. `keyboard: map keysym -> modifier bit` WAIT? 3. `pointer: map physical button -> logical button` You're thinking: "Great, so the X server does these things for us!" Nope! It exposes those mappings, and leaves the actual transformations up to the client. Generally, the actual transformations are performed automatically inside of libX11/libxcb. Vocab: ------ - keycode: A numeric ID for a hardware button; this is as close the the hardware as X11 modmaps let us get. These are conceptually identical to Linux kernel keycodes, but the numbers don't match up. Xorg keycodes are typically linux_keycode+8. - keysym: A 29-bit integer code that is meaningful to applications. A mapping of these to symbolic names is defined in and augmented by . See: XStringToKeysym() and XKeysymToString(). We will generally use the symbolic name in the modmap file. The symbolic names are case-sensitive. - Modifier state: An 8-bit bitmask of modifier keys (names are case-insensitive): 1 << 0 : shift 1 << 1 : lock 1 << 2 : control 1 << 3 : mod1 1 << 4 : mod2 1 << 5 : mod3 1 << 6 : mod4 1 << 7 : mod5 Commands by task: ----------------- The `xmodmap` command has its own little quirky syntax. There are 8 commands that it recognizes. Let's look at those, grouped by the 3 tasks that the modmap subsystem performs: 1. `keyboard: map keycode -> keysym` - `keycode KEYCODE = PLAIN [SHIFT [MODE_SWITCH [MODE_SWITCH+SHIFT ]]]` Actually takes a list of up to 8 keysyms, but only the first 4 have standard uses. - `keysym OLD_KEYSYM = NEW_KEYSYMS...` Takes the keycodes mapped to `OLD_KEYSYM` and maps them to `NEW_KEYSYM`. - `keysym any = KEYSYMS...` Finds an otherwise unused keycode, and has it map to the specified keysyms. 2. `keyboard: map keysym -> modifier bit` - `clear MODIFIER` - `add MODIFIERNAME = KEYSYMS...` - `remove MODIFIER = KEYSYMS...` 3. `pointer: map physical button -> logical button` - `pointer = default` This is equivalent to `pointer = 1 2 3 4 5 6...` where the list is as long as the number of buttons that there are. - `pointer = NUMBERS...` TODO Appendix: ========= I use this snippet in my Emacs configuration to make editing xmodmap files nicer: ;; http://www.emacswiki.org/emacs/XModMapMode (when (not (fboundp 'xmodmap-mode)) (define-generic-mode 'xmodmap-mode '(?!) '("add" "clear" "keycode" "keysym" "pointer" "remove") nil '("[xX]modmap\\(rc\\)?\\'") nil "Simple mode for xmodmap files."))