]> git.proxmox.com Git - mirror_qemu.git/blame - ui/input-linux.c
Include qemu/main-loop.h less
[mirror_qemu.git] / ui / input-linux.c
CommitLineData
e0d2bd51
GH
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"
da34e65c 8#include "qapi/error.h"
e0d2bd51 9#include "qemu/config-file.h"
db725815 10#include "qemu/main-loop.h"
0b8fa32f 11#include "qemu/module.h"
e0d2bd51
GH
12#include "qemu/sockets.h"
13#include "sysemu/sysemu.h"
14#include "ui/input.h"
0e066b2c 15#include "qom/object_interfaces.h"
2657846f
REK
16#include "sysemu/iothread.h"
17#include "block/aio.h"
e0d2bd51
GH
18
19#include <sys/ioctl.h>
20#include "standard-headers/linux/input.h"
21
2e6a64cb
GH
22static 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
0e066b2c
GH
33#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
e0d2bd51 41typedef struct InputLinux InputLinux;
0e066b2c 42typedef struct InputLinuxClass InputLinuxClass;
e0d2bd51
GH
43
44struct InputLinux {
0e066b2c
GH
45 Object parent;
46
47 char *evdev;
e0d2bd51 48 int fd;
a6ccabd6 49 bool repeat;
e0d2bd51
GH
50 bool grab_request;
51 bool grab_active;
46d921be 52 bool grab_all;
e0d2bd51
GH
53 bool keydown[KEY_CNT];
54 int keycount;
55 int wheel;
0e066b2c 56 bool initialized;
2e6a64cb
GH
57
58 bool has_rel_x;
59 bool has_abs_x;
60 int num_keys;
61 int num_btns;
d755defd
PV
62 int abs_x_min;
63 int abs_x_max;
64 int abs_y_min;
65 int abs_y_max;
1684907c
JC
66 struct input_event event;
67 int read_offset;
2e6a64cb 68
2657846f
REK
69 enum GrabToggleKeys grab_toggle;
70
46d921be 71 QTAILQ_ENTRY(InputLinux) next;
e0d2bd51
GH
72};
73
0e066b2c
GH
74struct InputLinuxClass {
75 ObjectClass parent_class;
76};
77
46d921be
GH
78static QTAILQ_HEAD(, InputLinux) inputs = QTAILQ_HEAD_INITIALIZER(inputs);
79
e0d2bd51
GH
80static void input_linux_toggle_grab(InputLinux *il)
81{
82 intptr_t request = !il->grab_active;
46d921be 83 InputLinux *item;
e0d2bd51
GH
84 int rc;
85
86 rc = ioctl(il->fd, EVIOCGRAB, request);
87 if (rc < 0) {
88 return;
89 }
90 il->grab_active = !il->grab_active;
46d921be
GH
91
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 }
e0d2bd51
GH
104}
105
2657846f
REK
106static 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
2330e9e7
GH
144static 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 */
2657846f 174 if (il->grab_active && !input_linux_should_skip(il, event)) {
2330e9e7
GH
175 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 ... */
2657846f 180 if (input_linux_check_toggle(il)) {
2330e9e7
GH
181 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
e0d2bd51
GH
196static 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
d4df42c4
GH
204static 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;
1266b68c
FL
229 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;
d4df42c4
GH
235 };
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;
d755defd
PV
250 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;
d4df42c4
GH
262 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
2e6a64cb 274static void input_linux_event(void *opaque)
e0d2bd51
GH
275{
276 InputLinux *il = opaque;
e0d2bd51 277 int rc;
1684907c
JC
278 int read_size;
279 uint8_t *p = (uint8_t *)&il->event;
e0d2bd51
GH
280
281 for (;;) {
1684907c
JC
282 read_size = sizeof(il->event) - il->read_offset;
283 rc = read(il->fd, &p[il->read_offset], read_size);
284 if (rc != read_size) {
e0d2bd51
GH
285 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);
1684907c
JC
289 } else if (rc > 0) {
290 il->read_offset += rc;
e0d2bd51
GH
291 }
292 break;
293 }
1684907c 294 il->read_offset = 0;
e0d2bd51 295
2e6a64cb 296 if (il->num_keys) {
1684907c 297 input_linux_handle_keyboard(il, &il->event);
2e6a64cb 298 }
d755defd 299 if ((il->has_rel_x || il->has_abs_x) && il->num_btns) {
1684907c 300 input_linux_handle_mouse(il, &il->event);
2e6a64cb 301 }
e0d2bd51
GH
302 }
303}
304
0e066b2c 305static void input_linux_complete(UserCreatable *uc, Error **errp)
e0d2bd51 306{
0e066b2c 307 InputLinux *il = INPUT_LINUX(uc);
2a57c55f
GH
308 uint8_t evtmap, relmap, absmap;
309 uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8];
2e6a64cb 310 unsigned int i;
e0d2bd51 311 int rc, ver;
d755defd 312 struct input_absinfo absinfo;
e0d2bd51 313
e0d2bd51
GH
314 if (!il->evdev) {
315 error_setg(errp, "no input device specified");
0e066b2c 316 return;
e0d2bd51
GH
317 }
318
319 il->fd = open(il->evdev, O_RDWR);
320 if (il->fd < 0) {
321 error_setg_file_open(errp, errno, il->evdev);
0e066b2c 322 return;
e0d2bd51
GH
323 }
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);
ce47d3d4
GH
333 if (rc < 0) {
334 error_setg(errp, "%s: failed to read event bits", il->evdev);
335 goto err_close;
336 }
e0d2bd51
GH
337
338 if (evtmap & (1 << EV_REL)) {
2e6a64cb 339 relmap = 0;
ce47d3d4 340 rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap);
2e6a64cb
GH
341 if (relmap & (1 << REL_X)) {
342 il->has_rel_x = true;
ce47d3d4
GH
343 }
344 }
345
346 if (evtmap & (1 << EV_ABS)) {
2e6a64cb
GH
347 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;
d755defd
PV
351 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;
ce47d3d4
GH
357 }
358 }
359
2e6a64cb
GH
360 if (evtmap & (1 << EV_KEY)) {
361 memset(keymap, 0, sizeof(keymap));
362 rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap);
2a57c55f 363 rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate);
2e6a64cb
GH
364 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 }
2a57c55f
GH
371 if (keystate[i / 8] & (1 << (i % 8))) {
372 il->keydown[i] = true;
373 il->keycount++;
374 }
2e6a64cb
GH
375 }
376 }
e0d2bd51 377 }
2e6a64cb
GH
378
379 qemu_set_fd_handler(il->fd, input_linux_event, NULL, il);
2a57c55f
GH
380 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 }
46d921be 386 QTAILQ_INSERT_TAIL(&inputs, il, next);
0e066b2c
GH
387 il->initialized = true;
388 return;
e0d2bd51
GH
389
390err_close:
391 close(il->fd);
0e066b2c
GH
392 return;
393}
394
395static 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);
e0d2bd51
GH
404}
405
0e066b2c
GH
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
2657846f
REK
455static 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
0e066b2c
GH
470static 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);
2657846f
REK
481 object_property_add_enum(obj, "grab-toggle", "GrabToggleKeys",
482 &GrabToggleKeys_lookup,
483 input_linux_get_grab_toggle,
484 input_linux_set_grab_toggle, NULL);
0e066b2c
GH
485}
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 }
e0d2bd51
GH
506};
507
0e066b2c 508static void register_types(void)
e0d2bd51 509{
0e066b2c 510 type_register_static(&input_linux_info);
e0d2bd51 511}
0e066b2c
GH
512
513type_init(register_types);