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        error_setg(errp, "%s: failed to read event bits", il->evdev);
 338        goto err_close;
 339    }
 340
 341    if (evtmap & (1 << EV_REL)) {
 342        relmap = 0;
 343        rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap);
 344        if (relmap & (1 << REL_X)) {
 345            il->has_rel_x = true;
 346        }
 347    }
 348
 349    if (evtmap & (1 << EV_ABS)) {
 350        absmap = 0;
 351        rc = ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap);
 352        if (absmap & (1 << ABS_X)) {
 353            il->has_abs_x = true;
 354            rc = ioctl(il->fd, EVIOCGABS(ABS_X), &absinfo);
 355            il->abs_x_min = absinfo.minimum;
 356            il->abs_x_max = absinfo.maximum;
 357            rc = ioctl(il->fd, EVIOCGABS(ABS_Y), &absinfo);
 358            il->abs_y_min = absinfo.minimum;
 359            il->abs_y_max = absinfo.maximum;
 360        }
 361    }
 362
 363    if (evtmap & (1 << EV_KEY)) {
 364        memset(keymap, 0, sizeof(keymap));
 365        rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap);
 366        rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate);
 367        for (i = 0; i < KEY_CNT; i++) {
 368            if (keymap[i / 8] & (1 << (i % 8))) {
 369                if (linux_is_button(i)) {
 370                    il->num_btns++;
 371                } else {
 372                    il->num_keys++;
 373                }
 374                if (keystate[i / 8] & (1 << (i % 8))) {
 375                    il->keydown[i] = true;
 376                    il->keycount++;
 377                }
 378            }
 379        }
 380    }
 381
 382    qemu_set_fd_handler(il->fd, input_linux_event, NULL, il);
 383    if (il->keycount) {
 384        /* delay grab until all keys are released */
 385        il->grab_request = true;
 386    } else {
 387        input_linux_toggle_grab(il);
 388    }
 389    QTAILQ_INSERT_TAIL(&inputs, il, next);
 390    il->initialized = true;
 391    return;
 392
 393err_close:
 394    close(il->fd);
 395    return;
 396}
 397
 398static void input_linux_instance_finalize(Object *obj)
 399{
 400    InputLinux *il = INPUT_LINUX(obj);
 401
 402    if (il->initialized) {
 403        QTAILQ_REMOVE(&inputs, il, next);
 404        close(il->fd);
 405    }
 406    g_free(il->evdev);
 407}
 408
 409static char *input_linux_get_evdev(Object *obj, Error **errp)
 410{
 411    InputLinux *il = INPUT_LINUX(obj);
 412
 413    return g_strdup(il->evdev);
 414}
 415
 416static void input_linux_set_evdev(Object *obj, const char *value,
 417                                  Error **errp)
 418{
 419    InputLinux *il = INPUT_LINUX(obj);
 420
 421    if (il->evdev) {
 422        error_setg(errp, "evdev property already set");
 423        return;
 424    }
 425    il->evdev = g_strdup(value);
 426}
 427
 428static bool input_linux_get_grab_all(Object *obj, Error **errp)
 429{
 430    InputLinux *il = INPUT_LINUX(obj);
 431
 432    return il->grab_all;
 433}
 434
 435static void input_linux_set_grab_all(Object *obj, bool value,
 436                                   Error **errp)
 437{
 438    InputLinux *il = INPUT_LINUX(obj);
 439
 440    il->grab_all = value;
 441}
 442
 443static bool input_linux_get_repeat(Object *obj, Error **errp)
 444{
 445    InputLinux *il = INPUT_LINUX(obj);
 446
 447    return il->repeat;
 448}
 449
 450static void input_linux_set_repeat(Object *obj, bool value,
 451                                   Error **errp)
 452{
 453    InputLinux *il = INPUT_LINUX(obj);
 454
 455    il->repeat = value;
 456}
 457
 458static int input_linux_get_grab_toggle(Object *obj, Error **errp)
 459{
 460    InputLinux *il = INPUT_LINUX(obj);
 461
 462    return il->grab_toggle;
 463}
 464
 465static void input_linux_set_grab_toggle(Object *obj, int value,
 466                                       Error **errp)
 467{
 468    InputLinux *il = INPUT_LINUX(obj);
 469
 470    il->grab_toggle = value;
 471}
 472
 473static void input_linux_instance_init(Object *obj)
 474{
 475    object_property_add_str(obj, "evdev",
 476                            input_linux_get_evdev,
 477                            input_linux_set_evdev, NULL);
 478    object_property_add_bool(obj, "grab_all",
 479                             input_linux_get_grab_all,
 480                             input_linux_set_grab_all, NULL);
 481    object_property_add_bool(obj, "repeat",
 482                             input_linux_get_repeat,
 483                             input_linux_set_repeat, NULL);
 484    object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys",
 485                             &GrabToggleKeys_lookup,
 486                             input_linux_get_grab_toggle,
 487                             input_linux_set_grab_toggle, NULL);
 488}
 489
 490static void input_linux_class_init(ObjectClass *oc, void *data)
 491{
 492    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 493
 494    ucc->complete = input_linux_complete;
 495}
 496
 497static const TypeInfo input_linux_info = {
 498    .name = TYPE_INPUT_LINUX,
 499    .parent = TYPE_OBJECT,
 500    .class_size = sizeof(InputLinuxClass),
 501    .class_init = input_linux_class_init,
 502    .instance_size = sizeof(InputLinux),
 503    .instance_init = input_linux_instance_init,
 504    .instance_finalize = input_linux_instance_finalize,
 505    .interfaces = (InterfaceInfo[]) {
 506        { TYPE_USER_CREATABLE },
 507        { }
 508    }
 509};
 510
 511static void register_types(void)
 512{
 513    type_register_static(&input_linux_info);
 514}
 515
 516type_init(register_types);
 517