qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

input-linux.c (15029B)


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