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/config-file.h" 10db725815SMarkus Armbruster #include "qemu/main-loop.h" 110b8fa32fSMarkus Armbruster #include "qemu/module.h" 12e0d2bd51SGerd Hoffmann #include "qemu/sockets.h" 13e0d2bd51SGerd Hoffmann #include "ui/input.h" 140e066b2cSGerd Hoffmann #include "qom/object_interfaces.h" 152657846fSRyan El Kochta #include "sysemu/iothread.h" 162657846fSRyan El Kochta #include "block/aio.h" 17e0d2bd51SGerd Hoffmann 18e0d2bd51SGerd Hoffmann #include <sys/ioctl.h> 19e0d2bd51SGerd Hoffmann #include "standard-headers/linux/input.h" 20e0d2bd51SGerd Hoffmann 212e6a64cbSGerd Hoffmann static bool linux_is_button(unsigned int lnx) 222e6a64cbSGerd Hoffmann { 232e6a64cbSGerd Hoffmann if (lnx < 0x100) { 242e6a64cbSGerd Hoffmann return false; 252e6a64cbSGerd Hoffmann } 262e6a64cbSGerd Hoffmann if (lnx >= 0x160 && lnx < 0x2c0) { 272e6a64cbSGerd Hoffmann return false; 282e6a64cbSGerd Hoffmann } 292e6a64cbSGerd Hoffmann return true; 302e6a64cbSGerd Hoffmann } 312e6a64cbSGerd Hoffmann 320e066b2cSGerd Hoffmann #define TYPE_INPUT_LINUX "input-linux" 330e066b2cSGerd Hoffmann #define INPUT_LINUX(obj) \ 340e066b2cSGerd Hoffmann OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX) 350e066b2cSGerd Hoffmann #define INPUT_LINUX_GET_CLASS(obj) \ 360e066b2cSGerd Hoffmann OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX) 370e066b2cSGerd Hoffmann #define INPUT_LINUX_CLASS(klass) \ 380e066b2cSGerd Hoffmann OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX) 390e066b2cSGerd Hoffmann 40e0d2bd51SGerd Hoffmann typedef struct InputLinux InputLinux; 410e066b2cSGerd Hoffmann typedef struct InputLinuxClass InputLinuxClass; 42e0d2bd51SGerd Hoffmann 43e0d2bd51SGerd Hoffmann struct InputLinux { 440e066b2cSGerd Hoffmann Object parent; 450e066b2cSGerd Hoffmann 460e066b2cSGerd Hoffmann char *evdev; 47e0d2bd51SGerd Hoffmann int fd; 48a6ccabd6SGerd Hoffmann bool repeat; 49e0d2bd51SGerd Hoffmann bool grab_request; 50e0d2bd51SGerd Hoffmann bool grab_active; 5146d921beSGerd Hoffmann bool grab_all; 52e0d2bd51SGerd Hoffmann bool keydown[KEY_CNT]; 53e0d2bd51SGerd Hoffmann int keycount; 54e0d2bd51SGerd Hoffmann int wheel; 550e066b2cSGerd Hoffmann bool initialized; 562e6a64cbSGerd Hoffmann 572e6a64cbSGerd Hoffmann bool has_rel_x; 582e6a64cbSGerd Hoffmann bool has_abs_x; 592e6a64cbSGerd Hoffmann int num_keys; 602e6a64cbSGerd Hoffmann int num_btns; 61d755defdSPhilippe Voinov int abs_x_min; 62d755defdSPhilippe Voinov int abs_x_max; 63d755defdSPhilippe Voinov int abs_y_min; 64d755defdSPhilippe Voinov int abs_y_max; 651684907cSJavier Celaya struct input_event event; 661684907cSJavier Celaya int read_offset; 672e6a64cbSGerd Hoffmann 682657846fSRyan El Kochta enum GrabToggleKeys grab_toggle; 692657846fSRyan El Kochta 7046d921beSGerd Hoffmann QTAILQ_ENTRY(InputLinux) next; 71e0d2bd51SGerd Hoffmann }; 72e0d2bd51SGerd Hoffmann 730e066b2cSGerd Hoffmann struct InputLinuxClass { 740e066b2cSGerd Hoffmann ObjectClass parent_class; 750e066b2cSGerd Hoffmann }; 760e066b2cSGerd Hoffmann 7746d921beSGerd Hoffmann static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs); 7846d921beSGerd Hoffmann 79e0d2bd51SGerd Hoffmann static void input_linux_toggle_grab(InputLinux *il) 80e0d2bd51SGerd Hoffmann { 81e0d2bd51SGerd Hoffmann intptr_t request = !il->grab_active; 8246d921beSGerd Hoffmann InputLinux *item; 83e0d2bd51SGerd Hoffmann int rc; 84e0d2bd51SGerd Hoffmann 85e0d2bd51SGerd Hoffmann rc = ioctl(il->fd, EVIOCGRAB, request); 86e0d2bd51SGerd Hoffmann if (rc < 0) { 87e0d2bd51SGerd Hoffmann return; 88e0d2bd51SGerd Hoffmann } 89e0d2bd51SGerd Hoffmann il->grab_active = !il->grab_active; 9046d921beSGerd Hoffmann 9146d921beSGerd Hoffmann if (!il->grab_all) { 9246d921beSGerd Hoffmann return; 9346d921beSGerd Hoffmann } 9446d921beSGerd Hoffmann QTAILQ_FOREACH(item, &inputs, next) { 9546d921beSGerd Hoffmann if (item == il || item->grab_all) { 9646d921beSGerd Hoffmann /* avoid endless loops */ 9746d921beSGerd Hoffmann continue; 9846d921beSGerd Hoffmann } 9946d921beSGerd Hoffmann if (item->grab_active != il->grab_active) { 10046d921beSGerd Hoffmann input_linux_toggle_grab(item); 10146d921beSGerd Hoffmann } 10246d921beSGerd Hoffmann } 103e0d2bd51SGerd Hoffmann } 104e0d2bd51SGerd Hoffmann 1052657846fSRyan El Kochta static bool input_linux_check_toggle(InputLinux *il) 1062657846fSRyan El Kochta { 1072657846fSRyan El Kochta switch (il->grab_toggle) { 1082657846fSRyan El Kochta case GRAB_TOGGLE_KEYS_CTRL_CTRL: 1092657846fSRyan El Kochta return il->keydown[KEY_LEFTCTRL] && 1102657846fSRyan El Kochta il->keydown[KEY_RIGHTCTRL]; 1112657846fSRyan El Kochta 1122657846fSRyan El Kochta case GRAB_TOGGLE_KEYS_ALT_ALT: 1132657846fSRyan El Kochta return il->keydown[KEY_LEFTALT] && 1142657846fSRyan El Kochta il->keydown[KEY_RIGHTALT]; 1152657846fSRyan El Kochta 116*a923b471SNiklas Haas case GRAB_TOGGLE_KEYS_SHIFT_SHIFT: 117*a923b471SNiklas Haas return il->keydown[KEY_LEFTSHIFT] && 118*a923b471SNiklas Haas il->keydown[KEY_RIGHTSHIFT]; 119*a923b471SNiklas Haas 1202657846fSRyan El Kochta case GRAB_TOGGLE_KEYS_META_META: 1212657846fSRyan El Kochta return il->keydown[KEY_LEFTMETA] && 1222657846fSRyan El Kochta il->keydown[KEY_RIGHTMETA]; 1232657846fSRyan El Kochta 1242657846fSRyan El Kochta case GRAB_TOGGLE_KEYS_SCROLLLOCK: 1252657846fSRyan El Kochta return il->keydown[KEY_SCROLLLOCK]; 1262657846fSRyan El Kochta 1272657846fSRyan El Kochta case GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK: 1282657846fSRyan El Kochta return (il->keydown[KEY_LEFTCTRL] || 1292657846fSRyan El Kochta il->keydown[KEY_RIGHTCTRL]) && 1302657846fSRyan El Kochta il->keydown[KEY_SCROLLLOCK]; 1312657846fSRyan El Kochta 1322657846fSRyan El Kochta case GRAB_TOGGLE_KEYS__MAX: 1332657846fSRyan El Kochta /* avoid gcc error */ 1342657846fSRyan El Kochta break; 1352657846fSRyan El Kochta } 1362657846fSRyan El Kochta return false; 1372657846fSRyan El Kochta } 1382657846fSRyan El Kochta 1392657846fSRyan El Kochta static bool input_linux_should_skip(InputLinux *il, 1402657846fSRyan El Kochta struct input_event *event) 1412657846fSRyan El Kochta { 1422657846fSRyan El Kochta return (il->grab_toggle == GRAB_TOGGLE_KEYS_SCROLLLOCK || 1432657846fSRyan El Kochta il->grab_toggle == GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK) && 1442657846fSRyan El Kochta event->code == KEY_SCROLLLOCK; 1452657846fSRyan El Kochta } 1462657846fSRyan El Kochta 1472330e9e7SGerd Hoffmann static void input_linux_handle_keyboard(InputLinux *il, 1482330e9e7SGerd Hoffmann struct input_event *event) 149e0d2bd51SGerd Hoffmann { 1502330e9e7SGerd Hoffmann if (event->type == EV_KEY) { 1512330e9e7SGerd Hoffmann if (event->value > 2 || (event->value > 1 && !il->repeat)) { 152e0d2bd51SGerd Hoffmann /* 153e0d2bd51SGerd Hoffmann * ignore autorepeat + unknown key events 154e0d2bd51SGerd Hoffmann * 0 == up, 1 == down, 2 == autorepeat, other == undefined 155e0d2bd51SGerd Hoffmann */ 1562330e9e7SGerd Hoffmann return; 157e0d2bd51SGerd Hoffmann } 1582330e9e7SGerd Hoffmann if (event->code >= KEY_CNT) { 15981b00c96SGerd Hoffmann /* 16081b00c96SGerd Hoffmann * Should not happen. But better safe than sorry, 16181b00c96SGerd Hoffmann * and we make Coverity happy too. 16281b00c96SGerd Hoffmann */ 1632330e9e7SGerd Hoffmann return; 16481b00c96SGerd Hoffmann } 1652330e9e7SGerd Hoffmann 166e0d2bd51SGerd Hoffmann /* keep track of key state */ 1672330e9e7SGerd Hoffmann if (!il->keydown[event->code] && event->value) { 1682330e9e7SGerd Hoffmann il->keydown[event->code] = true; 169e0d2bd51SGerd Hoffmann il->keycount++; 170e0d2bd51SGerd Hoffmann } 1712330e9e7SGerd Hoffmann if (il->keydown[event->code] && !event->value) { 1722330e9e7SGerd Hoffmann il->keydown[event->code] = false; 173e0d2bd51SGerd Hoffmann il->keycount--; 174e0d2bd51SGerd Hoffmann } 175e0d2bd51SGerd Hoffmann 176e0d2bd51SGerd Hoffmann /* send event to guest when grab is active */ 1772657846fSRyan El Kochta if (il->grab_active && !input_linux_should_skip(il, event)) { 1782330e9e7SGerd Hoffmann int qcode = qemu_input_linux_to_qcode(event->code); 1792330e9e7SGerd Hoffmann qemu_input_event_send_key_qcode(NULL, qcode, event->value); 180e0d2bd51SGerd Hoffmann } 181e0d2bd51SGerd Hoffmann 182e0d2bd51SGerd Hoffmann /* hotkey -> record switch request ... */ 1832657846fSRyan El Kochta if (input_linux_check_toggle(il)) { 184e0d2bd51SGerd Hoffmann il->grab_request = true; 185e0d2bd51SGerd Hoffmann } 186e0d2bd51SGerd Hoffmann 187e0d2bd51SGerd Hoffmann /* 188e0d2bd51SGerd Hoffmann * ... and do the switch when all keys are lifted, so we 189e0d2bd51SGerd Hoffmann * confuse neither guest nor host with keys which seem to 190e0d2bd51SGerd Hoffmann * be stuck due to missing key-up events. 191e0d2bd51SGerd Hoffmann */ 192e0d2bd51SGerd Hoffmann if (il->grab_request && !il->keycount) { 193e0d2bd51SGerd Hoffmann il->grab_request = false; 194e0d2bd51SGerd Hoffmann input_linux_toggle_grab(il); 195e0d2bd51SGerd Hoffmann } 1962330e9e7SGerd Hoffmann } 1972330e9e7SGerd Hoffmann } 1982330e9e7SGerd Hoffmann 199e0d2bd51SGerd Hoffmann static void input_linux_event_mouse_button(int button) 200e0d2bd51SGerd Hoffmann { 201e0d2bd51SGerd Hoffmann qemu_input_queue_btn(NULL, button, true); 202e0d2bd51SGerd Hoffmann qemu_input_event_sync(); 203e0d2bd51SGerd Hoffmann qemu_input_queue_btn(NULL, button, false); 204e0d2bd51SGerd Hoffmann qemu_input_event_sync(); 205e0d2bd51SGerd Hoffmann } 206e0d2bd51SGerd Hoffmann 207d4df42c4SGerd Hoffmann static void input_linux_handle_mouse(InputLinux *il, struct input_event *event) 208d4df42c4SGerd Hoffmann { 209d4df42c4SGerd Hoffmann if (!il->grab_active) { 210d4df42c4SGerd Hoffmann return; 211d4df42c4SGerd Hoffmann } 212d4df42c4SGerd Hoffmann 213d4df42c4SGerd Hoffmann switch (event->type) { 214d4df42c4SGerd Hoffmann case EV_KEY: 215d4df42c4SGerd Hoffmann switch (event->code) { 216d4df42c4SGerd Hoffmann case BTN_LEFT: 217d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event->value); 218d4df42c4SGerd Hoffmann break; 219d4df42c4SGerd Hoffmann case BTN_RIGHT: 220d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event->value); 221d4df42c4SGerd Hoffmann break; 222d4df42c4SGerd Hoffmann case BTN_MIDDLE: 223d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event->value); 224d4df42c4SGerd Hoffmann break; 225d4df42c4SGerd Hoffmann case BTN_GEAR_UP: 226d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event->value); 227d4df42c4SGerd Hoffmann break; 228d4df42c4SGerd Hoffmann case BTN_GEAR_DOWN: 229d4df42c4SGerd Hoffmann qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN, 230d4df42c4SGerd Hoffmann event->value); 231d4df42c4SGerd Hoffmann break; 2321266b68cSFabian Lesniak case BTN_SIDE: 2331266b68cSFabian Lesniak qemu_input_queue_btn(NULL, INPUT_BUTTON_SIDE, event->value); 2341266b68cSFabian Lesniak break; 2351266b68cSFabian Lesniak case BTN_EXTRA: 2361266b68cSFabian Lesniak qemu_input_queue_btn(NULL, INPUT_BUTTON_EXTRA, event->value); 2371266b68cSFabian Lesniak break; 238d4df42c4SGerd Hoffmann }; 239d4df42c4SGerd Hoffmann break; 240d4df42c4SGerd Hoffmann case EV_REL: 241d4df42c4SGerd Hoffmann switch (event->code) { 242d4df42c4SGerd Hoffmann case REL_X: 243d4df42c4SGerd Hoffmann qemu_input_queue_rel(NULL, INPUT_AXIS_X, event->value); 244d4df42c4SGerd Hoffmann break; 245d4df42c4SGerd Hoffmann case REL_Y: 246d4df42c4SGerd Hoffmann qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event->value); 247d4df42c4SGerd Hoffmann break; 248d4df42c4SGerd Hoffmann case REL_WHEEL: 249d4df42c4SGerd Hoffmann il->wheel = event->value; 250d4df42c4SGerd Hoffmann break; 251d4df42c4SGerd Hoffmann } 252d4df42c4SGerd Hoffmann break; 253d755defdSPhilippe Voinov case EV_ABS: 254d755defdSPhilippe Voinov switch (event->code) { 255d755defdSPhilippe Voinov case ABS_X: 256d755defdSPhilippe Voinov qemu_input_queue_abs(NULL, INPUT_AXIS_X, event->value, 257d755defdSPhilippe Voinov il->abs_x_min, il->abs_x_max); 258d755defdSPhilippe Voinov break; 259d755defdSPhilippe Voinov case ABS_Y: 260d755defdSPhilippe Voinov qemu_input_queue_abs(NULL, INPUT_AXIS_Y, event->value, 261d755defdSPhilippe Voinov il->abs_y_min, il->abs_y_max); 262d755defdSPhilippe Voinov break; 263d755defdSPhilippe Voinov } 264d755defdSPhilippe Voinov break; 265d4df42c4SGerd Hoffmann case EV_SYN: 266d4df42c4SGerd Hoffmann qemu_input_event_sync(); 267d4df42c4SGerd Hoffmann if (il->wheel != 0) { 268d4df42c4SGerd Hoffmann input_linux_event_mouse_button((il->wheel > 0) 269d4df42c4SGerd Hoffmann ? INPUT_BUTTON_WHEEL_UP 270d4df42c4SGerd Hoffmann : INPUT_BUTTON_WHEEL_DOWN); 271d4df42c4SGerd Hoffmann il->wheel = 0; 272d4df42c4SGerd Hoffmann } 273d4df42c4SGerd Hoffmann break; 274d4df42c4SGerd Hoffmann } 275d4df42c4SGerd Hoffmann } 276d4df42c4SGerd Hoffmann 2772e6a64cbSGerd Hoffmann static void input_linux_event(void *opaque) 278e0d2bd51SGerd Hoffmann { 279e0d2bd51SGerd Hoffmann InputLinux *il = opaque; 280e0d2bd51SGerd Hoffmann int rc; 2811684907cSJavier Celaya int read_size; 2821684907cSJavier Celaya uint8_t *p = (uint8_t *)&il->event; 283e0d2bd51SGerd Hoffmann 284e0d2bd51SGerd Hoffmann for (;;) { 2851684907cSJavier Celaya read_size = sizeof(il->event) - il->read_offset; 2861684907cSJavier Celaya rc = read(il->fd, &p[il->read_offset], read_size); 2871684907cSJavier Celaya if (rc != read_size) { 288e0d2bd51SGerd Hoffmann if (rc < 0 && errno != EAGAIN) { 289e0d2bd51SGerd Hoffmann fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno)); 290e0d2bd51SGerd Hoffmann qemu_set_fd_handler(il->fd, NULL, NULL, NULL); 291e0d2bd51SGerd Hoffmann close(il->fd); 2921684907cSJavier Celaya } else if (rc > 0) { 2931684907cSJavier Celaya il->read_offset += rc; 294e0d2bd51SGerd Hoffmann } 295e0d2bd51SGerd Hoffmann break; 296e0d2bd51SGerd Hoffmann } 2971684907cSJavier Celaya il->read_offset = 0; 298e0d2bd51SGerd Hoffmann 2992e6a64cbSGerd Hoffmann if (il->num_keys) { 3001684907cSJavier Celaya input_linux_handle_keyboard(il, &il->event); 3012e6a64cbSGerd Hoffmann } 302d755defdSPhilippe Voinov if ((il->has_rel_x || il->has_abs_x) && il->num_btns) { 3031684907cSJavier Celaya input_linux_handle_mouse(il, &il->event); 304e0d2bd51SGerd Hoffmann } 305e0d2bd51SGerd Hoffmann } 3062e6a64cbSGerd Hoffmann } 307e0d2bd51SGerd Hoffmann 3080e066b2cSGerd Hoffmann static void input_linux_complete(UserCreatable *uc, Error **errp) 309e0d2bd51SGerd Hoffmann { 3100e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(uc); 3112a57c55fSGerd Hoffmann uint8_t evtmap, relmap, absmap; 3122a57c55fSGerd Hoffmann uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8]; 3132e6a64cbSGerd Hoffmann unsigned int i; 314e0d2bd51SGerd Hoffmann int rc, ver; 315d755defdSPhilippe Voinov struct input_absinfo absinfo; 316e0d2bd51SGerd Hoffmann 317e0d2bd51SGerd Hoffmann if (!il->evdev) { 318e0d2bd51SGerd Hoffmann error_setg(errp, "no input device specified"); 3190e066b2cSGerd Hoffmann return; 320e0d2bd51SGerd Hoffmann } 321e0d2bd51SGerd Hoffmann 322e0d2bd51SGerd Hoffmann il->fd = open(il->evdev, O_RDWR); 323e0d2bd51SGerd Hoffmann if (il->fd < 0) { 324e0d2bd51SGerd Hoffmann error_setg_file_open(errp, errno, il->evdev); 3250e066b2cSGerd Hoffmann return; 326e0d2bd51SGerd Hoffmann } 327e0d2bd51SGerd Hoffmann qemu_set_nonblock(il->fd); 328e0d2bd51SGerd Hoffmann 329e0d2bd51SGerd Hoffmann rc = ioctl(il->fd, EVIOCGVERSION, &ver); 330e0d2bd51SGerd Hoffmann if (rc < 0) { 331e0d2bd51SGerd Hoffmann error_setg(errp, "%s: is not an evdev device", il->evdev); 332e0d2bd51SGerd Hoffmann goto err_close; 333e0d2bd51SGerd Hoffmann } 334e0d2bd51SGerd Hoffmann 335e0d2bd51SGerd Hoffmann rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap); 336ce47d3d4SGerd Hoffmann if (rc < 0) { 337ce47d3d4SGerd Hoffmann error_setg(errp, "%s: failed to read event bits", il->evdev); 338ce47d3d4SGerd Hoffmann goto err_close; 339ce47d3d4SGerd Hoffmann } 340e0d2bd51SGerd Hoffmann 341e0d2bd51SGerd Hoffmann if (evtmap & (1 << EV_REL)) { 342ce47d3d4SGerd Hoffmann relmap = 0; 3432e6a64cbSGerd Hoffmann rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap); 3442e6a64cbSGerd Hoffmann if (relmap & (1 << REL_X)) { 3452e6a64cbSGerd Hoffmann il->has_rel_x = true; 346ce47d3d4SGerd Hoffmann } 347ce47d3d4SGerd Hoffmann } 348ce47d3d4SGerd Hoffmann 349ce47d3d4SGerd Hoffmann if (evtmap & (1 << EV_ABS)) { 350ce47d3d4SGerd Hoffmann absmap = 0; 3512e6a64cbSGerd Hoffmann rc = ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap); 3522e6a64cbSGerd Hoffmann if (absmap & (1 << ABS_X)) { 3532e6a64cbSGerd Hoffmann il->has_abs_x = true; 354d755defdSPhilippe Voinov rc = ioctl(il->fd, EVIOCGABS(ABS_X), &absinfo); 355d755defdSPhilippe Voinov il->abs_x_min = absinfo.minimum; 356d755defdSPhilippe Voinov il->abs_x_max = absinfo.maximum; 357d755defdSPhilippe Voinov rc = ioctl(il->fd, EVIOCGABS(ABS_Y), &absinfo); 358d755defdSPhilippe Voinov il->abs_y_min = absinfo.minimum; 359d755defdSPhilippe Voinov il->abs_y_max = absinfo.maximum; 360ce47d3d4SGerd Hoffmann } 361ce47d3d4SGerd Hoffmann } 362ce47d3d4SGerd Hoffmann 3632e6a64cbSGerd Hoffmann if (evtmap & (1 << EV_KEY)) { 3642e6a64cbSGerd Hoffmann memset(keymap, 0, sizeof(keymap)); 3652e6a64cbSGerd Hoffmann rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap); 3662a57c55fSGerd Hoffmann rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate); 3672e6a64cbSGerd Hoffmann for (i = 0; i < KEY_CNT; i++) { 3682e6a64cbSGerd Hoffmann if (keymap[i / 8] & (1 << (i % 8))) { 3692e6a64cbSGerd Hoffmann if (linux_is_button(i)) { 3702e6a64cbSGerd Hoffmann il->num_btns++; 371e0d2bd51SGerd Hoffmann } else { 3722e6a64cbSGerd Hoffmann il->num_keys++; 373e0d2bd51SGerd Hoffmann } 3742a57c55fSGerd Hoffmann if (keystate[i / 8] & (1 << (i % 8))) { 3752a57c55fSGerd Hoffmann il->keydown[i] = true; 3762a57c55fSGerd Hoffmann il->keycount++; 3772a57c55fSGerd Hoffmann } 3782e6a64cbSGerd Hoffmann } 3792e6a64cbSGerd Hoffmann } 3802e6a64cbSGerd Hoffmann } 3812e6a64cbSGerd Hoffmann 3822e6a64cbSGerd Hoffmann qemu_set_fd_handler(il->fd, input_linux_event, NULL, il); 3832a57c55fSGerd Hoffmann if (il->keycount) { 3842a57c55fSGerd Hoffmann /* delay grab until all keys are released */ 3852a57c55fSGerd Hoffmann il->grab_request = true; 3862a57c55fSGerd Hoffmann } else { 387e0d2bd51SGerd Hoffmann input_linux_toggle_grab(il); 3882a57c55fSGerd Hoffmann } 38946d921beSGerd Hoffmann QTAILQ_INSERT_TAIL(&inputs, il, next); 3900e066b2cSGerd Hoffmann il->initialized = true; 3910e066b2cSGerd Hoffmann return; 392e0d2bd51SGerd Hoffmann 393e0d2bd51SGerd Hoffmann err_close: 394e0d2bd51SGerd Hoffmann close(il->fd); 3950e066b2cSGerd Hoffmann return; 396e0d2bd51SGerd Hoffmann } 397e0d2bd51SGerd Hoffmann 3980e066b2cSGerd Hoffmann static void input_linux_instance_finalize(Object *obj) 399e0d2bd51SGerd Hoffmann { 4000e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4010e066b2cSGerd Hoffmann 4020e066b2cSGerd Hoffmann if (il->initialized) { 4030e066b2cSGerd Hoffmann QTAILQ_REMOVE(&inputs, il, next); 4040e066b2cSGerd Hoffmann close(il->fd); 4050e066b2cSGerd Hoffmann } 4060e066b2cSGerd Hoffmann g_free(il->evdev); 4070e066b2cSGerd Hoffmann } 4080e066b2cSGerd Hoffmann 4090e066b2cSGerd Hoffmann static char *input_linux_get_evdev(Object *obj, Error **errp) 4100e066b2cSGerd Hoffmann { 4110e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4120e066b2cSGerd Hoffmann 4130e066b2cSGerd Hoffmann return g_strdup(il->evdev); 4140e066b2cSGerd Hoffmann } 4150e066b2cSGerd Hoffmann 4160e066b2cSGerd Hoffmann static void input_linux_set_evdev(Object *obj, const char *value, 4170e066b2cSGerd Hoffmann Error **errp) 4180e066b2cSGerd Hoffmann { 4190e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4200e066b2cSGerd Hoffmann 4210e066b2cSGerd Hoffmann if (il->evdev) { 4220e066b2cSGerd Hoffmann error_setg(errp, "evdev property already set"); 4230e066b2cSGerd Hoffmann return; 4240e066b2cSGerd Hoffmann } 4250e066b2cSGerd Hoffmann il->evdev = g_strdup(value); 4260e066b2cSGerd Hoffmann } 4270e066b2cSGerd Hoffmann 4280e066b2cSGerd Hoffmann static bool input_linux_get_grab_all(Object *obj, Error **errp) 4290e066b2cSGerd Hoffmann { 4300e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4310e066b2cSGerd Hoffmann 4320e066b2cSGerd Hoffmann return il->grab_all; 4330e066b2cSGerd Hoffmann } 4340e066b2cSGerd Hoffmann 4350e066b2cSGerd Hoffmann static void input_linux_set_grab_all(Object *obj, bool value, 4360e066b2cSGerd Hoffmann Error **errp) 4370e066b2cSGerd Hoffmann { 4380e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4390e066b2cSGerd Hoffmann 4400e066b2cSGerd Hoffmann il->grab_all = value; 4410e066b2cSGerd Hoffmann } 4420e066b2cSGerd Hoffmann 4430e066b2cSGerd Hoffmann static bool input_linux_get_repeat(Object *obj, Error **errp) 4440e066b2cSGerd Hoffmann { 4450e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4460e066b2cSGerd Hoffmann 4470e066b2cSGerd Hoffmann return il->repeat; 4480e066b2cSGerd Hoffmann } 4490e066b2cSGerd Hoffmann 4500e066b2cSGerd Hoffmann static void input_linux_set_repeat(Object *obj, bool value, 4510e066b2cSGerd Hoffmann Error **errp) 4520e066b2cSGerd Hoffmann { 4530e066b2cSGerd Hoffmann InputLinux *il = INPUT_LINUX(obj); 4540e066b2cSGerd Hoffmann 4550e066b2cSGerd Hoffmann il->repeat = value; 4560e066b2cSGerd Hoffmann } 4570e066b2cSGerd Hoffmann 4582657846fSRyan El Kochta static int input_linux_get_grab_toggle(Object *obj, Error **errp) 4592657846fSRyan El Kochta { 4602657846fSRyan El Kochta InputLinux *il = INPUT_LINUX(obj); 4612657846fSRyan El Kochta 4622657846fSRyan El Kochta return il->grab_toggle; 4632657846fSRyan El Kochta } 4642657846fSRyan El Kochta 4652657846fSRyan El Kochta static void input_linux_set_grab_toggle(Object *obj, int value, 4662657846fSRyan El Kochta Error **errp) 4672657846fSRyan El Kochta { 4682657846fSRyan El Kochta InputLinux *il = INPUT_LINUX(obj); 4692657846fSRyan El Kochta 4702657846fSRyan El Kochta il->grab_toggle = value; 4712657846fSRyan El Kochta } 4722657846fSRyan El Kochta 4730e066b2cSGerd Hoffmann static void input_linux_instance_init(Object *obj) 4740e066b2cSGerd Hoffmann { 4750e066b2cSGerd Hoffmann object_property_add_str(obj, "evdev", 4760e066b2cSGerd Hoffmann input_linux_get_evdev, 4770e066b2cSGerd Hoffmann input_linux_set_evdev, NULL); 4780e066b2cSGerd Hoffmann object_property_add_bool(obj, "grab_all", 4790e066b2cSGerd Hoffmann input_linux_get_grab_all, 4800e066b2cSGerd Hoffmann input_linux_set_grab_all, NULL); 4810e066b2cSGerd Hoffmann object_property_add_bool(obj, "repeat", 4820e066b2cSGerd Hoffmann input_linux_get_repeat, 4830e066b2cSGerd Hoffmann input_linux_set_repeat, NULL); 4842657846fSRyan El Kochta object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys", 4852657846fSRyan El Kochta &GrabToggleKeys_lookup, 4862657846fSRyan El Kochta input_linux_get_grab_toggle, 4872657846fSRyan El Kochta input_linux_set_grab_toggle, NULL); 4880e066b2cSGerd Hoffmann } 4890e066b2cSGerd Hoffmann 4900e066b2cSGerd Hoffmann static void input_linux_class_init(ObjectClass *oc, void *data) 4910e066b2cSGerd Hoffmann { 4920e066b2cSGerd Hoffmann UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 4930e066b2cSGerd Hoffmann 4940e066b2cSGerd Hoffmann ucc->complete = input_linux_complete; 4950e066b2cSGerd Hoffmann } 4960e066b2cSGerd Hoffmann 4970e066b2cSGerd Hoffmann static const TypeInfo input_linux_info = { 4980e066b2cSGerd Hoffmann .name = TYPE_INPUT_LINUX, 4990e066b2cSGerd Hoffmann .parent = TYPE_OBJECT, 5000e066b2cSGerd Hoffmann .class_size = sizeof(InputLinuxClass), 5010e066b2cSGerd Hoffmann .class_init = input_linux_class_init, 5020e066b2cSGerd Hoffmann .instance_size = sizeof(InputLinux), 5030e066b2cSGerd Hoffmann .instance_init = input_linux_instance_init, 5040e066b2cSGerd Hoffmann .instance_finalize = input_linux_instance_finalize, 5050e066b2cSGerd Hoffmann .interfaces = (InterfaceInfo[]) { 5060e066b2cSGerd Hoffmann { TYPE_USER_CREATABLE }, 5070e066b2cSGerd Hoffmann { } 5080e066b2cSGerd Hoffmann } 509e0d2bd51SGerd Hoffmann }; 510e0d2bd51SGerd Hoffmann 5110e066b2cSGerd Hoffmann static void register_types(void) 512e0d2bd51SGerd Hoffmann { 5130e066b2cSGerd Hoffmann type_register_static(&input_linux_info); 514e0d2bd51SGerd Hoffmann } 5150e066b2cSGerd Hoffmann 5160e066b2cSGerd Hoffmann type_init(register_types); 517