From c0f6966ddfdf29ea7f80bbf030946671cd0136f1 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 | 39 ++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/Library/SRShortcutAction.m b/Library/SRShortcutAction.m index 6de4b5ea..62a474a5 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,32 @@ - (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; + + // Each modifier flag is "1" in the binary representation. + __auto_type numberOfChangedFlags = __builtin_popcountll(addedModifierFlags) + __builtin_popcountll(removedModifierFlags); + + if (numberOfChangedFlags != 1) + { + os_trace("#Error Ambigious flags changed event: default to SRKeyEventTypeDown"); + eventType = addedModifierFlags != 0 ? SRKeyEventTypeDown : SRKeyEventTypeUp; + } + else if (addedModifierFlags) + eventType = SRKeyEventTypeDown; + else if (removedModifierFlags) + eventType = SRKeyEventTypeUp; + } + else + eventType = nsEvent.SR_keyEventType; + + _lastSeenModifierFlags = nsEvent.modifierFlags & SRCocoaModifierFlagsMask; __auto_type actions = [self enabledActionsForShortcut:shortcut keyEvent:eventType]; __block BOOL isHandled = NO; @@ -1577,11 +1604,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)