Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 1 | /* |
| 2 | * QEMU System Emulator |
| 3 | * |
| 4 | * Copyright (c) 2003-2008 Fabrice Bellard |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to deal |
| 8 | * in the Software without restriction, including without limitation the rights |
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | * copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in |
| 14 | * all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. |
| 23 | */ |
| 24 | |
Peter Maydell | e16f4c8 | 2016-01-29 17:49:51 +0000 | [diff] [blame] | 25 | #include "qemu/osdep.h" |
Markus Armbruster | 9af2398 | 2018-02-11 10:36:01 +0100 | [diff] [blame] | 26 | #include "qapi/qapi-commands-ui.h" |
Paolo Bonzini | 9c17d61 | 2012-12-17 18:20:04 +0100 | [diff] [blame] | 27 | #include "sysemu/sysemu.h" |
Paolo Bonzini | 28ecbae | 2012-11-28 12:06:30 +0100 | [diff] [blame] | 28 | #include "ui/console.h" |
Michael S. Tsirkin | 0041e9a | 2018-05-03 22:51:00 +0300 | [diff] [blame] | 29 | #include "keymaps.h" |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 30 | #include "ui/input.h" |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 31 | |
Gerd Hoffmann | 72711ef | 2013-04-24 12:08:37 +0200 | [diff] [blame] | 32 | struct QEMUPutMouseEntry { |
| 33 | QEMUPutMouseEvent *qemu_put_mouse_event; |
| 34 | void *qemu_put_mouse_event_opaque; |
| 35 | int qemu_put_mouse_event_absolute; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 36 | |
| 37 | /* new input core */ |
| 38 | QemuInputHandler h; |
| 39 | QemuInputHandlerState *s; |
Eric Blake | 7fb1cf1 | 2015-11-18 01:52:57 -0700 | [diff] [blame] | 40 | int axis[INPUT_AXIS__MAX]; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 41 | int buttons; |
Gerd Hoffmann | 72711ef | 2013-04-24 12:08:37 +0200 | [diff] [blame] | 42 | }; |
| 43 | |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 44 | struct QEMUPutKbdEntry { |
| 45 | QEMUPutKBDEvent *put_kbd; |
| 46 | void *opaque; |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 47 | QemuInputHandlerState *s; |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 48 | }; |
| 49 | |
Gerd Hoffmann | 72711ef | 2013-04-24 12:08:37 +0200 | [diff] [blame] | 50 | struct QEMUPutLEDEntry { |
| 51 | QEMUPutLEDEvent *put_led; |
| 52 | void *opaque; |
| 53 | QTAILQ_ENTRY(QEMUPutLEDEntry) next; |
| 54 | }; |
| 55 | |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 56 | static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = |
| 57 | QTAILQ_HEAD_INITIALIZER(led_handlers); |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 58 | |
Wolfgang Bumiller | 64ffbe0 | 2016-01-13 09:09:58 +0100 | [diff] [blame] | 59 | int index_from_key(const char *key, size_t key_length) |
Amos Kong | 1048c88 | 2012-08-31 10:56:25 +0800 | [diff] [blame] | 60 | { |
Luiz Capitulino | 9d537c9 | 2012-09-20 14:47:02 -0300 | [diff] [blame] | 61 | int i; |
Amos Kong | 1048c88 | 2012-08-31 10:56:25 +0800 | [diff] [blame] | 62 | |
Markus Armbruster | 1c236ba | 2017-08-24 10:46:06 +0200 | [diff] [blame] | 63 | for (i = 0; i < Q_KEY_CODE__MAX; i++) { |
Markus Armbruster | 977c736 | 2017-08-24 10:46:08 +0200 | [diff] [blame] | 64 | if (!strncmp(key, QKeyCode_str(i), key_length) && |
| 65 | !QKeyCode_str(i)[key_length]) { |
Amos Kong | 1048c88 | 2012-08-31 10:56:25 +0800 | [diff] [blame] | 66 | break; |
| 67 | } |
| 68 | } |
| 69 | |
Eric Blake | 7fb1cf1 | 2015-11-18 01:52:57 -0700 | [diff] [blame] | 70 | /* Return Q_KEY_CODE__MAX if the key is invalid */ |
Amos Kong | 1048c88 | 2012-08-31 10:56:25 +0800 | [diff] [blame] | 71 | return i; |
| 72 | } |
| 73 | |
Gerd Hoffmann | ce53f2f | 2014-04-29 13:17:43 +0200 | [diff] [blame] | 74 | static KeyValue *copy_key_value(KeyValue *src) |
| 75 | { |
| 76 | KeyValue *dst = g_new(KeyValue, 1); |
| 77 | memcpy(dst, src, sizeof(*src)); |
Daniel P. Berrange | 1d5b8d7 | 2017-10-19 15:28:41 +0100 | [diff] [blame] | 78 | if (dst->type == KEY_VALUE_KIND_NUMBER) { |
| 79 | QKeyCode code = qemu_input_key_number_to_qcode(dst->u.number.data); |
| 80 | dst->type = KEY_VALUE_KIND_QCODE; |
| 81 | dst->u.qcode.data = code; |
| 82 | } |
Gerd Hoffmann | ce53f2f | 2014-04-29 13:17:43 +0200 | [diff] [blame] | 83 | return dst; |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 84 | } |
| 85 | |
Luiz Capitulino | 9f32897 | 2012-09-20 14:19:47 -0300 | [diff] [blame] | 86 | void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 87 | Error **errp) |
| 88 | { |
Luiz Capitulino | 9f32897 | 2012-09-20 14:19:47 -0300 | [diff] [blame] | 89 | KeyValueList *p; |
Gerd Hoffmann | e37f202 | 2014-09-26 10:02:16 +0200 | [diff] [blame] | 90 | KeyValue **up = NULL; |
| 91 | int count = 0; |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 92 | |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 93 | if (!has_hold_time) { |
Gerd Hoffmann | 2e377f1 | 2014-05-28 13:03:37 +0200 | [diff] [blame] | 94 | hold_time = 0; /* use default */ |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 95 | } |
| 96 | |
| 97 | for (p = keys; p != NULL; p = p->next) { |
Gerd Hoffmann | ce53f2f | 2014-04-29 13:17:43 +0200 | [diff] [blame] | 98 | qemu_input_event_send_key(NULL, copy_key_value(p->value), true); |
Gerd Hoffmann | 2e377f1 | 2014-05-28 13:03:37 +0200 | [diff] [blame] | 99 | qemu_input_event_send_key_delay(hold_time); |
Gerd Hoffmann | e37f202 | 2014-09-26 10:02:16 +0200 | [diff] [blame] | 100 | up = g_realloc(up, sizeof(*up) * (count+1)); |
| 101 | up[count] = copy_key_value(p->value); |
| 102 | count++; |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 103 | } |
Gerd Hoffmann | e37f202 | 2014-09-26 10:02:16 +0200 | [diff] [blame] | 104 | while (count) { |
| 105 | count--; |
| 106 | qemu_input_event_send_key(NULL, up[count], false); |
Gerd Hoffmann | 2e377f1 | 2014-05-28 13:03:37 +0200 | [diff] [blame] | 107 | qemu_input_event_send_key_delay(hold_time); |
| 108 | } |
Gerd Hoffmann | e37f202 | 2014-09-26 10:02:16 +0200 | [diff] [blame] | 109 | g_free(up); |
Amos Kong | e4c8f00 | 2012-08-31 10:56:26 +0800 | [diff] [blame] | 110 | } |
| 111 | |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 112 | static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, |
| 113 | InputEvent *evt) |
| 114 | { |
| 115 | QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev; |
Gerd Hoffmann | 02aa76c | 2014-03-11 12:15:39 +0100 | [diff] [blame] | 116 | int scancodes[3], i, count; |
Eric Blake | 32bafa8 | 2016-03-17 16:48:37 -0600 | [diff] [blame] | 117 | InputKeyEvent *key = evt->u.key.data; |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 118 | |
| 119 | if (!entry || !entry->put_kbd) { |
| 120 | return; |
| 121 | } |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 122 | count = qemu_input_key_value_to_scancode(key->key, |
| 123 | key->down, |
Gerd Hoffmann | 02aa76c | 2014-03-11 12:15:39 +0100 | [diff] [blame] | 124 | scancodes); |
| 125 | for (i = 0; i < count; i++) { |
| 126 | entry->put_kbd(entry->opaque, scancodes[i]); |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 127 | } |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | static QemuInputHandler legacy_kbd_handler = { |
| 131 | .name = "legacy-kbd", |
| 132 | .mask = INPUT_EVENT_MASK_KEY, |
| 133 | .event = legacy_kbd_event, |
| 134 | }; |
| 135 | |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 136 | QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 137 | { |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 138 | QEMUPutKbdEntry *entry; |
| 139 | |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 140 | entry = g_new0(QEMUPutKbdEntry, 1); |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 141 | entry->put_kbd = func; |
| 142 | entry->opaque = opaque; |
Gerd Hoffmann | 9784e57 | 2013-11-27 11:59:25 +0100 | [diff] [blame] | 143 | entry->s = qemu_input_handler_register((DeviceState *)entry, |
| 144 | &legacy_kbd_handler); |
Gerd Hoffmann | 7f5e07d | 2014-03-11 14:08:31 +0100 | [diff] [blame] | 145 | qemu_input_handler_activate(entry->s); |
Gerd Hoffmann | 5a37532 | 2013-04-24 12:08:38 +0200 | [diff] [blame] | 146 | return entry; |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 147 | } |
| 148 | |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 149 | static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, |
| 150 | InputEvent *evt) |
| 151 | { |
Eric Blake | 7fb1cf1 | 2015-11-18 01:52:57 -0700 | [diff] [blame] | 152 | static const int bmap[INPUT_BUTTON__MAX] = { |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 153 | [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, |
| 154 | [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, |
| 155 | [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, |
| 156 | }; |
| 157 | QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 158 | InputBtnEvent *btn; |
| 159 | InputMoveEvent *move; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 160 | |
Eric Blake | 568c73a | 2015-10-26 16:34:58 -0600 | [diff] [blame] | 161 | switch (evt->type) { |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 162 | case INPUT_EVENT_KIND_BTN: |
Eric Blake | 32bafa8 | 2016-03-17 16:48:37 -0600 | [diff] [blame] | 163 | btn = evt->u.btn.data; |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 164 | if (btn->down) { |
| 165 | s->buttons |= bmap[btn->button]; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 166 | } else { |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 167 | s->buttons &= ~bmap[btn->button]; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 168 | } |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 169 | if (btn->down && btn->button == INPUT_BUTTON_WHEEL_UP) { |
Gerd Hoffmann | dbb2a13 | 2014-03-10 09:31:01 +0100 | [diff] [blame] | 170 | s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, |
| 171 | s->axis[INPUT_AXIS_X], |
| 172 | s->axis[INPUT_AXIS_Y], |
| 173 | -1, |
| 174 | s->buttons); |
| 175 | } |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 176 | if (btn->down && btn->button == INPUT_BUTTON_WHEEL_DOWN) { |
Gerd Hoffmann | dbb2a13 | 2014-03-10 09:31:01 +0100 | [diff] [blame] | 177 | s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, |
| 178 | s->axis[INPUT_AXIS_X], |
| 179 | s->axis[INPUT_AXIS_Y], |
| 180 | 1, |
| 181 | s->buttons); |
| 182 | } |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 183 | break; |
| 184 | case INPUT_EVENT_KIND_ABS: |
Eric Blake | 32bafa8 | 2016-03-17 16:48:37 -0600 | [diff] [blame] | 185 | move = evt->u.abs.data; |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 186 | s->axis[move->axis] = move->value; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 187 | break; |
| 188 | case INPUT_EVENT_KIND_REL: |
Eric Blake | 32bafa8 | 2016-03-17 16:48:37 -0600 | [diff] [blame] | 189 | move = evt->u.rel.data; |
Eric Blake | b5a1b44 | 2016-03-03 09:16:49 -0700 | [diff] [blame] | 190 | s->axis[move->axis] += move->value; |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 191 | break; |
| 192 | default: |
| 193 | break; |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | static void legacy_mouse_sync(DeviceState *dev) |
| 198 | { |
| 199 | QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; |
| 200 | |
| 201 | s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, |
| 202 | s->axis[INPUT_AXIS_X], |
| 203 | s->axis[INPUT_AXIS_Y], |
| 204 | 0, |
| 205 | s->buttons); |
| 206 | |
| 207 | if (!s->qemu_put_mouse_event_absolute) { |
| 208 | s->axis[INPUT_AXIS_X] = 0; |
| 209 | s->axis[INPUT_AXIS_Y] = 0; |
| 210 | } |
| 211 | } |
| 212 | |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 213 | QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, |
| 214 | void *opaque, int absolute, |
| 215 | const char *name) |
| 216 | { |
Anthony Liguori | 6fef28e | 2010-03-09 20:52:22 -0600 | [diff] [blame] | 217 | QEMUPutMouseEntry *s; |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 218 | |
Markus Armbruster | fedf0d3 | 2015-11-03 17:12:03 +0100 | [diff] [blame] | 219 | s = g_new0(QEMUPutMouseEntry, 1); |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 220 | |
| 221 | s->qemu_put_mouse_event = func; |
| 222 | s->qemu_put_mouse_event_opaque = opaque; |
| 223 | s->qemu_put_mouse_event_absolute = absolute; |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 224 | |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 225 | s->h.name = name; |
| 226 | s->h.mask = INPUT_EVENT_MASK_BTN | |
| 227 | (absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL); |
| 228 | s->h.event = legacy_mouse_event; |
| 229 | s->h.sync = legacy_mouse_sync; |
| 230 | s->s = qemu_input_handler_register((DeviceState *)s, |
| 231 | &s->h); |
| 232 | |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 233 | return s; |
| 234 | } |
| 235 | |
Anthony Liguori | 6fef28e | 2010-03-09 20:52:22 -0600 | [diff] [blame] | 236 | void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry) |
| 237 | { |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 238 | qemu_input_handler_activate(entry->s); |
Anthony Liguori | 6fef28e | 2010-03-09 20:52:22 -0600 | [diff] [blame] | 239 | } |
| 240 | |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 241 | void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) |
| 242 | { |
Gerd Hoffmann | edd85a3 | 2013-11-27 17:41:40 +0100 | [diff] [blame] | 243 | qemu_input_handler_unregister(entry->s); |
| 244 | |
Anthony Liguori | 7267c09 | 2011-08-20 22:09:37 -0500 | [diff] [blame] | 245 | g_free(entry); |
Paolo Bonzini | 8f0056b | 2010-01-13 14:05:34 +0100 | [diff] [blame] | 246 | } |
| 247 | |
Gerd Hoffmann | 03a23a8 | 2010-02-26 17:17:36 +0100 | [diff] [blame] | 248 | QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, |
| 249 | void *opaque) |
| 250 | { |
| 251 | QEMUPutLEDEntry *s; |
| 252 | |
Markus Armbruster | fedf0d3 | 2015-11-03 17:12:03 +0100 | [diff] [blame] | 253 | s = g_new0(QEMUPutLEDEntry, 1); |
Gerd Hoffmann | 03a23a8 | 2010-02-26 17:17:36 +0100 | [diff] [blame] | 254 | |
| 255 | s->put_led = func; |
| 256 | s->opaque = opaque; |
| 257 | QTAILQ_INSERT_TAIL(&led_handlers, s, next); |
| 258 | return s; |
| 259 | } |
| 260 | |
| 261 | void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) |
| 262 | { |
| 263 | if (entry == NULL) |
| 264 | return; |
| 265 | QTAILQ_REMOVE(&led_handlers, entry, next); |
Anthony Liguori | 7267c09 | 2011-08-20 22:09:37 -0500 | [diff] [blame] | 266 | g_free(entry); |
Gerd Hoffmann | 03a23a8 | 2010-02-26 17:17:36 +0100 | [diff] [blame] | 267 | } |
| 268 | |
Gerd Hoffmann | 03a23a8 | 2010-02-26 17:17:36 +0100 | [diff] [blame] | 269 | void kbd_put_ledstate(int ledstate) |
| 270 | { |
| 271 | QEMUPutLEDEntry *cursor; |
| 272 | |
| 273 | QTAILQ_FOREACH(cursor, &led_handlers, next) { |
| 274 | cursor->put_led(cursor->opaque, ledstate); |
| 275 | } |
| 276 | } |