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-common.h"
  10#include "qemu/config-file.h"
  11#include "qemu/sockets.h"
  12#include "sysemu/sysemu.h"
  13#include "ui/input.h"
  14#include "qom/object_interfaces.h"
  15
  16#include <sys/ioctl.h>
  17#include "standard-headers/linux/input.h"
  18
  19static int linux_to_qcode[KEY_CNT] = {
  20    [KEY_ESC]            = Q_KEY_CODE_ESC,
  21    [KEY_1]              = Q_KEY_CODE_1,
  22    [KEY_2]              = Q_KEY_CODE_2,
  23    [KEY_3]              = Q_KEY_CODE_3,
  24    [KEY_4]              = Q_KEY_CODE_4,
  25    [KEY_5]              = Q_KEY_CODE_5,
  26    [KEY_6]              = Q_KEY_CODE_6,
  27    [KEY_7]              = Q_KEY_CODE_7,
  28    [KEY_8]              = Q_KEY_CODE_8,
  29    [KEY_9]              = Q_KEY_CODE_9,
  30    [KEY_0]              = Q_KEY_CODE_0,
  31    [KEY_MINUS]          = Q_KEY_CODE_MINUS,
  32    [KEY_EQUAL]          = Q_KEY_CODE_EQUAL,
  33    [KEY_BACKSPACE]      = Q_KEY_CODE_BACKSPACE,
  34    [KEY_TAB]            = Q_KEY_CODE_TAB,
  35    [KEY_Q]              = Q_KEY_CODE_Q,
  36    [KEY_W]              = Q_KEY_CODE_W,
  37    [KEY_E]              = Q_KEY_CODE_E,
  38    [KEY_R]              = Q_KEY_CODE_R,
  39    [KEY_T]              = Q_KEY_CODE_T,
  40    [KEY_Y]              = Q_KEY_CODE_Y,
  41    [KEY_U]              = Q_KEY_CODE_U,
  42    [KEY_I]              = Q_KEY_CODE_I,
  43    [KEY_O]              = Q_KEY_CODE_O,
  44    [KEY_P]              = Q_KEY_CODE_P,
  45    [KEY_LEFTBRACE]      = Q_KEY_CODE_BRACKET_LEFT,
  46    [KEY_RIGHTBRACE]     = Q_KEY_CODE_BRACKET_RIGHT,
  47    [KEY_ENTER]          = Q_KEY_CODE_RET,
  48    [KEY_LEFTCTRL]       = Q_KEY_CODE_CTRL,
  49    [KEY_A]              = Q_KEY_CODE_A,
  50    [KEY_S]              = Q_KEY_CODE_S,
  51    [KEY_D]              = Q_KEY_CODE_D,
  52    [KEY_F]              = Q_KEY_CODE_F,
  53    [KEY_G]              = Q_KEY_CODE_G,
  54    [KEY_H]              = Q_KEY_CODE_H,
  55    [KEY_J]              = Q_KEY_CODE_J,
  56    [KEY_K]              = Q_KEY_CODE_K,
  57    [KEY_L]              = Q_KEY_CODE_L,
  58    [KEY_SEMICOLON]      = Q_KEY_CODE_SEMICOLON,
  59    [KEY_APOSTROPHE]     = Q_KEY_CODE_APOSTROPHE,
  60    [KEY_GRAVE]          = Q_KEY_CODE_GRAVE_ACCENT,
  61    [KEY_LEFTSHIFT]      = Q_KEY_CODE_SHIFT,
  62    [KEY_BACKSLASH]      = Q_KEY_CODE_BACKSLASH,
  63    [KEY_102ND]          = Q_KEY_CODE_LESS,
  64    [KEY_Z]              = Q_KEY_CODE_Z,
  65    [KEY_X]              = Q_KEY_CODE_X,
  66    [KEY_C]              = Q_KEY_CODE_C,
  67    [KEY_V]              = Q_KEY_CODE_V,
  68    [KEY_B]              = Q_KEY_CODE_B,
  69    [KEY_N]              = Q_KEY_CODE_N,
  70    [KEY_M]              = Q_KEY_CODE_M,
  71    [KEY_COMMA]          = Q_KEY_CODE_COMMA,
  72    [KEY_DOT]            = Q_KEY_CODE_DOT,
  73    [KEY_SLASH]          = Q_KEY_CODE_SLASH,
  74    [KEY_RIGHTSHIFT]     = Q_KEY_CODE_SHIFT_R,
  75    [KEY_LEFTALT]        = Q_KEY_CODE_ALT,
  76    [KEY_SPACE]          = Q_KEY_CODE_SPC,
  77    [KEY_CAPSLOCK]       = Q_KEY_CODE_CAPS_LOCK,
  78    [KEY_F1]             = Q_KEY_CODE_F1,
  79    [KEY_F2]             = Q_KEY_CODE_F2,
  80    [KEY_F3]             = Q_KEY_CODE_F3,
  81    [KEY_F4]             = Q_KEY_CODE_F4,
  82    [KEY_F5]             = Q_KEY_CODE_F5,
  83    [KEY_F6]             = Q_KEY_CODE_F6,
  84    [KEY_F7]             = Q_KEY_CODE_F7,
  85    [KEY_F8]             = Q_KEY_CODE_F8,
  86    [KEY_F9]             = Q_KEY_CODE_F9,
  87    [KEY_F10]            = Q_KEY_CODE_F10,
  88    [KEY_NUMLOCK]        = Q_KEY_CODE_NUM_LOCK,
  89    [KEY_SCROLLLOCK]     = Q_KEY_CODE_SCROLL_LOCK,
  90    [KEY_KP0]            = Q_KEY_CODE_KP_0,
  91    [KEY_KP1]            = Q_KEY_CODE_KP_1,
  92    [KEY_KP2]            = Q_KEY_CODE_KP_2,
  93    [KEY_KP3]            = Q_KEY_CODE_KP_3,
  94    [KEY_KP4]            = Q_KEY_CODE_KP_4,
  95    [KEY_KP5]            = Q_KEY_CODE_KP_5,
  96    [KEY_KP6]            = Q_KEY_CODE_KP_6,
  97    [KEY_KP7]            = Q_KEY_CODE_KP_7,
  98    [KEY_KP8]            = Q_KEY_CODE_KP_8,
  99    [KEY_KP9]            = Q_KEY_CODE_KP_9,
 100    [KEY_KPMINUS]        = Q_KEY_CODE_KP_SUBTRACT,
 101    [KEY_KPPLUS]         = Q_KEY_CODE_KP_ADD,
 102    [KEY_KPDOT]          = Q_KEY_CODE_KP_DECIMAL,
 103    [KEY_KPENTER]        = Q_KEY_CODE_KP_ENTER,
 104    [KEY_KPSLASH]        = Q_KEY_CODE_KP_DIVIDE,
 105    [KEY_KPASTERISK]     = Q_KEY_CODE_KP_MULTIPLY,
 106    [KEY_F11]            = Q_KEY_CODE_F11,
 107    [KEY_F12]            = Q_KEY_CODE_F12,
 108    [KEY_RIGHTCTRL]      = Q_KEY_CODE_CTRL_R,
 109    [KEY_SYSRQ]          = Q_KEY_CODE_SYSRQ,
 110    [KEY_RIGHTALT]       = Q_KEY_CODE_ALT_R,
 111    [KEY_HOME]           = Q_KEY_CODE_HOME,
 112    [KEY_UP]             = Q_KEY_CODE_UP,
 113    [KEY_PAGEUP]         = Q_KEY_CODE_PGUP,
 114    [KEY_LEFT]           = Q_KEY_CODE_LEFT,
 115    [KEY_RIGHT]          = Q_KEY_CODE_RIGHT,
 116    [KEY_END]            = Q_KEY_CODE_END,
 117    [KEY_DOWN]           = Q_KEY_CODE_DOWN,
 118    [KEY_PAGEDOWN]       = Q_KEY_CODE_PGDN,
 119    [KEY_INSERT]         = Q_KEY_CODE_INSERT,
 120    [KEY_DELETE]         = Q_KEY_CODE_DELETE,
 121    [KEY_LEFTMETA]       = Q_KEY_CODE_META_L,
 122    [KEY_RIGHTMETA]      = Q_KEY_CODE_META_R,
 123    [KEY_MENU]           = Q_KEY_CODE_MENU,
 124};
 125
 126static int qemu_input_linux_to_qcode(unsigned int lnx)
 127{
 128    assert(lnx < KEY_CNT);
 129    return linux_to_qcode[lnx];
 130}
 131
 132#define TYPE_INPUT_LINUX "input-linux"
 133#define INPUT_LINUX(obj) \
 134    OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX)
 135#define INPUT_LINUX_GET_CLASS(obj) \
 136    OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX)
 137#define INPUT_LINUX_CLASS(klass) \
 138    OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX)
 139
 140typedef struct InputLinux InputLinux;
 141typedef struct InputLinuxClass InputLinuxClass;
 142
 143struct InputLinux {
 144    Object parent;
 145
 146    char        *evdev;
 147    int         fd;
 148    bool        repeat;
 149    bool        grab_request;
 150    bool        grab_active;
 151    bool        grab_all;
 152    bool        keydown[KEY_CNT];
 153    int         keycount;
 154    int         wheel;
 155    bool        initialized;
 156    QTAILQ_ENTRY(InputLinux) next;
 157};
 158
 159struct InputLinuxClass {
 160    ObjectClass parent_class;
 161};
 162
 163static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs);
 164
 165static void input_linux_toggle_grab(InputLinux *il)
 166{
 167    intptr_t request = !il->grab_active;
 168    InputLinux *item;
 169    int rc;
 170
 171    rc = ioctl(il->fd, EVIOCGRAB, request);
 172    if (rc < 0) {
 173        return;
 174    }
 175    il->grab_active = !il->grab_active;
 176
 177    if (!il->grab_all) {
 178        return;
 179    }
 180    QTAILQ_FOREACH(item, &inputs, next) {
 181        if (item == il || item->grab_all) {
 182            /* avoid endless loops */
 183            continue;
 184        }
 185        if (item->grab_active != il->grab_active) {
 186            input_linux_toggle_grab(item);
 187        }
 188    }
 189}
 190
 191static void input_linux_event_keyboard(void *opaque)
 192{
 193    InputLinux *il = opaque;
 194    struct input_event event;
 195    int rc;
 196
 197    for (;;) {
 198        rc = read(il->fd, &event, sizeof(event));
 199        if (rc != sizeof(event)) {
 200            if (rc < 0 && errno != EAGAIN) {
 201                fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno));
 202                qemu_set_fd_handler(il->fd, NULL, NULL, NULL);
 203                close(il->fd);
 204            }
 205            break;
 206        }
 207
 208        switch (event.type) {
 209        case EV_KEY:
 210            if (event.value > 2 || (event.value > 1 && !il->repeat)) {
 211                /*
 212                 * ignore autorepeat + unknown key events
 213                 * 0 == up, 1 == down, 2 == autorepeat, other == undefined
 214                 */
 215                continue;
 216            }
 217            if (event.code >= KEY_CNT) {
 218                /*
 219                 * Should not happen.  But better safe than sorry,
 220                 * and we make Coverity happy too.
 221                 */
 222                continue;
 223            }
 224            /* keep track of key state */
 225            if (!il->keydown[event.code] && event.value) {
 226                il->keydown[event.code] = true;
 227                il->keycount++;
 228            }
 229            if (il->keydown[event.code] && !event.value) {
 230                il->keydown[event.code] = false;
 231                il->keycount--;
 232            }
 233
 234            /* send event to guest when grab is active */
 235            if (il->grab_active) {
 236                int qcode = qemu_input_linux_to_qcode(event.code);
 237                qemu_input_event_send_key_qcode(NULL, qcode, event.value);
 238            }
 239
 240            /* hotkey -> record switch request ... */
 241            if (il->keydown[KEY_LEFTCTRL] &&
 242                il->keydown[KEY_RIGHTCTRL]) {
 243                il->grab_request = true;
 244            }
 245
 246            /*
 247             * ... and do the switch when all keys are lifted, so we
 248             * confuse neither guest nor host with keys which seem to
 249             * be stuck due to missing key-up events.
 250             */
 251            if (il->grab_request && !il->keycount) {
 252                il->grab_request = false;
 253                input_linux_toggle_grab(il);
 254            }
 255            break;
 256        }
 257    }
 258}
 259
 260static void input_linux_event_mouse_button(int button)
 261{
 262    qemu_input_queue_btn(NULL, button, true);
 263    qemu_input_event_sync();
 264    qemu_input_queue_btn(NULL, button, false);
 265    qemu_input_event_sync();
 266}
 267
 268static void input_linux_event_mouse(void *opaque)
 269{
 270    InputLinux *il = opaque;
 271    struct input_event event;
 272    int rc;
 273
 274    for (;;) {
 275        rc = read(il->fd, &event, sizeof(event));
 276        if (rc != sizeof(event)) {
 277            if (rc < 0 && errno != EAGAIN) {
 278                fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno));
 279                qemu_set_fd_handler(il->fd, NULL, NULL, NULL);
 280                close(il->fd);
 281            }
 282            break;
 283        }
 284
 285        /* only send event to guest when grab is active */
 286        if (!il->grab_active) {
 287            continue;
 288        }
 289
 290        switch (event.type) {
 291        case EV_KEY:
 292            switch (event.code) {
 293            case BTN_LEFT:
 294                qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event.value);
 295                break;
 296            case BTN_RIGHT:
 297                qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event.value);
 298                break;
 299            case BTN_MIDDLE:
 300                qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event.value);
 301                break;
 302            case BTN_GEAR_UP:
 303                qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event.value);
 304                break;
 305            case BTN_GEAR_DOWN:
 306                qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN,
 307                                     event.value);
 308                break;
 309            };
 310            break;
 311        case EV_REL:
 312            switch (event.code) {
 313            case REL_X:
 314                qemu_input_queue_rel(NULL, INPUT_AXIS_X, event.value);
 315                break;
 316            case REL_Y:
 317                qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event.value);
 318                break;
 319            case REL_WHEEL:
 320                il->wheel = event.value;
 321                break;
 322            }
 323            break;
 324        case EV_SYN:
 325            qemu_input_event_sync();
 326            if (il->wheel != 0) {
 327                input_linux_event_mouse_button((il->wheel > 0)
 328                                               ? INPUT_BUTTON_WHEEL_UP
 329                                               : INPUT_BUTTON_WHEEL_DOWN);
 330                il->wheel = 0;
 331            }
 332            break;
 333        }
 334    }
 335}
 336
 337static void input_linux_complete(UserCreatable *uc, Error **errp)
 338{
 339    InputLinux *il = INPUT_LINUX(uc);
 340    uint32_t evtmap, relmap, absmap;
 341    int rc, ver;
 342
 343    if (!il->evdev) {
 344        error_setg(errp, "no input device specified");
 345        return;
 346    }
 347
 348    il->fd = open(il->evdev, O_RDWR);
 349    if (il->fd < 0)  {
 350        error_setg_file_open(errp, errno, il->evdev);
 351        return;
 352    }
 353    qemu_set_nonblock(il->fd);
 354
 355    rc = ioctl(il->fd, EVIOCGVERSION, &ver);
 356    if (rc < 0) {
 357        error_setg(errp, "%s: is not an evdev device", il->evdev);
 358        goto err_close;
 359    }
 360
 361    rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap);
 362    if (rc < 0) {
 363        error_setg(errp, "%s: failed to read event bits", il->evdev);
 364        goto err_close;
 365    }
 366
 367    if (evtmap & (1 << EV_REL)) {
 368        rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap);
 369        if (rc < 0) {
 370            relmap = 0;
 371        }
 372    }
 373
 374    if (evtmap & (1 << EV_ABS)) {
 375        ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap);
 376        if (rc < 0) {
 377            absmap = 0;
 378        }
 379    }
 380
 381    if ((evtmap & (1 << EV_REL)) &&
 382        (relmap & (1 << REL_X))) {
 383        /* has relative x axis -> assume mouse */
 384        qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il);
 385    } else if ((evtmap & (1 << EV_ABS)) &&
 386               (absmap & (1 << ABS_X))) {
 387        /* has absolute x axis -> not supported */
 388        error_setg(errp, "tablet/touchscreen not supported");
 389        goto err_close;
 390    } else if (evtmap & (1 << EV_KEY)) {
 391        /* has keys/buttons (and no x axis) -> assume keyboard */
 392        qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il);
 393    } else {
 394        /* Huh? What is this? */
 395        error_setg(errp, "unknown kind of input device");
 396        goto err_close;
 397    }
 398    input_linux_toggle_grab(il);
 399    QTAILQ_INSERT_TAIL(&inputs, il, next);
 400    il->initialized = true;
 401    return;
 402
 403err_close:
 404    close(il->fd);
 405    return;
 406}
 407
 408static void input_linux_instance_finalize(Object *obj)
 409{
 410    InputLinux *il = INPUT_LINUX(obj);
 411
 412    if (il->initialized) {
 413        QTAILQ_REMOVE(&inputs, il, next);
 414        close(il->fd);
 415    }
 416    g_free(il->evdev);
 417}
 418
 419static char *input_linux_get_evdev(Object *obj, Error **errp)
 420{
 421    InputLinux *il = INPUT_LINUX(obj);
 422
 423    return g_strdup(il->evdev);
 424}
 425
 426static void input_linux_set_evdev(Object *obj, const char *value,
 427                                  Error **errp)
 428{
 429    InputLinux *il = INPUT_LINUX(obj);
 430
 431    if (il->evdev) {
 432        error_setg(errp, "evdev property already set");
 433        return;
 434    }
 435    il->evdev = g_strdup(value);
 436}
 437
 438static bool input_linux_get_grab_all(Object *obj, Error **errp)
 439{
 440    InputLinux *il = INPUT_LINUX(obj);
 441
 442    return il->grab_all;
 443}
 444
 445static void input_linux_set_grab_all(Object *obj, bool value,
 446                                   Error **errp)
 447{
 448    InputLinux *il = INPUT_LINUX(obj);
 449
 450    il->grab_all = value;
 451}
 452
 453static bool input_linux_get_repeat(Object *obj, Error **errp)
 454{
 455    InputLinux *il = INPUT_LINUX(obj);
 456
 457    return il->repeat;
 458}
 459
 460static void input_linux_set_repeat(Object *obj, bool value,
 461                                   Error **errp)
 462{
 463    InputLinux *il = INPUT_LINUX(obj);
 464
 465    il->repeat = value;
 466}
 467
 468static void input_linux_instance_init(Object *obj)
 469{
 470    object_property_add_str(obj, "evdev",
 471                            input_linux_get_evdev,
 472                            input_linux_set_evdev, NULL);
 473    object_property_add_bool(obj, "grab_all",
 474                             input_linux_get_grab_all,
 475                             input_linux_set_grab_all, NULL);
 476    object_property_add_bool(obj, "repeat",
 477                             input_linux_get_repeat,
 478                             input_linux_set_repeat, NULL);
 479}
 480
 481static void input_linux_class_init(ObjectClass *oc, void *data)
 482{
 483    UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
 484
 485    ucc->complete = input_linux_complete;
 486}
 487
 488static const TypeInfo input_linux_info = {
 489    .name = TYPE_INPUT_LINUX,
 490    .parent = TYPE_OBJECT,
 491    .class_size = sizeof(InputLinuxClass),
 492    .class_init = input_linux_class_init,
 493    .instance_size = sizeof(InputLinux),
 494    .instance_init = input_linux_instance_init,
 495    .instance_finalize = input_linux_instance_finalize,
 496    .interfaces = (InterfaceInfo[]) {
 497        { TYPE_USER_CREATABLE },
 498        { }
 499    }
 500};
 501
 502static void register_types(void)
 503{
 504    type_register_static(&input_linux_info);
 505}
 506
 507type_init(register_types);
 508