1e0d2bd51SGerd Hoffmann /* 2e0d2bd51SGerd Hoffmann * This work is licensed under the terms of the GNU GPL, version 2 or 3e0d2bd51SGerd Hoffmann * (at your option) any later version. See the COPYING file in the 4e0d2bd51SGerd Hoffmann * top-level directory. 5e0d2bd51SGerd Hoffmann */ 6e0d2bd51SGerd Hoffmann 7e0d2bd51SGerd Hoffmann #include "qemu/osdep.h" 8da34e65cSMarkus Armbruster #include "qapi/error.h" 9e0d2bd51SGerd Hoffmann #include "qemu-common.h" 10e0d2bd51SGerd Hoffmann #include "qemu/config-file.h" 11e0d2bd51SGerd Hoffmann #include "qemu/sockets.h" 12e0d2bd51SGerd Hoffmann #include "sysemu/sysemu.h" 13e0d2bd51SGerd Hoffmann #include "ui/input.h" 140e066b2cSGerd Hoffmann #include "qom/object_interfaces.h" 15e0d2bd51SGerd Hoffmann 16e0d2bd51SGerd Hoffmann #include <sys/ioctl.h> 17e0d2bd51SGerd Hoffmann #include "standard-headers/linux/input.h" 18e0d2bd51SGerd Hoffmann 19e0d2bd51SGerd Hoffmann static int linux_to_qcode[KEY_CNT] = { 20e0d2bd51SGerd Hoffmann [KEY_ESC] = Q_KEY_CODE_ESC, 21e0d2bd51SGerd Hoffmann [KEY_1] = Q_KEY_CODE_1, 22e0d2bd51SGerd Hoffmann [KEY_2] = Q_KEY_CODE_2, 23e0d2bd51SGerd Hoffmann [KEY_3] = Q_KEY_CODE_3, 24e0d2bd51SGerd Hoffmann [KEY_4] = Q_KEY_CODE_4, 25e0d2bd51SGerd Hoffmann [KEY_5] = Q_KEY_CODE_5, 26e0d2bd51SGerd Hoffmann [KEY_6] = Q_KEY_CODE_6, 27e0d2bd51SGerd Hoffmann [KEY_7] = Q_KEY_CODE_7, 28e0d2bd51SGerd Hoffmann [KEY_8] = Q_KEY_CODE_8, 29e0d2bd51SGerd Hoffmann [KEY_9] = Q_KEY_CODE_9, 30e0d2bd51SGerd Hoffmann [KEY_0] = Q_KEY_CODE_0, 31e0d2bd51SGerd Hoffmann [KEY_MINUS] = Q_KEY_CODE_MINUS, 32e0d2bd51SGerd Hoffmann [KEY_EQUAL] = Q_KEY_CODE_EQUAL, 33e0d2bd51SGerd Hoffmann [KEY_BACKSPACE] = Q_KEY_CODE_BACKSPACE, 34e0d2bd51SGerd Hoffmann [KEY_TAB] = Q_KEY_CODE_TAB, 35e0d2bd51SGerd Hoffmann [KEY_Q] = Q_KEY_CODE_Q, 36e0d2bd51SGerd Hoffmann [KEY_W] = Q_KEY_CODE_W, 37e0d2bd51SGerd Hoffmann [KEY_E] = Q_KEY_CODE_E, 38e0d2bd51SGerd Hoffmann [KEY_R] = Q_KEY_CODE_R, 39e0d2bd51SGerd Hoffmann [KEY_T] = Q_KEY_CODE_T, 40e0d2bd51SGerd Hoffmann [KEY_Y] = Q_KEY_CODE_Y, 41e0d2bd51SGerd Hoffmann [KEY_U] = Q_KEY_CODE_U, 42e0d2bd51SGerd Hoffmann [KEY_I] = Q_KEY_CODE_I, 43e0d2bd51SGerd Hoffmann [KEY_O] = Q_KEY_CODE_O, 44e0d2bd51SGerd Hoffmann [KEY_P] = Q_KEY_CODE_P, 45e0d2bd51SGerd Hoffmann [KEY_LEFTBRACE] = Q_KEY_CODE_BRACKET_LEFT, 46e0d2bd51SGerd Hoffmann [KEY_RIGHTBRACE] = Q_KEY_CODE_BRACKET_RIGHT, 47e0d2bd51SGerd Hoffmann [KEY_ENTER] = Q_KEY_CODE_RET, 48e0d2bd51SGerd Hoffmann [KEY_LEFTCTRL] = Q_KEY_CODE_CTRL, 49e0d2bd51SGerd Hoffmann [KEY_A] = Q_KEY_CODE_A, 50e0d2bd51SGerd Hoffmann [KEY_S] = Q_KEY_CODE_S, 51e0d2bd51SGerd Hoffmann [KEY_D] = Q_KEY_CODE_D, 52e0d2bd51SGerd Hoffmann [KEY_F] = Q_KEY_CODE_F, 53e0d2bd51SGerd Hoffmann [KEY_G] = Q_KEY_CODE_G, 54e0d2bd51SGerd Hoffmann [KEY_H] = Q_KEY_CODE_H, 55e0d2bd51SGerd Hoffmann [KEY_J] = Q_KEY_CODE_J, 56e0d2bd51SGerd Hoffmann [KEY_K] = Q_KEY_CODE_K, 57e0d2bd51SGerd Hoffmann [KEY_L] = Q_KEY_CODE_L, 58e0d2bd51SGerd Hoffmann [KEY_SEMICOLON] = Q_KEY_CODE_SEMICOLON, 59e0d2bd51SGerd Hoffmann [KEY_APOSTROPHE] = Q_KEY_CODE_APOSTROPHE, 60e0d2bd51SGerd Hoffmann [KEY_GRAVE] = Q_KEY_CODE_GRAVE_ACCENT, 61e0d2bd51SGerd Hoffmann [KEY_LEFTSHIFT] = Q_KEY_CODE_SHIFT, 62e0d2bd51SGerd Hoffmann [KEY_BACKSLASH] = Q_KEY_CODE_BACKSLASH, 63e0d2bd51SGerd Hoffmann [KEY_102ND] = Q_KEY_CODE_LESS, 64e0d2bd51SGerd Hoffmann [KEY_Z] = Q_KEY_CODE_Z, 65e0d2bd51SGerd Hoffmann [KEY_X] = Q_KEY_CODE_X, 66e0d2bd51SGerd Hoffmann [KEY_C] = Q_KEY_CODE_C, 67e0d2bd51SGerd Hoffmann [KEY_V] = Q_KEY_CODE_V, 68e0d2bd51SGerd Hoffmann [KEY_B] = Q_KEY_CODE_B, 69e0d2bd51SGerd Hoffmann [KEY_N] = Q_KEY_CODE_N, 70e0d2bd51SGerd Hoffmann [KEY_M] = Q_KEY_CODE_M, 71e0d2bd51SGerd Hoffmann [KEY_COMMA] = Q_KEY_CODE_COMMA, 72e0d2bd51SGerd Hoffmann [KEY_DOT] = Q_KEY_CODE_DOT, 73e0d2bd51SGerd Hoffmann [KEY_SLASH] = Q_KEY_CODE_SLASH, 74e0d2bd51SGerd Hoffmann [KEY_RIGHTSHIFT] = Q_KEY_CODE_SHIFT_R, 75e0d2bd51SGerd Hoffmann [KEY_LEFTALT] = Q_KEY_CODE_ALT, 76e0d2bd51SGerd Hoffmann [KEY_SPACE] = Q_KEY_CODE_SPC, 77e0d2bd51SGerd Hoffmann [KEY_CAPSLOCK] = Q_KEY_CODE_CAPS_LOCK, 78e0d2bd51SGerd Hoffmann [KEY_F1] = Q_KEY_CODE_F1, 79e0d2bd51SGerd Hoffmann [KEY_F2] = Q_KEY_CODE_F2, 80e0d2bd51SGerd Hoffmann [KEY_F3] = Q_KEY_CODE_F3, 81e0d2bd51SGerd Hoffmann [KEY_F4] = Q_KEY_CODE_F4, 82e0d2bd51SGerd Hoffmann [KEY_F5] = Q_KEY_CODE_F5, 83e0d2bd51SGerd Hoffmann [KEY_F6] = Q_KEY_CODE_F6, 84e0d2bd51SGerd Hoffmann [KEY_F7] = Q_KEY_CODE_F7, 85e0d2bd51SGerd Hoffmann [KEY_F8] = Q_KEY_CODE_F8, 86e0d2bd51SGerd Hoffmann [KEY_F9] = Q_KEY_CODE_F9, 87e0d2bd51SGerd Hoffmann [KEY_F10] = Q_KEY_CODE_F10, 88e0d2bd51SGerd Hoffmann [KEY_NUMLOCK] = Q_KEY_CODE_NUM_LOCK, 89e0d2bd51SGerd Hoffmann [KEY_SCROLLLOCK] = Q_KEY_CODE_SCROLL_LOCK, 90e0d2bd51SGerd Hoffmann [KEY_KP0] = Q_KEY_CODE_KP_0, 91e0d2bd51SGerd Hoffmann [KEY_KP1] = Q_KEY_CODE_KP_1, 92e0d2bd51SGerd Hoffmann [KEY_KP2] = Q_KEY_CODE_KP_2, 93e0d2bd51SGerd Hoffmann [KEY_KP3] = Q_KEY_CODE_KP_3, 94e0d2bd51SGerd Hoffmann [KEY_KP4] = Q_KEY_CODE_KP_4, 95e0d2bd51SGerd Hoffmann [KEY_KP5] = Q_KEY_CODE_KP_5, 96e0d2bd51SGerd Hoffmann [KEY_KP6] = Q_KEY_CODE_KP_6, 97e0d2bd51SGerd Hoffmann [KEY_KP7] = Q_KEY_CODE_KP_7, 98e0d2bd51SGerd Hoffmann [KEY_KP8] = Q_KEY_CODE_KP_8, 99e0d2bd51SGerd Hoffmann [KEY_KP9] = Q_KEY_CODE_KP_9, 100e0d2bd51SGerd Hoffmann [KEY_KPMINUS] = Q_KEY_CODE_KP_SUBTRACT, 101e0d2bd51SGerd Hoffmann [KEY_KPPLUS] = Q_KEY_CODE_KP_ADD, 102e0d2bd51SGerd Hoffmann [KEY_KPDOT] = Q_KEY_CODE_KP_DECIMAL, 103e0d2bd51SGerd Hoffmann [KEY_KPENTER] = Q_KEY_CODE_KP_ENTER, 104e0d2bd51SGerd Hoffmann [KEY_KPSLASH] = Q_KEY_CODE_KP_DIVIDE, 105e0d2bd51SGerd Hoffmann [KEY_KPASTERISK] = Q_KEY_CODE_KP_MULTIPLY, 106e0d2bd51SGerd Hoffmann [KEY_F11] = Q_KEY_CODE_F11, 107e0d2bd51SGerd Hoffmann [KEY_F12] = Q_KEY_CODE_F12, 108e0d2bd51SGerd Hoffmann [KEY_RIGHTCTRL] = Q_KEY_CODE_CTRL_R, 109e0d2bd51SGerd Hoffmann [KEY_SYSRQ] = Q_KEY_CODE_SYSRQ, 110e0d2bd51SGerd Hoffmann [KEY_RIGHTALT] = Q_KEY_CODE_ALT_R, 111e0d2bd51SGerd Hoffmann [KEY_HOME] = Q_KEY_CODE_HOME, 112e0d2bd51SGerd Hoffmann [KEY_UP] = Q_KEY_CODE_UP, 113e0d2bd51SGerd Hoffmann [KEY_PAGEUP] = Q_KEY_CODE_PGUP, 114e0d2bd51SGerd Hoffmann [KEY_LEFT] = Q_KEY_CODE_LEFT, 115e0d2bd51SGerd Hoffmann [KEY_RIGHT] = Q_KEY_CODE_RIGHT, 116e0d2bd51SGerd Hoffmann [KEY_END] = Q_KEY_CODE_END, 117e0d2bd51SGerd Hoffmann [KEY_DOWN] = Q_KEY_CODE_DOWN, 118e0d2bd51SGerd Hoffmann [KEY_PAGEDOWN] = Q_KEY_CODE_PGDN, 119e0d2bd51SGerd Hoffmann [KEY_INSERT] = Q_KEY_CODE_INSERT, 120e0d2bd51SGerd Hoffmann [KEY_DELETE] = Q_KEY_CODE_DELETE, 121e0d2bd51SGerd Hoffmann [KEY_LEFTMETA] = Q_KEY_CODE_META_L, 122e0d2bd51SGerd Hoffmann [KEY_RIGHTMETA] = Q_KEY_CODE_META_R, 123e0d2bd51SGerd Hoffmann [KEY_MENU] = Q_KEY_CODE_MENU, 124e0d2bd51SGerd Hoffmann }; 125e0d2bd51SGerd Hoffmann 126e0d2bd51SGerd Hoffmann static int qemu_input_linux_to_qcode(unsigned int lnx) 127e0d2bd51SGerd Hoffmann { 128e0d2bd51SGerd Hoffmann assert(lnx < KEY_CNT); 129e0d2bd51SGerd Hoffmann return linux_to_qcode[lnx]; 130e0d2bd51SGerd Hoffmann } 131e0d2bd51SGerd Hoffmann 1320e066b2cSGerd Hoffmann #define TYPE_INPUT_LINUX "input-linux" 1330e066b2cSGerd Hoffmann #define INPUT_LINUX(obj) \ 1340e066b2cSGerd Hoffmann OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX) 1350e066b2cSGerd Hoffmann #define INPUT_LINUX_GET_CLASS(obj) \ 1360e066b2cSGerd Hoffmann OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX) 1370e066b2cSGerd Hoffmann #define INPUT_LINUX_CLASS(klass) \ 1380e066b2cSGerd Hoffmann OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX) 1390e066b2cSGerd Hoffmann 140e0d2bd51SGerd Hoffmann typedef struct InputLinux InputLinux; 1410e066b2cSGerd Hoffmann typedef struct InputLinuxClass InputLinuxClass; 142e0d2bd51SGerd Hoffmann 143e0d2bd51SGerd Hoffmann struct InputLinux { 1440e066b2cSGerd Hoffmann Object parent; 1450e066b2cSGerd Hoffmann 1460e066b2cSGerd Hoffmann char *evdev; 147e0d2bd51SGerd Hoffmann int fd; 148a6ccabd6SGerd Hoffmann bool repeat; 149e0d2bd51SGerd Hoffmann bool grab_request; 150e0d2bd51SGerd Hoffmann bool grab_active; 15146d921beSGerd Hoffmann bool grab_all; 152e0d2bd51SGerd Hoffmann bool keydown[KEY_CNT]; 153e0d2bd51SGerd Hoffmann int keycount; 154e0d2bd51SGerd Hoffmann int wheel; 1550e066b2cSGerd Hoffmann bool initialized; 15646d921beSGerd Hoffmann QTAILQ_ENTRY(InputLinux) next; 157e0d2bd51SGerd Hoffmann }; 158e0d2bd51SGerd Hoffmann 1590e066b2cSGerd Hoffmann struct InputLinuxClass { 1600e066b2cSGerd Hoffmann ObjectClass parent_class; 1610e066b2cSGerd Hoffmann }; 1620e066b2cSGerd Hoffmann 16346d921beSGerd Hoffmann static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs); 16446d921beSGerd Hoffmann 165e0d2bd51SGerd Hoffmann static void input_linux_toggle_grab(InputLinux *il) 166e0d2bd51SGerd Hoffmann { 167e0d2bd51SGerd Hoffmann intptr_t request = !il->grab_active; 16846d921beSGerd Hoffmann InputLinux *item; 169e0d2bd51SGerd Hoffmann int rc; 170e0d2bd51SGerd Hoffmann 171e0d2bd51SGerd Hoffmann rc = ioctl(il->fd, EVIOCGRAB, request); 172e0d2bd51SGerd Hoffmann if (rc < 0) { 173e0d2bd51SGerd Hoffmann return; 174e0d2bd51SGerd Hoffmann } 175e0d2bd51SGerd Hoffmann il->grab_active = !il->grab_active; 17646d921beSGerd Hoffmann 17746d921beSGerd Hoffmann if (!il->grab_all) { 17846d921beSGerd Hoffmann return; 17946d921beSGerd Hoffmann } 18046d921beSGerd Hoffmann QTAILQ_FOREACH(item, &inputs, next) { 18146d921beSGerd Hoffmann if (item == il || item->grab_all) { 18246d921beSGerd Hoffmann /* avoid endless loops */ 18346d921beSGerd Hoffmann continue; 18446d921beSGerd Hoffmann } 18546d921beSGerd Hoffmann if (item->grab_active != il->grab_active) { 18646d921beSGerd Hoffmann input_linux_toggle_grab(item); 18746d921beSGerd Hoffmann } 18846d921beSGerd Hoffmann } 189e0d2bd51SGerd Hoffmann } 190e0d2bd51SGerd Hoffmann 191e0d2bd51SGerd Hoffmann static void input_linux_event_keyboard(void *opaque) 192e0d2bd51SGerd Hoffmann { 193e0d2bd51SGerd Hoffmann InputLinux *il = opaque; 194e0d2bd51SGerd Hoffmann struct input_event event; 195e0d2bd51SGerd Hoffmann int rc; 196e0d2bd51SGerd Hoffmann 197e0d2bd51SGerd Hoffmann for (;;) { 198e0d2bd51SGerd Hoffmann rc = read(il->fd, &event, sizeof(event)); 199e0d2bd51SGerd Hoffmann if (rc != sizeof(event)) { 200e0d2bd51SGerd Hoffmann if (rc < 0 && errno != EAGAIN) { 201e0d2bd51SGerd Hoffmann fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno)); 202e0d2bd51SGerd Hoffmann qemu_set_fd_handler(il->fd, NULL, NULL, NULL); 203e0d2bd51SGerd Hoffmann close(il->fd); 204e0d2bd51SGerd Hoffmann } 205e0d2bd51SGerd Hoffmann break; 206e0d2bd51SGerd Hoffmann } 207e0d2bd51SGerd Hoffmann 208e0d2bd51SGerd Hoffmann switch (event.type) { 209e0d2bd51SGerd Hoffmann case EV_KEY: 210a6ccabd6SGerd Hoffmann if (event.value > 2 || (event.value > 1 && !il->repeat)) { 211e0d2bd51SGerd Hoffmann /* 212e0d2bd51SGerd Hoffmann * ignore autorepeat + unknown key events 213e0d2bd51SGerd Hoffmann * 0 == up, 1 == down, 2 == autorepeat, other == undefined 214e0d2bd51SGerd Hoffmann */ 215e0d2bd51SGerd Hoffmann continue; 216e0d2bd51SGerd Hoffmann } 21781b00c96SGerd Hoffmann if (event.code >= KEY_CNT) { 21881b00c96SGerd Hoffmann /* 21981b00c96SGerd Hoffmann * Should not happen. But better safe than sorry, 22081b00c96SGerd Hoffmann * and we make Coverity happy too. 22181b00c96SGerd Hoffmann */ 22281b00c96SGerd Hoffmann continue; 22381b00c96SGerd Hoffmann } 224e0d2bd51SGerd Hoffmann /* keep track of key state */ 225e0d2bd51SGerd Hoffmann if (!il->keydown[event.code] && event.value) { 226e0d2bd51SGerd Hoffmann il->keydown[event.code] = true; 227e0d2bd51SGerd Hoffmann il->keycount++; 228e0d2bd51SGerd Hoffmann } 229e0d2bd51SGerd Hoffmann if (il->keydown[event.code] && !event.value) { 230e0d2bd51SGerd Hoffmann il->keydown[event.code] = false; 231e0d2bd51SGerd Hoffmann il->keycount--; 232e0d2bd51SGerd Hoffmann } 233e0d2bd51SGerd Hoffmann 234e0d2bd51SGerd Hoffmann /* send event to guest when grab is active */ 235e0d2bd51SGerd Hoffmann if (il->grab_active) { 236e0d2bd51SGerd Hoffmann int qcode = qemu_input_linux_to_qcode(event.code); 237e0d2bd51SGerd Hoffmann qemu_input_event_send_key_qcode(NULL, qcode, event.value); 238e0d2bd51SGerd Hoffmann } 239e0d2bd51SGerd Hoffmann 240e0d2bd51SGerd Hoffmann /* hotkey -> record switch request ... */ 241e0d2bd51SGerd Hoffmann if (il->keydown[KEY_LEFTCTRL] && 242e0d2bd51SGerd Hoffmann il->keydown[KEY_RIGHTCTRL]) { 243e0d2bd51SGerd Hoffmann il->grab_request = true; 244e0d2bd51SGerd Hoffmann } 245e0d2bd51SGerd Hoffmann 246e0d2bd51SGerd Hoffmann /* 247e0d2bd51SGerd Hoffmann * ... and do the switch when all keys are lifted, so we 248e0d2bd51SGerd Hoffmann * confuse neither guest nor host with keys which seem to 249e0d2bd51SGerd Hoffmann * be stuck due to missing key-up events. 250e0d2bd51SGerd Hoffmann */ 251e0d2bd51SGerd Hoffmann if (il->grab_request && !il->keycount) { 252e0d2bd51SGerd Hoffmann il->grab_request = false; 253e0d2bd51SGerd Hoffmann input_linux_toggle_grab(il); 254e0d2bd51SGerd Hoffmann } 255e0d2bd51SGerd Hoffmann break; 256e0d2bd51SGerd Hoffmann } 257e0d2bd51SGerd Hoffmann } 258e0d2bd51SGerd Hoffmann } 259e0d2bd51SGerd Hoffmann 260e0d2bd51SGerd Hoffmann static void input_linux_event_mouse_button(int button) 261e0d2bd51SGerd Hoffmann { 262e0d2bd51SGerd Hoffmann qemu_input_queue_btn(NULL, button, true); 263e0d2bd51SGerd Hoffmann qemu_input_event_sync(); 264e0d2bd51SGerd Hoffmann qemu_input_queue_btn(NULL, button, false); 265e0d2bd51SGerd Hoffmann qemu_input_event_sync(); 266e0d2bd51SGerd Hoffmann } 267e0d2bd51SGerd Hoffmann 268*d4df42c4SGerd Hoffmann static void input_linux_handle_mouse(InputLinux *il, struct input_event *event) 269*d4df42c4SGerd Hoffmann { 270*d4df42c4SGerd Hoffmann if (!il->grab_active) { 271*d4df42c4SGerd Hoffmann return; 272*d4df42c4SGerd Hoffmann } 273*d4df42c4SGerd Hoffmann 274*d4df42c4SGerd Hoffmann switch (event->type) { 275*d4df42c4SGerd Hoffmann case EV_KEY: 276*d4df42c4SGerd Hoffmann switch (event->code) { 277*d4df42c4SGerd Hoffmann case BTN_LEFT: 278*d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event->value); 279*d4df42c4SGerd Hoffmann break; 280*d4df42c4SGerd Hoffmann case BTN_RIGHT: 281*d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event->value); 282*d4df42c4SGerd Hoffmann break; 283*d4df42c4SGerd Hoffmann case BTN_MIDDLE: 284*d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event->value); 285*d4df42c4SGerd Hoffmann break; 286*d4df42c4SGerd Hoffmann case BTN_GEAR_UP: 287*d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event->value); 288*d4df42c4SGerd Hoffmann break; 289*d4df42c4SGerd Hoffmann case BTN_GEAR_DOWN: 290*d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN, 291*d4df42c4SGerd Hoffmann event->value); 292*d4df42c4SGerd Hoffmann break; 293*d4df42c4SGerd Hoffmann }; 294*d4df42c4SGerd Hoffmann break; 295*d4df42c4SGerd Hoffmann case EV_REL: 296*d4df42c4SGerd Hoffmann switch (event->code) { 297*d4df42c4SGerd Hoffmann case REL_X: 298*d4df42c4SGerd Hoffmann qemu_input_queue_rel(NULL, INPUT_AXIS_X, event->value); 299*d4df42c4SGerd Hoffmann break; 300*d4df42c4SGerd Hoffmann case REL_Y: 301*d4df42c4SGerd Hoffmann qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event->value); 302*d4df42c4SGerd Hoffmann break; 303*d4df42c4SGerd Hoffmann case REL_WHEEL: 304*d4df42c4SGerd Hoffmann il->wheel = event->value; 305*d4df42c4SGerd Hoffmann break; 306*d4df42c4SGerd Hoffmann } 307*d4df42c4SGerd Hoffmann break; 308*d4df42c4SGerd Hoffmann case EV_SYN: 309*d4df42c4SGerd Hoffmann qemu_input_event_sync(); 310*d4df42c4SGerd Hoffmann if (il->wheel != 0) { 311*d4df42c4SGerd Hoffmann input_linux_event_mouse_button((il->wheel > 0) 312*d4df42c4SGerd Hoffmann ? INPUT_BUTTON_WHEEL_UP 313*d4df42c4SGerd Hoffmann : INPUT_BUTTON_WHEEL_DOWN); 314*d4df42c4SGerd Hoffmann il->wheel = 0; 315*d4df42c4SGerd Hoffmann } 316*d4df42c4SGerd Hoffmann break; 317*d4df42c4SGerd Hoffmann } 318*d4df42c4SGerd Hoffmann } 319*d4df42c4SGerd Hoffmann 320e0d2bd51SGerd Hoffmann static void input_linux_event_mouse(void *opaque) 321e0d2bd51SGerd Hoffmann { 322e0d2bd51SGerd Hoffmann InputLinux *il = opaque; 323e0d2bd51SGerd Hoffmann struct input_event event; 324e0d2bd51SGerd Hoffmann int rc; 325e0d2bd51SGerd Hoffmann 326e0d2bd51SGerd Hoffmann for (;;) { 327e0d2bd51SGerd Hoffmann rc = read(il->fd, &event, sizeof(event)); 328e0d2bd51SGerd Hoffmann if (rc != sizeof(event)) { 329e0d2bd51SGerd Hoffmann if (rc < 0 && errno != EAGAIN) { 330e0d2bd51SGerd Hoffmann fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno)); 331e0d2bd51SGerd Hoffmann qemu_set_fd_handler(il->fd, NULL, NULL, NULL); 332e0d2bd51SGerd Hoffmann close(il->fd); 333e0d2bd51SGerd Hoffmann } 334e0d2bd51SGerd Hoffmann break; 335e0d2bd51SGerd Hoffmann } 336e0d2bd51SGerd Hoffmann 337*d4df42c4SGerd Hoffmann input_linux_handle_mouse(il, &event); 338e0d2bd51SGerd Hoffmann } 339e0d2bd51SGerd Hoffmann } 340e0d2bd51SGerd Hoffmann 3410e066b2cSGerd Hoffmann static void input_linux_complete(UserCreatable *uc, Error **errp) 342e0d2bd51SGerd Hoffmann { 3430e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(uc); 344ce47d3d4SGerd Hoffmann uint32_t evtmap, relmap, absmap; 345e0d2bd51SGerd Hoffmann int rc, ver; 346e0d2bd51SGerd Hoffmann 347e0d2bd51SGerd Hoffmann if (!il->evdev) { 348e0d2bd51SGerd Hoffmann error_setg(errp, "no input device specified"); 3490e066b2cSGerd Hoffmann return; 350e0d2bd51SGerd Hoffmann } 351e0d2bd51SGerd Hoffmann 352e0d2bd51SGerd Hoffmann il->fd = open(il->evdev, O_RDWR); 353e0d2bd51SGerd Hoffmann if (il->fd < 0) { 354e0d2bd51SGerd Hoffmann error_setg_file_open(errp, errno, il->evdev); 3550e066b2cSGerd Hoffmann return; 356e0d2bd51SGerd Hoffmann } 357e0d2bd51SGerd Hoffmann qemu_set_nonblock(il->fd); 358e0d2bd51SGerd Hoffmann 359e0d2bd51SGerd Hoffmann rc = ioctl(il->fd, EVIOCGVERSION, &ver); 360e0d2bd51SGerd Hoffmann if (rc < 0) { 361e0d2bd51SGerd Hoffmann error_setg(errp, "%s: is not an evdev device", il->evdev); 362e0d2bd51SGerd Hoffmann goto err_close; 363e0d2bd51SGerd Hoffmann } 364e0d2bd51SGerd Hoffmann 365e0d2bd51SGerd Hoffmann rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); 366ce47d3d4SGerd Hoffmann if (rc < 0) { 367ce47d3d4SGerd Hoffmann error_setg(errp, "%s: failed to read event bits", il->evdev); 368ce47d3d4SGerd Hoffmann goto err_close; 369ce47d3d4SGerd Hoffmann } 370e0d2bd51SGerd Hoffmann 371e0d2bd51SGerd Hoffmann if (evtmap & (1 << EV_REL)) { 372ce47d3d4SGerd Hoffmann rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap); 373ce47d3d4SGerd Hoffmann if (rc < 0) { 374ce47d3d4SGerd Hoffmann relmap = 0; 375ce47d3d4SGerd Hoffmann } 376ce47d3d4SGerd Hoffmann } 377ce47d3d4SGerd Hoffmann 378ce47d3d4SGerd Hoffmann if (evtmap & (1 << EV_ABS)) { 379ce47d3d4SGerd Hoffmann ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap); 380ce47d3d4SGerd Hoffmann if (rc < 0) { 381ce47d3d4SGerd Hoffmann absmap = 0; 382ce47d3d4SGerd Hoffmann } 383ce47d3d4SGerd Hoffmann } 384ce47d3d4SGerd Hoffmann 385ce47d3d4SGerd Hoffmann if ((evtmap & (1 << EV_REL)) && 386ce47d3d4SGerd Hoffmann (relmap & (1 << REL_X))) { 387ce47d3d4SGerd Hoffmann /* has relative x axis -> assume mouse */ 388e0d2bd51SGerd Hoffmann qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il); 389ce47d3d4SGerd Hoffmann } else if ((evtmap & (1 << EV_ABS)) && 390ce47d3d4SGerd Hoffmann (absmap & (1 << ABS_X))) { 391ce47d3d4SGerd Hoffmann /* has absolute x axis -> not supported */ 392e0d2bd51SGerd Hoffmann error_setg(errp, "tablet/touchscreen not supported"); 393e0d2bd51SGerd Hoffmann goto err_close; 394e0d2bd51SGerd Hoffmann } else if (evtmap & (1 << EV_KEY)) { 395ce47d3d4SGerd Hoffmann /* has keys/buttons (and no x axis) -> assume keyboard */ 396e0d2bd51SGerd Hoffmann qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il); 397e0d2bd51SGerd Hoffmann } else { 398e0d2bd51SGerd Hoffmann /* Huh? What is this? */ 399e0d2bd51SGerd Hoffmann error_setg(errp, "unknown kind of input device"); 400e0d2bd51SGerd Hoffmann goto err_close; 401e0d2bd51SGerd Hoffmann } 402e0d2bd51SGerd Hoffmann input_linux_toggle_grab(il); 40346d921beSGerd Hoffmann QTAILQ_INSERT_TAIL(&inputs, il, next); 4040e066b2cSGerd Hoffmann il->initialized = true; 4050e066b2cSGerd Hoffmann return; 406e0d2bd51SGerd Hoffmann 407e0d2bd51SGerd Hoffmann err_close: 408e0d2bd51SGerd Hoffmann close(il->fd); 4090e066b2cSGerd Hoffmann return; 410e0d2bd51SGerd Hoffmann } 411e0d2bd51SGerd Hoffmann 4120e066b2cSGerd Hoffmann static void input_linux_instance_finalize(Object *obj) 413e0d2bd51SGerd Hoffmann { 4140e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4150e066b2cSGerd Hoffmann 4160e066b2cSGerd Hoffmann if (il->initialized) { 4170e066b2cSGerd Hoffmann QTAILQ_REMOVE(&inputs, il, next); 4180e066b2cSGerd Hoffmann close(il->fd); 4190e066b2cSGerd Hoffmann } 4200e066b2cSGerd Hoffmann g_free(il->evdev); 4210e066b2cSGerd Hoffmann } 4220e066b2cSGerd Hoffmann 4230e066b2cSGerd Hoffmann static char *input_linux_get_evdev(Object *obj, Error **errp) 4240e066b2cSGerd Hoffmann { 4250e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4260e066b2cSGerd Hoffmann 4270e066b2cSGerd Hoffmann return g_strdup(il->evdev); 4280e066b2cSGerd Hoffmann } 4290e066b2cSGerd Hoffmann 4300e066b2cSGerd Hoffmann static void input_linux_set_evdev(Object *obj, const char *value, 4310e066b2cSGerd Hoffmann Error **errp) 4320e066b2cSGerd Hoffmann { 4330e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4340e066b2cSGerd Hoffmann 4350e066b2cSGerd Hoffmann if (il->evdev) { 4360e066b2cSGerd Hoffmann error_setg(errp, "evdev property already set"); 4370e066b2cSGerd Hoffmann return; 4380e066b2cSGerd Hoffmann } 4390e066b2cSGerd Hoffmann il->evdev = g_strdup(value); 4400e066b2cSGerd Hoffmann } 4410e066b2cSGerd Hoffmann 4420e066b2cSGerd Hoffmann static bool input_linux_get_grab_all(Object *obj, Error **errp) 4430e066b2cSGerd Hoffmann { 4440e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4450e066b2cSGerd Hoffmann 4460e066b2cSGerd Hoffmann return il->grab_all; 4470e066b2cSGerd Hoffmann } 4480e066b2cSGerd Hoffmann 4490e066b2cSGerd Hoffmann static void input_linux_set_grab_all(Object *obj, bool value, 4500e066b2cSGerd Hoffmann Error **errp) 4510e066b2cSGerd Hoffmann { 4520e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4530e066b2cSGerd Hoffmann 4540e066b2cSGerd Hoffmann il->grab_all = value; 4550e066b2cSGerd Hoffmann } 4560e066b2cSGerd Hoffmann 4570e066b2cSGerd Hoffmann static bool input_linux_get_repeat(Object *obj, Error **errp) 4580e066b2cSGerd Hoffmann { 4590e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4600e066b2cSGerd Hoffmann 4610e066b2cSGerd Hoffmann return il->repeat; 4620e066b2cSGerd Hoffmann } 4630e066b2cSGerd Hoffmann 4640e066b2cSGerd Hoffmann static void input_linux_set_repeat(Object *obj, bool value, 4650e066b2cSGerd Hoffmann Error **errp) 4660e066b2cSGerd Hoffmann { 4670e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4680e066b2cSGerd Hoffmann 4690e066b2cSGerd Hoffmann il->repeat = value; 4700e066b2cSGerd Hoffmann } 4710e066b2cSGerd Hoffmann 4720e066b2cSGerd Hoffmann static void input_linux_instance_init(Object *obj) 4730e066b2cSGerd Hoffmann { 4740e066b2cSGerd Hoffmann object_property_add_str(obj, "evdev", 4750e066b2cSGerd Hoffmann input_linux_get_evdev, 4760e066b2cSGerd Hoffmann input_linux_set_evdev, NULL); 4770e066b2cSGerd Hoffmann object_property_add_bool(obj, "grab_all", 4780e066b2cSGerd Hoffmann input_linux_get_grab_all, 4790e066b2cSGerd Hoffmann input_linux_set_grab_all, NULL); 4800e066b2cSGerd Hoffmann object_property_add_bool(obj, "repeat", 4810e066b2cSGerd Hoffmann input_linux_get_repeat, 4820e066b2cSGerd Hoffmann input_linux_set_repeat, NULL); 4830e066b2cSGerd Hoffmann } 4840e066b2cSGerd Hoffmann 4850e066b2cSGerd Hoffmann static void input_linux_class_init(ObjectClass *oc, void *data) 4860e066b2cSGerd Hoffmann { 4870e066b2cSGerd Hoffmann UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 4880e066b2cSGerd Hoffmann 4890e066b2cSGerd Hoffmann ucc->complete = input_linux_complete; 4900e066b2cSGerd Hoffmann } 4910e066b2cSGerd Hoffmann 4920e066b2cSGerd Hoffmann static const TypeInfo input_linux_info = { 4930e066b2cSGerd Hoffmann .name = TYPE_INPUT_LINUX, 4940e066b2cSGerd Hoffmann .parent = TYPE_OBJECT, 4950e066b2cSGerd Hoffmann .class_size = sizeof(InputLinuxClass), 4960e066b2cSGerd Hoffmann .class_init = input_linux_class_init, 4970e066b2cSGerd Hoffmann .instance_size = sizeof(InputLinux), 4980e066b2cSGerd Hoffmann .instance_init = input_linux_instance_init, 4990e066b2cSGerd Hoffmann .instance_finalize = input_linux_instance_finalize, 5000e066b2cSGerd Hoffmann .interfaces = (InterfaceInfo[]) { 5010e066b2cSGerd Hoffmann { TYPE_USER_CREATABLE }, 5020e066b2cSGerd Hoffmann { } 5030e066b2cSGerd Hoffmann } 504e0d2bd51SGerd Hoffmann }; 505e0d2bd51SGerd Hoffmann 5060e066b2cSGerd Hoffmann static void register_types(void) 507e0d2bd51SGerd Hoffmann { 5080e066b2cSGerd Hoffmann type_register_static(&input_linux_info); 509e0d2bd51SGerd Hoffmann } 5100e066b2cSGerd Hoffmann 5110e066b2cSGerd Hoffmann type_init(register_types); 512