Skip to content

Commit

Permalink
SRAXGlobalShortcutMonitor defaults to kCGEventTapOptionListenOnly.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kentzo committed May 12, 2020
1 parent de14cf7 commit ae35edd
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 5 deletions.
21 changes: 17 additions & 4 deletions Library/SRShortcutAction.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,15 +380,17 @@ NS_SWIFT_NAME(GlobalShortcutMonitor)
Handle shortcuts regardless of the currently active application via Quartz Event Service API.
@discussion
Unlike SRGlobalShortcutMonitor it can handle shortcuts with the SRKeyCodeNone key code. But it has
security implications as this API requires the app to either run under the root user or been allowed
Unlike SRGlobalShortcutMonitor it can handle modifier-falgs-only shortcuts with the SRKeyCodeNone key code.
But it has security implications as this API requires the app to either run under the root user or been allowed
the Accessibility permission.
The monitor automatically enables and disables the tap when needed.
@see SRGlobalShortcutMonitor
@see AXIsProcessTrustedWithOptions
@see IOHIDCheckAccess
@see NSAppleEventsUsageDescription
@see https://developer.apple.com/videos/play/wwdc2019/701/
*/
@interface SRAXGlobalShortcutMonitor : SRShortcutMonitor

Expand All @@ -412,22 +414,31 @@ NS_SWIFT_NAME(GlobalShortcutMonitor)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnullability"
/*!
Initialize the monitor by installing the event tap in the current run loop.
Initialize the monitor by installing the event tap in the current run loop for listening only.
*/
- (nullable instancetype)init;
#pragma clang diagnostic pop

/*!
Initialize the monitor by installing the event tap in a given loop for listening only.
*/
- (nullable instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop;

/*!
Initialize the monitor by installing the event tap in a given run loop.
@param aRunLoop Run loop for the event tap.
@param aTapOptions Tap options determine whether the monitor is an active filter or a passive listener.
@discussion
Initialization may fail if it's impossible to create the event tap.
Tap options control whether the event handler can actively filter and modify the events
@see https://stackoverflow.com/q/52738506/188530
*/
- (nullable instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop tapOptions:(CGEventTapOptions)aTapOptions NS_DESIGNATED_INITIALIZER;

/*!
Perform the action associated with a given event.
Expand All @@ -439,6 +450,8 @@ NS_SWIFT_NAME(GlobalShortcutMonitor)
@discussion
If there is more than one action associated with the event, they are performed one by one
either until one of them returns YES or the iteration is exhausted.
@note In order to filter (by returning nil) and modify events, the monitor must be initialized with kCGEventTapOptionDefault.
*/
- (nullable CGEventRef)handleEvent:(CGEventRef)anEvent;

Expand Down
14 changes: 13 additions & 1 deletion Library/SRShortcutAction.m
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,9 @@ - (void)willRemoveShortcut:(SRShortcut *)aShortcut


@implementation SRAXGlobalShortcutMonitor
{
BOOL _canActivelyFilterEvents;
}

CGEventRef _Nullable _SRQuartzEventHandler(CGEventTapProxy aProxy, CGEventType aType, CGEventRef anEvent, void * _Nullable aUserInfo)
{
Expand All @@ -1287,13 +1290,18 @@ - (instancetype)init
}

- (instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop
{
return [self initWithRunLoop:aRunLoop tapOptions:kCGEventTapOptionListenOnly];
}

- (instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop tapOptions:(CGEventTapOptions)aTapOptions
{
static const CGEventMask Mask = (CGEventMaskBit(kCGEventKeyDown) |
CGEventMaskBit(kCGEventKeyUp) |
CGEventMaskBit(kCGEventFlagsChanged));
__auto_type eventTap = CGEventTapCreate(kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
aTapOptions,
Mask,
_SRQuartzEventHandler,
(__bridge void *)self);
Expand All @@ -1309,6 +1317,7 @@ - (instancetype)initWithRunLoop:(NSRunLoop *)aRunLoop
{
_eventTap = eventTap;
_eventTapSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
_canActivelyFilterEvents = (aTapOptions & kCGEventTapOptionListenOnly) == 0;
CFRunLoopAddSource(aRunLoop.getCFRunLoop, _eventTapSource, kCFRunLoopDefaultMode);
}

Expand Down Expand Up @@ -1359,6 +1368,9 @@ - (CGEventRef)handleEvent:(CGEventRef)anEvent
result = isHandled ? nil : anEvent;
});

if (!result && !_canActivelyFilterEvents)
os_trace_error("#Developer #Error The monitor is not configured to actively filter events");

return result;
}

Expand Down

0 comments on commit ae35edd

Please sign in to comment.