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
return 1; | return 1; | ||||
case FL_UNFOCUS: | 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(); | Fl::enable_im(); | ||||
return 1; | return 1; | ||||
} | } | ||||
void Viewport::resetKeyboard() | |||||
{ | |||||
while (!downKeySym.empty()) | |||||
handleKeyRelease(downKeySym.begin()->first); | |||||
} | |||||
void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) | void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) | ||||
{ | { | ||||
static bool menuRecursion = false; | static bool menuRecursion = false; | ||||
return 1; | return 1; | ||||
} | } | ||||
#elif defined(__APPLE__) | #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)) { | if (cocoa_is_keyboard_event(event)) { | ||||
int keyCode; | int keyCode; | ||||
void handlePointerEvent(const rfb::Point& pos, int buttonMask); | void handlePointerEvent(const rfb::Point& pos, int buttonMask); | ||||
static void handlePointerTimeout(void *data); | static void handlePointerTimeout(void *data); | ||||
void resetKeyboard(); | |||||
void handleKeyPress(int keyCode, rdr::U32 keySym); | void handleKeyPress(int keyCode, rdr::U32 keySym); | ||||
void handleKeyRelease(int keyCode); | void handleKeyRelease(int keyCode); | ||||
bool cocoa_win_is_zoomed(Fl_Window *win); | bool cocoa_win_is_zoomed(Fl_Window *win); | ||||
void cocoa_win_zoom(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_keyboard_event(const void *event); | ||||
int cocoa_is_key_press(const void *event); | int cocoa_is_key_press(const void *event); |
[nsw zoom:nsw]; | [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) | int cocoa_is_keyboard_event(const void *event) | ||||
{ | { | ||||
NSEvent *nsevent; | NSEvent *nsevent; | ||||
case NSKeyDown: | case NSKeyDown: | ||||
case NSKeyUp: | case NSKeyUp: | ||||
case NSFlagsChanged: | case NSFlagsChanged: | ||||
if (cocoa_is_keyboard_sync(event)) | |||||
return 0; | |||||
return 1; | return 1; | ||||
default: | default: | ||||
return 0; | return 0; |