1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
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 <X11/keysymdef.h> and augmented by
</usr/share/X11/XKeysymDB>. 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."))
|