As long as I found the proper solution, I will answer my own question.
There is a program named keyfuzz that can change the keyboard maps used by the kernel, based on input devices - i.e. separately for every keyboard attached to the computer.
There are two problems with this program that are not described properly in the documentation:
- The USB keyboards generate scan codes, other than the scan codes of keyboards attached to ps/2 port. This way, if you need to remap USB keyboard, you will need a way to know the scan codes of the keys. The tool "showkey", usually recommended for testing scancode and keycode will not do the job, because it reads form
/dev/console
that emits "standard" scan codes, regardless of the keyboard.
In order to test the scan codes of the keyboard based on its /dev/input/KEYBOARD
address, you need to use the program named getscancodes. Notice that the downloaded file from the above link is not properly compressed. It is named getscancodes.tar.gz
, but is compressed with ZIP algorithm. The package contains the source code as well as precompiled binaries.
In my case the keyfuzz configuration file looks this way:
### evdev 1.0.0., driver 'TK Stealth keyboard'
### Proper old-style numpad handling
0x70059 107
0x7005A 108
0x7005B 109
0x7005C 105
0x7005D 108
0x7005E 106
0x7005F 102
0x70060 103
0x70061 104
0x70062 110
0x70063 111
- The program "keyfuzz" starts as a service during the boot, in order to patch the tables as early as possible. Unfortunately, the USB keyboards are added to the devices later, so when the keyfuzz starts, there is no keyboard to be patched, even if the USB keyboard is attached during the boot.
The solution is to use udev
rules files and to start keyfuzz on adding the needed keyboard.
In order to do it, you need to add a file /etc/udev/rules.d/mykeyboard.rules
, containing (in my case):
ACTION=="add", ATTRS{idVendor}=="2516", RUN+="/usr/lib/systemd/scripts/keyfuzz start"
Now, after plugging the keyboard, the keyfuzz start script will start and patch the keyboard decoding tables.
Try setting both layouts in the same file using explicit [Group]'s:
key <...> { symbols[Group1] = [ ... ], symbols[Group2] = [ ... ] };
Best Answer
tl;dr: On Linux, you should be using the
evdev
rules. As it says in the XKB guide you link:The difference is largely historical.
evdev
is the modern Linux kernel input subsystem and did not exist when XKB was first written. If you look into the source code for xkeyboard-config, you'll find that bothevdev
andbase
rules are generated from (mostly) the same templates. Compare the generated files in your system XKB database withdiff
, though. You'll see many entries where thebase
rules loadsinet
symbols for specific keyboard models, while theevdev
rules do away with most of those model-specific entries and load a more generalized set:No really, that's the whole model-to-symbols section from the
evdev
rules, whereas thebase
version is 60-odd lines long. Theevdev.m_s.part
file is the source template for that section of the rules; it's a model-to-symbol mapping (the!model = symbol
line at the start of that section; hence them_s
in the filename). The only other evdev-specific section of the rules comes from theevdev.m_k.part
file, which is a model-to-keycodes mapping (the!model = keycodes
section of the rules), and the differences there are similar.For further details, consult the keycodes and symbols files referenced by those rules (especially
/usr/share/X11/xkb/keycodes/evdev
and/usr/share/X11/xkb/symbols/inet
). You may be interested in this writeup of the XKB rules format.