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