master
c 716 lines 18.7 KB
Raw
1 #include "qemu/osdep.h"
2 #include "system/system.h"
3 #include "qapi/error.h"
4 #include "qapi/qapi-commands-ui.h"
5 #include "trace.h"
6 #include "ui/input.h"
7 #include "ui/console.h"
8 #include "system/replay.h"
9 #include "system/runstate.h"
10
11 struct QemuInputHandlerState {
12 DeviceState *dev;
13 const QemuInputHandler *handler;
14 int id;
15 int events;
16 QemuConsole *con;
17 uint32_t leds_mask;
18 QTAILQ_ENTRY(QemuInputHandlerState) node;
19 };
20
21 typedef struct QemuInputEventQueue QemuInputEventQueue;
22 typedef QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue)
23 QemuInputEventQueueHead;
24
25 struct QemuInputEventQueue {
26 enum {
27 QEMU_INPUT_QUEUE_DELAY = 1,
28 QEMU_INPUT_QUEUE_EVENT,
29 QEMU_INPUT_QUEUE_SYNC,
30 } type;
31 QEMUTimer *timer;
32 uint32_t delay_ms;
33 QemuConsole *src;
34 QemuInputEvent evt;
35 QTAILQ_ENTRY(QemuInputEventQueue) node;
36 };
37
38 static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
39 QTAILQ_HEAD_INITIALIZER(handlers);
40 static NotifierList mouse_mode_notifiers =
41 NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
42 static NotifierList leds_notifiers =
43 NOTIFIER_LIST_INITIALIZER(leds_notifiers);
44
45 static QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
46 static QEMUTimer *kbd_timer;
47 static uint32_t kbd_default_delay_ms = 10;
48 static uint32_t queue_count;
49 static uint32_t queue_limit = 1024;
50
51 static void notify_input_changed(uint32_t mask)
52 {
53 notifier_list_notify(&mouse_mode_notifiers, NULL);
54 if (mask & INPUT_EVENT_MASK_KEY) {
55 notifier_list_notify(&leds_notifiers, NULL);
56 }
57 }
58
59 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
60 const QemuInputHandler *handler)
61 {
62 QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
63 static int id = 1;
64
65 s->dev = dev;
66 s->handler = handler;
67 s->id = id++;
68 QTAILQ_INSERT_TAIL(&handlers, s, node);
69 notify_input_changed(handler->mask);
70
71 return s;
72 }
73
74 void qemu_input_handler_activate(QemuInputHandlerState *s)
75 {
76 QTAILQ_REMOVE(&handlers, s, node);
77 QTAILQ_INSERT_HEAD(&handlers, s, node);
78 notify_input_changed(s->handler->mask);
79 }
80
81 void qemu_input_handler_deactivate(QemuInputHandlerState *s)
82 {
83 QTAILQ_REMOVE(&handlers, s, node);
84 QTAILQ_INSERT_TAIL(&handlers, s, node);
85 notify_input_changed(s->handler->mask);
86 }
87
88 void qemu_input_handler_unregister(QemuInputHandlerState *s)
89 {
90 uint32_t mask = s->handler->mask;
91
92 QTAILQ_REMOVE(&handlers, s, node);
93 g_free(s);
94 notify_input_changed(mask);
95 }
96
97 void qemu_input_handler_bind(QemuInputHandlerState *s,
98 const char *device_id, int head,
99 Error **errp)
100 {
101 QemuConsole *con;
102 Error *err = NULL;
103
104 con = qemu_console_lookup_by_device_name(device_id, head, &err);
105 if (err) {
106 error_propagate(errp, err);
107 return;
108 }
109
110 s->con = con;
111 }
112
113 static QemuInputHandlerState*
114 qemu_input_find_handler(uint32_t mask, const QemuConsole *con)
115 {
116 QemuInputHandlerState *s;
117
118 QTAILQ_FOREACH(s, &handlers, node) {
119 if (s->con == NULL || s->con != con) {
120 continue;
121 }
122 if (mask & s->handler->mask) {
123 return s;
124 }
125 }
126
127 QTAILQ_FOREACH(s, &handlers, node) {
128 if (s->con != NULL) {
129 continue;
130 }
131 if (mask & s->handler->mask) {
132 return s;
133 }
134 }
135 return NULL;
136 }
137
138 void qemu_input_handler_set_leds_mask(QemuInputHandlerState *s, uint32_t leds_mask)
139 {
140 assert(s->handler->mask & INPUT_EVENT_MASK_KEY);
141 s->leds_mask = leds_mask;
142 notifier_list_notify(&leds_notifiers, NULL);
143 }
144
145 void qemu_input_led_notifier_add(Notifier *n)
146 {
147 notifier_list_add(&leds_notifiers, n);
148 }
149
150 void qemu_input_led_notifier_remove(Notifier *n)
151 {
152 notifier_remove(n);
153 }
154
155 void qmp_input_send_event(const char *device,
156 bool has_head, int64_t head,
157 InputEventList *events, Error **errp)
158 {
159 InputEventList *e;
160 QemuConsole *con;
161 Error *err = NULL;
162
163 con = NULL;
164 if (device) {
165 if (!has_head) {
166 head = 0;
167 }
168 con = qemu_console_lookup_by_device_name(device, head, &err);
169 if (err) {
170 error_propagate(errp, err);
171 return;
172 }
173 }
174
175 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
176 error_setg(errp, "VM not running");
177 return;
178 }
179
180 for (e = events; e != NULL; e = e->next) {
181 InputEvent *event = e->value;
182
183 if (!qemu_input_find_handler(1 << event->type, con)) {
184 error_setg(errp, "Input handler not found for "
185 "event type %s",
186 InputEventKind_str(event->type));
187 return;
188 }
189 }
190
191 for (e = events; e != NULL; e = e->next) {
192 InputEvent *qapi = e->value;
193 QemuInputEvent evt;
194
195 evt.type = qapi->type;
196
197 switch (qapi->type) {
198 case INPUT_EVENT_KIND_KEY:
199 evt.key.key = qemu_input_key_value_to_linux(qapi->u.key.data->key);
200 evt.key.down = qapi->u.key.data->down;
201 break;
202
203 case INPUT_EVENT_KIND_BTN:
204 evt.btn = *qapi->u.btn.data;
205 break;
206
207 case INPUT_EVENT_KIND_REL:
208 evt.rel = *qapi->u.rel.data;
209 break;
210
211 case INPUT_EVENT_KIND_ABS:
212 evt.abs = *qapi->u.abs.data;
213 break;
214
215 case INPUT_EVENT_KIND_MTT:
216 evt.mtt = *qapi->u.mtt.data;
217 break;
218
219 default:
220 g_assert_not_reached();
221 }
222
223 qemu_input_event_send(con, &evt);
224 }
225
226 qemu_input_event_sync();
227 }
228
229 static void qemu_input_event_trace(QemuConsole *src, QemuInputEvent *evt)
230 {
231 const char *name;
232 int idx = -1;
233 QemuInputKeyEvent *key;
234 InputBtnEvent *btn;
235 InputMoveEvent *move;
236 InputMultiTouchEvent *mtt;
237
238 if (src) {
239 idx = qemu_console_get_index(src);
240 }
241 switch (evt->type) {
242 case INPUT_EVENT_KIND_KEY:
243 key = &evt->key;
244 name = QKeyCode_str(qemu_input_linux_to_qcode(key->key));
245 trace_input_event_key_qcode(idx, name, key->down);
246 break;
247 case INPUT_EVENT_KIND_BTN:
248 btn = &evt->btn;
249 name = btn->button < INPUT_BUTTON__MAX ? InputButton_str(btn->button) : "invalid";
250 trace_input_event_btn(idx, name, btn->down);
251 break;
252 case INPUT_EVENT_KIND_REL:
253 move = &evt->rel;
254 name = move->axis < INPUT_AXIS__MAX ? InputAxis_str(move->axis) : "invalid";
255 trace_input_event_rel(idx, name, move->value);
256 break;
257 case INPUT_EVENT_KIND_ABS:
258 move = &evt->abs;
259 name = move->axis < INPUT_AXIS__MAX ? InputAxis_str(move->axis) : "invalid";
260 trace_input_event_abs(idx, name, move->value);
261 break;
262 case INPUT_EVENT_KIND_MTT:
263 mtt = &evt->mtt;
264 name = mtt->axis < INPUT_AXIS__MAX ? InputAxis_str(mtt->axis) : "invalid";
265 trace_input_event_mtt(idx, name, mtt->value);
266 break;
267 case INPUT_EVENT_KIND__MAX:
268 /* keep gcc happy */
269 break;
270 }
271 }
272
273 static void qemu_input_queue_process(void *opaque)
274 {
275 QemuInputEventQueueHead *queue = opaque;
276 QemuInputEventQueue *item;
277
278 g_assert(!QTAILQ_EMPTY(queue));
279 item = QTAILQ_FIRST(queue);
280 g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
281 QTAILQ_REMOVE(queue, item, node);
282 queue_count--;
283 g_free(item);
284
285 while (!QTAILQ_EMPTY(queue)) {
286 item = QTAILQ_FIRST(queue);
287 switch (item->type) {
288 case QEMU_INPUT_QUEUE_DELAY:
289 timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
290 + item->delay_ms);
291 return;
292 case QEMU_INPUT_QUEUE_EVENT:
293 qemu_input_event_send(item->src, &item->evt);
294 break;
295 case QEMU_INPUT_QUEUE_SYNC:
296 qemu_input_event_sync();
297 break;
298 }
299 QTAILQ_REMOVE(queue, item, node);
300 queue_count--;
301 g_free(item);
302 }
303 }
304
305 static void qemu_input_queue_delay(QemuInputEventQueueHead *queue,
306 QEMUTimer *timer, uint32_t delay_ms)
307 {
308 QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
309 bool start_timer = QTAILQ_EMPTY(queue);
310
311 item->type = QEMU_INPUT_QUEUE_DELAY;
312 item->delay_ms = delay_ms;
313 item->timer = timer;
314 QTAILQ_INSERT_TAIL(queue, item, node);
315 queue_count++;
316
317 if (start_timer) {
318 timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
319 + item->delay_ms);
320 }
321 }
322
323 static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
324 QemuConsole *src, QemuInputEvent *evt)
325 {
326 QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
327
328 item->type = QEMU_INPUT_QUEUE_EVENT;
329 item->src = src;
330 item->evt = *evt;
331 QTAILQ_INSERT_TAIL(queue, item, node);
332 queue_count++;
333 }
334
335 static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
336 {
337 QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
338
339 item->type = QEMU_INPUT_QUEUE_SYNC;
340 QTAILQ_INSERT_TAIL(queue, item, node);
341 queue_count++;
342 }
343
344 void qemu_input_event_send_impl(QemuConsole *src, QemuInputEvent *evt)
345 {
346 QemuInputHandlerState *s;
347
348 qemu_input_event_trace(src, evt);
349
350 /* send event */
351 s = qemu_input_find_handler(1 << evt->type, src);
352 if (!s) {
353 return;
354 }
355 s->handler->event(s->dev, src, evt);
356 s->events++;
357 }
358
359 void qemu_input_event_send(QemuConsole *src, QemuInputEvent *evt)
360 {
361 if (evt->type == INPUT_EVENT_KIND_KEY && !evt->key.key) {
362 return;
363 }
364
365 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
366 return;
367 }
368
369 replay_input_event(src, evt);
370 }
371
372 void qemu_input_event_sync_impl(void)
373 {
374 QemuInputHandlerState *s;
375
376 trace_input_event_sync();
377
378 QTAILQ_FOREACH(s, &handlers, node) {
379 if (!s->events) {
380 continue;
381 }
382 if (s->handler->sync) {
383 s->handler->sync(s->dev);
384 }
385 s->events = 0;
386 }
387 }
388
389 void qemu_input_event_sync(void)
390 {
391 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
392 return;
393 }
394
395 replay_input_sync_event();
396 }
397
398 void qemu_input_event_send_key_linux(QemuConsole *src, unsigned int lnx,
399 bool down)
400 {
401 QemuInputEvent evt = {
402 .type = INPUT_EVENT_KIND_KEY,
403 .key = {
404 .key = lnx,
405 .down = down,
406 },
407 };
408
409 if (QTAILQ_EMPTY(&kbd_queue)) {
410 qemu_input_event_send(src, &evt);
411 qemu_input_event_sync();
412 } else if (queue_count < queue_limit) {
413 qemu_input_queue_event(&kbd_queue, src, &evt);
414 qemu_input_queue_sync(&kbd_queue);
415 }
416 }
417
418 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
419 {
420 unsigned int lnx = qemu_input_key_number_to_linux(num);
421 qemu_input_event_send_key_linux(src, lnx, down);
422 }
423
424 void qemu_input_event_send_key_delay(uint32_t delay_ms)
425 {
426 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
427 return;
428 }
429
430 if (!kbd_timer) {
431 kbd_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
432 SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
433 qemu_input_queue_process, &kbd_queue);
434 }
435 if (queue_count < queue_limit) {
436 qemu_input_queue_delay(&kbd_queue, kbd_timer,
437 delay_ms ? delay_ms : kbd_default_delay_ms);
438 }
439 }
440
441 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
442 {
443 QemuInputEvent evt = {
444 .type = INPUT_EVENT_KIND_BTN,
445 .btn = {
446 .button = btn,
447 .down = down,
448 }
449 };
450
451 qemu_input_event_send(src, &evt);
452 }
453
454 void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
455 uint32_t button_old, uint32_t button_new)
456 {
457 InputButton btn;
458 uint32_t mask;
459
460 for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) {
461 mask = button_map[btn];
462 if ((button_old & mask) == (button_new & mask)) {
463 continue;
464 }
465 qemu_input_queue_btn(src, btn, button_new & mask);
466 }
467 }
468
469 bool qemu_input_is_absolute(const QemuConsole *con)
470 {
471 QemuInputHandlerState *s;
472
473 s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
474 con);
475 return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
476 }
477
478 uint32_t qemu_input_get_leds_mask(const QemuConsole *con)
479 {
480 QemuInputHandlerState *s;
481
482 s = qemu_input_find_handler(INPUT_EVENT_MASK_KEY, con);
483 if (s) {
484 return s->leds_mask;
485 }
486 return 0;
487 }
488
489 int qemu_input_scale_axis(int value,
490 int min_in, int max_in,
491 int min_out, int max_out)
492 {
493 int64_t range_in = (int64_t)max_in - min_in;
494 int64_t range_out = (int64_t)max_out - min_out;
495
496 if (range_in < 1) {
497 return min_out + range_out / 2;
498 }
499 return ((int64_t)value - min_in) * range_out / range_in + min_out;
500 }
501
502 void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
503 {
504 QemuInputEvent evt = {
505 .type = INPUT_EVENT_KIND_REL,
506 .rel = {
507 .axis = axis,
508 .value = value,
509 },
510 };
511
512 qemu_input_event_send(src, &evt);
513 }
514
515 void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
516 int min_in, int max_in)
517 {
518 QemuInputEvent evt = {
519 .type = INPUT_EVENT_KIND_ABS,
520 .abs = {
521 .axis = axis,
522 .value = qemu_input_scale_axis(value, min_in, max_in,
523 INPUT_EVENT_ABS_MIN,
524 INPUT_EVENT_ABS_MAX),
525 },
526 };
527
528 qemu_input_event_send(src, &evt);
529 }
530
531 void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
532 int slot, int tracking_id)
533 {
534 QemuInputEvent evt = {
535 .type = INPUT_EVENT_KIND_MTT,
536 .mtt = {
537 .type = type,
538 .slot = slot,
539 .tracking_id = tracking_id,
540 },
541 };
542
543 qemu_input_event_send(src, &evt);
544 }
545
546 void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
547 int min_in, int max_in, int slot, int tracking_id)
548 {
549 QemuInputEvent evt = {
550 .type = INPUT_EVENT_KIND_MTT,
551 .mtt = {
552 .type = INPUT_MULTI_TOUCH_TYPE_DATA,
553 .slot = slot,
554 .tracking_id = tracking_id,
555 .axis = axis,
556 .value = qemu_input_scale_axis(value, min_in, max_in,
557 INPUT_EVENT_ABS_MIN,
558 INPUT_EVENT_ABS_MAX),
559 }
560 };
561
562 qemu_input_event_send(src, &evt);
563 }
564
565 void qemu_add_mouse_mode_change_notifier(Notifier *notify)
566 {
567 notifier_list_add(&mouse_mode_notifiers, notify);
568 }
569
570 void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
571 {
572 notifier_remove(notify);
573 }
574
575 MouseInfoList *qmp_query_mice(Error **errp)
576 {
577 MouseInfoList *mice_list = NULL;
578 MouseInfo *info;
579 QemuInputHandlerState *s;
580 bool current = true;
581
582 QTAILQ_FOREACH(s, &handlers, node) {
583 if (!(s->handler->mask &
584 (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
585 continue;
586 }
587
588 info = g_new0(MouseInfo, 1);
589 info->index = s->id;
590 info->name = g_strdup(s->handler->name);
591 info->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
592 info->current = current;
593
594 current = false;
595 QAPI_LIST_PREPEND(mice_list, info);
596 }
597
598 return mice_list;
599 }
600
601 bool qemu_mouse_set(int index, Error **errp)
602 {
603 QemuInputHandlerState *s;
604
605 QTAILQ_FOREACH(s, &handlers, node) {
606 if (s->id == index) {
607 break;
608 }
609 }
610
611 if (!s) {
612 error_setg(errp, "Mouse at index '%d' not found", index);
613 return false;
614 }
615
616 if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
617 INPUT_EVENT_MASK_ABS))) {
618 error_setg(errp, "Input device '%s' is not a mouse",
619 s->handler->name);
620 return false;
621 }
622
623 qemu_input_handler_activate(s);
624 return true;
625 }
626
627 void qemu_input_touch_event(QemuConsole *con,
628 struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
629 uint64_t num_slot,
630 int width, int height,
631 double x, double y,
632 InputMultiTouchType type,
633 Error **errp)
634 {
635 struct touch_slot *slot;
636 bool needs_sync = false;
637 int update;
638 int i;
639
640 if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
641 error_setg(errp,
642 "Unexpected touch slot number: % " PRId64" >= %d",
643 num_slot, INPUT_EVENT_SLOTS_MAX);
644 return;
645 }
646
647 slot = &touch_slots[num_slot];
648 slot->x = x;
649 slot->y = y;
650
651 if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
652 slot->tracking_id = num_slot;
653 }
654
655 for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
656 if (i == num_slot) {
657 update = type;
658 } else {
659 update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
660 }
661
662 slot = &touch_slots[i];
663
664 if (slot->tracking_id == -1) {
665 continue;
666 }
667
668 if (update == INPUT_MULTI_TOUCH_TYPE_END) {
669 slot->tracking_id = -1;
670 qemu_input_queue_mtt(con, update, i, slot->tracking_id);
671 needs_sync = true;
672 } else {
673 qemu_input_queue_mtt(con, update, i, slot->tracking_id);
674 qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
675 qemu_input_queue_mtt_abs(con,
676 INPUT_AXIS_X, (int) slot->x,
677 0, width,
678 i, slot->tracking_id);
679 qemu_input_queue_mtt_abs(con,
680 INPUT_AXIS_Y, (int) slot->y,
681 0, height,
682 i, slot->tracking_id);
683 needs_sync = true;
684 }
685 }
686
687 if (needs_sync) {
688 qemu_input_event_sync();
689 }
690 }
691
692 void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
693 Error **errp)
694 {
695 KeyValueList *p;
696 unsigned int *up = NULL;
697 int count = 0;
698
699 if (!has_hold_time) {
700 hold_time = 0; /* use default */
701 }
702
703 for (p = keys; p != NULL; p = p->next) {
704 up = g_realloc_n(up, count + 1, sizeof(*up));
705 up[count] = qemu_input_key_value_to_linux(p->value);
706 qemu_input_event_send_key_linux(NULL, up[count], true);
707 qemu_input_event_send_key_delay(hold_time);
708 count++;
709 }
710 while (count) {
711 count--;
712 qemu_input_event_send_key_linux(NULL, up[count], false);
713 qemu_input_event_send_key_delay(hold_time);
714 }
715 g_free(up);
716 }