xref: /openbmc/qemu/ui/input.c (revision 65e7545e)
1 #include "sysemu/sysemu.h"
2 #include "qapi-types.h"
3 #include "qmp-commands.h"
4 #include "trace.h"
5 #include "ui/input.h"
6 #include "ui/console.h"
7 
8 struct QemuInputHandlerState {
9     DeviceState       *dev;
10     QemuInputHandler  *handler;
11     int               id;
12     int               events;
13     QTAILQ_ENTRY(QemuInputHandlerState) node;
14 };
15 static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
16     QTAILQ_HEAD_INITIALIZER(handlers);
17 static NotifierList mouse_mode_notifiers =
18     NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
19 
20 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
21                                                    QemuInputHandler *handler)
22 {
23     QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
24     static int id = 1;
25 
26     s->dev = dev;
27     s->handler = handler;
28     s->id = id++;
29     QTAILQ_INSERT_TAIL(&handlers, s, node);
30 
31     qemu_input_check_mode_change();
32     return s;
33 }
34 
35 void qemu_input_handler_activate(QemuInputHandlerState *s)
36 {
37     QTAILQ_REMOVE(&handlers, s, node);
38     QTAILQ_INSERT_HEAD(&handlers, s, node);
39     qemu_input_check_mode_change();
40 }
41 
42 void qemu_input_handler_deactivate(QemuInputHandlerState *s)
43 {
44     QTAILQ_REMOVE(&handlers, s, node);
45     QTAILQ_INSERT_TAIL(&handlers, s, node);
46     qemu_input_check_mode_change();
47 }
48 
49 void qemu_input_handler_unregister(QemuInputHandlerState *s)
50 {
51     QTAILQ_REMOVE(&handlers, s, node);
52     g_free(s);
53     qemu_input_check_mode_change();
54 }
55 
56 static QemuInputHandlerState*
57 qemu_input_find_handler(uint32_t mask)
58 {
59     QemuInputHandlerState *s;
60 
61     QTAILQ_FOREACH(s, &handlers, node) {
62         if (mask & s->handler->mask) {
63             return s;
64         }
65     }
66     return NULL;
67 }
68 
69 static void qemu_input_transform_abs_rotate(InputEvent *evt)
70 {
71     switch (graphic_rotate) {
72     case 90:
73         if (evt->abs->axis == INPUT_AXIS_X) {
74             evt->abs->axis = INPUT_AXIS_Y;
75         } else if (evt->abs->axis == INPUT_AXIS_Y) {
76             evt->abs->axis = INPUT_AXIS_X;
77             evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
78         }
79         break;
80     case 180:
81         evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
82         break;
83     case 270:
84         if (evt->abs->axis == INPUT_AXIS_X) {
85             evt->abs->axis = INPUT_AXIS_Y;
86             evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
87         } else if (evt->abs->axis == INPUT_AXIS_Y) {
88             evt->abs->axis = INPUT_AXIS_X;
89         }
90         break;
91     }
92 }
93 
94 static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
95 {
96     const char *name;
97     int idx = -1;
98 
99     if (src) {
100         idx = qemu_console_get_index(src);
101     }
102     switch (evt->kind) {
103     case INPUT_EVENT_KIND_KEY:
104         switch (evt->key->key->kind) {
105         case KEY_VALUE_KIND_NUMBER:
106             trace_input_event_key_number(idx, evt->key->key->number,
107                                          evt->key->down);
108             break;
109         case KEY_VALUE_KIND_QCODE:
110             name = QKeyCode_lookup[evt->key->key->qcode];
111             trace_input_event_key_qcode(idx, name, evt->key->down);
112             break;
113         case KEY_VALUE_KIND_MAX:
114             /* keep gcc happy */
115             break;
116         }
117         break;
118     case INPUT_EVENT_KIND_BTN:
119         name = InputButton_lookup[evt->btn->button];
120         trace_input_event_btn(idx, name, evt->btn->down);
121         break;
122     case INPUT_EVENT_KIND_REL:
123         name = InputAxis_lookup[evt->rel->axis];
124         trace_input_event_rel(idx, name, evt->rel->value);
125         break;
126     case INPUT_EVENT_KIND_ABS:
127         name = InputAxis_lookup[evt->abs->axis];
128         trace_input_event_abs(idx, name, evt->abs->value);
129         break;
130     case INPUT_EVENT_KIND_MAX:
131         /* keep gcc happy */
132         break;
133     }
134 }
135 
136 void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
137 {
138     QemuInputHandlerState *s;
139 
140     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
141         return;
142     }
143 
144     qemu_input_event_trace(src, evt);
145 
146     /* pre processing */
147     if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
148             qemu_input_transform_abs_rotate(evt);
149     }
150 
151     /* send event */
152     s = qemu_input_find_handler(1 << evt->kind);
153     if (!s) {
154         return;
155     }
156     s->handler->event(s->dev, src, evt);
157     s->events++;
158 }
159 
160 void qemu_input_event_sync(void)
161 {
162     QemuInputHandlerState *s;
163 
164     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
165         return;
166     }
167 
168     trace_input_event_sync();
169 
170     QTAILQ_FOREACH(s, &handlers, node) {
171         if (!s->events) {
172             continue;
173         }
174         if (s->handler->sync) {
175             s->handler->sync(s->dev);
176         }
177         s->events = 0;
178     }
179 }
180 
181 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
182 {
183     InputEvent *evt = g_new0(InputEvent, 1);
184     evt->key = g_new0(InputKeyEvent, 1);
185     evt->kind = INPUT_EVENT_KIND_KEY;
186     evt->key->key = key;
187     evt->key->down = down;
188     return evt;
189 }
190 
191 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
192 {
193     InputEvent *evt;
194     evt = qemu_input_event_new_key(key, down);
195     qemu_input_event_send(src, evt);
196     qemu_input_event_sync();
197     qapi_free_InputEvent(evt);
198 }
199 
200 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
201 {
202     KeyValue *key = g_new0(KeyValue, 1);
203     key->kind = KEY_VALUE_KIND_NUMBER;
204     key->number = num;
205     qemu_input_event_send_key(src, key, down);
206 }
207 
208 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
209 {
210     KeyValue *key = g_new0(KeyValue, 1);
211     key->kind = KEY_VALUE_KIND_QCODE;
212     key->qcode = q;
213     qemu_input_event_send_key(src, key, down);
214 }
215 
216 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
217 {
218     InputEvent *evt = g_new0(InputEvent, 1);
219     evt->btn = g_new0(InputBtnEvent, 1);
220     evt->kind = INPUT_EVENT_KIND_BTN;
221     evt->btn->button = btn;
222     evt->btn->down = down;
223     return evt;
224 }
225 
226 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
227 {
228     InputEvent *evt;
229     evt = qemu_input_event_new_btn(btn, down);
230     qemu_input_event_send(src, evt);
231     qapi_free_InputEvent(evt);
232 }
233 
234 void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
235                                uint32_t button_old, uint32_t button_new)
236 {
237     InputButton btn;
238     uint32_t mask;
239 
240     for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
241         mask = button_map[btn];
242         if ((button_old & mask) == (button_new & mask)) {
243             continue;
244         }
245         qemu_input_queue_btn(src, btn, button_new & mask);
246     }
247 }
248 
249 bool qemu_input_is_absolute(void)
250 {
251     QemuInputHandlerState *s;
252 
253     s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS);
254     return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
255 }
256 
257 int qemu_input_scale_axis(int value, int size_in, int size_out)
258 {
259     if (size_in < 2) {
260         return size_out / 2;
261     }
262     return (int64_t)value * (size_out - 1) / (size_in - 1);
263 }
264 
265 InputEvent *qemu_input_event_new_move(InputEventKind kind,
266                                       InputAxis axis, int value)
267 {
268     InputEvent *evt = g_new0(InputEvent, 1);
269     InputMoveEvent *move = g_new0(InputMoveEvent, 1);
270 
271     evt->kind = kind;
272     evt->data = move;
273     move->axis = axis;
274     move->value = value;
275     return evt;
276 }
277 
278 void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
279 {
280     InputEvent *evt;
281     evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
282     qemu_input_event_send(src, evt);
283     qapi_free_InputEvent(evt);
284 }
285 
286 void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
287 {
288     InputEvent *evt;
289     int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
290     evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
291     qemu_input_event_send(src, evt);
292     qapi_free_InputEvent(evt);
293 }
294 
295 void qemu_input_check_mode_change(void)
296 {
297     static int current_is_absolute;
298     int is_absolute;
299 
300     is_absolute = qemu_input_is_absolute();
301 
302     if (is_absolute != current_is_absolute) {
303         trace_input_mouse_mode(is_absolute);
304         notifier_list_notify(&mouse_mode_notifiers, NULL);
305     }
306 
307     current_is_absolute = is_absolute;
308 }
309 
310 void qemu_add_mouse_mode_change_notifier(Notifier *notify)
311 {
312     notifier_list_add(&mouse_mode_notifiers, notify);
313 }
314 
315 void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
316 {
317     notifier_remove(notify);
318 }
319 
320 MouseInfoList *qmp_query_mice(Error **errp)
321 {
322     MouseInfoList *mice_list = NULL;
323     MouseInfoList *info;
324     QemuInputHandlerState *s;
325     bool current = true;
326 
327     QTAILQ_FOREACH(s, &handlers, node) {
328         if (!(s->handler->mask &
329               (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
330             continue;
331         }
332 
333         info = g_new0(MouseInfoList, 1);
334         info->value = g_new0(MouseInfo, 1);
335         info->value->index = s->id;
336         info->value->name = g_strdup(s->handler->name);
337         info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
338         info->value->current = current;
339 
340         current = false;
341         info->next = mice_list;
342         mice_list = info;
343     }
344 
345     return mice_list;
346 }
347 
348 void do_mouse_set(Monitor *mon, const QDict *qdict)
349 {
350     QemuInputHandlerState *s;
351     int index = qdict_get_int(qdict, "index");
352     int found = 0;
353 
354     QTAILQ_FOREACH(s, &handlers, node) {
355         if (s->id != index) {
356             continue;
357         }
358         if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
359                                   INPUT_EVENT_MASK_ABS))) {
360             error_report("Input device '%s' is not a mouse", s->handler->name);
361             return;
362         }
363         found = 1;
364         qemu_input_handler_activate(s);
365         break;
366     }
367 
368     if (!found) {
369         error_report("Mouse at index '%d' not found", index);
370     }
371 
372     qemu_input_check_mode_change();
373 }
374