Bug 76461 - USB HID modifier keys dropped when encoded in key array
Summary: USB HID modifier keys dropped when encoded in key array
Status: NEW
Alias: None
Product: Drivers
Classification: Unclassified
Component: Input Devices (show other bugs)
Hardware: x86-64 Linux
: P1 normal
Assignee: drivers_input-devices
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-05-19 02:43 UTC by Bryan C. Mills
Modified: 2014-10-17 02:16 UTC (History)
2 users (show)

See Also:
Kernel Version: 3.13.7-1
Subsystem:
Regression: No
Bisected commit-id:


Attachments
evemu-record output for "+ctrl, +alt, -alt, -ctrl" (9.15 KB, text/plain)
2014-05-19 02:43 UTC, Bryan C. Mills
Details
usbhid-dump -e all (1.38 KB, text/plain)
2014-05-19 15:00 UTC, Bryan C. Mills
Details

Description Bryan C. Mills 2014-05-19 02:43:21 UTC
Created attachment 136651 [details]
evemu-record output for "+ctrl, +alt, -alt, -ctrl"

I recently acquired a Delcom foot pedal to use for modifier keys (Ctrl, Alt, Shift).  It works fine on Windows, but not on Linux.

The symptom is that the first modifier is dropped when the second key is depressed.  For example, for the sequence "press Ctrl, press Alt, release Alt, release Ctrl", the kernel generates a spurious release event for the Ctrl key as soon as the Alt key is pressed.

I ran a USB sniffer on the foot pedal, and discovered that it's encoding modifier keys a bit differently than a standard keyboard.  It has the usual 8-bit bitfield for modifier keys, but doesn't use that for buttons that have been assigned to modifiers directly.  Instead, it encodes the corresponding codes (E0-E8) in the array with all of the other keys.

I suspect that the interaction of the key codes with the bitfield is causing the driver to generate the spurious release event.


The output of usbhid-dump for that sequence (ctrl down, alt down, alt up, ctrl up) is:

003:126:000:STREAM             1400459270.547743
 DC 00 00 E4 00 00 00 00

003:126:000:STREAM             1400459272.155765
 DC 00 00 E4 00 00 E2 00

003:126:000:STREAM             1400459273.587799
 DC 00 00 E4 00 00 00 00

003:126:000:STREAM             1400459274.971830
 DC 00 00 00 00 00 00 00

As you can see, the "Alt down" (E2) event still includes the Ctrl key (E4), and all of the flag bits (the second byte of each event) remain clear the whole time.


Please find the output of evemu-record for the same sequence attached.


See also https://bugs.freedesktop.org/show_bug.cgi?id=78868 - I had initially thought it was an evdev bug, but the X.org devs tell me the issue is in the kernel.
Comment 1 Bryan C. Mills 2014-05-19 15:00:13 UTC
Created attachment 136761 [details]
usbhid-dump -e all

usbhid-dump with descriptor
Comment 2 Benjamin Tissoires 2014-05-19 19:28:19 UTC
It took me a while to realise that the device is sending two times the modifiers in the same report:
- the first byte is the reportID
- the second byte contains an array of modifiers, which are null in your case (control, alt, shift, GUI, for left and right)
- the third byte is a constant
- the last five bytes are the actual array of keys.

The following occurs:
- DC 00 00 E4 00 00 00 00 is translated to:
input_event(input, KEY, KEY_LEFTCTRL, 0)
input_event(input, KEY, KEY_LEFTALT, 0)
...
input_event(input, KEY, KEY_LEFTCTRL, 1)

- DC 00 00 E4 00 00 E2 00 is translated to:
input_event(input, KEY, KEY_LEFTCTRL, 0)
input_event(input, KEY, KEY_LEFTALT, 0)
...
input_event(input, KEY, KEY_LEFTALT, 1)

(KEY_LEFTCTRL 1 is ignored because the array already set it)

- DC 00 00 E4 00 00 00 00 is translated to:
input_event(input, KEY, KEY_LEFTCTRL, 0)
input_event(input, KEY, KEY_LEFTALT, 0)
...
input_event(input, KEY, KEY_LEFTALT, 0)

- DC 00 00 00 00 00 00 00 is translated to:
input_event(input, KEY, KEY_LEFTCTRL, 0)
input_event(input, KEY, KEY_LEFTALT, 0)
...
input_event(input, KEY, KEY_LEFTCTRL, 0)

So there is a conflict between the modifiers at the beginning of the report and the actual keys in the array.

I can see two solutions to fix that:
1. change hid-input.c to send the key down no matter was the previous state
2. fix the report descriptor of the device, and set the first byte as constant.

Both solutions are working, but I am not sure which one to pick actually.

The second one should be preferable, but we need more tests with the device to be sure that the first useful byte is actually always 00.
Comment 3 Bryan C. Mills 2014-05-19 20:11:42 UTC
The report descriptor is actually accurate - when programmed for mod+key combinations all on one pedal, the footswitch encodes the mod bits in the second byte and the remaining keys in the 5-byte array.  If you like, I can reprogram the pedal and send traces exhibiting this behavior.

(Unfortunately, it doesn't correctly union the mod bits, but that's clearly a defect of the manufacturer and not a bug in the kernel.)


So amending the descriptor would actually break some functionality of the switch, albeit functionality that I'm not using and don't really care about.  (There may be other users who do care about that, though.)

That being the case, I think option (1) (send the key-down regardless of state) is preferable.

Note You need to log in before you can comment on or make changes to this bug.