xref: /openbmc/qemu/ui/input.c (revision b45c03f5)
1 #include "hw/qdev.h"
2 #include "sysemu/sysemu.h"
3 #include "qapi-types.h"
4 #include "qemu/error-report.h"
5 #include "qmp-commands.h"
6 #include "trace.h"
7 #include "ui/input.h"
8 #include "ui/console.h"
9 
10 struct QemuInputHandlerState {
11     DeviceState       *dev;
12     QemuInputHandler  *handler;
13     int               id;
14     int               events;
15     QemuConsole       *con;
16     QTAILQ_ENTRY(QemuInputHandlerState) node;
17 };
18 
19 typedef struct QemuInputEventQueue QemuInputEventQueue;
20 struct QemuInputEventQueue {
21     enum {
22         QEMU_INPUT_QUEUE_DELAY = 1,
23         QEMU_INPUT_QUEUE_EVENT,
24         QEMU_INPUT_QUEUE_SYNC,
25     } type;
26     QEMUTimer *timer;
27     uint32_t delay_ms;
28     QemuConsole *src;
29     InputEvent *evt;
30     QTAILQ_ENTRY(QemuInputEventQueue) node;
31 };
32 
33 static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
34     QTAILQ_HEAD_INITIALIZER(handlers);
35 static NotifierList mouse_mode_notifiers =
36     NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
37 
38 static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
39     QTAILQ_HEAD_INITIALIZER(kbd_queue);
40 static QEMUTimer *kbd_timer;
41 static uint32_t kbd_default_delay_ms = 10;
42 
43 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
44                                                    QemuInputHandler *handler)
45 {
46     QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
47     static int id = 1;
48 
49     s->dev = dev;
50     s->handler = handler;
51     s->id = id++;
52     QTAILQ_INSERT_TAIL(&handlers, s, node);
53 
54     qemu_input_check_mode_change();
55     return s;
56 }
57 
58 void qemu_input_handler_activate(QemuInputHandlerState *s)
59 {
60     QTAILQ_REMOVE(&handlers, s, node);
61     QTAILQ_INSERT_HEAD(&handlers, s, node);
62     qemu_input_check_mode_change();
63 }
64 
65 void qemu_input_handler_deactivate(QemuInputHandlerState *s)
66 {
67     QTAILQ_REMOVE(&handlers, s, node);
68     QTAILQ_INSERT_TAIL(&handlers, s, node);
69     qemu_input_check_mode_change();
70 }
71 
72 void qemu_input_handler_unregister(QemuInputHandlerState *s)
73 {
74     QTAILQ_REMOVE(&handlers, s, node);
75     g_free(s);
76     qemu_input_check_mode_change();
77 }
78 
79 void qemu_input_handler_bind(QemuInputHandlerState *s,
80                              const char *device_id, int head,
81                              Error **errp)
82 {
83     DeviceState *dev;
84     QemuConsole *con;
85 
86     dev = qdev_find_recursive(sysbus_get_default(), device_id);
87     if (dev == NULL) {
88         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
89                   "Device '%s' not found", device_id);
90         return;
91     }
92 
93     con = qemu_console_lookup_by_device(dev, head);
94     if (con == NULL) {
95         error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
96         return;
97     }
98 
99     s->con = con;
100 }
101 
102 static QemuInputHandlerState*
103 qemu_input_find_handler(uint32_t mask, QemuConsole *con)
104 {
105     QemuInputHandlerState *s;
106 
107     QTAILQ_FOREACH(s, &handlers, node) {
108         if (s->con == NULL || s->con != con) {
109             continue;
110         }
111         if (mask & s->handler->mask) {
112             return s;
113         }
114     }
115 
116     QTAILQ_FOREACH(s, &handlers, node) {
117         if (s->con != NULL) {
118             continue;
119         }
120         if (mask & s->handler->mask) {
121             return s;
122         }
123     }
124     return NULL;
125 }
126 
127 void qmp_x_input_send_event(bool has_console, int64_t console,
128                             InputEventList *events, Error **errp)
129 {
130     InputEventList *e;
131     QemuConsole *con;
132 
133     con = NULL;
134     if (has_console) {
135         con = qemu_console_lookup_by_index(console);
136         if (!con) {
137             error_setg(errp, "console %" PRId64 " not found", console);
138             return;
139         }
140     }
141 
142     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
143         error_setg(errp, "VM not running");
144         return;
145     }
146 
147     for (e = events; e != NULL; e = e->next) {
148         InputEvent *event = e->value;
149 
150         if (!qemu_input_find_handler(1 << event->kind, con)) {
151             error_setg(errp, "Input handler not found for "
152                              "event type %s",
153                             InputEventKind_lookup[event->kind]);
154             return;
155         }
156     }
157 
158     for (e = events; e != NULL; e = e->next) {
159         InputEvent *event = e->value;
160 
161         qemu_input_event_send(con, event);
162     }
163 
164     qemu_input_event_sync();
165 }
166 
167 static void qemu_input_transform_abs_rotate(InputEvent *evt)
168 {
169     switch (graphic_rotate) {
170     case 90:
171         if (evt->abs->axis == INPUT_AXIS_X) {
172             evt->abs->axis = INPUT_AXIS_Y;
173         } else if (evt->abs->axis == INPUT_AXIS_Y) {
174             evt->abs->axis = INPUT_AXIS_X;
175             evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
176         }
177         break;
178     case 180:
179         evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
180         break;
181     case 270:
182         if (evt->abs->axis == INPUT_AXIS_X) {
183             evt->abs->axis = INPUT_AXIS_Y;
184             evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
185         } else if (evt->abs->axis == INPUT_AXIS_Y) {
186             evt->abs->axis = INPUT_AXIS_X;
187         }
188         break;
189     }
190 }
191 
192 static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
193 {
194     const char *name;
195     int qcode, idx = -1;
196 
197     if (src) {
198         idx = qemu_console_get_index(src);
199     }
200     switch (evt->kind) {
201     case INPUT_EVENT_KIND_KEY:
202         switch (evt->key->key->kind) {
203         case KEY_VALUE_KIND_NUMBER:
204             qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
205             name = QKeyCode_lookup[qcode];
206             trace_input_event_key_number(idx, evt->key->key->number,
207                                          name, evt->key->down);
208             break;
209         case KEY_VALUE_KIND_QCODE:
210             name = QKeyCode_lookup[evt->key->key->qcode];
211             trace_input_event_key_qcode(idx, name, evt->key->down);
212             break;
213         case KEY_VALUE_KIND_MAX:
214             /* keep gcc happy */
215             break;
216         }
217         break;
218     case INPUT_EVENT_KIND_BTN:
219         name = InputButton_lookup[evt->btn->button];
220         trace_input_event_btn(idx, name, evt->btn->down);
221         break;
222     case INPUT_EVENT_KIND_REL:
223         name = InputAxis_lookup[evt->rel->axis];
224         trace_input_event_rel(idx, name, evt->rel->value);
225         break;
226     case INPUT_EVENT_KIND_ABS:
227         name = InputAxis_lookup[evt->abs->axis];
228         trace_input_event_abs(idx, name, evt->abs->value);
229         break;
230     case INPUT_EVENT_KIND_MAX:
231         /* keep gcc happy */
232         break;
233     }
234 }
235 
236 static void qemu_input_queue_process(void *opaque)
237 {
238     struct QemuInputEventQueueHead *queue = opaque;
239     QemuInputEventQueue *item;
240 
241     g_assert(!QTAILQ_EMPTY(queue));
242     item = QTAILQ_FIRST(queue);
243     g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
244     QTAILQ_REMOVE(queue, item, node);
245     g_free(item);
246 
247     while (!QTAILQ_EMPTY(queue)) {
248         item = QTAILQ_FIRST(queue);
249         switch (item->type) {
250         case QEMU_INPUT_QUEUE_DELAY:
251             timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
252                       + item->delay_ms);
253             return;
254         case QEMU_INPUT_QUEUE_EVENT:
255             qemu_input_event_send(item->src, item->evt);
256             qapi_free_InputEvent(item->evt);
257             break;
258         case QEMU_INPUT_QUEUE_SYNC:
259             qemu_input_event_sync();
260             break;
261         }
262         QTAILQ_REMOVE(queue, item, node);
263         g_free(item);
264     }
265 }
266 
267 static void qemu_input_queue_delay(struct 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 
278     if (start_timer) {
279         timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
280                   + item->delay_ms);
281     }
282 }
283 
284 static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
285                                    QemuConsole *src, InputEvent *evt)
286 {
287     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
288 
289     item->type = QEMU_INPUT_QUEUE_EVENT;
290     item->src = src;
291     item->evt = evt;
292     QTAILQ_INSERT_TAIL(queue, item, node);
293 }
294 
295 static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
296 {
297     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
298 
299     item->type = QEMU_INPUT_QUEUE_SYNC;
300     QTAILQ_INSERT_TAIL(queue, item, node);
301 }
302 
303 void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
304 {
305     QemuInputHandlerState *s;
306 
307     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
308         return;
309     }
310 
311     qemu_input_event_trace(src, evt);
312 
313     /* pre processing */
314     if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
315             qemu_input_transform_abs_rotate(evt);
316     }
317 
318     /* send event */
319     s = qemu_input_find_handler(1 << evt->kind, src);
320     if (!s) {
321         return;
322     }
323     s->handler->event(s->dev, src, evt);
324     s->events++;
325 }
326 
327 void qemu_input_event_sync(void)
328 {
329     QemuInputHandlerState *s;
330 
331     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
332         return;
333     }
334 
335     trace_input_event_sync();
336 
337     QTAILQ_FOREACH(s, &handlers, node) {
338         if (!s->events) {
339             continue;
340         }
341         if (s->handler->sync) {
342             s->handler->sync(s->dev);
343         }
344         s->events = 0;
345     }
346 }
347 
348 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
349 {
350     InputEvent *evt = g_new0(InputEvent, 1);
351     evt->key = g_new0(InputKeyEvent, 1);
352     evt->kind = INPUT_EVENT_KIND_KEY;
353     evt->key->key = key;
354     evt->key->down = down;
355     return evt;
356 }
357 
358 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
359 {
360     InputEvent *evt;
361     evt = qemu_input_event_new_key(key, down);
362     if (QTAILQ_EMPTY(&kbd_queue)) {
363         qemu_input_event_send(src, evt);
364         qemu_input_event_sync();
365         qapi_free_InputEvent(evt);
366     } else {
367         qemu_input_queue_event(&kbd_queue, src, evt);
368         qemu_input_queue_sync(&kbd_queue);
369     }
370 }
371 
372 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
373 {
374     KeyValue *key = g_new0(KeyValue, 1);
375     key->kind = KEY_VALUE_KIND_NUMBER;
376     key->number = num;
377     qemu_input_event_send_key(src, key, down);
378 }
379 
380 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
381 {
382     KeyValue *key = g_new0(KeyValue, 1);
383     key->kind = KEY_VALUE_KIND_QCODE;
384     key->qcode = q;
385     qemu_input_event_send_key(src, key, down);
386 }
387 
388 void qemu_input_event_send_key_delay(uint32_t delay_ms)
389 {
390     if (!kbd_timer) {
391         kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
392                                  &kbd_queue);
393     }
394     qemu_input_queue_delay(&kbd_queue, kbd_timer,
395                            delay_ms ? delay_ms : kbd_default_delay_ms);
396 }
397 
398 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
399 {
400     InputEvent *evt = g_new0(InputEvent, 1);
401     evt->btn = g_new0(InputBtnEvent, 1);
402     evt->kind = INPUT_EVENT_KIND_BTN;
403     evt->btn->button = btn;
404     evt->btn->down = down;
405     return evt;
406 }
407 
408 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
409 {
410     InputEvent *evt;
411     evt = qemu_input_event_new_btn(btn, down);
412     qemu_input_event_send(src, evt);
413     qapi_free_InputEvent(evt);
414 }
415 
416 void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
417                                uint32_t button_old, uint32_t button_new)
418 {
419     InputButton btn;
420     uint32_t mask;
421 
422     for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
423         mask = button_map[btn];
424         if ((button_old & mask) == (button_new & mask)) {
425             continue;
426         }
427         qemu_input_queue_btn(src, btn, button_new & mask);
428     }
429 }
430 
431 bool qemu_input_is_absolute(void)
432 {
433     QemuInputHandlerState *s;
434 
435     s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
436                                 NULL);
437     return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
438 }
439 
440 int qemu_input_scale_axis(int value, int size_in, int size_out)
441 {
442     if (size_in < 2) {
443         return size_out / 2;
444     }
445     return (int64_t)value * (size_out - 1) / (size_in - 1);
446 }
447 
448 InputEvent *qemu_input_event_new_move(InputEventKind kind,
449                                       InputAxis axis, int value)
450 {
451     InputEvent *evt = g_new0(InputEvent, 1);
452     InputMoveEvent *move = g_new0(InputMoveEvent, 1);
453 
454     evt->kind = kind;
455     evt->data = move;
456     move->axis = axis;
457     move->value = value;
458     return evt;
459 }
460 
461 void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
462 {
463     InputEvent *evt;
464     evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
465     qemu_input_event_send(src, evt);
466     qapi_free_InputEvent(evt);
467 }
468 
469 void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
470 {
471     InputEvent *evt;
472     int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
473     evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
474     qemu_input_event_send(src, evt);
475     qapi_free_InputEvent(evt);
476 }
477 
478 void qemu_input_check_mode_change(void)
479 {
480     static int current_is_absolute;
481     int is_absolute;
482 
483     is_absolute = qemu_input_is_absolute();
484 
485     if (is_absolute != current_is_absolute) {
486         trace_input_mouse_mode(is_absolute);
487         notifier_list_notify(&mouse_mode_notifiers, NULL);
488     }
489 
490     current_is_absolute = is_absolute;
491 }
492 
493 void qemu_add_mouse_mode_change_notifier(Notifier *notify)
494 {
495     notifier_list_add(&mouse_mode_notifiers, notify);
496 }
497 
498 void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
499 {
500     notifier_remove(notify);
501 }
502 
503 MouseInfoList *qmp_query_mice(Error **errp)
504 {
505     MouseInfoList *mice_list = NULL;
506     MouseInfoList *info;
507     QemuInputHandlerState *s;
508     bool current = true;
509 
510     QTAILQ_FOREACH(s, &handlers, node) {
511         if (!(s->handler->mask &
512               (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
513             continue;
514         }
515 
516         info = g_new0(MouseInfoList, 1);
517         info->value = g_new0(MouseInfo, 1);
518         info->value->index = s->id;
519         info->value->name = g_strdup(s->handler->name);
520         info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
521         info->value->current = current;
522 
523         current = false;
524         info->next = mice_list;
525         mice_list = info;
526     }
527 
528     return mice_list;
529 }
530 
531 void hmp_mouse_set(Monitor *mon, const QDict *qdict)
532 {
533     QemuInputHandlerState *s;
534     int index = qdict_get_int(qdict, "index");
535     int found = 0;
536 
537     QTAILQ_FOREACH(s, &handlers, node) {
538         if (s->id != index) {
539             continue;
540         }
541         if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
542                                   INPUT_EVENT_MASK_ABS))) {
543             error_report("Input device '%s' is not a mouse", s->handler->name);
544             return;
545         }
546         found = 1;
547         qemu_input_handler_activate(s);
548         break;
549     }
550 
551     if (!found) {
552         error_report("Mouse at index '%d' not found", index);
553     }
554 
555     qemu_input_check_mode_change();
556 }
557