0

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 :)

Dharman
  • 30,962
  • 25
  • 85
  • 135
Adi
  • 562
  • 7
  • 18
  • Is there an exception when running `setxkbmap`? Try using `subprocess.check_call()` or `.check_output()`. It seems like it could be something like `setxkbmap` expecting a `DISPLAY` environment variable, but it's tough to tell without an error message. – AdamKG May 02 '12 at 09:18
  • I tried and there appears to be no excepton, both setxkbmap and xmodmap return 0, the difference is that setxkbmap doesn't change anything. Maybe the keyboard is not fully initialized by udev when the events occur so setxkdmap can't set the layout? Looking through the configs of both tools, it appears that xmodmap operates at a lower level.. May this be the case? – Adi May 02 '12 at 10:13
  • It may have something to do with X authentication. – Keith May 05 '12 at 20:21

1 Answers1

2

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.

  • Thank you very much :) I ended up learning how sysfs works continuing from the solution in your answer! – Adi Jun 12 '12 at 16:53