Question

I wrote this script to change the usb keyboard layout automatically on plug-in

import pyudev                                                                   
from subprocess import call

monitor = pyudev.Monitor.from_netlink(pyudev.Context())
monitor.filter_by('usb')

def kbd_event(action, device):
    if action == 'add':
        call(["setxkbmap", "carpalx"])

observer = pyudev.MonitorObserver(monitor, kbd_event)
observer.start()

setxkbmap carpalx works if I type it in bash, but it doesn't change the layout in the above code. So I did this in bash:

setxkbmap carpalx
xmodmap -pke > carpalx2

changed the above call line to call(["xmodmap", "./carpalx2"]) and now the script works. I have the following problems:

  1. Why does xmodmap work in the code and setxkbmap doesn't, but both work in bash?
  2. Currently, kbd_event is called for every usb event and call(["xmodmap", "./carpalx2"]) is run for every usb device I plug in. How can I further filter the events so the layout changes only when I insert a keyboard?

With my current code, the keyboard layout changes every time I plug in my mouse :)

Was it helpful?

Solution

You can filter keyboards by checking for the ID_INPUT_KEYBOARD property:

if action == 'add' and device['ID_INPUT_KEYBOARD'] == '1':
    print('a keyboard was added')

Concerning the difference between calling setxkbmap directly and using the script, I'd guess that the X server needs time to initialize the keyboard, too. UDev invokes the callback as soon as the keyboard has finished udev processing, but this can easily before the X11 server configures and initializes the new keyboard.

Check the X.org logs, and any error message that setxkbmap might print.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top