input.c revision aa8236dc1b1ea300ab18716db5b8fab42aca3ca7
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 "net/net.h"
27#include "monitor/monitor.h"
28#include "ui/console.h"
29#include "qapi/qmp/qjson.h"
30
31#ifdef CONFIG_SKINNING
32QEMUPutMouseEntry *original_qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
33                                                         void *opaque, int absolute,
34                                                         const char *name);
35#undef qemu_add_mouse_event_handler
36#define qemu_add_mouse_event_handler original_qemu_add_mouse_event_handler
37#endif
38static QTAILQ_HEAD(, QEMUPutKBDEntry) kbd_handlers =
39    QTAILQ_HEAD_INITIALIZER(kbd_handlers);
40static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers);
41static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
42    QTAILQ_HEAD_INITIALIZER(mouse_handlers);
43static NotifierList mouse_mode_notifiers =
44    NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
45
46void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
47{
48    QEMUPutKBDEntry *s;
49
50    if (func != NULL) {
51        s = g_malloc0(sizeof(QEMUPutKBDEntry));
52
53        s->put_kbd_event = func;
54        s->opaque = opaque;
55
56        QTAILQ_INSERT_TAIL(&kbd_handlers, s, next);
57    }
58}
59
60void qemu_remove_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
61{
62    QEMUPutKBDEntry *cursor, *cursor_next;
63    if (func != NULL) {
64        QTAILQ_FOREACH_SAFE(cursor, &kbd_handlers, next, cursor_next) {
65            if (cursor->put_kbd_event == func && cursor->opaque == opaque) {
66                QTAILQ_REMOVE(&kbd_handlers, cursor, next);
67            }
68        }
69    }
70}
71
72static void check_mode_change(void)
73{
74    static int current_is_absolute, current_has_absolute;
75    int is_absolute;
76    int has_absolute;
77
78    is_absolute = kbd_mouse_is_absolute();
79    has_absolute = kbd_mouse_has_absolute();
80
81    if (is_absolute != current_is_absolute ||
82        has_absolute != current_has_absolute) {
83        notifier_list_notify(&mouse_mode_notifiers);
84    }
85
86    current_is_absolute = is_absolute;
87    current_has_absolute = has_absolute;
88}
89
90QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
91                                                void *opaque, int absolute,
92                                                const char *name)
93{
94    QEMUPutMouseEntry *s;
95    static int mouse_index = 0;
96
97    s = g_malloc0(sizeof(QEMUPutMouseEntry));
98
99    s->qemu_put_mouse_event = func;
100    s->qemu_put_mouse_event_opaque = opaque;
101    s->qemu_put_mouse_event_absolute = absolute;
102    s->qemu_put_mouse_event_name = g_strdup(name);
103    s->index = mouse_index++;
104
105    QTAILQ_INSERT_TAIL(&mouse_handlers, s, node);
106
107    check_mode_change();
108
109    return s;
110}
111
112void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
113{
114    QTAILQ_REMOVE(&mouse_handlers, entry, node);
115    QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node);
116
117    check_mode_change();
118}
119
120void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
121{
122    QTAILQ_REMOVE(&mouse_handlers, entry, node);
123
124    g_free(entry->qemu_put_mouse_event_name);
125    g_free(entry);
126
127    check_mode_change();
128}
129
130QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
131                                            void *opaque)
132{
133    QEMUPutLEDEntry *s;
134
135    s = g_malloc0(sizeof(QEMUPutLEDEntry));
136
137    s->put_led = func;
138    s->opaque = opaque;
139    QTAILQ_INSERT_TAIL(&led_handlers, s, next);
140    return s;
141}
142
143void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
144{
145    if (entry == NULL)
146        return;
147    QTAILQ_REMOVE(&led_handlers, entry, next);
148    g_free(entry);
149}
150
151void kbd_put_keycode(int keycode)
152{
153    QEMUPutKBDEntry *cursor;
154    QTAILQ_FOREACH(cursor, &kbd_handlers, next) {
155        cursor->put_kbd_event(cursor->opaque, keycode);
156    }
157}
158
159void kbd_put_ledstate(int ledstate)
160{
161    QEMUPutLEDEntry *cursor;
162
163    QTAILQ_FOREACH(cursor, &led_handlers, next) {
164        cursor->put_led(cursor->opaque, ledstate);
165    }
166}
167
168void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
169{
170    QEMUPutMouseEntry *entry;
171    QEMUPutMouseEvent *mouse_event;
172    void *mouse_event_opaque;
173#ifndef CONFIG_SKINNING
174    int width;
175#endif
176
177    if (QTAILQ_EMPTY(&mouse_handlers)) {
178        return;
179    }
180
181    entry = QTAILQ_FIRST(&mouse_handlers);
182
183    mouse_event = entry->qemu_put_mouse_event;
184    mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
185
186    if (mouse_event) {
187#ifndef CONFIG_SKINNING
188        if (graphic_rotate) {
189            if (entry->qemu_put_mouse_event_absolute) {
190                width = 0x7fff;
191            } else {
192                width = graphic_width - 1;
193            }
194            mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state);
195        } else {
196            mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
197        }
198#else
199        mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
200#endif
201    }
202}
203
204int kbd_mouse_is_absolute(void)
205{
206    if (QTAILQ_EMPTY(&mouse_handlers)) {
207        return 0;
208    }
209
210    return QTAILQ_FIRST(&mouse_handlers)->qemu_put_mouse_event_absolute;
211}
212
213int kbd_mouse_has_absolute(void)
214{
215    QEMUPutMouseEntry *entry;
216
217    QTAILQ_FOREACH(entry, &mouse_handlers, node) {
218        if (entry->qemu_put_mouse_event_absolute) {
219            return 1;
220        }
221    }
222
223    return 0;
224}
225
226static void info_mice_iter(QObject *data, void *opaque)
227{
228    QDict *mouse;
229    Monitor *mon = opaque;
230
231    mouse = qobject_to_qdict(data);
232    monitor_printf(mon, "%c Mouse #%" PRId64 ": %s%s\n",
233                  (qdict_get_bool(mouse, "current") ? '*' : ' '),
234                   qdict_get_int(mouse, "index"), qdict_get_str(mouse, "name"),
235                   qdict_get_bool(mouse, "absolute") ? " (absolute)" : "");
236}
237
238void do_info_mice_print(Monitor *mon, const QObject *data)
239{
240    QList *mice_list;
241
242    mice_list = qobject_to_qlist(data);
243    if (qlist_empty(mice_list)) {
244        monitor_printf(mon, "No mouse devices connected\n");
245        return;
246    }
247
248    qlist_iter(mice_list, info_mice_iter, mon);
249}
250
251void do_info_mice(Monitor *mon, QObject **ret_data)
252{
253    QEMUPutMouseEntry *cursor;
254    QList *mice_list;
255    int current;
256
257    mice_list = qlist_new();
258
259    if (QTAILQ_EMPTY(&mouse_handlers)) {
260        goto out;
261    }
262
263    current = QTAILQ_FIRST(&mouse_handlers)->index;
264
265    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
266        QObject *obj;
267        obj = qobject_from_jsonf("{ 'name': %s,"
268                                 "  'index': %d,"
269                                 "  'current': %i,"
270                                 "  'absolute': %i }",
271                                 cursor->qemu_put_mouse_event_name,
272                                 cursor->index,
273                                 cursor->index == current,
274                                 !!cursor->qemu_put_mouse_event_absolute);
275        qlist_append_obj(mice_list, obj);
276    }
277
278out:
279    *ret_data = QOBJECT(mice_list);
280}
281
282void do_mouse_set(Monitor *mon, const QDict *qdict)
283{
284    QEMUPutMouseEntry *cursor;
285    int index = qdict_get_int(qdict, "index");
286    int found = 0;
287
288    if (QTAILQ_EMPTY(&mouse_handlers)) {
289        monitor_printf(mon, "No mouse devices connected\n");
290        return;
291    }
292
293    QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
294        if (cursor->index == index) {
295            found = 1;
296            qemu_activate_mouse_event_handler(cursor);
297            break;
298        }
299    }
300
301    if (!found) {
302        monitor_printf(mon, "Mouse at given index not found\n");
303    }
304
305    check_mode_change();
306}
307
308void qemu_add_mouse_mode_change_notifier(Notifier *notify)
309{
310    notifier_list_add(&mouse_mode_notifiers, notify);
311}
312
313void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
314{
315    notifier_list_remove(&mouse_mode_notifiers, notify);
316}
317