The support for multiple keyboard devices is essential for emulating embedded boards where multiple input devices are present (eg. keypad and rotary encoder) which are implemented using separate QEMU devices.
Signed-off-by: Filip Navara <filip.nav...@gmail.com> --- console.h | 11 ++++++++++- hw/xenfb.c | 8 ++++++-- vl.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/console.h b/console.h index 9615f56..568d097 100644 --- a/console.h +++ b/console.h @@ -26,7 +26,16 @@ typedef struct QEMUPutMouseEntry { struct QEMUPutMouseEntry *next; } QEMUPutMouseEntry; -void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); +typedef struct QEMUPutKeyboardEntry { + QEMUPutKBDEvent *qemu_put_kbd_event; + void *qemu_put_kbd_event_opaque; + + /* used internally by qemu for handling mice */ + struct QEMUPutKeyboardEntry *next; +} QEMUPutKeyboardEntry; + +QEMUPutKeyboardEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); +void qemu_remove_kbd_event_handler(QEMUPutKeyboardEntry *entry); QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute, const char *name); diff --git a/hw/xenfb.c b/hw/xenfb.c index 795a326..090f857 100644 --- a/hw/xenfb.c +++ b/hw/xenfb.c @@ -68,6 +68,7 @@ struct XenInput { int button_state; /* Last seen pointer button state */ int extended; QEMUPutMouseEntry *qmouse; + QEMUPutKeyboardEntry *qkeyboard; }; #define UP_QUEUE 8 @@ -373,7 +374,7 @@ static int input_connect(struct XenDevice *xendev) if (rc != 0) return rc; - qemu_add_kbd_event_handler(xenfb_key_event, in); + in->qkeyboard = qemu_add_kbd_event_handler(xenfb_key_event, in); in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in, in->abs_pointer_wanted, "Xen PVFB Mouse"); @@ -388,7 +389,10 @@ static void input_disconnect(struct XenDevice *xendev) qemu_remove_mouse_event_handler(in->qmouse); in->qmouse = NULL; } - qemu_add_kbd_event_handler(NULL, NULL); + if (in->qkeyboard) { + qemu_remove_kbd_event_handler(in->qkeyboard); + in->qkeyboard = NULL; + } common_unbind(&in->c); } diff --git a/vl.c b/vl.c index eb2744e..1bb7d40 100644 --- a/vl.c +++ b/vl.c @@ -346,15 +346,57 @@ ram_addr_t qemu_balloon_status(void) /***********************************************************/ /* keyboard/mouse */ -static QEMUPutKBDEvent *qemu_put_kbd_event; -static void *qemu_put_kbd_event_opaque; +static QEMUPutKeyboardEntry *qemu_put_kbd_event_head; static QEMUPutMouseEntry *qemu_put_mouse_event_head; static QEMUPutMouseEntry *qemu_put_mouse_event_current; -void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) +QEMUPutKeyboardEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { - qemu_put_kbd_event_opaque = opaque; - qemu_put_kbd_event = func; + QEMUPutKeyboardEntry *s, *cursor; + + s = qemu_mallocz(sizeof(QEMUPutKeyboardEntry)); + + s->qemu_put_kbd_event = func; + s->qemu_put_kbd_event_opaque = opaque; + s->next = NULL; + + if (!qemu_put_kbd_event_head) { + qemu_put_kbd_event_head = s; + return s; + } + + cursor = qemu_put_kbd_event_head; + while (cursor->next != NULL) + cursor = cursor->next; + + cursor->next = s; + + return s; +} + +void qemu_remove_kbd_event_handler(QEMUPutKeyboardEntry *entry) +{ + QEMUPutKeyboardEntry *prev = NULL, *cursor; + + if (!qemu_put_kbd_event_head || entry == NULL) + return; + + cursor = qemu_put_kbd_event_head; + while (cursor != NULL && cursor != entry) { + prev = cursor; + cursor = cursor->next; + } + + if (cursor == NULL) // does not exist or list empty + return; + else if (prev == NULL) { // entry is head + qemu_put_kbd_event_head = cursor->next; + qemu_free(entry); + return; + } + + prev->next = entry->next; + qemu_free(entry); } QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, @@ -421,8 +463,12 @@ void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) void kbd_put_keycode(int keycode) { - if (qemu_put_kbd_event) { - qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); + QEMUPutKeyboardEntry *cursor; + + cursor = qemu_put_kbd_event_head; + while (cursor != NULL) { + cursor->qemu_put_kbd_event(cursor->qemu_put_kbd_event_opaque, keycode); + cursor = cursor->next; } } -- 1.6.3.2.1299.gee46c