@@ -27,47 +27,144 @@
#include "ui/console.h"
#include "qemu/timer.h"
#include "hw/input/hid.h"
+#include "include/hw/input/usb-keys.h"
+#include <math.h>
#define HID_USAGE_ERROR_ROLLOVER 0x01
#define HID_USAGE_POSTFAIL 0x02
#define HID_USAGE_ERROR_UNDEFINED 0x03
-/* Indices are QEMU keycodes, values are from HID Usage Table. Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d. */
-static const uint8_t hid_usage_keys[0x100] = {
- 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
- 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
- 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
- 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
- 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
- 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
- 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
- 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
- 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
- 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
- 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44,
- 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
- 0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
- 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
- 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
- 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+#define RELEASED -1
+#define PUSHED -2
+
+/* Translates a QKeyCode to USB HID value */
+static const uint8_t qcode_to_usb_hid[] = {
+ [Q_KEY_CODE_SHIFT] = USB_HID_LEFT_SHIFT,
+ [Q_KEY_CODE_SHIFT_R] = USB_HID_RIGHT_SHIFT,
+ [Q_KEY_CODE_ALT] = USB_HID_LEFT_OPTION,
+ [Q_KEY_CODE_ALT_R] = USB_HID_RIGHT_OPTION,
+ [Q_KEY_CODE_ALTGR] = USB_HID_LEFT_OPTION,
+ [Q_KEY_CODE_ALTGR_R] = USB_HID_RIGHT_OPTION,
+ [Q_KEY_CODE_CTRL] = USB_HID_LEFT_CONTROL,
+ [Q_KEY_CODE_CTRL_R] = USB_HID_RIGHT_CONTROL,
+ [Q_KEY_CODE_MENU] = USB_HID_MENU,
+ [Q_KEY_CODE_ESC] = USB_HID_ESC,
+ [Q_KEY_CODE_1] = USB_HID_1,
+ [Q_KEY_CODE_2] = USB_HID_2,
+ [Q_KEY_CODE_3] = USB_HID_3,
+ [Q_KEY_CODE_4] = USB_HID_4,
+ [Q_KEY_CODE_5] = USB_HID_5,
+ [Q_KEY_CODE_6] = USB_HID_6,
+ [Q_KEY_CODE_7] = USB_HID_7,
+ [Q_KEY_CODE_8] = USB_HID_8,
+ [Q_KEY_CODE_9] = USB_HID_9,
+ [Q_KEY_CODE_0] = USB_HID_0,
+ [Q_KEY_CODE_MINUS] = USB_HID_MINUS,
+ [Q_KEY_CODE_EQUAL] = USB_HID_EQUALS,
+ [Q_KEY_CODE_BACKSPACE] = USB_HID_DELETE,
+ [Q_KEY_CODE_TAB] = USB_HID_TAB,
+ [Q_KEY_CODE_Q] = USB_HID_Q,
+ [Q_KEY_CODE_W] = USB_HID_W,
+ [Q_KEY_CODE_E] = USB_HID_E,
+ [Q_KEY_CODE_R] = USB_HID_R,
+ [Q_KEY_CODE_T] = USB_HID_T,
+ [Q_KEY_CODE_Y] = USB_HID_Y,
+ [Q_KEY_CODE_U] = USB_HID_U,
+ [Q_KEY_CODE_I] = USB_HID_I,
+ [Q_KEY_CODE_O] = USB_HID_O,
+ [Q_KEY_CODE_P] = USB_HID_P,
+ [Q_KEY_CODE_BRACKET_LEFT] = USB_HID_LEFT_BRACKET,
+ [Q_KEY_CODE_BRACKET_RIGHT] = USB_HID_RIGHT_BRACKET,
+ [Q_KEY_CODE_RET] = USB_HID_RETURN,
+ [Q_KEY_CODE_A] = USB_HID_A,
+ [Q_KEY_CODE_S] = USB_HID_S,
+ [Q_KEY_CODE_D] = USB_HID_D,
+ [Q_KEY_CODE_F] = USB_HID_F,
+ [Q_KEY_CODE_G] = USB_HID_G,
+ [Q_KEY_CODE_H] = USB_HID_H,
+ [Q_KEY_CODE_J] = USB_HID_J,
+ [Q_KEY_CODE_K] = USB_HID_K,
+ [Q_KEY_CODE_L] = USB_HID_L,
+ [Q_KEY_CODE_SEMICOLON] = USB_HID_SEMICOLON,
+ [Q_KEY_CODE_APOSTROPHE] = USB_HID_QUOTE,
+ [Q_KEY_CODE_GRAVE_ACCENT] = USB_HID_GRAVE_ACCENT,
+ [Q_KEY_CODE_BACKSLASH] = USB_HID_BACKSLASH,
+ [Q_KEY_CODE_Z] = USB_HID_Z,
+ [Q_KEY_CODE_X] = USB_HID_X,
+ [Q_KEY_CODE_C] = USB_HID_C,
+ [Q_KEY_CODE_V] = USB_HID_V,
+ [Q_KEY_CODE_B] = USB_HID_B,
+ [Q_KEY_CODE_N] = USB_HID_N,
+ [Q_KEY_CODE_M] = USB_HID_M,
+ [Q_KEY_CODE_COMMA] = USB_HID_COMMA,
+ [Q_KEY_CODE_DOT] = USB_HID_PERIOD,
+ [Q_KEY_CODE_SLASH] = USB_HID_FORWARD_SLASH,
+ [Q_KEY_CODE_ASTERISK] = USB_HID_KP_MULTIPLY,
+ [Q_KEY_CODE_SPC] = USB_HID_SPACE,
+ [Q_KEY_CODE_CAPS_LOCK] = USB_HID_CAPS_LOCK,
+ [Q_KEY_CODE_F1] = USB_HID_F1,
+ [Q_KEY_CODE_F2] = USB_HID_F2,
+ [Q_KEY_CODE_F3] = USB_HID_F3,
+ [Q_KEY_CODE_F4] = USB_HID_F4,
+ [Q_KEY_CODE_F5] = USB_HID_F5,
+ [Q_KEY_CODE_F6] = USB_HID_F6,
+ [Q_KEY_CODE_F7] = USB_HID_F7,
+ [Q_KEY_CODE_F8] = USB_HID_F8,
+ [Q_KEY_CODE_F9] = USB_HID_F9,
+ [Q_KEY_CODE_F10] = USB_HID_F10,
+ [Q_KEY_CODE_NUM_LOCK] = USB_HID_CLEAR,
+ [Q_KEY_CODE_SCROLL_LOCK] = USB_HID_SCROLL_LOCK,
+ [Q_KEY_CODE_KP_DIVIDE] = USB_HID_KP_DIVIDE,
+ [Q_KEY_CODE_KP_MULTIPLY] = USB_HID_KP_MULTIPLY,
+ [Q_KEY_CODE_KP_SUBTRACT] = USB_HID_KP_MINUS,
+ [Q_KEY_CODE_KP_ADD] = USB_HID_KP_ADD,
+ [Q_KEY_CODE_KP_ENTER] = USB_HID_KP_ENTER,
+ [Q_KEY_CODE_KP_DECIMAL] = USB_HID_KP_PERIOD,
+ [Q_KEY_CODE_SYSRQ] = USB_HID_PRINT,
+ [Q_KEY_CODE_KP_0] = USB_HID_KP_0,
+ [Q_KEY_CODE_KP_1] = USB_HID_KP_1,
+ [Q_KEY_CODE_KP_2] = USB_HID_KP_2,
+ [Q_KEY_CODE_KP_3] = USB_HID_KP_3,
+ [Q_KEY_CODE_KP_4] = USB_HID_KP_4,
+ [Q_KEY_CODE_KP_5] = USB_HID_KP_5,
+ [Q_KEY_CODE_KP_6] = USB_HID_KP_6,
+ [Q_KEY_CODE_KP_7] = USB_HID_KP_7,
+ [Q_KEY_CODE_KP_8] = USB_HID_KP_8,
+ [Q_KEY_CODE_KP_9] = USB_HID_KP_9,
+ [Q_KEY_CODE_LESS] = 0,
+ [Q_KEY_CODE_F11] = USB_HID_F11,
+ [Q_KEY_CODE_F12] = USB_HID_F12,
+ [Q_KEY_CODE_PRINT] = USB_HID_PRINT,
+ [Q_KEY_CODE_HOME] = USB_HID_HOME,
+ [Q_KEY_CODE_PGUP] = USB_HID_PAGE_UP,
+ [Q_KEY_CODE_PGDN] = USB_HID_PAGE_DOWN,
+ [Q_KEY_CODE_END] = USB_HID_END,
+ [Q_KEY_CODE_LEFT] = USB_HID_LEFT_ARROW,
+ [Q_KEY_CODE_UP] = USB_HID_UP_ARROW,
+ [Q_KEY_CODE_DOWN] = USB_HID_DOWN_ARROW,
+ [Q_KEY_CODE_RIGHT] = USB_HID_RIGHT_ARROW,
+ [Q_KEY_CODE_INSERT] = USB_HID_INSERT,
+ [Q_KEY_CODE_DELETE] = USB_HID_FORWARD_DELETE,
+ [Q_KEY_CODE_STOP] = USB_HID_STOP,
+ [Q_KEY_CODE_AGAIN] = USB_HID_AGAIN,
+ [Q_KEY_CODE_PROPS] = 0,
+ [Q_KEY_CODE_UNDO] = USB_HID_UNDO,
+ [Q_KEY_CODE_FRONT] = 0,
+ [Q_KEY_CODE_COPY] = USB_HID_COPY,
+ [Q_KEY_CODE_OPEN] = 0,
+ [Q_KEY_CODE_PASTE] = USB_HID_PASTE,
+ [Q_KEY_CODE_FIND] = USB_HID_FIND,
+ [Q_KEY_CODE_CUT] = USB_HID_CUT,
+ [Q_KEY_CODE_LF] = 0,
+ [Q_KEY_CODE_HELP] = USB_HID_HELP,
+ [Q_KEY_CODE_META_L] = USB_HID_LEFT_GUI,
+ [Q_KEY_CODE_META_R] = USB_HID_RIGHT_GUI,
+ [Q_KEY_CODE_COMPOSE] = 0,
+ [Q_KEY_CODE_PAUSE] = USB_HID_PAUSE,
+ [Q_KEY_CODE_RO] = 0,
+ [Q_KEY_CODE_KP_COMMA] = USB_HID_KP_COMMA,
+ [Q_KEY_CODE_KP_EQUALS] = USB_HID_KP_EQUALS,
+ [Q_KEY_CODE_POWER] = USB_HID_POWER,
};
bool hid_has_events(HIDState *hs)
@@ -227,12 +324,22 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
{
HIDState *hs = (HIDState *)dev;
int scancodes[3], i, count;
- int slot;
- InputKeyEvent *key = evt->u.key.data;
+ int slot, qcode, keycode;
+
+ qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key);
+ if (qcode >= ARRAY_SIZE(qcode_to_usb_hid)) {
+ return;
+ }
+ keycode = qcode_to_usb_hid[qcode];
+
+ count = 2;
+ if (evt->u.key.data->down == false) { /* if key up event */
+ scancodes[0] = RELEASED;
+ } else {
+ scancodes[0] = PUSHED;
+ }
+ scancodes[1] = keycode;
- count = qemu_input_key_value_to_scancode(key->key,
- key->down,
- scancodes);
if (hs->n + count > QUEUE_LENGTH) {
fprintf(stderr, "usb-kbd: warning: key event queue full\n");
return;
@@ -244,67 +351,47 @@ static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
hs->event(hs);
}
+/* Sets the modifiers variable */
+static void set_modifiers(int status, int bit_position, uint16_t *modifiers)
+{
+ int value = pow(2, bit_position);
+ if (status == PUSHED) {
+ *modifiers |= value;
+ } else {
+ *modifiers &= ~value;
+ }
+}
+
+/* Handles the modifier keys - they are handled differently from other keys. */
+static void process_modifier_key(int status, int keycode, uint16_t *modifiers)
+{
+ /* subtracting 0xe0 from the keycode gives us the bit position */
+ set_modifiers(status, keycode - 0xe0, modifiers);
+}
+
static void hid_keyboard_process_keycode(HIDState *hs)
{
- uint8_t hid_code, index, key;
- int i, keycode, slot;
+ int i, keycode, slot, status;
if (hs->n == 0) {
return;
}
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+ status = hs->kbd.keycodes[slot];
+ slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
keycode = hs->kbd.keycodes[slot];
- key = keycode & 0x7f;
- index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
- hid_code = hid_usage_keys[index];
- hs->kbd.modifiers &= ~(1 << 8);
-
- switch (hid_code) {
- case 0x00:
- return;
-
- case 0xe0:
- assert(key == 0x1d);
- if (hs->kbd.modifiers & (1 << 9)) {
- /* 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;
- }
- /* 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);
+ /* handle Control, Option, GUI/Windows/Command, and Shift keys */
+ if (keycode >= 0xe0) {
+ process_modifier_key(status, keycode, &(hs->kbd.modifiers));
return;
-
- case 0xea ... 0xef:
- abort();
-
- default:
- break;
}
- if (keycode & (1 << 7)) {
+ /* if key released */
+ if (status == RELEASED) {
+ /* find the key then remove it from the buffer */
for (i = hs->kbd.keys - 1; i >= 0; i--) {
- if (hs->kbd.key[i] == hid_code) {
+ if (hs->kbd.key[i] == keycode) {
hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
hs->kbd.key[hs->kbd.keys] = 0x00;
break;
@@ -314,14 +401,15 @@ static void hid_keyboard_process_keycode(HIDState *hs)
return;
}
} else {
+ /* search for the key's location in the buffer */
for (i = hs->kbd.keys - 1; i >= 0; i--) {
- if (hs->kbd.key[i] == hid_code) {
+ if (hs->kbd.key[i] == keycode) {
break;
}
}
if (i < 0) {
if (hs->kbd.keys < sizeof(hs->kbd.key)) {
- hs->kbd.key[hs->kbd.keys++] = hid_code;
+ hs->kbd.key[hs->kbd.keys++] = keycode;
}
} else {
return;
Switches hid.c from PS/2 to QKeyCode support. Signed-off-by: John Arbuckle <programmingkidx@gmail.com> --- hw/input/hid.c | 270 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 179 insertions(+), 91 deletions(-)