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