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