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 25 #include "sysemu/sysemu.h" 26 #include "monitor/monitor.h" 27 #include "ui/console.h" 28 #include "qapi/error.h" 29 #include "qmp-commands.h" 30 #include "qapi-types.h" 31 #include "ui/keymaps.h" 32 #include "ui/input.h" 33 34 struct QEMUPutMouseEntry { 35 QEMUPutMouseEvent *qemu_put_mouse_event; 36 void *qemu_put_mouse_event_opaque; 37 int qemu_put_mouse_event_absolute; 38 39 /* new input core */ 40 QemuInputHandler h; 41 QemuInputHandlerState *s; 42 int axis[INPUT_AXIS_MAX]; 43 int buttons; 44 }; 45 46 struct QEMUPutKbdEntry { 47 QEMUPutKBDEvent *put_kbd; 48 void *opaque; 49 QemuInputHandlerState *s; 50 }; 51 52 struct QEMUPutLEDEntry { 53 QEMUPutLEDEvent *put_led; 54 void *opaque; 55 QTAILQ_ENTRY(QEMUPutLEDEntry) next; 56 }; 57 58 static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = 59 QTAILQ_HEAD_INITIALIZER(led_handlers); 60 static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = 61 QTAILQ_HEAD_INITIALIZER(mouse_handlers); 62 63 int index_from_key(const char *key) 64 { 65 int i; 66 67 for (i = 0; QKeyCode_lookup[i] != NULL; i++) { 68 if (!strcmp(key, QKeyCode_lookup[i])) { 69 break; 70 } 71 } 72 73 /* Return Q_KEY_CODE_MAX if the key is invalid */ 74 return i; 75 } 76 77 static KeyValue *copy_key_value(KeyValue *src) 78 { 79 KeyValue *dst = g_new(KeyValue, 1); 80 memcpy(dst, src, sizeof(*src)); 81 return dst; 82 } 83 84 void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, 85 Error **errp) 86 { 87 KeyValueList *p; 88 KeyValue **up = NULL; 89 int count = 0; 90 91 if (!has_hold_time) { 92 hold_time = 0; /* use default */ 93 } 94 95 for (p = keys; p != NULL; p = p->next) { 96 qemu_input_event_send_key(NULL, copy_key_value(p->value), true); 97 qemu_input_event_send_key_delay(hold_time); 98 up = g_realloc(up, sizeof(*up) * (count+1)); 99 up[count] = copy_key_value(p->value); 100 count++; 101 } 102 while (count) { 103 count--; 104 qemu_input_event_send_key(NULL, up[count], false); 105 qemu_input_event_send_key_delay(hold_time); 106 } 107 g_free(up); 108 } 109 110 static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, 111 InputEvent *evt) 112 { 113 QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev; 114 int scancodes[3], i, count; 115 116 if (!entry || !entry->put_kbd) { 117 return; 118 } 119 count = qemu_input_key_value_to_scancode(evt->key->key, 120 evt->key->down, 121 scancodes); 122 for (i = 0; i < count; i++) { 123 entry->put_kbd(entry->opaque, scancodes[i]); 124 } 125 } 126 127 static QemuInputHandler legacy_kbd_handler = { 128 .name = "legacy-kbd", 129 .mask = INPUT_EVENT_MASK_KEY, 130 .event = legacy_kbd_event, 131 }; 132 133 QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) 134 { 135 QEMUPutKbdEntry *entry; 136 137 entry = g_new0(QEMUPutKbdEntry, 1); 138 entry->put_kbd = func; 139 entry->opaque = opaque; 140 entry->s = qemu_input_handler_register((DeviceState *)entry, 141 &legacy_kbd_handler); 142 qemu_input_handler_activate(entry->s); 143 return entry; 144 } 145 146 void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry) 147 { 148 qemu_input_handler_unregister(entry->s); 149 g_free(entry); 150 } 151 152 static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, 153 InputEvent *evt) 154 { 155 static const int bmap[INPUT_BUTTON_MAX] = { 156 [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, 157 [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, 158 [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, 159 }; 160 QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; 161 162 switch (evt->kind) { 163 case INPUT_EVENT_KIND_BTN: 164 if (evt->btn->down) { 165 s->buttons |= bmap[evt->btn->button]; 166 } else { 167 s->buttons &= ~bmap[evt->btn->button]; 168 } 169 if (evt->btn->down && evt->btn->button == INPUT_BUTTON_WHEEL_UP) { 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 } 176 if (evt->btn->down && evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { 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 } 183 break; 184 case INPUT_EVENT_KIND_ABS: 185 s->axis[evt->abs->axis] = evt->abs->value; 186 break; 187 case INPUT_EVENT_KIND_REL: 188 s->axis[evt->rel->axis] += evt->rel->value; 189 break; 190 default: 191 break; 192 } 193 } 194 195 static void legacy_mouse_sync(DeviceState *dev) 196 { 197 QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; 198 199 s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, 200 s->axis[INPUT_AXIS_X], 201 s->axis[INPUT_AXIS_Y], 202 0, 203 s->buttons); 204 205 if (!s->qemu_put_mouse_event_absolute) { 206 s->axis[INPUT_AXIS_X] = 0; 207 s->axis[INPUT_AXIS_Y] = 0; 208 } 209 } 210 211 QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, 212 void *opaque, int absolute, 213 const char *name) 214 { 215 QEMUPutMouseEntry *s; 216 217 s = g_malloc0(sizeof(QEMUPutMouseEntry)); 218 219 s->qemu_put_mouse_event = func; 220 s->qemu_put_mouse_event_opaque = opaque; 221 s->qemu_put_mouse_event_absolute = absolute; 222 223 s->h.name = name; 224 s->h.mask = INPUT_EVENT_MASK_BTN | 225 (absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL); 226 s->h.event = legacy_mouse_event; 227 s->h.sync = legacy_mouse_sync; 228 s->s = qemu_input_handler_register((DeviceState *)s, 229 &s->h); 230 231 return s; 232 } 233 234 void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry) 235 { 236 qemu_input_handler_activate(entry->s); 237 } 238 239 void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) 240 { 241 qemu_input_handler_unregister(entry->s); 242 243 g_free(entry); 244 } 245 246 QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, 247 void *opaque) 248 { 249 QEMUPutLEDEntry *s; 250 251 s = g_malloc0(sizeof(QEMUPutLEDEntry)); 252 253 s->put_led = func; 254 s->opaque = opaque; 255 QTAILQ_INSERT_TAIL(&led_handlers, s, next); 256 return s; 257 } 258 259 void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) 260 { 261 if (entry == NULL) 262 return; 263 QTAILQ_REMOVE(&led_handlers, entry, next); 264 g_free(entry); 265 } 266 267 void kbd_put_ledstate(int ledstate) 268 { 269 QEMUPutLEDEntry *cursor; 270 271 QTAILQ_FOREACH(cursor, &led_handlers, next) { 272 cursor->put_led(cursor->opaque, ledstate); 273 } 274 } 275