diff options
Diffstat (limited to 'ui/input.c')
-rw-r--r-- | ui/input.c | 157 |
1 files changed, 149 insertions, 8 deletions
diff --git a/ui/input.c b/ui/input.c index fc91fba83c..89d9db78c0 100644 --- a/ui/input.c +++ b/ui/input.c @@ -1,3 +1,4 @@ +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qapi-types.h" #include "qmp-commands.h" @@ -10,13 +11,34 @@ struct QemuInputHandlerState { QemuInputHandler *handler; int id; int events; + QemuConsole *con; QTAILQ_ENTRY(QemuInputHandlerState) node; }; + +typedef struct QemuInputEventQueue QemuInputEventQueue; +struct QemuInputEventQueue { + enum { + QEMU_INPUT_QUEUE_DELAY = 1, + QEMU_INPUT_QUEUE_EVENT, + QEMU_INPUT_QUEUE_SYNC, + } type; + QEMUTimer *timer; + uint32_t delay_ms; + QemuConsole *src; + InputEvent *evt; + QTAILQ_ENTRY(QemuInputEventQueue) node; +}; + static QTAILQ_HEAD(, QemuInputHandlerState) handlers = QTAILQ_HEAD_INITIALIZER(handlers); static NotifierList mouse_mode_notifiers = NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); +static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue = + QTAILQ_HEAD_INITIALIZER(kbd_queue); +static QEMUTimer *kbd_timer; +static uint32_t kbd_default_delay_ms = 10; + QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, QemuInputHandler *handler) { @@ -53,12 +75,46 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s) qemu_input_check_mode_change(); } +void qemu_input_handler_bind(QemuInputHandlerState *s, + const char *device_id, int head, + Error **errp) +{ + DeviceState *dev; + QemuConsole *con; + + dev = qdev_find_recursive(sysbus_get_default(), device_id); + if (dev == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device_id); + return; + } + + con = qemu_console_lookup_by_device(dev, head); + if (con == NULL) { + error_setg(errp, "Device %s is not bound to a QemuConsole", device_id); + return; + } + + s->con = con; +} + static QemuInputHandlerState* -qemu_input_find_handler(uint32_t mask) +qemu_input_find_handler(uint32_t mask, QemuConsole *con) { QemuInputHandlerState *s; QTAILQ_FOREACH(s, &handlers, node) { + if (s->con == NULL || s->con != con) { + continue; + } + if (mask & s->handler->mask) { + return s; + } + } + + QTAILQ_FOREACH(s, &handlers, node) { + if (s->con != NULL) { + continue; + } if (mask & s->handler->mask) { return s; } @@ -94,7 +150,7 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt) static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) { const char *name; - int idx = -1; + int qcode, idx = -1; if (src) { idx = qemu_console_get_index(src); @@ -103,8 +159,10 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) case INPUT_EVENT_KIND_KEY: switch (evt->key->key->kind) { case KEY_VALUE_KIND_NUMBER: + qcode = qemu_input_key_number_to_qcode(evt->key->key->number); + name = QKeyCode_lookup[qcode]; trace_input_event_key_number(idx, evt->key->key->number, - evt->key->down); + name, evt->key->down); break; case KEY_VALUE_KIND_QCODE: name = QKeyCode_lookup[evt->key->key->qcode]; @@ -133,6 +191,73 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) } } +static void qemu_input_queue_process(void *opaque) +{ + struct QemuInputEventQueueHead *queue = opaque; + QemuInputEventQueue *item; + + g_assert(!QTAILQ_EMPTY(queue)); + item = QTAILQ_FIRST(queue); + g_assert(item->type == QEMU_INPUT_QUEUE_DELAY); + QTAILQ_REMOVE(queue, item, node); + g_free(item); + + while (!QTAILQ_EMPTY(queue)) { + item = QTAILQ_FIRST(queue); + switch (item->type) { + case QEMU_INPUT_QUEUE_DELAY: + timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + item->delay_ms); + return; + case QEMU_INPUT_QUEUE_EVENT: + qemu_input_event_send(item->src, item->evt); + qapi_free_InputEvent(item->evt); + break; + case QEMU_INPUT_QUEUE_SYNC: + qemu_input_event_sync(); + break; + } + QTAILQ_REMOVE(queue, item, node); + g_free(item); + } +} + +static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue, + QEMUTimer *timer, uint32_t delay_ms) +{ + QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1); + bool start_timer = QTAILQ_EMPTY(queue); + + item->type = QEMU_INPUT_QUEUE_DELAY; + item->delay_ms = delay_ms; + item->timer = timer; + QTAILQ_INSERT_TAIL(queue, item, node); + + if (start_timer) { + timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + item->delay_ms); + } +} + +static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue, + QemuConsole *src, InputEvent *evt) +{ + QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1); + + item->type = QEMU_INPUT_QUEUE_EVENT; + item->src = src; + item->evt = evt; + QTAILQ_INSERT_TAIL(queue, item, node); +} + +static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue) +{ + QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1); + + item->type = QEMU_INPUT_QUEUE_SYNC; + QTAILQ_INSERT_TAIL(queue, item, node); +} + void qemu_input_event_send(QemuConsole *src, InputEvent *evt) { QemuInputHandlerState *s; @@ -149,7 +274,7 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt) } /* send event */ - s = qemu_input_find_handler(1 << evt->kind); + s = qemu_input_find_handler(1 << evt->kind, src); if (!s) { return; } @@ -192,9 +317,14 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down) { InputEvent *evt; evt = qemu_input_event_new_key(key, down); - qemu_input_event_send(src, evt); - qemu_input_event_sync(); - qapi_free_InputEvent(evt); + if (QTAILQ_EMPTY(&kbd_queue)) { + qemu_input_event_send(src, evt); + qemu_input_event_sync(); + qapi_free_InputEvent(evt); + } else { + qemu_input_queue_event(&kbd_queue, src, evt); + qemu_input_queue_sync(&kbd_queue); + } } void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down) @@ -213,6 +343,16 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down) qemu_input_event_send_key(src, key, down); } +void qemu_input_event_send_key_delay(uint32_t delay_ms) +{ + if (!kbd_timer) { + kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process, + &kbd_queue); + } + qemu_input_queue_delay(&kbd_queue, kbd_timer, + delay_ms ? delay_ms : kbd_default_delay_ms); +} + InputEvent *qemu_input_event_new_btn(InputButton btn, bool down) { InputEvent *evt = g_new0(InputEvent, 1); @@ -250,7 +390,8 @@ bool qemu_input_is_absolute(void) { QemuInputHandlerState *s; - s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS); + s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS, + NULL); return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); } |