]>
Commit | Line | Data |
---|---|---|
c8b405b6 GH |
1 | #include "sysemu/sysemu.h" |
2 | #include "qapi-types.h" | |
c43ce551 | 3 | #include "trace.h" |
c8b405b6 | 4 | #include "ui/input.h" |
c43ce551 | 5 | #include "ui/console.h" |
c8b405b6 GH |
6 | |
7 | struct QemuInputHandlerState { | |
8 | DeviceState *dev; | |
9 | QemuInputHandler *handler; | |
10 | int id; | |
11 | int events; | |
12 | QTAILQ_ENTRY(QemuInputHandlerState) node; | |
13 | }; | |
14 | static QTAILQ_HEAD(, QemuInputHandlerState) handlers = | |
15 | QTAILQ_HEAD_INITIALIZER(handlers); | |
4a33f45e GH |
16 | static NotifierList mouse_mode_notifiers = |
17 | NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); | |
c8b405b6 GH |
18 | |
19 | QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, | |
20 | QemuInputHandler *handler) | |
21 | { | |
22 | QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1); | |
23 | static int id = 1; | |
24 | ||
25 | s->dev = dev; | |
26 | s->handler = handler; | |
27 | s->id = id++; | |
28 | QTAILQ_INSERT_TAIL(&handlers, s, node); | |
4a33f45e GH |
29 | |
30 | qemu_input_check_mode_change(); | |
c8b405b6 GH |
31 | return s; |
32 | } | |
33 | ||
34 | void qemu_input_handler_activate(QemuInputHandlerState *s) | |
35 | { | |
36 | QTAILQ_REMOVE(&handlers, s, node); | |
37 | QTAILQ_INSERT_HEAD(&handlers, s, node); | |
4a33f45e | 38 | qemu_input_check_mode_change(); |
c8b405b6 GH |
39 | } |
40 | ||
41 | void qemu_input_handler_unregister(QemuInputHandlerState *s) | |
42 | { | |
43 | QTAILQ_REMOVE(&handlers, s, node); | |
44 | g_free(s); | |
4a33f45e | 45 | qemu_input_check_mode_change(); |
c8b405b6 GH |
46 | } |
47 | ||
48 | static QemuInputHandlerState* | |
49 | qemu_input_find_handler(uint32_t mask) | |
50 | { | |
51 | QemuInputHandlerState *s; | |
52 | ||
53 | QTAILQ_FOREACH(s, &handlers, node) { | |
54 | if (mask & s->handler->mask) { | |
55 | return s; | |
56 | } | |
57 | } | |
58 | return NULL; | |
59 | } | |
60 | ||
d3535431 GH |
61 | static void qemu_input_transform_abs_rotate(InputEvent *evt) |
62 | { | |
63 | switch (graphic_rotate) { | |
64 | case 90: | |
65 | if (evt->abs->axis == INPUT_AXIS_X) { | |
66 | evt->abs->axis = INPUT_AXIS_Y; | |
67 | } else if (evt->abs->axis == INPUT_AXIS_Y) { | |
68 | evt->abs->axis = INPUT_AXIS_X; | |
69 | evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value; | |
70 | } | |
71 | break; | |
72 | case 180: | |
73 | evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value; | |
74 | break; | |
75 | case 270: | |
76 | if (evt->abs->axis == INPUT_AXIS_X) { | |
77 | evt->abs->axis = INPUT_AXIS_Y; | |
78 | evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value; | |
79 | } else if (evt->abs->axis == INPUT_AXIS_Y) { | |
80 | evt->abs->axis = INPUT_AXIS_X; | |
81 | } | |
82 | break; | |
83 | } | |
84 | } | |
85 | ||
c43ce551 GH |
86 | static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) |
87 | { | |
88 | const char *name; | |
89 | int idx = -1; | |
90 | ||
91 | if (src) { | |
92 | idx = qemu_console_get_index(src); | |
93 | } | |
94 | switch (evt->kind) { | |
95 | case INPUT_EVENT_KIND_KEY: | |
96 | switch (evt->key->key->kind) { | |
97 | case KEY_VALUE_KIND_NUMBER: | |
98 | trace_input_event_key_number(idx, evt->key->key->number, | |
99 | evt->key->down); | |
100 | break; | |
101 | case KEY_VALUE_KIND_QCODE: | |
102 | name = QKeyCode_lookup[evt->key->key->qcode]; | |
103 | trace_input_event_key_qcode(idx, name, evt->key->down); | |
104 | break; | |
105 | case KEY_VALUE_KIND_MAX: | |
106 | /* keep gcc happy */ | |
107 | break; | |
108 | } | |
109 | break; | |
110 | case INPUT_EVENT_KIND_BTN: | |
111 | name = InputButton_lookup[evt->btn->button]; | |
112 | trace_input_event_btn(idx, name, evt->btn->down); | |
113 | break; | |
114 | case INPUT_EVENT_KIND_REL: | |
115 | name = InputAxis_lookup[evt->rel->axis]; | |
116 | trace_input_event_rel(idx, name, evt->rel->value); | |
117 | break; | |
118 | case INPUT_EVENT_KIND_ABS: | |
119 | name = InputAxis_lookup[evt->abs->axis]; | |
120 | trace_input_event_abs(idx, name, evt->abs->value); | |
121 | break; | |
122 | case INPUT_EVENT_KIND_MAX: | |
123 | /* keep gcc happy */ | |
124 | break; | |
125 | } | |
126 | } | |
127 | ||
c8b405b6 GH |
128 | void qemu_input_event_send(QemuConsole *src, InputEvent *evt) |
129 | { | |
130 | QemuInputHandlerState *s; | |
131 | ||
132 | if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { | |
133 | return; | |
134 | } | |
135 | ||
c43ce551 GH |
136 | qemu_input_event_trace(src, evt); |
137 | ||
d3535431 GH |
138 | /* pre processing */ |
139 | if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) { | |
140 | qemu_input_transform_abs_rotate(evt); | |
141 | } | |
142 | ||
143 | /* send event */ | |
c8b405b6 GH |
144 | s = qemu_input_find_handler(1 << evt->kind); |
145 | s->handler->event(s->dev, src, evt); | |
146 | s->events++; | |
147 | } | |
148 | ||
149 | void qemu_input_event_sync(void) | |
150 | { | |
151 | QemuInputHandlerState *s; | |
152 | ||
153 | if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { | |
154 | return; | |
155 | } | |
156 | ||
c43ce551 GH |
157 | trace_input_event_sync(); |
158 | ||
c8b405b6 GH |
159 | QTAILQ_FOREACH(s, &handlers, node) { |
160 | if (!s->events) { | |
161 | continue; | |
162 | } | |
163 | if (s->handler->sync) { | |
164 | s->handler->sync(s->dev); | |
165 | } | |
166 | s->events = 0; | |
167 | } | |
168 | } | |
65671475 GH |
169 | |
170 | InputEvent *qemu_input_event_new_key(KeyValue *key, bool down) | |
171 | { | |
172 | InputEvent *evt = g_new0(InputEvent, 1); | |
173 | evt->key = g_new0(InputKeyEvent, 1); | |
174 | evt->kind = INPUT_EVENT_KIND_KEY; | |
175 | evt->key->key = key; | |
176 | evt->key->down = down; | |
177 | return evt; | |
178 | } | |
179 | ||
180 | void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down) | |
181 | { | |
182 | InputEvent *evt; | |
183 | evt = qemu_input_event_new_key(key, down); | |
184 | qemu_input_event_send(src, evt); | |
185 | qemu_input_event_sync(); | |
186 | qapi_free_InputEvent(evt); | |
187 | } | |
188 | ||
189 | void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down) | |
190 | { | |
191 | KeyValue *key = g_new0(KeyValue, 1); | |
192 | key->kind = KEY_VALUE_KIND_NUMBER; | |
193 | key->number = num; | |
194 | qemu_input_event_send_key(src, key, down); | |
195 | } | |
196 | ||
197 | void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down) | |
198 | { | |
199 | KeyValue *key = g_new0(KeyValue, 1); | |
200 | key->kind = KEY_VALUE_KIND_QCODE; | |
201 | key->qcode = q; | |
202 | qemu_input_event_send_key(src, key, down); | |
203 | } | |
43579403 GH |
204 | |
205 | InputEvent *qemu_input_event_new_btn(InputButton btn, bool down) | |
206 | { | |
207 | InputEvent *evt = g_new0(InputEvent, 1); | |
208 | evt->btn = g_new0(InputBtnEvent, 1); | |
209 | evt->kind = INPUT_EVENT_KIND_BTN; | |
210 | evt->btn->button = btn; | |
211 | evt->btn->down = down; | |
212 | return evt; | |
213 | } | |
214 | ||
215 | void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down) | |
216 | { | |
217 | InputEvent *evt; | |
218 | evt = qemu_input_event_new_btn(btn, down); | |
219 | qemu_input_event_send(src, evt); | |
220 | qapi_free_InputEvent(evt); | |
221 | } | |
222 | ||
223 | void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, | |
224 | uint32_t button_old, uint32_t button_new) | |
225 | { | |
226 | InputButton btn; | |
227 | uint32_t mask; | |
228 | ||
229 | for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) { | |
230 | mask = button_map[btn]; | |
231 | if ((button_old & mask) == (button_new & mask)) { | |
232 | continue; | |
233 | } | |
234 | qemu_input_queue_btn(src, btn, button_new & mask); | |
235 | } | |
236 | } | |
237 | ||
502c8db5 GH |
238 | bool qemu_input_is_absolute(void) |
239 | { | |
240 | QemuInputHandlerState *s; | |
241 | ||
242 | s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS); | |
243 | return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); | |
244 | } | |
245 | ||
43579403 GH |
246 | int qemu_input_scale_axis(int value, int size_in, int size_out) |
247 | { | |
248 | if (size_in < 2) { | |
249 | return size_out / 2; | |
250 | } | |
251 | return (int64_t)value * (size_out - 1) / (size_in - 1); | |
252 | } | |
253 | ||
254 | InputEvent *qemu_input_event_new_move(InputEventKind kind, | |
255 | InputAxis axis, int value) | |
256 | { | |
257 | InputEvent *evt = g_new0(InputEvent, 1); | |
258 | InputMoveEvent *move = g_new0(InputMoveEvent, 1); | |
259 | ||
260 | evt->kind = kind; | |
261 | evt->data = move; | |
262 | move->axis = axis; | |
263 | move->value = value; | |
264 | return evt; | |
265 | } | |
266 | ||
267 | void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value) | |
268 | { | |
269 | InputEvent *evt; | |
270 | evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value); | |
271 | qemu_input_event_send(src, evt); | |
272 | qapi_free_InputEvent(evt); | |
273 | } | |
274 | ||
275 | void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size) | |
276 | { | |
277 | InputEvent *evt; | |
278 | int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE); | |
279 | evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled); | |
280 | qemu_input_event_send(src, evt); | |
281 | qapi_free_InputEvent(evt); | |
282 | } | |
4a33f45e GH |
283 | |
284 | void qemu_input_check_mode_change(void) | |
285 | { | |
286 | static int current_is_absolute; | |
287 | int is_absolute; | |
288 | ||
289 | is_absolute = qemu_input_is_absolute(); | |
290 | ||
291 | if (is_absolute != current_is_absolute) { | |
292 | notifier_list_notify(&mouse_mode_notifiers, NULL); | |
293 | } | |
294 | ||
295 | current_is_absolute = is_absolute; | |
296 | } | |
297 | ||
298 | void qemu_add_mouse_mode_change_notifier(Notifier *notify) | |
299 | { | |
300 | notifier_list_add(&mouse_mode_notifiers, notify); | |
301 | } | |
302 | ||
303 | void qemu_remove_mouse_mode_change_notifier(Notifier *notify) | |
304 | { | |
305 | notifier_remove(notify); | |
306 | } |