michael orlitzky

Fixing KVM (QEMU) keymaps

The Problem

According to Norse mythology, my text editor of choice is GNU Emacs. For those unfamiliar, most of the commands in Emacs involve terrorizing the keyboard while the left Ctrl key is held down. For example, to save the current file, one would hold down the left Ctrl key, and then press x and s in succession.

M-x make-universe

And so it had come to pass after the great Wōđan ruled Asgård for many days and many nights. He tired, as did his people tire and weep not only for themselves but for those who should follow in their footsteps. From foreign lands observers came, at last, to witness that final act; whose noble art would make his name known the earth and heavens over.

Emacs man page

Unfortunately, some asshole moved the control key. As a result, everything is bad and humans now execute Emacs commands at great peril. Luckily, it's easy to re-map the keys of a standard PC keyboard under Linux. (Apparently, it can be done under Windows, too. But who knows.)

So everything is awesome, and we can make Caps Lock act like a third Ctrl key. Except for some stupid reason it won't work in KVM/QEMU guests. That is, Caps Lock is acting as Ctrl in the host system. This keybinding doesn't translate to the KVM guest, which is fine; but, it's also seemingly-impossible to re-map the keys within the guest. Like, fixing the keys from within the guest just does not work.

Virtual Terminal Config

First, a quick overview of how I've got the keys mapped. Under Linux, you have to do this in two places, using two different interfaces (awesome). The first place is within the virtual terminals (i.e. where you are before X starts). This can be done with the utilities dumpkeys, loadkeys, and showkey.

Basically, you put the key mappings in a file, and then call loadkeys on it. What goes in the keymap file, you ask? You think there's like, a list or something? No, you get to figure it out. That's what dumpkeys and showkey are for. You can use dumpkeys to dump the current keymap, and showkey will show you what keycodes are being received while you mash on the keyboard.

My keymap file, /usr/share/keymaps/i386/qwerty/mjo.map:

keymaps 0-2,4-6,8-9,12

keycode 58  = Alt     # Caps Lock
keycode 29  = Alt     # Left Control
keycode 97  = Alt     # Right Control
keycode 56  = Control # Left Alt
keycode 100 = Control # Right Alt

I have no idea what that first line does. The rest of the rules simply switch the Ctrl and Alt keys, and set the Caps Lock key to act like a third Alt. To load this at boot time, just add the following to your /etc/cond.f/local.start (Gentoo) or /etc/rc.local (everybody else):

echo "Setting keymap..."
loadkeys < /usr/share/keymaps/i386/qwerty/mjo.map

Fix the path to point to the correct keymap file or suffer the consequences.

X Config

The second place you have to remap your keys is within X. The virtual terminal method above simply will not work, even if you attempt it from within X and tell loadkeys that it should target X's virtual terminal. So, the way to go is xmodmap.

With xmodmap, you put your key mappings in ~/.Xmodmap, and then run xmodmap on it. The syntax is different than the one for loadkeys, because somebody has a really good sense of humor. Here's mine; it accomplishes the same thing as the one above.

clear Lock
clear Control
clear Mod1

keycode 64 = Control_L
keycode 108 = Control_L
add Control = Control_L

keycode 37 = Alt_L
keycode 66 = Alt_L
keycode 105 = Alt_R
add Mod1 = Alt_L Alt_R

You will notice that, not only are the key names different, but also the key codes. Ha ha! You have to use the xev program to figure them out.

And don't you dare try to put loadkeys-style comments in your .Xmodmap file. Comments for xmodmap begin with an exclamation point, and require a separate line as God intended.

Fixing KVM and QEMU

Ok, so when I started out, this article was going to be a lot more exciting. Like a fool, I read the documentation for qemu and trusted it.

-k language

Use keyboard layout language (for example “fr” for French). This option is only needed where it is not easy to get raw PC keycodes (e.g. on Macs, with some X11 servers or with a VNC display). You don't normally need to use it on PC/Linux or PC/Windows hosts.

The available layouts are:

[blah blah blah blah blah]

The default is “en-us”.

Knowing this, I set out to modify the default keymap to suit my purposes. This was pretty easy; all I had to do was make a copy of an existing keymap, and modify the appropriate keys. So I did, and it worked. My keymap was named mjo, and so in my kvm script, I added -k mjo to set the keymap to the one I'd just created. It works, great.

In the course of writing this, I discovered a little problem. I decided to test a few different keyboard layouts within my VMs, and when I modified the mjo keymap, nothing happened. However, if I changed my ~/.Xmodmap file, kvm would pick up the changes. Ok, what?

I'll cut to the chase here: kvm doesn't care about my keymap, it was just ignoring the default. If you specify a keymap on the command line—any keymap at all—it will pick up the correct .Xmodmap mappings.

But isn't the default keymap en-us? Yeah, fucking nope. Specify no keymap, and nothing will work. Specify -k en-us, and everything is money.