From d4c853375508086132a72f2570e8877608ad6fe7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 09:58:18 +0100 Subject: [PATCH 01/38] console: export QemuConsole index,width,height Add functions to query QemuConsole properties. Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 3 +++ ui/console.c | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/include/ui/console.h b/include/ui/console.h index 4156a876e1..8543d18319 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -289,6 +289,9 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev); bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); +int qemu_console_get_index(QemuConsole *con); +int qemu_console_get_width(QemuConsole *con, int fallback); +int qemu_console_get_height(QemuConsole *con, int fallback); void text_consoles_set_display(DisplayState *ds); void console_select(unsigned int index); diff --git a/ui/console.c b/ui/console.c index 502e1600ab..0bbefe545f 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1641,6 +1641,30 @@ bool qemu_console_is_fixedsize(QemuConsole *con) return con && (con->console_type != TEXT_CONSOLE); } +int qemu_console_get_index(QemuConsole *con) +{ + if (con == NULL) { + con = active_console; + } + return con ? con->index : -1; +} + +int qemu_console_get_width(QemuConsole *con, int fallback) +{ + if (con == NULL) { + con = active_console; + } + return con ? surface_width(con->surface) : fallback; +} + +int qemu_console_get_height(QemuConsole *con, int fallback) +{ + if (con == NULL) { + con = active_console; + } + return con ? surface_height(con->surface) : fallback; +} + static void text_console_set_echo(CharDriverState *chr, bool echo) { QemuConsole *s = chr->opaque; From 7ad95ff76ccc11c702ca8edcb01a95938eb7ffcd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 09:29:27 +0100 Subject: [PATCH 02/38] input: rename file to legacy Rename ui/input.c to ui/input-legacy.c. We are going to replace it step by step. Signed-off-by: Gerd Hoffmann --- ui/Makefile.objs | 2 +- ui/{input.c => input-legacy.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename ui/{input.c => input-legacy.c} (100%) diff --git a/ui/Makefile.objs b/ui/Makefile.objs index f33be47576..39ceadcdd8 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -7,7 +7,7 @@ vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o vnc-obj-y += vnc-jobs.o -common-obj-y += keymaps.o console.o cursor.o input.o qemu-pixman.o +common-obj-y += keymaps.o console.o cursor.o input-legacy.o qemu-pixman.o common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o common-obj-$(CONFIG_COCOA) += cocoa.o diff --git a/ui/input.c b/ui/input-legacy.c similarity index 100% rename from ui/input.c rename to ui/input-legacy.c From 031fa964399d3ed9090acc1378b65eee2633a5eb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 09:08:40 +0100 Subject: [PATCH 03/38] input: qapi: define event types Define input event types, using qapi. So we get nicely autogenerated types for our input events. And when it comes to qmp support some day things will be a lot easier. Types are modeled after the linux input layer. There are separate event types for each value. There is a sync to indicate the end of a event group. Mouse events are split into motion events (one for each axis) and button events, which are grouped by sync. Keyboard events are using the existing KeyValue type. Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Blake --- qapi-schema.json | 76 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index 193e7e4d3f..9d7d7a8c2e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -4566,3 +4566,79 @@ # Since: 1.7 ## { 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } } + +## +# @InputButton +# +# Button of a pointer input device (mouse, tablet). +# +# Since: 2.0 +## +{ 'enum' : 'InputButton', + 'data' : [ 'Left', 'Middle', 'Right', 'WheelUp', 'WheelDown' ] } + +## +# @InputButton +# +# Position axis of a pointer input device (mouse, tablet). +# +# Since: 2.0 +## +{ 'enum' : 'InputAxis', + 'data' : [ 'X', 'Y' ] } + +## +# @InputKeyEvent +# +# Keyboard input event. +# +# @key: Which key this event is for. +# @down: True for key-down and false for key-up events. +# +# Since: 2.0 +## +{ 'type' : 'InputKeyEvent', + 'data' : { 'key' : 'KeyValue', + 'down' : 'bool' } } + +## +# @InputBtnEvent +# +# Pointer button input event. +# +# @button: Which button this event is for. +# @down: True for key-down and false for key-up events. +# +# Since: 2.0 +## +{ 'type' : 'InputBtnEvent', + 'data' : { 'button' : 'InputButton', + 'down' : 'bool' } } + +## +# @InputMoveEvent +# +# Pointer motion input event. +# +# @axis: Which axis is referenced by @value. +# @value: Pointer position. For absolute coordinates the +# valid range is 0 -> 0x7ffff +# +# Since: 2.0 +## +{ 'type' : 'InputMoveEvent', + 'data' : { 'axis' : 'InputAxis', + 'value' : 'int' } } + +## +# @InputEvent +# +# Input event union. +# +# Since: 2.0 +## +{ 'union' : 'InputEvent', + 'data' : { 'key' : 'InputKeyEvent', + 'btn' : 'InputBtnEvent', + 'rel' : 'InputMoveEvent', + 'abs' : 'InputMoveEvent' } } From bbd1b1cc25d551f2e0f85f4b635f4a769dbd86e4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 13 Dec 2013 12:10:14 +0100 Subject: [PATCH 04/38] input: qapi: add unmapped key Simplifies building something -> QkeyCode mapping tables. Uninitialized entries can easily identified then. Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Blake --- qapi-schema.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qapi-schema.json b/qapi-schema.json index 9d7d7a8c2e..609d576c01 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3555,9 +3555,12 @@ # This is used by the send-key command. # # Since: 1.3.0 +# +# 'unmapped' since 2.0 ## { 'enum': 'QKeyCode', - 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', + 'data': [ 'unmapped', + 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right', From 8b6b0c59a600d8254a409b837d5358d16e881fd0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 16 Dec 2013 10:34:53 +0100 Subject: [PATCH 05/38] input: qapi: add pause key It's missing. Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Blake --- qapi-schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qapi-schema.json b/qapi-schema.json index 609d576c01..6c381b7306 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3556,7 +3556,7 @@ # # Since: 1.3.0 # -# 'unmapped' since 2.0 +# 'unmapped' and 'pause' since 2.0 ## { 'enum': 'QKeyCode', 'data': [ 'unmapped', @@ -3574,7 +3574,7 @@ 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end', 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', - 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } + 'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause' ] } ## # @KeyValue From c8b405b6798e3731eb9a71fcd753745f224ce698 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 10:35:26 +0100 Subject: [PATCH 06/38] input: add core bits of the new input layer Register and unregister handlers. Event dispatcher code. Signed-off-by: Gerd Hoffmann --- include/ui/input.h | 32 ++++++++++++++++++ ui/Makefile.objs | 2 +- ui/input.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 include/ui/input.h create mode 100644 ui/input.c diff --git a/include/ui/input.h b/include/ui/input.h new file mode 100644 index 0000000000..3cf3641243 --- /dev/null +++ b/include/ui/input.h @@ -0,0 +1,32 @@ +#ifndef INPUT_H +#define INPUT_H + +#include "qapi-types.h" + +#define INPUT_EVENT_MASK_KEY (1<dev = dev; + s->handler = handler; + s->id = id++; + QTAILQ_INSERT_TAIL(&handlers, s, node); + return s; +} + +void qemu_input_handler_activate(QemuInputHandlerState *s) +{ + QTAILQ_REMOVE(&handlers, s, node); + QTAILQ_INSERT_HEAD(&handlers, s, node); +} + +void qemu_input_handler_unregister(QemuInputHandlerState *s) +{ + QTAILQ_REMOVE(&handlers, s, node); + g_free(s); +} + +static QemuInputHandlerState* +qemu_input_find_handler(uint32_t mask) +{ + QemuInputHandlerState *s; + + QTAILQ_FOREACH(s, &handlers, node) { + if (mask & s->handler->mask) { + return s; + } + } + return NULL; +} + +void qemu_input_event_send(QemuConsole *src, InputEvent *evt) +{ + QemuInputHandlerState *s; + + if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { + return; + } + + s = qemu_input_find_handler(1 << evt->kind); + s->handler->event(s->dev, src, evt); + s->events++; +} + +void qemu_input_event_sync(void) +{ + QemuInputHandlerState *s; + + if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { + return; + } + + QTAILQ_FOREACH(s, &handlers, node) { + if (!s->events) { + continue; + } + if (s->handler->sync) { + s->handler->sync(s->dev); + } + s->events = 0; + } +} From 6567147588fabd87c1b633cc35760d45b71b8d41 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 11:38:47 +0100 Subject: [PATCH 07/38] input: keyboard: add helper functions to core A bunch of helper functions to manage keyboard events, to make life simpler for the ui code when submitting keyboard events. Signed-off-by: Gerd Hoffmann --- include/ui/input.h | 5 +++++ ui/input.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/ui/input.h b/include/ui/input.h index 3cf3641243..189f131b3b 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -29,4 +29,9 @@ void qemu_input_handler_unregister(QemuInputHandlerState *s); void qemu_input_event_send(QemuConsole *src, InputEvent *evt); void qemu_input_event_sync(void); +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); + #endif /* INPUT_H */ diff --git a/ui/input.c b/ui/input.c index 23c84f7254..61c8089749 100644 --- a/ui/input.c +++ b/ui/input.c @@ -81,3 +81,38 @@ void qemu_input_event_sync(void) s->events = 0; } } + +InputEvent *qemu_input_event_new_key(KeyValue *key, bool down) +{ + InputEvent *evt = g_new0(InputEvent, 1); + evt->key = g_new0(InputKeyEvent, 1); + evt->kind = INPUT_EVENT_KIND_KEY; + evt->key->key = key; + evt->key->down = down; + return evt; +} + +void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down) +{ + InputEvent *evt; + evt = qemu_input_event_new_key(key, down); + qemu_input_event_send(src, evt); + qemu_input_event_sync(); + qapi_free_InputEvent(evt); +} + +void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down) +{ + KeyValue *key = g_new0(KeyValue, 1); + key->kind = KEY_VALUE_KIND_NUMBER; + key->number = num; + qemu_input_event_send_key(src, key, down); +} + +void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down) +{ + KeyValue *key = g_new0(KeyValue, 1); + key->kind = KEY_VALUE_KIND_QCODE; + key->qcode = q; + qemu_input_event_send_key(src, key, down); +} From 9784e5793000f27cf4b506511fedf207dcf8521c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 11:59:25 +0100 Subject: [PATCH 08/38] input: keyboard: switch legacy handlers to new core legacy kbd event handlers are registered in the new core, so they receive events from the new input core code. keycode -> scancode translation needed here. legacy kbd_put_keycode() sends events to the new core. scancode -> keycode translation needed here. So with this patch the new input core is fully functional for keyboard events. New + legacy interfaces can be mixed in any way. Signed-off-by: Gerd Hoffmann --- ui/input-legacy.c | 66 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 1c70f60e0d..80f4f5cdb3 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -29,6 +29,7 @@ #include "qmp-commands.h" #include "qapi-types.h" #include "ui/keymaps.h" +#include "ui/input.h" struct QEMUPutMouseEntry { QEMUPutMouseEvent *qemu_put_mouse_event; @@ -45,7 +46,7 @@ struct QEMUPutMouseEntry { struct QEMUPutKbdEntry { QEMUPutKBDEvent *put_kbd; void *opaque; - QTAILQ_ENTRY(QEMUPutKbdEntry) next; + QemuInputHandlerState *s; }; struct QEMUPutLEDEntry { @@ -56,8 +57,6 @@ struct QEMUPutLEDEntry { static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers); -static QTAILQ_HEAD(, QEMUPutKbdEntry) kbd_handlers = - QTAILQ_HEAD_INITIALIZER(kbd_handlers); static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = QTAILQ_HEAD_INITIALIZER(mouse_handlers); static NotifierList mouse_mode_notifiers = @@ -312,20 +311,56 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, muldiv64(get_ticks_per_sec(), hold_time, 1000)); } +static void legacy_kbd_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev; + int keycode = keycode_from_keyvalue(evt->key->key); + + if (!entry || !entry->put_kbd) { + return; + } + if (evt->key->key->kind == KEY_VALUE_KIND_QCODE && + evt->key->key->qcode == Q_KEY_CODE_PAUSE) { + /* specific case */ + int v = evt->key->down ? 0 : 0x80; + entry->put_kbd(entry->opaque, 0xe1); + entry->put_kbd(entry->opaque, 0x1d | v); + entry->put_kbd(entry->opaque, 0x45 | v); + return; + } + if (keycode & SCANCODE_GREY) { + entry->put_kbd(entry->opaque, SCANCODE_EMUL0); + keycode &= ~SCANCODE_GREY; + } + if (!evt->key->down) { + keycode |= SCANCODE_UP; + } + entry->put_kbd(entry->opaque, keycode); +} + +static QemuInputHandler legacy_kbd_handler = { + .name = "legacy-kbd", + .mask = INPUT_EVENT_MASK_KEY, + .event = legacy_kbd_event, +}; + QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { QEMUPutKbdEntry *entry; - entry = g_malloc0(sizeof(QEMUPutKbdEntry)); + entry = g_new0(QEMUPutKbdEntry, 1); entry->put_kbd = func; entry->opaque = opaque; - QTAILQ_INSERT_HEAD(&kbd_handlers, entry, next); + entry->s = qemu_input_handler_register((DeviceState *)entry, + &legacy_kbd_handler); return entry; } void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry) { - QTAILQ_REMOVE(&kbd_handlers, entry, next); + qemu_input_handler_unregister(entry->s); + g_free(entry); } static void check_mode_change(void) @@ -409,14 +444,25 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) void kbd_put_keycode(int keycode) { - QEMUPutKbdEntry *entry = QTAILQ_FIRST(&kbd_handlers); + static bool emul0; + bool up; - if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { + if (keycode == SCANCODE_EMUL0) { + emul0 = true; return; } - if (entry && entry->put_kbd) { - entry->put_kbd(entry->opaque, keycode); + if (keycode & SCANCODE_UP) { + keycode &= ~SCANCODE_UP; + up = true; + } else { + up = false; } + if (emul0) { + keycode |= SCANCODE_GREY; + emul0 = false; + } + + qemu_input_event_send_key_number(NULL, keycode, !up); } void kbd_put_ledstate(int ledstate) From d2a9260335876ce9d17be0dabf0fd4ae1593de66 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 12:11:13 +0100 Subject: [PATCH 09/38] input: keyboard: switch qmp_send_key() to new core. Signed-off-by: Gerd Hoffmann --- ui/input-legacy.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 80f4f5cdb3..a4006cccb0 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -260,10 +260,8 @@ static void free_keycodes(void) static void release_keys(void *opaque) { while (keycodes_size > 0) { - if (keycodes[--keycodes_size] & SCANCODE_GREY) { - kbd_put_keycode(SCANCODE_EMUL0); - } - kbd_put_keycode(keycodes[keycodes_size] | SCANCODE_UP); + qemu_input_event_send_key_number(NULL, keycodes[--keycodes_size], + false); } free_keycodes(); @@ -297,10 +295,7 @@ void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time, return; } - if (keycode & SCANCODE_GREY) { - kbd_put_keycode(SCANCODE_EMUL0); - } - kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); + qemu_input_event_send_key_number(NULL, keycode, true); keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1)); keycodes[keycodes_size++] = keycode; From af98ba92ac3b417fa171736180a782f84b202cef Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 11:40:27 +0100 Subject: [PATCH 10/38] input: keyboard: switch gtk ui to new core Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index a633d89346..74c0936caf 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -59,6 +59,7 @@ #include "trace.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" #include "qmp-commands.h" #include "x_keymap.h" @@ -280,10 +281,7 @@ static void gtk_release_modifiers(GtkDisplayState *s) if (!s->modifier_pressed[i]) { continue; } - if (keycode & SCANCODE_GREY) { - kbd_put_keycode(SCANCODE_EMUL0); - } - kbd_put_keycode(keycode | SCANCODE_UP); + qemu_input_event_send_key_number(s->dcl.con, keycode, false); s->modifier_pressed[i] = false; } } @@ -745,17 +743,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque) } } - if (qemu_keycode & SCANCODE_GREY) { - kbd_put_keycode(SCANCODE_EMUL0); - } - - if (key->type == GDK_KEY_PRESS) { - kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK); - } else if (key->type == GDK_KEY_RELEASE) { - kbd_put_keycode(qemu_keycode | SCANCODE_UP); - } else { - g_assert_not_reached(); - } + qemu_input_event_send_key_number(s->dcl.con, qemu_keycode, + key->type == GDK_KEY_PRESS); return TRUE; } From a25f545d685f44064d32889f6afa7a98631aba21 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 12:17:35 +0100 Subject: [PATCH 11/38] input: keyboard: switch sdl ui to new core Signed-off-by: Gerd Hoffmann --- ui/sdl.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/ui/sdl.c b/ui/sdl.c index 9d8583c4e6..e78e020bd2 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -30,6 +30,7 @@ #include "qemu-common.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" #include "x_keymap.h" #include "sdl_zoom.h" @@ -261,9 +262,7 @@ static void reset_keys(void) int i; for(i = 0; i < 256; i++) { if (modifiers_state[i]) { - if (i & SCANCODE_GREY) - kbd_put_keycode(SCANCODE_EMUL0); - kbd_put_keycode(i | SCANCODE_UP); + qemu_input_event_send_key_number(dcl->con, i, false); modifiers_state[i] = 0; } } @@ -271,16 +270,12 @@ static void reset_keys(void) static void sdl_process_key(SDL_KeyboardEvent *ev) { - int keycode, v; + int keycode; if (ev->keysym.sym == SDLK_PAUSE) { /* specific case */ - v = 0; - if (ev->type == SDL_KEYUP) - v |= SCANCODE_UP; - kbd_put_keycode(0xe1); - kbd_put_keycode(0x1d | v); - kbd_put_keycode(0x45 | v); + qemu_input_event_send_key_qcode(dcl->con, Q_KEY_CODE_PAUSE, + ev->type == SDL_KEYDOWN); return; } @@ -312,19 +307,15 @@ static void sdl_process_key(SDL_KeyboardEvent *ev) case 0x45: /* num lock */ case 0x3a: /* caps lock */ /* SDL does not send the key up event, so we generate it */ - kbd_put_keycode(keycode); - kbd_put_keycode(keycode | SCANCODE_UP); + qemu_input_event_send_key_number(dcl->con, keycode, true); + qemu_input_event_send_key_number(dcl->con, keycode, false); return; #endif } /* now send the key code */ - if (keycode & SCANCODE_GREY) - kbd_put_keycode(SCANCODE_EMUL0); - if (ev->type == SDL_KEYUP) - kbd_put_keycode(keycode | SCANCODE_UP); - else - kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); + qemu_input_event_send_key_number(dcl->con, keycode, + ev->type == SDL_KEYDOWN); } static void sdl_update_caption(void) From 8d447d10b74e5116ed85ce2b890301b77774ec49 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 2 Dec 2013 14:27:18 +0100 Subject: [PATCH 12/38] input: keyboard: switch vnc ui to new core Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 5601cc34ef..4658559496 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -33,6 +33,7 @@ #include "qapi/qmp/types.h" #include "qmp-commands.h" #include "qemu/osdep.h" +#include "ui/input.h" #define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT #define VNC_REFRESH_INTERVAL_INC 50 @@ -1542,9 +1543,7 @@ static void reset_keys(VncState *vs) int i; for(i = 0; i < 256; i++) { if (vs->modifiers_state[i]) { - if (i & SCANCODE_GREY) - kbd_put_keycode(SCANCODE_EMUL0); - kbd_put_keycode(i | SCANCODE_UP); + qemu_input_event_send_key_number(vs->vd->dcl.con, i, false); vs->modifiers_state[i] = 0; } } @@ -1553,12 +1552,8 @@ static void reset_keys(VncState *vs) static void press_key(VncState *vs, int keysym) { int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK; - if (keycode & SCANCODE_GREY) - kbd_put_keycode(SCANCODE_EMUL0); - kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); - if (keycode & SCANCODE_GREY) - kbd_put_keycode(SCANCODE_EMUL0); - kbd_put_keycode(keycode | SCANCODE_UP); + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true); + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); } static int current_led_state(VncState *vs) @@ -1700,12 +1695,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) } if (qemu_console_is_graphic(NULL)) { - if (keycode & SCANCODE_GREY) - kbd_put_keycode(SCANCODE_EMUL0); - if (down) - kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); - else - kbd_put_keycode(keycode | SCANCODE_UP); + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down); } else { bool numlock = vs->modifiers_state[0x45]; bool control = (vs->modifiers_state[0x1d] || @@ -1826,10 +1816,7 @@ static void vnc_release_modifiers(VncState *vs) if (!vs->modifiers_state[keycode]) { continue; } - if (keycode & SCANCODE_GREY) { - kbd_put_keycode(SCANCODE_EMUL0); - } - kbd_put_keycode(keycode | SCANCODE_UP); + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); } } From de8f580b2360706d644296c690bb187ece6dc4c1 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 12:23:54 +0100 Subject: [PATCH 13/38] input: keyboard: switch spice ui to new core Signed-off-by: Gerd Hoffmann --- ui/spice-input.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/ui/spice-input.c b/ui/spice-input.c index 3beb8deadb..c9df699062 100644 --- a/ui/spice-input.c +++ b/ui/spice-input.c @@ -26,12 +26,15 @@ #include "qemu-common.h" #include "ui/qemu-spice.h" #include "ui/console.h" +#include "ui/keymaps.h" +#include "ui/input.h" /* keyboard bits */ typedef struct QemuSpiceKbd { SpiceKbdInstance sin; int ledstate; + bool emul0; } QemuSpiceKbd; static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag); @@ -47,9 +50,24 @@ static const SpiceKbdInterface kbd_interface = { .get_leds = kbd_get_leds, }; -static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag) +static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode) { - kbd_put_keycode(frag); + QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); + int keycode; + bool up; + + if (scancode == SCANCODE_EMUL0) { + kbd->emul0 = true; + return; + } + keycode = scancode & ~SCANCODE_UP; + up = scancode & SCANCODE_UP; + if (kbd->emul0) { + kbd->emul0 = false; + keycode |= SCANCODE_GREY; + } + + qemu_input_event_send_key_number(NULL, keycode, !up); } static uint8_t kbd_get_leds(SpiceKbdInstance *sin) From cd100328882ef6967918f3b47ddca9574bb31694 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 13:40:20 +0100 Subject: [PATCH 14/38] input: keyboard: switch curses ui to new core Signed-off-by: Gerd Hoffmann --- ui/curses.c | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/ui/curses.c b/ui/curses.c index dbc3d5ec73..b044790e43 100644 --- a/ui/curses.c +++ b/ui/curses.c @@ -30,6 +30,7 @@ #include "qemu-common.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" #define FONT_HEIGHT 16 @@ -274,32 +275,34 @@ static void curses_refresh(DisplayChangeListener *dcl) if (qemu_console_is_graphic(NULL)) { /* since terminals don't know about key press and release * events, we need to emit both for each key received */ - if (keycode & SHIFT) - kbd_put_keycode(SHIFT_CODE); - if (keycode & CNTRL) - kbd_put_keycode(CNTRL_CODE); - if (keycode & ALT) - kbd_put_keycode(ALT_CODE); - if (keycode & ALTGR) { - kbd_put_keycode(SCANCODE_EMUL0); - kbd_put_keycode(ALT_CODE); + if (keycode & SHIFT) { + qemu_input_event_send_key_number(NULL, SHIFT_CODE, true); } - if (keycode & GREY) - kbd_put_keycode(GREY_CODE); - kbd_put_keycode(keycode & KEY_MASK); - if (keycode & GREY) - kbd_put_keycode(GREY_CODE); - kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE); - if (keycode & ALTGR) { - kbd_put_keycode(SCANCODE_EMUL0); - kbd_put_keycode(ALT_CODE | KEY_RELEASE); + if (keycode & CNTRL) { + qemu_input_event_send_key_number(NULL, CNTRL_CODE, true); + } + if (keycode & ALT) { + qemu_input_event_send_key_number(NULL, ALT_CODE, true); + } + if (keycode & ALTGR) { + 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); + + if (keycode & ALTGR) { + qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false); + } + if (keycode & ALT) { + qemu_input_event_send_key_number(NULL, ALT_CODE, false); + } + if (keycode & CNTRL) { + qemu_input_event_send_key_number(NULL, CNTRL_CODE, false); + } + if (keycode & SHIFT) { + qemu_input_event_send_key_number(NULL, SHIFT_CODE, false); } - if (keycode & ALT) - kbd_put_keycode(ALT_CODE | KEY_RELEASE); - if (keycode & CNTRL) - kbd_put_keycode(CNTRL_CODE | KEY_RELEASE); - if (keycode & SHIFT) - kbd_put_keycode(SHIFT_CODE | KEY_RELEASE); } else { keysym = curses2qemu[chr]; if (keysym == -1) From 43579403a3d67d6aab5ceb682dedae8fde85703c Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 18:24:29 +0100 Subject: [PATCH 15/38] input: mouse: add helpers functions to core Likewise a bunch of helper functions to manage mouse button and movement events, again to make life easier for the ui code. Signed-off-by: Gerd Hoffmann --- include/ui/input.h | 14 +++++++++ ui/input.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/include/ui/input.h b/include/ui/input.h index 189f131b3b..c6f50c2440 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -8,6 +8,8 @@ #define INPUT_EVENT_MASK_REL (1<qcode = q; qemu_input_event_send_key(src, key, down); } + +InputEvent *qemu_input_event_new_btn(InputButton btn, bool down) +{ + InputEvent *evt = g_new0(InputEvent, 1); + evt->btn = g_new0(InputBtnEvent, 1); + evt->kind = INPUT_EVENT_KIND_BTN; + evt->btn->button = btn; + evt->btn->down = down; + return evt; +} + +void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down) +{ + InputEvent *evt; + evt = qemu_input_event_new_btn(btn, down); + qemu_input_event_send(src, evt); + qapi_free_InputEvent(evt); +} + +void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, + uint32_t button_old, uint32_t button_new) +{ + InputButton btn; + uint32_t mask; + + for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) { + mask = button_map[btn]; + if ((button_old & mask) == (button_new & mask)) { + continue; + } + qemu_input_queue_btn(src, btn, button_new & mask); + } +} + +int qemu_input_scale_axis(int value, int size_in, int size_out) +{ + if (size_in < 2) { + return size_out / 2; + } + return (int64_t)value * (size_out - 1) / (size_in - 1); +} + +InputEvent *qemu_input_event_new_move(InputEventKind kind, + InputAxis axis, int value) +{ + InputEvent *evt = g_new0(InputEvent, 1); + InputMoveEvent *move = g_new0(InputMoveEvent, 1); + + evt->kind = kind; + evt->data = move; + move->axis = axis; + move->value = value; + return evt; +} + +void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value) +{ + InputEvent *evt; + evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value); + qemu_input_event_send(src, evt); + qapi_free_InputEvent(evt); +} + +void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size) +{ + InputEvent *evt; + int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE); + evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled); + qemu_input_event_send(src, evt); + qapi_free_InputEvent(evt); +} From d3535431e8006e8bf71229f306ea9c62d9e737e8 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 11:29:33 +0100 Subject: [PATCH 16/38] input: mouse: add graphic_rotate support Transform absolute mouse events according to graphic_rotate. Legacy input code does it for both absolute and relative events, but the logic is broken for relative coordinates, so this is most likely not used anyway. Signed-off-by: Gerd Hoffmann --- ui/input.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/ui/input.c b/ui/input.c index a02172e36a..fd2293b399 100644 --- a/ui/input.c +++ b/ui/input.c @@ -50,6 +50,31 @@ qemu_input_find_handler(uint32_t mask) return NULL; } +static void qemu_input_transform_abs_rotate(InputEvent *evt) +{ + switch (graphic_rotate) { + case 90: + if (evt->abs->axis == INPUT_AXIS_X) { + evt->abs->axis = INPUT_AXIS_Y; + } else if (evt->abs->axis == INPUT_AXIS_Y) { + evt->abs->axis = INPUT_AXIS_X; + evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value; + } + break; + case 180: + evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value; + break; + case 270: + if (evt->abs->axis == INPUT_AXIS_X) { + evt->abs->axis = INPUT_AXIS_Y; + evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value; + } else if (evt->abs->axis == INPUT_AXIS_Y) { + evt->abs->axis = INPUT_AXIS_X; + } + break; + } +} + void qemu_input_event_send(QemuConsole *src, InputEvent *evt) { QemuInputHandlerState *s; @@ -58,6 +83,12 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt) return; } + /* pre processing */ + if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) { + qemu_input_transform_abs_rotate(evt); + } + + /* send event */ s = qemu_input_find_handler(1 << evt->kind); s->handler->event(s->dev, src, evt); s->events++; From 502c8db5b41bb3206ad136fa4baa753c186c9ebd Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 11:31:09 +0100 Subject: [PATCH 17/38] input: mouse: add qemu_input_is_absolute() Same as kbd_mouse_is_absolute(), but using new input core. Signed-off-by: Gerd Hoffmann --- include/ui/input.h | 1 + ui/input.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/include/ui/input.h b/include/ui/input.h index c6f50c2440..28afc45c04 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -41,6 +41,7 @@ void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down); void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, uint32_t button_old, uint32_t button_new); +bool qemu_input_is_absolute(void); int qemu_input_scale_axis(int value, int size_in, int size_out); InputEvent *qemu_input_event_new_move(InputEventKind kind, InputAxis axis, int value); diff --git a/ui/input.c b/ui/input.c index fd2293b399..01991cb2c0 100644 --- a/ui/input.c +++ b/ui/input.c @@ -181,6 +181,14 @@ void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map, } } +bool qemu_input_is_absolute(void) +{ + QemuInputHandlerState *s; + + s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS); + return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS); +} + int qemu_input_scale_axis(int value, int size_in, int size_out) { if (size_in < 2) { From edd85a3d9eff57f92f3c07a51eec5452ca8a24ef Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 27 Nov 2013 17:41:40 +0100 Subject: [PATCH 18/38] input: mouse: switch legacy handlers to new core legacy mouse event handlers are registered in the new core, so they receive events submitted to the new input core. legacy kbd_mouse_event() continues to use the old code paths. So new-core event handlers wouldn't see events submitted via kbd_mouse_event. This leads to the constrain that we we must transition all kbd_mouse_event() users first to keep things working. But that is easier to handle than translating legacy mouse events into new-core mouse events ;) Signed-off-by: Gerd Hoffmann --- ui/input-legacy.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/ui/input-legacy.c b/ui/input-legacy.c index a4006cccb0..dd2dec37dd 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -41,6 +41,12 @@ struct QEMUPutMouseEntry { /* used internally by qemu for handling mice */ QTAILQ_ENTRY(QEMUPutMouseEntry) node; + + /* new input core */ + QemuInputHandler h; + QemuInputHandlerState *s; + int axis[INPUT_AXIS_MAX]; + int buttons; }; struct QEMUPutKbdEntry { @@ -376,6 +382,51 @@ static void check_mode_change(void) current_has_absolute = has_absolute; } +static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, + InputEvent *evt) +{ + static const int bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, + [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, + [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, + }; + QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; + + switch (evt->kind) { + case INPUT_EVENT_KIND_BTN: + if (evt->btn->down) { + s->buttons |= bmap[evt->btn->button]; + } else { + s->buttons &= ~bmap[evt->btn->button]; + } + break; + case INPUT_EVENT_KIND_ABS: + s->axis[evt->abs->axis] = evt->abs->value; + break; + case INPUT_EVENT_KIND_REL: + s->axis[evt->rel->axis] += evt->rel->value; + break; + default: + break; + } +} + +static void legacy_mouse_sync(DeviceState *dev) +{ + QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev; + + s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, + s->axis[INPUT_AXIS_X], + s->axis[INPUT_AXIS_Y], + 0, + s->buttons); + + if (!s->qemu_put_mouse_event_absolute) { + s->axis[INPUT_AXIS_X] = 0; + s->axis[INPUT_AXIS_Y] = 0; + } +} + QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute, const char *name) @@ -393,6 +444,14 @@ QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, QTAILQ_INSERT_TAIL(&mouse_handlers, s, node); + s->h.name = name; + s->h.mask = INPUT_EVENT_MASK_BTN | + (absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL); + s->h.event = legacy_mouse_event; + s->h.sync = legacy_mouse_sync; + s->s = qemu_input_handler_register((DeviceState *)s, + &s->h); + check_mode_change(); return s; @@ -403,6 +462,8 @@ void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry) QTAILQ_REMOVE(&mouse_handlers, entry, node); QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node); + qemu_input_handler_activate(entry->s); + check_mode_change(); } @@ -410,6 +471,8 @@ void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) { QTAILQ_REMOVE(&mouse_handlers, entry, node); + qemu_input_handler_unregister(entry->s); + g_free(entry->qemu_put_mouse_event_name); g_free(entry); From 192f81bfcefa628d804f995449f6f03101c0195f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 12:06:04 +0100 Subject: [PATCH 19/38] input: mouse: switch gtk ui to new core Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 58 +++++++++++++++++++------------------------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 74c0936caf..185149571e 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -194,7 +194,7 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override) on_vga = gd_on_vga(s); if ((override || on_vga) && - (s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) { + (s->full_screen || qemu_input_is_absolute() || gd_is_grab_active(s))) { gdk_window_set_cursor(window, s->null_cursor); } else { gdk_window_set_cursor(window, NULL); @@ -580,7 +580,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, void *opaque) { GtkDisplayState *s = opaque; - int dx, dy; int x, y; int mx, my; int fbh, fbw; @@ -608,25 +607,21 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, return TRUE; } - if (kbd_mouse_is_absolute()) { - dx = x * 0x7FFF / (surface_width(s->ds) - 1); - dy = y * 0x7FFF / (surface_height(s->ds) - 1); - } else if (s->last_x == -1 || s->last_y == -1) { - dx = 0; - dy = 0; - } else { - dx = x - s->last_x; - dy = y - s->last_y; + if (qemu_input_is_absolute()) { + qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_X, x, + surface_width(s->ds)); + qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_Y, y, + surface_height(s->ds)); + qemu_input_event_sync(); + } else if (s->last_x != -1 && s->last_y != -1 && gd_is_grab_active(s)) { + qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_X, x - s->last_x); + qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_Y, y - s->last_y); + qemu_input_event_sync(); } - s->last_x = x; s->last_y = y; - if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) { - kbd_mouse_event(dx, dy, 0, s->button_mask); - } - - if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) { + if (!qemu_input_is_absolute() && gd_is_grab_active(s)) { GdkScreen *screen = gtk_widget_get_screen(s->drawing_area); int x = (int)motion->x_root; int y = (int)motion->y_root; @@ -671,35 +666,20 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button, void *opaque) { GtkDisplayState *s = opaque; - int dx, dy; - int n; + InputButton btn; if (button->button == 1) { - n = 0x01; + btn = INPUT_BUTTON_LEFT; } else if (button->button == 2) { - n = 0x04; + btn = INPUT_BUTTON_MIDDLE; } else if (button->button == 3) { - n = 0x02; + btn = INPUT_BUTTON_RIGHT; } else { - n = 0x00; + return TRUE; } - if (button->type == GDK_BUTTON_PRESS) { - s->button_mask |= n; - } else if (button->type == GDK_BUTTON_RELEASE) { - s->button_mask &= ~n; - } - - if (kbd_mouse_is_absolute()) { - dx = s->last_x * 0x7FFF / (surface_width(s->ds) - 1); - dy = s->last_y * 0x7FFF / (surface_height(s->ds) - 1); - } else { - dx = 0; - dy = 0; - } - - kbd_mouse_event(dx, dy, 0, s->button_mask); - + qemu_input_queue_btn(s->dcl.con, btn, button->type == GDK_BUTTON_PRESS); + qemu_input_event_sync(); return TRUE; } From 3ab193e66262e60e0ff74ac1ab5cff04412e83cb Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 28 Nov 2013 12:27:40 +0100 Subject: [PATCH 20/38] input: mouse: switch sdl ui to new core Signed-off-by: Gerd Hoffmann --- ui/sdl.c | 78 ++++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/ui/sdl.c b/ui/sdl.c index e78e020bd2..b80b3df97a 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -351,7 +351,7 @@ static void sdl_hide_cursor(void) if (!cursor_hide) return; - if (kbd_mouse_is_absolute()) { + if (qemu_input_is_absolute()) { SDL_ShowCursor(1); SDL_SetCursor(sdl_cursor_hidden); } else { @@ -364,10 +364,10 @@ static void sdl_show_cursor(void) if (!cursor_hide) return; - if (!kbd_mouse_is_absolute() || !qemu_console_is_graphic(NULL)) { + if (!qemu_input_is_absolute() || !qemu_console_is_graphic(NULL)) { SDL_ShowCursor(1); if (guest_cursor && - (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) + (gui_grab || qemu_input_is_absolute() || absolute_enabled)) SDL_SetCursor(guest_sprite); else SDL_SetCursor(sdl_cursor_normal); @@ -386,8 +386,9 @@ static void sdl_grab_start(void) } if (guest_cursor) { SDL_SetCursor(guest_sprite); - if (!kbd_mouse_is_absolute() && !absolute_enabled) + if (!qemu_input_is_absolute() && !absolute_enabled) { SDL_WarpMouse(guest_x, guest_y); + } } else sdl_hide_cursor(); SDL_WM_GrabInput(SDL_GRAB_ON); @@ -416,7 +417,7 @@ static void absolute_mouse_grab(void) static void sdl_mouse_mode_change(Notifier *notify, void *data) { - if (kbd_mouse_is_absolute()) { + if (qemu_input_is_absolute()) { if (!absolute_enabled) { absolute_enabled = 1; if (qemu_console_is_graphic(NULL)) { @@ -431,33 +432,36 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data) } } -static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state) +static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state) { - int buttons = 0; + static uint32_t bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT), + [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE), + [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT), + [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP), + [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN), + }; + static uint32_t prev_state; - if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) { - buttons |= MOUSE_EVENT_LBUTTON; - } - if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) { - buttons |= MOUSE_EVENT_RBUTTON; - } - if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) { - buttons |= MOUSE_EVENT_MBUTTON; + if (prev_state != state) { + qemu_input_update_buttons(dcl->con, bmap, prev_state, state); + prev_state = state; } - if (kbd_mouse_is_absolute()) { - dx = x * 0x7FFF / (real_screen->w - 1); - dy = y * 0x7FFF / (real_screen->h - 1); + if (qemu_input_is_absolute()) { + qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, x, + real_screen->w); + qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y, + real_screen->h); } else if (guest_cursor) { x -= guest_x; y -= guest_y; guest_x += x; guest_y += y; - dx = x; - dy = y; + qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, x); + qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, y); } - - kbd_mouse_event(dx, dy, dz, buttons); + qemu_input_event_sync(); } static void sdl_scale(int width, int height) @@ -685,7 +689,7 @@ static void handle_mousemotion(SDL_Event *ev) int max_x, max_y; if (qemu_console_is_graphic(NULL) && - (kbd_mouse_is_absolute() || absolute_enabled)) { + (qemu_input_is_absolute() || absolute_enabled)) { max_x = real_screen->w - 1; max_y = real_screen->h - 1; if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 || @@ -698,8 +702,8 @@ static void handle_mousemotion(SDL_Event *ev) sdl_grab_start(); } } - if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { - sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0, + if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, ev->motion.x, ev->motion.y, ev->motion.state); } } @@ -708,35 +712,24 @@ static void handle_mousebutton(SDL_Event *ev) { int buttonstate = SDL_GetMouseState(NULL, NULL); SDL_MouseButtonEvent *bev; - int dz; if (!qemu_console_is_graphic(NULL)) { return; } bev = &ev->button; - if (!gui_grab && !kbd_mouse_is_absolute()) { + if (!gui_grab && !qemu_input_is_absolute()) { if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { /* start grabbing all events */ sdl_grab_start(); } } else { - dz = 0; if (ev->type == SDL_MOUSEBUTTONDOWN) { buttonstate |= SDL_BUTTON(bev->button); } else { buttonstate &= ~SDL_BUTTON(bev->button); } -#ifdef SDL_BUTTON_WHEELUP - if (bev->button == SDL_BUTTON_WHEELUP && - ev->type == SDL_MOUSEBUTTONDOWN) { - dz = -1; - } else if (bev->button == SDL_BUTTON_WHEELDOWN && - ev->type == SDL_MOUSEBUTTONDOWN) { - dz = 1; - } -#endif - sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate); + sdl_send_mouse_event(0, 0, bev->x, bev->y, buttonstate); } } @@ -751,7 +744,7 @@ static void handle_activation(SDL_Event *ev) } #endif if (!gui_grab && ev->active.gain && qemu_console_is_graphic(NULL) && - (kbd_mouse_is_absolute() || absolute_enabled)) { + (qemu_input_is_absolute() || absolute_enabled)) { absolute_mouse_grab(); } if (ev->active.state & SDL_APPACTIVE) { @@ -823,10 +816,11 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl, if (on) { if (!guest_cursor) sdl_show_cursor(); - if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) { + if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { SDL_SetCursor(guest_sprite); - if (!kbd_mouse_is_absolute() && !absolute_enabled) + if (!qemu_input_is_absolute() && !absolute_enabled) { SDL_WarpMouse(x, y); + } } } else if (gui_grab) sdl_hide_cursor(); @@ -854,7 +848,7 @@ static void sdl_mouse_define(DisplayChangeListener *dcl, g_free(mask); if (guest_cursor && - (gui_grab || kbd_mouse_is_absolute() || absolute_enabled)) + (gui_grab || qemu_input_is_absolute() || absolute_enabled)) SDL_SetCursor(guest_sprite); } From 14768eba46e4ecf60fd267452baf8925afd9ed09 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 2 Dec 2013 15:17:45 +0100 Subject: [PATCH 21/38] input: mouse: switch vnc ui to new core Signed-off-by: Gerd Hoffmann --- ui/vnc.c | 46 ++++++++++++++++++++++------------------------ ui/vnc.h | 1 + 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/ui/vnc.c b/ui/vnc.c index 4658559496..7dfc94a358 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -1484,7 +1484,7 @@ static void client_cut_text(VncState *vs, size_t len, uint8_t *text) static void check_pointer_type_change(Notifier *notifier, void *data) { VncState *vs = container_of(notifier, VncState, mouse_mode_notifier); - int absolute = kbd_mouse_is_absolute(); + int absolute = qemu_input_is_absolute(); if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) { vnc_lock_output(vs); @@ -1503,39 +1503,37 @@ static void check_pointer_type_change(Notifier *notifier, void *data) static void pointer_event(VncState *vs, int button_mask, int x, int y) { - int buttons = 0; - int dz = 0; + static uint32_t bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = 0x01, + [INPUT_BUTTON_MIDDLE] = 0x02, + [INPUT_BUTTON_RIGHT] = 0x04, + [INPUT_BUTTON_WHEEL_UP] = 0x08, + [INPUT_BUTTON_WHEEL_DOWN] = 0x10, + }; + QemuConsole *con = vs->vd->dcl.con; int width = surface_width(vs->vd->ds); int height = surface_height(vs->vd->ds); - if (button_mask & 0x01) - buttons |= MOUSE_EVENT_LBUTTON; - if (button_mask & 0x02) - buttons |= MOUSE_EVENT_MBUTTON; - if (button_mask & 0x04) - buttons |= MOUSE_EVENT_RBUTTON; - if (button_mask & 0x08) - dz = -1; - if (button_mask & 0x10) - dz = 1; + if (vs->last_bmask != button_mask) { + qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask); + vs->last_bmask = button_mask; + } if (vs->absolute) { - kbd_mouse_event(width > 1 ? x * 0x7FFF / (width - 1) : 0x4000, - height > 1 ? y * 0x7FFF / (height - 1) : 0x4000, - dz, buttons); + qemu_input_queue_abs(con, INPUT_AXIS_X, x, width); + qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height); } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) { - x -= 0x7FFF; - y -= 0x7FFF; - - kbd_mouse_event(x, y, dz, buttons); + qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF); + qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF); } else { - if (vs->last_x != -1) - kbd_mouse_event(x - vs->last_x, - y - vs->last_y, - dz, buttons); + if (vs->last_x != -1) { + qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x); + qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y); + } vs->last_x = x; vs->last_y = y; } + qemu_input_event_sync(); } static void reset_keys(VncState *vs) diff --git a/ui/vnc.h b/ui/vnc.h index 6e9921387f..e63c14284b 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -257,6 +257,7 @@ struct VncState int absolute; int last_x; int last_y; + uint32_t last_bmask; int client_width; int client_height; VncShareMode share_mode; From f100db385d604d43332b2aece2db6645c4185e06 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 12:46:34 +0100 Subject: [PATCH 22/38] input: mouse: switch spice ui to new core Signed-off-by: Gerd Hoffmann --- ui/spice-input.c | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/ui/spice-input.c b/ui/spice-input.c index c9df699062..6dab23b75c 100644 --- a/ui/spice-input.c +++ b/ui/spice-input.c @@ -98,41 +98,52 @@ static void kbd_leds(void *opaque, int ledstate) typedef struct QemuSpicePointer { SpiceMouseInstance mouse; SpiceTabletInstance tablet; - int width, height, x, y; + int width, height; + uint32_t last_bmask; Notifier mouse_mode; bool absolute; } QemuSpicePointer; -static int map_buttons(int spice_buttons) +static void spice_update_buttons(QemuSpicePointer *pointer, + int wheel, uint32_t button_mask) { - int qemu_buttons = 0; + static uint32_t bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = 0x01, + [INPUT_BUTTON_MIDDLE] = 0x04, + [INPUT_BUTTON_RIGHT] = 0x02, + [INPUT_BUTTON_WHEEL_UP] = 0x10, + [INPUT_BUTTON_WHEEL_DOWN] = 0x20, + }; - /* - * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this - * isn't what we get passed in via interface callbacks for the - * middle and right button ... - */ - if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) { - qemu_buttons |= MOUSE_EVENT_LBUTTON; + if (wheel < 0) { + button_mask |= 0x10; } - if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) { - qemu_buttons |= MOUSE_EVENT_MBUTTON; + if (wheel > 0) { + button_mask |= 0x20; } - if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) { - qemu_buttons |= MOUSE_EVENT_RBUTTON; + + if (pointer->last_bmask == button_mask) { + return; } - return qemu_buttons; + qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask); + pointer->last_bmask = button_mask; } static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz, uint32_t buttons_state) { - kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state)); + QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse); + spice_update_buttons(pointer, dz, buttons_state); + qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx); + qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy); + qemu_input_event_sync(); } static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state) { - kbd_mouse_event(0, 0, 0, map_buttons(buttons_state)); + QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse); + spice_update_buttons(pointer, 0, buttons_state); + qemu_input_event_sync(); } static const SpiceMouseInterface mouse_interface = { @@ -163,9 +174,10 @@ static void tablet_position(SpiceTabletInstance* sin, int x, int y, { QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - pointer->x = x * 0x7FFF / (pointer->width - 1); - pointer->y = y * 0x7FFF / (pointer->height - 1); - kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state)); + spice_update_buttons(pointer, 0, buttons_state); + qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width); + qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->width); + qemu_input_event_sync(); } @@ -174,7 +186,8 @@ static void tablet_wheel(SpiceTabletInstance* sin, int wheel, { QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state)); + spice_update_buttons(pointer, wheel, buttons_state); + qemu_input_event_sync(); } static void tablet_buttons(SpiceTabletInstance *sin, @@ -182,7 +195,8 @@ static void tablet_buttons(SpiceTabletInstance *sin, { QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); - kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state)); + spice_update_buttons(pointer, 0, buttons_state); + qemu_input_event_sync(); } static const SpiceTabletInterface tablet_interface = { @@ -199,7 +213,7 @@ static const SpiceTabletInterface tablet_interface = { static void mouse_mode_notifier(Notifier *notifier, void *data) { QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode); - bool is_absolute = kbd_mouse_is_absolute(); + bool is_absolute = qemu_input_is_absolute(); if (pointer->absolute == is_absolute) { return; From c751a74afe07b82dbb968abd1eb45cd5163bd9f5 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 15:02:28 +0100 Subject: [PATCH 23/38] input: mouse: switch monitor to new core Signed-off-by: Gerd Hoffmann --- monitor.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/monitor.c b/monitor.c index 3863d83466..342e83baea 100644 --- a/monitor.c +++ b/monitor.c @@ -39,6 +39,7 @@ #include "monitor/monitor.h" #include "qemu/readline.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/blockdev.h" #include "audio/audio.h" #include "disas/disas.h" @@ -1463,23 +1464,43 @@ static int mouse_button_state; static void do_mouse_move(Monitor *mon, const QDict *qdict) { - int dx, dy, dz; + int dx, dy, dz, button; const char *dx_str = qdict_get_str(qdict, "dx_str"); const char *dy_str = qdict_get_str(qdict, "dy_str"); const char *dz_str = qdict_get_try_str(qdict, "dz_str"); + dx = strtol(dx_str, NULL, 0); dy = strtol(dy_str, NULL, 0); - dz = 0; - if (dz_str) + qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx); + qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy); + + if (dz_str) { dz = strtol(dz_str, NULL, 0); - kbd_mouse_event(dx, dy, dz, mouse_button_state); + if (dz != 0) { + button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN; + qemu_input_queue_btn(NULL, button, true); + qemu_input_event_sync(); + qemu_input_queue_btn(NULL, button, false); + } + } + qemu_input_event_sync(); } static void do_mouse_button(Monitor *mon, const QDict *qdict) { + static uint32_t bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, + [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, + [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, + }; int button_state = qdict_get_int(qdict, "button_state"); + + if (mouse_button_state == button_state) { + return; + } + qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state); + qemu_input_event_sync(); mouse_button_state = button_state; - kbd_mouse_event(0, 0, 0, mouse_button_state); } static void do_ioport_read(Monitor *mon, const QDict *qdict) From 2e08c665cccfcaa05e4a82b5a6a8865a6f42c340 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 12:53:44 +0100 Subject: [PATCH 24/38] input: keyboard: switch cocoa ui to new core Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 866177770a..d4af3e5710 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -514,16 +514,14 @@ QemuCocoaView *cocoaView; if (keycode) { if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup - kbd_put_keycode(keycode); - kbd_put_keycode(keycode | 0x80); + qemu_input_event_send_key_number(dcl->con, keycode, true); + qemu_input_event_send_key_number(dcl->con, keycode, false); } else if (qemu_console_is_graphic(NULL)) { - if (keycode & 0x80) - kbd_put_keycode(0xe0); if (modifiers_state[keycode] == 0) { // keydown - kbd_put_keycode(keycode & 0x7f); + qemu_input_event_send_key_number(dcl->con, keycode, true); modifiers_state[keycode] = 1; } else { // keyup - kbd_put_keycode(keycode | 0x80); + qemu_input_event_send_key_number(dcl->con, keycode, false); modifiers_state[keycode] = 0; } } @@ -557,9 +555,7 @@ QemuCocoaView *cocoaView; // handle keys for graphic console } else if (qemu_console_is_graphic(NULL)) { - if (keycode & 0x80) //check bit for e0 in front - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front + qemu_input_event_send_key_number(dcl->con, keycode, true); // handlekeys for Monitor } else { @@ -607,9 +603,7 @@ QemuCocoaView *cocoaView; } if (qemu_console_is_graphic(NULL)) { - if (keycode & 0x80) - kbd_put_keycode(0xe0); - kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key + qemu_input_event_send_key_number(dcl->con, keycode, false); } break; case NSMouseMoved: From 21bae11a39570bea2d7c839d01363dafdab608ce Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 14:08:04 +0100 Subject: [PATCH 25/38] input: mouse: switch cocoa ui to new core Build fixes by Peter Maydell. Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 2 ++ ui/cocoa.m | 63 +++++++++++++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 8543d18319..a3062d092c 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -14,6 +14,8 @@ #define MOUSE_EVENT_LBUTTON 0x01 #define MOUSE_EVENT_RBUTTON 0x02 #define MOUSE_EVENT_MBUTTON 0x04 +#define MOUSE_EVENT_WHEELUP 0x08 +#define MOUSE_EVENT_WHEELDN 0x10 /* identical to the ps/2 keyboard bits */ #define QEMU_SCROLL_LOCK_LED (1 << 0) diff --git a/ui/cocoa.m b/ui/cocoa.m index d4af3e5710..f20fd1ffa2 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -27,6 +27,7 @@ #include "qemu-common.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" #ifndef MAC_OS_X_VERSION_10_4 @@ -49,14 +50,6 @@ #endif #define cgrect(nsrect) (*(CGRect *)&(nsrect)) -#define COCOA_MOUSE_EVENT \ - if (isTabletEnabled) { \ - kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \ - } else if (isMouseGrabbed) { \ - kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \ - } else { \ - [NSApp sendEvent:event]; \ - } typedef struct { int width; @@ -67,6 +60,7 @@ typedef struct { NSWindow *normalWindow; static DisplayChangeListener *dcl; +static int last_buttons; int gArgc; char **gArgv; @@ -501,6 +495,7 @@ QemuCocoaView *cocoaView; int buttons = 0; int keycode; + bool mouse_event = false; NSPoint p = [event locationInWindow]; switch ([event type]) { @@ -620,7 +615,7 @@ QemuCocoaView *cocoaView; } } } - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSLeftMouseDown: if ([event modifierFlags] & NSCommandKeyMask) { @@ -628,15 +623,15 @@ QemuCocoaView *cocoaView; } else { buttons |= MOUSE_EVENT_LBUTTON; } - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSRightMouseDown: buttons |= MOUSE_EVENT_RBUTTON; - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSOtherMouseDown: buttons |= MOUSE_EVENT_MBUTTON; - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSLeftMouseDragged: if ([event modifierFlags] & NSCommandKeyMask) { @@ -644,19 +639,19 @@ QemuCocoaView *cocoaView; } else { buttons |= MOUSE_EVENT_LBUTTON; } - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSRightMouseDragged: buttons |= MOUSE_EVENT_RBUTTON; - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSOtherMouseDragged: buttons |= MOUSE_EVENT_MBUTTON; - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSLeftMouseUp: if (isTabletEnabled) { - COCOA_MOUSE_EVENT + mouse_event = true; } else if (!isMouseGrabbed) { if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) { [self grabMouse]; @@ -664,18 +659,20 @@ QemuCocoaView *cocoaView; [NSApp sendEvent:event]; } } else { - COCOA_MOUSE_EVENT + mouse_event = true; } break; case NSRightMouseUp: - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSOtherMouseUp: - COCOA_MOUSE_EVENT + mouse_event = true; break; case NSScrollWheel: if (isTabletEnabled || isMouseGrabbed) { - kbd_mouse_event(0, 0, -[event deltaY], 0); + buttons |= ([event deltaY] < 0) ? + MOUSE_EVENT_WHEELUP : MOUSE_EVENT_WHEELDN; + mouse_event = true; } else { [NSApp sendEvent:event]; } @@ -683,6 +680,30 @@ QemuCocoaView *cocoaView; default: [NSApp sendEvent:event]; } + + if (mouse_event) { + if (last_buttons != buttons) { + static uint32_t bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON, + [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON, + [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON, + [INPUT_BUTTON_WHEEL_UP] = MOUSE_EVENT_WHEELUP, + [INPUT_BUTTON_WHEEL_DOWN] = MOUSE_EVENT_WHEELDN, + }; + qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons); + last_buttons = buttons; + } + if (isTabletEnabled) { + qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width); + qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, p.y, screen.height); + } else if (isMouseGrabbed) { + qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]); + qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]); + } else { + [NSApp sendEvent:event]; + } + qemu_input_event_sync(); + } } - (void) grabMouse @@ -1017,7 +1038,7 @@ static void cocoa_refresh(DisplayChangeListener *dcl) COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); - if (kbd_mouse_is_absolute()) { + if (qemu_input_is_absolute()) { if (![cocoaView isAbsoluteEnabled]) { if ([cocoaView isMouseGrabbed]) { [cocoaView ungrabMouse]; From c43ce5512fad19896fc952dc769538d5c553f4c9 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Wed, 4 Dec 2013 15:20:05 +0100 Subject: [PATCH 26/38] input: trace events Signed-off-by: Gerd Hoffmann --- trace-events | 8 ++++++++ ui/input.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/trace-events b/trace-events index d86f98cb31..fcdd570096 100644 --- a/trace-events +++ b/trace-events @@ -1020,6 +1020,14 @@ gd_switch(int width, int height) "width=%d, height=%d" 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%d, 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" +input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x" +input_event_sync(void) "" + # hw/display/vmware_vga.c vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x" vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x" diff --git a/ui/input.c b/ui/input.c index 01991cb2c0..60302b1d3c 100644 --- a/ui/input.c +++ b/ui/input.c @@ -1,6 +1,8 @@ #include "sysemu/sysemu.h" #include "qapi-types.h" +#include "trace.h" #include "ui/input.h" +#include "ui/console.h" struct QemuInputHandlerState { DeviceState *dev; @@ -75,6 +77,48 @@ 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; + + if (src) { + idx = qemu_console_get_index(src); + } + switch (evt->kind) { + case INPUT_EVENT_KIND_KEY: + switch (evt->key->key->kind) { + case KEY_VALUE_KIND_NUMBER: + trace_input_event_key_number(idx, evt->key->key->number, + evt->key->down); + break; + case KEY_VALUE_KIND_QCODE: + name = QKeyCode_lookup[evt->key->key->qcode]; + trace_input_event_key_qcode(idx, name, evt->key->down); + break; + case KEY_VALUE_KIND_MAX: + /* keep gcc happy */ + break; + } + break; + case INPUT_EVENT_KIND_BTN: + name = InputButton_lookup[evt->btn->button]; + trace_input_event_btn(idx, name, evt->btn->down); + break; + case INPUT_EVENT_KIND_REL: + name = InputAxis_lookup[evt->rel->axis]; + trace_input_event_rel(idx, name, evt->rel->value); + break; + case INPUT_EVENT_KIND_ABS: + name = InputAxis_lookup[evt->abs->axis]; + trace_input_event_abs(idx, name, evt->abs->value); + break; + case INPUT_EVENT_KIND_MAX: + /* keep gcc happy */ + break; + } +} + void qemu_input_event_send(QemuConsole *src, InputEvent *evt) { QemuInputHandlerState *s; @@ -83,6 +127,8 @@ void qemu_input_event_send(QemuConsole *src, InputEvent *evt) return; } + qemu_input_event_trace(src, evt); + /* pre processing */ if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) { qemu_input_transform_abs_rotate(evt); @@ -102,6 +148,8 @@ void qemu_input_event_sync(void) return; } + trace_input_event_sync(); + QTAILQ_FOREACH(s, &handlers, node) { if (!s->events) { continue; From faecd955ce3100992a8930a4e96c9bc5e27349ce Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Dec 2013 08:12:19 +0100 Subject: [PATCH 27/38] input-legacy: remove kbd_put_keycode Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 - ui/input-legacy.c | 23 ----------------------- 2 files changed, 24 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index a3062d092c..c7f4e4fb32 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -46,7 +46,6 @@ void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry); QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque); void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry); -void kbd_put_keycode(int keycode); void kbd_put_ledstate(int ledstate); void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); diff --git a/ui/input-legacy.c b/ui/input-legacy.c index dd2dec37dd..3ac30e228f 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -500,29 +500,6 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) g_free(entry); } -void kbd_put_keycode(int keycode) -{ - static bool emul0; - bool up; - - if (keycode == SCANCODE_EMUL0) { - emul0 = true; - return; - } - if (keycode & SCANCODE_UP) { - keycode &= ~SCANCODE_UP; - up = true; - } else { - up = false; - } - if (emul0) { - keycode |= SCANCODE_GREY; - emul0 = false; - } - - qemu_input_event_send_key_number(NULL, keycode, !up); -} - void kbd_put_ledstate(int ledstate) { QEMUPutLEDEntry *cursor; From 16b0ecd16837c5987ebc675ef4a0e1926491dc72 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Dec 2013 08:19:02 +0100 Subject: [PATCH 28/38] input-legacy: remove kbd_mouse_has_absolute Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 3 --- ui/input-legacy.c | 21 ++------------------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index c7f4e4fb32..53e956d474 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -54,9 +54,6 @@ int kbd_mouse_is_absolute(void); void qemu_add_mouse_mode_change_notifier(Notifier *notify); void qemu_remove_mouse_mode_change_notifier(Notifier *notify); -/* Of all the mice, is there one that generates absolute events */ -int kbd_mouse_has_absolute(void); - struct MouseTransformInfo { /* Touchscreen resolution */ int x; diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 3ac30e228f..22796faa4f 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -366,20 +366,16 @@ void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry) static void check_mode_change(void) { - static int current_is_absolute, current_has_absolute; + static int current_is_absolute; int is_absolute; - int has_absolute; is_absolute = kbd_mouse_is_absolute(); - has_absolute = kbd_mouse_has_absolute(); - if (is_absolute != current_is_absolute || - has_absolute != current_has_absolute) { + if (is_absolute != current_is_absolute) { notifier_list_notify(&mouse_mode_notifiers, NULL); } current_is_absolute = is_absolute; - current_has_absolute = has_absolute; } static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, @@ -567,19 +563,6 @@ int kbd_mouse_is_absolute(void) return QTAILQ_FIRST(&mouse_handlers)->qemu_put_mouse_event_absolute; } -int kbd_mouse_has_absolute(void) -{ - QEMUPutMouseEntry *entry; - - QTAILQ_FOREACH(entry, &mouse_handlers, node) { - if (entry->qemu_put_mouse_event_absolute) { - return 1; - } - } - - return 0; -} - MouseInfoList *qmp_query_mice(Error **errp) { MouseInfoList *mice_list = NULL; From 2d0755d21cdc4bd47a44ccbd5e3ee70ba67b20ec Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Dec 2013 11:20:39 +0100 Subject: [PATCH 29/38] input-legacy: remove kbd_mouse_is_absolute Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 - ui/input-legacy.c | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 53e956d474..21b32e46d7 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -50,7 +50,6 @@ void kbd_put_ledstate(int ledstate); void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); /* Does the current mouse generate absolute events */ -int kbd_mouse_is_absolute(void); void qemu_add_mouse_mode_change_notifier(Notifier *notify); void qemu_remove_mouse_mode_change_notifier(Notifier *notify); diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 22796faa4f..412d4011dc 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -369,7 +369,7 @@ static void check_mode_change(void) static int current_is_absolute; int is_absolute; - is_absolute = kbd_mouse_is_absolute(); + is_absolute = qemu_input_is_absolute(); if (is_absolute != current_is_absolute) { notifier_list_notify(&mouse_mode_notifiers, NULL); @@ -554,15 +554,6 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) } } -int kbd_mouse_is_absolute(void) -{ - if (QTAILQ_EMPTY(&mouse_handlers)) { - return 0; - } - - return QTAILQ_FIRST(&mouse_handlers)->qemu_put_mouse_event_absolute; -} - MouseInfoList *qmp_query_mice(Error **errp) { MouseInfoList *mice_list = NULL; From 4798648e32112ce92be904bb9d53f8ad0f519c76 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Dec 2013 11:21:21 +0100 Subject: [PATCH 30/38] input-legacy: remove kbd_mouse_event Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 - ui/input-legacy.c | 49 -------------------------------------------- 2 files changed, 50 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 21b32e46d7..71a0da3fbf 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -47,7 +47,6 @@ QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque) void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry); void kbd_put_ledstate(int ledstate); -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); /* Does the current mouse generate absolute events */ void qemu_add_mouse_mode_change_notifier(Notifier *notify); diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 412d4011dc..26ff06fd8c 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -505,55 +505,6 @@ void kbd_put_ledstate(int ledstate) } } -void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) -{ - QEMUPutMouseEntry *entry; - QEMUPutMouseEvent *mouse_event; - void *mouse_event_opaque; - int width, height; - - if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) { - return; - } - if (QTAILQ_EMPTY(&mouse_handlers)) { - return; - } - - entry = QTAILQ_FIRST(&mouse_handlers); - - mouse_event = entry->qemu_put_mouse_event; - mouse_event_opaque = entry->qemu_put_mouse_event_opaque; - - if (mouse_event) { - if (entry->qemu_put_mouse_event_absolute) { - width = 0x7fff; - height = 0x7fff; - } else { - width = graphic_width - 1; - height = graphic_height - 1; - } - - switch (graphic_rotate) { - case 0: - mouse_event(mouse_event_opaque, - dx, dy, dz, buttons_state); - break; - case 90: - mouse_event(mouse_event_opaque, - width - dy, dx, dz, buttons_state); - break; - case 180: - mouse_event(mouse_event_opaque, - width - dx, height - dy, dz, buttons_state); - break; - case 270: - mouse_event(mouse_event_opaque, - dy, height - dx, dz, buttons_state); - break; - } - } -} - MouseInfoList *qmp_query_mice(Error **errp) { MouseInfoList *mice_list = NULL; From 4a33f45e2e4c773b47963baf5a8251963bd01e38 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Dec 2013 11:23:42 +0100 Subject: [PATCH 31/38] input: move mouse mode notifier to new core Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 4 ---- include/ui/input.h | 4 ++++ ui/input-legacy.c | 34 +--------------------------------- ui/input.c | 30 ++++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 37 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 71a0da3fbf..9a282cb077 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -48,10 +48,6 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry); void kbd_put_ledstate(int ledstate); -/* Does the current mouse generate absolute events */ -void qemu_add_mouse_mode_change_notifier(Notifier *notify); -void qemu_remove_mouse_mode_change_notifier(Notifier *notify); - struct MouseTransformInfo { /* Touchscreen resolution */ int x; diff --git a/include/ui/input.h b/include/ui/input.h index 28afc45c04..4976f3da2c 100644 --- a/include/ui/input.h +++ b/include/ui/input.h @@ -49,4 +49,8 @@ void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value); void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size); +void qemu_input_check_mode_change(void); +void qemu_add_mouse_mode_change_notifier(Notifier *notify); +void qemu_remove_mouse_mode_change_notifier(Notifier *notify); + #endif /* INPUT_H */ diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 26ff06fd8c..7f8e72b55e 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -65,8 +65,6 @@ static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers); static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = QTAILQ_HEAD_INITIALIZER(mouse_handlers); -static NotifierList mouse_mode_notifiers = - NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); static const int key_defs[] = { [Q_KEY_CODE_SHIFT] = 0x2a, @@ -364,20 +362,6 @@ void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry) g_free(entry); } -static void check_mode_change(void) -{ - static int current_is_absolute; - int is_absolute; - - is_absolute = qemu_input_is_absolute(); - - if (is_absolute != current_is_absolute) { - notifier_list_notify(&mouse_mode_notifiers, NULL); - } - - current_is_absolute = is_absolute; -} - static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) { @@ -448,8 +432,6 @@ QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, s->s = qemu_input_handler_register((DeviceState *)s, &s->h); - check_mode_change(); - return s; } @@ -459,8 +441,6 @@ void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry) QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node); qemu_input_handler_activate(entry->s); - - check_mode_change(); } void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) @@ -471,8 +451,6 @@ void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) g_free(entry->qemu_put_mouse_event_name); g_free(entry); - - check_mode_change(); } QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, @@ -551,15 +529,5 @@ void do_mouse_set(Monitor *mon, const QDict *qdict) monitor_printf(mon, "Mouse at given index not found\n"); } - check_mode_change(); -} - -void qemu_add_mouse_mode_change_notifier(Notifier *notify) -{ - notifier_list_add(&mouse_mode_notifiers, notify); -} - -void qemu_remove_mouse_mode_change_notifier(Notifier *notify) -{ - notifier_remove(notify); + qemu_input_check_mode_change(); } diff --git a/ui/input.c b/ui/input.c index 60302b1d3c..b8fc6818d2 100644 --- a/ui/input.c +++ b/ui/input.c @@ -13,6 +13,8 @@ struct QemuInputHandlerState { }; static QTAILQ_HEAD(, QemuInputHandlerState) handlers = QTAILQ_HEAD_INITIALIZER(handlers); +static NotifierList mouse_mode_notifiers = + NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, QemuInputHandler *handler) @@ -24,6 +26,8 @@ QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev, s->handler = handler; s->id = id++; QTAILQ_INSERT_TAIL(&handlers, s, node); + + qemu_input_check_mode_change(); return s; } @@ -31,12 +35,14 @@ void qemu_input_handler_activate(QemuInputHandlerState *s) { QTAILQ_REMOVE(&handlers, s, node); QTAILQ_INSERT_HEAD(&handlers, s, node); + qemu_input_check_mode_change(); } void qemu_input_handler_unregister(QemuInputHandlerState *s) { QTAILQ_REMOVE(&handlers, s, node); g_free(s); + qemu_input_check_mode_change(); } static QemuInputHandlerState* @@ -274,3 +280,27 @@ void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size) qemu_input_event_send(src, evt); qapi_free_InputEvent(evt); } + +void qemu_input_check_mode_change(void) +{ + static int current_is_absolute; + int is_absolute; + + is_absolute = qemu_input_is_absolute(); + + if (is_absolute != current_is_absolute) { + notifier_list_notify(&mouse_mode_notifiers, NULL); + } + + current_is_absolute = is_absolute; +} + +void qemu_add_mouse_mode_change_notifier(Notifier *notify) +{ + notifier_list_add(&mouse_mode_notifiers, notify); +} + +void qemu_remove_mouse_mode_change_notifier(Notifier *notify) +{ + notifier_remove(notify); +} From a8dfb1c34ffc17d16eebd46442be93d5e8fad44f Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Thu, 5 Dec 2013 11:24:14 +0100 Subject: [PATCH 32/38] input: add input_mouse_mode tracepoint Signed-off-by: Gerd Hoffmann --- trace-events | 1 + ui/input.c | 1 + 2 files changed, 2 insertions(+) diff --git a/trace-events b/trace-events index fcdd570096..744563cfd3 100644 --- a/trace-events +++ b/trace-events @@ -1027,6 +1027,7 @@ input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d" input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x" input_event_sync(void) "" +input_mouse_mode(int absolute) "absolute %d" # hw/display/vmware_vga.c vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x" diff --git a/ui/input.c b/ui/input.c index b8fc6818d2..afc037c3e9 100644 --- a/ui/input.c +++ b/ui/input.c @@ -289,6 +289,7 @@ void qemu_input_check_mode_change(void) is_absolute = qemu_input_is_absolute(); if (is_absolute != current_is_absolute) { + trace_input_mouse_mode(is_absolute); notifier_list_notify(&mouse_mode_notifiers, NULL); } From e842c68d449a51ec51a0442aa0fe237d4a4b736d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Dec 2013 17:09:36 +0100 Subject: [PATCH 33/38] input: move qmp_query_mice to new core Signed-off-by: Gerd Hoffmann --- ui/input-legacy.c | 23 ----------------------- ui/input.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 7f8e72b55e..7843482387 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -483,29 +483,6 @@ void kbd_put_ledstate(int ledstate) } } -MouseInfoList *qmp_query_mice(Error **errp) -{ - MouseInfoList *mice_list = NULL; - QEMUPutMouseEntry *cursor; - bool current = true; - - QTAILQ_FOREACH(cursor, &mouse_handlers, node) { - MouseInfoList *info = g_malloc0(sizeof(*info)); - info->value = g_malloc0(sizeof(*info->value)); - info->value->name = g_strdup(cursor->qemu_put_mouse_event_name); - info->value->index = cursor->index; - info->value->absolute = !!cursor->qemu_put_mouse_event_absolute; - info->value->current = current; - - current = false; - - info->next = mice_list; - mice_list = info; - } - - return mice_list; -} - void do_mouse_set(Monitor *mon, const QDict *qdict) { QEMUPutMouseEntry *cursor; diff --git a/ui/input.c b/ui/input.c index afc037c3e9..162e8d8a5a 100644 --- a/ui/input.c +++ b/ui/input.c @@ -1,5 +1,6 @@ #include "sysemu/sysemu.h" #include "qapi-types.h" +#include "qmp-commands.h" #include "trace.h" #include "ui/input.h" #include "ui/console.h" @@ -305,3 +306,31 @@ void qemu_remove_mouse_mode_change_notifier(Notifier *notify) { notifier_remove(notify); } + +MouseInfoList *qmp_query_mice(Error **errp) +{ + MouseInfoList *mice_list = NULL; + MouseInfoList *info; + QemuInputHandlerState *s; + bool current = true; + + QTAILQ_FOREACH(s, &handlers, node) { + if (!(s->handler->mask & + (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) { + continue; + } + + info = g_new0(MouseInfoList, 1); + info->value = g_new0(MouseInfo, 1); + info->value->index = s->id; + info->value->name = g_strdup(s->handler->name); + info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS; + info->value->current = current; + + current = false; + info->next = mice_list; + mice_list = info; + } + + return mice_list; +} From 70b52f62b8a94c34ccc939f374bcd00c22a8e3c4 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Dec 2013 17:16:03 +0100 Subject: [PATCH 34/38] input: move do_mouse_set to new core This removes the last user of the lecagy input mouse handler list, so we can remove more legacy bits with this. Signed-off-by: Gerd Hoffmann --- ui/input-legacy.c | 43 ------------------------------------------- ui/input.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 43 deletions(-) diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 7843482387..b51e6ad5df 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -35,12 +35,6 @@ struct QEMUPutMouseEntry { QEMUPutMouseEvent *qemu_put_mouse_event; void *qemu_put_mouse_event_opaque; int qemu_put_mouse_event_absolute; - char *qemu_put_mouse_event_name; - - int index; - - /* used internally by qemu for handling mice */ - QTAILQ_ENTRY(QEMUPutMouseEntry) node; /* new input core */ QemuInputHandler h; @@ -412,17 +406,12 @@ QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, const char *name) { QEMUPutMouseEntry *s; - static int mouse_index = 0; s = g_malloc0(sizeof(QEMUPutMouseEntry)); s->qemu_put_mouse_event = func; s->qemu_put_mouse_event_opaque = opaque; s->qemu_put_mouse_event_absolute = absolute; - s->qemu_put_mouse_event_name = g_strdup(name); - s->index = mouse_index++; - - QTAILQ_INSERT_TAIL(&mouse_handlers, s, node); s->h.name = name; s->h.mask = INPUT_EVENT_MASK_BTN | @@ -437,19 +426,13 @@ QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry) { - QTAILQ_REMOVE(&mouse_handlers, entry, node); - QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node); - qemu_input_handler_activate(entry->s); } void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) { - QTAILQ_REMOVE(&mouse_handlers, entry, node); - qemu_input_handler_unregister(entry->s); - g_free(entry->qemu_put_mouse_event_name); g_free(entry); } @@ -482,29 +465,3 @@ void kbd_put_ledstate(int ledstate) cursor->put_led(cursor->opaque, ledstate); } } - -void do_mouse_set(Monitor *mon, const QDict *qdict) -{ - QEMUPutMouseEntry *cursor; - int index = qdict_get_int(qdict, "index"); - int found = 0; - - if (QTAILQ_EMPTY(&mouse_handlers)) { - monitor_printf(mon, "No mouse devices connected\n"); - return; - } - - QTAILQ_FOREACH(cursor, &mouse_handlers, node) { - if (cursor->index == index) { - found = 1; - qemu_activate_mouse_event_handler(cursor); - break; - } - } - - if (!found) { - monitor_printf(mon, "Mouse at given index not found\n"); - } - - qemu_input_check_mode_change(); -} diff --git a/ui/input.c b/ui/input.c index 162e8d8a5a..2761911f3c 100644 --- a/ui/input.c +++ b/ui/input.c @@ -334,3 +334,24 @@ MouseInfoList *qmp_query_mice(Error **errp) return mice_list; } + +void do_mouse_set(Monitor *mon, const QDict *qdict) +{ + QemuInputHandlerState *s; + int index = qdict_get_int(qdict, "index"); + int found = 0; + + QTAILQ_FOREACH(s, &handlers, node) { + if (s->id == index) { + found = 1; + qemu_input_handler_activate(s); + break; + } + } + + if (!found) { + monitor_printf(mon, "Mouse at given index not found\n"); + } + + qemu_input_check_mode_change(); +} From 5c07d00f1b33729b23326c57b55e71a9cd9b9310 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 10 Dec 2013 17:30:15 +0100 Subject: [PATCH 35/38] input: remove index_from_keycode (no users) Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 1 - ui/input-legacy.c | 14 -------------- 2 files changed, 15 deletions(-) diff --git a/include/ui/console.h b/include/ui/console.h index 9a282cb077..3bf69ee2c2 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -329,7 +329,6 @@ void curses_display_init(DisplayState *ds, int full_screen); /* input.c */ int index_from_key(const char *key); -int index_from_keycode(int code); /* gtk.c */ void early_gtk_display_init(void); diff --git a/ui/input-legacy.c b/ui/input-legacy.c index b51e6ad5df..f38984b192 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -220,20 +220,6 @@ int index_from_key(const char *key) return i; } -int index_from_keycode(int code) -{ - int i; - - for (i = 0; i < Q_KEY_CODE_MAX; i++) { - if (key_defs[i] == code) { - break; - } - } - - /* Return Q_KEY_CODE_MAX if the code is invalid */ - return i; -} - static int *keycodes; static int keycodes_size; static QEMUTimer *key_timer; From 5643706a095044d75df1c0588aac553a595b972b Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 24 Jan 2014 15:35:21 +0100 Subject: [PATCH 36/38] console: add head to index to qemu consoles. Signed-off-by: Gerd Hoffmann --- hw/arm/musicpal.c | 2 +- hw/display/blizzard.c | 2 +- hw/display/cg3.c | 2 +- hw/display/cirrus_vga.c | 4 ++-- hw/display/exynos4210_fimd.c | 2 +- hw/display/g364fb.c | 2 +- hw/display/jazz_led.c | 2 +- hw/display/milkymist-vgafb.c | 2 +- hw/display/omap_lcdc.c | 2 +- hw/display/pl110.c | 2 +- hw/display/pxa2xx_lcd.c | 2 +- hw/display/qxl.c | 4 ++-- hw/display/sm501.c | 2 +- hw/display/ssd0303.c | 2 +- hw/display/ssd0323.c | 2 +- hw/display/tc6393xb.c | 2 +- hw/display/tcx.c | 4 ++-- hw/display/vga-isa-mm.c | 2 +- hw/display/vga-isa.c | 2 +- hw/display/vga-pci.c | 2 +- hw/display/vmware_vga.c | 2 +- hw/unicore32/puv3.c | 2 +- include/ui/console.h | 5 +++-- ui/console.c | 28 ++++++++++++++++++++++++---- 24 files changed, 52 insertions(+), 31 deletions(-) diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index cce7127598..d10b5dbb49 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -630,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd) "musicpal-lcd", MP_LCD_SIZE); sysbus_init_mmio(sbd, &s->iomem); - s->con = graphic_console_init(dev, &musicpal_gfx_ops, s); + s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s); qemu_console_resize(s->con, 128*3, 64*3); qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3); diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c index 4a466c8323..55c0ddf00b 100644 --- a/hw/display/blizzard.c +++ b/hw/display/blizzard.c @@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int) s->fb = g_malloc(0x180000); - s->con = graphic_console_init(NULL, &blizzard_ops, s); + s->con = graphic_console_init(NULL, 0, &blizzard_ops, s); surface = qemu_console_surface(s->con); switch (surface_bits_per_pixel(surface)) { diff --git a/hw/display/cg3.c b/hw/display/cg3.c index 6db8ca362a..a042b9ecbe 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -306,7 +306,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->irq); - s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s); qemu_console_resize(s->con, s->width, s->height); } diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 3a8fc0bf8e..0d3127da21 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp) cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0, isa_address_space(isadev), isa_address_space_io(isadev)); - s->con = graphic_console_init(dev, s->hw_ops, s); + s->con = graphic_console_init(dev, 0, s->hw_ops, s); rom_add_vga(VGABIOS_CIRRUS_FILENAME); /* XXX ISA-LFB support */ /* FIXME not qdev yet */ @@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev) vga_common_init(&s->vga, OBJECT(dev)); cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev), pci_address_space_io(dev)); - s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga); + s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga); /* setup PCI */ diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 65cca1d707..9750330c25 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s, "exynos4210.fimd", FIMD_REGS_SIZE); sysbus_init_mmio(dev, &s->iomem); - s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s); + s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s); return 0; } diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index bc909bb3de..5c6a2d3605 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s) { s->vram = g_malloc0(s->vram_size); - s->con = graphic_console_init(dev, &g364fb_ops, s); + s->con = graphic_console_init(dev, 0, &g364fb_ops, s); memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000); memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram", diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index 8407e6c2ef..f9e7d7c981 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev) memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1); sysbus_init_mmio(dev, &s->iomem); - s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s); return 0; } diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c index 5150cb48b7..603537aabb 100644 --- a/hw/display/milkymist-vgafb.c +++ b/hw/display/milkymist-vgafb.c @@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev) "milkymist-vgafb", R_MAX * 4); sysbus_init_mmio(dev, &s->regs_region); - s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s); return 0; } diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c index c3b9b68971..fda81baff0 100644 --- a/hw/display/omap_lcdc.c +++ b/hw/display/omap_lcdc.c @@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100); memory_region_add_subregion(sysmem, base, &s->iomem); - s->con = graphic_console_init(NULL, &omap_ops, s); + s->con = graphic_console_init(NULL, 0, &omap_ops, s); return s; } diff --git a/hw/display/pl110.c b/hw/display/pl110.c index ab689e9aae..c574cf1a81 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd) sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1); - s->con = graphic_console_init(dev, &pl110_gfx_ops, s); + s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s); return 0; } diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c index 990931ae45..09cdf17ab9 100644 --- a/hw/display/pxa2xx_lcd.c +++ b/hw/display/pxa2xx_lcd.c @@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem, "pxa2xx-lcd-controller", 0x00100000); memory_region_add_subregion(sysmem, base, &s->iomem); - s->con = graphic_console_init(NULL, &pxa2xx_ops, s); + s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s); surface = qemu_console_surface(s->con); switch (surface_bits_per_pixel(surface)) { diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 2a559ebcc9..47bbf1f1fe 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2069,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev) portio_list_set_flush_coalesced(qxl_vga_port_list); portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); - vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl); + vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); qemu_spice_display_init_common(&qxl->ssd); rc = qxl_init_common(qxl); @@ -2094,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev) qxl->vga.vram_size); vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev); qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); - qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl); + qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl); return qxl_init_common(qxl); } diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 0b5f993594..eedf2d48e0 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base, } /* create qemu graphic console */ - s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s); } diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index 89804e108b..c2eea04934 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c) { ssd0303_state *s = SSD0303(i2c); - s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s); + s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s); qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY); return 0; } diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index c3231c6116..46c3b40c79 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev) s->col_end = 63; s->row_end = 79; - s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s); qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1); diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c index 3dd9b98eca..f4011d2db0 100644 --- a/hw/display/tc6393xb.c +++ b/hw/display/tc6393xb.c @@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq) memory_region_add_subregion(sysmem, base + 0x100000, &s->vram); s->scr_width = 480; s->scr_height = 640; - s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s); + s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s); return s; } diff --git a/hw/display/tcx.c b/hw/display/tcx.c index e60769c2c9..2b37ffac4c 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev) &s->vram_mem, vram_offset, size); sysbus_init_mmio(dev, &s->vram_cplane); - s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s); } else { /* THC 8 bit (dummy) */ memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8", TCX_THC_NREGS_8); sysbus_init_mmio(dev, &s->thc8); - s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s); } qemu_console_resize(s->con, s->width, s->height); diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c index 8b514cc39d..afc46b8c9d 100644 --- a/hw/display/vga-isa-mm.c +++ b/hw/display/vga-isa-mm.c @@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base, vga_common_init(&s->vga, NULL); vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space); - s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s); + s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s); vga_init_vbe(&s->vga, NULL, address_space); return 0; diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index c2a19ad6ba..1d9ea6b51d 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp) isa_mem_base + 0x000a0000, vga_io_memory, 1); memory_region_set_coalescing(vga_io_memory); - s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s); vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev)); /* ROM BIOS */ diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index f74fc43aa6..574ea0e7f9 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev) vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev), true); - s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s); + s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s); /* XXX: VGA_RAM_SIZE must be a power of two */ pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 334e71856e..bd2c108c42 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s, s->scratch_size = SVGA_SCRATCH_SIZE; s->scratch = g_malloc(s->scratch_size * 4); - s->vga.con = graphic_console_init(dev, &vmsvga_ops, s); + s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s); s->fifo_size = SVGA_FIFO_SIZE; memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size); diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c index e05cbc131e..42913b6a5a 100644 --- a/hw/unicore32/puv3.c +++ b/hw/unicore32/puv3.c @@ -98,7 +98,7 @@ static void puv3_load_kernel(const char *kernel_filename) } /* cheat curses that we have a graphic console, only under ocd console */ - graphic_console_init(NULL, &no_ops, NULL); + graphic_console_init(NULL, 0, &no_ops, NULL); } static void puv3_init(QEMUMachineInitArgs *args) diff --git a/include/ui/console.h b/include/ui/console.h index 3bf69ee2c2..b2af53e5e6 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -268,7 +268,7 @@ typedef struct GraphicHwOps { void (*update_interval)(void *opaque, uint64_t interval); } GraphicHwOps; -QemuConsole *graphic_console_init(DeviceState *dev, +QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, const GraphicHwOps *ops, void *opaque); @@ -277,11 +277,12 @@ void graphic_hw_invalidate(QemuConsole *con); void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata); QemuConsole *qemu_console_lookup_by_index(unsigned int index); -QemuConsole *qemu_console_lookup_by_device(DeviceState *dev); +QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head); bool qemu_console_is_visible(QemuConsole *con); bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); int qemu_console_get_index(QemuConsole *con); +uint32_t qemu_console_get_head(QemuConsole *con); int qemu_console_get_width(QemuConsole *con, int fallback); int qemu_console_get_height(QemuConsole *con, int fallback); diff --git a/ui/console.c b/ui/console.c index 0bbefe545f..0a4f9128a5 100644 --- a/ui/console.c +++ b/ui/console.c @@ -124,6 +124,7 @@ struct QemuConsole { /* Graphic console state. */ Object *device; + uint32_t head; const GraphicHwOps *hw_ops; void *hw; @@ -1179,6 +1180,8 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type) s = QEMU_CONSOLE(obj); object_property_add_link(obj, "device", TYPE_DEVICE, (Object **)&s->device, &local_err); + object_property_add_uint32_ptr(obj, "head", + &s->head, &local_err); if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && (console_type == GRAPHIC_CONSOLE))) { @@ -1569,7 +1572,7 @@ DisplayState *init_displaystate(void) return display_state; } -QemuConsole *graphic_console_init(DeviceState *dev, +QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, const GraphicHwOps *hw_ops, void *opaque) { @@ -1587,6 +1590,8 @@ QemuConsole *graphic_console_init(DeviceState *dev, if (dev) { object_property_set_link(OBJECT(s), OBJECT(dev), "device", &local_err); + object_property_set_int(OBJECT(s), head, + "head", &local_err); } s->surface = qemu_create_displaysurface(width, height); @@ -1601,10 +1606,11 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index) return consoles[index]; } -QemuConsole *qemu_console_lookup_by_device(DeviceState *dev) +QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head) { Error *local_err = NULL; Object *obj; + uint32_t h; int i; for (i = 0; i < nb_consoles; i++) { @@ -1613,9 +1619,15 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev) } obj = object_property_get_link(OBJECT(consoles[i]), "device", &local_err); - if (DEVICE(obj) == dev) { - return consoles[i]; + if (DEVICE(obj) != dev) { + continue; } + h = object_property_get_int(OBJECT(consoles[i]), + "head", &local_err); + if (h != head) { + continue; + } + return consoles[i]; } return NULL; } @@ -1649,6 +1661,14 @@ int qemu_console_get_index(QemuConsole *con) return con ? con->index : -1; } +uint32_t qemu_console_get_head(QemuConsole *con) +{ + if (con == NULL) { + con = active_console; + } + return con ? con->head : -1; +} + int qemu_console_get_width(QemuConsole *con, int fallback) { if (con == NULL) { From 6f90f3d786ec1ddae31535bb4be4a1120fd5dfe0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 24 Jan 2014 17:38:20 +0100 Subject: [PATCH 37/38] console: add QemuUIInfo Signed-off-by: Gerd Hoffmann --- include/ui/console.h | 12 ++++++++++++ ui/console.c | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/ui/console.h b/include/ui/console.h index b2af53e5e6..08a38eab13 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -120,6 +120,14 @@ struct DisplaySurface { struct PixelFormat pf; }; +typedef struct QemuUIInfo { + /* geometry */ + int xoff; + int yoff; + uint32_t width; + uint32_t height; +} QemuUIInfo; + /* cursor data format is 32bit RGBA */ typedef struct QEMUCursor { int width, height; @@ -204,6 +212,8 @@ void update_displaychangelistener(DisplayChangeListener *dcl, uint64_t interval); void unregister_displaychangelistener(DisplayChangeListener *dcl); +int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info); + void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h); void dpy_gfx_replace_surface(QemuConsole *con, DisplaySurface *surface); @@ -266,6 +276,7 @@ typedef struct GraphicHwOps { void (*gfx_update)(void *opaque); void (*text_update)(void *opaque, console_ch_t *text); void (*update_interval)(void *opaque, uint64_t interval); + int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info); } GraphicHwOps; QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head, @@ -283,6 +294,7 @@ bool qemu_console_is_graphic(QemuConsole *con); bool qemu_console_is_fixedsize(QemuConsole *con); int qemu_console_get_index(QemuConsole *con); uint32_t qemu_console_get_head(QemuConsole *con); +QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con); int qemu_console_get_width(QemuConsole *con, int fallback); int qemu_console_get_height(QemuConsole *con, int fallback); diff --git a/ui/console.c b/ui/console.c index 0a4f9128a5..4df251d579 100644 --- a/ui/console.c +++ b/ui/console.c @@ -125,6 +125,7 @@ struct QemuConsole { /* Graphic console state. */ Object *device; uint32_t head; + QemuUIInfo ui_info; const GraphicHwOps *hw_ops; void *hw; @@ -1347,6 +1348,16 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl) gui_setup_refresh(ds); } +int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info) +{ + assert(con != NULL); + con->ui_info = *info; + if (con->hw_ops->ui_info) { + return con->hw_ops->ui_info(con->hw, con->head, info); + } + return -1; +} + void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h) { DisplayState *s = con->ds; @@ -1669,6 +1680,12 @@ uint32_t qemu_console_get_head(QemuConsole *con) return con ? con->head : -1; } +QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con) +{ + assert(con != NULL); + return &con->ui_info; +} + int qemu_console_get_width(QemuConsole *con, int fallback) { if (con == NULL) { From 47c03744b37c72b8f633b03380d5a323615b9ac4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 10 Dec 2013 14:05:51 +1000 Subject: [PATCH 38/38] ui/sdl2 : initial port to SDL 2.0 (v2.0) I've ported the SDL1.2 code over, and rewritten it to use the SDL2 interface. The biggest changes were in the input handling, where SDL2 has done a major overhaul, and I've had to include a generated translation file to get from SDL2 codes back to qemu compatible ones. I'm still not sure how the keyboard layout code works in qemu, so there may be further work if someone can point me a test case that works with SDL1.2 and doesn't with SDL2. Some SDL env vars we used to set are no longer used by SDL2, Windows, OSX support is untested, I don't think we can link to SDL1.2 and SDL2 at the same time, so I felt using --with-sdlabi=2.0 to select the new code should be fine, like how gtk does it. v1.1: fix keys in text console v1.2: fix shutdown, cleanups a bit of code, support ARGB cursor v2.0: merge the SDL multihead patch into this, g_new the number of consoles needed, wrap DCL inside per-console structure. Signed-off-by: Dave Airlie Fixes & improvements by kraxel: * baum build fix * remove text console logic * adapt to new input core * codestyle fixups Signed-off-by: Gerd Hoffmann --- backends/baum.c | 4 +- configure | 23 +- ui/Makefile.objs | 4 +- ui/sdl.c | 3 + ui/sdl2-keymap.h | 266 +++++++++++++++ ui/sdl2.c | 829 +++++++++++++++++++++++++++++++++++++++++++++++ ui/sdl_keysym.h | 3 +- 7 files changed, 1123 insertions(+), 9 deletions(-) create mode 100644 ui/sdl2-keymap.h create mode 100644 ui/sdl2.c diff --git a/backends/baum.c b/backends/baum.c index 1132899026..665107fa9c 100644 --- a/backends/baum.c +++ b/backends/baum.c @@ -566,7 +566,7 @@ CharDriverState *chr_baum_init(void) BaumDriverState *baum; CharDriverState *chr; brlapi_handle_t *handle; -#ifdef CONFIG_SDL +#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0) SDL_SysWMinfo info; #endif int tty; @@ -595,7 +595,7 @@ CharDriverState *chr_baum_init(void) goto fail; } -#ifdef CONFIG_SDL +#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0) memset(&info, 0, sizeof(info)); SDL_VERSION(&info.version); if (SDL_GetWMInfo(&info)) diff --git a/configure b/configure index 6ccadc3343..8b98ead239 100755 --- a/configure +++ b/configure @@ -207,6 +207,7 @@ fdt="" netmap="no" pixman="" sdl="" +sdlabi="1.2" virtfs="" vnc="yes" sparse="no" @@ -366,6 +367,7 @@ query_pkg_config() { } pkg_config=query_pkg_config sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}" +sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}" # If the user hasn't specified ARFLAGS, default to 'rv', just as make does. ARFLAGS="${ARFLAGS-rv}" @@ -775,6 +777,8 @@ for opt do ;; --enable-sdl) sdl="yes" ;; + --with-sdlabi=*) sdlabi="$optarg" + ;; --disable-qom-cast-debug) qom_cast_debug="no" ;; --enable-qom-cast-debug) qom_cast_debug="yes" @@ -1196,6 +1200,7 @@ Advanced options (experts only): --disable-werror disable compilation abort on warning --disable-sdl disable SDL --enable-sdl enable SDL + --with-sdlabi select preferred SDL ABI 1.2 or 2.0 --disable-gtk disable gtk UI --enable-gtk enable gtk UI --disable-virtfs disable VirtFS @@ -1955,12 +1960,22 @@ fi # Look for sdl configuration program (pkg-config or sdl-config). Try # sdl-config even without cross prefix, and favour pkg-config over sdl-config. -if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then - sdl_config=sdl-config + +if test $sdlabi = "2.0"; then + sdl_config=$sdl2_config + sdlname=sdl2 + sdlconfigname=sdl2_config +else + sdlname=sdl + sdlconfigname=sdl_config fi -if $pkg_config sdl --exists; then - sdlconfig="$pkg_config sdl" +if test "`basename $sdl_config`" != $sdlconfigname && ! has ${sdl_config}; then + sdl_config=$sdlconfigname +fi + +if $pkg_config $sdlname --exists; then + sdlconfig="$pkg_config $sdlname" _sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'` elif has ${sdl_config}; then sdlconfig="$sdl_config" diff --git a/ui/Makefile.objs b/ui/Makefile.objs index 27af551de2..6f2294efda 100644 --- a/ui/Makefile.objs +++ b/ui/Makefile.objs @@ -9,12 +9,12 @@ vnc-obj-y += vnc-jobs.o common-obj-y += keymaps.o console.o cursor.o input.o input-legacy.o qemu-pixman.o common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o -common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o +common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o common-obj-$(CONFIG_COCOA) += cocoa.o common-obj-$(CONFIG_CURSES) += curses.o common-obj-$(CONFIG_VNC) += $(vnc-obj-y) common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o -$(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS) +$(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS) $(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS) diff --git a/ui/sdl.c b/ui/sdl.c index b80b3df97a..c1a16bebdc 100644 --- a/ui/sdl.c +++ b/ui/sdl.c @@ -26,6 +26,8 @@ #undef WIN32_LEAN_AND_MEAN #include + +#if SDL_MAJOR_VERSION == 1 #include #include "qemu-common.h" @@ -951,3 +953,4 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) atexit(sdl_cleanup); } +#endif diff --git a/ui/sdl2-keymap.h b/ui/sdl2-keymap.h new file mode 100644 index 0000000000..5a12f4543a --- /dev/null +++ b/ui/sdl2-keymap.h @@ -0,0 +1,266 @@ + +/* map SDL2 scancodes to QKeyCode */ + +static const int sdl2_scancode_to_qcode[SDL_NUM_SCANCODES] = { + [SDL_SCANCODE_A] = Q_KEY_CODE_A, + [SDL_SCANCODE_B] = Q_KEY_CODE_B, + [SDL_SCANCODE_C] = Q_KEY_CODE_C, + [SDL_SCANCODE_D] = Q_KEY_CODE_D, + [SDL_SCANCODE_E] = Q_KEY_CODE_E, + [SDL_SCANCODE_F] = Q_KEY_CODE_F, + [SDL_SCANCODE_G] = Q_KEY_CODE_G, + [SDL_SCANCODE_H] = Q_KEY_CODE_H, + [SDL_SCANCODE_I] = Q_KEY_CODE_I, + [SDL_SCANCODE_J] = Q_KEY_CODE_J, + [SDL_SCANCODE_K] = Q_KEY_CODE_K, + [SDL_SCANCODE_L] = Q_KEY_CODE_L, + [SDL_SCANCODE_M] = Q_KEY_CODE_M, + [SDL_SCANCODE_N] = Q_KEY_CODE_N, + [SDL_SCANCODE_O] = Q_KEY_CODE_O, + [SDL_SCANCODE_P] = Q_KEY_CODE_P, + [SDL_SCANCODE_Q] = Q_KEY_CODE_Q, + [SDL_SCANCODE_R] = Q_KEY_CODE_R, + [SDL_SCANCODE_S] = Q_KEY_CODE_S, + [SDL_SCANCODE_T] = Q_KEY_CODE_T, + [SDL_SCANCODE_U] = Q_KEY_CODE_U, + [SDL_SCANCODE_V] = Q_KEY_CODE_V, + [SDL_SCANCODE_W] = Q_KEY_CODE_W, + [SDL_SCANCODE_X] = Q_KEY_CODE_X, + [SDL_SCANCODE_Y] = Q_KEY_CODE_Y, + [SDL_SCANCODE_Z] = Q_KEY_CODE_Z, + + [SDL_SCANCODE_1] = Q_KEY_CODE_1, + [SDL_SCANCODE_2] = Q_KEY_CODE_2, + [SDL_SCANCODE_3] = Q_KEY_CODE_3, + [SDL_SCANCODE_4] = Q_KEY_CODE_4, + [SDL_SCANCODE_5] = Q_KEY_CODE_5, + [SDL_SCANCODE_6] = Q_KEY_CODE_6, + [SDL_SCANCODE_7] = Q_KEY_CODE_7, + [SDL_SCANCODE_8] = Q_KEY_CODE_8, + [SDL_SCANCODE_9] = Q_KEY_CODE_9, + [SDL_SCANCODE_0] = Q_KEY_CODE_0, + + [SDL_SCANCODE_RETURN] = Q_KEY_CODE_RET, + [SDL_SCANCODE_ESCAPE] = Q_KEY_CODE_ESC, + [SDL_SCANCODE_BACKSPACE] = Q_KEY_CODE_BACKSPACE, + [SDL_SCANCODE_TAB] = Q_KEY_CODE_TAB, + [SDL_SCANCODE_SPACE] = Q_KEY_CODE_SPC, + [SDL_SCANCODE_MINUS] = Q_KEY_CODE_MINUS, + [SDL_SCANCODE_EQUALS] = Q_KEY_CODE_EQUAL, + [SDL_SCANCODE_LEFTBRACKET] = Q_KEY_CODE_BRACKET_LEFT, + [SDL_SCANCODE_RIGHTBRACKET] = Q_KEY_CODE_BRACKET_RIGHT, + [SDL_SCANCODE_BACKSLASH] = Q_KEY_CODE_BACKSLASH, +#if 0 + [SDL_SCANCODE_NONUSHASH] = Q_KEY_CODE_NONUSHASH, +#endif + [SDL_SCANCODE_SEMICOLON] = Q_KEY_CODE_SEMICOLON, + [SDL_SCANCODE_APOSTROPHE] = Q_KEY_CODE_APOSTROPHE, + [SDL_SCANCODE_GRAVE] = Q_KEY_CODE_GRAVE_ACCENT, + [SDL_SCANCODE_COMMA] = Q_KEY_CODE_COMMA, + [SDL_SCANCODE_PERIOD] = Q_KEY_CODE_DOT, + [SDL_SCANCODE_SLASH] = Q_KEY_CODE_SLASH, + [SDL_SCANCODE_CAPSLOCK] = Q_KEY_CODE_CAPS_LOCK, + + [SDL_SCANCODE_F1] = Q_KEY_CODE_F1, + [SDL_SCANCODE_F2] = Q_KEY_CODE_F2, + [SDL_SCANCODE_F3] = Q_KEY_CODE_F3, + [SDL_SCANCODE_F4] = Q_KEY_CODE_F4, + [SDL_SCANCODE_F5] = Q_KEY_CODE_F5, + [SDL_SCANCODE_F6] = Q_KEY_CODE_F6, + [SDL_SCANCODE_F7] = Q_KEY_CODE_F7, + [SDL_SCANCODE_F8] = Q_KEY_CODE_F8, + [SDL_SCANCODE_F9] = Q_KEY_CODE_F9, + [SDL_SCANCODE_F10] = Q_KEY_CODE_F10, + [SDL_SCANCODE_F11] = Q_KEY_CODE_F11, + [SDL_SCANCODE_F12] = Q_KEY_CODE_F12, + + [SDL_SCANCODE_PRINTSCREEN] = Q_KEY_CODE_PRINT, + [SDL_SCANCODE_SCROLLLOCK] = Q_KEY_CODE_SCROLL_LOCK, + [SDL_SCANCODE_PAUSE] = Q_KEY_CODE_PAUSE, + [SDL_SCANCODE_INSERT] = Q_KEY_CODE_INSERT, + [SDL_SCANCODE_HOME] = Q_KEY_CODE_HOME, + [SDL_SCANCODE_PAGEUP] = Q_KEY_CODE_PGUP, + [SDL_SCANCODE_DELETE] = Q_KEY_CODE_DELETE, + [SDL_SCANCODE_END] = Q_KEY_CODE_END, + [SDL_SCANCODE_PAGEDOWN] = Q_KEY_CODE_PGDN, + [SDL_SCANCODE_RIGHT] = Q_KEY_CODE_RIGHT, + [SDL_SCANCODE_LEFT] = Q_KEY_CODE_LEFT, + [SDL_SCANCODE_DOWN] = Q_KEY_CODE_DOWN, + [SDL_SCANCODE_UP] = Q_KEY_CODE_UP, + [SDL_SCANCODE_NUMLOCKCLEAR] = Q_KEY_CODE_NUM_LOCK, + + [SDL_SCANCODE_KP_DIVIDE] = Q_KEY_CODE_KP_DIVIDE, + [SDL_SCANCODE_KP_MULTIPLY] = Q_KEY_CODE_KP_MULTIPLY, + [SDL_SCANCODE_KP_MINUS] = Q_KEY_CODE_KP_SUBTRACT, + [SDL_SCANCODE_KP_PLUS] = Q_KEY_CODE_KP_ADD, + [SDL_SCANCODE_KP_ENTER] = Q_KEY_CODE_KP_ENTER, + [SDL_SCANCODE_KP_1] = Q_KEY_CODE_KP_1, + [SDL_SCANCODE_KP_2] = Q_KEY_CODE_KP_2, + [SDL_SCANCODE_KP_3] = Q_KEY_CODE_KP_3, + [SDL_SCANCODE_KP_4] = Q_KEY_CODE_KP_4, + [SDL_SCANCODE_KP_5] = Q_KEY_CODE_KP_5, + [SDL_SCANCODE_KP_6] = Q_KEY_CODE_KP_6, + [SDL_SCANCODE_KP_7] = Q_KEY_CODE_KP_7, + [SDL_SCANCODE_KP_8] = Q_KEY_CODE_KP_8, + [SDL_SCANCODE_KP_9] = Q_KEY_CODE_KP_9, + [SDL_SCANCODE_KP_0] = Q_KEY_CODE_KP_0, + [SDL_SCANCODE_KP_PERIOD] = Q_KEY_CODE_KP_DECIMAL, +#if 0 + [SDL_SCANCODE_NONUSBACKSLASH] = Q_KEY_CODE_NONUSBACKSLASH, + [SDL_SCANCODE_APPLICATION] = Q_KEY_CODE_APPLICATION, + [SDL_SCANCODE_POWER] = Q_KEY_CODE_POWER, + [SDL_SCANCODE_KP_EQUALS] = Q_KEY_CODE_KP_EQUALS, + + [SDL_SCANCODE_F13] = Q_KEY_CODE_F13, + [SDL_SCANCODE_F14] = Q_KEY_CODE_F14, + [SDL_SCANCODE_F15] = Q_KEY_CODE_F15, + [SDL_SCANCODE_F16] = Q_KEY_CODE_F16, + [SDL_SCANCODE_F17] = Q_KEY_CODE_F17, + [SDL_SCANCODE_F18] = Q_KEY_CODE_F18, + [SDL_SCANCODE_F19] = Q_KEY_CODE_F19, + [SDL_SCANCODE_F20] = Q_KEY_CODE_F20, + [SDL_SCANCODE_F21] = Q_KEY_CODE_F21, + [SDL_SCANCODE_F22] = Q_KEY_CODE_F22, + [SDL_SCANCODE_F23] = Q_KEY_CODE_F23, + [SDL_SCANCODE_F24] = Q_KEY_CODE_F24, + + [SDL_SCANCODE_EXECUTE] = Q_KEY_CODE_EXECUTE, +#endif + [SDL_SCANCODE_HELP] = Q_KEY_CODE_HELP, + [SDL_SCANCODE_MENU] = Q_KEY_CODE_MENU, +#if 0 + [SDL_SCANCODE_SELECT] = Q_KEY_CODE_SELECT, +#endif + [SDL_SCANCODE_STOP] = Q_KEY_CODE_STOP, + [SDL_SCANCODE_AGAIN] = Q_KEY_CODE_AGAIN, + [SDL_SCANCODE_UNDO] = Q_KEY_CODE_UNDO, + [SDL_SCANCODE_CUT] = Q_KEY_CODE_CUT, + [SDL_SCANCODE_COPY] = Q_KEY_CODE_COPY, + [SDL_SCANCODE_PASTE] = Q_KEY_CODE_PASTE, + [SDL_SCANCODE_FIND] = Q_KEY_CODE_FIND, +#if 0 + [SDL_SCANCODE_MUTE] = Q_KEY_CODE_MUTE, + [SDL_SCANCODE_VOLUMEUP] = Q_KEY_CODE_VOLUMEUP, + [SDL_SCANCODE_VOLUMEDOWN] = Q_KEY_CODE_VOLUMEDOWN, + + [SDL_SCANCODE_KP_COMMA] = Q_KEY_CODE_KP_COMMA, + [SDL_SCANCODE_KP_EQUALSAS400] = Q_KEY_CODE_KP_EQUALSAS400, + + [SDL_SCANCODE_INTERNATIONAL1] = Q_KEY_CODE_INTERNATIONAL1, + [SDL_SCANCODE_INTERNATIONAL2] = Q_KEY_CODE_INTERNATIONAL2, + [SDL_SCANCODE_INTERNATIONAL3] = Q_KEY_CODE_INTERNATIONAL3, + [SDL_SCANCODE_INTERNATIONAL4] = Q_KEY_CODE_INTERNATIONAL4, + [SDL_SCANCODE_INTERNATIONAL5] = Q_KEY_CODE_INTERNATIONAL5, + [SDL_SCANCODE_INTERNATIONAL6] = Q_KEY_CODE_INTERNATIONAL6, + [SDL_SCANCODE_INTERNATIONAL7] = Q_KEY_CODE_INTERNATIONAL7, + [SDL_SCANCODE_INTERNATIONAL8] = Q_KEY_CODE_INTERNATIONAL8, + [SDL_SCANCODE_INTERNATIONAL9] = Q_KEY_CODE_INTERNATIONAL9, + [SDL_SCANCODE_LANG1] = Q_KEY_CODE_LANG1, + [SDL_SCANCODE_LANG2] = Q_KEY_CODE_LANG2, + [SDL_SCANCODE_LANG3] = Q_KEY_CODE_LANG3, + [SDL_SCANCODE_LANG4] = Q_KEY_CODE_LANG4, + [SDL_SCANCODE_LANG5] = Q_KEY_CODE_LANG5, + [SDL_SCANCODE_LANG6] = Q_KEY_CODE_LANG6, + [SDL_SCANCODE_LANG7] = Q_KEY_CODE_LANG7, + [SDL_SCANCODE_LANG8] = Q_KEY_CODE_LANG8, + [SDL_SCANCODE_LANG9] = Q_KEY_CODE_LANG9, + [SDL_SCANCODE_ALTERASE] = Q_KEY_CODE_ALTERASE, +#endif + [SDL_SCANCODE_SYSREQ] = Q_KEY_CODE_SYSRQ, +#if 0 + [SDL_SCANCODE_CANCEL] = Q_KEY_CODE_CANCEL, + [SDL_SCANCODE_CLEAR] = Q_KEY_CODE_CLEAR, + [SDL_SCANCODE_PRIOR] = Q_KEY_CODE_PRIOR, + [SDL_SCANCODE_RETURN2] = Q_KEY_CODE_RETURN2, + [SDL_SCANCODE_SEPARATOR] = Q_KEY_CODE_SEPARATOR, + [SDL_SCANCODE_OUT] = Q_KEY_CODE_OUT, + [SDL_SCANCODE_OPER] = Q_KEY_CODE_OPER, + [SDL_SCANCODE_CLEARAGAIN] = Q_KEY_CODE_CLEARAGAIN, + [SDL_SCANCODE_CRSEL] = Q_KEY_CODE_CRSEL, + [SDL_SCANCODE_EXSEL] = Q_KEY_CODE_EXSEL, + [SDL_SCANCODE_KP_00] = Q_KEY_CODE_KP_00, + [SDL_SCANCODE_KP_000] = Q_KEY_CODE_KP_000, + [SDL_SCANCODE_THOUSANDSSEPARATOR] = Q_KEY_CODE_THOUSANDSSEPARATOR, + [SDL_SCANCODE_DECIMALSEPARATOR] = Q_KEY_CODE_DECIMALSEPARATOR, + [SDL_SCANCODE_CURRENCYUNIT] = Q_KEY_CODE_CURRENCYUNIT, + [SDL_SCANCODE_CURRENCYSUBUNIT] = Q_KEY_CODE_CURRENCYSUBUNIT, + [SDL_SCANCODE_KP_LEFTPAREN] = Q_KEY_CODE_KP_LEFTPAREN, + [SDL_SCANCODE_KP_RIGHTPAREN] = Q_KEY_CODE_KP_RIGHTPAREN, + [SDL_SCANCODE_KP_LEFTBRACE] = Q_KEY_CODE_KP_LEFTBRACE, + [SDL_SCANCODE_KP_RIGHTBRACE] = Q_KEY_CODE_KP_RIGHTBRACE, + [SDL_SCANCODE_KP_TAB] = Q_KEY_CODE_KP_TAB, + [SDL_SCANCODE_KP_BACKSPACE] = Q_KEY_CODE_KP_BACKSPACE, + [SDL_SCANCODE_KP_A] = Q_KEY_CODE_KP_A, + [SDL_SCANCODE_KP_B] = Q_KEY_CODE_KP_B, + [SDL_SCANCODE_KP_C] = Q_KEY_CODE_KP_C, + [SDL_SCANCODE_KP_D] = Q_KEY_CODE_KP_D, + [SDL_SCANCODE_KP_E] = Q_KEY_CODE_KP_E, + [SDL_SCANCODE_KP_F] = Q_KEY_CODE_KP_F, + [SDL_SCANCODE_KP_XOR] = Q_KEY_CODE_KP_XOR, + [SDL_SCANCODE_KP_POWER] = Q_KEY_CODE_KP_POWER, + [SDL_SCANCODE_KP_PERCENT] = Q_KEY_CODE_KP_PERCENT, + [SDL_SCANCODE_KP_LESS] = Q_KEY_CODE_KP_LESS, + [SDL_SCANCODE_KP_GREATER] = Q_KEY_CODE_KP_GREATER, + [SDL_SCANCODE_KP_AMPERSAND] = Q_KEY_CODE_KP_AMPERSAND, + [SDL_SCANCODE_KP_DBLAMPERSAND] = Q_KEY_CODE_KP_DBLAMPERSAND, + [SDL_SCANCODE_KP_VERTICALBAR] = Q_KEY_CODE_KP_VERTICALBAR, + [SDL_SCANCODE_KP_DBLVERTICALBAR] = Q_KEY_CODE_KP_DBLVERTICALBAR, + [SDL_SCANCODE_KP_COLON] = Q_KEY_CODE_KP_COLON, + [SDL_SCANCODE_KP_HASH] = Q_KEY_CODE_KP_HASH, + [SDL_SCANCODE_KP_SPACE] = Q_KEY_CODE_KP_SPACE, + [SDL_SCANCODE_KP_AT] = Q_KEY_CODE_KP_AT, + [SDL_SCANCODE_KP_EXCLAM] = Q_KEY_CODE_KP_EXCLAM, + [SDL_SCANCODE_KP_MEMSTORE] = Q_KEY_CODE_KP_MEMSTORE, + [SDL_SCANCODE_KP_MEMRECALL] = Q_KEY_CODE_KP_MEMRECALL, + [SDL_SCANCODE_KP_MEMCLEAR] = Q_KEY_CODE_KP_MEMCLEAR, + [SDL_SCANCODE_KP_MEMADD] = Q_KEY_CODE_KP_MEMADD, + [SDL_SCANCODE_KP_MEMSUBTRACT] = Q_KEY_CODE_KP_MEMSUBTRACT, + [SDL_SCANCODE_KP_MEMMULTIPLY] = Q_KEY_CODE_KP_MEMMULTIPLY, + [SDL_SCANCODE_KP_MEMDIVIDE] = Q_KEY_CODE_KP_MEMDIVIDE, + [SDL_SCANCODE_KP_PLUSMINUS] = Q_KEY_CODE_KP_PLUSMINUS, + [SDL_SCANCODE_KP_CLEAR] = Q_KEY_CODE_KP_CLEAR, + [SDL_SCANCODE_KP_CLEARENTRY] = Q_KEY_CODE_KP_CLEARENTRY, + [SDL_SCANCODE_KP_BINARY] = Q_KEY_CODE_KP_BINARY, + [SDL_SCANCODE_KP_OCTAL] = Q_KEY_CODE_KP_OCTAL, + [SDL_SCANCODE_KP_DECIMAL] = Q_KEY_CODE_KP_DECIMAL, + [SDL_SCANCODE_KP_HEXADECIMAL] = Q_KEY_CODE_KP_HEXADECIMAL, +#endif + [SDL_SCANCODE_LCTRL] = Q_KEY_CODE_CTRL, + [SDL_SCANCODE_LSHIFT] = Q_KEY_CODE_SHIFT, + [SDL_SCANCODE_LALT] = Q_KEY_CODE_ALT, + [SDL_SCANCODE_LGUI] = Q_KEY_CODE_META_L, + [SDL_SCANCODE_RCTRL] = Q_KEY_CODE_CTRL_R, + [SDL_SCANCODE_RSHIFT] = Q_KEY_CODE_SHIFT_R, + [SDL_SCANCODE_RALT] = Q_KEY_CODE_ALTGR, + [SDL_SCANCODE_RGUI] = Q_KEY_CODE_META_R, +#if 0 + [SDL_SCANCODE_MODE] = Q_KEY_CODE_MODE, + [SDL_SCANCODE_AUDIONEXT] = Q_KEY_CODE_AUDIONEXT, + [SDL_SCANCODE_AUDIOPREV] = Q_KEY_CODE_AUDIOPREV, + [SDL_SCANCODE_AUDIOSTOP] = Q_KEY_CODE_AUDIOSTOP, + [SDL_SCANCODE_AUDIOPLAY] = Q_KEY_CODE_AUDIOPLAY, + [SDL_SCANCODE_AUDIOMUTE] = Q_KEY_CODE_AUDIOMUTE, + [SDL_SCANCODE_MEDIASELECT] = Q_KEY_CODE_MEDIASELECT, + [SDL_SCANCODE_WWW] = Q_KEY_CODE_WWW, + [SDL_SCANCODE_MAIL] = Q_KEY_CODE_MAIL, + [SDL_SCANCODE_CALCULATOR] = Q_KEY_CODE_CALCULATOR, + [SDL_SCANCODE_COMPUTER] = Q_KEY_CODE_COMPUTER, + [SDL_SCANCODE_AC_SEARCH] = Q_KEY_CODE_AC_SEARCH, + [SDL_SCANCODE_AC_HOME] = Q_KEY_CODE_AC_HOME, + [SDL_SCANCODE_AC_BACK] = Q_KEY_CODE_AC_BACK, + [SDL_SCANCODE_AC_FORWARD] = Q_KEY_CODE_AC_FORWARD, + [SDL_SCANCODE_AC_STOP] = Q_KEY_CODE_AC_STOP, + [SDL_SCANCODE_AC_REFRESH] = Q_KEY_CODE_AC_REFRESH, + [SDL_SCANCODE_AC_BOOKMARKS] = Q_KEY_CODE_AC_BOOKMARKS, + [SDL_SCANCODE_BRIGHTNESSDOWN] = Q_KEY_CODE_BRIGHTNESSDOWN, + [SDL_SCANCODE_BRIGHTNESSUP] = Q_KEY_CODE_BRIGHTNESSUP, + [SDL_SCANCODE_DISPLAYSWITCH] = Q_KEY_CODE_DISPLAYSWITCH, + [SDL_SCANCODE_KBDILLUMTOGGLE] = Q_KEY_CODE_KBDILLUMTOGGLE, + [SDL_SCANCODE_KBDILLUMDOWN] = Q_KEY_CODE_KBDILLUMDOWN, + [SDL_SCANCODE_KBDILLUMUP] = Q_KEY_CODE_KBDILLUMUP, + [SDL_SCANCODE_EJECT] = Q_KEY_CODE_EJECT, + [SDL_SCANCODE_SLEEP] = Q_KEY_CODE_SLEEP, + [SDL_SCANCODE_APP1] = Q_KEY_CODE_APP1, + [SDL_SCANCODE_APP2] = Q_KEY_CODE_APP2, +#endif +}; diff --git a/ui/sdl2.c b/ui/sdl2.c new file mode 100644 index 0000000000..f1532e9d2c --- /dev/null +++ b/ui/sdl2.c @@ -0,0 +1,829 @@ +/* + * QEMU SDL display driver + * + * Copyright (c) 2003 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */ + +/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */ +#undef WIN32_LEAN_AND_MEAN + +#include + +#if SDL_MAJOR_VERSION == 2 +#include + +#include "qemu-common.h" +#include "ui/console.h" +#include "ui/input.h" +#include "sysemu/sysemu.h" +#include "sdl_zoom.h" + +#include "sdl2-keymap.h" + +static int sdl2_num_outputs; +static struct sdl2_state { + DisplayChangeListener dcl; + DisplaySurface *surface; + SDL_Texture *texture; + SDL_Window *real_window; + SDL_Renderer *real_renderer; + int idx; + int last_vm_running; /* per console for caption reasons */ + int x, y; +} *sdl2_console; + +static SDL_Surface *guest_sprite_surface; +static int gui_grab; /* if true, all keyboard/mouse events are grabbed */ + +static bool gui_saved_scaling; +static int gui_saved_width; +static int gui_saved_height; +static int gui_saved_grab; +static int gui_fullscreen; +static int gui_noframe; +static int gui_key_modifier_pressed; +static int gui_keysym; +static int gui_grab_code = KMOD_LALT | KMOD_LCTRL; +static uint8_t modifiers_state[SDL_NUM_SCANCODES]; +static SDL_Cursor *sdl_cursor_normal; +static SDL_Cursor *sdl_cursor_hidden; +static int absolute_enabled; +static int guest_cursor; +static int guest_x, guest_y; +static SDL_Cursor *guest_sprite; +static int scaling_active; +static Notifier mouse_mode_notifier; + +static void sdl_update_caption(struct sdl2_state *scon); + +static struct sdl2_state *get_scon_from_window(uint32_t window_id) +{ + int i; + for (i = 0; i < sdl2_num_outputs; i++) { + if (sdl2_console[i].real_window == SDL_GetWindowFromID(window_id)) { + return &sdl2_console[i]; + } + } + return NULL; +} + +static void sdl_update(DisplayChangeListener *dcl, + int x, int y, int w, int h) +{ + struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl); + SDL_Rect rect; + DisplaySurface *surf = qemu_console_surface(dcl->con); + + if (!surf) { + return; + } + if (!scon->texture) { + return; + } + + rect.x = x; + rect.y = y; + rect.w = w; + rect.h = h; + + SDL_UpdateTexture(scon->texture, NULL, surface_data(surf), + surface_stride(surf)); + SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect); + SDL_RenderPresent(scon->real_renderer); +} + +static void do_sdl_resize(struct sdl2_state *scon, int width, int height, + int bpp) +{ + int flags; + + if (scon->real_window && scon->real_renderer) { + if (width && height) { + SDL_RenderSetLogicalSize(scon->real_renderer, width, height); + SDL_SetWindowSize(scon->real_window, width, height); + } else { + SDL_DestroyRenderer(scon->real_renderer); + SDL_DestroyWindow(scon->real_window); + scon->real_renderer = NULL; + scon->real_window = NULL; + } + } else { + if (!width || !height) { + return; + } + flags = 0; + if (gui_fullscreen) { + flags |= SDL_WINDOW_FULLSCREEN; + } else { + flags |= SDL_WINDOW_RESIZABLE; + } + + scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + width, height, flags); + scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); + sdl_update_caption(scon); + } +} + +static void sdl_switch(DisplayChangeListener *dcl, + DisplaySurface *new_surface) +{ + struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl); + int format = 0; + int idx = scon->idx; + DisplaySurface *old_surface = scon->surface; + + /* temporary hack: allows to call sdl_switch to handle scaling changes */ + if (new_surface) { + scon->surface = new_surface; + } + + if (!new_surface && idx > 0) { + scon->surface = NULL; + } + + if (new_surface == NULL) { + do_sdl_resize(scon, 0, 0, 0); + } else { + do_sdl_resize(scon, surface_width(scon->surface), + surface_height(scon->surface), 0); + } + + if (old_surface && scon->texture) { + SDL_DestroyTexture(scon->texture); + scon->texture = NULL; + } + + if (new_surface) { + if (!scon->texture) { + if (surface_bits_per_pixel(scon->surface) == 16) { + format = SDL_PIXELFORMAT_RGB565; + } else if (surface_bits_per_pixel(scon->surface) == 32) { + format = SDL_PIXELFORMAT_ARGB8888; + } + + scon->texture = SDL_CreateTexture(scon->real_renderer, format, + SDL_TEXTUREACCESS_STREAMING, + surface_width(new_surface), + surface_height(new_surface)); + } + } +} + +static void reset_keys(void) +{ + 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); + modifiers_state[i] = 0; + } + } +} + +static void sdl_process_key(SDL_KeyboardEvent *ev) +{ + int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode]; + + 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); + return; +#endif + case SDL_SCANCODE_LCTRL: + case SDL_SCANCODE_LSHIFT: + case SDL_SCANCODE_LALT: + case SDL_SCANCODE_LGUI: + case SDL_SCANCODE_RCTRL: + case SDL_SCANCODE_RSHIFT: + case SDL_SCANCODE_RALT: + case SDL_SCANCODE_RGUI: + if (ev->type == SDL_KEYUP) { + modifiers_state[ev->keysym.scancode] = 0; + } else { + modifiers_state[ev->keysym.scancode] = 1; + } + /* fall though */ + default: + qemu_input_event_send_key_qcode(NULL, qcode, + ev->type == SDL_KEYDOWN); + } +} + +static void sdl_update_caption(struct sdl2_state *scon) +{ + char win_title[1024]; + char icon_title[1024]; + const char *status = ""; + + if (!runstate_is_running()) { + status = " [Stopped]"; + } else if (gui_grab) { + if (alt_grab) { + status = " - Press Ctrl-Alt-Shift to exit mouse grab"; + } else if (ctrl_grab) { + status = " - Press Right-Ctrl to exit mouse grab"; + } else { + status = " - Press Ctrl-Alt to exit mouse grab"; + } + } + + if (qemu_name) { + snprintf(win_title, sizeof(win_title), "QEMU (%s-%d)%s", qemu_name, + scon->idx, status); + snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name); + } else { + snprintf(win_title, sizeof(win_title), "QEMU%s", status); + snprintf(icon_title, sizeof(icon_title), "QEMU"); + } + + if (scon->real_window) { + SDL_SetWindowTitle(scon->real_window, win_title); + } +} + +static void sdl_hide_cursor(void) +{ + if (!cursor_hide) { + return; + } + + if (qemu_input_is_absolute()) { + SDL_ShowCursor(1); + SDL_SetCursor(sdl_cursor_hidden); + } else { + SDL_ShowCursor(0); + } +} + +static void sdl_show_cursor(void) +{ + if (!cursor_hide) { + return; + } + + if (!qemu_input_is_absolute()) { + SDL_ShowCursor(1); + if (guest_cursor && + (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { + SDL_SetCursor(guest_sprite); + } else { + SDL_SetCursor(sdl_cursor_normal); + } + } +} + +static void sdl_grab_start(struct sdl2_state *scon) +{ + /* + * If the application is not active, do not try to enter grab state. This + * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the + * application (SDL bug). + */ + if (!(SDL_GetWindowFlags(scon->real_window) & SDL_WINDOW_INPUT_FOCUS)) { + return; + } + if (guest_cursor) { + SDL_SetCursor(guest_sprite); + if (!qemu_input_is_absolute() && !absolute_enabled) { + SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y); + } + } else { + sdl_hide_cursor(); + } + SDL_SetWindowGrab(scon->real_window, SDL_TRUE); + gui_grab = 1; + sdl_update_caption(scon); +} + +static void sdl_grab_end(struct sdl2_state *scon) +{ + SDL_SetWindowGrab(scon->real_window, SDL_FALSE); + gui_grab = 0; + sdl_show_cursor(); + sdl_update_caption(scon); +} + +static void absolute_mouse_grab(struct sdl2_state *scon) +{ + int mouse_x, mouse_y; + int scr_w, scr_h; + SDL_GetMouseState(&mouse_x, &mouse_y); + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + if (mouse_x > 0 && mouse_x < scr_w - 1 && + mouse_y > 0 && mouse_y < scr_h - 1) { + sdl_grab_start(scon); + } +} + +static void sdl_mouse_mode_change(Notifier *notify, void *data) +{ + if (qemu_input_is_absolute()) { + if (!absolute_enabled) { + absolute_enabled = 1; + absolute_mouse_grab(&sdl2_console[0]); + } + } else if (absolute_enabled) { + if (!gui_fullscreen) { + sdl_grab_end(&sdl2_console[0]); + } + absolute_enabled = 0; + } +} + +static void sdl_send_mouse_event(struct sdl2_state *scon, int dx, int dy, + int dz, int x, int y, int state) +{ + static uint32_t bmap[INPUT_BUTTON_MAX] = { + [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT), + [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE), + [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT), +#if 0 + [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP), + [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN), +#endif + }; + static uint32_t prev_state; + + if (prev_state != state) { + qemu_input_update_buttons(scon->dcl.con, bmap, prev_state, state); + prev_state = state; + } + + if (qemu_input_is_absolute()) { + int scr_w, scr_h; + int max_w = 0, max_h = 0; + int off_x = 0, off_y = 0; + int cur_off_x = 0, cur_off_y = 0; + int i; + + for (i = 0; i < sdl2_num_outputs; i++) { + struct sdl2_state *thiscon = &sdl2_console[i]; + if (thiscon->real_window && thiscon->surface) { + SDL_GetWindowSize(thiscon->real_window, &scr_w, &scr_h); + cur_off_x = thiscon->x; + cur_off_y = thiscon->y; + if (scr_w + cur_off_x > max_w) { + max_w = scr_w + cur_off_x; + } + if (scr_h + cur_off_y > max_h) { + max_h = scr_h + cur_off_y; + } + if (i == scon->idx) { + off_x = cur_off_x; + off_y = cur_off_y; + } + } + } + qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w); + qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h); + } else if (guest_cursor) { + x -= guest_x; + y -= guest_y; + guest_x += x; + guest_y += y; + qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, x); + qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, y); + } + qemu_input_event_sync(); +} + +static void sdl_scale(struct sdl2_state *scon, int width, int height) +{ + int bpp = 0; + do_sdl_resize(scon, width, height, bpp); + scaling_active = 1; +} + +static void toggle_full_screen(struct sdl2_state *scon) +{ + int width = surface_width(scon->surface); + int height = surface_height(scon->surface); + int bpp = surface_bits_per_pixel(scon->surface); + + gui_fullscreen = !gui_fullscreen; + if (gui_fullscreen) { + SDL_GetWindowSize(scon->real_window, + &gui_saved_width, &gui_saved_height); + gui_saved_scaling = scaling_active; + + do_sdl_resize(scon, width, height, bpp); + scaling_active = 0; + + gui_saved_grab = gui_grab; + sdl_grab_start(scon); + } else { + if (gui_saved_scaling) { + sdl_scale(scon, gui_saved_width, gui_saved_height); + } else { + do_sdl_resize(scon, width, height, 0); + } + if (!gui_saved_grab) { + sdl_grab_end(scon); + } + } + graphic_hw_invalidate(scon->dcl.con); + graphic_hw_update(scon->dcl.con); +} + +static void handle_keydown(SDL_Event *ev) +{ + int mod_state; + struct sdl2_state *scon = get_scon_from_window(ev->key.windowID); + + if (alt_grab) { + mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) == + (gui_grab_code | KMOD_LSHIFT); + } else if (ctrl_grab) { + mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL; + } else { + mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code; + } + gui_key_modifier_pressed = mod_state; + + if (gui_key_modifier_pressed) { + switch (ev->key.keysym.scancode) { + case SDL_SCANCODE_F: + toggle_full_screen(scon); + gui_keysym = 1; + break; + case SDL_SCANCODE_U: + if (scaling_active) { + scaling_active = 0; + sdl_switch(&scon->dcl, NULL); + graphic_hw_invalidate(scon->dcl.con); + graphic_hw_update(scon->dcl.con); + } + gui_keysym = 1; + break; + case SDL_SCANCODE_KP_PLUS: + case SDL_SCANCODE_KP_MINUS: + if (!gui_fullscreen) { + int scr_w, scr_h; + int width, height; + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + + width = MAX(scr_w + (ev->key.keysym.scancode == + SDL_SCANCODE_KP_PLUS ? 50 : -50), + 160); + height = (surface_height(scon->surface) * width) / + surface_width(scon->surface); + + sdl_scale(scon, width, height); + graphic_hw_invalidate(NULL); + graphic_hw_update(NULL); + gui_keysym = 1; + } + default: + break; + } + } + if (!gui_keysym) { + sdl_process_key(&ev->key); + } +} + +static void handle_keyup(SDL_Event *ev) +{ + int mod_state; + struct sdl2_state *scon = get_scon_from_window(ev->key.windowID); + + if (!alt_grab) { + mod_state = (ev->key.keysym.mod & gui_grab_code); + } else { + mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT)); + } + if (!mod_state && gui_key_modifier_pressed) { + gui_key_modifier_pressed = 0; + if (gui_keysym == 0) { + /* exit/enter grab if pressing Ctrl-Alt */ + if (!gui_grab) { + sdl_grab_start(scon); + } else if (!gui_fullscreen) { + sdl_grab_end(scon); + } + /* SDL does not send back all the modifiers key, so we must + * correct it. */ + reset_keys(); + return; + } + gui_keysym = 0; + } + if (!gui_keysym) { + sdl_process_key(&ev->key); + } +} + +static void handle_mousemotion(SDL_Event *ev) +{ + int max_x, max_y; + struct sdl2_state *scon = get_scon_from_window(ev->key.windowID); + + if (qemu_input_is_absolute() || absolute_enabled) { + int scr_w, scr_h; + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + max_x = scr_w - 1; + max_y = scr_h - 1; + if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 || + ev->motion.x == max_x || ev->motion.y == max_y)) { + sdl_grab_end(scon); + } + if (!gui_grab && + (ev->motion.x > 0 && ev->motion.x < max_x && + ev->motion.y > 0 && ev->motion.y < max_y)) { + sdl_grab_start(scon); + } + } + if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, 0, + ev->motion.x, ev->motion.y, ev->motion.state); + } +} + +static void handle_mousebutton(SDL_Event *ev) +{ + int buttonstate = SDL_GetMouseState(NULL, NULL); + SDL_MouseButtonEvent *bev; + struct sdl2_state *scon = get_scon_from_window(ev->key.windowID); + int dz; + + bev = &ev->button; + if (!gui_grab && !qemu_input_is_absolute()) { + if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { + /* start grabbing all events */ + sdl_grab_start(scon); + } + } else { + dz = 0; + if (ev->type == SDL_MOUSEBUTTONDOWN) { + buttonstate |= SDL_BUTTON(bev->button); + } else { + buttonstate &= ~SDL_BUTTON(bev->button); + } +#ifdef SDL_BUTTON_WHEELUP + if (bev->button == SDL_BUTTON_WHEELUP && + ev->type == SDL_MOUSEBUTTONDOWN) { + dz = -1; + } else if (bev->button == SDL_BUTTON_WHEELDOWN && + ev->type == SDL_MOUSEBUTTONDOWN) { + dz = 1; + } +#endif + sdl_send_mouse_event(scon, 0, 0, dz, bev->x, bev->y, buttonstate); + } +} + +static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev) +{ + int w, h; + struct sdl2_state *scon = get_scon_from_window(ev->key.windowID); + + switch (ev->window.event) { + case SDL_WINDOWEVENT_RESIZED: + sdl_scale(scon, ev->window.data1, ev->window.data2); + graphic_hw_invalidate(scon->dcl.con); + graphic_hw_update(scon->dcl.con); + break; + case SDL_WINDOWEVENT_EXPOSED: + SDL_GetWindowSize(SDL_GetWindowFromID(ev->window.windowID), &w, &h); + sdl_update(dcl, 0, 0, w, h); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_ENTER: + if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) { + absolute_mouse_grab(scon); + } + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + if (gui_grab && !gui_fullscreen) { + sdl_grab_end(scon); + } + break; + case SDL_WINDOWEVENT_RESTORED: + update_displaychangelistener(dcl, GUI_REFRESH_INTERVAL_DEFAULT); + break; + case SDL_WINDOWEVENT_MINIMIZED: + update_displaychangelistener(dcl, 500); + break; + case SDL_WINDOWEVENT_CLOSE: + if (!no_quit) { + no_shutdown = 0; + qemu_system_shutdown_request(); + } + break; + } +} + +static void sdl_refresh(DisplayChangeListener *dcl) +{ + struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl); + SDL_Event ev1, *ev = &ev1; + + if (scon->last_vm_running != runstate_is_running()) { + scon->last_vm_running = runstate_is_running(); + sdl_update_caption(scon); + } + + graphic_hw_update(dcl->con); + + while (SDL_PollEvent(ev)) { + switch (ev->type) { + case SDL_KEYDOWN: + handle_keydown(ev); + break; + case SDL_KEYUP: + handle_keyup(ev); + break; + case SDL_QUIT: + if (!no_quit) { + no_shutdown = 0; + qemu_system_shutdown_request(); + } + break; + case SDL_MOUSEMOTION: + handle_mousemotion(ev); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + handle_mousebutton(ev); + break; + case SDL_WINDOWEVENT: + handle_windowevent(dcl, ev); + break; + default: + break; + } + } +} + +static void sdl_mouse_warp(DisplayChangeListener *dcl, + int x, int y, int on) +{ + struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl); + if (on) { + if (!guest_cursor) { + sdl_show_cursor(); + } + if (gui_grab || qemu_input_is_absolute() || absolute_enabled) { + SDL_SetCursor(guest_sprite); + if (!qemu_input_is_absolute() && !absolute_enabled) { + SDL_WarpMouseInWindow(scon->real_window, x, y); + } + } + } else if (gui_grab) { + sdl_hide_cursor(); + } + guest_cursor = on; + guest_x = x, guest_y = y; +} + +static void sdl_mouse_define(DisplayChangeListener *dcl, + QEMUCursor *c) +{ + + if (guest_sprite) { + SDL_FreeCursor(guest_sprite); + } + + if (guest_sprite_surface) { + SDL_FreeSurface(guest_sprite_surface); + } + + guest_sprite_surface = + SDL_CreateRGBSurfaceFrom(c->data, c->width, c->height, 32, c->width * 4, + 0xff0000, 0x00ff00, 0xff, 0xff000000); + + if (!guest_sprite_surface) { + fprintf(stderr, "Failed to make rgb surface from %p\n", c); + return; + } + guest_sprite = SDL_CreateColorCursor(guest_sprite_surface, + c->hot_x, c->hot_y); + if (!guest_sprite) { + fprintf(stderr, "Failed to make color cursor from %p\n", c); + return; + } + if (guest_cursor && + (gui_grab || qemu_input_is_absolute() || absolute_enabled)) { + SDL_SetCursor(guest_sprite); + } +} + +static void sdl_cleanup(void) +{ + if (guest_sprite) { + SDL_FreeCursor(guest_sprite); + } + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} + +static const DisplayChangeListenerOps dcl_ops = { + .dpy_name = "sdl", + .dpy_gfx_update = sdl_update, + .dpy_gfx_switch = sdl_switch, + .dpy_refresh = sdl_refresh, + .dpy_mouse_set = sdl_mouse_warp, + .dpy_cursor_define = sdl_mouse_define, +}; + +void sdl_display_init(DisplayState *ds, int full_screen, int no_frame) +{ + int flags; + uint8_t data = 0; + char *filename; + int i; + + if (no_frame) { + gui_noframe = 1; + } + +#ifdef __linux__ + /* on Linux, SDL may use fbcon|directfb|svgalib when run without + * accessible $DISPLAY to open X11 window. This is often the case + * when qemu is run using sudo. But in this case, and when actually + * run in X11 environment, SDL fights with X11 for the video card, + * making current display unavailable, often until reboot. + * So make x11 the default SDL video driver if this variable is unset. + * This is a bit hackish but saves us from bigger problem. + * Maybe it's a good idea to fix this in SDL instead. + */ + setenv("SDL_VIDEODRIVER", "x11", 0); +#endif + + flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE; + if (SDL_Init(flags)) { + fprintf(stderr, "Could not initialize SDL(%s) - exiting\n", + SDL_GetError()); + exit(1); + } + + for (i = 0;; i++) { + QemuConsole *con = qemu_console_lookup_by_index(i); + if (!con || !qemu_console_is_graphic(con)) { + break; + } + } + sdl2_num_outputs = i; + sdl2_console = g_new0(struct sdl2_state, sdl2_num_outputs); + for (i = 0; i < sdl2_num_outputs; i++) { + QemuConsole *con = qemu_console_lookup_by_index(i); + sdl2_console[i].dcl.ops = &dcl_ops; + sdl2_console[i].dcl.con = con; + register_displaychangelistener(&sdl2_console[i].dcl); + sdl2_console[i].idx = i; + } + + /* Load a 32x32x4 image. White pixels are transparent. */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp"); + if (filename) { + SDL_Surface *image = SDL_LoadBMP(filename); + if (image) { + uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255); + SDL_SetColorKey(image, SDL_TRUE, colorkey); + SDL_SetWindowIcon(sdl2_console[0].real_window, image); + } + g_free(filename); + } + + if (full_screen) { + gui_fullscreen = 1; + sdl_grab_start(0); + } + + mouse_mode_notifier.notify = sdl_mouse_mode_change; + qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier); + + gui_grab = 0; + + sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0); + sdl_cursor_normal = SDL_GetCursor(); + + atexit(sdl_cleanup); +} +#endif diff --git a/ui/sdl_keysym.h b/ui/sdl_keysym.h index ee904805da..599d9fc64d 100644 --- a/ui/sdl_keysym.h +++ b/ui/sdl_keysym.h @@ -200,6 +200,7 @@ static const name2keysym_t name2keysym[]={ { "yacute", 0x0fd}, { "thorn", 0x0fe}, { "ydiaeresis", 0x0ff}, +#if SDL_MAJOR_VERSION == 1 {"EuroSign", SDLK_EURO}, /* modifiers */ @@ -272,6 +273,6 @@ static const name2keysym_t name2keysym[]={ {"Num_Lock", SDLK_NUMLOCK}, {"Pause", SDLK_PAUSE}, {"Escape", SDLK_ESCAPE}, - +#endif {NULL, 0}, };