blob: e96e1ea0f02fd2c50df54fb6ab6a7bae4601f0b0 [file] [log] [blame]
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +02001#include "hw/qdev.h"
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +01002#include "sysemu/sysemu.h"
3#include "qapi-types.h"
Gerd Hoffmanne842c682013-12-10 17:09:36 +01004#include "qmp-commands.h"
Gerd Hoffmannc43ce552013-12-04 15:20:05 +01005#include "trace.h"
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +01006#include "ui/input.h"
Gerd Hoffmannc43ce552013-12-04 15:20:05 +01007#include "ui/console.h"
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +01008
9struct QemuInputHandlerState {
10 DeviceState *dev;
11 QemuInputHandler *handler;
12 int id;
13 int events;
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +020014 QemuConsole *con;
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010015 QTAILQ_ENTRY(QemuInputHandlerState) node;
16};
Gerd Hoffmannbe1a7172014-05-28 13:02:40 +020017
18typedef struct QemuInputEventQueue QemuInputEventQueue;
19struct QemuInputEventQueue {
20 enum {
21 QEMU_INPUT_QUEUE_DELAY = 1,
22 QEMU_INPUT_QUEUE_EVENT,
23 QEMU_INPUT_QUEUE_SYNC,
24 } type;
25 QEMUTimer *timer;
26 uint32_t delay_ms;
27 QemuConsole *src;
28 InputEvent *evt;
29 QTAILQ_ENTRY(QemuInputEventQueue) node;
30};
31
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010032static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
33 QTAILQ_HEAD_INITIALIZER(handlers);
Gerd Hoffmann4a33f452013-12-05 11:23:42 +010034static NotifierList mouse_mode_notifiers =
35 NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010036
Gerd Hoffmannbe1a7172014-05-28 13:02:40 +020037static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
38 QTAILQ_HEAD_INITIALIZER(kbd_queue);
39static QEMUTimer *kbd_timer;
40static uint32_t kbd_default_delay_ms = 10;
41
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010042QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
43 QemuInputHandler *handler)
44{
45 QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
46 static int id = 1;
47
48 s->dev = dev;
49 s->handler = handler;
50 s->id = id++;
51 QTAILQ_INSERT_TAIL(&handlers, s, node);
Gerd Hoffmann4a33f452013-12-05 11:23:42 +010052
53 qemu_input_check_mode_change();
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010054 return s;
55}
56
57void qemu_input_handler_activate(QemuInputHandlerState *s)
58{
59 QTAILQ_REMOVE(&handlers, s, node);
60 QTAILQ_INSERT_HEAD(&handlers, s, node);
Gerd Hoffmann4a33f452013-12-05 11:23:42 +010061 qemu_input_check_mode_change();
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010062}
63
Gerd Hoffmann528728f2014-03-16 00:38:45 +010064void qemu_input_handler_deactivate(QemuInputHandlerState *s)
65{
66 QTAILQ_REMOVE(&handlers, s, node);
67 QTAILQ_INSERT_TAIL(&handlers, s, node);
68 qemu_input_check_mode_change();
69}
70
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010071void qemu_input_handler_unregister(QemuInputHandlerState *s)
72{
73 QTAILQ_REMOVE(&handlers, s, node);
74 g_free(s);
Gerd Hoffmann4a33f452013-12-05 11:23:42 +010075 qemu_input_check_mode_change();
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +010076}
77
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +020078void qemu_input_handler_bind(QemuInputHandlerState *s,
79 const char *device_id, int head,
80 Error **errp)
81{
82 DeviceState *dev;
83 QemuConsole *con;
84
85 dev = qdev_find_recursive(sysbus_get_default(), device_id);
86 if (dev == NULL) {
Markus Armbruster75158eb2015-03-16 08:57:47 +010087 error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
88 "Device '%s' not found", device_id);
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +020089 return;
90 }
91
92 con = qemu_console_lookup_by_device(dev, head);
93 if (con == NULL) {
94 error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
95 return;
96 }
97
98 s->con = con;
99}
100
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +0100101static QemuInputHandlerState*
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +0200102qemu_input_find_handler(uint32_t mask, QemuConsole *con)
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +0100103{
104 QemuInputHandlerState *s;
105
106 QTAILQ_FOREACH(s, &handlers, node) {
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +0200107 if (s->con == NULL || s->con != con) {
108 continue;
109 }
110 if (mask & s->handler->mask) {
111 return s;
112 }
113 }
114
115 QTAILQ_FOREACH(s, &handlers, node) {
116 if (s->con != NULL) {
117 continue;
118 }
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +0100119 if (mask & s->handler->mask) {
120 return s;
121 }
122 }
123 return NULL;
124}
125
Gerd Hoffmanndf5b2ad2014-11-25 14:54:17 +0100126void qmp_x_input_send_event(bool has_console, int64_t console,
127 InputEventList *events, Error **errp)
Marcelo Tosatti50c66172014-09-30 18:10:17 -0300128{
129 InputEventList *e;
130 QemuConsole *con;
131
Amos Kong51fc4472014-11-07 12:41:25 +0800132 con = NULL;
133 if (has_console) {
134 con = qemu_console_lookup_by_index(console);
135 if (!con) {
136 error_setg(errp, "console %" PRId64 " not found", console);
137 return;
138 }
Marcelo Tosatti50c66172014-09-30 18:10:17 -0300139 }
140
141 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
142 error_setg(errp, "VM not running");
143 return;
144 }
145
146 for (e = events; e != NULL; e = e->next) {
147 InputEvent *event = e->value;
148
149 if (!qemu_input_find_handler(1 << event->kind, con)) {
150 error_setg(errp, "Input handler not found for "
151 "event type %s",
152 InputEventKind_lookup[event->kind]);
153 return;
154 }
155 }
156
157 for (e = events; e != NULL; e = e->next) {
158 InputEvent *event = e->value;
159
160 qemu_input_event_send(con, event);
161 }
162
163 qemu_input_event_sync();
164}
165
Gerd Hoffmannd3535432013-11-28 11:29:33 +0100166static void qemu_input_transform_abs_rotate(InputEvent *evt)
167{
168 switch (graphic_rotate) {
169 case 90:
170 if (evt->abs->axis == INPUT_AXIS_X) {
171 evt->abs->axis = INPUT_AXIS_Y;
172 } else if (evt->abs->axis == INPUT_AXIS_Y) {
173 evt->abs->axis = INPUT_AXIS_X;
174 evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
175 }
176 break;
177 case 180:
178 evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
179 break;
180 case 270:
181 if (evt->abs->axis == INPUT_AXIS_X) {
182 evt->abs->axis = INPUT_AXIS_Y;
183 evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
184 } else if (evt->abs->axis == INPUT_AXIS_Y) {
185 evt->abs->axis = INPUT_AXIS_X;
186 }
187 break;
188 }
189}
190
Gerd Hoffmannc43ce552013-12-04 15:20:05 +0100191static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
192{
193 const char *name;
Gerd Hoffmann2386a902014-05-21 13:49:59 +0200194 int qcode, idx = -1;
Gerd Hoffmannc43ce552013-12-04 15:20:05 +0100195
196 if (src) {
197 idx = qemu_console_get_index(src);
198 }
199 switch (evt->kind) {
200 case INPUT_EVENT_KIND_KEY:
201 switch (evt->key->key->kind) {
202 case KEY_VALUE_KIND_NUMBER:
Gerd Hoffmann2386a902014-05-21 13:49:59 +0200203 qcode = qemu_input_key_number_to_qcode(evt->key->key->number);
204 name = QKeyCode_lookup[qcode];
Gerd Hoffmannc43ce552013-12-04 15:20:05 +0100205 trace_input_event_key_number(idx, evt->key->key->number,
Gerd Hoffmann2386a902014-05-21 13:49:59 +0200206 name, evt->key->down);
Gerd Hoffmannc43ce552013-12-04 15:20:05 +0100207 break;
208 case KEY_VALUE_KIND_QCODE:
209 name = QKeyCode_lookup[evt->key->key->qcode];
210 trace_input_event_key_qcode(idx, name, evt->key->down);
211 break;
212 case KEY_VALUE_KIND_MAX:
213 /* keep gcc happy */
214 break;
215 }
216 break;
217 case INPUT_EVENT_KIND_BTN:
218 name = InputButton_lookup[evt->btn->button];
219 trace_input_event_btn(idx, name, evt->btn->down);
220 break;
221 case INPUT_EVENT_KIND_REL:
222 name = InputAxis_lookup[evt->rel->axis];
223 trace_input_event_rel(idx, name, evt->rel->value);
224 break;
225 case INPUT_EVENT_KIND_ABS:
226 name = InputAxis_lookup[evt->abs->axis];
227 trace_input_event_abs(idx, name, evt->abs->value);
228 break;
229 case INPUT_EVENT_KIND_MAX:
230 /* keep gcc happy */
231 break;
232 }
233}
234
Gerd Hoffmannbe1a7172014-05-28 13:02:40 +0200235static void qemu_input_queue_process(void *opaque)
236{
237 struct QemuInputEventQueueHead *queue = opaque;
238 QemuInputEventQueue *item;
239
240 g_assert(!QTAILQ_EMPTY(queue));
241 item = QTAILQ_FIRST(queue);
242 g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
243 QTAILQ_REMOVE(queue, item, node);
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 g_free(item);
263 }
264}
265
266static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
267 QEMUTimer *timer, uint32_t delay_ms)
268{
269 QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
270 bool start_timer = QTAILQ_EMPTY(queue);
271
272 item->type = QEMU_INPUT_QUEUE_DELAY;
273 item->delay_ms = delay_ms;
274 item->timer = timer;
275 QTAILQ_INSERT_TAIL(queue, item, node);
276
277 if (start_timer) {
278 timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
279 + item->delay_ms);
280 }
281}
282
283static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
284 QemuConsole *src, InputEvent *evt)
285{
286 QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
287
288 item->type = QEMU_INPUT_QUEUE_EVENT;
289 item->src = src;
290 item->evt = evt;
291 QTAILQ_INSERT_TAIL(queue, item, node);
292}
293
294static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
295{
296 QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
297
298 item->type = QEMU_INPUT_QUEUE_SYNC;
299 QTAILQ_INSERT_TAIL(queue, item, node);
300}
301
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +0100302void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
303{
304 QemuInputHandlerState *s;
305
306 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
307 return;
308 }
309
Gerd Hoffmannc43ce552013-12-04 15:20:05 +0100310 qemu_input_event_trace(src, evt);
311
Gerd Hoffmannd3535432013-11-28 11:29:33 +0100312 /* pre processing */
313 if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
314 qemu_input_transform_abs_rotate(evt);
315 }
316
317 /* send event */
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +0200318 s = qemu_input_find_handler(1 << evt->kind, src);
Gerd Hoffmannbdcc3a22014-03-31 16:07:30 +0200319 if (!s) {
320 return;
321 }
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +0100322 s->handler->event(s->dev, src, evt);
323 s->events++;
324}
325
326void qemu_input_event_sync(void)
327{
328 QemuInputHandlerState *s;
329
330 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
331 return;
332 }
333
Gerd Hoffmannc43ce552013-12-04 15:20:05 +0100334 trace_input_event_sync();
335
Gerd Hoffmannc8b405b2013-11-27 10:35:26 +0100336 QTAILQ_FOREACH(s, &handlers, node) {
337 if (!s->events) {
338 continue;
339 }
340 if (s->handler->sync) {
341 s->handler->sync(s->dev);
342 }
343 s->events = 0;
344 }
345}
Gerd Hoffmann65671472013-11-27 11:38:47 +0100346
347InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
348{
349 InputEvent *evt = g_new0(InputEvent, 1);
350 evt->key = g_new0(InputKeyEvent, 1);
351 evt->kind = INPUT_EVENT_KIND_KEY;
352 evt->key->key = key;
353 evt->key->down = down;
354 return evt;
355}
356
357void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
358{
359 InputEvent *evt;
360 evt = qemu_input_event_new_key(key, down);
Gerd Hoffmannbe1a7172014-05-28 13:02:40 +0200361 if (QTAILQ_EMPTY(&kbd_queue)) {
362 qemu_input_event_send(src, evt);
363 qemu_input_event_sync();
364 qapi_free_InputEvent(evt);
365 } else {
366 qemu_input_queue_event(&kbd_queue, src, evt);
367 qemu_input_queue_sync(&kbd_queue);
368 }
Gerd Hoffmann65671472013-11-27 11:38:47 +0100369}
370
371void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
372{
373 KeyValue *key = g_new0(KeyValue, 1);
374 key->kind = KEY_VALUE_KIND_NUMBER;
375 key->number = num;
376 qemu_input_event_send_key(src, key, down);
377}
378
379void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
380{
381 KeyValue *key = g_new0(KeyValue, 1);
382 key->kind = KEY_VALUE_KIND_QCODE;
383 key->qcode = q;
384 qemu_input_event_send_key(src, key, down);
385}
Gerd Hoffmann43579402013-11-27 18:24:29 +0100386
Gerd Hoffmannbe1a7172014-05-28 13:02:40 +0200387void qemu_input_event_send_key_delay(uint32_t delay_ms)
388{
389 if (!kbd_timer) {
390 kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
391 &kbd_queue);
392 }
393 qemu_input_queue_delay(&kbd_queue, kbd_timer,
394 delay_ms ? delay_ms : kbd_default_delay_ms);
395}
396
Gerd Hoffmann43579402013-11-27 18:24:29 +0100397InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
398{
399 InputEvent *evt = g_new0(InputEvent, 1);
400 evt->btn = g_new0(InputBtnEvent, 1);
401 evt->kind = INPUT_EVENT_KIND_BTN;
402 evt->btn->button = btn;
403 evt->btn->down = down;
404 return evt;
405}
406
407void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
408{
409 InputEvent *evt;
410 evt = qemu_input_event_new_btn(btn, down);
411 qemu_input_event_send(src, evt);
412 qapi_free_InputEvent(evt);
413}
414
415void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
416 uint32_t button_old, uint32_t button_new)
417{
418 InputButton btn;
419 uint32_t mask;
420
421 for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
422 mask = button_map[btn];
423 if ((button_old & mask) == (button_new & mask)) {
424 continue;
425 }
426 qemu_input_queue_btn(src, btn, button_new & mask);
427 }
428}
429
Gerd Hoffmann502c8db2013-11-28 11:31:09 +0100430bool qemu_input_is_absolute(void)
431{
432 QemuInputHandlerState *s;
433
Gerd Hoffmann6f5943c2014-05-19 15:18:37 +0200434 s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
435 NULL);
Gerd Hoffmann502c8db2013-11-28 11:31:09 +0100436 return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
437}
438
Gerd Hoffmann43579402013-11-27 18:24:29 +0100439int qemu_input_scale_axis(int value, int size_in, int size_out)
440{
441 if (size_in < 2) {
442 return size_out / 2;
443 }
444 return (int64_t)value * (size_out - 1) / (size_in - 1);
445}
446
447InputEvent *qemu_input_event_new_move(InputEventKind kind,
448 InputAxis axis, int value)
449{
450 InputEvent *evt = g_new0(InputEvent, 1);
451 InputMoveEvent *move = g_new0(InputMoveEvent, 1);
452
453 evt->kind = kind;
454 evt->data = move;
455 move->axis = axis;
456 move->value = value;
457 return evt;
458}
459
460void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
461{
462 InputEvent *evt;
463 evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
464 qemu_input_event_send(src, evt);
465 qapi_free_InputEvent(evt);
466}
467
468void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
469{
470 InputEvent *evt;
471 int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
472 evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
473 qemu_input_event_send(src, evt);
474 qapi_free_InputEvent(evt);
475}
Gerd Hoffmann4a33f452013-12-05 11:23:42 +0100476
477void qemu_input_check_mode_change(void)
478{
479 static int current_is_absolute;
480 int is_absolute;
481
482 is_absolute = qemu_input_is_absolute();
483
484 if (is_absolute != current_is_absolute) {
Gerd Hoffmanna8dfb1c2013-12-05 11:24:14 +0100485 trace_input_mouse_mode(is_absolute);
Gerd Hoffmann4a33f452013-12-05 11:23:42 +0100486 notifier_list_notify(&mouse_mode_notifiers, NULL);
487 }
488
489 current_is_absolute = is_absolute;
490}
491
492void qemu_add_mouse_mode_change_notifier(Notifier *notify)
493{
494 notifier_list_add(&mouse_mode_notifiers, notify);
495}
496
497void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
498{
499 notifier_remove(notify);
500}
Gerd Hoffmanne842c682013-12-10 17:09:36 +0100501
502MouseInfoList *qmp_query_mice(Error **errp)
503{
504 MouseInfoList *mice_list = NULL;
505 MouseInfoList *info;
506 QemuInputHandlerState *s;
507 bool current = true;
508
509 QTAILQ_FOREACH(s, &handlers, node) {
510 if (!(s->handler->mask &
511 (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
512 continue;
513 }
514
515 info = g_new0(MouseInfoList, 1);
516 info->value = g_new0(MouseInfo, 1);
517 info->value->index = s->id;
518 info->value->name = g_strdup(s->handler->name);
519 info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
520 info->value->current = current;
521
522 current = false;
523 info->next = mice_list;
524 mice_list = info;
525 }
526
527 return mice_list;
528}
Gerd Hoffmann70b52f62013-12-10 17:16:03 +0100529
Markus Armbruster3e5a50d2015-02-06 13:55:43 +0100530void hmp_mouse_set(Monitor *mon, const QDict *qdict)
Gerd Hoffmann70b52f62013-12-10 17:16:03 +0100531{
532 QemuInputHandlerState *s;
533 int index = qdict_get_int(qdict, "index");
534 int found = 0;
535
536 QTAILQ_FOREACH(s, &handlers, node) {
Hani Benhabiles0419f782014-03-31 23:09:06 +0100537 if (s->id != index) {
538 continue;
Gerd Hoffmann70b52f62013-12-10 17:16:03 +0100539 }
Hani Benhabiles0419f782014-03-31 23:09:06 +0100540 if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
541 INPUT_EVENT_MASK_ABS))) {
542 error_report("Input device '%s' is not a mouse", s->handler->name);
543 return;
544 }
545 found = 1;
546 qemu_input_handler_activate(s);
547 break;
Gerd Hoffmann70b52f62013-12-10 17:16:03 +0100548 }
549
550 if (!found) {
Hani Benhabiles0419f782014-03-31 23:09:06 +0100551 error_report("Mouse at index '%d' not found", index);
Gerd Hoffmann70b52f62013-12-10 17:16:03 +0100552 }
553
554 qemu_input_check_mode_change();
555}