xref: /openbmc/qemu/ui/input.c (revision 01c22f2c)
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     s->handler->event(s->dev, src, evt);
147     s->events++;
148 }
149 
150 void qemu_input_event_sync(void)
151 {
152     QemuInputHandlerState *s;
153 
154     if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
155         return;
156     }
157 
158     trace_input_event_sync();
159 
160     QTAILQ_FOREACH(s, &handlers, node) {
161         if (!s->events) {
162             continue;
163         }
164         if (s->handler->sync) {
165             s->handler->sync(s->dev);
166         }
167         s->events = 0;
168     }
169 }
170 
171 InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
172 {
173     InputEvent *evt = g_new0(InputEvent, 1);
174     evt->key = g_new0(InputKeyEvent, 1);
175     evt->kind = INPUT_EVENT_KIND_KEY;
176     evt->key->key = key;
177     evt->key->down = down;
178     return evt;
179 }
180 
181 void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
182 {
183     InputEvent *evt;
184     evt = qemu_input_event_new_key(key, down);
185     qemu_input_event_send(src, evt);
186     qemu_input_event_sync();
187     qapi_free_InputEvent(evt);
188 }
189 
190 void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
191 {
192     KeyValue *key = g_new0(KeyValue, 1);
193     key->kind = KEY_VALUE_KIND_NUMBER;
194     key->number = num;
195     qemu_input_event_send_key(src, key, down);
196 }
197 
198 void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
199 {
200     KeyValue *key = g_new0(KeyValue, 1);
201     key->kind = KEY_VALUE_KIND_QCODE;
202     key->qcode = q;
203     qemu_input_event_send_key(src, key, down);
204 }
205 
206 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
207 {
208     InputEvent *evt = g_new0(InputEvent, 1);
209     evt->btn = g_new0(InputBtnEvent, 1);
210     evt->kind = INPUT_EVENT_KIND_BTN;
211     evt->btn->button = btn;
212     evt->btn->down = down;
213     return evt;
214 }
215 
216 void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
217 {
218     InputEvent *evt;
219     evt = qemu_input_event_new_btn(btn, down);
220     qemu_input_event_send(src, evt);
221     qapi_free_InputEvent(evt);
222 }
223 
224 void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
225                                uint32_t button_old, uint32_t button_new)
226 {
227     InputButton btn;
228     uint32_t mask;
229 
230     for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
231         mask = button_map[btn];
232         if ((button_old & mask) == (button_new & mask)) {
233             continue;
234         }
235         qemu_input_queue_btn(src, btn, button_new & mask);
236     }
237 }
238 
239 bool qemu_input_is_absolute(void)
240 {
241     QemuInputHandlerState *s;
242 
243     s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS);
244     return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
245 }
246 
247 int qemu_input_scale_axis(int value, int size_in, int size_out)
248 {
249     if (size_in < 2) {
250         return size_out / 2;
251     }
252     return (int64_t)value * (size_out - 1) / (size_in - 1);
253 }
254 
255 InputEvent *qemu_input_event_new_move(InputEventKind kind,
256                                       InputAxis axis, int value)
257 {
258     InputEvent *evt = g_new0(InputEvent, 1);
259     InputMoveEvent *move = g_new0(InputMoveEvent, 1);
260 
261     evt->kind = kind;
262     evt->data = move;
263     move->axis = axis;
264     move->value = value;
265     return evt;
266 }
267 
268 void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
269 {
270     InputEvent *evt;
271     evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
272     qemu_input_event_send(src, evt);
273     qapi_free_InputEvent(evt);
274 }
275 
276 void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
277 {
278     InputEvent *evt;
279     int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
280     evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
281     qemu_input_event_send(src, evt);
282     qapi_free_InputEvent(evt);
283 }
284 
285 void qemu_input_check_mode_change(void)
286 {
287     static int current_is_absolute;
288     int is_absolute;
289 
290     is_absolute = qemu_input_is_absolute();
291 
292     if (is_absolute != current_is_absolute) {
293         trace_input_mouse_mode(is_absolute);
294         notifier_list_notify(&mouse_mode_notifiers, NULL);
295     }
296 
297     current_is_absolute = is_absolute;
298 }
299 
300 void qemu_add_mouse_mode_change_notifier(Notifier *notify)
301 {
302     notifier_list_add(&mouse_mode_notifiers, notify);
303 }
304 
305 void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
306 {
307     notifier_remove(notify);
308 }
309 
310 MouseInfoList *qmp_query_mice(Error **errp)
311 {
312     MouseInfoList *mice_list = NULL;
313     MouseInfoList *info;
314     QemuInputHandlerState *s;
315     bool current = true;
316 
317     QTAILQ_FOREACH(s, &handlers, node) {
318         if (!(s->handler->mask &
319               (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
320             continue;
321         }
322 
323         info = g_new0(MouseInfoList, 1);
324         info->value = g_new0(MouseInfo, 1);
325         info->value->index = s->id;
326         info->value->name = g_strdup(s->handler->name);
327         info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
328         info->value->current = current;
329 
330         current = false;
331         info->next = mice_list;
332         mice_list = info;
333     }
334 
335     return mice_list;
336 }
337 
338 void do_mouse_set(Monitor *mon, const QDict *qdict)
339 {
340     QemuInputHandlerState *s;
341     int index = qdict_get_int(qdict, "index");
342     int found = 0;
343 
344     QTAILQ_FOREACH(s, &handlers, node) {
345         if (s->id == index) {
346             found = 1;
347             qemu_input_handler_activate(s);
348             break;
349         }
350     }
351 
352     if (!found) {
353         monitor_printf(mon, "Mouse at given index not found\n");
354     }
355 
356     qemu_input_check_mode_change();
357 }
358