From 8b84286f4cd0ff5dbf367dc55cf20d9762ac5634 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 19 May 2014 15:02:21 +0200 Subject: [PATCH] input: switch hid mouse and tablet to the new input layer api. Signed-off-by: Gerd Hoffmann --- hw/input/hid.c | 193 ++++++++++++++++++++++++++--------------- include/hw/input/hid.h | 1 - 2 files changed, 123 insertions(+), 71 deletions(-) diff --git a/hw/input/hid.c b/hw/input/hid.c index ff75e41a46af..295bdab6528c 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -105,57 +105,115 @@ void hid_set_next_idle(HIDState *hs) } } -static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) +static void hid_pointer_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - e->xdx = e->ydy = e->dz = 0; - e->buttons_state = buttons; -} + static const int bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = 0x01, + [INPUT_BUTTON_RIGHT] = 0x02, + [INPUT_BUTTON_MIDDLE] = 0x04, + }; + HIDState *hs = (HIDState *)dev; + HIDPointerEvent *e; -static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, - int x1, int y1, int z1) { - if (xyrel) { - e->xdx += x1; - e->ydy += y1; - } else { - e->xdx = x1; - e->ydy = y1; - /* Windows drivers do not like the 0/0 position and ignore such - * events. */ - if (!(x1 | y1)) { - e->xdx = 1; + assert(hs->n < QUEUE_LENGTH); + e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; + + switch (evt->kind) { + case INPUT_EVENT_KIND_REL: + if (evt->rel->axis == INPUT_AXIS_X) { + e->xdx += evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + e->ydy -= evt->rel->value; + } + break; + + case INPUT_EVENT_KIND_ABS: + if (evt->rel->axis == INPUT_AXIS_X) { + e->xdx = evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + e->ydy = evt->rel->value; + } + break; + + case INPUT_EVENT_KIND_BTN: + if (evt->btn->down) { + e->buttons_state |= bmap[evt->btn->button]; + if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) { + e->dz--; + } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { + e->dz++; + } + } else { + e->buttons_state &= ~bmap[evt->btn->button]; } + break; + + default: + /* keep gcc happy */ + break; } - e->dz += z1; + } -static void hid_pointer_event(void *opaque, - int x1, int y1, int z1, int buttons_state) +static void hid_pointer_sync(DeviceState *dev) { - HIDState *hs = opaque; - unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; - unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; - - /* We combine events where feasible to keep the queue small. We shouldn't - * combine anything with the first event of a particular button state, as - * that would change the location of the button state change. When the - * queue is empty, a second event is needed because we don't know if - * the first event changed the button state. */ - if (hs->n == QUEUE_LENGTH) { - /* Queue full. Discard old button state, combine motion normally. */ - hs->ptr.queue[use_slot].buttons_state = buttons_state; - } else if (hs->n < 2 || - hs->ptr.queue[use_slot].buttons_state != buttons_state || - hs->ptr.queue[previous_slot].buttons_state != - hs->ptr.queue[use_slot].buttons_state) { - /* Cannot or should not combine, so add an empty item to the queue. */ - QUEUE_INCR(use_slot); + HIDState *hs = (HIDState *)dev; + HIDPointerEvent *prev, *curr, *next; + bool event_compression = false; + + if (hs->n == QUEUE_LENGTH-1) { + /* + * Queue full. We are loosing information, but we at least + * keep track of most recent button state. + */ + return; + } + + prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; + curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; + next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; + + if (hs->n > 0) { + /* + * No button state change between previous and current event + * (and previous wasn't seen by the guest yet), so there is + * motion information only and we can combine the two event + * into one. + */ + if (curr->buttons_state == prev->buttons_state) { + event_compression = true; + } + } + + if (event_compression) { + /* add current motion to previous, clear current */ + if (hs->kind == HID_MOUSE) { + prev->xdx += curr->xdx; + curr->xdx = 0; + prev->ydy -= curr->ydy; + curr->ydy = 0; + } else { + prev->xdx = curr->xdx; + prev->ydy = curr->ydy; + } + prev->dz += curr->dz; + curr->dz = 0; + } else { + /* prepate next (clear rel, copy abs + btns) */ + if (hs->kind == HID_MOUSE) { + next->xdx = 0; + next->ydy = 0; + } else { + next->xdx = curr->xdx; + next->ydy = curr->ydy; + } + next->dz = 0; + next->buttons_state = curr->buttons_state; + /* make current guest visible, notify guest */ hs->n++; - hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); + hs->event(hs); } - hid_pointer_event_combine(&hs->ptr.queue[use_slot], - hs->kind == HID_MOUSE, - x1, y1, z1); - hs->event(hs); } static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, @@ -254,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax) void hid_pointer_activate(HIDState *hs) { if (!hs->ptr.mouse_grabbed) { - qemu_activate_mouse_event_handler(hs->ptr.eh_entry); + qemu_input_handler_activate(hs->s); hs->ptr.mouse_grabbed = 1; } } int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) { - int dx, dy, dz, b, l; + int dx, dy, dz, l; int index; HIDPointerEvent *e; @@ -286,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) dz = int_clamp(e->dz, -127, 127); e->dz -= dz; - b = 0; - if (e->buttons_state & MOUSE_EVENT_LBUTTON) { - b |= 0x01; - } - if (e->buttons_state & MOUSE_EVENT_RBUTTON) { - b |= 0x02; - } - if (e->buttons_state & MOUSE_EVENT_MBUTTON) { - b |= 0x04; - } - if (hs->n && !e->dz && (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { @@ -311,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) switch (hs->kind) { case HID_MOUSE: if (len > l) { - buf[l++] = b; + buf[l++] = e->buttons_state; } if (len > l) { buf[l++] = dx; @@ -326,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) case HID_TABLET: if (len > l) { - buf[l++] = b; + buf[l++] = e->buttons_state; } if (len > l) { buf[l++] = dx & 0xff; @@ -420,15 +467,7 @@ void hid_reset(HIDState *hs) void hid_free(HIDState *hs) { - switch (hs->kind) { - case HID_KEYBOARD: - qemu_input_handler_unregister(hs->s); - break; - case HID_MOUSE: - case HID_TABLET: - qemu_remove_mouse_event_handler(hs->ptr.eh_entry); - break; - } + qemu_input_handler_unregister(hs->s); hid_del_idle_timer(hs); } @@ -438,6 +477,20 @@ static QemuInputHandler hid_keyboard_handler = { .event = hid_keyboard_event, }; +static QemuInputHandler hid_mouse_handler = { + .name = "QEMU HID Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = hid_pointer_event, + .sync = hid_pointer_sync, +}; + +static QemuInputHandler hid_tablet_handler = { + .name = "QEMU HID Tablet", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, + .event = hid_pointer_event, + .sync = hid_pointer_sync, +}; + void hid_init(HIDState *hs, int kind, HIDEventFunc event) { hs->kind = kind; @@ -448,11 +501,11 @@ void hid_init(HIDState *hs, int kind, HIDEventFunc event) &hid_keyboard_handler); qemu_input_handler_activate(hs->s); } else if (hs->kind == HID_MOUSE) { - hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, - 0, "QEMU HID Mouse"); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_mouse_handler); } else if (hs->kind == HID_TABLET) { - hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, - 1, "QEMU HID Tablet"); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_tablet_handler); } } diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h index fb913ba3bb5e..2127c7ce454e 100644 --- a/include/hw/input/hid.h +++ b/include/hw/input/hid.h @@ -23,7 +23,6 @@ typedef void (*HIDEventFunc)(HIDState *s); typedef struct HIDMouseState { HIDPointerEvent queue[QUEUE_LENGTH]; int mouse_grabbed; - QEMUPutMouseEntry *eh_entry; } HIDMouseState; typedef struct HIDKeyboardState {