aboutsummaryrefslogtreecommitdiffstats
path: root/vncviewer
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2021-12-14 17:06:36 +0100
committerPierre Ossman <ossman@cendio.se>2022-12-13 14:52:13 +0100
commit4f6d4895c3420e5ac301a916bced4a0065a19183 (patch)
treef838f2f17e2902c57bf5f5b15be8e12338aa0436 /vncviewer
parent946fb2b03b7663abd9d71014de5dfdf25a7e040d (diff)
downloadtigervnc-4f6d4895c3420e5ac301a916bced4a0065a19183.tar.gz
tigervnc-4f6d4895c3420e5ac301a916bced4a0065a19183.zip
Handle macOS keyboard stealing
The system steals keyboard events for certain system keyboard shortcuts, e.g. Cmd+Tab. Unfortunately this isn't considered a focus loss, so we don't realise we've lost a few keyboard events and can end up in a confused state. Fortunately it is possible to detect when this happens and reset the keyboard state, just like we do when focus is lost.
Diffstat (limited to 'vncviewer')
-rw-r--r--vncviewer/Viewport.cxx20
-rw-r--r--vncviewer/Viewport.h2
-rw-r--r--vncviewer/cocoa.h1
-rw-r--r--vncviewer/cocoa.mm21
4 files changed, 40 insertions, 4 deletions
diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx
index 81ad9827..83872ced 100644
--- a/vncviewer/Viewport.cxx
+++ b/vncviewer/Viewport.cxx
@@ -643,10 +643,9 @@ 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)
- while (!downKeySym.empty())
- handleKeyRelease(downKeySym.begin()->first);
+ // We won't get more key events, so reset our knowledge about keys
+ resetKeyboard();
+
Fl::enable_im();
return 1;
@@ -823,6 +822,13 @@ void Viewport::handlePointerTimeout(void *data)
}
+void Viewport::resetKeyboard()
+{
+ while (!downKeySym.empty())
+ handleKeyRelease(downKeySym.begin()->first);
+}
+
+
void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
{
static bool menuRecursion = false;
@@ -1125,6 +1131,12 @@ int Viewport::handleSystemEvent(void *event, void *data)
return 1;
}
#elif defined(__APPLE__)
+ // Special event that means we temporarily lost some input
+ if (cocoa_is_keyboard_sync(event)) {
+ self->resetKeyboard();
+ return 1;
+ }
+
if (cocoa_is_keyboard_event(event)) {
int keyCode;
diff --git a/vncviewer/Viewport.h b/vncviewer/Viewport.h
index 19def92c..a42b06c6 100644
--- a/vncviewer/Viewport.h
+++ b/vncviewer/Viewport.h
@@ -84,6 +84,8 @@ private:
void handlePointerEvent(const rfb::Point& pos, int buttonMask);
static void handlePointerTimeout(void *data);
+ void resetKeyboard();
+
void handleKeyPress(int keyCode, rdr::U32 keySym);
void handleKeyRelease(int keyCode);
diff --git a/vncviewer/cocoa.h b/vncviewer/cocoa.h
index ca17ddf9..63b2a535 100644
--- a/vncviewer/cocoa.h
+++ b/vncviewer/cocoa.h
@@ -34,6 +34,7 @@ CGColorSpaceRef cocoa_win_color_space(Fl_Window *win);
bool cocoa_win_is_zoomed(Fl_Window *win);
void cocoa_win_zoom(Fl_Window *win);
+int cocoa_is_keyboard_sync(const void *event);
int cocoa_is_keyboard_event(const void *event);
int cocoa_is_key_press(const void *event);
diff --git a/vncviewer/cocoa.mm b/vncviewer/cocoa.mm
index cf9c9a8e..e8b202d6 100644
--- a/vncviewer/cocoa.mm
+++ b/vncviewer/cocoa.mm
@@ -175,6 +175,25 @@ void cocoa_win_zoom(Fl_Window *win)
[nsw zoom:nsw];
}
+int cocoa_is_keyboard_sync(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 0;
+ if ([nsevent keyCode] != 0)
+ return 0;
+
+ return 1;
+}
+
int cocoa_is_keyboard_event(const void *event)
{
NSEvent *nsevent;
@@ -185,6 +204,8 @@ int cocoa_is_keyboard_event(const void *event)
case NSKeyDown:
case NSKeyUp:
case NSFlagsChanged:
+ if (cocoa_is_keyboard_sync(event))
+ return 0;
return 1;
default:
return 0;