From 717c598b2b7ed064d04163000aee8644d201c7df Mon Sep 17 00:00:00 2001 From: Ilya Kulakov Date: Thu, 25 Jun 2020 00:11:35 +0600 Subject: [PATCH] SRShortcutAction: Try to recover type of the NSEventTypeFlagsChanged event when keyCode is incorrect SRAXGlobalShortcutMonitor intercepts all keyboard events which allows to track changes of the modifier flags more or less reliably and thus diff previous and current values. Refs #129 --- Library/SRShortcutAction.m | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/Library/SRShortcutAction.m b/Library/SRShortcutAction.m index 6de4b5ea..458529ac 100644 --- a/Library/SRShortcutAction.m +++ b/Library/SRShortcutAction.m @@ -6,6 +6,7 @@ #import #import #import +#import #import "SRShortcutAction.h" #import "SRCommon.h" @@ -1265,6 +1266,7 @@ - (void)willRemoveShortcut:(SRShortcut *)aShortcut @implementation SRAXGlobalShortcutMonitor { BOOL _canActivelyFilterEvents; + _Atomic(NSEventModifierFlags) _lastSeenModifierFlags; } CGEventRef _Nullable _SRQuartzEventHandler(CGEventTapProxy aProxy, CGEventType aType, CGEventRef anEvent, void * _Nullable aUserInfo) @@ -1298,6 +1300,8 @@ - (instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop - (instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop tapOptions:(CGEventTapOptions)aTapOptions { + _lastSeenModifierFlags = ATOMIC_VAR_INIT(0); + static const CGEventMask Mask = (CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp) | CGEventMaskBit(kCGEventFlagsChanged)); @@ -1356,9 +1360,31 @@ - (CGEventRef)handleEvent:(CGEventRef)anEvent return; } - SRKeyEventType eventType = nsEvent.SR_keyEventType; - if (eventType == 0) - return; + SRKeyEventType eventType = 0; + + if (nsEvent.type == NSEventTypeFlagsChanged && nsEvent.keyCode == 0) + { + os_trace("#Error Flags changed event without a key code"); + __auto_type currentModifierFlags = nsEvent.modifierFlags & SRCocoaModifierFlagsMask; + __auto_type addedModifierFlags = currentModifierFlags & ~_lastSeenModifierFlags; + __auto_type removedModifierFlags = _lastSeenModifierFlags & ~currentModifierFlags; + + int numberOfChangedFlags = __builtin_popcount(addedModifierFlags) + __builtin_popcount(removedModifierFlags); + + if (numberOfChangedFlags != 1) + { + os_trace("#Error Ambigious flags changed event: default to SRKeyEventTypeDown"); + eventType = SRKeyEventTypeDown; + } + else if (addedModifierFlags) + eventType = SRKeyEventTypeDown; + else if (removedModifierFlags) + eventType = SRKeyEventTypeUp; + } + else + eventType = nsEvent.SR_keyEventType; + + _lastSeenModifierFlags = nsEvent.modifierFlags; __auto_type actions = [self enabledActionsForShortcut:shortcut keyEvent:eventType]; __block BOOL isHandled = NO; @@ -1577,11 +1603,7 @@ - (BOOL)handleEvent:(NSEvent *)anEvent withTarget:(nullable id)aTarget return NO; } - SRKeyEventType eventType = anEvent.SR_keyEventType; - if (eventType == 0) - return NO; - - __auto_type actions = [self enabledActionsForShortcut:shortcut keyEvent:eventType]; + __auto_type actions = [self enabledActionsForShortcut:shortcut keyEvent:anEvent.SR_keyEventType]; __block BOOL isHandled = NO; [actions enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SRShortcutAction *obj, NSUInteger idx, BOOL *stop)