Before I get started, let me run the basic vocabulary by you, so we're on the same page. If you know your
xmodmap, you can safely skip this bit.
First, you have
keycode
s. 666, the number of the key. They're pretty arbitrary in that they have no meaning and depend on your hardware. Then you have maps saying what keycode generates what
keysym
— if the key that has printed
A on its plastic
keycap
has
keycode 666, the standard mapping might be for
keycode 666 to be translated to
keysym A. Only, it will probably be
keysym a. Keys may have several
layer
s, like
with and without shift. That makes one
group
,
a and
A. If you use
AltGr (right alt) to get funny extra characters like € and @, that's another layer. That layer is in turn part of another group:
AltGr with and without shift. If you have more than one national layout (e.g. US keyboard and Ivrit, or, if you appreciate pain, US and French layouts), that also adds one group (e.g. Ivrit
with and without shift
). Now, I keep saying
Shift
…
Let the insanity begin …
Shift
of course is a key you can hold and then press another key. You use it to get an uppercase letter where normally, you'd get a lowercase one, for instance. Or to get a symbol instead of a digit. Or to get
niqqud.
CapsLock
or
AltGr
can similarly be pressed together with other "normal" keys. This is called a chord — like on an organ, you press several keys at once. Holding down the
Shift
key creates a
Shift
keysym, of course. But that doesn't print a "shift character". It sets a
Shift modifier
, a special flag that says to interpret other keys in a new way.
Shift-
a of course gives
A. Or expressed in our new vocabulary: When the
Shift modifier
is engaged, the second (
A) rather than the first (
a)
keysym
from the active
group
is taken. Given that Shift selects
within a group, it stands to reason that another key can select
between groups. One such example is our
AltGr of course, which generates
Mode_switch or
Iso_Level3_Shift.
So. The shift keys have shift keysyms (
Shift_L and
Shift_R, respectively, for left and right), and they set shift modifiers. (If any other keysyms are set to generate shift modifiers, or if shift keysyms are to to create non-shift modifiers, X will kill a puppy.) Similarly, the keys that have the
Control_L and
Control_R keysyms (should) generate the Control modifier bit. Then, there's the Lock modifier, for Shift Lock or Caps Lock.
Here's the twist: there isn't a Hyper modifier, or an Alt modifier in plain X. There are
Shift, Lock, Control, and Mod1 … Mod5
modifier bits. If you stick
"generate Mod3"
on a key that has a
Hyper
keysym (i.e.,
Hyper_L or
Hyper_R),
Mod3
means
Hyper
(and no keys that
aren't Hyper
may create
Mod3
). If you'd stuck
Mod3
to
Alt_L and
Mod4
to
Hyper_L, then
Mod3
would mean
Alt
, and
Mod4
would mean
Hyper
. Let me repeat, you can't be certain what, say,
Mod2
means until you've checked. Not that you need to known — unless you wish to modify your keyboard setup, or write almost any sort of interesting GUI application.
The correct application to set up these things for plain X is
xkeycaps. It shows your keyboard, and what keysyms the keys generate. In the case of modifier-keys, it also shows what modifier is generated. You can also modify those settings, and save them in a file
~/.Xmodmap that you can apply using the
xmodmap command (in fact that may happen automatically when your X session starts) without having to call
xkeycaps every time.
So, as we've discussed, there may be various groups. Suppose we're looking at a single key ("A"). Suppose group 1 has the US keyboard (a, A), group 2 has Ivrit (ש, ְ ), and group 3 has some AltGr rubbish (æ, Æ). Now it stands to reason that you can change all those keysyms using
xkeycaps/xmodmap. And you can. You can even ask X to have AltGr-A generate "cursor left" instead of æ. Here's the rub: you can do it with the A key. You
can't do it with the J key.
What!
, you say. Actually, on vanilla X, this will work. Where vanilla X is
"X without the XKB extension."
If you disable XKB using
export XKB_DISABLE=1 before calling the program you need the funny key-layout in (usually your entire session), this will also work. Why doesn't it with XKB? It doesn't work with XKB apparently because in the XKB setup for "my" country, the
A key has some keysyms defined in the
AltGr layer, and the
J key doesn't. And if they don't exist, you can't overwrite them. I consider this a bug. On the other hand, while this would solve the problem at hand, I don't want to just switch off XKB. It has its uses, and without it, the
compiz
window manager behaves strangely. For instance, the
ring switcher
(
Alt-Tab / Super-Tab) suddenly requires me to confirm my selection by pressing
Return rather than just release
Alt.
So, I learned the XKB syntax, and made my own map (which you may
download as an example, but which is an ugly hack that's not as modular as it could be — to use it, save it as
/usr/share/X11/xkb/symbols/azou and e.g.
setxkbmap -layout azou -variant nodeadkeys). The syntax is funky, but not as funky as it could be, not by a long shot. So, I put the cursor keysyms in the
AltGr layer of
J K L I. (I actually duplicated the entire cursor block,
PgUp/PgDn, Insert/Delete etc., but let's keep things simple.) That part was surprisingly simple. I set the left
Win-key to generate be
"Super."
I set the right
Win-key up to be
"Hyper"
(for use in
xemacs
, mostly). Then in order to not muck up my wrists when using the new cursor keys a lot, I had the
CapsLock key generate
ISO_Level3_Shift
, same as "
AltGr". This also worked fine. Except that
Control-AltGr-J would correctly give
"word left"
in xemacs, while
Control-Caps-J, which should do exactly the same, did nothing at all. Did I forget to set a modifier? Did I set a modifier I shouldn't? What was going on? After almost an hour of experimenting, I was enlightened when it suddenly occurred to me to try
Control-Caps-J on the laptop's keyboard, where it worked famously. After first finding one of only two keys (
J and
N) on my keyboard that weren't fully accessible to
xmodmap, I had now found one of the few chords that my external keyboard could not generate (or that were eaten in the PS/2-to-USB adapter).
Thanks ever so bloody much, life!
Of course once the problem was identified, it could be remedied (bind
Super-Caps-J to
backward-word in
xemacs
, and
Super-Caps-L to
forward-word). Plus of course there is no guarantee that the new keyboard will even
have that limitation. I think I might still amend
Azundris' rule of debugging
to say:
If finding a bug in your own code takes more than half an hour, make sure it's not the library, or the compiler — or the hardware.
rodin.rizili.com on : PingBack