* [Qemu-devel] [PATCH 0/6] add input routing and multiseat support
@ 2014-05-20 14:00 Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 1/6] input: switch hid keyboard to new input layer api Gerd Hoffmann
` (5 more replies)
0 siblings, 6 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Hi,
$subject says all. Last patch has detailed usage docs,
so I'm not repeating it here.
cheers,
Gerd
Gerd Hoffmann (6):
input: switch hid keyboard to new input layer api.
input: switch hid mouse and tablet to the new input layer api.
input: bind devices and input routing
sdl: pass key event source to input layer
usb: add input routing support for tablet and keyboard
docs: add multiseat.txt
docs/multiseat.txt | 76 +++++++++++++++++
hw/input/hid.c | 220 ++++++++++++++++++++++++++++++++-----------------
hw/usb/dev-hid.c | 13 +++
include/hw/input/hid.h | 4 +-
include/ui/input.h | 3 +
ui/input.c | 43 +++++++++-
ui/sdl2.c | 21 +++--
7 files changed, 290 insertions(+), 90 deletions(-)
create mode 100644 docs/multiseat.txt
--
1.8.3.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 1/6] input: switch hid keyboard to new input layer api.
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
@ 2014-05-20 14:00 ` Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 2/6] input: switch hid mouse and tablet to the " Gerd Hoffmann
` (4 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Minimal patch to get the switchover done. We continue processing ps/2
scancodes for now as they are part of the live migration stream. Fixing
that, then mapping directly from QKeyValue to HID keycodes is left as
excercise for another day.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/input/hid.c | 29 ++++++++++++++++++++++-------
include/hw/input/hid.h | 3 ++-
2 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index bb0fa6a..ff75e41 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -158,17 +158,24 @@ static void hid_pointer_event(void *opaque,
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);
}
@@ -415,7 +422,7 @@ void hid_free(HIDState *hs)
{
switch (hs->kind) {
case HID_KEYBOARD:
- qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
+ qemu_input_handler_unregister(hs->s);
break;
case HID_MOUSE:
case HID_TABLET:
@@ -425,13 +432,21 @@ void hid_free(HIDState *hs)
hid_del_idle_timer(hs);
}
+static QemuInputHandler hid_keyboard_handler = {
+ .name = "QEMU HID Keyboard",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = hid_keyboard_event,
+};
+
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");
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
index 2567879..fb913ba 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
@@ -31,7 +32,6 @@ typedef struct HIDKeyboardState {
uint8_t leds;
uint8_t key[16];
int32_t keys;
- QEMUPutKbdEntry *eh_entry;
} HIDKeyboardState;
struct HIDState {
@@ -47,6 +47,7 @@ struct HIDState {
bool idle_pending;
QEMUTimer *idle_timer;
HIDEventFunc event;
+ QemuInputHandlerState *s;
};
void hid_init(HIDState *hs, int kind, HIDEventFunc event);
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 2/6] input: switch hid mouse and tablet to the new input layer api.
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 1/6] input: switch hid keyboard to new input layer api Gerd Hoffmann
@ 2014-05-20 14:00 ` Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 3/6] input: bind devices and input routing Gerd Hoffmann
` (3 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/input/hid.c | 193 +++++++++++++++++++++++++++++++------------------
include/hw/input/hid.h | 1 -
2 files changed, 123 insertions(+), 71 deletions(-)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index ff75e41..295bdab 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -105,57 +105,115 @@ 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(DeviceState *dev, QemuConsole *src,
@@ -254,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;
@@ -286,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))) {
@@ -311,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;
@@ -326,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;
@@ -420,15 +467,7 @@ void hid_reset(HIDState *hs)
void hid_free(HIDState *hs)
{
- switch (hs->kind) {
- case HID_KEYBOARD:
- qemu_input_handler_unregister(hs->s);
- 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);
}
@@ -438,6 +477,20 @@ static QemuInputHandler hid_keyboard_handler = {
.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;
@@ -448,11 +501,11 @@ void hid_init(HIDState *hs, int kind, HIDEventFunc event)
&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/include/hw/input/hid.h b/include/hw/input/hid.h
index fb913ba..2127c7c 100644
--- a/include/hw/input/hid.h
+++ b/include/hw/input/hid.h
@@ -23,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 {
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 3/6] input: bind devices and input routing
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 1/6] input: switch hid keyboard to new input layer api Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 2/6] input: switch hid mouse and tablet to the " Gerd Hoffmann
@ 2014-05-20 14:00 ` Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 4/6] sdl: pass key event source to input layer Gerd Hoffmann
` (2 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori
Add function to bind input devices to display devices. Implementing
input routing on top of this: Events coming from the display device in
question are routed to the input device bound to it (if there is one).
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
include/ui/input.h | 3 +++
ui/input.c | 43 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 43 insertions(+), 3 deletions(-)
diff --git a/include/ui/input.h b/include/ui/input.h
index 3d3d487..3c670d2 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);
diff --git a/ui/input.c b/ui/input.c
index fc91fba..40351f3 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;
}
@@ -149,7 +185,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 +286,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);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 4/6] sdl: pass key event source to input layer
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
` (2 preceding siblings ...)
2014-05-20 14:00 ` [Qemu-devel] [PATCH 3/6] input: bind devices and input routing Gerd Hoffmann
@ 2014-05-20 14:00 ` Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 5/6] usb: add input routing support for tablet and keyboard Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt Gerd Hoffmann
5 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori
So the input layer knows where the input is coming from
and input routing works correctly.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
ui/sdl2.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 361de61..0e884f9 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -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);
}
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 5/6] usb: add input routing support for tablet and keyboard
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
` (3 preceding siblings ...)
2014-05-20 14:00 ` [Qemu-devel] [PATCH 4/6] sdl: pass key event source to input layer Gerd Hoffmann
@ 2014-05-20 14:00 ` Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt Gerd Hoffmann
5 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add display property to the keyboard.
Add display and head properties to the tablet.
If properties are set bind device to the display specified to
setup input routing.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/dev-hid.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index d097d93..67a57f1 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);
}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
` (4 preceding siblings ...)
2014-05-20 14:00 ` [Qemu-devel] [PATCH 5/6] usb: add input routing support for tablet and keyboard Gerd Hoffmann
@ 2014-05-20 14:00 ` Gerd Hoffmann
2014-05-20 18:08 ` Paolo Bonzini
5 siblings, 1 reply; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-20 14:00 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Howto on setting up multiseat for guests.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
docs/multiseat.txt | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 docs/multiseat.txt
diff --git a/docs/multiseat.txt b/docs/multiseat.txt
new file mode 100644
index 0000000..a6c71dd
--- /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>
--
1.8.3.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt
2014-05-20 14:00 ` [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt Gerd Hoffmann
@ 2014-05-20 18:08 ` Paolo Bonzini
2014-05-21 8:38 ` Gerd Hoffmann
0 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2014-05-20 18:08 UTC (permalink / raw)
To: Gerd Hoffmann, qemu-devel
Il 20/05/2014 16:00, Gerd Hoffmann ha scritto:
> + -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.
> +
Is there anything about the window that we would like to configure? If
so, should this be something like
-object window,id=window.2 \
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
-device secondary-vga,bus=head.2,addr=02.0,window=window.2 \
-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
-device usb-kbd,bus=usb.2.0,port=1,window=window.2 \
-device usb-tablet,bus=usb.2.0,port=2,window=window.2
?
Paolo
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt
2014-05-20 18:08 ` Paolo Bonzini
@ 2014-05-21 8:38 ` Gerd Hoffmann
2014-05-21 9:18 ` Paolo Bonzini
0 siblings, 1 reply; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-21 8:38 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel
On Di, 2014-05-20 at 20:08 +0200, Paolo Bonzini wrote:
> Il 20/05/2014 16:00, Gerd Hoffmann ha scritto:
> > + -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.
> > +
>
> Is there anything about the window that we would like to configure? If
> so, should this be something like
>
> -object window,id=window.2 \
> -device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
> -device secondary-vga,bus=head.2,addr=02.0,window=window.2 \
> -device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
> -device usb-kbd,bus=usb.2.0,port=1,window=window.2 \
> -device usb-tablet,bus=usb.2.0,port=2,window=window.2
>
> ?
The "window" is a QemuConsole. Which is a object already, visible
in /backend/console[nr]. Has a device link pointing to the display
device it is bound to.
QemuConsoles are automatically created by display devices and don't have
ids, so we lookup them using the display device id. See
qemu_input_handler_bind in patch #3.
If there is anything to configure then it most likely will be ui
specific, i.e. we could possibly allow something like this ...
-display gtk,display=video.1 \
-vnc :0,display=video.2
... to have one head show up on gtk and the other on vnc (needs '-vga
none -device VGA,id=video.1' instead of '-vga std').
cheers,
Gerd
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt
2014-05-21 8:38 ` Gerd Hoffmann
@ 2014-05-21 9:18 ` Paolo Bonzini
2014-05-21 9:51 ` Gerd Hoffmann
0 siblings, 1 reply; 11+ messages in thread
From: Paolo Bonzini @ 2014-05-21 9:18 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
Il 21/05/2014 10:38, Gerd Hoffmann ha scritto:
> On Di, 2014-05-20 at 20:08 +0200, Paolo Bonzini wrote:
>> Is there anything about the window that we would like to configure? If
>> so, should this be something like
>>
>> -object window,id=window.2 \
>> -device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
>> -device secondary-vga,bus=head.2,addr=02.0,window=window.2 \
>> -device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
>> -device usb-kbd,bus=usb.2.0,port=1,window=window.2 \
>> -device usb-tablet,bus=usb.2.0,port=2,window=window.2
>>
>> ?
>
> The "window" is a QemuConsole. Which is a object already, visible
> in /backend/console[nr]. Has a device link pointing to the display
> device it is bound to.
>
> QemuConsoles are automatically created by display devices and don't have
> ids, so we lookup them using the display device id. See
> qemu_input_handler_bind in patch #3.
>
> If there is anything to configure then it most likely will be ui
> specific, i.e. we could possibly allow something like this ...
>
> -display gtk,display=video.1 \
> -vnc :0,display=video.2
>
> ... to have one head show up on gtk and the other on vnc (needs '-vga
> none -device VGA,id=video.1' instead of '-vga std').
How would you configure the case where one input goes to multiple heads
(e.g. 2 seats, 4 monitors)?
Paolo
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt
2014-05-21 9:18 ` Paolo Bonzini
@ 2014-05-21 9:51 ` Gerd Hoffmann
0 siblings, 0 replies; 11+ messages in thread
From: Gerd Hoffmann @ 2014-05-21 9:51 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: qemu-devel
Hi,
> > If there is anything to configure then it most likely will be ui
> > specific, i.e. we could possibly allow something like this ...
> >
> > -display gtk,display=video.1 \
> > -vnc :0,display=video.2
> >
> > ... to have one head show up on gtk and the other on vnc (needs '-vga
> > none -device VGA,id=video.1' instead of '-vga std').
>
> How would you configure the case where one input goes to multiple heads
> (e.g. 2 seats, 4 monitors)?
You need one keyboard per head (i.e. 2) and one tablet per display (i.e.
4). The usb tablet has a additional head property, so you can specify
which tablet belongs to which monitor. You also need a vga card which
supports multiple heads (non-upstream virtio-gpu will do).
Not figured yet how to do guest configuration (teach X server which
tablet belongs to which monitor) for the multihead case.
Note: qxl supports multi-head already, but can't be used for this as it
goes spice-specific side ways to get the job done. Fixing that is on my
todo list, but it isn't trivial, especially the backward compatibility.
Probably also needs spice-server changes.
cheers,
Gerd
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-05-21 9:51 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-20 14:00 [Qemu-devel] [PATCH 0/6] add input routing and multiseat support Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 1/6] input: switch hid keyboard to new input layer api Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 2/6] input: switch hid mouse and tablet to the " Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 3/6] input: bind devices and input routing Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 4/6] sdl: pass key event source to input layer Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 5/6] usb: add input routing support for tablet and keyboard Gerd Hoffmann
2014-05-20 14:00 ` [Qemu-devel] [PATCH 6/6] docs: add multiseat.txt Gerd Hoffmann
2014-05-20 18:08 ` Paolo Bonzini
2014-05-21 8:38 ` Gerd Hoffmann
2014-05-21 9:18 ` Paolo Bonzini
2014-05-21 9:51 ` Gerd Hoffmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).