Should a Power-User Key Mapping Change Be This Difficult?

Tuesday 31 May 2011 by Bradley M. Kuhn

It's been some time since X made me hate computing, but it happened again today (well, yesterday into the early hours of today, actually.

I got the stupid idea to upgrade to squeeze from lenny yesterday. I was at work, but it was actually a holiday in the USA, and I figured it would be a good time to do some sysadmin work instead of my usual work.

I admittedly had some things to fix that were my fault: I had backports and other mess installed, but upon removing, the upgrade itself was more-or-less smooth. I faced only a minor problem with my MD device for /boot not starting properly, but the upgrade warned me that I needed to switch to properly using the UUIDs for my RAID arrays, and once I corrected that, all booted fine, even with GRUB2 on my old hardware.

Once I was in X, things got weird, keyboard-wise. My meta and alt keys weren't working. BTW, I separate Alt from Meta, making my actual Alt key into a meta key, while my lower control is set to an Alt (ala Mod2), since I throw away caps lock and make it a control. (This is for when I'm on the laptop keyboard rather than the HHKB.)

I've used the same xmodmap for two decades to get this done:

keycode 22 = BackSpace

clear Mod1
clear Mod2
clear Lock
clear Control

keycode 66  = Control_L

keycode 64 = Meta_L
keycode 113 = Meta_R
keycode 37 = Alt_L
keycode 109 = Alt_R

add Control = Control_L

add Mod1 = Meta_L
add Mod1 = Meta_R

add Mod2 = Alt_L
add Mod2 = Alt_R

This just “doesn't work” in squeeze (or presumably any Xorg 7.5 system). Instead, it just gives this error message:

X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  118 (X_SetModifierMapping)
  Value in failed request:  0x17
  Serial number of failed request:  21
  Current serial number in output stream:  21
… and while my Control key ends up fine, it leaves me with no Mod1 nor Mod2 key.

There appear to be at least two Debian bugs (564327 and 432011), which were against squeeze before it was released. In retrospect, I sure wish they'd have been release-critical!. (There's also an Ubuntu bug, which of course just punts to the upstream Debian bug.) There are also two further upstream bugs at freedeskop (20145 and 11822), although Daniel Stone thinks the main problem might be fixed upstream.

I gather that many people “in the know” believe xmodmap to be deprecated, and we all should have switched to xkb years ago. I even got snarky comments to that effect. (Update:) However, after I made this first post, quite angry after 8 hours of just trying to make my Alt key DTRT, I was elated to see Daniel Stone indicate that xmodmap should be backwards compatible. It's always true that almost every time I get pissed off about some Free Software not working, a developer often shows up and tells me they want to fix it. This is in some ways just as valuable as the thing being fixed: knowing that the developer doesn't want the bug to be there — it means it'll be fixed eventually and only patience is required.

However, the bigger problem really is that xkb appears to lack good documentation. If any exists, I can't find it. madduck did this useful blog post (and, later, vinc17 showed me some docs he was working on too). These are basically the only things I could find that were real help on the issue, and they were sparse. I was able to learn, after hours, that this should be the rough equivalent to my old modmap:

partial modifier_keys
xkb_symbols "thinkpad" {
    replace key <CAPS>  {  [ Control_L, Control_L ] };
    modifier_map  Control { <CAPS> };
    replace key <LALT>  {  [ Meta_L ] };
    modifier_map Mod1   { Meta_L, Meta_R };
    key <LCTL> { [ Alt_L ] };
    modifier_map Mod2 { Alt_L };
};

But, you can't just load that with a program! No, it must be placed in a file called /path/symbols/bkuhn, which it is then loaded with an incantation like this:

xkb_keymap {
        xkb_keycodes  { include "evdev+aliases(qwerty)" };
        xkb_types     { include "complete"      };
        xkb_compat    { include "complete"      };
        xkb_symbols   { include "pc+us+inet(evdev)+bkuhn(thinkpad)"     };
        xkb_geometry  { include "pc(pc105)"     };
};

