xref: /openbmc/qemu/ui/input.c (revision 7d87775f)
1 #include "qemu/osdep.h"
2 #include "sysemu/sysemu.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 "sysemu/replay.h"
9 #include "sysemu/runstate.h"
10 
11 struct QemuInputHandlerState {
12     DeviceState       *dev;
13     const QemuInputHandler *handler;
14     int               id;
15     int               events;
16     QemuConsole       *con;
17     QTAILQ_ENTRY(QemuInputHandlerState) node;
18 };
19 
20 typedef struct QemuInputEventQueue QemuInputEventQueue;
21 typedef QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue)
22     QemuInputEventQueueHead;
23 
24 struct QemuInputEventQueue {
25     enum {
26         QEMU_INPUT_QUEUE_DELAY = 1,
27         QEMU_INPUT_QUEUE_EVENT,
28         QEMU_INPUT_QUEUE_SYNC,
29     } type;
30     QEMUTimer *timer;
31     uint32_t delay_ms;
32     QemuConsole *src;
33     InputEvent *evt;
34     QTAILQ_ENTRY(QemuInputEventQueue) node;
35 };
36 
37 static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
38     QTAILQ_HEAD_INITIALIZER(handlers);
39 static NotifierList mouse_mode_notifiers =
40     NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
41 
42 static QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
43 static QEMUTimer *kbd_timer;
44 static uint32_t kbd_default_delay_ms = 10;
45 static uint32_t queue_count;
46 static uint32_t queue_limit = 1024;
47 
48 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
49                                             const QemuInputHandler *handler)
50 {
51     QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
52     static int id = 1;
53 
54     s->dev = dev;
55     s->handler = handler;
56     s->id = id++;
57     QTAILQ_INSERT_TAIL(&handlers, s, node);
58 
59     notifier_list_notify(&mouse_mode_notifiers, NULL);
60     return s;
61 }
62 
63 void qemu_input_handler_activate(QemuInputHandlerState *s)
64 {
65     QTAILQ_REMOVE(&handlers, s, node);
66     QTAILQ_INSERT_HEAD(&handlers, s, node);
67     notifier_list_notify(&mouse_mode_notifiers, NULL);
68 }
69 
70 void qemu_input_handler_deactivate(QemuInputHandlerState *s)
71 {
72     QTAILQ_REMOVE(&handlers, s, node);
73     QTAILQ_INSERT_TAIL(&handlers, s, node);
74     notifier_list_notify(&mouse_mode_notifiers, NULL);
75 }
76 
77 void qemu_input_handler_unregister(QemuInputHandlerState *s)
78 {
79     QTAILQ_REMOVE(&handlers, s, node);
80     g_free(s);
81     notifier_list_notify(&mouse_mode_notifiers, NULL);
82 }
83 
84 void qemu_input_handler_bind(QemuInputHandlerState *s,
85                              const char *device_id, int head,
86                              Error **errp)
87 {
88     QemuConsole *con;
89     Error *err = NULL;
90 
91     con = qemu_console_lookup_by_device_name(device_id, head, &err);
92     if (err) {
93         error_propagate(errp, err);
94         return;
95     }
96 
97     s->con = con;
98 }
99 
100 static QemuInputHandlerState*
101 qemu_input_find_handler(uint32_t mask, QemuConsole *con)
102 {
103     QemuInputHandlerState *s;
104 
105     QTAILQ_FOREACH(s, &handlers, node) {
106         if (s->con == NULL || s->con != con) {
107             continue;
108         }
109         if (mask & s->handler->mask) {
110             return s;
111         }
112     }
113 
114     QTAILQ_FOREACH(s, &handlers, node) {
115         if (s->con != NULL) {
116             continue;
117         }
118         if (mask & s->handler->mask) {
119             return s;
120         }
121     }
122     return NULL;
123 }
124 
125 void qmp_input_send_event(const char *device,
126                           bool has_head, int64_t head,
127                           InputEventList *events, Error **errp)
128 {
129     InputEventList *e;
130     QemuConsole *con;
131     Error *err = NULL;
132 
133     con = NULL;
134     if (device) {
135         if (!has_head) {
136             head = 0;
137         }
138         con = qemu_console_lookup_by_device_name(device, head, &err);
139         if (err) {
140             error_propagate(errp, err);
141             return;
142         }
143     }
144 
145     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
146         error_setg(errp, "VM not running");
147         return;
148     }
149 
150     for (e = events; e != NULL; e = e->next) {
151         InputEvent *event = e->value;
152 
153         if (!qemu_input_find_handler(1 << event->type, con)) {
154             error_setg(errp, "Input handler not found for "
155                              "event type %s",
156                             InputEventKind_str(event->type));
157             return;
158         }
159     }
160 
161     for (e = events; e != NULL; e = e->next) {
162         InputEvent *evt = e->value;
163 
164         if (evt->type == INPUT_EVENT_KIND_KEY &&
165             evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER) {
166             KeyValue *key = evt->u.key.data->key;
167             QKeyCode code = qemu_input_key_number_to_qcode(key->u.number.data);
168             qemu_input_event_send_key_qcode(con, code, evt->u.key.data->down);
169         } else {
170             qemu_input_event_send(con, evt);
171         }
172     }
173 
174     qemu_input_event_sync();
175 }
176 
177 static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
178 {
179     const char *name;
180     int qcode, idx = -1;
181     InputKeyEvent *key;
182     InputBtnEvent *btn;
183     InputMoveEvent *move;
184     InputMultiTouchEvent *mtt;
185 
186     if (src) {
187         idx = qemu_console_get_index(src);
188     }
189     switch (evt->type) {
190     case INPUT_EVENT_KIND_KEY:
191         key = evt->u.key.data;
192         switch (key->key->type) {
193         case KEY_VALUE_KIND_NUMBER:
194             qcode = qemu_input_key_number_to_qcode(key->key->u.number.data);
195             name = QKeyCode_str(qcode);
196             trace_input_event_key_number(idx, key->key->u.number.data,
197                                          name, key->down);
198             break;
199         case KEY_VALUE_KIND_QCODE:
200             name = QKeyCode_str(key->key->u.qcode.data);
201             trace_input_event_key_qcode(idx, name, key->down);
202             break;
203         case KEY_VALUE_KIND__MAX:
204             /* keep gcc happy */
205             break;
206         }
207         break;
208     case INPUT_EVENT_KIND_BTN:
209         btn = evt->u.btn.data;
210         name = InputButton_str(btn->button);
211         trace_input_event_btn(idx, name, btn->down);
212         break;
213     case INPUT_EVENT_KIND_REL:
214         move = evt->u.rel.data;
215         name = InputAxis_str(move->axis);
216         trace_input_event_rel(idx, name, move->value);
217         break;
218     case INPUT_EVENT_KIND_ABS:
219         move = evt->u.abs.data;
220         name = InputAxis_str(move->axis);
221         trace_input_event_abs(idx, name, move->value);
222         break;
223     case INPUT_EVENT_KIND_MTT:
224         mtt = evt->u.mtt.data;
225         name = InputAxis_str(mtt->axis);
226         trace_input_event_mtt(idx, name, mtt->value);
227         break;
228     case INPUT_EVENT_KIND__MAX:
229         /* keep gcc happy */
230         break;
231     }
232 }
233 
234 static void qemu_input_queue_process(void *opaque)
235 {
236     QemuInputEventQueueHead *queue = opaque;
237     QemuInputEventQueue *item;
238 
239     g_assert(!QTAILQ_EMPTY(queue));
240     item = QTAILQ_FIRST(queue);
241     g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
242     QTAILQ_REMOVE(queue, item, node);
243     queue_count--;
244     g_free(item);
245 
246     while (!QTAILQ_EMPTY(queue)) {
247         item = QTAILQ_FIRST(queue);
248         switch (item->type) {
249         case QEMU_INPUT_QUEUE_DELAY:
250             timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
251                       + item->delay_ms);
252             return;
253         case QEMU_INPUT_QUEUE_EVENT:
254             qemu_input_event_send(item->src, item->evt);
255             qapi_free_InputEvent(item->evt);
256             break;
257         case QEMU_INPUT_QUEUE_SYNC:
258             qemu_input_event_sync();
259             break;
260         }
261         QTAILQ_REMOVE(queue, item, node);
262         queue_count--;
263         g_free(item);
264     }
265 }
266 
267 static void qemu_input_queue_delay(QemuInputEventQueueHead *queue,
268                                    QEMUTimer *timer, uint32_t delay_ms)
269 {
270     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
271     bool start_timer = QTAILQ_EMPTY(queue);
272 
273     item->type = QEMU_INPUT_QUEUE_DELAY;
274     item->delay_ms = delay_ms;
275     item->timer = timer;
276     QTAILQ_INSERT_TAIL(queue, item, node);
277     queue_count++;
278 
279     if (start_timer) {
280         timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
281                   + item->delay_ms);
282     }
283 }
284 
285 static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
286                                    QemuConsole *src, InputEvent *evt)
287 {
288     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
289 
290     item->type = QEMU_INPUT_QUEUE_EVENT;
291     item->src = src;
292     item->evt = evt;
293     QTAILQ_INSERT_TAIL(queue, item, node);
294     queue_count++;
295 }
296 
297 static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
298 {
299     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
300 
301     item->type = QEMU_INPUT_QUEUE_SYNC;
302     QTAILQ_INSERT_TAIL(queue, item, node);
303     queue_count++;
304 }
305 
306 void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
307 {
308     QemuInputHandlerState *s;
309 
310     qemu_input_event_trace(src, evt);
311 
312     /* send event */
313     s = qemu_input_find_handler(1 << evt->type, src);
314     if (!s) {
315         return;
316     }
317     s->handler->event(s->dev, src, evt);
318     s->events++;
319 }
320 
321 void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
322 {
323     /* Expect all parts of QEMU to send events with QCodes exclusively.
324      * Key numbers are only supported as end-user input via QMP */
325     assert(!(evt->type == INPUT_EVENT_KIND_KEY &&
326              evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER));
327 
328 
329     /*
330      * 'sysrq' was mistakenly added to hack around the fact that
331      * the ps2 driver was not generating correct scancodes sequences
332      * when 'alt+print' was pressed. This flaw is now fixed and the
333      * 'sysrq' key serves no further purpose. We normalize it to
334      * 'print', so that downstream receivers of the event don't
335      * need to deal with this mistake
336      */
337     if (evt->type == INPUT_EVENT_KIND_KEY &&
338         evt->u.key.data->key->u.qcode.data == Q_KEY_CODE_SYSRQ) {
339         evt->u.key.data->key->u.qcode.data = Q_KEY_CODE_PRINT;
340     }
341 
342     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
343         return;
344     }
345 
346     replay_input_event(src, evt);
347 }
348 
349 void qemu_input_event_sync_impl(void)
350 {
351     QemuInputHandlerState *s;
352 
353     trace_input_event_sync();
354 
355     QTAILQ_FOREACH(s, &handlers, node) {
356         if (!s->events) {
357             continue;
358         }
359         if (s->handler->sync) {
360             s->handler->sync(s->dev);
361         }
362         s->events = 0;
363     }
364 }
365 
366 void qemu_input_event_sync(void)
367 {
368     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
369         return;
370     }
371 
372     replay_input_sync_event();
373 }
374 
375 static InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
376 {
377     InputEvent *evt = g_new0(InputEvent, 1);
378     evt->u.key.data = g_new0(InputKeyEvent, 1);
379     evt->type = INPUT_EVENT_KIND_KEY;
380     evt->u.key.data->key = key;
381     evt->u.key.data->down = down;
382     return evt;
383 }
384 
385 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
386 {
387     InputEvent *evt;
388     evt = qemu_input_event_new_key(key, down);
389     if (QTAILQ_EMPTY(&kbd_queue)) {
390         qemu_input_event_send(src, evt);
391         qemu_input_event_sync();
392         qapi_free_InputEvent(evt);
393     } else if (queue_count < queue_limit) {
394         qemu_input_queue_event(&kbd_queue, src, evt);
395         qemu_input_queue_sync(&kbd_queue);
396     } else {
397         qapi_free_InputEvent(evt);
398     }
399 }
400 
401 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
402 {
403     QKeyCode code = qemu_input_key_number_to_qcode(num);
404     qemu_input_event_send_key_qcode(src, code, down);
405 }
406 
407 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
408 {
409     KeyValue *key = g_new0(KeyValue, 1);
410     key->type = KEY_VALUE_KIND_QCODE;
411     key->u.qcode.data = q;
412     qemu_input_event_send_key(src, key, down);
413 }
414 
415 void qemu_input_event_send_key_delay(uint32_t delay_ms)
416 {
417     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
418         return;
419     }
420 
421     if (!kbd_timer) {
422         kbd_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
423                                    SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
424                                    qemu_input_queue_process, &kbd_queue);
425     }
426     if (queue_count < queue_limit) {
427         qemu_input_queue_delay(&kbd_queue, kbd_timer,
428                                delay_ms ? delay_ms : kbd_default_delay_ms);
429     }
430 }
431 
432 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
433 {
434     InputBtnEvent bevt = {
435         .button = btn,
436         .down = down,
437     };
438     InputEvent evt = {
439         .type = INPUT_EVENT_KIND_BTN,
440         .u.btn.data = &bevt,
441     };
442 
443     qemu_input_event_send(src, &evt);
444 }
445 
446 void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
447                                uint32_t button_old, uint32_t button_new)
448 {
449     InputButton btn;
450     uint32_t mask;
451 
452     for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) {
453         mask = button_map[btn];
454         if ((button_old & mask) == (button_new & mask)) {
455             continue;
456         }
457         qemu_input_queue_btn(src, btn, button_new & mask);
458     }
459 }
460 
461 bool qemu_input_is_absolute(QemuConsole *con)
462 {
463     QemuInputHandlerState *s;
464 
465     s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
466                                 con);
467     return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
468 }
469 
470 int qemu_input_scale_axis(int value,
471                           int min_in, int max_in,
472                           int min_out, int max_out)
473 {
474     int64_t range_in = (int64_t)max_in - min_in;
475     int64_t range_out = (int64_t)max_out - min_out;
476 
477     if (range_in < 1) {
478         return min_out + range_out / 2;
479     }
480     return ((int64_t)value - min_in) * range_out / range_in + min_out;
481 }
482 
483 void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
484 {
485     InputMoveEvent move = {
486         .axis = axis,
487         .value = value,
488     };
489     InputEvent evt = {
490         .type = INPUT_EVENT_KIND_REL,
491         .u.rel.data = &move,
492     };
493 
494     qemu_input_event_send(src, &evt);
495 }
496 
497 void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
498                           int min_in, int max_in)
499 {
500     InputMoveEvent move = {
501         .axis = axis,
502         .value = qemu_input_scale_axis(value, min_in, max_in,
503                                        INPUT_EVENT_ABS_MIN,
504                                        INPUT_EVENT_ABS_MAX),
505     };
506     InputEvent evt = {
507         .type = INPUT_EVENT_KIND_ABS,
508         .u.abs.data = &move,
509     };
510 
511     qemu_input_event_send(src, &evt);
512 }
513 
514 void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
515                           int slot, int tracking_id)
516 {
517     InputMultiTouchEvent mtt = {
518         .type = type,
519         .slot = slot,
520         .tracking_id = tracking_id,
521     };
522     InputEvent evt = {
523         .type = INPUT_EVENT_KIND_MTT,
524         .u.mtt.data = &mtt,
525     };
526 
527     qemu_input_event_send(src, &evt);
528 }
529 
530 void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
531                               int min_in, int max_in, int slot, int tracking_id)
532 {
533     InputMultiTouchEvent mtt = {
534         .type = INPUT_MULTI_TOUCH_TYPE_DATA,
535         .slot = slot,
536         .tracking_id = tracking_id,
537         .axis = axis,
538         .value = qemu_input_scale_axis(value, min_in, max_in,
539                                        INPUT_EVENT_ABS_MIN,
540                                        INPUT_EVENT_ABS_MAX),
541     };
542     InputEvent evt = {
543         .type = INPUT_EVENT_KIND_MTT,
544         .u.mtt.data = &mtt,
545     };
546 
547     qemu_input_event_send(src, &evt);
548 }
549 
550 void qemu_add_mouse_mode_change_notifier(Notifier *notify)
551 {
552     notifier_list_add(&mouse_mode_notifiers, notify);
553 }
554 
555 void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
556 {
557     notifier_remove(notify);
558 }
559 
560 MouseInfoList *qmp_query_mice(Error **errp)
561 {
562     MouseInfoList *mice_list = NULL;
563     MouseInfo *info;
564     QemuInputHandlerState *s;
565     bool current = true;
566 
567     QTAILQ_FOREACH(s, &handlers, node) {
568         if (!(s->handler->mask &
569               (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
570             continue;
571         }
572 
573         info = g_new0(MouseInfo, 1);
574         info->index = s->id;
575         info->name = g_strdup(s->handler->name);
576         info->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
577         info->current = current;
578 
579         current = false;
580         QAPI_LIST_PREPEND(mice_list, info);
581     }
582 
583     return mice_list;
584 }
585 
586 bool qemu_mouse_set(int index, Error **errp)
587 {
588     QemuInputHandlerState *s;
589 
590     QTAILQ_FOREACH(s, &handlers, node) {
591         if (s->id == index) {
592             break;
593         }
594     }
595 
596     if (!s) {
597         error_setg(errp, "Mouse at index '%d' not found", index);
598         return false;
599     }
600 
601     if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
602                               INPUT_EVENT_MASK_ABS))) {
603         error_setg(errp, "Input device '%s' is not a mouse",
604                    s->handler->name);
605         return false;
606     }
607 
608     qemu_input_handler_activate(s);
609     notifier_list_notify(&mouse_mode_notifiers, NULL);
610     return true;
611 }
612