blob: e0a39f08a500bb491f4e9f184d826a6486855939 [file] [log] [blame]
Paolo Bonzini8f0056b2010-01-13 14:05:34 +01001/*
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
Paolo Bonzini9c17d612012-12-17 18:20:04 +010025#include "sysemu/sysemu.h"
Paolo Bonzini28ecbae2012-11-28 12:06:30 +010026#include "ui/console.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010027#include "qapi/error.h"
Luiz Capitulinoe235cec2011-09-21 15:29:55 -030028#include "qmp-commands.h"
Amos Konge4c8f002012-08-31 10:56:26 +080029#include "qapi-types.h"
Amos Kongb2d16742013-05-16 13:19:47 +080030#include "ui/keymaps.h"
Gerd Hoffmann9784e572013-11-27 11:59:25 +010031#include "ui/input.h"
Paolo Bonzini8f0056b2010-01-13 14:05:34 +010032
Gerd Hoffmann72711ef2013-04-24 12:08:37 +020033struct QEMUPutMouseEntry {
34 QEMUPutMouseEvent *qemu_put_mouse_event;
35 void *qemu_put_mouse_event_opaque;
36 int qemu_put_mouse_event_absolute;
Gerd Hoffmannedd85a32013-11-27 17:41:40 +010037
38 /* new input core */
39 QemuInputHandler h;
40 QemuInputHandlerState *s;
41 int axis[INPUT_AXIS_MAX];
42 int buttons;
Gerd Hoffmann72711ef2013-04-24 12:08:37 +020043};
44
Gerd Hoffmann5a375322013-04-24 12:08:38 +020045struct QEMUPutKbdEntry {
46 QEMUPutKBDEvent *put_kbd;
47 void *opaque;
Gerd Hoffmann9784e572013-11-27 11:59:25 +010048 QemuInputHandlerState *s;
Gerd Hoffmann5a375322013-04-24 12:08:38 +020049};
50
Gerd Hoffmann72711ef2013-04-24 12:08:37 +020051struct QEMUPutLEDEntry {
52 QEMUPutLEDEvent *put_led;
53 void *opaque;
54 QTAILQ_ENTRY(QEMUPutLEDEntry) next;
55};
56
Gerd Hoffmann5a375322013-04-24 12:08:38 +020057static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
58 QTAILQ_HEAD_INITIALIZER(led_handlers);
Paolo Bonzini8f0056b2010-01-13 14:05:34 +010059
Amos Kong1048c882012-08-31 10:56:25 +080060int index_from_key(const char *key)
61{
Luiz Capitulino9d537c92012-09-20 14:47:02 -030062 int i;
Amos Kong1048c882012-08-31 10:56:25 +080063
64 for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
65 if (!strcmp(key, QKeyCode_lookup[i])) {
66 break;
67 }
68 }
69
Amos Kong1048c882012-08-31 10:56:25 +080070 /* Return Q_KEY_CODE_MAX if the key is invalid */
71 return i;
72}
73
Gerd Hoffmannce53f2f2014-04-29 13:17:43 +020074static KeyValue *copy_key_value(KeyValue *src)
75{
76 KeyValue *dst = g_new(KeyValue, 1);
77 memcpy(dst, src, sizeof(*src));
78 return dst;
Amos Konge4c8f002012-08-31 10:56:26 +080079}
80
Luiz Capitulino9f328972012-09-20 14:19:47 -030081void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
Amos Konge4c8f002012-08-31 10:56:26 +080082 Error **errp)
83{
Luiz Capitulino9f328972012-09-20 14:19:47 -030084 KeyValueList *p;
Gerd Hoffmanne37f2022014-09-26 10:02:16 +020085 KeyValue **up = NULL;
86 int count = 0;
Amos Konge4c8f002012-08-31 10:56:26 +080087
Amos Konge4c8f002012-08-31 10:56:26 +080088 if (!has_hold_time) {
Gerd Hoffmann2e377f12014-05-28 13:03:37 +020089 hold_time = 0; /* use default */
Amos Konge4c8f002012-08-31 10:56:26 +080090 }
91
92 for (p = keys; p != NULL; p = p->next) {
Gerd Hoffmannce53f2f2014-04-29 13:17:43 +020093 qemu_input_event_send_key(NULL, copy_key_value(p->value), true);
Gerd Hoffmann2e377f12014-05-28 13:03:37 +020094 qemu_input_event_send_key_delay(hold_time);
Gerd Hoffmanne37f2022014-09-26 10:02:16 +020095 up = g_realloc(up, sizeof(*up) * (count+1));
96 up[count] = copy_key_value(p->value);
97 count++;
Amos Konge4c8f002012-08-31 10:56:26 +080098 }
Gerd Hoffmanne37f2022014-09-26 10:02:16 +020099 while (count) {
100 count--;
101 qemu_input_event_send_key(NULL, up[count], false);
Gerd Hoffmann2e377f12014-05-28 13:03:37 +0200102 qemu_input_event_send_key_delay(hold_time);
103 }
Gerd Hoffmanne37f2022014-09-26 10:02:16 +0200104 g_free(up);
Amos Konge4c8f002012-08-31 10:56:26 +0800105}
106
Gerd Hoffmann9784e572013-11-27 11:59:25 +0100107static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
108 InputEvent *evt)
109{
110 QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev;
Gerd Hoffmann02aa76c2014-03-11 12:15:39 +0100111 int scancodes[3], i, count;
Gerd Hoffmann9784e572013-11-27 11:59:25 +0100112
113 if (!entry || !entry->put_kbd) {
114 return;
115 }
Eric Blake568c73a2015-10-26 16:34:58 -0600116 count = qemu_input_key_value_to_scancode(evt->u.key->key,
117 evt->u.key->down,
Gerd Hoffmann02aa76c2014-03-11 12:15:39 +0100118 scancodes);
119 for (i = 0; i < count; i++) {
120 entry->put_kbd(entry->opaque, scancodes[i]);
Gerd Hoffmann9784e572013-11-27 11:59:25 +0100121 }
Gerd Hoffmann9784e572013-11-27 11:59:25 +0100122}
123
124static QemuInputHandler legacy_kbd_handler = {
125 .name = "legacy-kbd",
126 .mask = INPUT_EVENT_MASK_KEY,
127 .event = legacy_kbd_event,
128};
129
Gerd Hoffmann5a375322013-04-24 12:08:38 +0200130QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100131{
Gerd Hoffmann5a375322013-04-24 12:08:38 +0200132 QEMUPutKbdEntry *entry;
133
Gerd Hoffmann9784e572013-11-27 11:59:25 +0100134 entry = g_new0(QEMUPutKbdEntry, 1);
Gerd Hoffmann5a375322013-04-24 12:08:38 +0200135 entry->put_kbd = func;
136 entry->opaque = opaque;
Gerd Hoffmann9784e572013-11-27 11:59:25 +0100137 entry->s = qemu_input_handler_register((DeviceState *)entry,
138 &legacy_kbd_handler);
Gerd Hoffmann7f5e07d2014-03-11 14:08:31 +0100139 qemu_input_handler_activate(entry->s);
Gerd Hoffmann5a375322013-04-24 12:08:38 +0200140 return entry;
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100141}
142
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100143static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
144 InputEvent *evt)
145{
146 static const int bmap[INPUT_BUTTON_MAX] = {
147 [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
148 [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
149 [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
150 };
151 QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
152
Eric Blake568c73a2015-10-26 16:34:58 -0600153 switch (evt->type) {
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100154 case INPUT_EVENT_KIND_BTN:
Eric Blake568c73a2015-10-26 16:34:58 -0600155 if (evt->u.btn->down) {
156 s->buttons |= bmap[evt->u.btn->button];
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100157 } else {
Eric Blake568c73a2015-10-26 16:34:58 -0600158 s->buttons &= ~bmap[evt->u.btn->button];
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100159 }
Eric Blake568c73a2015-10-26 16:34:58 -0600160 if (evt->u.btn->down && evt->u.btn->button == INPUT_BUTTON_WHEEL_UP) {
Gerd Hoffmanndbb2a132014-03-10 09:31:01 +0100161 s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
162 s->axis[INPUT_AXIS_X],
163 s->axis[INPUT_AXIS_Y],
164 -1,
165 s->buttons);
166 }
Eric Blake568c73a2015-10-26 16:34:58 -0600167 if (evt->u.btn->down &&
168 evt->u.btn->button == INPUT_BUTTON_WHEEL_DOWN) {
Gerd Hoffmanndbb2a132014-03-10 09:31:01 +0100169 s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
170 s->axis[INPUT_AXIS_X],
171 s->axis[INPUT_AXIS_Y],
172 1,
173 s->buttons);
174 }
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100175 break;
176 case INPUT_EVENT_KIND_ABS:
Eric Blake568c73a2015-10-26 16:34:58 -0600177 s->axis[evt->u.abs->axis] = evt->u.abs->value;
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100178 break;
179 case INPUT_EVENT_KIND_REL:
Eric Blake568c73a2015-10-26 16:34:58 -0600180 s->axis[evt->u.rel->axis] += evt->u.rel->value;
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100181 break;
182 default:
183 break;
184 }
185}
186
187static void legacy_mouse_sync(DeviceState *dev)
188{
189 QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
190
191 s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
192 s->axis[INPUT_AXIS_X],
193 s->axis[INPUT_AXIS_Y],
194 0,
195 s->buttons);
196
197 if (!s->qemu_put_mouse_event_absolute) {
198 s->axis[INPUT_AXIS_X] = 0;
199 s->axis[INPUT_AXIS_Y] = 0;
200 }
201}
202
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100203QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
204 void *opaque, int absolute,
205 const char *name)
206{
Anthony Liguori6fef28e2010-03-09 20:52:22 -0600207 QEMUPutMouseEntry *s;
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100208
Markus Armbrusterfedf0d32015-11-03 17:12:03 +0100209 s = g_new0(QEMUPutMouseEntry, 1);
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100210
211 s->qemu_put_mouse_event = func;
212 s->qemu_put_mouse_event_opaque = opaque;
213 s->qemu_put_mouse_event_absolute = absolute;
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100214
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100215 s->h.name = name;
216 s->h.mask = INPUT_EVENT_MASK_BTN |
217 (absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL);
218 s->h.event = legacy_mouse_event;
219 s->h.sync = legacy_mouse_sync;
220 s->s = qemu_input_handler_register((DeviceState *)s,
221 &s->h);
222
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100223 return s;
224}
225
Anthony Liguori6fef28e2010-03-09 20:52:22 -0600226void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
227{
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100228 qemu_input_handler_activate(entry->s);
Anthony Liguori6fef28e2010-03-09 20:52:22 -0600229}
230
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100231void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
232{
Gerd Hoffmannedd85a32013-11-27 17:41:40 +0100233 qemu_input_handler_unregister(entry->s);
234
Anthony Liguori7267c092011-08-20 22:09:37 -0500235 g_free(entry);
Paolo Bonzini8f0056b2010-01-13 14:05:34 +0100236}
237
Gerd Hoffmann03a23a82010-02-26 17:17:36 +0100238QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
239 void *opaque)
240{
241 QEMUPutLEDEntry *s;
242
Markus Armbrusterfedf0d32015-11-03 17:12:03 +0100243 s = g_new0(QEMUPutLEDEntry, 1);
Gerd Hoffmann03a23a82010-02-26 17:17:36 +0100244
245 s->put_led = func;
246 s->opaque = opaque;
247 QTAILQ_INSERT_TAIL(&led_handlers, s, next);
248 return s;
249}
250
251void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
252{
253 if (entry == NULL)
254 return;
255 QTAILQ_REMOVE(&led_handlers, entry, next);
Anthony Liguori7267c092011-08-20 22:09:37 -0500256 g_free(entry);
Gerd Hoffmann03a23a82010-02-26 17:17:36 +0100257}
258
Gerd Hoffmann03a23a82010-02-26 17:17:36 +0100259void kbd_put_ledstate(int ledstate)
260{
261 QEMUPutLEDEntry *cursor;
262
263 QTAILQ_FOREACH(cursor, &led_handlers, next) {
264 cursor->put_led(cursor->opaque, ledstate);
265 }
266}