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