diff options
-rw-r--r-- | docs/multiseat.txt | 76 | ||||
-rw-r--r-- | hw/input/hid.c | 220 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 13 | ||||
-rw-r--r-- | include/hw/input/hid.h | 4 | ||||
-rw-r--r-- | include/ui/input.h | 4 | ||||
-rw-r--r-- | trace-events | 2 | ||||
-rw-r--r-- | ui/curses.c | 4 | ||||
-rw-r--r-- | ui/input-keymap.c | 13 | ||||
-rw-r--r-- | ui/input.c | 49 | ||||
-rw-r--r-- | ui/sdl2.c | 21 |
10 files changed, 308 insertions, 98 deletions
diff --git a/docs/multiseat.txt b/docs/multiseat.txt new file mode 100644 index 0000000000..a6c71dd74f --- /dev/null +++ b/docs/multiseat.txt @@ -0,0 +1,76 @@ + +multiseat howto (with some multihead coverage) +============================================== + +host side +--------- + +First you must compile qemu with a user interface supporting +multihead/multiseat and input event routing. Right now this list is +pretty short: sdl2. + + ./configure --enable-sdl --with-sdlabi=2.0 + + +Next put together the qemu command line: + +qemu -enable-kvm -usb $memory $disk $whatever \ + -display sdl \ + -vga std \ + -device usb-tablet + +That is it for the first head, which will use the standard vga, the +standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the +additional switches for the second head: + + -device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \ + -device secondary-vga,bus=head.2,addr=02.0,id=video.2 \ + -device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \ + -device usb-kbd,bus=usb.2.0,port=1,display=video.2 \ + -device usb-tablet,bus=usb.2.0,port=2,display=video.2 + +This places a pci bridge in slot 12, connects a display adapter and +xhci (usb) controller to the bridge. Then it adds a usb keyboard and +usb mouse, both connected to the xhci and linked to the display. + +The "display=video2" sets up the input routing. Any input coming from +the window which belongs to the video.2 display adapter will be routed +to these input devices. + + +guest side +---------- + +You need a pretty recent linux guest. systemd with loginctl. kernel +3.14+ with CONFIG_DRM_BOCHS enabled. Fedora 20 will do. Must be +fully updated for the new kernel though, i.e. the live iso doesn't cut +it. + +Now we'll have to configure the guest. Boot and login. By default +all devices belong to seat0. You can use "loginctl seat-status seat0" +to list them all (and to get the sysfs paths for cut+paste). Now +we'll go assign all pci devices connected the pci bridge in slot 12 to +a new head: + +loginctl attach seat-qemu \ + /sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1 +loginctl attach seat-qemu \ + /sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1 +loginctl attach seat-qemu \ + /sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2 + +Use "loginctl seat-status seat-qemu" to check the result. It isn't +needed to assign the usb devices to the head individually, assigning a +usb (root) hub will automatically assign all usb devices connected to +it too. + +BTW: loginctl writes udev rules to /etc/udev/rules.d to make these +device assignments permanent, so you need to do this only once. + +Now simply restart gdm (rebooting will do too), and a login screen +should show up on the second head. + +Enjoy! + +-- +Gerd Hoffmann <kraxel@redhat.com> diff --git a/hw/input/hid.c b/hw/input/hid.c index bb0fa6a619..295bdab652 100644 --- a/hw/input/hid.c +++ b/hw/input/hid.c @@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs) } } -static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons) +static void hid_pointer_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - e->xdx = e->ydy = e->dz = 0; - e->buttons_state = buttons; -} + static const int bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = 0x01, + [INPUT_BUTTON_RIGHT] = 0x02, + [INPUT_BUTTON_MIDDLE] = 0x04, + }; + HIDState *hs = (HIDState *)dev; + HIDPointerEvent *e; -static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel, - int x1, int y1, int z1) { - if (xyrel) { - e->xdx += x1; - e->ydy += y1; - } else { - e->xdx = x1; - e->ydy = y1; - /* Windows drivers do not like the 0/0 position and ignore such - * events. */ - if (!(x1 | y1)) { - e->xdx = 1; + assert(hs->n < QUEUE_LENGTH); + e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; + + switch (evt->kind) { + case INPUT_EVENT_KIND_REL: + if (evt->rel->axis == INPUT_AXIS_X) { + e->xdx += evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + e->ydy -= evt->rel->value; + } + break; + + case INPUT_EVENT_KIND_ABS: + if (evt->rel->axis == INPUT_AXIS_X) { + e->xdx = evt->rel->value; + } else if (evt->rel->axis == INPUT_AXIS_Y) { + e->ydy = evt->rel->value; } + break; + + case INPUT_EVENT_KIND_BTN: + if (evt->btn->down) { + e->buttons_state |= bmap[evt->btn->button]; + if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) { + e->dz--; + } else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { + e->dz++; + } + } else { + e->buttons_state &= ~bmap[evt->btn->button]; + } + break; + + default: + /* keep gcc happy */ + break; } - e->dz += z1; + } -static void hid_pointer_event(void *opaque, - int x1, int y1, int z1, int buttons_state) +static void hid_pointer_sync(DeviceState *dev) { - HIDState *hs = opaque; - unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK; - unsigned previous_slot = (use_slot - 1) & QUEUE_MASK; - - /* We combine events where feasible to keep the queue small. We shouldn't - * combine anything with the first event of a particular button state, as - * that would change the location of the button state change. When the - * queue is empty, a second event is needed because we don't know if - * the first event changed the button state. */ - if (hs->n == QUEUE_LENGTH) { - /* Queue full. Discard old button state, combine motion normally. */ - hs->ptr.queue[use_slot].buttons_state = buttons_state; - } else if (hs->n < 2 || - hs->ptr.queue[use_slot].buttons_state != buttons_state || - hs->ptr.queue[previous_slot].buttons_state != - hs->ptr.queue[use_slot].buttons_state) { - /* Cannot or should not combine, so add an empty item to the queue. */ - QUEUE_INCR(use_slot); + HIDState *hs = (HIDState *)dev; + HIDPointerEvent *prev, *curr, *next; + bool event_compression = false; + + if (hs->n == QUEUE_LENGTH-1) { + /* + * Queue full. We are loosing information, but we at least + * keep track of most recent button state. + */ + return; + } + + prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK]; + curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK]; + next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK]; + + if (hs->n > 0) { + /* + * No button state change between previous and current event + * (and previous wasn't seen by the guest yet), so there is + * motion information only and we can combine the two event + * into one. + */ + if (curr->buttons_state == prev->buttons_state) { + event_compression = true; + } + } + + if (event_compression) { + /* add current motion to previous, clear current */ + if (hs->kind == HID_MOUSE) { + prev->xdx += curr->xdx; + curr->xdx = 0; + prev->ydy -= curr->ydy; + curr->ydy = 0; + } else { + prev->xdx = curr->xdx; + prev->ydy = curr->ydy; + } + prev->dz += curr->dz; + curr->dz = 0; + } else { + /* prepate next (clear rel, copy abs + btns) */ + if (hs->kind == HID_MOUSE) { + next->xdx = 0; + next->ydy = 0; + } else { + next->xdx = curr->xdx; + next->ydy = curr->ydy; + } + next->dz = 0; + next->buttons_state = curr->buttons_state; + /* make current guest visible, notify guest */ hs->n++; - hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state); + hs->event(hs); } - hid_pointer_event_combine(&hs->ptr.queue[use_slot], - hs->kind == HID_MOUSE, - x1, y1, z1); - hs->event(hs); } -static void hid_keyboard_event(void *opaque, int keycode) +static void hid_keyboard_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) { - HIDState *hs = opaque; + HIDState *hs = (HIDState *)dev; + int scancodes[3], i, count; int slot; - if (hs->n == QUEUE_LENGTH) { + count = qemu_input_key_value_to_scancode(evt->key->key, + evt->key->down, + scancodes); + if (hs->n + count > QUEUE_LENGTH) { fprintf(stderr, "usb-kbd: warning: key event queue full\n"); return; } - slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; - hs->kbd.keycodes[slot] = keycode; + for (i = 0; i < count; i++) { + slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++; + hs->kbd.keycodes[slot] = scancodes[i]; + } hs->event(hs); } @@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax) void hid_pointer_activate(HIDState *hs) { if (!hs->ptr.mouse_grabbed) { - qemu_activate_mouse_event_handler(hs->ptr.eh_entry); + qemu_input_handler_activate(hs->s); hs->ptr.mouse_grabbed = 1; } } int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) { - int dx, dy, dz, b, l; + int dx, dy, dz, l; int index; HIDPointerEvent *e; @@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) dz = int_clamp(e->dz, -127, 127); e->dz -= dz; - b = 0; - if (e->buttons_state & MOUSE_EVENT_LBUTTON) { - b |= 0x01; - } - if (e->buttons_state & MOUSE_EVENT_RBUTTON) { - b |= 0x02; - } - if (e->buttons_state & MOUSE_EVENT_MBUTTON) { - b |= 0x04; - } - if (hs->n && !e->dz && (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) { @@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) switch (hs->kind) { case HID_MOUSE: if (len > l) { - buf[l++] = b; + buf[l++] = e->buttons_state; } if (len > l) { buf[l++] = dx; @@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len) case HID_TABLET: if (len > l) { - buf[l++] = b; + buf[l++] = e->buttons_state; } if (len > l) { buf[l++] = dx & 0xff; @@ -413,31 +467,45 @@ void hid_reset(HIDState *hs) void hid_free(HIDState *hs) { - switch (hs->kind) { - case HID_KEYBOARD: - qemu_remove_kbd_event_handler(hs->kbd.eh_entry); - break; - case HID_MOUSE: - case HID_TABLET: - qemu_remove_mouse_event_handler(hs->ptr.eh_entry); - break; - } + qemu_input_handler_unregister(hs->s); hid_del_idle_timer(hs); } +static QemuInputHandler hid_keyboard_handler = { + .name = "QEMU HID Keyboard", + .mask = INPUT_EVENT_MASK_KEY, + .event = hid_keyboard_event, +}; + +static QemuInputHandler hid_mouse_handler = { + .name = "QEMU HID Mouse", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, + .event = hid_pointer_event, + .sync = hid_pointer_sync, +}; + +static QemuInputHandler hid_tablet_handler = { + .name = "QEMU HID Tablet", + .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, + .event = hid_pointer_event, + .sync = hid_pointer_sync, +}; + void hid_init(HIDState *hs, int kind, HIDEventFunc event) { hs->kind = kind; hs->event = event; if (hs->kind == HID_KEYBOARD) { - hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_keyboard_handler); + qemu_input_handler_activate(hs->s); } else if (hs->kind == HID_MOUSE) { - hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, - 0, "QEMU HID Mouse"); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_mouse_handler); } else if (hs->kind == HID_TABLET) { - hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs, - 1, "QEMU HID Tablet"); + hs->s = qemu_input_handler_register((DeviceState *)hs, + &hid_tablet_handler); } } diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index d097d937ea..67a57f1dcd 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -47,6 +47,8 @@ typedef struct USBHIDState { USBEndpoint *intr; HIDState hid; uint32_t usb_version; + char *display; + uint32_t head; } USBHIDState; enum { @@ -574,6 +576,9 @@ static int usb_hid_initfn(USBDevice *dev, int kind) usb_desc_init(dev); us->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); hid_init(&us->hid, kind, usb_hid_changed); + if (us->display && us->hid.s) { + qemu_input_handler_bind(us->hid.s, us->display, us->head, NULL); + } return 0; } @@ -653,6 +658,8 @@ static void usb_hid_class_initfn(ObjectClass *klass, void *data) static Property usb_tablet_properties[] = { DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), + DEFINE_PROP_STRING("display", USBHIDState, display), + DEFINE_PROP_UINT32("head", USBHIDState, head, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -696,6 +703,11 @@ static const TypeInfo usb_mouse_info = { .class_init = usb_mouse_class_initfn, }; +static Property usb_keyboard_properties[] = { + DEFINE_PROP_STRING("display", USBHIDState, display), + DEFINE_PROP_END_OF_LIST(), +}; + static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -706,6 +718,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Keyboard"; uc->usb_desc = &desc_keyboard; dc->vmsd = &vmstate_usb_kbd; + dc->props = usb_keyboard_properties; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h index 2567879399..2127c7ce45 100644 --- a/include/hw/input/hid.h +++ b/include/hw/input/hid.h @@ -2,6 +2,7 @@ #define QEMU_HID_H #include "migration/vmstate.h" +#include "ui/input.h" #define HID_MOUSE 1 #define HID_TABLET 2 @@ -22,7 +23,6 @@ typedef void (*HIDEventFunc)(HIDState *s); typedef struct HIDMouseState { HIDPointerEvent queue[QUEUE_LENGTH]; int mouse_grabbed; - QEMUPutMouseEntry *eh_entry; } HIDMouseState; typedef struct HIDKeyboardState { @@ -31,7 +31,6 @@ typedef struct HIDKeyboardState { uint8_t leds; uint8_t key[16]; int32_t keys; - QEMUPutKbdEntry *eh_entry; } HIDKeyboardState; struct HIDState { @@ -47,6 +46,7 @@ struct HIDState { bool idle_pending; QEMUTimer *idle_timer; HIDEventFunc event; + QemuInputHandlerState *s; }; void hid_init(HIDState *hs, int kind, HIDEventFunc event); diff --git a/include/ui/input.h b/include/ui/input.h index 3d3d487f18..aa99b0cac7 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -29,6 +29,9 @@ QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, void qemu_input_handler_activate(QemuInputHandlerState *s); void qemu_input_handler_deactivate(QemuInputHandlerState *s); void qemu_input_handler_unregister(QemuInputHandlerState *s); +void qemu_input_handler_bind(QemuInputHandlerState *s, + const char *device_id, int head, + Error **errp); void qemu_input_event_send(QemuConsole *src, InputEvent *evt); void qemu_input_event_sync(void); @@ -36,6 +39,7 @@ InputEvent *qemu_input_event_new_key(KeyValue *key, bool down); void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down); void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down); void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down); +int qemu_input_key_number_to_qcode(uint8_t nr); int qemu_input_key_value_to_number(const KeyValue *value); int qemu_input_key_value_to_qcode(const KeyValue *value); int qemu_input_key_value_to_scancode(const KeyValue *value, bool down, diff --git a/trace-events b/trace-events index 7a415d952a..ea56d5281e 100644 --- a/trace-events +++ b/trace-events @@ -1047,7 +1047,7 @@ gd_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d" gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)" # ui/input.c -input_event_key_number(int conidx, int number, bool down) "con %d, key number 0x%x, down %d" +input_event_key_number(int conidx, int number, const char *qcode, bool down) "con %d, key number 0x%x [%s], down %d" input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d" input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d" input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d" diff --git a/ui/curses.c b/ui/curses.c index b044790e43..de85f7610f 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -288,8 +288,8 @@ static void curses_refresh(DisplayChangeListener *dcl) qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true); } - qemu_input_event_send_key_number(NULL, keycode, true); - qemu_input_event_send_key_number(NULL, keycode, false); + qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, true); + qemu_input_event_send_key_number(NULL, keycode & KEY_MASK, false); if (keycode & ALTGR) { qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); diff --git a/ui/input-keymap.c b/ui/input-keymap.c index 6da4495103..5d299353a8 100644 --- a/ui/input-keymap.c +++ b/ui/input-keymap.c @@ -13,6 +13,8 @@ static const int qcode_to_number[] = { [Q_KEY_CODE_CTRL] = 0x1d, [Q_KEY_CODE_CTRL_R] = 0x9d, + [Q_KEY_CODE_META_L] = 0xdb, + [Q_KEY_CODE_META_R] = 0xdc, [Q_KEY_CODE_MENU] = 0xdd, [Q_KEY_CODE_ESC] = 0x01, @@ -129,7 +131,7 @@ static const int qcode_to_number[] = { [Q_KEY_CODE_MAX] = 0, }; -static int number_to_qcode[0xff]; +static int number_to_qcode[0x100]; int qemu_input_key_value_to_number(const KeyValue *value) { @@ -141,7 +143,7 @@ int qemu_input_key_value_to_number(const KeyValue *value) } } -int qemu_input_key_value_to_qcode(const KeyValue *value) +int qemu_input_key_number_to_qcode(uint8_t nr) { static int first = true; @@ -155,11 +157,16 @@ int qemu_input_key_value_to_qcode(const KeyValue *value) } } + return number_to_qcode[nr]; +} + +int qemu_input_key_value_to_qcode(const KeyValue *value) +{ if (value->kind == KEY_VALUE_KIND_QCODE) { return value->qcode; } else { assert(value->kind == KEY_VALUE_KIND_NUMBER); - return number_to_qcode[value->number]; + return qemu_input_key_number_to_qcode(value->number); } } diff --git a/ui/input.c b/ui/input.c index fc91fba83c..14c9434f5e 100644 --- a/ui/input.c +++ b/ui/input.c @@ -1,3 +1,4 @@ +#include "hw/qdev.h" #include "sysemu/sysemu.h" #include "qapi-types.h" #include "qmp-commands.h" @@ -10,6 +11,7 @@ struct QemuInputHandlerState { QemuInputHandler *handler; int id; int events; + QemuConsole *con; QTAILQ_ENTRY(QemuInputHandlerState) node; }; static QTAILQ_HEAD(, QemuInputHandlerState) handlers = @@ -53,12 +55,46 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s) qemu_input_check_mode_change(); } +void qemu_input_handler_bind(QemuInputHandlerState *s, + const char *device_id, int head, + Error **errp) +{ + DeviceState *dev; + QemuConsole *con; + + dev = qdev_find_recursive(sysbus_get_default(), device_id); + if (dev == NULL) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device_id); + return; + } + + con = qemu_console_lookup_by_device(dev, head); + if (con == NULL) { + error_setg(errp, "Device %s is not bound to a QemuConsole", device_id); + return; + } + + s->con = con; +} + static QemuInputHandlerState* -qemu_input_find_handler(uint32_t mask) +qemu_input_find_handler(uint32_t mask, QemuConsole *con) { QemuInputHandlerState *s; QTAILQ_FOREACH(s, &handlers, node) { + if (s->con == NULL || s->con != con) { + continue; + } + if (mask & s->handler->mask) { + return s; + } + } + + QTAILQ_FOREACH(s, &handlers, node) { + if (s->con != NULL) { + continue; + } if (mask & s->handler->mask) { return s; } @@ -94,7 +130,7 @@ static void qemu_input_transform_abs_rotate(InputEvent *evt) static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) { const char *name; - int idx = -1; + int qcode, idx = -1; if (src) { idx = qemu_console_get_index(src); @@ -103,8 +139,10 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt) case INPUT_EVENT_KIND_KEY: switch (evt->key->key->kind) { case KEY_VALUE_KIND_NUMBER: + qcode = qemu_input_key_number_to_qcode(evt->key->key->number); + name = QKeyCode_lookup[qcode]; trace_input_event_key_number(idx, evt->key->key->number, - evt->key->down); + name, evt->key->down); break; case KEY_VALUE_KIND_QCODE: name = QKeyCode_lookup[evt->key->key->qcode]; @@ -149,7 +187,7 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt) } /* send event */ - s = qemu_input_find_handler(1 << evt->kind); + s = qemu_input_find_handler(1 << evt->kind, src); if (!s) { return; } @@ -250,7 +288,8 @@ bool qemu_input_is_absolute(void) { QemuInputHandlerState *s; - s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS); + s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS, + NULL); return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); } @@ -190,30 +190,33 @@ static void sdl_switch(DisplayChangeListener *dcl, } } -static void reset_keys(void) +static void reset_keys(struct sdl2_state *scon) { + QemuConsole *con = scon ? scon->dcl.con : NULL; int i; for (i = 0; i < 256; i++) { if (modifiers_state[i]) { int qcode = sdl2_scancode_to_qcode[i]; - qemu_input_event_send_key_qcode(NULL, qcode, false); + qemu_input_event_send_key_qcode(con, qcode, false); modifiers_state[i] = 0; } } } -static void sdl_process_key(SDL_KeyboardEvent *ev) +static void sdl_process_key(struct sdl2_state *scon, + SDL_KeyboardEvent *ev) { int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode]; + QemuConsole *con = scon ? scon->dcl.con : NULL; switch (ev->keysym.scancode) { #if 0 case SDL_SCANCODE_NUMLOCKCLEAR: case SDL_SCANCODE_CAPSLOCK: /* SDL does not send the key up event, so we generate it */ - qemu_input_event_send_key_qcode(NULL, qcode, true); - qemu_input_event_send_key_qcode(NULL, qcode, false); + qemu_input_event_send_key_qcode(con, qcode, true); + qemu_input_event_send_key_qcode(con, qcode, false); return; #endif case SDL_SCANCODE_LCTRL: @@ -231,7 +234,7 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) } /* fall though */ default: - qemu_input_event_send_key_qcode(NULL, qcode, + qemu_input_event_send_key_qcode(con, qcode, ev->type == SDL_KEYDOWN); } } @@ -506,7 +509,7 @@ static void handle_keydown(SDL_Event *ev) } } if (!gui_keysym) { - sdl_process_key(&ev->key); + sdl_process_key(scon, &ev->key); } } @@ -531,13 +534,13 @@ static void handle_keyup(SDL_Event *ev) } /* SDL does not send back all the modifiers key, so we must * correct it. */ - reset_keys(); + reset_keys(scon); return; } gui_keysym = 0; } if (!gui_keysym) { - sdl_process_key(&ev->key); + sdl_process_key(scon, &ev->key); } } |