xref: /openbmc/qemu/ui/input.c (revision f774a677507966222624a9b2859f06ede7608100)
1e16f4c87SPeter Maydell #include "qemu/osdep.h"
2c8b405b6SGerd Hoffmann #include "sysemu/sysemu.h"
3e688df6bSMarkus Armbruster #include "qapi/error.h"
49af23989SMarkus Armbruster #include "qapi/qapi-commands-ui.h"
5c43ce551SGerd Hoffmann #include "trace.h"
6c8b405b6SGerd Hoffmann #include "ui/input.h"
7c43ce551SGerd Hoffmann #include "ui/console.h"
8ee312992SPavel Dovgalyuk #include "sysemu/replay.h"
954d31236SMarkus Armbruster #include "sysemu/runstate.h"
10c8b405b6SGerd Hoffmann 
11c8b405b6SGerd Hoffmann struct QemuInputHandlerState {
12c8b405b6SGerd Hoffmann     DeviceState       *dev;
13*b1be65f6SPhilippe Mathieu-Daudé     const QemuInputHandler *handler;
14c8b405b6SGerd Hoffmann     int               id;
15c8b405b6SGerd Hoffmann     int               events;
166f5943cfSGerd Hoffmann     QemuConsole       *con;
17c8b405b6SGerd Hoffmann     QTAILQ_ENTRY(QemuInputHandlerState) node;
18c8b405b6SGerd Hoffmann };
19be1a7176SGerd Hoffmann 
20be1a7176SGerd Hoffmann typedef struct QemuInputEventQueue QemuInputEventQueue;
21f481ee2dSPaolo Bonzini typedef QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue)
22f481ee2dSPaolo Bonzini     QemuInputEventQueueHead;
23f481ee2dSPaolo Bonzini 
24be1a7176SGerd Hoffmann struct QemuInputEventQueue {
25be1a7176SGerd Hoffmann     enum {
26be1a7176SGerd Hoffmann         QEMU_INPUT_QUEUE_DELAY = 1,
27be1a7176SGerd Hoffmann         QEMU_INPUT_QUEUE_EVENT,
28be1a7176SGerd Hoffmann         QEMU_INPUT_QUEUE_SYNC,
29be1a7176SGerd Hoffmann     } type;
30be1a7176SGerd Hoffmann     QEMUTimer *timer;
31be1a7176SGerd Hoffmann     uint32_t delay_ms;
32be1a7176SGerd Hoffmann     QemuConsole *src;
33be1a7176SGerd Hoffmann     InputEvent *evt;
34be1a7176SGerd Hoffmann     QTAILQ_ENTRY(QemuInputEventQueue) node;
35be1a7176SGerd Hoffmann };
36be1a7176SGerd Hoffmann 
37c8b405b6SGerd Hoffmann static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
38c8b405b6SGerd Hoffmann     QTAILQ_HEAD_INITIALIZER(handlers);
394a33f45eSGerd Hoffmann static NotifierList mouse_mode_notifiers =
404a33f45eSGerd Hoffmann     NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
41c8b405b6SGerd Hoffmann 
42f481ee2dSPaolo Bonzini static QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
43be1a7176SGerd Hoffmann static QEMUTimer *kbd_timer;
44be1a7176SGerd Hoffmann static uint32_t kbd_default_delay_ms = 10;
45fa18f36aSGerd Hoffmann static uint32_t queue_count;
46fa18f36aSGerd Hoffmann static uint32_t queue_limit = 1024;
47be1a7176SGerd Hoffmann 
qemu_input_handler_register(DeviceState * dev,const QemuInputHandler * handler)48c8b405b6SGerd Hoffmann QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
49*b1be65f6SPhilippe Mathieu-Daudé                                             const QemuInputHandler *handler)
50c8b405b6SGerd Hoffmann {
51c8b405b6SGerd Hoffmann     QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
52c8b405b6SGerd Hoffmann     static int id = 1;
53c8b405b6SGerd Hoffmann 
54c8b405b6SGerd Hoffmann     s->dev = dev;
55c8b405b6SGerd Hoffmann     s->handler = handler;
56c8b405b6SGerd Hoffmann     s->id = id++;
57c8b405b6SGerd Hoffmann     QTAILQ_INSERT_TAIL(&handlers, s, node);
584a33f45eSGerd Hoffmann 
590337e412SAkihiko Odaki     notifier_list_notify(&mouse_mode_notifiers, NULL);
60c8b405b6SGerd Hoffmann     return s;
61c8b405b6SGerd Hoffmann }
62c8b405b6SGerd Hoffmann 
qemu_input_handler_activate(QemuInputHandlerState * s)63c8b405b6SGerd Hoffmann void qemu_input_handler_activate(QemuInputHandlerState *s)
64c8b405b6SGerd Hoffmann {
65c8b405b6SGerd Hoffmann     QTAILQ_REMOVE(&handlers, s, node);
66c8b405b6SGerd Hoffmann     QTAILQ_INSERT_HEAD(&handlers, s, node);
670337e412SAkihiko Odaki     notifier_list_notify(&mouse_mode_notifiers, NULL);
68c8b405b6SGerd Hoffmann }
69c8b405b6SGerd Hoffmann 
qemu_input_handler_deactivate(QemuInputHandlerState * s)70528728fdSGerd Hoffmann void qemu_input_handler_deactivate(QemuInputHandlerState *s)
71528728fdSGerd Hoffmann {
72528728fdSGerd Hoffmann     QTAILQ_REMOVE(&handlers, s, node);
73528728fdSGerd Hoffmann     QTAILQ_INSERT_TAIL(&handlers, s, node);
740337e412SAkihiko Odaki     notifier_list_notify(&mouse_mode_notifiers, NULL);
75528728fdSGerd Hoffmann }
76528728fdSGerd Hoffmann 
qemu_input_handler_unregister(QemuInputHandlerState * s)77c8b405b6SGerd Hoffmann void qemu_input_handler_unregister(QemuInputHandlerState *s)
78c8b405b6SGerd Hoffmann {
79c8b405b6SGerd Hoffmann     QTAILQ_REMOVE(&handlers, s, node);
80c8b405b6SGerd Hoffmann     g_free(s);
810337e412SAkihiko Odaki     notifier_list_notify(&mouse_mode_notifiers, NULL);
82c8b405b6SGerd Hoffmann }
83c8b405b6SGerd Hoffmann 
qemu_input_handler_bind(QemuInputHandlerState * s,const char * device_id,int head,Error ** errp)846f5943cfSGerd Hoffmann void qemu_input_handler_bind(QemuInputHandlerState *s,
856f5943cfSGerd Hoffmann                              const char *device_id, int head,
866f5943cfSGerd Hoffmann                              Error **errp)
876f5943cfSGerd Hoffmann {
886f5943cfSGerd Hoffmann     QemuConsole *con;
89f2c1d54cSGerd Hoffmann     Error *err = NULL;
906f5943cfSGerd Hoffmann 
91f2c1d54cSGerd Hoffmann     con = qemu_console_lookup_by_device_name(device_id, head, &err);
92f2c1d54cSGerd Hoffmann     if (err) {
93f2c1d54cSGerd Hoffmann         error_propagate(errp, err);
946f5943cfSGerd Hoffmann         return;
956f5943cfSGerd Hoffmann     }
966f5943cfSGerd Hoffmann 
976f5943cfSGerd Hoffmann     s->con = con;
986f5943cfSGerd Hoffmann }
996f5943cfSGerd Hoffmann 
100c8b405b6SGerd Hoffmann static QemuInputHandlerState*
qemu_input_find_handler(uint32_t mask,QemuConsole * con)1016f5943cfSGerd Hoffmann qemu_input_find_handler(uint32_t mask, QemuConsole *con)
102c8b405b6SGerd Hoffmann {
103c8b405b6SGerd Hoffmann     QemuInputHandlerState *s;
104c8b405b6SGerd Hoffmann 
105c8b405b6SGerd Hoffmann     QTAILQ_FOREACH(s, &handlers, node) {
1066f5943cfSGerd Hoffmann         if (s->con == NULL || s->con != con) {
1076f5943cfSGerd Hoffmann             continue;
1086f5943cfSGerd Hoffmann         }
1096f5943cfSGerd Hoffmann         if (mask & s->handler->mask) {
1106f5943cfSGerd Hoffmann             return s;
1116f5943cfSGerd Hoffmann         }
1126f5943cfSGerd Hoffmann     }
1136f5943cfSGerd Hoffmann 
1146f5943cfSGerd Hoffmann     QTAILQ_FOREACH(s, &handlers, node) {
1156f5943cfSGerd Hoffmann         if (s->con != NULL) {
1166f5943cfSGerd Hoffmann             continue;
1176f5943cfSGerd Hoffmann         }
118c8b405b6SGerd Hoffmann         if (mask & s->handler->mask) {
119c8b405b6SGerd Hoffmann             return s;
120c8b405b6SGerd Hoffmann         }
121c8b405b6SGerd Hoffmann     }
122c8b405b6SGerd Hoffmann     return NULL;
123c8b405b6SGerd Hoffmann }
124c8b405b6SGerd Hoffmann 
qmp_input_send_event(const char * device,bool has_head,int64_t head,InputEventList * events,Error ** errp)1253f41a3adSMarkus Armbruster void qmp_input_send_event(const char *device,
126b98d26e3SGerd Hoffmann                           bool has_head, int64_t head,
12751fc4476SAmos Kong                           InputEventList *events, Error **errp)
12850c6617fSMarcelo Tosatti {
12950c6617fSMarcelo Tosatti     InputEventList *e;
13050c6617fSMarcelo Tosatti     QemuConsole *con;
131b98d26e3SGerd Hoffmann     Error *err = NULL;
13250c6617fSMarcelo Tosatti 
13351fc4476SAmos Kong     con = NULL;
1343f41a3adSMarkus Armbruster     if (device) {
135b98d26e3SGerd Hoffmann         if (!has_head) {
136b98d26e3SGerd Hoffmann             head = 0;
137b98d26e3SGerd Hoffmann         }
138b98d26e3SGerd Hoffmann         con = qemu_console_lookup_by_device_name(device, head, &err);
139b98d26e3SGerd Hoffmann         if (err) {
140b98d26e3SGerd Hoffmann             error_propagate(errp, err);
14150c6617fSMarcelo Tosatti             return;
14250c6617fSMarcelo Tosatti         }
14351fc4476SAmos Kong     }
14450c6617fSMarcelo Tosatti 
14550c6617fSMarcelo Tosatti     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
14650c6617fSMarcelo Tosatti         error_setg(errp, "VM not running");
14750c6617fSMarcelo Tosatti         return;
14850c6617fSMarcelo Tosatti     }
14950c6617fSMarcelo Tosatti 
15050c6617fSMarcelo Tosatti     for (e = events; e != NULL; e = e->next) {
15150c6617fSMarcelo Tosatti         InputEvent *event = e->value;
15250c6617fSMarcelo Tosatti 
153568c73a4SEric Blake         if (!qemu_input_find_handler(1 << event->type, con)) {
15450c6617fSMarcelo Tosatti             error_setg(errp, "Input handler not found for "
15550c6617fSMarcelo Tosatti                              "event type %s",
156977c736fSMarkus Armbruster                             InputEventKind_str(event->type));
15750c6617fSMarcelo Tosatti             return;
15850c6617fSMarcelo Tosatti         }
15950c6617fSMarcelo Tosatti     }
16050c6617fSMarcelo Tosatti 
16150c6617fSMarcelo Tosatti     for (e = events; e != NULL; e = e->next) {
162af07e5ffSDaniel P. Berrange         InputEvent *evt = e->value;
16350c6617fSMarcelo Tosatti 
164af07e5ffSDaniel P. Berrange         if (evt->type == INPUT_EVENT_KIND_KEY &&
165af07e5ffSDaniel P. Berrange             evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER) {
166af07e5ffSDaniel P. Berrange             KeyValue *key = evt->u.key.data->key;
167237925baSDaniel P. Berrange             QKeyCode code = qemu_input_key_number_to_qcode(key->u.number.data);
168af07e5ffSDaniel P. Berrange             qemu_input_event_send_key_qcode(con, code, evt->u.key.data->down);
169af07e5ffSDaniel P. Berrange         } else {
170af07e5ffSDaniel P. Berrange             qemu_input_event_send(con, evt);
171af07e5ffSDaniel P. Berrange         }
17250c6617fSMarcelo Tosatti     }
17350c6617fSMarcelo Tosatti 
17450c6617fSMarcelo Tosatti     qemu_input_event_sync();
17550c6617fSMarcelo Tosatti }
17650c6617fSMarcelo Tosatti 
qemu_input_event_trace(QemuConsole * src,InputEvent * evt)177c43ce551SGerd Hoffmann static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
178c43ce551SGerd Hoffmann {
179c43ce551SGerd Hoffmann     const char *name;
1802386a907SGerd Hoffmann     int qcode, idx = -1;
181b5a1b443SEric Blake     InputKeyEvent *key;
182b5a1b443SEric Blake     InputBtnEvent *btn;
183b5a1b443SEric Blake     InputMoveEvent *move;
1842bfb10dfSSergio Lopez     InputMultiTouchEvent *mtt;
185c43ce551SGerd Hoffmann 
186c43ce551SGerd Hoffmann     if (src) {
187c43ce551SGerd Hoffmann         idx = qemu_console_get_index(src);
188c43ce551SGerd Hoffmann     }
189568c73a4SEric Blake     switch (evt->type) {
190c43ce551SGerd Hoffmann     case INPUT_EVENT_KIND_KEY:
19132bafa8fSEric Blake         key = evt->u.key.data;
192b5a1b443SEric Blake         switch (key->key->type) {
193c43ce551SGerd Hoffmann         case KEY_VALUE_KIND_NUMBER:
19432bafa8fSEric Blake             qcode = qemu_input_key_number_to_qcode(key->key->u.number.data);
195977c736fSMarkus Armbruster             name = QKeyCode_str(qcode);
19632bafa8fSEric Blake             trace_input_event_key_number(idx, key->key->u.number.data,
197b5a1b443SEric Blake                                          name, key->down);
198c43ce551SGerd Hoffmann             break;
199c43ce551SGerd Hoffmann         case KEY_VALUE_KIND_QCODE:
200977c736fSMarkus Armbruster             name = QKeyCode_str(key->key->u.qcode.data);
201b5a1b443SEric Blake             trace_input_event_key_qcode(idx, name, key->down);
202c43ce551SGerd Hoffmann             break;
2037fb1cf16SEric Blake         case KEY_VALUE_KIND__MAX:
204c43ce551SGerd Hoffmann             /* keep gcc happy */
205c43ce551SGerd Hoffmann             break;
206c43ce551SGerd Hoffmann         }
207c43ce551SGerd Hoffmann         break;
208c43ce551SGerd Hoffmann     case INPUT_EVENT_KIND_BTN:
20932bafa8fSEric Blake         btn = evt->u.btn.data;
210977c736fSMarkus Armbruster         name = InputButton_str(btn->button);
211b5a1b443SEric Blake         trace_input_event_btn(idx, name, btn->down);
212c43ce551SGerd Hoffmann         break;
213c43ce551SGerd Hoffmann     case INPUT_EVENT_KIND_REL:
21432bafa8fSEric Blake         move = evt->u.rel.data;
215977c736fSMarkus Armbruster         name = InputAxis_str(move->axis);
216b5a1b443SEric Blake         trace_input_event_rel(idx, name, move->value);
217c43ce551SGerd Hoffmann         break;
218c43ce551SGerd Hoffmann     case INPUT_EVENT_KIND_ABS:
21932bafa8fSEric Blake         move = evt->u.abs.data;
220977c736fSMarkus Armbruster         name = InputAxis_str(move->axis);
221b5a1b443SEric Blake         trace_input_event_abs(idx, name, move->value);
222c43ce551SGerd Hoffmann         break;
2232bfb10dfSSergio Lopez     case INPUT_EVENT_KIND_MTT:
2242bfb10dfSSergio Lopez         mtt = evt->u.mtt.data;
2252bfb10dfSSergio Lopez         name = InputAxis_str(mtt->axis);
2262bfb10dfSSergio Lopez         trace_input_event_mtt(idx, name, mtt->value);
2272bfb10dfSSergio Lopez         break;
2287fb1cf16SEric Blake     case INPUT_EVENT_KIND__MAX:
229c43ce551SGerd Hoffmann         /* keep gcc happy */
230c43ce551SGerd Hoffmann         break;
231c43ce551SGerd Hoffmann     }
232c43ce551SGerd Hoffmann }
233c43ce551SGerd Hoffmann 
qemu_input_queue_process(void * opaque)234be1a7176SGerd Hoffmann static void qemu_input_queue_process(void *opaque)
235be1a7176SGerd Hoffmann {
236f481ee2dSPaolo Bonzini     QemuInputEventQueueHead *queue = opaque;
237be1a7176SGerd Hoffmann     QemuInputEventQueue *item;
238be1a7176SGerd Hoffmann 
239be1a7176SGerd Hoffmann     g_assert(!QTAILQ_EMPTY(queue));
240be1a7176SGerd Hoffmann     item = QTAILQ_FIRST(queue);
241be1a7176SGerd Hoffmann     g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
242be1a7176SGerd Hoffmann     QTAILQ_REMOVE(queue, item, node);
24377b0359bSAlexander Graf     queue_count--;
244be1a7176SGerd Hoffmann     g_free(item);
245be1a7176SGerd Hoffmann 
246be1a7176SGerd Hoffmann     while (!QTAILQ_EMPTY(queue)) {
247be1a7176SGerd Hoffmann         item = QTAILQ_FIRST(queue);
248be1a7176SGerd Hoffmann         switch (item->type) {
249be1a7176SGerd Hoffmann         case QEMU_INPUT_QUEUE_DELAY:
25005ff8dc3SArtem Pisarenko             timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
251be1a7176SGerd Hoffmann                       + item->delay_ms);
252be1a7176SGerd Hoffmann             return;
253be1a7176SGerd Hoffmann         case QEMU_INPUT_QUEUE_EVENT:
254be1a7176SGerd Hoffmann             qemu_input_event_send(item->src, item->evt);
255be1a7176SGerd Hoffmann             qapi_free_InputEvent(item->evt);
256be1a7176SGerd Hoffmann             break;
257be1a7176SGerd Hoffmann         case QEMU_INPUT_QUEUE_SYNC:
258be1a7176SGerd Hoffmann             qemu_input_event_sync();
259be1a7176SGerd Hoffmann             break;
260be1a7176SGerd Hoffmann         }
261be1a7176SGerd Hoffmann         QTAILQ_REMOVE(queue, item, node);
262fa18f36aSGerd Hoffmann         queue_count--;
263be1a7176SGerd Hoffmann         g_free(item);
264be1a7176SGerd Hoffmann     }
265be1a7176SGerd Hoffmann }
266be1a7176SGerd Hoffmann 
qemu_input_queue_delay(QemuInputEventQueueHead * queue,QEMUTimer * timer,uint32_t delay_ms)267f481ee2dSPaolo Bonzini static void qemu_input_queue_delay(QemuInputEventQueueHead *queue,
268be1a7176SGerd Hoffmann                                    QEMUTimer *timer, uint32_t delay_ms)
269be1a7176SGerd Hoffmann {
270be1a7176SGerd Hoffmann     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
271be1a7176SGerd Hoffmann     bool start_timer = QTAILQ_EMPTY(queue);
272be1a7176SGerd Hoffmann 
273be1a7176SGerd Hoffmann     item->type = QEMU_INPUT_QUEUE_DELAY;
274be1a7176SGerd Hoffmann     item->delay_ms = delay_ms;
275be1a7176SGerd Hoffmann     item->timer = timer;
276be1a7176SGerd Hoffmann     QTAILQ_INSERT_TAIL(queue, item, node);
277fa18f36aSGerd Hoffmann     queue_count++;
278be1a7176SGerd Hoffmann 
279be1a7176SGerd Hoffmann     if (start_timer) {
28005ff8dc3SArtem Pisarenko         timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
281be1a7176SGerd Hoffmann                   + item->delay_ms);
282be1a7176SGerd Hoffmann     }
283be1a7176SGerd Hoffmann }
284be1a7176SGerd Hoffmann 
qemu_input_queue_event(QemuInputEventQueueHead * queue,QemuConsole * src,InputEvent * evt)285f481ee2dSPaolo Bonzini static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
286be1a7176SGerd Hoffmann                                    QemuConsole *src, InputEvent *evt)
287be1a7176SGerd Hoffmann {
288be1a7176SGerd Hoffmann     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
289be1a7176SGerd Hoffmann 
290be1a7176SGerd Hoffmann     item->type = QEMU_INPUT_QUEUE_EVENT;
291be1a7176SGerd Hoffmann     item->src = src;
292be1a7176SGerd Hoffmann     item->evt = evt;
293be1a7176SGerd Hoffmann     QTAILQ_INSERT_TAIL(queue, item, node);
294fa18f36aSGerd Hoffmann     queue_count++;
295be1a7176SGerd Hoffmann }
296be1a7176SGerd Hoffmann 
qemu_input_queue_sync(QemuInputEventQueueHead * queue)297f481ee2dSPaolo Bonzini static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
298be1a7176SGerd Hoffmann {
299be1a7176SGerd Hoffmann     QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
300be1a7176SGerd Hoffmann 
301be1a7176SGerd Hoffmann     item->type = QEMU_INPUT_QUEUE_SYNC;
302be1a7176SGerd Hoffmann     QTAILQ_INSERT_TAIL(queue, item, node);
303fa18f36aSGerd Hoffmann     queue_count++;
304be1a7176SGerd Hoffmann }
305be1a7176SGerd Hoffmann 
qemu_input_event_send_impl(QemuConsole * src,InputEvent * evt)306ee312992SPavel Dovgalyuk void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
307c8b405b6SGerd Hoffmann {
308c8b405b6SGerd Hoffmann     QemuInputHandlerState *s;
309c8b405b6SGerd Hoffmann 
310c43ce551SGerd Hoffmann     qemu_input_event_trace(src, evt);
311c43ce551SGerd Hoffmann 
312d3535431SGerd Hoffmann     /* send event */
313568c73a4SEric Blake     s = qemu_input_find_handler(1 << evt->type, src);
314bdcc3a28SGerd Hoffmann     if (!s) {
315bdcc3a28SGerd Hoffmann         return;
316bdcc3a28SGerd Hoffmann     }
317c8b405b6SGerd Hoffmann     s->handler->event(s->dev, src, evt);
318c8b405b6SGerd Hoffmann     s->events++;
319c8b405b6SGerd Hoffmann }
320c8b405b6SGerd Hoffmann 
qemu_input_event_send(QemuConsole * src,InputEvent * evt)321ee312992SPavel Dovgalyuk void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
322c8b405b6SGerd Hoffmann {
323af07e5ffSDaniel P. Berrange     /* Expect all parts of QEMU to send events with QCodes exclusively.
324af07e5ffSDaniel P. Berrange      * Key numbers are only supported as end-user input via QMP */
325af07e5ffSDaniel P. Berrange     assert(!(evt->type == INPUT_EVENT_KIND_KEY &&
326af07e5ffSDaniel P. Berrange              evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER));
327af07e5ffSDaniel P. Berrange 
32880b857f0SDaniel P. Berrange 
32980b857f0SDaniel P. Berrange     /*
33080b857f0SDaniel P. Berrange      * 'sysrq' was mistakenly added to hack around the fact that
33180b857f0SDaniel P. Berrange      * the ps2 driver was not generating correct scancodes sequences
33280b857f0SDaniel P. Berrange      * when 'alt+print' was pressed. This flaw is now fixed and the
33380b857f0SDaniel P. Berrange      * 'sysrq' key serves no further purpose. We normalize it to
33480b857f0SDaniel P. Berrange      * 'print', so that downstream receivers of the event don't
335118d4ed0SDr. David Alan Gilbert      * need to deal with this mistake
33680b857f0SDaniel P. Berrange      */
33780b857f0SDaniel P. Berrange     if (evt->type == INPUT_EVENT_KIND_KEY &&
33880b857f0SDaniel P. Berrange         evt->u.key.data->key->u.qcode.data == Q_KEY_CODE_SYSRQ) {
33980b857f0SDaniel P. Berrange         evt->u.key.data->key->u.qcode.data = Q_KEY_CODE_PRINT;
34080b857f0SDaniel P. Berrange     }
34180b857f0SDaniel P. Berrange 
342c8b405b6SGerd Hoffmann     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
343c8b405b6SGerd Hoffmann         return;
344c8b405b6SGerd Hoffmann     }
345c8b405b6SGerd Hoffmann 
346ee312992SPavel Dovgalyuk     replay_input_event(src, evt);
347ee312992SPavel Dovgalyuk }
348ee312992SPavel Dovgalyuk 
qemu_input_event_sync_impl(void)349ee312992SPavel Dovgalyuk void qemu_input_event_sync_impl(void)
350ee312992SPavel Dovgalyuk {
351ee312992SPavel Dovgalyuk     QemuInputHandlerState *s;
352ee312992SPavel Dovgalyuk 
353c43ce551SGerd Hoffmann     trace_input_event_sync();
354c43ce551SGerd Hoffmann 
355c8b405b6SGerd Hoffmann     QTAILQ_FOREACH(s, &handlers, node) {
356c8b405b6SGerd Hoffmann         if (!s->events) {
357c8b405b6SGerd Hoffmann             continue;
358c8b405b6SGerd Hoffmann         }
359c8b405b6SGerd Hoffmann         if (s->handler->sync) {
360c8b405b6SGerd Hoffmann             s->handler->sync(s->dev);
361c8b405b6SGerd Hoffmann         }
362c8b405b6SGerd Hoffmann         s->events = 0;
363c8b405b6SGerd Hoffmann     }
364c8b405b6SGerd Hoffmann }
36565671475SGerd Hoffmann 
qemu_input_event_sync(void)366ee312992SPavel Dovgalyuk void qemu_input_event_sync(void)
367ee312992SPavel Dovgalyuk {
368ee312992SPavel Dovgalyuk     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
369ee312992SPavel Dovgalyuk         return;
370ee312992SPavel Dovgalyuk     }
371ee312992SPavel Dovgalyuk 
372ee312992SPavel Dovgalyuk     replay_input_sync_event();
373ee312992SPavel Dovgalyuk }
374ee312992SPavel Dovgalyuk 
qemu_input_event_new_key(KeyValue * key,bool down)3753ad35e7aSDaniel P. Berrange static InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
37665671475SGerd Hoffmann {
37765671475SGerd Hoffmann     InputEvent *evt = g_new0(InputEvent, 1);
37832bafa8fSEric Blake     evt->u.key.data = g_new0(InputKeyEvent, 1);
379568c73a4SEric Blake     evt->type = INPUT_EVENT_KIND_KEY;
38032bafa8fSEric Blake     evt->u.key.data->key = key;
38132bafa8fSEric Blake     evt->u.key.data->down = down;
38265671475SGerd Hoffmann     return evt;
38365671475SGerd Hoffmann }
38465671475SGerd Hoffmann 
qemu_input_event_send_key(QemuConsole * src,KeyValue * key,bool down)38565671475SGerd Hoffmann void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
38665671475SGerd Hoffmann {
38765671475SGerd Hoffmann     InputEvent *evt;
38865671475SGerd Hoffmann     evt = qemu_input_event_new_key(key, down);
389be1a7176SGerd Hoffmann     if (QTAILQ_EMPTY(&kbd_queue)) {
39065671475SGerd Hoffmann         qemu_input_event_send(src, evt);
39165671475SGerd Hoffmann         qemu_input_event_sync();
39265671475SGerd Hoffmann         qapi_free_InputEvent(evt);
393fa18f36aSGerd Hoffmann     } else if (queue_count < queue_limit) {
394be1a7176SGerd Hoffmann         qemu_input_queue_event(&kbd_queue, src, evt);
395be1a7176SGerd Hoffmann         qemu_input_queue_sync(&kbd_queue);
396fca4774aSlinzhecheng     } else {
397fca4774aSlinzhecheng         qapi_free_InputEvent(evt);
398be1a7176SGerd Hoffmann     }
39965671475SGerd Hoffmann }
40065671475SGerd Hoffmann 
qemu_input_event_send_key_number(QemuConsole * src,int num,bool down)40165671475SGerd Hoffmann void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
40265671475SGerd Hoffmann {
403af07e5ffSDaniel P. Berrange     QKeyCode code = qemu_input_key_number_to_qcode(num);
404af07e5ffSDaniel P. Berrange     qemu_input_event_send_key_qcode(src, code, down);
40565671475SGerd Hoffmann }
40665671475SGerd Hoffmann 
qemu_input_event_send_key_qcode(QemuConsole * src,QKeyCode q,bool down)40765671475SGerd Hoffmann void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
40865671475SGerd Hoffmann {
40965671475SGerd Hoffmann     KeyValue *key = g_new0(KeyValue, 1);
410568c73a4SEric Blake     key->type = KEY_VALUE_KIND_QCODE;
41132bafa8fSEric Blake     key->u.qcode.data = q;
41265671475SGerd Hoffmann     qemu_input_event_send_key(src, key, down);
41365671475SGerd Hoffmann }
41443579403SGerd Hoffmann 
qemu_input_event_send_key_delay(uint32_t delay_ms)415be1a7176SGerd Hoffmann void qemu_input_event_send_key_delay(uint32_t delay_ms)
416be1a7176SGerd Hoffmann {
41705c6638bSMarc-André Lureau     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
41805c6638bSMarc-André Lureau         return;
41905c6638bSMarc-André Lureau     }
42005c6638bSMarc-André Lureau 
421be1a7176SGerd Hoffmann     if (!kbd_timer) {
422e81f8679SArtem Pisarenko         kbd_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
423e81f8679SArtem Pisarenko                                    SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
424e81f8679SArtem Pisarenko                                    qemu_input_queue_process, &kbd_queue);
425be1a7176SGerd Hoffmann     }
426fa18f36aSGerd Hoffmann     if (queue_count < queue_limit) {
427be1a7176SGerd Hoffmann         qemu_input_queue_delay(&kbd_queue, kbd_timer,
428be1a7176SGerd Hoffmann                                delay_ms ? delay_ms : kbd_default_delay_ms);
429be1a7176SGerd Hoffmann     }
430fa18f36aSGerd Hoffmann }
431be1a7176SGerd Hoffmann 
qemu_input_queue_btn(QemuConsole * src,InputButton btn,bool down)43243579403SGerd Hoffmann void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
43343579403SGerd Hoffmann {
4347a1b46e0SGerd Hoffmann     InputBtnEvent bevt = {
4357a1b46e0SGerd Hoffmann         .button = btn,
4367a1b46e0SGerd Hoffmann         .down = down,
4377a1b46e0SGerd Hoffmann     };
4387a1b46e0SGerd Hoffmann     InputEvent evt = {
4397a1b46e0SGerd Hoffmann         .type = INPUT_EVENT_KIND_BTN,
4407a1b46e0SGerd Hoffmann         .u.btn.data = &bevt,
4417a1b46e0SGerd Hoffmann     };
4427a1b46e0SGerd Hoffmann 
4437a1b46e0SGerd Hoffmann     qemu_input_event_send(src, &evt);
44443579403SGerd Hoffmann }
44543579403SGerd Hoffmann 
qemu_input_update_buttons(QemuConsole * src,uint32_t * button_map,uint32_t button_old,uint32_t button_new)44643579403SGerd Hoffmann void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
44743579403SGerd Hoffmann                                uint32_t button_old, uint32_t button_new)
44843579403SGerd Hoffmann {
44943579403SGerd Hoffmann     InputButton btn;
45043579403SGerd Hoffmann     uint32_t mask;
45143579403SGerd Hoffmann 
4527fb1cf16SEric Blake     for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) {
45343579403SGerd Hoffmann         mask = button_map[btn];
45443579403SGerd Hoffmann         if ((button_old & mask) == (button_new & mask)) {
45543579403SGerd Hoffmann             continue;
45643579403SGerd Hoffmann         }
45743579403SGerd Hoffmann         qemu_input_queue_btn(src, btn, button_new & mask);
45843579403SGerd Hoffmann     }
45943579403SGerd Hoffmann }
46043579403SGerd Hoffmann 
qemu_input_is_absolute(QemuConsole * con)4610337e412SAkihiko Odaki bool qemu_input_is_absolute(QemuConsole *con)
462502c8db5SGerd Hoffmann {
463502c8db5SGerd Hoffmann     QemuInputHandlerState *s;
464502c8db5SGerd Hoffmann 
4656f5943cfSGerd Hoffmann     s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
4660337e412SAkihiko Odaki                                 con);
467502c8db5SGerd Hoffmann     return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
468502c8db5SGerd Hoffmann }
469502c8db5SGerd Hoffmann 
qemu_input_scale_axis(int value,int min_in,int max_in,int min_out,int max_out)4709cfa7ab9SPhilippe Voinov int qemu_input_scale_axis(int value,
4719cfa7ab9SPhilippe Voinov                           int min_in, int max_in,
4729cfa7ab9SPhilippe Voinov                           int min_out, int max_out)
47343579403SGerd Hoffmann {
4749cfa7ab9SPhilippe Voinov     int64_t range_in = (int64_t)max_in - min_in;
4759cfa7ab9SPhilippe Voinov     int64_t range_out = (int64_t)max_out - min_out;
4769cfa7ab9SPhilippe Voinov 
4779cfa7ab9SPhilippe Voinov     if (range_in < 1) {
4789cfa7ab9SPhilippe Voinov         return min_out + range_out / 2;
47943579403SGerd Hoffmann     }
4809cfa7ab9SPhilippe Voinov     return ((int64_t)value - min_in) * range_out / range_in + min_out;
48143579403SGerd Hoffmann }
48243579403SGerd Hoffmann 
qemu_input_queue_rel(QemuConsole * src,InputAxis axis,int value)48343579403SGerd Hoffmann void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
48443579403SGerd Hoffmann {
4857a1b46e0SGerd Hoffmann     InputMoveEvent move = {
4867a1b46e0SGerd Hoffmann         .axis = axis,
4877a1b46e0SGerd Hoffmann         .value = value,
4887a1b46e0SGerd Hoffmann     };
4897a1b46e0SGerd Hoffmann     InputEvent evt = {
4907a1b46e0SGerd Hoffmann         .type = INPUT_EVENT_KIND_REL,
4917a1b46e0SGerd Hoffmann         .u.rel.data = &move,
4927a1b46e0SGerd Hoffmann     };
4937a1b46e0SGerd Hoffmann 
4947a1b46e0SGerd Hoffmann     qemu_input_event_send(src, &evt);
49543579403SGerd Hoffmann }
49643579403SGerd Hoffmann 
qemu_input_queue_abs(QemuConsole * src,InputAxis axis,int value,int min_in,int max_in)4979cfa7ab9SPhilippe Voinov void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
4989cfa7ab9SPhilippe Voinov                           int min_in, int max_in)
49943579403SGerd Hoffmann {
5007a1b46e0SGerd Hoffmann     InputMoveEvent move = {
5017a1b46e0SGerd Hoffmann         .axis = axis,
5027a1b46e0SGerd Hoffmann         .value = qemu_input_scale_axis(value, min_in, max_in,
5039cfa7ab9SPhilippe Voinov                                        INPUT_EVENT_ABS_MIN,
5047a1b46e0SGerd Hoffmann                                        INPUT_EVENT_ABS_MAX),
5057a1b46e0SGerd Hoffmann     };
5067a1b46e0SGerd Hoffmann     InputEvent evt = {
5077a1b46e0SGerd Hoffmann         .type = INPUT_EVENT_KIND_ABS,
5087a1b46e0SGerd Hoffmann         .u.abs.data = &move,
5097a1b46e0SGerd Hoffmann     };
5107a1b46e0SGerd Hoffmann 
5117a1b46e0SGerd Hoffmann     qemu_input_event_send(src, &evt);
51243579403SGerd Hoffmann }
5134a33f45eSGerd Hoffmann 
qemu_input_queue_mtt(QemuConsole * src,InputMultiTouchType type,int slot,int tracking_id)514f6157392SSergio Lopez void qemu_input_queue_mtt(QemuConsole *src, InputMultiTouchType type,
515f6157392SSergio Lopez                           int slot, int tracking_id)
516f6157392SSergio Lopez {
517f6157392SSergio Lopez     InputMultiTouchEvent mtt = {
518f6157392SSergio Lopez         .type = type,
519f6157392SSergio Lopez         .slot = slot,
520f6157392SSergio Lopez         .tracking_id = tracking_id,
521f6157392SSergio Lopez     };
522f6157392SSergio Lopez     InputEvent evt = {
523f6157392SSergio Lopez         .type = INPUT_EVENT_KIND_MTT,
524f6157392SSergio Lopez         .u.mtt.data = &mtt,
525f6157392SSergio Lopez     };
526f6157392SSergio Lopez 
527f6157392SSergio Lopez     qemu_input_event_send(src, &evt);
528f6157392SSergio Lopez }
529f6157392SSergio Lopez 
qemu_input_queue_mtt_abs(QemuConsole * src,InputAxis axis,int value,int min_in,int max_in,int slot,int tracking_id)530f6157392SSergio Lopez void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
531f6157392SSergio Lopez                               int min_in, int max_in, int slot, int tracking_id)
532f6157392SSergio Lopez {
533f6157392SSergio Lopez     InputMultiTouchEvent mtt = {
534f6157392SSergio Lopez         .type = INPUT_MULTI_TOUCH_TYPE_DATA,
535f6157392SSergio Lopez         .slot = slot,
536f6157392SSergio Lopez         .tracking_id = tracking_id,
537f6157392SSergio Lopez         .axis = axis,
538f6157392SSergio Lopez         .value = qemu_input_scale_axis(value, min_in, max_in,
539f6157392SSergio Lopez                                        INPUT_EVENT_ABS_MIN,
540f6157392SSergio Lopez                                        INPUT_EVENT_ABS_MAX),
541f6157392SSergio Lopez     };
542f6157392SSergio Lopez     InputEvent evt = {
543f6157392SSergio Lopez         .type = INPUT_EVENT_KIND_MTT,
544f6157392SSergio Lopez         .u.mtt.data = &mtt,
545f6157392SSergio Lopez     };
546f6157392SSergio Lopez 
547f6157392SSergio Lopez     qemu_input_event_send(src, &evt);
548f6157392SSergio Lopez }
549f6157392SSergio Lopez 
qemu_add_mouse_mode_change_notifier(Notifier * notify)5504a33f45eSGerd Hoffmann void qemu_add_mouse_mode_change_notifier(Notifier *notify)
5514a33f45eSGerd Hoffmann {
5524a33f45eSGerd Hoffmann     notifier_list_add(&mouse_mode_notifiers, notify);
5534a33f45eSGerd Hoffmann }
5544a33f45eSGerd Hoffmann 
qemu_remove_mouse_mode_change_notifier(Notifier * notify)5554a33f45eSGerd Hoffmann void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
5564a33f45eSGerd Hoffmann {
5574a33f45eSGerd Hoffmann     notifier_remove(notify);
5584a33f45eSGerd Hoffmann }
559e842c68dSGerd Hoffmann 
qmp_query_mice(Error ** errp)560e842c68dSGerd Hoffmann MouseInfoList *qmp_query_mice(Error **errp)
561e842c68dSGerd Hoffmann {
562e842c68dSGerd Hoffmann     MouseInfoList *mice_list = NULL;
56354aa3de7SEric Blake     MouseInfo *info;
564e842c68dSGerd Hoffmann     QemuInputHandlerState *s;
565e842c68dSGerd Hoffmann     bool current = true;
566e842c68dSGerd Hoffmann 
567e842c68dSGerd Hoffmann     QTAILQ_FOREACH(s, &handlers, node) {
568e842c68dSGerd Hoffmann         if (!(s->handler->mask &
569e842c68dSGerd Hoffmann               (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
570e842c68dSGerd Hoffmann             continue;
571e842c68dSGerd Hoffmann         }
572e842c68dSGerd Hoffmann 
57354aa3de7SEric Blake         info = g_new0(MouseInfo, 1);
57454aa3de7SEric Blake         info->index = s->id;
57554aa3de7SEric Blake         info->name = g_strdup(s->handler->name);
57654aa3de7SEric Blake         info->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
57754aa3de7SEric Blake         info->current = current;
578e842c68dSGerd Hoffmann 
579e842c68dSGerd Hoffmann         current = false;
58054aa3de7SEric Blake         QAPI_LIST_PREPEND(mice_list, info);
581e842c68dSGerd Hoffmann     }
582e842c68dSGerd Hoffmann 
583e842c68dSGerd Hoffmann     return mice_list;
584e842c68dSGerd Hoffmann }
58570b52f62SGerd Hoffmann 
qemu_mouse_set(int index,Error ** errp)586ec843b97SMarkus Armbruster bool qemu_mouse_set(int index, Error **errp)
58770b52f62SGerd Hoffmann {
58870b52f62SGerd Hoffmann     QemuInputHandlerState *s;
58970b52f62SGerd Hoffmann 
59070b52f62SGerd Hoffmann     QTAILQ_FOREACH(s, &handlers, node) {
591a0506b7cSMarkus Armbruster         if (s->id == index) {
592a0506b7cSMarkus Armbruster             break;
5930419f78fSHani Benhabiles         }
594a0506b7cSMarkus Armbruster     }
595a0506b7cSMarkus Armbruster 
596a0506b7cSMarkus Armbruster     if (!s) {
597a0506b7cSMarkus Armbruster         error_setg(errp, "Mouse at index '%d' not found", index);
598a0506b7cSMarkus Armbruster         return false;
599a0506b7cSMarkus Armbruster     }
600a0506b7cSMarkus Armbruster 
6010419f78fSHani Benhabiles     if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
6020419f78fSHani Benhabiles                               INPUT_EVENT_MASK_ABS))) {
603ec843b97SMarkus Armbruster         error_setg(errp, "Input device '%s' is not a mouse",
604ec843b97SMarkus Armbruster                    s->handler->name);
605ec843b97SMarkus Armbruster         return false;
6060419f78fSHani Benhabiles     }
607a0506b7cSMarkus Armbruster 
60870b52f62SGerd Hoffmann     qemu_input_handler_activate(s);
6090337e412SAkihiko Odaki     notifier_list_notify(&mouse_mode_notifiers, NULL);
610ec843b97SMarkus Armbruster     return true;
61170b52f62SGerd Hoffmann }
612