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