Hi.
A few weeks back, I asked about standard tools to handle hot-plugged
keyboards with different layouts under X11 without root privileges,
hinting that I know how to do it with non-standard tools or with root
privileges.
Here is a concentrate of what I know about the issue, for Debian testing
as of 2020-02-19.
Most of it is already documented on the web, but not all, and not all in
one place. If you find this interesting, feel free to dump it in a wiki
somewhere. And please let me know if there are inaccuracies.
The default keyboard layout on Debian is configured in
/etc/default/keyboard. This file is created and edited by the package
keyboard-configuration, whose bulk is in the debconf configure script,
not the actual contents.
/etc/default/keyboard can be queried and carelessly overwritten by a
DBus service provided by systemd-localed in the systemd package. It can
be queried by the client localectl or with a generic DBus client:
dbus-send --system --print-reply \
--dest=org.freedesktop.locale1 /org/freedesktop/locale1 \
org.freedesktop.DBus.Properties.Get \
string:org.freedesktop.locale1 string:X11Layout
But X.org does not use this.
The udev rule /lib/udev/rules.d/64-xorg-xkb.rules provided by the
xserver-xorg-core package causes /etc/default/keyboard to be imported
into the environment of udev events detected to be associated with
keyboards. The environment can be overridden by a later rule, something
like:
ACTION=="add|change", \
SUBSYSTEM=="input", KERNEL=="event[0-9]*", \
ENV{ID_INPUT_KEY}=="?*", \
ATTRS{idVendor}=="1997", ATTRS{idProduct}=="2433", \
ENV{XKBLAYOUT}="fr"
udev stores the final environment in /run/udev/data/c${major}:${minor}.
When a new input device is detected, X.org applies the configuration
files. If nothing is specified, /usr/share/X11/xorg.conf.d/10-evdev.conf
from xserver-xorg-input-evdev tells to use the evdev driver but is soon
overridden by /usr/share/X11/xorg.conf.d/40-libinput.conf from
xserver-xorg-input-libinput that tells to use the libinput driver.
The configuration snippets can define several InputClass sections that
can use match criteria to selectively apply options. See INPUTCLASS in
xorg.conf(5) and the examples of the two files above.
If the configuration does not set the layout, the options from the udev
environment are used. I have not found where this fact is documented, I
suspect it is a very generic mechanism in X.org that can apply to any
options, for example touchpad fancy stuff.
All this allows to set different layouts for hot-plugged keyboards using
either snippets of configuration for the X11 server or udev rules.
All this is more or less explained there:
https://wiki.debian.org/XStrikeForce/InputHotplugGuide
It all requires root privileges. Let's see what we can do without.
Handling the layout of hot-plugged keyboards involves two X11
extensions, XKEYBOARD aka XKB and XInputExtension aka XI2.
Configuring a keyboard layout is done with XKB.
The high-level configuration of XKB involves a few settings: layout,
variant and options, as set in /etc/default/keyboard. They are mapped to
snippets of detailed configuration using the contents of
/usr/share/X11/xkb/rules/. It produce a skeleton description that looks
like:
xkb_keymap {
xkb_keycodes { include "evdev+aliases(azerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_geometry { include "pc(pc105)" };
xkb_symbols { include "pc+fr+compose(menu)+terminate(ctrl_alt_bksp)" };
};
The high-level tool to set the layout is setxkbmap.
The description, either generated by rules or written by hand, is
handled by xkbcomp, a tool to convert a textual description into a
compiled description and back. It can operate with files, with standard
extension .xkb for text and .xkm for compiled, and directly with the
tables in the X11 server, only in compiled form obviously.
The current complete description can be obtained with:
xkbcomp $DISPLAY output.xkb
A description ca be loaded to the keyboard with:
xkbcomp input.xkb $DISPLAY
We can display the complete current layout with:
xkbcomp :0 - | xkbcomp - - | xkbprint - - | display -
Hot-plugged input devices are handled by the XI2 extension. The standard
tool xinput from the package with the same name can be used to control
it.
Keyboards are grouped in a shallow hierarchy, with the "Virtual core
keyboard" as the root and master and the actual keyboards under it. I
know it is possible to have several master pointers, which correspond to
several actual pointers on the screen moving independently. I have not
checked what happens if we try to create a second master keyboard.
The xinput command without arguments print the current hierarchy.
xinput can be used to change options on individual devices. That's how
we set the speed on a specific mouse for example:
xinput set-prop "Logitech USB Optical Mouse" "libinput Accel Speed" -0.4
For keyboard layouts, xinput is not smart enough. We need to use x