blob: e3fa799c34fb843c5c14fcea3e6361cd608cf7f9 [file] [log] [blame]
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +01001/*
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"
Markus Armbrusterda34e652016-03-14 09:01:28 +01008#include "qapi/error.h"
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +01009#include "qemu/config-file.h"
Markus Armbrusterdb725812019-08-12 07:23:50 +020010#include "qemu/main-loop.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020011#include "qemu/module.h"
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010012#include "qemu/sockets.h"
13#include "sysemu/sysemu.h"
14#include "ui/input.h"
Gerd Hoffmann0e066b22016-03-11 08:38:20 +010015#include "qom/object_interfaces.h"
Ryan El Kochta26578462019-01-23 16:45:55 -050016#include "sysemu/iothread.h"
17#include "block/aio.h"
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010018
19#include <sys/ioctl.h>
20#include "standard-headers/linux/input.h"
21
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +020022static 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
Gerd Hoffmann0e066b22016-03-11 08:38:20 +010033#define TYPE_INPUT_LINUX "input-linux"
34#define INPUT_LINUX(obj) \
35 OBJECT_CHECK(InputLinux, (obj), TYPE_INPUT_LINUX)
36#define INPUT_LINUX_GET_CLASS(obj) \
37 OBJECT_GET_CLASS(InputLinuxClass, (obj), TYPE_INPUT_LINUX)
38#define INPUT_LINUX_CLASS(klass) \
39 OBJECT_CLASS_CHECK(InputLinuxClass, (klass), TYPE_INPUT_LINUX)
40
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010041typedef struct InputLinux InputLinux;
Gerd Hoffmann0e066b22016-03-11 08:38:20 +010042typedef struct InputLinuxClass InputLinuxClass;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010043
44struct InputLinux {
Gerd Hoffmann0e066b22016-03-11 08:38:20 +010045 Object parent;
46
47 char *evdev;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010048 int fd;
Gerd Hoffmanna6ccabd2016-03-04 11:25:16 +010049 bool repeat;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010050 bool grab_request;
51 bool grab_active;
Gerd Hoffmann46d921b2016-03-04 11:25:15 +010052 bool grab_all;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010053 bool keydown[KEY_CNT];
54 int keycount;
55 int wheel;
Gerd Hoffmann0e066b22016-03-11 08:38:20 +010056 bool initialized;
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +020057
58 bool has_rel_x;
59 bool has_abs_x;
60 int num_keys;
61 int num_btns;
Philippe Voinovd755def2017-05-05 15:42:31 +020062 int abs_x_min;
63 int abs_x_max;
64 int abs_y_min;
65 int abs_y_max;
Javier Celaya16849072017-03-27 20:26:24 +020066 struct input_event event;
67 int read_offset;
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +020068
Ryan El Kochta26578462019-01-23 16:45:55 -050069 enum GrabToggleKeys grab_toggle;
70
Gerd Hoffmann46d921b2016-03-04 11:25:15 +010071 QTAILQ_ENTRY(InputLinux) next;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010072};
73
Gerd Hoffmann0e066b22016-03-11 08:38:20 +010074struct InputLinuxClass {
75 ObjectClass parent_class;
76};
77
Gerd Hoffmann46d921b2016-03-04 11:25:15 +010078static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs);
79
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010080static void input_linux_toggle_grab(InputLinux *il)
81{
82 intptr_t request = !il->grab_active;
Gerd Hoffmann46d921b2016-03-04 11:25:15 +010083 InputLinux *item;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +010084 int rc;
85
86 rc = ioctl(il->fd, EVIOCGRAB, request);
87 if (rc < 0) {
88 return;
89 }
90 il->grab_active = !il->grab_active;
Gerd Hoffmann46d921b2016-03-04 11:25:15 +010091
92 if (!il->grab_all) {
93 return;
94 }
95 QTAILQ_FOREACH(item, &inputs, next) {
96 if (item == il || item->grab_all) {
97 /* avoid endless loops */
98 continue;
99 }
100 if (item->grab_active != il->grab_active) {
101 input_linux_toggle_grab(item);
102 }
103 }
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100104}
105
Ryan El Kochta26578462019-01-23 16:45:55 -0500106static bool input_linux_check_toggle(InputLinux *il)
107{
108 switch (il->grab_toggle) {
109 case GRAB_TOGGLE_KEYS_CTRL_CTRL:
110 return il->keydown[KEY_LEFTCTRL] &&
111 il->keydown[KEY_RIGHTCTRL];
112
113 case GRAB_TOGGLE_KEYS_ALT_ALT:
114 return il->keydown[KEY_LEFTALT] &&
115 il->keydown[KEY_RIGHTALT];
116
117 case GRAB_TOGGLE_KEYS_META_META:
118 return il->keydown[KEY_LEFTMETA] &&
119 il->keydown[KEY_RIGHTMETA];
120
121 case GRAB_TOGGLE_KEYS_SCROLLLOCK:
122 return il->keydown[KEY_SCROLLLOCK];
123
124 case GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK:
125 return (il->keydown[KEY_LEFTCTRL] ||
126 il->keydown[KEY_RIGHTCTRL]) &&
127 il->keydown[KEY_SCROLLLOCK];
128
129 case GRAB_TOGGLE_KEYS__MAX:
130 /* avoid gcc error */
131 break;
132 }
133 return false;
134}
135
136static bool input_linux_should_skip(InputLinux *il,
137 struct input_event *event)
138{
139 return (il->grab_toggle == GRAB_TOGGLE_KEYS_SCROLLLOCK ||
140 il->grab_toggle == GRAB_TOGGLE_KEYS_CTRL_SCROLLLOCK) &&
141 event->code == KEY_SCROLLLOCK;
142}
143
Gerd Hoffmann2330e9e2016-06-16 11:03:19 +0200144static void input_linux_handle_keyboard(InputLinux *il,
145 struct input_event *event)
146{
147 if (event->type == EV_KEY) {
148 if (event->value > 2 || (event->value > 1 && !il->repeat)) {
149 /*
150 * ignore autorepeat + unknown key events
151 * 0 == up, 1 == down, 2 == autorepeat, other == undefined
152 */
153 return;
154 }
155 if (event->code >= KEY_CNT) {
156 /*
157 * Should not happen. But better safe than sorry,
158 * and we make Coverity happy too.
159 */
160 return;
161 }
162
163 /* keep track of key state */
164 if (!il->keydown[event->code] && event->value) {
165 il->keydown[event->code] = true;
166 il->keycount++;
167 }
168 if (il->keydown[event->code] && !event->value) {
169 il->keydown[event->code] = false;
170 il->keycount--;
171 }
172
173 /* send event to guest when grab is active */
Ryan El Kochta26578462019-01-23 16:45:55 -0500174 if (il->grab_active && !input_linux_should_skip(il, event)) {
Gerd Hoffmann2330e9e2016-06-16 11:03:19 +0200175 int qcode = qemu_input_linux_to_qcode(event->code);
176 qemu_input_event_send_key_qcode(NULL, qcode, event->value);
177 }
178
179 /* hotkey -> record switch request ... */
Ryan El Kochta26578462019-01-23 16:45:55 -0500180 if (input_linux_check_toggle(il)) {
Gerd Hoffmann2330e9e2016-06-16 11:03:19 +0200181 il->grab_request = true;
182 }
183
184 /*
185 * ... and do the switch when all keys are lifted, so we
186 * confuse neither guest nor host with keys which seem to
187 * be stuck due to missing key-up events.
188 */
189 if (il->grab_request && !il->keycount) {
190 il->grab_request = false;
191 input_linux_toggle_grab(il);
192 }
193 }
194}
195
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100196static void input_linux_event_mouse_button(int button)
197{
198 qemu_input_queue_btn(NULL, button, true);
199 qemu_input_event_sync();
200 qemu_input_queue_btn(NULL, button, false);
201 qemu_input_event_sync();
202}
203
Gerd Hoffmannd4df42c2016-06-16 11:03:18 +0200204static void input_linux_handle_mouse(InputLinux *il, struct input_event *event)
205{
206 if (!il->grab_active) {
207 return;
208 }
209
210 switch (event->type) {
211 case EV_KEY:
212 switch (event->code) {
213 case BTN_LEFT:
214 qemu_input_queue_btn(NULL, INPUT_BUTTON_LEFT, event->value);
215 break;
216 case BTN_RIGHT:
217 qemu_input_queue_btn(NULL, INPUT_BUTTON_RIGHT, event->value);
218 break;
219 case BTN_MIDDLE:
220 qemu_input_queue_btn(NULL, INPUT_BUTTON_MIDDLE, event->value);
221 break;
222 case BTN_GEAR_UP:
223 qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_UP, event->value);
224 break;
225 case BTN_GEAR_DOWN:
226 qemu_input_queue_btn(NULL, INPUT_BUTTON_WHEEL_DOWN,
227 event->value);
228 break;
Fabian Lesniak1266b682016-12-06 20:00:07 +0100229 case BTN_SIDE:
230 qemu_input_queue_btn(NULL, INPUT_BUTTON_SIDE, event->value);
231 break;
232 case BTN_EXTRA:
233 qemu_input_queue_btn(NULL, INPUT_BUTTON_EXTRA, event->value);
234 break;
Gerd Hoffmannd4df42c2016-06-16 11:03:18 +0200235 };
236 break;
237 case EV_REL:
238 switch (event->code) {
239 case REL_X:
240 qemu_input_queue_rel(NULL, INPUT_AXIS_X, event->value);
241 break;
242 case REL_Y:
243 qemu_input_queue_rel(NULL, INPUT_AXIS_Y, event->value);
244 break;
245 case REL_WHEEL:
246 il->wheel = event->value;
247 break;
248 }
249 break;
Philippe Voinovd755def2017-05-05 15:42:31 +0200250 case EV_ABS:
251 switch (event->code) {
252 case ABS_X:
253 qemu_input_queue_abs(NULL, INPUT_AXIS_X, event->value,
254 il->abs_x_min, il->abs_x_max);
255 break;
256 case ABS_Y:
257 qemu_input_queue_abs(NULL, INPUT_AXIS_Y, event->value,
258 il->abs_y_min, il->abs_y_max);
259 break;
260 }
261 break;
Gerd Hoffmannd4df42c2016-06-16 11:03:18 +0200262 case EV_SYN:
263 qemu_input_event_sync();
264 if (il->wheel != 0) {
265 input_linux_event_mouse_button((il->wheel > 0)
266 ? INPUT_BUTTON_WHEEL_UP
267 : INPUT_BUTTON_WHEEL_DOWN);
268 il->wheel = 0;
269 }
270 break;
271 }
272}
273
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200274static void input_linux_event(void *opaque)
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100275{
276 InputLinux *il = opaque;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100277 int rc;
Javier Celaya16849072017-03-27 20:26:24 +0200278 int read_size;
279 uint8_t *p = (uint8_t *)&il->event;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100280
281 for (;;) {
Javier Celaya16849072017-03-27 20:26:24 +0200282 read_size = sizeof(il->event) - il->read_offset;
283 rc = read(il->fd, &p[il->read_offset], read_size);
284 if (rc != read_size) {
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100285 if (rc < 0 && errno != EAGAIN) {
286 fprintf(stderr, "%s: read: %s\n", __func__, strerror(errno));
287 qemu_set_fd_handler(il->fd, NULL, NULL, NULL);
288 close(il->fd);
Javier Celaya16849072017-03-27 20:26:24 +0200289 } else if (rc > 0) {
290 il->read_offset += rc;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100291 }
292 break;
293 }
Javier Celaya16849072017-03-27 20:26:24 +0200294 il->read_offset = 0;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100295
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200296 if (il->num_keys) {
Javier Celaya16849072017-03-27 20:26:24 +0200297 input_linux_handle_keyboard(il, &il->event);
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200298 }
Philippe Voinovd755def2017-05-05 15:42:31 +0200299 if ((il->has_rel_x || il->has_abs_x) && il->num_btns) {
Javier Celaya16849072017-03-27 20:26:24 +0200300 input_linux_handle_mouse(il, &il->event);
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200301 }
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100302 }
303}
304
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100305static void input_linux_complete(UserCreatable *uc, Error **errp)
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100306{
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100307 InputLinux *il = INPUT_LINUX(uc);
Gerd Hoffmann2a57c552016-10-12 15:03:04 +0200308 uint8_t evtmap, relmap, absmap;
309 uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8];
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200310 unsigned int i;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100311 int rc, ver;
Philippe Voinovd755def2017-05-05 15:42:31 +0200312 struct input_absinfo absinfo;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100313
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100314 if (!il->evdev) {
315 error_setg(errp, "no input device specified");
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100316 return;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100317 }
318
319 il->fd = open(il->evdev, O_RDWR);
320 if (il->fd < 0) {
321 error_setg_file_open(errp, errno, il->evdev);
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100322 return;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100323 }
324 qemu_set_nonblock(il->fd);
325
326 rc = ioctl(il->fd, EVIOCGVERSION, &ver);
327 if (rc < 0) {
328 error_setg(errp, "%s: is not an evdev device", il->evdev);
329 goto err_close;
330 }
331
332 rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap);
Gerd Hoffmannce47d3d2016-04-12 11:21:43 +0200333 if (rc < 0) {
334 error_setg(errp, "%s: failed to read event bits", il->evdev);
335 goto err_close;
336 }
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100337
338 if (evtmap & (1 << EV_REL)) {
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200339 relmap = 0;
Gerd Hoffmannce47d3d2016-04-12 11:21:43 +0200340 rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap);
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200341 if (relmap & (1 << REL_X)) {
342 il->has_rel_x = true;
Gerd Hoffmannce47d3d2016-04-12 11:21:43 +0200343 }
344 }
345
346 if (evtmap & (1 << EV_ABS)) {
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200347 absmap = 0;
348 rc = ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap);
349 if (absmap & (1 << ABS_X)) {
350 il->has_abs_x = true;
Philippe Voinovd755def2017-05-05 15:42:31 +0200351 rc = ioctl(il->fd, EVIOCGABS(ABS_X), &absinfo);
352 il->abs_x_min = absinfo.minimum;
353 il->abs_x_max = absinfo.maximum;
354 rc = ioctl(il->fd, EVIOCGABS(ABS_Y), &absinfo);
355 il->abs_y_min = absinfo.minimum;
356 il->abs_y_max = absinfo.maximum;
Gerd Hoffmannce47d3d2016-04-12 11:21:43 +0200357 }
358 }
359
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200360 if (evtmap & (1 << EV_KEY)) {
361 memset(keymap, 0, sizeof(keymap));
362 rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap);
Gerd Hoffmann2a57c552016-10-12 15:03:04 +0200363 rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate);
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200364 for (i = 0; i < KEY_CNT; i++) {
365 if (keymap[i / 8] & (1 << (i % 8))) {
366 if (linux_is_button(i)) {
367 il->num_btns++;
368 } else {
369 il->num_keys++;
370 }
Gerd Hoffmann2a57c552016-10-12 15:03:04 +0200371 if (keystate[i / 8] & (1 << (i % 8))) {
372 il->keydown[i] = true;
373 il->keycount++;
374 }
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200375 }
376 }
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100377 }
Gerd Hoffmann2e6a64c2016-06-16 11:03:20 +0200378
379 qemu_set_fd_handler(il->fd, input_linux_event, NULL, il);
Gerd Hoffmann2a57c552016-10-12 15:03:04 +0200380 if (il->keycount) {
381 /* delay grab until all keys are released */
382 il->grab_request = true;
383 } else {
384 input_linux_toggle_grab(il);
385 }
Gerd Hoffmann46d921b2016-03-04 11:25:15 +0100386 QTAILQ_INSERT_TAIL(&inputs, il, next);
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100387 il->initialized = true;
388 return;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100389
390err_close:
391 close(il->fd);
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100392 return;
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100393}
394
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100395static void input_linux_instance_finalize(Object *obj)
396{
397 InputLinux *il = INPUT_LINUX(obj);
398
399 if (il->initialized) {
400 QTAILQ_REMOVE(&inputs, il, next);
401 close(il->fd);
402 }
403 g_free(il->evdev);
404}
405
406static char *input_linux_get_evdev(Object *obj, Error **errp)
407{
408 InputLinux *il = INPUT_LINUX(obj);
409
410 return g_strdup(il->evdev);
411}
412
413static void input_linux_set_evdev(Object *obj, const char *value,
414 Error **errp)
415{
416 InputLinux *il = INPUT_LINUX(obj);
417
418 if (il->evdev) {
419 error_setg(errp, "evdev property already set");
420 return;
421 }
422 il->evdev = g_strdup(value);
423}
424
425static bool input_linux_get_grab_all(Object *obj, Error **errp)
426{
427 InputLinux *il = INPUT_LINUX(obj);
428
429 return il->grab_all;
430}
431
432static void input_linux_set_grab_all(Object *obj, bool value,
433 Error **errp)
434{
435 InputLinux *il = INPUT_LINUX(obj);
436
437 il->grab_all = value;
438}
439
440static bool input_linux_get_repeat(Object *obj, Error **errp)
441{
442 InputLinux *il = INPUT_LINUX(obj);
443
444 return il->repeat;
445}
446
447static void input_linux_set_repeat(Object *obj, bool value,
448 Error **errp)
449{
450 InputLinux *il = INPUT_LINUX(obj);
451
452 il->repeat = value;
453}
454
Ryan El Kochta26578462019-01-23 16:45:55 -0500455static int input_linux_get_grab_toggle(Object *obj, Error **errp)
456{
457 InputLinux *il = INPUT_LINUX(obj);
458
459 return il->grab_toggle;
460}
461
462static void input_linux_set_grab_toggle(Object *obj, int value,
463 Error **errp)
464{
465 InputLinux *il = INPUT_LINUX(obj);
466
467 il->grab_toggle = value;
468}
469
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100470static void input_linux_instance_init(Object *obj)
471{
472 object_property_add_str(obj, "evdev",
473 input_linux_get_evdev,
474 input_linux_set_evdev, NULL);
475 object_property_add_bool(obj, "grab_all",
476 input_linux_get_grab_all,
477 input_linux_set_grab_all, NULL);
478 object_property_add_bool(obj, "repeat",
479 input_linux_get_repeat,
480 input_linux_set_repeat, NULL);
Ryan El Kochta26578462019-01-23 16:45:55 -0500481 object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys",
482 &GrabToggleKeys_lookup,
483 input_linux_get_grab_toggle,
484 input_linux_set_grab_toggle, NULL);
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100485}
486
487static void input_linux_class_init(ObjectClass *oc, void *data)
488{
489 UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
490
491 ucc->complete = input_linux_complete;
492}
493
494static const TypeInfo input_linux_info = {
495 .name = TYPE_INPUT_LINUX,
496 .parent = TYPE_OBJECT,
497 .class_size = sizeof(InputLinuxClass),
498 .class_init = input_linux_class_init,
499 .instance_size = sizeof(InputLinux),
500 .instance_init = input_linux_instance_init,
501 .instance_finalize = input_linux_instance_finalize,
502 .interfaces = (InterfaceInfo[]) {
503 { TYPE_USER_CREATABLE },
504 { }
505 }
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100506};
507
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100508static void register_types(void)
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100509{
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100510 type_register_static(&input_linux_info);
Gerd Hoffmanne0d2bd52016-03-04 11:25:14 +0100511}
Gerd Hoffmann0e066b22016-03-11 08:38:20 +0100512
513type_init(register_types);