…which, in turn, requires to be fed into: xkbcomp -I/path - $DISPLAY as stdin. Oh, did I mention you have to get the majority of that stuff above by running setxkbmap -print, then modify it to add the bkuhn(thinkpad) part? I'm impressed that madduck figured this all out. I mean, I know xmodmap was arcane incantations and all, but this is supposed to be clearer and better for users wanting to change key mappings? WTF!?!

Oh, so, BTW, my code in /path/symbols/bkuhn didn't work. I tried every incantation I could think of, but I couldn't get it to think about Alt and Meta as separate Mod2 and Mod1 keys. I think it's actually a bug, because weird things happened when I added lines like:

    modifier_map Mod5 { <META> };
Namely, when I added the above line to my /path/symbols/bkuhn, the Mod2 was then picked up correctly (magically!), but then both LCTL and LALT acted like a Mod2, and I still had no Mod1! Frankly, I was too desperate to get back to my 20 years of keystroke memory to try to document what was going on well enough for a coherent bug report. (Remember, I was doing all this on a laptop where my control key kept MAKING ME SHOUT INSTEAD OF DOING ITS JOB.)

I finally got the idea to give up entirely on Mod2 and see if i could force the literal LCTL key to be a Mod3, hopefully allowing Emacs to again see my usual Mod1 Meta expectations for LALT. So, I saw what some of the code in /usr/share/X11/xkb/symbols/altwin did to handle Mod3, and I got this working (although it required a sawfish change to expect Mod3 instead of Mod2, of course, but that part was 5 seconds of search and replace). Here's what finally worked as contents of /path/symbols/bkuhn:

partial modifier_keys
xkb_symbols "thinkpad" {
    modifier_map  Control { <CAPS> };
    replace key <LALT>  {  [ Meta_L ] };
    modifier_map Mod1   { Meta_L };
    key <LCTL> { type[Group1] = "ONE_LEVEL",
                 symbols[Group1] = [ Super_L ] };
    modifier_map Mod3 { Super_L };
};

So, is all this really less arcane than xmodmap? Was the eight hours of my life spent learning xkb was somehow worth it, because now I know a better tool than xmodmap? I realize I'm a power user, but I'm not convinced that it should be this hard even for power users. I felt reminiscent of days when I had to use Eric Raymond's mode timings howto to get X working. That was actually easier than this!

Even though spot claimed this is somehow Debian's fault, I don't believe him. I bet I would run into the same problem on any system using Xorg 7.5. There are clearly known bugs in xmodmap, and I think there is probably a subtle bug I uncovered that exist xkbd, but I am not sure I can coherently report it without revisiting this horrible computing evening again. Clearly, that first thing I tried should have not made two keys be a Mod2, but only when I moved META into Mod5, right?

BTW, If you're looking for me online tomorrow early, you hopefully know where I am. I'm going to bed two hours before my usual waketime. Ugh. (Update: tekk later typo'ed xmodmap as ’xmodnap‘ on identi.ca. Quite fitting; after working on that all night, I surely needed an xmodnap!

Update on 2013-04-03: I want to note that the X11 and now Wayland developer named Daniel Stone took an interest in this bug and actually followed up with me two years later giving me a report. It is apparently really hard to fix without a lot of effort, and I've switched to xkb (which I think is even more arcane), but mostly works, except when I'm in Xnest. But my main point is that Daniel stuck with the problem and while he didn't get resolution, he kept me posted. That's a dedicated Free Software developer; I'm just a random user, after all!

Posted on Tuesday 31 May 2011 at 03:00 by Bradley M. Kuhn.

Comment on this post in this identi.ca conversation.



Creative Commons License This website and all documents on it are licensed under a Creative Commons Attribution-Share Alike 3.0 United States License .


#include <std/disclaimer.h>
use Standard::Disclaimer;
from standard import disclaimer
SELECT full_text FROM standard WHERE type = 'disclaimer';

Both previously and presently, I have been employed by and/or done work for various organizations that also have views on Free, Libre, and Open Source Software. As should be blatantly obvious, this is my website, not theirs, so please do not assume views and opinions here belong to any such organization. Since I do co-own ebb.org with my wife, it may not be so obvious that these aren't her views and opinions, either.

— bkuhn


ebb ® is a registered service mark of Bradley M. Kuhn.

Bradley M. Kuhn <bkuhn@ebb.org>