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