123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- #include "qemu/osdep.h"
- #include "system/system.h"
- #include "qapi/error.h"
- #include "qapi/qapi-commands-ui.h"
- #include "trace.h"
- #include "ui/input.h"
- #include "ui/console.h"
- #include "system/replay.h"
- #include "system/runstate.h"
- struct QemuInputHandlerState {
- DeviceState *dev;
- const QemuInputHandler *handler;
- int id;
- int events;
- QemuConsole *con;
- QTAILQ_ENTRY(QemuInputHandlerState) node;
- };
- typedef struct QemuInputEventQueue QemuInputEventQueue;
- typedef QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue)
- QemuInputEventQueueHead;
- 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 QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
- static QEMUTimer *kbd_timer;
- static uint32_t kbd_default_delay_ms = 10;
- static uint32_t queue_count;
- static uint32_t queue_limit = 1024;
- QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
- const QemuInputHandler *handler)
- {
- QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
- static int id = 1;
- s->dev = dev;
- s->handler = handler;
- s->id = id++;
- QTAILQ_INSERT_TAIL(&handlers, s, node);
- notifier_list_notify(&mouse_mode_notifiers, NULL);
- return s;
- }
- void qemu_input_handler_activate(QemuInputHandlerState *s)
- {
- QTAILQ_REMOVE(&handlers, s, node);
- QTAILQ_INSERT_HEAD(&handlers, s, node);
- notifier_list_notify(&mouse_mode_notifiers, NULL);
- }
- void qemu_input_handler_deactivate(QemuInputHandlerState *s)
- {
- QTAILQ_REMOVE(&handlers, s, node);
- QTAILQ_INSERT_TAIL(&handlers, s, node);
- notifier_list_notify(&mouse_mode_notifiers, NULL);
- }
- void qemu_input_handler_unregister(QemuInputHandlerState *s)
- {
- QTAILQ_REMOVE(&handlers, s, node);
- g_free(s);
- notifier_list_notify(&mouse_mode_notifiers, NULL);
- }
- void qemu_input_handler_bind(QemuInputHandlerState *s,
- const char *device_id, int head,
- Error **errp)
- {
- QemuConsole *con;
- Error *err = NULL;
- con = qemu_console_lookup_by_device_name(device_id, head, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- s->con = con;
- }
- static QemuInputHandlerState*
- 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;
- }
- }
- return NULL;
- }
- void qmp_input_send_event(const char *device,
- bool has_head, int64_t head,
- InputEventList *events, Error **errp)
- {
- InputEventList *e;
- QemuConsole *con;
- Error *err = NULL;
- con = NULL;
- if (device) {
- if (!has_head) {
- head = 0;
- }
- con = qemu_console_lookup_by_device_name(device, head, &err);
- if (err) {
- error_propagate(errp, err);
- return;
- }
- }
- if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
- error_setg(errp, "VM not running");
- return;
- }
- for (e = events; e != NULL; e = e->next) {
- InputEvent *event = e->value;
- if (!qemu_input_find_handler(1 << event->type, con)) {
- error_setg(errp, "Input handler not found for "
- "event type %s",
- InputEventKind_str(event->type));
- return;
- }
- }
- for (e = events; e != NULL; e = e->next) {
- InputEvent *evt = e->value;
- if (evt->type == INPUT_EVENT_KIND_KEY &&
- evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER) {
- KeyValue *key = evt->u.key.data->key;
- QKeyCode code = qemu_input_key_number_to_qcode(key->u.number.data);
- qemu_input_event_send_key_qcode(con, code, evt->u.key.data->down);
- } else {
- qemu_input_event_send(con, evt);
- }
- }
- qemu_input_event_sync();
- }
- static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
- {
- const char *name;
- int qcode, idx = -1;
- InputKeyEvent *key;
- InputBtnEvent *btn;
- InputMoveEvent *move;
- InputMultiTouchEvent *mtt;
- if (src) {
- idx = qemu_console_get_index(src);
- }
- switch (evt->type) {
- case INPUT_EVENT_KIND_KEY:
- key = evt->u.key.data;
- switch (key->key->type) {
- case KEY_VALUE_KIND_NUMBER:
- qcode = qemu_input_key_number_to_qcode(key->key->u.number.data);
- name = QKeyCode_str(qcode);
- trace_input_event_key_number(idx, key->key->u.number.data,
- name, key->down);
- break;
- case KEY_VALUE_KIND_QCODE:
- name = QKeyCode_str(key->key->u.qcode.data);
- trace_input_event_key_qcode(idx, name, key->down);
- break;
- case KEY_VALUE_KIND__MAX:
- /* keep gcc happy */
- break;
- }
- break;
- case INPUT_EVENT_KIND_BTN:
- btn = evt->u.btn.data;
- name = InputButton_str(btn->button);
- trace_input_event_btn(idx, name, btn->down);
- break;
- case INPUT_EVENT_KIND_REL:
- move = evt->u.rel.data;
- name = InputAxis_str(move->axis);
- trace_input_event_rel(idx, name, move->value);
- break;
- case INPUT_EVENT_KIND_ABS:
- move = evt->u.abs.data;
- name = InputAxis_str(move->axis);
- trace_input_event_abs(idx, name, move->value);
- break;
- case INPUT_EVENT_KIND_MTT:
- mtt = evt->u.mtt.data;
- name = InputAxis_str(mtt->axis);
- trace_input_event_mtt(idx, name, mtt->value);
- break;
- case INPUT_EVENT_KIND__MAX:
- /* keep gcc happy */
- break;
- }
- }
- static void qemu_input_queue_process(void *opaque)
- {
- 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);
- queue_count--;
- 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);
- queue_count--;
- g_free(item);
- }
- }
- static void qemu_input_queue_delay(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);
- queue_count++;
- if (start_timer) {
- timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
- + item->delay_ms);
- }
- }
- static void qemu_input_queue_event(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);
- queue_count++;
- }
- static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
- {
- QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
- item->type = QEMU_INPUT_QUEUE_SYNC;
- QTAILQ_INSERT_TAIL(queue, item, node);
- queue_count++;
- }
- void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
- {
- QemuInputHandlerState *s;
- qemu_input_event_trace(src, evt);
- /* send event */
- s = qemu_input_find_handler(1 << evt->type, src);
- if (!s) {
- return;
- }
- s->handler->event(s->dev, src, evt);
- s->events++;
- }
- void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
- {
- /* Expect all parts of QEMU to send events with QCodes exclusively.
- * Key numbers are only supported as end-user input via QMP */
- assert(!(evt->type == INPUT_EVENT_KIND_KEY &&
- evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER));
- /*
- * 'sysrq' was mistakenly added to hack around the fact that
- * the ps2 driver was not generating correct scancodes sequences
- * when 'alt+print' was pressed. This flaw is now fixed and the
- * 'sysrq' key serves no further purpose. We normalize it to
- * 'print', so that downstream receivers of the event don't
- * need to deal with this mistake
- */
- if (evt->type == INPUT_EVENT_KIND_KEY &&
- evt->u.key.data->key->u.qcode.data == Q_KEY_CODE_SYSRQ) {
- evt->u.key.data->key->u.qcode.data = Q_KEY_CODE_PRINT;
- }
- if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
- return;
- }
- replay_input_event(src, evt);
- }
- void qemu_input_event_sync_impl(void)
- {
- QemuInputHandlerState *s;
- trace_input_event_sync();
- QTAILQ_FOREACH(s, &handlers, node) {
- if (!s->events) {
- continue;
- }
- if (s->handler->sync) {
- s->handler->sync(s->dev);
- }
- s->events = 0;
- }
- }
- void qemu_input_event_sync(void)
- {
- if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
- return;
- }
- replay_input_sync_event();
- }
- static InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
- {
- InputEvent *evt = g_new0(InputEvent, 1);
- evt->u.key.data = g_new0(InputKeyEvent, 1);
- evt->type = INPUT_EVENT_KIND_KEY;
- evt->u.key.data->key = key;
- evt->u.key.data->down = down;
- return evt;
- }
- void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
- {
- InputEvent *evt;
- evt = qemu_input_event_new_key(key, down);
- if (QTAILQ_EMPTY(&kbd_queue)) {
- qemu_input_event_send(src, evt);
- qemu_input_event_sync();
- qapi_free_InputEvent(evt);
- } else if (queue_count < queue_limit) {
- qemu_input_queue_event(&kbd_queue, src, evt);
- qemu_input_queue_sync(&kbd_queue);
- } else {
- qapi_free_InputEvent(evt);
- }
- }
- void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
- {
- QKeyCode code = qemu_input_key_number_to_qcode(num);
- qemu_input_event_send_key_qcode(src, code, down);
- }
- void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
- {
- KeyValue *key = g_new0(KeyValue, 1);
- key->type = KEY_VALUE_KIND_QCODE;
- key->u.qcode.data = q;
- qemu_input_event_send_key(src, key, down);
- }
- void qemu_input_event_send_key_delay(uint32_t delay_ms)
- {
- if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
- return;
- }
- if (!kbd_timer) {
- kbd_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
- SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
- qemu_input_queue_process, &kbd_queue);
- }
- if (queue_count < queue_limit) {
- qemu_input_queue_delay(&kbd_queue, kbd_timer,
- delay_ms ? delay_ms : kbd_default_delay_ms);
- }
- }
- void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
- {
- InputBtnEvent bevt = {
- .button = btn,
- .down = down,
- };
- InputEvent evt = {
- .type = INPUT_EVENT_KIND_BTN,
- .u.btn.data = &bevt,
- };
- qemu_input_event_send(src, &evt);
- }
- void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
- uint32_t button_old, uint32_t button_new)
- {
- InputButton btn;
- uint32_t mask;
- for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) {
- mask = button_map[btn];
- if ((button_old & mask) == (button_new & mask)) {
- continue;
- }
- qemu_input_queue_btn(src, btn, button_new & mask);
- }
- }
- bool qemu_input_is_absolute(QemuConsole *con)
- {
- QemuInputHandlerState *s;
- s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
- con);
- return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
- }
- int qemu_input_scale_axis(int value,
- int min_in, int max_in,
- int min_out, int max_out)
- {
- int64_t range_in = (int64_t)max_in - min_in;
- int64_t range_out = (int64_t)max_out - min_out;
- if (range_in < 1) {
- return min_out + range_out / 2;
- }
- return ((int64_t)value - min_in) * range_out / range_in + min_out;
- }
- void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
- {
- InputMoveEvent move = {
- .axis = axis,
- .value = value,
- };
- InputEvent evt = {
- .type = INPUT_EVENT_KIND_REL,
- .u.rel.data = &move,
- };
- qemu_input_event_send(src, &evt);
- }
- void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
- int min_in, int max_in)
- {
- InputMoveEvent move = {
- .axis = axis,
- .value = qemu_input_scale_axis(value, min_in, max_in,
- INPUT_EVENT_ABS_MIN,
- INPUT_EVENT_ABS_MAX),
- };
- InputEvent evt = {
- .type = INPUT_EVENT_KIND_ABS,
- .u.abs.data = &move,
- };
- qemu_input_event_send(src, &evt);
- }
- void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
- int slot, int tracking_id)
- {
- InputMultiTouchEvent mtt = {
- .type = type,
- .slot = slot,
- .tracking_id = tracking_id,
- };
- InputEvent evt = {
- .type = INPUT_EVENT_KIND_MTT,
- .u.mtt.data = &mtt,
- };
- qemu_input_event_send(src, &evt);
- }
- void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
- int min_in, int max_in, int slot, int tracking_id)
- {
- InputMultiTouchEvent mtt = {
- .type = INPUT_MULTI_TOUCH_TYPE_DATA,
- .slot = slot,
- .tracking_id = tracking_id,
- .axis = axis,
- .value = qemu_input_scale_axis(value, min_in, max_in,
- INPUT_EVENT_ABS_MIN,
- INPUT_EVENT_ABS_MAX),
- };
- InputEvent evt = {
- .type = INPUT_EVENT_KIND_MTT,
- .u.mtt.data = &mtt,
- };
- qemu_input_event_send(src, &evt);
- }
- void qemu_add_mouse_mode_change_notifier(Notifier *notify)
- {
- notifier_list_add(&mouse_mode_notifiers, notify);
- }
- void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
- {
- notifier_remove(notify);
- }
- MouseInfoList *qmp_query_mice(Error **errp)
- {
- MouseInfoList *mice_list = NULL;
- MouseInfo *info;
- QemuInputHandlerState *s;
- bool current = true;
- QTAILQ_FOREACH(s, &handlers, node) {
- if (!(s->handler->mask &
- (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
- continue;
- }
- info = g_new0(MouseInfo, 1);
- info->index = s->id;
- info->name = g_strdup(s->handler->name);
- info->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
- info->current = current;
- current = false;
- QAPI_LIST_PREPEND(mice_list, info);
- }
- return mice_list;
- }
- bool qemu_mouse_set(int index, Error **errp)
- {
- QemuInputHandlerState *s;
- QTAILQ_FOREACH(s, &handlers, node) {
- if (s->id == index) {
- break;
- }
- }
- if (!s) {
- error_setg(errp, "Mouse at index '%d' not found", index);
- return false;
- }
- if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
- INPUT_EVENT_MASK_ABS))) {
- error_setg(errp, "Input device '%s' is not a mouse",
- s->handler->name);
- return false;
- }
- qemu_input_handler_activate(s);
- notifier_list_notify(&mouse_mode_notifiers, NULL);
- return true;
- }
|