From af8862b2a2445d0110f3b3125c1a41fbb5934123 Mon Sep 17 00:00:00 2001 From: Ian McKellar via Qemu-devel Date: Fri, 26 May 2017 16:38:16 -0700 Subject: Improve Cocoa modifier key handling I had two problems with QEMU on macOS: 1) Sometimes when alt-tabbing to QEMU it would act as if the 'a' key was pressed so I'd get 'aaaaaaaaa....'. 2) Using Sikuli to programatically send keys to the QEMU window text like "foo_bar" would come out as "fooa-bar". They looked similar and after much digging the problem turned out to be the same. When QEMU's ui/cocoa.m received an NSFlagsChanged NSEvent it looked at the keyCode to determine what modifier key changed. This usually works fine but sometimes the keyCode is 0 and the app should instead be looking at the modifierFlags bitmask. Key code 0 is the 'a' key. I added code that handles keyCode == 0 differently. It checks the modifierFlags and if they differ from QEMU's idea of which modifier keys are currently pressed it toggles those changed keys. This fixes my problems and seems work fine. Signed-off-by: Ian McKellar Message-id: 20170526233816.47627-1-ianloic@google.com Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 60 ++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 004ec27..1f010d3 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -52,6 +52,8 @@ /* macOS 10.12 deprecated many constants, #define the new names for older SDKs */ #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 #define NSEventMaskAny NSAnyEventMask +#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask +#define NSEventModifierFlagShift NSShiftKeyMask #define NSEventModifierFlagCommand NSCommandKeyMask #define NSEventModifierFlagControl NSControlKeyMask #define NSEventModifierFlagOption NSAlternateKeyMask @@ -268,7 +270,7 @@ static void handleAnyDeviceErrors(Error * err) NSWindow *fullScreenWindow; float cx,cy,cw,ch,cdx,cdy; CGDataProviderRef dataProviderRef; - int modifiers_state[256]; + BOOL modifiers_state[256]; BOOL isMouseGrabbed; BOOL isFullscreen; BOOL isAbsoluteEnabled; @@ -536,18 +538,59 @@ QemuCocoaView *cocoaView; } } +- (void) toggleModifier: (int)keycode { + // Toggle the stored state. + modifiers_state[keycode] = !modifiers_state[keycode]; + // Send a keyup or keydown depending on the state. + qemu_input_event_send_key_qcode(dcl->con, keycode, modifiers_state[keycode]); +} + +- (void) toggleStatefulModifier: (int)keycode { + // Toggle the stored state. + modifiers_state[keycode] = !modifiers_state[keycode]; + // Generate keydown and keyup. + qemu_input_event_send_key_qcode(dcl->con, keycode, true); + qemu_input_event_send_key_qcode(dcl->con, keycode, false); +} + - (void) handleEvent:(NSEvent *)event { COCOA_DEBUG("QemuCocoaView: handleEvent\n"); int buttons = 0; - int keycode; + int keycode = 0; bool mouse_event = false; NSPoint p = [event locationInWindow]; switch ([event type]) { case NSEventTypeFlagsChanged: - keycode = cocoa_keycode_to_qemu([event keyCode]); + if ([event keyCode] == 0) { + // When the Cocoa keyCode is zero that means keys should be + // synthesized based on the values in in the eventModifiers + // bitmask. + + if (qemu_console_is_graphic(NULL)) { + NSEventModifierFlags modifiers = [event modifierFlags]; + + if (!!(modifiers & NSEventModifierFlagCapsLock) != !!modifiers_state[Q_KEY_CODE_CAPS_LOCK]) { + [self toggleStatefulModifier:Q_KEY_CODE_CAPS_LOCK]; + } + if (!!(modifiers & NSEventModifierFlagShift) != !!modifiers_state[Q_KEY_CODE_SHIFT]) { + [self toggleModifier:Q_KEY_CODE_SHIFT]; + } + if (!!(modifiers & NSEventModifierFlagControl) != !!modifiers_state[Q_KEY_CODE_CTRL]) { + [self toggleModifier:Q_KEY_CODE_CTRL]; + } + if (!!(modifiers & NSEventModifierFlagOption) != !!modifiers_state[Q_KEY_CODE_ALT]) { + [self toggleModifier:Q_KEY_CODE_ALT]; + } + if (!!(modifiers & NSEventModifierFlagCommand) != !!modifiers_state[Q_KEY_CODE_META_L]) { + [self toggleModifier:Q_KEY_CODE_META_L]; + } + } + } else { + keycode = cocoa_keycode_to_qemu([event keyCode]); + } if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R) && !isMouseGrabbed) { @@ -559,16 +602,9 @@ QemuCocoaView *cocoaView; // emulate caps lock and num lock keydown and keyup if (keycode == Q_KEY_CODE_CAPS_LOCK || keycode == Q_KEY_CODE_NUM_LOCK) { - qemu_input_event_send_key_qcode(dcl->con, keycode, true); - qemu_input_event_send_key_qcode(dcl->con, keycode, false); + [self toggleStatefulModifier:keycode]; } else if (qemu_console_is_graphic(NULL)) { - if (modifiers_state[keycode] == 0) { // keydown - qemu_input_event_send_key_qcode(dcl->con, keycode, true); - modifiers_state[keycode] = 1; - } else { // keyup - qemu_input_event_send_key_qcode(dcl->con, keycode, false); - modifiers_state[keycode] = 0; - } + [self toggleModifier:keycode]; } } -- cgit v1.1 From bfefa6d7d6e930429ac3a7ff3347c9c67f069289 Mon Sep 17 00:00:00 2001 From: Jonathon Jongsma Date: Wed, 10 May 2017 15:20:06 -0500 Subject: spice: Use proper enum type for kbd led state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although the Qemu and spice flags currently have the same value, it seems more correct to pass the spice flag values to spice_server_kbd_leds(), especially considering that this function already makes an effort to convert between the QEMU_*_LED and SPICE_KEYBOARD_MODIFIER_* values. Signed-off-by: Jonathon Jongsma Reviewed-by: Marc-André Lureau Message-id: 20170510202006.31737-1-jjongsma@redhat.com Signed-off-by: Gerd Hoffmann --- ui/spice-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/spice-input.c b/ui/spice-input.c index 86293dd..9185802 100644 --- a/ui/spice-input.c +++ b/ui/spice-input.c @@ -87,7 +87,7 @@ static void kbd_leds(void *opaque, int ledstate) if (ledstate & QEMU_CAPS_LOCK_LED) { kbd->ledstate |= SPICE_KEYBOARD_MODIFIER_FLAGS_CAPS_LOCK; } - spice_server_kbd_leds(&kbd->sin, ledstate); + spice_server_kbd_leds(&kbd->sin, kbd->ledstate); } /* mouse bits */ -- cgit v1.1 From 5fe309ff0d1e8234fd79c21544bfcc436ece6386 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Jun 2017 12:53:36 +0200 Subject: gtk: prefer gtk3 over gtk2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case the configure script finds both gtk2 and gtk3 installed it still prefers gtk2 over gtk3. Prefer gtk3 instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20170606105339.3613-2-kraxel@redhat.com --- configure | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/configure b/configure index b147191..bfba156 100755 --- a/configure +++ b/configure @@ -2301,14 +2301,14 @@ fi # GTK probe if test "$gtkabi" = ""; then - # The GTK ABI was not specified explicitly, so try whether 2.0 is available. - # Use 3.0 as a fallback if that is available. - if $pkg_config --exists "gtk+-2.0 >= 2.18.0"; then - gtkabi=2.0 - elif $pkg_config --exists "gtk+-3.0 >= 3.0.0"; then + # The GTK ABI was not specified explicitly, so try whether 3.0 is available. + # Use 2.0 as a fallback if that is available. + if $pkg_config --exists "gtk+-3.0 >= 3.0.0"; then gtkabi=3.0 - else + elif $pkg_config --exists "gtk+-2.0 >= 2.18.0"; then gtkabi=2.0 + else + gtkabi=3.0 fi fi @@ -2331,7 +2331,7 @@ if test "$gtk" != "no"; then libs_softmmu="$gtk_libs $libs_softmmu" gtk="yes" elif test "$gtk" = "yes"; then - feature_not_found "gtk" "Install gtk2 or gtk3 devel" + feature_not_found "gtk" "Install gtk3-devel" else gtk="no" fi -- cgit v1.1 From 8f4ea9cd0b770dbe496d9d24f0ef8813fdbfe0d0 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Jun 2017 12:53:37 +0200 Subject: sdl: prefer sdl2 over sdl1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case the configure script finds both SDL 1.2 and SDL 2.x installed it still prefers SDL 1.2. Prefer SDL 2.x instead. Signed-off-by: Gerd Hoffmann Reviewed-by: Marc-André Lureau Message-id: 20170606105339.3613-3-kraxel@redhat.com --- configure | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure b/configure index bfba156..db0798d 100755 --- a/configure +++ b/configure @@ -2598,12 +2598,12 @@ fi # sdl-config even without cross prefix, and favour pkg-config over sdl-config. if test "$sdlabi" = ""; then - if $pkg_config --exists "sdl"; then - sdlabi=1.2 - elif $pkg_config --exists "sdl2"; then + if $pkg_config --exists "sdl2"; then sdlabi=2.0 - else + elif $pkg_config --exists "sdl"; then sdlabi=1.2 + else + sdlabi=2.0 fi fi @@ -2630,7 +2630,7 @@ elif has ${sdl_config}; then sdlversion=$($sdlconfig --version) else if test "$sdl" = "yes" ; then - feature_not_found "sdl" "Install SDL devel" + feature_not_found "sdl" "Install SDL2-devel" fi sdl=no fi -- cgit v1.1 From fe5c44f9c95be3f74fb58902077ac587998d1392 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 6 Jun 2017 13:06:18 +0200 Subject: spice: don't enter opengl mode in case another UI provides opengl support Signed-off-by: Gerd Hoffmann Message-id: 20170606110618.10393-1-kraxel@redhat.com --- include/ui/spice-display.h | 2 ++ ui/spice-core.c | 1 + ui/spice-display.c | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/ui/spice-display.h b/include/ui/spice-display.h index 184d4c3..4ba9444 100644 --- a/include/ui/spice-display.h +++ b/include/ui/spice-display.h @@ -140,6 +140,8 @@ struct SimpleSpiceCursor { QXLCursor cursor; }; +extern bool spice_opengl; + int qemu_spice_rect_is_empty(const QXLRect* r); void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r); diff --git a/ui/spice-core.c b/ui/spice-core.c index a087ad5..182f550 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -847,6 +847,7 @@ void qemu_spice_init(void) exit(1); } display_opengl = 1; + spice_opengl = 1; } #endif } diff --git a/ui/spice-display.c b/ui/spice-display.c index b353445..042292c 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -27,6 +27,7 @@ #include "ui/spice-display.h" static int debug = 0; +bool spice_opengl; static void GCC_FMT_ATTR(2, 3) dprint(int level, const char *fmt, ...) { @@ -1013,7 +1014,7 @@ static void qemu_spice_display_init_one(QemuConsole *con) ssd->dcl.ops = &display_listener_ops; #ifdef HAVE_SPICE_GL - if (display_opengl) { + if (spice_opengl) { ssd->dcl.ops = &display_listener_gl_ops; ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd); ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME, -- cgit v1.1