qemu/ui/input.c
<<
>>
Prefs
   1#include "hw/qdev.h"
   2#include "sysemu/sysemu.h"
   3#include "qapi-types.h"
   4#include "qmp-commands.h"
   5#include "trace.h"
   6#include "ui/input.h"
   7#include "ui/console.h"
   8
   9struct QemuInputHandlerState {
  10    DeviceState       *dev;
  11    QemuInputHandler  *handler;
  12    int               id;
  13    int               events;
  14    QemuConsole       *con;
  15    QTAILQ_ENTRY(QemuInputHandlerState) node;
  16};
  17
  18typedef struct QemuInputEventQueue QemuInputEventQueue;
  19struct QemuInputEventQueue {
  20    enum {
  21        QEMU_INPUT_QUEUE_DELAY = 1,
  22        QEMU_INPUT_QUEUE_EVENT,
  23        QEMU_INPUT_QUEUE_SYNC,
  24    } type;
  25    QEMUTimer *timer;
  26    uint32_t delay_ms;
  27    QemuConsole *src;
  28    InputEvent *evt;
  29    QTAILQ_ENTRY(QemuInputEventQueue) node;
  30};
  31
  32static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
  33    QTAILQ_HEAD_INITIALIZER(handlers);
  34static NotifierList mouse_mode_notifiers =
  35    NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
  36
  37static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
  38    QTAILQ_HEAD_INITIALIZER(kbd_queue);
  39static QEMUTimer *kbd_timer;
  40static uint32_t kbd_default_delay_ms = 10;
  41
  42QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
  43                                                   QemuInputHandler *handler)
  44{
  45    QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
  46    static int id = 1;
  47
  48    s->dev = dev;
  49    s->handler = handler;
  50    s->id = id++;
  51    QTAILQ_INSERT_TAIL(&handlers, s, node);
  52
  53    qemu_input_check_mode_change();
  54    return s;
  55}
  56
  57void qemu_input_handler_activate(QemuInputHandlerState *s)
  58{
  59    QTAILQ_REMOVE(&handlers, s, node);
  60    QTAILQ_INSERT_HEAD(&handlers, s, node);
  61    qemu_input_check_mode_change();
  62}
  63
  64void qemu_input_handler_deactivate(QemuInputHandlerState *s)
  65{
  66    QTAILQ_REMOVE(&handlers, s, node);
  67    QTAILQ_INSERT_TAIL(&handlers, s, node);
  68    qemu_input_check_mode_change();
  69}
  70
  71void qemu_input_handler_unregister(QemuInputHandlerState *s)
  72{
  73    QTAILQ_REMOVE(&handlers, s, node);
  74    g_free(s);
  75    qemu_input_check_mode_change();
  76}
  77
  78void qemu_input_handler_bind(QemuInputHandlerState *s,
  79                             const char *device_id, int head,
  80                             Error **errp)
  81{
  82    DeviceState *dev;
  83    QemuConsole *con;
  84
  85    dev = qdev_find_recursive(sysbus_get_default(), device_id);
  86    if (dev == NULL) {
  87        error_set(errp, QERR_DEVICE_NOT_FOUND, device_id);
  88        return;
  89    }
  90
  91    con = qemu_console_lookup_by_device(dev, head);
  92    if (con == NULL) {
  93        error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
  94        return;
  95    }
  96
  97    s->con = con;
  98}
  99
 100static QemuInputHandlerState*
 101qemu_input_find_handler(uint32_t mask, QemuConsole *con)
 102{
 103    QemuInputHandlerState *s;
 104
 105    QTAILQ_FOREACH(s, &handlers, node) {
 106        if (s->con == NULL || s->con != con) {
 107            continue;
 108        }
 109        if (mask & s->handler->mask) {
 110            return s;
 111        }
 112    }
 113
 114    QTAILQ_FOREACH(s, &handlers, node) {
 115        if (s->con != NULL) {
 116            continue;
 117        }
 118        if (mask & s->handler->mask) {
 119            return s;
 120        }
 121    }
 122    return NULL;
 123}
 124
 125void qmp_x_input_send_event(bool has_console, int64_t console,
 126                            InputEventList *events, Error **errp)
 127{
 128    InputEventList *e;
 129    QemuConsole *con;
 130
 131    con = NULL;
 132    if (has_console) {
 133        con = qemu_console_lookup_by_index(console);
 134        if (!con) {
 135            error_setg(errp, "console %" PRId64 " not found", console);
 136            return;
 137        }
 138    }
 139
 140    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
 141        error_setg(errp, "VM not running");
 142        return;
 143    }
 144
 145    for (e = events; e != NULL; e = e->next) {
 146        InputEvent *event = e->value;
 147
 148        if (!qemu_input_find_handler(1 << event->kind, con)) {
 149            error_setg(errp, "Input handler not found for "
 150                             "event type %s",
 151                            InputEventKind_lookup[event->kind]);
 152            return;
 153        }
 154    }
 155
 156    for (e = events; e != NULL; e = e->next) {
 157        InputEvent *event = e->value;
 158
 159        qemu_input_event_send(con, event);
 160    }
 161
 162    qemu_input_event_sync();
 163}
 164
 165static void qemu_input_transform_abs_rotate(InputEvent *evt)
 166{
 167    switch (graphic_rotate) {
 168    case 90:
 169        if (evt->abs->axis == INPUT_AXIS_X) {
 170            evt->abs->axis = INPUT_AXIS_Y;
 171        } else if (evt->abs->axis == INPUT_AXIS_Y) {
 172            evt->abs->axis = INPUT_AXIS_X;
 173            evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
 174        }
 175        break;
 176    case 180:
 177        evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
 178        break;
 179    case 270:
 180        if (evt->abs->axis == INPUT_AXIS_X) {
 181            evt->abs->axis = INPUT_AXIS_Y;
 182            evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
 183        } else if (evt->abs->axis == INPUT_AXIS_Y) {
 184            evt->abs->axis = INPUT_AXIS_X;
 185        }
 186        break;
 187    }
 188}
 189
 190static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
 191{
 192    const char *name;
 193    int qcode, idx = -1;
 194
 195    if (src) {
 196        idx = qemu_console_get_index(src);
 197    }
 198    switch (evt->kind) {
 199    case INPUT_EVENT_KIND_KEY:
 200        switch (evt->key->key->kind) {
 201        case KEY_VALUE_KIND_NUMBER:
 202            qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
 203            name = QKeyCode_lookup[qcode];
 204            trace_input_event_key_number(idx, evt->key->key->number,
 205                                         name, evt->key->down);
 206            break;
 207        case KEY_VALUE_KIND_QCODE:
 208            name = QKeyCode_lookup[evt->key->key->qcode];
 209            trace_input_event_key_qcode(idx, name, evt->key->down);
 210            break;
 211        case KEY_VALUE_KIND_MAX:
 212            /* keep gcc happy */
 213            break;
 214        }
 215        break;
 216    case INPUT_EVENT_KIND_BTN:
 217        name = InputButton_lookup[evt->btn->button];
 218        trace_input_event_btn(idx, name, evt->btn->down);
 219        break;
 220    case INPUT_EVENT_KIND_REL:
 221        name = InputAxis_lookup[evt->rel->axis];
 222        trace_input_event_rel(idx, name, evt->rel->value);
 223        break;
 224    case INPUT_EVENT_KIND_ABS:
 225        name = InputAxis_lookup[evt->abs->axis];
 226        trace_input_event_abs(idx, name, evt->abs->value);
 227        break;
 228    case INPUT_EVENT_KIND_MAX:
 229        /* keep gcc happy */
 230        break;
 231    }
 232}
 233
 234static void qemu_input_queue_process(void *opaque)
 235{
 236    struct QemuInputEventQueueHead *queue = opaque;
 237    QemuInputEventQueue *item;
 238
 239    g_assert(!QTAILQ_EMPTY(queue));
 240    item = QTAILQ_FIRST(queue);
 241    g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
 242    QTAILQ_REMOVE(queue, item, node);
 243    g_free(item);
 244
 245    while (!QTAILQ_EMPTY(queue)) {
 246        item = QTAILQ_FIRST(queue);
 247        switch (item->type) {
 248        case QEMU_INPUT_QUEUE_DELAY:
 249            timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
 250                      + item->delay_ms);
 251            return;
 252        case QEMU_INPUT_QUEUE_EVENT:
 253            qemu_input_event_send(item->src, item->evt);
 254            qapi_free_InputEvent(item->evt);
 255            break;
 256        case QEMU_INPUT_QUEUE_SYNC:
 257            qemu_input_event_sync();
 258            break;
 259        }
 260        QTAILQ_REMOVE(queue, item, node);
 261        g_free(item);
 262    }
 263}
 264
 265static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
 266                                   QEMUTimer *timer, uint32_t delay_ms)
 267{
 268    QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
 269    bool start_timer = QTAILQ_EMPTY(queue);
 270
 271    item->type = QEMU_INPUT_QUEUE_DELAY;
 272    item->delay_ms = delay_ms;
 273    item->timer = timer;
 274    QTAILQ_INSERT_TAIL(queue, item, node);
 275
 276    if (start_timer) {
 277        timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
 278                  + item->delay_ms);
 279    }
 280}
 281
 282static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
 283                                   QemuConsole *src, InputEvent *evt)
 284{
 285    QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
 286
 287    item->type = QEMU_INPUT_QUEUE_EVENT;
 288    item->src = src;
 289    item->evt = evt;
 290    QTAILQ_INSERT_TAIL(queue, item, node);
 291}
 292
 293static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
 294{
 295    QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
 296
 297    item->type = QEMU_INPUT_QUEUE_SYNC;
 298    QTAILQ_INSERT_TAIL(queue, item, node);
 299}
 300
 301void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
 302{
 303    QemuInputHandlerState *s;
 304
 305    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
 306        return;
 307    }
 308
 309    qemu_input_event_trace(src, evt);
 310
 311    /* pre processing */
 312    if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
 313            qemu_input_transform_abs_rotate(evt);
 314    }
 315
 316    /* send event */
 317    s = qemu_input_find_handler(1 << evt->kind, src);
 318    if (!s) {
 319        return;
 320    }
 321    s->handler->event(s->dev, src, evt);
 322    s->events++;
 323}
 324
 325void qemu_input_event_sync(void)
 326{
 327    QemuInputHandlerState *s;
 328
 329    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
 330        return;
 331    }
 332
 333    trace_input_event_sync();
 334
 335    QTAILQ_FOREACH(s, &handlers, node) {
 336        if (!s->events) {
 337            continue;
 338        }
 339        if (s->handler->sync) {
 340            s->handler->sync(s->dev);
 341        }
 342        s->events = 0;
 343    }
 344}
 345
 346InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
 347{
 348    InputEvent *evt = g_new0(InputEvent, 1);
 349    evt->key = g_new0(InputKeyEvent, 1);
 350    evt->kind = INPUT_EVENT_KIND_KEY;
 351    evt->key->key = key;
 352    evt->key->down = down;
 353    return evt;
 354}
 355
 356void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
 357{
 358    InputEvent *evt;
 359    evt = qemu_input_event_new_key(key, down);
 360    if (QTAILQ_EMPTY(&kbd_queue)) {
 361        qemu_input_event_send(src, evt);
 362        qemu_input_event_sync();
 363        qapi_free_InputEvent(evt);
 364    } else {
 365        qemu_input_queue_event(&kbd_queue, src, evt);
 366        qemu_input_queue_sync(&kbd_queue);
 367    }
 368}
 369
 370void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
 371{
 372    KeyValue *key = g_new0(KeyValue, 1);
 373    key->kind = KEY_VALUE_KIND_NUMBER;
 374    key->number = num;
 375    qemu_input_event_send_key(src, key, down);
 376}
 377
 378void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
 379{
 380    KeyValue *key = g_new0(KeyValue, 1);
 381    key->kind = KEY_VALUE_KIND_QCODE;
 382    key->qcode = q;
 383    qemu_input_event_send_key(src, key, down);
 384}
 385
 386void qemu_input_event_send_key_delay(uint32_t delay_ms)
 387{
 388    if (!kbd_timer) {
 389        kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
 390                                 &kbd_queue);
 391    }
 392    qemu_input_queue_delay(&kbd_queue, kbd_timer,
 393                           delay_ms ? delay_ms : kbd_default_delay_ms);
 394}
 395
 396InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
 397{
 398    InputEvent *evt = g_new0(InputEvent, 1);
 399    evt->btn = g_new0(InputBtnEvent, 1);
 400    evt->kind = INPUT_EVENT_KIND_BTN;
 401    evt->btn->button = btn;
 402    evt->btn->down = down;
 403    return evt;
 404}
 405
 406void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
 407{
 408    InputEvent *evt;
 409    evt = qemu_input_event_new_btn(btn, down);
 410    qemu_input_event_send(src, evt);
 411    qapi_free_InputEvent(evt);
 412}
 413
 414void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
 415                               uint32_t button_old, uint32_t button_new)
 416{
 417    InputButton btn;
 418    uint32_t mask;
 419
 420    for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
 421        mask = button_map[btn];
 422        if ((button_old & mask) == (button_new & mask)) {
 423            continue;
 424        }
 425        qemu_input_queue_btn(src, btn, button_new & mask);
 426    }
 427}
 428
 429bool qemu_input_is_absolute(void)
 430{
 431    QemuInputHandlerState *s;
 432
 433    s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
 434                                NULL);
 435    return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
 436}
 437
 438int qemu_input_scale_axis(int value, int size_in, int size_out)
 439{
 440    if (size_in < 2) {
 441        return size_out / 2;
 442    }
 443    return (int64_t)value * (size_out - 1) / (size_in - 1);
 444}
 445
 446InputEvent *qemu_input_event_new_move(InputEventKind kind,
 447                                      InputAxis axis, int value)
 448{
 449    InputEvent *evt = g_new0(InputEvent, 1);
 450    InputMoveEvent *move = g_new0(InputMoveEvent, 1);
 451
 452    evt->kind = kind;
 453    evt->data = move;
 454    move->axis = axis;
 455    move->value = value;
 456    return evt;
 457}
 458
 459void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
 460{
 461    InputEvent *evt;
 462    evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
 463    qemu_input_event_send(src, evt);
 464    qapi_free_InputEvent(evt);
 465}
 466
 467void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
 468{
 469    InputEvent *evt;
 470    int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
 471    evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
 472    qemu_input_event_send(src, evt);
 473    qapi_free_InputEvent(evt);
 474}
 475
 476void qemu_input_check_mode_change(void)
 477{
 478    static int current_is_absolute;
 479    int is_absolute;
 480
 481    is_absolute = qemu_input_is_absolute();
 482
 483    if (is_absolute != current_is_absolute) {
 484        trace_input_mouse_mode(is_absolute);
 485        notifier_list_notify(&mouse_mode_notifiers, NULL);
 486    }
 487
 488    current_is_absolute = is_absolute;
 489}
 490
 491void qemu_add_mouse_mode_change_notifier(Notifier *notify)
 492{
 493    notifier_list_add(&mouse_mode_notifiers, notify);
 494}
 495
 496void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
 497{
 498    notifier_remove(notify);
 499}
 500
 501MouseInfoList *qmp_query_mice(Error **errp)
 502{
 503    MouseInfoList *mice_list = NULL;
 504    MouseInfoList *info;
 505    QemuInputHandlerState *s;
 506    bool current = true;
 507
 508    QTAILQ_FOREACH(s, &handlers, node) {
 509        if (!(s->handler->mask &
 510              (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
 511            continue;
 512        }
 513
 514        info = g_new0(MouseInfoList, 1);
 515        info->value = g_new0(MouseInfo, 1);
 516        info->value->index = s->id;
 517        info->value->name = g_strdup(s->handler->name);
 518        info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
 519        info->value->current = current;
 520
 521        current = false;
 522        info->next = mice_list;
 523        mice_list = info;
 524    }
 525
 526    return mice_list;
 527}
 528
 529void do_mouse_set(Monitor *mon, const QDict *qdict)
 530{
 531    QemuInputHandlerState *s;
 532    int index = qdict_get_int(qdict, "index");
 533    int found = 0;
 534
 535    QTAILQ_FOREACH(s, &handlers, node) {
 536        if (s->id != index) {
 537            continue;
 538        }
 539        if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
 540                                  INPUT_EVENT_MASK_ABS))) {
 541            error_report("Input device '%s' is not a mouse", s->handler->name);
 542            return;
 543        }
 544        found = 1;
 545        qemu_input_handler_activate(s);
 546        break;
 547    }
 548
 549    if (!found) {
 550        error_report("Mouse at index '%d' not found", index);
 551    }
 552
 553    qemu_input_check_mode_change();
 554}
 555