From c2b852a512605f601a1caefc5498c66259233b31 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 14 Dec 2021 17:06:36 +0100 Subject: [PATCH] TEMP: handle macOS keyboard steal --- vncviewer/KeyboardMacOS.h | 3 +++ vncviewer/KeyboardMacOS.mm | 22 +++++++++++++++++++ vncviewer/Viewport.cxx | 43 +++++++++++++++++++++++++------------- vncviewer/Viewport.h | 2 ++ 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/vncviewer/KeyboardMacOS.h b/vncviewer/KeyboardMacOS.h index 5ebab7b5f..e61e26143 100644 --- a/vncviewer/KeyboardMacOS.h +++ b/vncviewer/KeyboardMacOS.h @@ -39,6 +39,9 @@ class KeyboardMacOS : public Keyboard { virtual unsigned getLEDState(); virtual void setLEDState(unsigned state); + // Special helper on macOS + static bool isKeyboardSync(const void* event); + protected: bool isKeyboardEvent(const NSEvent* nsevent); bool isKeyPress(const NSEvent* nsevent); diff --git a/vncviewer/KeyboardMacOS.mm b/vncviewer/KeyboardMacOS.mm index 62cdcdfcd..42964d3ac 100644 --- a/vncviewer/KeyboardMacOS.mm +++ b/vncviewer/KeyboardMacOS.mm @@ -296,12 +296,34 @@ // No support for Scroll Lock // } +bool KeyboardMacOS::isKeyboardSync(const void* event) +{ + const NSEvent* nsevent = (const NSEvent*)event; + + assert(event); + + // If we get a NSFlagsChanged event with key code 0 then this isn't + // an actual keyboard event but rather the system trying to sync up + // modifier state after it has stolen input for some reason (e.g. + // Cmd+Tab) + + if ([nsevent type] != NSFlagsChanged) + return false; + if ([nsevent keyCode] != 0) + return false; + + return true; +} + bool KeyboardMacOS::isKeyboardEvent(const NSEvent* nsevent) { switch ([nsevent type]) { case NSKeyDown: case NSKeyUp: + return true; case NSFlagsChanged: + if (isKeyboardSync(nsevent)) + return false; return true; default: return false; diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index a48071b4a..2cc99c357 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -457,21 +457,8 @@ int Viewport::handle(int event) return 1; case FL_UNFOCUS: - // Release all keys that were pressed as that generally makes most - // sense (e.g. Alt+Tab where we only see the Alt press) - try { - cc->releaseAllKeys(); - } catch (rdr::Exception& e) { - vlog.error("%s", e.str()); - abort_connection(_("An unexpected error occurred when communicating " - "with the server:\n\n%s"), e.str()); - } - keyboard->reset(); - - hotKeyHandler.reset(); - hotKeyBypass = false; - hotKeyActive = false; - pressedKeys.clear(); + // We won't get more key events, so reset our knowledge about keys + resetKeyboard(); //Fl::enable_im(); return 1; @@ -610,6 +597,24 @@ void Viewport::handlePointerTimeout(void *data) } } +void Viewport::resetKeyboard() +{ + // Release all keys that were pressed as that generally makes most + // sense (e.g. Alt+Tab where we only see the Alt press) + try { + cc->releaseAllKeys(); + } catch (rdr::Exception& e) { + vlog.error("%s", e.str()); + abort_connection(_("An unexpected error occurred when communicating " + "with the server:\n\n%s"), e.str()); + } + keyboard->reset(); + + hotKeyHandler.reset(); + hotKeyBypass = false; + hotKeyActive = false; + pressedKeys.clear(); +} void Viewport::handleKeyPress(int systemKeyCode, rdr::U32 keyCode, rdr::U32 keySym) @@ -807,6 +812,14 @@ int Viewport::handleSystemEvent(void *event, void *data) if (!self->hasFocus()) return 0; +#ifdef __APPLE__ + // Special event that means we temporarily lost some input + if (KeyboardMacOS::isKeyboardSync(event)) { + self->resetKeyboard(); + return 1; + } +#endif + consumed = self->keyboard->handleEvent(event); if (consumed) return 1; diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h index 5e526161d..f6de5cebe 100644 --- a/vncviewer/Viewport.h +++ b/vncviewer/Viewport.h @@ -84,6 +84,8 @@ class Viewport : public Fl_Widget, protected EmulateMB, void handlePointerEvent(const rfb::Point& pos, int buttonMask); static void handlePointerTimeout(void *data); + void resetKeyboard(); + virtual void handleKeyPress(int systemKeyCode, rdr::U32 keyCode, rdr::U32 keySym); virtual void handleKeyRelease(int systemKeyCode);