2 #include "sysemu/sysemu.h"
3 #include "qapi-types.h"
4 #include "qemu/error-report.h"
5 #include "qmp-commands.h"
8 #include "ui/console.h"
9 #include "sysemu/replay.h"
11 struct QemuInputHandlerState
{
13 QemuInputHandler
*handler
;
17 QTAILQ_ENTRY(QemuInputHandlerState
) node
;
20 typedef struct QemuInputEventQueue QemuInputEventQueue
;
21 struct QemuInputEventQueue
{
23 QEMU_INPUT_QUEUE_DELAY
= 1,
24 QEMU_INPUT_QUEUE_EVENT
,
25 QEMU_INPUT_QUEUE_SYNC
,
31 QTAILQ_ENTRY(QemuInputEventQueue
) node
;
34 static QTAILQ_HEAD(, QemuInputHandlerState
) handlers
=
35 QTAILQ_HEAD_INITIALIZER(handlers
);
36 static NotifierList mouse_mode_notifiers
=
37 NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers
);
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;
44 QemuInputHandlerState
*qemu_input_handler_register(DeviceState
*dev
,
45 QemuInputHandler
*handler
)
47 QemuInputHandlerState
*s
= g_new0(QemuInputHandlerState
, 1);
53 QTAILQ_INSERT_TAIL(&handlers
, s
, node
);
55 qemu_input_check_mode_change();
59 void qemu_input_handler_activate(QemuInputHandlerState
*s
)
61 QTAILQ_REMOVE(&handlers
, s
, node
);
62 QTAILQ_INSERT_HEAD(&handlers
, s
, node
);
63 qemu_input_check_mode_change();
66 void qemu_input_handler_deactivate(QemuInputHandlerState
*s
)
68 QTAILQ_REMOVE(&handlers
, s
, node
);
69 QTAILQ_INSERT_TAIL(&handlers
, s
, node
);
70 qemu_input_check_mode_change();
73 void qemu_input_handler_unregister(QemuInputHandlerState
*s
)
75 QTAILQ_REMOVE(&handlers
, s
, node
);
77 qemu_input_check_mode_change();
80 void qemu_input_handler_bind(QemuInputHandlerState
*s
,
81 const char *device_id
, int head
,
87 dev
= qdev_find_recursive(sysbus_get_default(), device_id
);
89 error_set(errp
, ERROR_CLASS_DEVICE_NOT_FOUND
,
90 "Device '%s' not found", device_id
);
94 con
= qemu_console_lookup_by_device(dev
, head
);
96 error_setg(errp
, "Device %s is not bound to a QemuConsole", device_id
);
103 static QemuInputHandlerState
*
104 qemu_input_find_handler(uint32_t mask
, QemuConsole
*con
)
106 QemuInputHandlerState
*s
;
108 QTAILQ_FOREACH(s
, &handlers
, node
) {
109 if (s
->con
== NULL
|| s
->con
!= con
) {
112 if (mask
& s
->handler
->mask
) {
117 QTAILQ_FOREACH(s
, &handlers
, node
) {
118 if (s
->con
!= NULL
) {
121 if (mask
& s
->handler
->mask
) {
128 void qmp_x_input_send_event(bool has_console
, int64_t console
,
129 InputEventList
*events
, Error
**errp
)
136 con
= qemu_console_lookup_by_index(console
);
138 error_setg(errp
, "console %" PRId64
" not found", console
);
143 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED
)) {
144 error_setg(errp
, "VM not running");
148 for (e
= events
; e
!= NULL
; e
= e
->next
) {
149 InputEvent
*event
= e
->value
;
151 if (!qemu_input_find_handler(1 << event
->type
, con
)) {
152 error_setg(errp
, "Input handler not found for "
154 InputEventKind_lookup
[event
->type
]);
159 for (e
= events
; e
!= NULL
; e
= e
->next
) {
160 InputEvent
*event
= e
->value
;
162 qemu_input_event_send(con
, event
);
165 qemu_input_event_sync();
168 static void qemu_input_transform_abs_rotate(InputEvent
*evt
)
170 switch (graphic_rotate
) {
172 if (evt
->u
.abs
->axis
== INPUT_AXIS_X
) {
173 evt
->u
.abs
->axis
= INPUT_AXIS_Y
;
174 } else if (evt
->u
.abs
->axis
== INPUT_AXIS_Y
) {
175 evt
->u
.abs
->axis
= INPUT_AXIS_X
;
176 evt
->u
.abs
->value
= INPUT_EVENT_ABS_SIZE
- 1 - evt
->u
.abs
->value
;
180 evt
->u
.abs
->value
= INPUT_EVENT_ABS_SIZE
- 1 - evt
->u
.abs
->value
;
183 if (evt
->u
.abs
->axis
== INPUT_AXIS_X
) {
184 evt
->u
.abs
->axis
= INPUT_AXIS_Y
;
185 evt
->u
.abs
->value
= INPUT_EVENT_ABS_SIZE
- 1 - evt
->u
.abs
->value
;
186 } else if (evt
->u
.abs
->axis
== INPUT_AXIS_Y
) {
187 evt
->u
.abs
->axis
= INPUT_AXIS_X
;
193 static void qemu_input_event_trace(QemuConsole
*src
, InputEvent
*evt
)
199 idx
= qemu_console_get_index(src
);
202 case INPUT_EVENT_KIND_KEY
:
203 switch (evt
->u
.key
->key
->type
) {
204 case KEY_VALUE_KIND_NUMBER
:
205 qcode
= qemu_input_key_number_to_qcode(evt
->u
.key
->key
->u
.number
);
206 name
= QKeyCode_lookup
[qcode
];
207 trace_input_event_key_number(idx
, evt
->u
.key
->key
->u
.number
,
208 name
, evt
->u
.key
->down
);
210 case KEY_VALUE_KIND_QCODE
:
211 name
= QKeyCode_lookup
[evt
->u
.key
->key
->u
.qcode
];
212 trace_input_event_key_qcode(idx
, name
, evt
->u
.key
->down
);
214 case KEY_VALUE_KIND_MAX
:
219 case INPUT_EVENT_KIND_BTN
:
220 name
= InputButton_lookup
[evt
->u
.btn
->button
];
221 trace_input_event_btn(idx
, name
, evt
->u
.btn
->down
);
223 case INPUT_EVENT_KIND_REL
:
224 name
= InputAxis_lookup
[evt
->u
.rel
->axis
];
225 trace_input_event_rel(idx
, name
, evt
->u
.rel
->value
);
227 case INPUT_EVENT_KIND_ABS
:
228 name
= InputAxis_lookup
[evt
->u
.abs
->axis
];
229 trace_input_event_abs(idx
, name
, evt
->u
.abs
->value
);
231 case INPUT_EVENT_KIND_MAX
:
237 static void qemu_input_queue_process(void *opaque
)
239 struct QemuInputEventQueueHead
*queue
= opaque
;
240 QemuInputEventQueue
*item
;
242 g_assert(!QTAILQ_EMPTY(queue
));
243 item
= QTAILQ_FIRST(queue
);
244 g_assert(item
->type
== QEMU_INPUT_QUEUE_DELAY
);
245 QTAILQ_REMOVE(queue
, item
, node
);
248 while (!QTAILQ_EMPTY(queue
)) {
249 item
= QTAILQ_FIRST(queue
);
250 switch (item
->type
) {
251 case QEMU_INPUT_QUEUE_DELAY
:
252 timer_mod(item
->timer
, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
)
255 case QEMU_INPUT_QUEUE_EVENT
:
256 qemu_input_event_send(item
->src
, item
->evt
);
257 qapi_free_InputEvent(item
->evt
);
259 case QEMU_INPUT_QUEUE_SYNC
:
260 qemu_input_event_sync();
263 QTAILQ_REMOVE(queue
, item
, node
);
268 static void qemu_input_queue_delay(struct QemuInputEventQueueHead
*queue
,
269 QEMUTimer
*timer
, uint32_t delay_ms
)
271 QemuInputEventQueue
*item
= g_new0(QemuInputEventQueue
, 1);
272 bool start_timer
= QTAILQ_EMPTY(queue
);
274 item
->type
= QEMU_INPUT_QUEUE_DELAY
;
275 item
->delay_ms
= delay_ms
;
277 QTAILQ_INSERT_TAIL(queue
, item
, node
);
280 timer_mod(item
->timer
, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL
)
285 static void qemu_input_queue_event(struct QemuInputEventQueueHead
*queue
,
286 QemuConsole
*src
, InputEvent
*evt
)
288 QemuInputEventQueue
*item
= g_new0(QemuInputEventQueue
, 1);
290 item
->type
= QEMU_INPUT_QUEUE_EVENT
;
293 QTAILQ_INSERT_TAIL(queue
, item
, node
);
296 static void qemu_input_queue_sync(struct QemuInputEventQueueHead
*queue
)
298 QemuInputEventQueue
*item
= g_new0(QemuInputEventQueue
, 1);
300 item
->type
= QEMU_INPUT_QUEUE_SYNC
;
301 QTAILQ_INSERT_TAIL(queue
, item
, node
);
304 void qemu_input_event_send_impl(QemuConsole
*src
, InputEvent
*evt
)
306 QemuInputHandlerState
*s
;
308 qemu_input_event_trace(src
, evt
);
311 if (graphic_rotate
&& (evt
->type
== INPUT_EVENT_KIND_ABS
)) {
312 qemu_input_transform_abs_rotate(evt
);
316 s
= qemu_input_find_handler(1 << evt
->type
, src
);
320 s
->handler
->event(s
->dev
, src
, evt
);
324 void qemu_input_event_send(QemuConsole
*src
, InputEvent
*evt
)
326 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED
)) {
330 replay_input_event(src
, evt
);
333 void qemu_input_event_sync_impl(void)
335 QemuInputHandlerState
*s
;
337 trace_input_event_sync();
339 QTAILQ_FOREACH(s
, &handlers
, node
) {
343 if (s
->handler
->sync
) {
344 s
->handler
->sync(s
->dev
);
350 void qemu_input_event_sync(void)
352 if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED
)) {
356 replay_input_sync_event();
359 InputEvent
*qemu_input_event_new_key(KeyValue
*key
, bool down
)
361 InputEvent
*evt
= g_new0(InputEvent
, 1);
362 evt
->u
.key
= g_new0(InputKeyEvent
, 1);
363 evt
->type
= INPUT_EVENT_KIND_KEY
;
364 evt
->u
.key
->key
= key
;
365 evt
->u
.key
->down
= down
;
369 void qemu_input_event_send_key(QemuConsole
*src
, KeyValue
*key
, bool down
)
372 evt
= qemu_input_event_new_key(key
, down
);
373 if (QTAILQ_EMPTY(&kbd_queue
)) {
374 qemu_input_event_send(src
, evt
);
375 qemu_input_event_sync();
376 qapi_free_InputEvent(evt
);
378 qemu_input_queue_event(&kbd_queue
, src
, evt
);
379 qemu_input_queue_sync(&kbd_queue
);
383 void qemu_input_event_send_key_number(QemuConsole
*src
, int num
, bool down
)
385 KeyValue
*key
= g_new0(KeyValue
, 1);
386 key
->type
= KEY_VALUE_KIND_NUMBER
;
388 qemu_input_event_send_key(src
, key
, down
);
391 void qemu_input_event_send_key_qcode(QemuConsole
*src
, QKeyCode q
, bool down
)
393 KeyValue
*key
= g_new0(KeyValue
, 1);
394 key
->type
= KEY_VALUE_KIND_QCODE
;
396 qemu_input_event_send_key(src
, key
, down
);
399 void qemu_input_event_send_key_delay(uint32_t delay_ms
)
402 kbd_timer
= timer_new_ms(QEMU_CLOCK_VIRTUAL
, qemu_input_queue_process
,
405 qemu_input_queue_delay(&kbd_queue
, kbd_timer
,
406 delay_ms
? delay_ms
: kbd_default_delay_ms
);
409 InputEvent
*qemu_input_event_new_btn(InputButton btn
, bool down
)
411 InputEvent
*evt
= g_new0(InputEvent
, 1);
412 evt
->u
.btn
= g_new0(InputBtnEvent
, 1);
413 evt
->type
= INPUT_EVENT_KIND_BTN
;
414 evt
->u
.btn
->button
= btn
;
415 evt
->u
.btn
->down
= down
;
419 void qemu_input_queue_btn(QemuConsole
*src
, InputButton btn
, bool down
)
422 evt
= qemu_input_event_new_btn(btn
, down
);
423 qemu_input_event_send(src
, evt
);
424 qapi_free_InputEvent(evt
);
427 void qemu_input_update_buttons(QemuConsole
*src
, uint32_t *button_map
,
428 uint32_t button_old
, uint32_t button_new
)
433 for (btn
= 0; btn
< INPUT_BUTTON_MAX
; btn
++) {
434 mask
= button_map
[btn
];
435 if ((button_old
& mask
) == (button_new
& mask
)) {
438 qemu_input_queue_btn(src
, btn
, button_new
& mask
);
442 bool qemu_input_is_absolute(void)
444 QemuInputHandlerState
*s
;
446 s
= qemu_input_find_handler(INPUT_EVENT_MASK_REL
| INPUT_EVENT_MASK_ABS
,
448 return (s
!= NULL
) && (s
->handler
->mask
& INPUT_EVENT_MASK_ABS
);
451 int qemu_input_scale_axis(int value
, int size_in
, int size_out
)
456 return (int64_t)value
* (size_out
- 1) / (size_in
- 1);
459 InputEvent
*qemu_input_event_new_move(InputEventKind kind
,
460 InputAxis axis
, int value
)
462 InputEvent
*evt
= g_new0(InputEvent
, 1);
463 InputMoveEvent
*move
= g_new0(InputMoveEvent
, 1);
472 void qemu_input_queue_rel(QemuConsole
*src
, InputAxis axis
, int value
)
475 evt
= qemu_input_event_new_move(INPUT_EVENT_KIND_REL
, axis
, value
);
476 qemu_input_event_send(src
, evt
);
477 qapi_free_InputEvent(evt
);
480 void qemu_input_queue_abs(QemuConsole
*src
, InputAxis axis
, int value
, int size
)
483 int scaled
= qemu_input_scale_axis(value
, size
, INPUT_EVENT_ABS_SIZE
);
484 evt
= qemu_input_event_new_move(INPUT_EVENT_KIND_ABS
, axis
, scaled
);
485 qemu_input_event_send(src
, evt
);
486 qapi_free_InputEvent(evt
);
489 void qemu_input_check_mode_change(void)
491 static int current_is_absolute
;
494 is_absolute
= qemu_input_is_absolute();
496 if (is_absolute
!= current_is_absolute
) {
497 trace_input_mouse_mode(is_absolute
);
498 notifier_list_notify(&mouse_mode_notifiers
, NULL
);
501 current_is_absolute
= is_absolute
;
504 void qemu_add_mouse_mode_change_notifier(Notifier
*notify
)
506 notifier_list_add(&mouse_mode_notifiers
, notify
);
509 void qemu_remove_mouse_mode_change_notifier(Notifier
*notify
)
511 notifier_remove(notify
);
514 MouseInfoList
*qmp_query_mice(Error
**errp
)
516 MouseInfoList
*mice_list
= NULL
;
518 QemuInputHandlerState
*s
;
521 QTAILQ_FOREACH(s
, &handlers
, node
) {
522 if (!(s
->handler
->mask
&
523 (INPUT_EVENT_MASK_REL
| INPUT_EVENT_MASK_ABS
))) {
527 info
= g_new0(MouseInfoList
, 1);
528 info
->value
= g_new0(MouseInfo
, 1);
529 info
->value
->index
= s
->id
;
530 info
->value
->name
= g_strdup(s
->handler
->name
);
531 info
->value
->absolute
= s
->handler
->mask
& INPUT_EVENT_MASK_ABS
;
532 info
->value
->current
= current
;
535 info
->next
= mice_list
;
542 void hmp_mouse_set(Monitor
*mon
, const QDict
*qdict
)
544 QemuInputHandlerState
*s
;
545 int index
= qdict_get_int(qdict
, "index");
548 QTAILQ_FOREACH(s
, &handlers
, node
) {
549 if (s
->id
!= index
) {
552 if (!(s
->handler
->mask
& (INPUT_EVENT_MASK_REL
|
553 INPUT_EVENT_MASK_ABS
))) {
554 error_report("Input device '%s' is not a mouse", s
->handler
->name
);
558 qemu_input_handler_activate(s
);
563 error_report("Mouse at index '%d' not found", index
);
566 qemu_input_check_mode_change();