Remapping keys, so that it propagates to AppVMs

I’ve been struggling a lot trying to remap a key to something else, in a way that propagates to all AppVMs. It appears there’s no straight-forward way to do it as of R4.2, and I’m going to collect here the observations I’ve made along the way.

  • The basic way to accomplish this in Linux is by issuing xmodmap -e keycode <keycode> = <keysym>. To find out what keycode a particular key on your keyboard issues, you have to use a program called xev; this isn’t installed in dom0, but comes with the debian template. So just start a terminal in a debian AppVM, run xev and then press the key on your keyboard; it will tell you its keycode. The keysym value corresponds to what the clients (apps) actually receive; possible values include a, equal, etc.
    • By doing this in qubesOS, you can remap a particular key to something else, but only in dom0. Unfortunately, the change doesn’t propagate to any AppVMs.
  • Alternatively, you can change your entire keyboard layout. In dom0, the files containing layout definitions are located in /usr/share/X11/xkb/symbols/. You can change the layout using setxkbmap <layout>, where <layout> is the name of one of those files.
    • Surprisingly, changing the layout does propagate to AppVMs. I’m not sure how this happens, but the value of qvm-prefs <appvm> keyboard_layout updates right away after issuing setkbmap in dom0. And issuing setxkbmap -print -verbose in an AppVM shows that the new layout was added to the symbols entry.
    • This gave me the idea of maybe getting the remapped key to propagate to AppVMs, by editing the layout file in /usr/share/X11/xkb/symbols/ accordingly. But doing so again results in remapping it for dom0 and not for AppVMs.
    • You can also create a new layout file, with your own changes, and save it as /usr/share/X11/xkb/symbols/my-map. Then you can activate it using setxkbmap my-map. This results in the new layout working in dom0; but AppVMs will not change their layout.
  • So taking everything into account, it seems that AppVMs receive the keycode directly, not a keysym. And the translation to a keysym is left up to the AppVM. There’s probably some Qubes service that runs in dom0 and in AppVMs, which registers when the keyboard layout is changed in dom0 and signals it to AppVMs; then the AppVM chooses to update its own layout. If the AppVM doesn’t have a layout file which corresponds to the layout name in dom0, no change takes place.

So, like I said. There’s no straight forward way to remap a key in qubesOS. It seems like the only way forward is to add the xmodmap command in the startup scripts for each individual AppVM. So I’m now looking into how to use salt to do this.

I have keyd running in dom0 and remapped ctrl, alt, some other stuff and it is working with AppVMs.

1 Like

I’ve found a good solution to this, which doesn’t require installing any extra packages in dom0.

First, I realised the issue with using xmodmap is that the result is tethered to the X11 environment. AppVMs other than dom0 probably receive keyboard input outside of the X session which runs in dom0; this explains why the remapping that happens in dom0’s X session doesn’t propagate to the other AppVMs.

Fortunately, there is a low-level command called setkeycodes, which operates at the kernel level. It takes two arguments: setkeycodes <scancode> <keycode>. The command maps <scancode> to a <keycode>. To get the relevant values, you run showkey -s and showkey -k respectively, in a virtual console.

So, for example: let’s say I want to remap the key that has the sticker a on it, so that when I press it, I get the letter b instead. Here are the steps:

  1. Press Ctrl + Alt + F2 to activate a virtual console and log in.
  2. Run showkey -s and press the key with sticker a. You will get two hex values in the format 0x<scancode>; make a note of the first <scancode>.
  3. Run showkey -k and press the key with sticker b. You will get a value in the format keycode <keycode>. Make a note of it.
  4. Press Ctrl + Alt + F1 to return to your X session.
  5. Now, in a dom0 terminal, run: sudo setkeycodes <scancode> <keycode>.

That’s it. Now, all userland programs (in dom0 and AppVMs) will receive the same keycode, regardless if you press the key with sticker a or sticker b on it. As far as the programs are concerned, they won’t be able to know that the signal comes from two different keys on your keyboard.

To make this change persistent, add the sudo setkeycodes command to one of your dom0 startup scripts.

It seems that your problem can be solved by my recent guide → Running kanata (keyboard remapping software) which doesn’t require running stuff in dom0

1 Like

In my case, I’m on a laptop. I don’t think this solution works for keyboards which are not connected via USB.

1 Like