Opened 12 years ago

Closed 12 years ago

#3841 closed bug (fixed)

USB Keyboard Loses Shift State When Changing Shift Keys

Reported by: bonefish Owned by: mmlr
Priority: normal Milestone: R1
Component: Servers/input_server Version: R1/pre-alpha1
Keywords: Cc:
Blocked By: Blocking:
Platform: All


Haiku hrev30344, gcc4, Lenovo T61, Kinesis USB keyboard:

  • In a text editor start selecting text with left shift + cursor keys.
  • While still holding the left shift key, press the right shift key.
  • Release the left shift key, while still holding the right shift key.
  • Continue holding the right shift key and extending the selection with the cursor keys.

Works fine with PS/2 keyboard, but with the USB keyboard the selection is lost. Apparently the application is no longer aware that a shift key is held.

In case anyone wonders, the Kinesis keyboard has the up/down and left/right cursor keys on different sides of the keyboard, which makes switching shift keys necessary when selecting with the cursor keys.

Change History (4)

comment:1 by mmlr, 12 years ago

Status: newassigned

Funny that you report this right now. I experienced this yesterday and wondered if this was only with usb_hid or also with PS/2. In that case I'll look into it.

comment:2 by mmlr, 12 years ago

Component: Drivers/USBDrivers/Keyboard/USB

comment:3 by mmlr, 12 years ago

Component: Drivers/Keyboard/USBServers/input_server

Actually this is not a problem of usb_hid. The keyboard input_server add-on handles the modifier changes incorrectly. The reported modifier state looks about as follows:

left shift down:  0x0000 -> 0x0101 = B_SHIFT_KEY | B_LEFT_SHIFT_KEY
right shift down: 0x0101 -> 0x0301 = B_SHIFT_KEY | B_LEFT_SHIFT_KEY | B_RIGHT_SHIFT_KEY
left shift up:    0x0301 -> 0x0200 = B_RIGHT_SHIFT_KEY

So when the left shift key is released it will not only remove the B_LEFT_SHIFT_KEY flag, but also incorrectly remove the B_SHIFT_KEY flag. You can see this pretty well in the Keymap preferences where the correct shift key is always displayed as pressed, but the keymap changes from shifted to unshifted when releasing the first modifier key.

The reason why you don't see it for PS/2 is a behavioural difference. The PS/2 keyboard driver includes modifiers in repeat key handling, meaning that a pressed shift key will constantly fire B_UNMAPPED_KEY_DOWN and B_MODIFIERS_CHANGED messages. For usb_hid this isn't the case, as it only repeats actual keys and no modifiers. What you get is that the B_SHIFT_KEY flag is removed (incorrectly) as above, but on the next repeat it'll get set again. You can see that in the Keymap prefs as well, as when you release one of the shift keys, the keymap will switch to the unshifted one for a short time and then be shifted again.

I'm looking into fixing the lost B_SHIFT_KEY flag now, but I'm not sure about the behaviour difference. I personally find it more sensible to exclude the modifiers from repeat handling as in the usb_hid case as they don't actually need to be repeated.

comment:4 by mmlr, 12 years ago

Resolution: fixed
Status: assignedclosed

Fixed in hrev30538.

Note: See TracTickets for help on using tickets.