summaryrefslogtreecommitdiffstats
path: root/hw/input/hid.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/input/hid.c')
-rw-r--r--hw/input/hid.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/hw/input/hid.c b/hw/input/hid.c
index 6841cb8..21ebd9e 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -239,7 +239,7 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
static void hid_keyboard_process_keycode(HIDState *hs)
{
- uint8_t hid_code, key;
+ uint8_t hid_code, index, key;
int i, keycode, slot;
if (hs->n == 0) {
@@ -249,7 +249,8 @@ static void hid_keyboard_process_keycode(HIDState *hs)
keycode = hs->kbd.keycodes[slot];
key = keycode & 0x7f;
- hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+ index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
+ hid_code = hid_usage_keys[index];
hs->kbd.modifiers &= ~(1 << 8);
switch (hid_code) {
@@ -257,18 +258,41 @@ static void hid_keyboard_process_keycode(HIDState *hs)
return;
case 0xe0:
+ assert(key == 0x1d);
if (hs->kbd.modifiers & (1 << 9)) {
- hs->kbd.modifiers ^= 3 << 8;
+ /* The hid_codes for the 0xe1/0x1d scancode sequence are 0xe9/0xe0.
+ * Here we're processing the second hid_code. By dropping bit 9
+ * and setting bit 8, the scancode after 0x1d will access the
+ * second half of the table.
+ */
+ hs->kbd.modifiers ^= (1 << 8) | (1 << 9);
return;
}
+ /* fall through to process Ctrl_L */
case 0xe1 ... 0xe7:
+ /* Ctrl_L/Ctrl_R, Shift_L/Shift_R, Alt_L/Alt_R, Win_L/Win_R.
+ * Handle releases here, or fall through to process presses.
+ */
if (keycode & (1 << 7)) {
hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
return;
}
- case 0xe8 ... 0xef:
+ /* fall through */
+ case 0xe8 ... 0xe9:
+ /* USB modifiers are just 1 byte long. Bits 8 and 9 of
+ * hs->kbd.modifiers implement a state machine that detects the
+ * 0xe0 and 0xe1/0x1d sequences. These bits do not follow the
+ * usual rules where bit 7 marks released keys; they are cleared
+ * elsewhere in the function as the state machine dictates.
+ */
hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
return;
+
+ case 0xea ... 0xef:
+ abort();
+
+ default:
+ break;
}
if (keycode & (1 << 7)) {
OpenPOWER on IntegriCloud