qemu/ui/input-linux.c
<<
>>
Prefs
   1/*
   2 * This work is licensed under the terms of the GNU GPL, version 2 or
   3 * (at your option) any later version.  See the COPYING file in the
   4 * top-level directory.
   5 */
   6
   7#include "qemu/osdep.h"
   8#include "qapi/error.h"
   9#include "qemu/config-file.h"
  10#include "qemu/main-loop.h"
  11#include "qemu/module.h"
  12#include "qemu/sockets.h"
  13#include "ui/input.h"
  14#include "qom/object_interfaces.h"
  15#include "sysemu/iothread.h"
  16#include "block/aio.h"
  17
  18#include <sys/ioctl.h>
  19#include "standard-headers/linux/input.h"
  20
  21static bool linux_is_button(unsigned int lnx)
  22{
  23    if (lnx < 0x100) {
  24        return false;
  25    }
  26    if (lnx >= 0x160 && lnx < 0x2c0) {
  27        return false;
  28    }
  29    return true;
  30}
  31
  32#define TYPE_INPUT_LINUX "input-linux"
  33#define INPUT_LINUX(obj) \
  34    OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX)
  35#define INPUT_LINUX_GET_CLASS(obj) \
  36    OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX)
  37#define INPUT_LINUX_CLASS(klass) \
  38    OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX)
  39
  40typedef struct InputLinux InputLinux;
  41typedef struct InputLinuxClass InputLinuxClass;
  42
  43struct InputLinux {
  44    Object parent;
  45
  46    char        *evdev;
  47    int         fd;
  48    bool        repeat;
  49    bool        grab_request;
  50    bool        grab_active;
  51    bool        grab_all;
  52    bool        keydown[KEY_CNT];
  53    int         keycount;
  54    int         wheel;
  55    bool        initialized;
  56
  57    bool        has_rel_x;
  58    bool        has_abs_x;
  59    int         num_keys;
  60    int         num_btns;
  61    int         abs_x_min;
  62    int         abs_x_max;
  63    int         abs_y_min;
  64    int         abs_y_max;
  65    struct input_event event;
  66    int         read_offset;
  67
  68    enum GrabToggleKeys grab_toggle;
  69
  70    QTAILQ_ENTRY(InputLinux) next;
  71};
  72
  73struct InputLinuxClass {
  74    ObjectClass parent_class;
  75};
  76
  77static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs);
  78
  79static void input_linux_toggle_grab(InputLinux *il)
  80{
  81    intptr_t request = !il->grab_active;
  82    InputLinux *item;
  83    int rc;
  84
  85    rc = ioctl(il->fd, EVIOCGRAB, request);
  86    if (rc < 0) {
  87        return;
  88    }
  89    il->grab_active = !il->grab_active;
  90
  91    if (!il->grab_all) {
  92        return;
  93    }
  94    QTAILQ_FOREACH(item, &inputs, next) {
  95        if (item == il || item->grab_all) {
  96            /* avoid endless loops */
  97            continue;
  98        }
  99        if (item->grab_active != il->grab_active) {
 100            input_linux_toggle_grab(item);
 101        }
 102    }
 103}
 104
 105static bool input_linux_check_toggle(InputLinux *il)
 106{
 107    switch (il->grab_toggle) {
 108    case GRAB_TOGGLE_KEYS_CTRL_CTRL:
 109        return il->keydown[KEY_LEFTCTRL] &&
 110            il->keydown[KEY_RIGHTCTRL];
 111
 112    case GRAB_TOGGLE_KEYS_ALT_ALT:
 113        return il->keydown[KEY_LEFTALT] &&
 114            il->keydown[KEY_RIGHTALT];
 115
 116    case GRAB_TOGGLE_KEYS_SHIFT_SHIFT:
 117        return il->keydown[KEY_LEFTSHIFT] &&
 118            il->keydown[KEY_RIGHTSHIFT];
 119
 120    case GRAB_TOGGLE_KEYS_META_META:
 121        return il->keydown[KEY_LEFTMETA] &&
 122            il->keydown[KEY_RIGHTMETA];
 123
 124    case GRAB_TOGGLE_KEYS_SCROLLLOCK:
 125        return il->keydown[KEY_SCROLLLOCK];
 126
 127    case GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK:
 128        return (il->keydown[KEY_LEFTCTRL] ||
 129                il->keydown[KEY_RIGHTCTRL]) &&
 130            il->keydown[KEY_SCROLLLOCK];
 131
 132    case GRAB_TOGGLE_KEYS__MAX:
 133        /* avoid gcc error */
 134        break;
 135    }
 136    return false;
 137}
 138
 139static bool input_linux_should_skip(InputLinux *il,
 140                                    struct input_event *event)
 141{
 142    return (il->grab_toggle == GRAB_TOGGLE_KEYS_SCROLLLOCK ||
 143            il->grab_toggle == GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK) &&
 144            event->code == KEY_SCROLLLOCK;
 145}
 146
 147static void input_linux_handle_keyboard(InputLinux *il,
 148                                        struct input_event *event)
 149{
 150    if (event->type == EV_KEY) {
 151        if (event->value > 2 || (event->value > 1 && !il->repeat)) {
 152            /*
 153             * ignore autorepeat + unknown key events
 154             * 0 == up, 1 == down, 2 == autorepeat, other == undefined
 155             */
 156            return;
 157        }
 158        if (event->code >= KEY_CNT) {
 159            /*
 160             * Should not happen.  But better safe than sorry,
 161             * and we make Coverity happy too.
 162             */
 163            return;
 164        }
 165
 166        /* keep track of key state */
 167        if (!il->keydown[event->code] && event->value) {
 168            il->keydown[event->code] = true;
 169            il->keycount++;
 170        }
 171        if (il->keydown[event->code] && !event->value) {
 172            il->keydown[event->code] = false;
 173            il->keycount--;
 174        }
 175
 176        /* send event to guest when grab is active */
 177        if (il->grab_active && !input_linux_should_skip(il, event)) {
 178            int qcode = qemu_input_linux_to_qcode(event->code);
 179            qemu_input_event_send_key_qcode(NULL, qcode, event->value);
 180        }
 181
 182        /* hotkey -> record switch request ... */
 183        if (input_linux_check_toggle(il)) {
 184            il->grab_request = true;
 185        }
 186
 187        /*
 188         * ... and do the switch when all keys are lifted, so we
 189         * confuse neither guest nor host with keys which seem to
 190         * be stuck due to missing key-up events.
 191         */
 192        if (il->grab_request && !il->keycount) {
 193            il->grab_request = false;
 194            input_linux_toggle_grab(il);
 195        }
 196    }
 197}
 198
 199static void input_linux_event_mouse_button(int button)
 200{
 201    qemu_input_queue_btn(NULL, button, true);
 202    qemu_input_event_sync();
 203    qemu_input_queue_btn(NULL, button, false);
 204    qemu_input_event_sync();
 205}
 206
 207static void input_linux_handle_mouse(InputLinux *il, struct input_event *event)
 208{
 209    if (!il->grab_active) {
 210        return;
 211    }
 212
 213    switch (event->type) {
 214    case EV_KEY:
 215        switch (event->code) {
 216        case BTN_LEFT:
 217            qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event->value);
 218            break;
 219        case BTN_RIGHT:
 220            qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event->value);
 221            break;
 222        case BTN_MIDDLE:
 223            qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event->value);
 224            break;
 225        case BTN_GEAR_UP:
 226            qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event->value);
 227            break;
 228        case BTN_GEAR_DOWN:
 229            qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN,
 230                                 event->value);
 231            break;
 232        case BTN_SIDE:
 233            qemu_input_queue_btn(NULL, INPUT_BUTTON_SIDE, event->value);
 234            break;
 235        case BTN_EXTRA:
 236            qemu_input_queue_btn(NULL, INPUT_BUTTON_EXTRA, event->value);
 237            break;
 238        };
 239        break;
 240    case EV_REL:
 241        switch (event->code) {
 242        case REL_X:
 243            qemu_input_queue_rel(NULL, INPUT_AXIS_X, event->value);
 244            break;
 245        case REL_Y:
 246            qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event->value);
 247            break;
 248        case REL_WHEEL:
 249            il->wheel = event->value;
 250            break;
 251        }
 252        break;
 253    case EV_ABS:
 254        switch (event->code) {
 255        case ABS_X:
 256            qemu_input_queue_abs(NULL, INPUT_AXIS_X, event->value,
 257                                 il->abs_x_min, il->abs_x_max);
 258            break;
 259        case ABS_Y:
 260            qemu_input_queue_abs(NULL, INPUT_AXIS_Y, event->value,
 261                                 il->abs_y_min, il->abs_y_max);
 262            break;
 263        }
 264        break;
 265    case EV_SYN:
 266        qemu_input_event_sync();
 267        if (il->wheel != 0) {
 268            input_linux_event_mouse_button((il->wheel > 0)
 269                                           ? INPUT_BUTTON_WHEEL_UP
 270                                           : INPUT_BUTTON_WHEEL_DOWN);
 271            il->wheel = 0;
 272        }
 273        break;
 274    }
 275}
 276
 277static void input_linux_event(void *opaque)
 278{
 279    InputLinux *il = opaque;
 280    int rc;
 281    int read_size;
 282    uint8_t *p = (uint8_t *)&il->event;
 283
 284    for (;;) {
 285        read_size = sizeof(il->event) - il->read_offset;
 286        rc = read(il->fd, &p[il->read_offset], read_size);
 287        if (rc != read_size) {
 288            if (rc < 0 && errno != EAGAIN) {
 289                fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno));
 290                qemu_set_fd_handler(il->fd, NULL, NULL, NULL);
 291                close(il->fd);
 292            } else if (rc > 0) {
 293                il->read_offset += rc;
 294            }
 295            break;
 296        }
 297        il->read_offset = 0;
 298
 299        if (il->num_keys) {
 300            input_linux_handle_keyboard(il, &il->event);
 301        }
 302        if ((il->has_rel_x || il->has_abs_x) && il->num_btns) {
 303            input_linux_handle_mouse(il, &il->event);
 304        }
 305    }
 306}
 307
 308static void input_linux_complete(UserCreatable *uc, Error **errp)
 309{
 310    InputLinux *il = INPUT_LINUX(uc);
 311    uint8_t evtmap, relmap, absmap;
 312    uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8];
 313    unsigned int i;
 314    int rc, ver;
 315    struct input_absinfo absinfo;
 316
 317    if (!il->evdev) {
 318        error_setg(errp, "no input device specified");
 319        return;
 320    }
 321
 322    il->fd = open(il->evdev, O_RDWR);
 323    if (il->fd < 0)  {
 324        error_setg_file_open(errp, errno, il->evdev);
 325        return;
 326    }
 327    qemu_set_nonblock(il->fd);
 328
 329    rc = ioctl(il->fd, EVIOCGVERSION, &ver);
 330    if (rc < 0) {
 331        error_setg(errp, "%s: is not an evdev device", il->evdev);
 332        goto err_close;
 333    }
 334
 335    rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap);
 336    if (rc < 0) {
 337        goto err_read_event_bits;
 338    }
 339
 340    if (evtmap & (1 << EV_REL)) {
 341        relmap = 0;
 342        rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap);
 343        if (rc < 0) {
 344            goto err_read_event_bits;
 345        }
 346        if (relmap & (1 << REL_X)) {
 347            il->has_rel_x = true;
 348        }
 349    }
 350
 351    if (evtmap & (1 << EV_ABS)) {
 352        absmap = 0;
 353        rc = ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap);
 354        if (rc < 0) {
 355            goto err_read_event_bits;
 356        }
 357        if (absmap & (1 << ABS_X)) {
 358            il->has_abs_x = true;
 359            rc = ioctl(il->fd, EVIOCGABS(ABS_X), &absinfo);
 360            if (rc < 0) {
 361                error_setg(errp, "%s: failed to get get absolute X value",
 362                           il->evdev);
 363                goto err_close;
 364            }
 365            il->abs_x_min = absinfo.minimum;
 366            il->abs_x_max = absinfo.maximum;
 367            rc = ioctl(il->fd, EVIOCGABS(ABS_Y), &absinfo);
 368            if (rc < 0) {
 369                error_setg(errp, "%s: failed to get get absolute Y value",
 370                           il->evdev);
 371                goto err_close;
 372            }
 373            il->abs_y_min = absinfo.minimum;
 374            il->abs_y_max = absinfo.maximum;
 375        }
 376    }
 377
 378    if (evtmap & (1 << EV_KEY)) {
 379        memset(keymap, 0, sizeof(keymap));
 380        rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap);
 381        if (rc < 0) {
 382            goto err_read_event_bits;
 383        }
 384        rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate);
 385        if (rc < 0) {
 386            error_setg(errp, "%s: failed to get global key state", il->evdev);
 387            goto err_close;
 388        }
 389        for (i = 0; i < KEY_CNT; i++) {
 390            if (keymap[i / 8] & (1 << (i % 8))) {
 391                if (linux_is_button(i)) {
 392                    il->num_btns++;
 393                } else {
 394                    il->num_keys++;
 395                }
 396                if (keystate[i / 8] & (1 << (i % 8))) {
 397                    il->keydown[i] = true;
 398                    il->keycount++;
 399                }
 400            }
 401        }
 402    }
 403
 404    qemu_set_fd_handler(il->fd, input_linux_event, NULL, il);
 405    if (il->keycount) {
 406        /* delay grab until all keys are released */
 407        il->grab_request = true;
 408    } else {
 409        input_linux_toggle_grab(il);
 410    }
 411    QTAILQ_INSERT_TAIL(&inputs, il, next);
 412    il->initialized = true;
 413    return;
 414
 415err_read_event_bits:
 416    error_setg(errp, "%s: failed to read event bits", il->evdev);
 417
 418err_close:
 419    close(il->fd);
 420    return;
 421}
 422
 423static void input_linux_instance_finalize(Object *obj)
 424{
 425    InputLinux *il = INPUT_LINUX(obj);
 426
 427    if (il->initialized) {
 428        QTAILQ_REMOVE(&inputs, il, next);
 429        close(il->fd);
 430    }
 431    g_free(il->evdev);
 432}
 433
 434static char *input_linux_get_evdev(Object *obj, Error **errp)
 435{
 436    InputLinux *il = INPUT_LINUX(obj);
 437
 438    return g_strdup(il->evdev);
 439}
 440
 441static void input_linux_set_evdev(Object *obj, const char *value,
 442                                  Error **errp)
 443{
 444    InputLinux *il = INPUT_LINUX(obj);
 445
 446    if (il->evdev) {
 447        error_setg(errp, "evdev property already set");
 448        return;
 449    }
 450    il->evdev = g_strdup(value);
 451}
 452
 453static bool input_linux_get_grab_all(Object *obj, Error **errp)
 454{
 455    InputLinux *il = INPUT_LINUX(obj);
 456
 457    return il->grab_all;
 458}
 459
 460static void input_linux_set_grab_all(Object *obj, bool value,
 461                                   Error **errp)
 462{
 463    InputLinux *il = INPUT_LINUX(obj);
 464
 465    il->grab_all = value;
 466}
 467
 468static bool input_linux_get_repeat(Object *obj, Error **errp)
 469{
 470    InputLinux *il = INPUT_LINUX(obj);
 471
 472    return il->repeat;
 473}
 474
 475static void input_linux_set_repeat(Object *obj, bool value,
 476                                   Error **errp)
 477{
 478    InputLinux *il = INPUT_LINUX(obj);
 479
 480    il->repeat = value;
 481}
 482
 483static int input_linux_get_grab_toggle(Object *obj, Error **errp)
 484{
 485    InputLinux *il = INPUT_LINUX(obj);
 486
 487    return il->grab_toggle;
 488}
 489
 490static void input_linux_set_grab_toggle(Object *obj, int value,
 491                                       Error **errp)
 492{
 493    InputLinux *il = INPUT_LINUX(obj);
 494
 495    il->grab_toggle = value;
 496}
 497
 498static void input_linux_instance_init(Object *obj)
 499{
 500    object_property_add_str(obj, "evdev",
 501                            input_linux_get_evdev,
 502                            input_linux_set_evdev, NULL);
 503    object_property_add_bool(obj, "grab_all",
 504                             input_linux_get_grab_all,
 505                             input_linux_set_grab_all, NULL);
 506    object_property_add_bool(obj, "repeat",
 507                             input_linux_get_repeat,
 508                             input_linux_set_repeat, NULL);
 509    object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys",
 510                             &GrabToggleKeys_lookup,
 511                             input_linux_get_grab_toggle,
 512                             input_linux_set_grab_toggle, NULL);
 513}
 514
 515static void input_linux_class_init(ObjectClass *oc, void *data)
 516{
 517    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 518
 519    ucc->complete = input_linux_complete;
 520}
 521
 522static const TypeInfo input_linux_info = {
 523    .name = TYPE_INPUT_LINUX,
 524    .parent = TYPE_OBJECT,
 525    .class_size = sizeof(InputLinuxClass),
 526    .class_init = input_linux_class_init,
 527    .instance_size = sizeof(InputLinux),
 528    .instance_init = input_linux_instance_init,
 529    .instance_finalize = input_linux_instance_finalize,
 530    .interfaces = (InterfaceInfo[]) {
 531        { TYPE_USER_CREATABLE },
 532        { }
 533    }
 534};
 535
 536static void register_types(void)
 537{
 538    type_register_static(&input_linux_info);
 539}
 540
 541type_init(register_types);
 542