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