Prevent keyboard layout reset when USB keyboard is plugged in

hot-plugkeyboardkeyboard-layoutnot-root-userx11

Whenever I plug in a USB keyboard, the layout of all keyboards is reset to some system default (a US layout which doesn't have modifiers and other keys the way I want them). I've observed this on many Debian and Ubuntu systems, including Ubuntu 16.04 and 18.04. This behavior has been around for a very long time.

I use X11 with no desktop environment (though some Gnome demons tend to get started). I set my keyboard layout with XKB (specifically … | xkbcomp - "$DISPLAY") when I log in.

When I insert a USB keyboard, I want it to have my layout, not the system layout. In fact, I wish the system would just keep using my current layout for both the already present keyboard(s) if any, and the newly inserted keyboard. If that's not possible, I'd settle for re-applying a layout that I chose.

Likewise the repeat rate on both keyboards is set to the login-time default instead of the rate I set with xset r.

How can I prevent a keyboard hotplug from resetting the keyboard layout and the repeat rate? Or failing that how can I at least make it reset to my chosen layout?

There's a fairly clumsy way which is with a udev rule. It's clumsy because it assumes that there's a single X server, and most problematically, it assumes that the user has root permission. I do not have root permissions, so any method that involves setting udev rules or editing Xorg.conf is inapplicable here.

Best Answer

I set my keyboard layout with XKB (specifically … | xkbcomp - "$DISPLAY") when I log in.

How can I prevent a keyboard hotplug from resetting the keyboard layout and the repeat rate?

It's not that it resets it. If you already have a keyboard plugged in, and are adding a second one, the old keyboard will continue to use the same settings.

The problem is that the either the client-side way of loading an xkb configuration (with xkbcomp) or the server-side (with setxkbmap) will only apply the layout to the existing, actual devices, not to the "Core Keyboard" abstraction. When a device is unplugged, its settings are lost.

The solution is to monitor yourself when a keyboard is added, and call xkbcomp/setxkbmap and xset r rate with your preferred settings.

For that, you do not need any udev rule or any root privileges; any X11 client program can monitor changes to the input devices via the X11 Input extension and act on them.

A program which can be used from the shell for that and is readily installable with apt-get on Debian & similar distros is inputplug.

Example:

$ cat ./on-new-kbd
#! /bin/sh
keymap=/path/to/your/keymap

echo >&2 "$@"
event=$1 id=$2 type=$3

case "$event $type" in
'XIDeviceEnabled XISlaveKeyboard')
        xset r rate 200 50
        xkbcomp -i "$id" "$keymap" "$DISPLAY"
esac

$ chmod 755 ./on-new-kbd

$ inputplug -d -c ./on-new-kbd

<plug keyboard>

XIDeviceEnabled 13 XISlavePointer GASIA USB KB V11
XISlaveAdded 13 XIFloatingSlave GASIA USB KB V11
XISlaveAdded 14 XIFloatingSlave GASIA USB KB V11
XIDeviceEnabled 14 XISlaveKeyboard GASIA USB KB V11

Notice the -i option of xkbcomp -- you can use different settings for each keyboard. The protocol also allows to set the repeat rate on a per-device basis, but I don't know how to do that with xset.

Of course, your window manager / desktop environment may itself listen for those events and override your settings.

Related Question