Browse Source

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.
tags/v1.12.90
Pierre Ossman 2 years ago
parent
commit
4f6d4895c3
4 changed files with 40 additions and 4 deletions
  1. 16
    4
      vncviewer/Viewport.cxx
  2. 2
    0
      vncviewer/Viewport.h
  3. 1
    0
      vncviewer/cocoa.h
  4. 21
    0
      vncviewer/cocoa.mm

+ 16
- 4
vncviewer/Viewport.cxx View File

@@ -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;


+ 2
- 0
vncviewer/Viewport.h View File

@@ -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);


+ 1
- 0
vncviewer/cocoa.h View File

@@ -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);

+ 21
- 0
vncviewer/cocoa.mm View File

@@ -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;

Loading…
Cancel
Save