summaryrefslogtreecommitdiff
path: root/public/kbd-xmodmap.md
blob: 5dbccc19d5909ecf7cde92a6610bf028c670ea90 (plain)
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."))