Using xkbcomp for a specific device

Darren Hart darren at dvhart.com
Sun Sep 16 13:41:02 PDT 2012


I'm looking to modify the keysyms of a remote that presents as a usbhid device.
I also have an HP wireless keyboard and mouse combination device that I do not
wish to modify. I'm trying to accomplish this with a combination of setxkbmap
and xkbcomp, using the "-i device_id" to xkbcomp to modify the keymap of only
the remote. The problem: both devices get remapped.

The following describes my system and the exact steps I've taken to try and
remap the remote.

$ xinput --list 
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ HOLTEK                                  	id=10	[slave  pointer  (2)]
⎜   ↳ HP HP Wireless Mini Keyboard            	id=11	[slave  pointer  (2)]
⎜   ↳ HP HP Wireless Mini Keyboard            	id=12	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Power Button                            	id=6	[slave  keyboard (3)]
    ↳ Video Bus                               	id=7	[slave  keyboard (3)]
    ↳ Power Button                            	id=8	[slave  keyboard (3)]
    ↳ HOLTEK                                  	id=9	[slave  keyboard (3)]

In the list above, the HOLTEK is the remote (it sends both keyboard and mouse
events). Yes it's horrible, but it's what I have and I'd like to make it work. The
two entries for the HP Wireless Mini Keyboard correspond to the single USB
receiver for the keyboard and mouse.

$ lsusb
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 1241:e000 Belkin          <----- This is the remote 
Bus 002 Device 004: ID 03f0:a107 Hewlett-Packard <----- This is the HP keyboard/mouse

$ lsusb -t
/:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 480M
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/8p, 480M
        |__ Port 5: Dev 4, If 0, Class=HID, Driver=usbhid, 12M <----- HP keyboard/mouse
        |__ Port 5: Dev 4, If 1, Class=HID, Driver=usbhid, 12M <----- HP keyboard/mouse
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/6p, 480M
        |__ Port 3: Dev 3, If 0, Class=HID, Driver=usbhid, 1.5M <----- Remote
        |__ Port 3: Dev 3, If 1, Class=HID, Driver=usbhid, 1.5M <----- Remote

dmesg reports each as USB input devices using the usbhid driver:

$ dmesg | egrep "(HOLTEK|HP Wireless)"
[    3.966054] input: HOLTEK as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.3/1-1.3:1.0/input/input2
[    3.966267] hid-generic 0003:1241:E000.0001: input,hidraw0: USB HID v1.10 Keyboard [HOLTEK] on usb-0000:00:1a.0-1.3/input0
[    3.966405] input: HOLTEK as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.3/1-1.3:1.1/input/input3
[    3.966480] hid-generic 0003:1241:E000.0002: input,hiddev0,hidraw1: USB HID v1.10 Mouse [HOLTEK] on usb-0000:00:1a.0-1.3/input1
[    3.966605] input: HP HP Wireless Mini Keyboard as /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5/2-1.5:1.0/input/input4
[    3.966649] hid-generic 0003:03F0:A107.0003: input,hidraw2: USB HID v1.11 Keyboard [HP HP Wireless Mini Keyboard] on usb-0000:00:1d.0-1.5/input0
[    3.966752] input: HP HP Wireless Mini Keyboard as /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.5/2-1.5:1.1/input/input5
[    3.966833] hid-generic 0003:03F0:A107.0004: input,hidraw3: USB HID v1.11 Mouse [HP HP Wireless Mini Keyboard] on usb-0000:00:1d.0-1.5/input1

The remote sends ctrl+p and ctrl+shift+p for pause and play. MythTV doesn't
distinguish between the two, so I want to change the shifted P to another key,
such as XF86AudioPlay. I'd also like to change the Backspace to Esc on the remote.
I can make this work with the following script which I lifted from the MythTV
wiki, and then modified:

#!/bin/sh
set -x

remote_id=$(xinput list | sed -n 's/.*HOLTEK.*id=\([0-9]*\).*keyboard.*/\1/p')
[ "$remote_id" ] || exit

mkdir -p /tmp/xkb/symbols
cat >/tmp/xkb/symbols/custom <<\EOF
xkb_symbols "remote" {
	key <AD10> {        [ p,    XF86AudioPlay ]       };
	key <BKSP> { [ Escape, Escape ] };
};
EOF

setxkbmap -device $remote_id -print | sed 's/\(xkb_symbols.*\)"/\1+custom(remote)"/' | xkbcomp -I/tmp/xkb -i $remote_id -synch - $DISPLAY 2>/dev/null


Once run, the HP keyboard p and backspace keys continue to work. But once I run xev
and press the play button, both the remote and the HP keyboard have been remapped.
shift+p sends XF86AudioPlay and Backspace sends Esc on both devices. I checked that
my version of xkbcomp contains the per-device patch by downloading the sources and
checking the contents of xkbcomp.c:

$ grep -B 3 device_id x11-xkb-utils-7.6+4/xkbcomp/xkbcomp.c
static char *preErrorMsg = NULL;
static char *postErrorMsg = NULL;
static char *errorPrefix = NULL;
static unsigned int device_id = XkbUseCoreKbd;
--
                if (warningLevel > 0)
                    WARN("No device ID specified\n");
            }
            device_id = atoi(argv[i]);
--
                ok = False;
                break;
            }
            result.xkb->device_spec = device_id;
--
                ERROR1("Cannot read XKM file \"%s\"\n", inputFile);
                ok = False;
            }
            result.xkb->device_spec = device_id;
--
    {
        bzero((char *) &result, sizeof(result));
        result.type = XkmKeymapFile;
        result.xkb = XkbGetMap(inDpy, XkbAllMapComponentsMask, device_id);


I also confirmed that if I send a bad device_id, the script displays X11 out of range
errors, with the value to the operation being the hex value of the bogus device_id.
No error is reported when I pass "9" (the device_id for the HOLTEK keyboard xinput
assigns to the remote). If I use the HP Wireless xinput device IDs, the remapping does
not take place.

I can reset the devices to their original state using:

$ setxkbmap -print | xkbcomp - $DISPLAY 2>/dev/null

If I try to use "-i 11" or "-i 12" to reset just the HP Wireless keyboard, the change doesn't take effect.

I am running on a 32 bit installation of Ubuntu 12.04 (Mythbuntu specifically). I've
tried this in the XFCE desktop as well as with a .xinitrc with only an xterm running
with the same results.

Am I on the right track? Or is there another method I should be considering?

Can anyone point to why xkbcomp appears to be sending the device_id, yet both
the remote and the keyboard are being remapped?

Thanks in advance!

--
Darren Hart



More information about the xorg mailing list