11// Copyright (c) 2009 Stephen Deken
2- // Copyright (c) 2014-2023 Andrew Kitchen
2+ // Copyright (c) 2014-2024 Andrew Kitchen
33//
44// All rights reserved.
55//
2626// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2727// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828
29+ #if !__has_feature(objc_arc)
30+ #error "ARC is required for this file -- enable with -fobjc-arc"
31+ #endif
2932
3033#import " KCEventTap.h"
3134#import " KCKeystroke.h"
3235#import " KCKeycastrEvent.h"
3336#import " KCMouseEvent.h"
3437
3538@interface KCEventTap () {
36- CFMachPortRef eventTap;
37- CFRunLoopRef eventTapRunLoop;
38- CFRunLoopSourceRef eventTapEventSource;
39+ CFMachPortRef keyEventTap;
40+ CFMachPortRef mouseAndFlagsEventTap;
41+ CFRunLoopSourceRef keyEventTapSource;
42+ CFRunLoopSourceRef mouseAndFlagsEventTapSource;
3943}
4044
4145- (void )_noteMouseEvent : (CGEventRef)eventRef ;
@@ -44,22 +48,33 @@ - (void)_noteFlagsChanged:(CGEventRef)event;
4448
4549@end
4650
47- CGEventRef nullEventTapCallback (
51+ CGEventRef keyEventTapCallback (
4852 CGEventTapProxy proxy,
4953 CGEventType type,
5054 CGEventRef event,
51- void *vp )
55+ void *context )
5256{
53- return NULL ;
57+ KCEventTap *eventTap = (__bridge KCEventTap *)context;
58+ switch (type)
59+ {
60+ case kCGEventKeyDown :
61+ [eventTap _noteKeyEvent: event];
62+ break ;
63+ case kCGEventKeyUp :
64+ break ;
65+ default :
66+ break ;
67+ }
68+ return event;
5469}
5570
56- CGEventRef eventTapCallback (
71+ CGEventRef mouseAndFlagsEventTapCallback (
5772 CGEventTapProxy proxy,
5873 CGEventType type,
5974 CGEventRef event,
60- void *vp )
75+ void *context )
6176{
62- KCEventTap* keyTap = (KCEventTap*)vp ;
77+ KCEventTap *eventTap = (__bridge KCEventTap *)context ;
6378 switch (type)
6479 {
6580 case kCGEventLeftMouseDown :
@@ -71,24 +86,19 @@ CGEventRef eventTapCallback(
7186 case kCGEventOtherMouseDown :
7287 case kCGEventOtherMouseUp :
7388 case kCGEventOtherMouseDragged :
74- [keyTap _noteMouseEvent: event];
75- break ;
76- case kCGEventKeyDown :
77- [keyTap _noteKeyEvent: event];
89+ [eventTap _noteMouseEvent: event];
7890 break ;
7991 case kCGEventFlagsChanged :
80- [keyTap _noteFlagsChanged: event];
92+ [eventTap _noteFlagsChanged: event];
8193 break ;
8294 default :
8395 break ;
8496 }
85- return NULL ;
97+ return event ;
8698}
8799
88100@implementation KCEventTap
89101
90- @synthesize delegate = _delegate;
91-
92102-(id ) init
93103{
94104 if (!(self = [super init ]))
@@ -101,8 +111,6 @@ - (void)dealloc {
101111 if (_tapInstalled) {
102112 [self removeTap ];
103113 }
104-
105- [super dealloc ];
106114}
107115
108116-(NSError *) constructErrorWithDescription : (NSString *)description {
@@ -121,69 +129,52 @@ -(BOOL) installTapWithError:(NSError **)error {
121129 // We have to try to tap the keydown event independently because CGEventTapCreate will succeed if it can
122130 // install the event tap for the flags changed event, which apparently doesn't require universal access
123131 // to be enabled. Thus, the call would succeed but KeyCastr would be, um, useless.
124- CFMachPortRef tapKeyDown = CGEventTapCreate (
125- kCGSessionEventTap ,
126- kCGHeadInsertEventTap ,
127- kCGEventTapOptionListenOnly ,
128- CGEventMaskBit (kCGEventKeyDown ),
129- nullEventTapCallback,
130- self
131- );
132-
133- if (tapKeyDown == NULL ) {
134- if (error != NULL ) {
135- *error = [self constructErrorWithDescription: @" Could not create keyDown event tap!" ];
136- }
137- return NO ;
138- }
139- CFRelease ( tapKeyDown );
140-
141- eventTap = CGEventTapCreate (
142- kCGSessionEventTap ,
143- kCGHeadInsertEventTap ,
144- kCGEventTapOptionListenOnly ,
145- CGEventMaskBit (kCGEventLeftMouseDown )
146- | CGEventMaskBit (kCGEventLeftMouseUp )
147- | CGEventMaskBit (kCGEventRightMouseDown )
148- | CGEventMaskBit (kCGEventRightMouseUp )
149- | CGEventMaskBit (kCGEventLeftMouseDragged )
150- | CGEventMaskBit (kCGEventRightMouseDragged )
151- | CGEventMaskBit (kCGEventKeyDown )
152- | CGEventMaskBit (kCGEventFlagsChanged )
153- | CGEventMaskBit (kCGEventOtherMouseDown )
154- | CGEventMaskBit (kCGEventOtherMouseUp )
155- | CGEventMaskBit (kCGEventOtherMouseDragged ),
156- eventTapCallback,
157- self
158- );
159-
160- if (eventTap == NULL ) {
132+ keyEventTap = CGEventTapCreate (kCGSessionEventTap ,
133+ kCGHeadInsertEventTap ,
134+ kCGEventTapOptionListenOnly ,
135+ CGEventMaskBit (kCGEventKeyDown )
136+ | CGEventMaskBit (kCGEventKeyUp ),
137+ keyEventTapCallback,
138+ (__bridge void *)self
139+ );
140+
141+ if (keyEventTap == NULL ) {
161142 if (error != NULL ) {
162- *error = [self constructErrorWithDescription: @" Could not create keyDown|flagsChanged event tap!" ];
143+ *error = [self constructErrorWithDescription: @" Could not create key event tap! Permissions needed... " ];
163144 }
164145 return NO ;
165146 }
166147
167- eventTapEventSource = CFMachPortCreateRunLoopSource (NULL , eventTap, 0 );
168- if (eventTapEventSource == NULL ) {
169- CFRelease (eventTap);
170- if (error != NULL ) {
171- *error = [self constructErrorWithDescription: @" Could not create run loop source!" ];
172- }
173- return NO ;
174- }
148+ mouseAndFlagsEventTap = CGEventTapCreate (kCGSessionEventTap ,
149+ kCGHeadInsertEventTap ,
150+ kCGEventTapOptionListenOnly ,
151+ CGEventMaskBit (kCGEventLeftMouseDown )
152+ | CGEventMaskBit (kCGEventLeftMouseUp )
153+ | CGEventMaskBit (kCGEventRightMouseDown )
154+ | CGEventMaskBit (kCGEventRightMouseUp )
155+ | CGEventMaskBit (kCGEventLeftMouseDragged )
156+ | CGEventMaskBit (kCGEventRightMouseDragged )
157+ | CGEventMaskBit (kCGEventFlagsChanged )
158+ | CGEventMaskBit (kCGEventOtherMouseDown )
159+ | CGEventMaskBit (kCGEventOtherMouseUp )
160+ | CGEventMaskBit (kCGEventOtherMouseDragged ),
161+ mouseAndFlagsEventTapCallback,
162+ (__bridge void *)self
163+ );
175164
176- eventTapRunLoop = CFRunLoopGetCurrent ();
177- if (eventTapRunLoop == NULL ) {
178- CFRelease (eventTapEventSource);
179- CFRelease (eventTap);
165+ if (mouseAndFlagsEventTap == NULL ) {
180166 if (error != NULL ) {
181- *error = [self constructErrorWithDescription: @" Could not get current run loop !" ];
167+ *error = [self constructErrorWithDescription: @" Could not create mouse and modifiers event tap !" ];
182168 }
183169 return NO ;
184170 }
185171
186- CFRunLoopAddSource (eventTapRunLoop, eventTapEventSource, kCFRunLoopDefaultMode );
172+ keyEventTapSource = CFMachPortCreateRunLoopSource (NULL , keyEventTap, 0 );
173+ mouseAndFlagsEventTapSource = CFMachPortCreateRunLoopSource (NULL , mouseAndFlagsEventTap, 0 );
174+
175+ CFRunLoopRef runLoop = CFRunLoopGetCurrent ();
176+ CFRunLoopAddSource (runLoop, keyEventTapSource, kCFRunLoopDefaultMode );
177+ CFRunLoopAddSource (runLoop, mouseAndFlagsEventTapSource, kCFRunLoopDefaultMode );
187178
188179 _tapInstalled = YES ;
189180
@@ -194,10 +185,15 @@ -(void) removeTap {
194185 if (!_tapInstalled) {
195186 return ;
196187 }
197-
198- CFRunLoopRemoveSource (eventTapRunLoop, eventTapEventSource, kCFRunLoopDefaultMode );
199- CFRelease (eventTapEventSource);
200- CFRelease (eventTap);
188+
189+ CFRunLoopSourceInvalidate (keyEventTapSource);
190+ CFRunLoopSourceInvalidate (mouseAndFlagsEventTapSource);
191+
192+ CFRelease (keyEventTapSource);
193+ CFRelease (mouseAndFlagsEventTapSource);
194+
195+ CFRelease (keyEventTap);
196+ CFRelease (mouseAndFlagsEventTap);
201197
202198 _tapInstalled = NO ;
203199}
0 commit comments