udev rule to auto load keyboard layout when usb keyboard plugged in

I found a way to work around this, though its a little hacky.

I got to the same exact point today in trying to set up two keyboards with udev, setxkbmap, and xinput --list and for them to work with usb hotplugging. I am swapping keys around, not changing the layout, but its all the same, once you've identified your keyboard on a hotplug and can conditonally call setxkbmap, then you should be able to set the language of only the keyboard you've specified. The list of keyboard layouts can be found here ls -l /usr/share/kbd/keymaps/i386/ and you can find your device name to gre on with xinput -list.

  1. You'll want to replace rizumu with your username, as I found it wasn't possible a way to do this without being explicit.
  2. Make sure you grep on the your keyboard name.
  3. Use lsusb to discover the Hardware ID that you need to set in the udev rule. My das keyboard looks like this Bus 002 Device 009: ID 04d9:2013 Holtek Semiconductor, Inc.

I first set up the udev rule to autodetct the keyboard is by creating a udev rule:

In the file /etc/udev/rules.d/00-usb-keyboards.rules:

ACTION=="add", ATTRS{idVendor}=="04d9", ATTRS{idProduct}=="2013", RUN+="/home/rizumu/bin/kbd_udev", OWNER="rizumu"

I have two files ~/bin/kbd and ~/bin/kbd_udev. Make sure they have the right permissions chmod 755 ~/bin/kbd*

The ~/bin/kbd_udev script contains:

#!/bin/bash
/home/rizumu/bin/kbd &

And you'll notice that all it does is call ~/bin/kbd in the background, so that udev can complete its process and activate the keyboard. Inside the ~/bin/kbd script we sleep for a second, because we need to wait until the keyboard is activated so we can get the device id using xinput. To achive this I've set some variables and exported them so xinput setxkbmap can do thier work: DISPLAY, XAUTHORITY, HOME, and one daskb_id for the id of my daskeyboard:

#!/bin/bash
sleep 1
DISPLAY=":0.0"
HOME=/home/rizumu/
XAUTHORITY=$HOME/.Xauthority
export DISPLAY XAUTHORITY HOME
daskb_id=`xinput -list | grep -i 'daskeyboard' | grep -o id=[0-9]. | grep -o [0-9]. | head -1`

xset r rate 200 30
setxkbmap -layout colemak
setxkbmap -option ctrl:nocaps
if [ "${daskb_id}" ]; then
    setxkbmap -device "${daskb_id}" -option altwin:swap_lalt_lwin
fi

Depending on your distro, you may already have a udev rule for keyboards in /lib/udev/rules.d/64-xorg-xkb.rules. On Ubuntu, this imports /etc/default/keyboard, which has options roughly like this:

XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""

For my setup, I found that this built-in rule was executing after my custom udev rule, and was overriding my settings. Instead I changed XKBOPTIONS in /etc/default/keyboard to be:

XKBOPTIONS="-option ctrl:nocaps"

To get the "Caps Lock is Control" behavior I wanted on all keyboards.


If you're running GNOME then you'll need to disable its keyboard management plugin so that it doesn't override your layout changes.

gconftool-2 --toggle /apps/gnome_settings_daemon/plugins/keyboard/active

Run the same command again to enable it as desired.

Tags:

Linux

Usb

Udev