From 8885ff55b9779be18c6730ae956b9ce6b3c3c52e Mon Sep 17 00:00:00 2001 From: Aaron Kollasch Date: Sat, 27 Nov 2021 01:27:39 -0500 Subject: [PATCH 1/2] Fix UI freeze if permissions disabled while running After a delay, the OS will detect the CGEventTap has timed out and will send a kCGEventTapDisabledByTimeout event. This event will now trigger an exit(). --- jitouch/Jitouch/Gesture.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jitouch/Jitouch/Gesture.m b/jitouch/Jitouch/Gesture.m index 9f39258..bb524d1 100644 --- a/jitouch/Jitouch/Gesture.m +++ b/jitouch/Jitouch/Gesture.m @@ -2814,8 +2814,11 @@ static CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEve CGEventSetIntegerValueField(event, kCGMouseEventButtonNumber, 2); CGEventSetType(event, kCGEventOtherMouseDragged); } - } else if (type == kCGEventTapDisabledByUserInput || type == kCGEventTapDisabledByTimeout) { + } else if (type == kCGEventTapDisabledByUserInput) { CGEventTapEnable(eventTap, true); + } else if (type == kCGEventTapDisabledByTimeout) { + NSLog(@"kCGEventTapDisabledByTimeout; exiting."); + exit(1); } From 01152f0c9d1c97394889d96bc261f6eafbc36d7b Mon Sep 17 00:00:00 2001 From: Aaron Kollasch Date: Sat, 27 Nov 2021 03:50:58 -0500 Subject: [PATCH 2/2] Improve handling of kCGEventTapDisabledByTimeout CGEventCallback will attempt to recreate the CGEventTap --- jitouch/Jitouch/Gesture.m | 85 ++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 23 deletions(-) diff --git a/jitouch/Jitouch/Gesture.m b/jitouch/Jitouch/Gesture.m index bb524d1..1d549bd 100644 --- a/jitouch/Jitouch/Gesture.m +++ b/jitouch/Jitouch/Gesture.m @@ -2817,8 +2817,23 @@ static CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEve } else if (type == kCGEventTapDisabledByUserInput) { CGEventTapEnable(eventTap, true); } else if (type == kCGEventTapDisabledByTimeout) { - NSLog(@"kCGEventTapDisabledByTimeout; exiting."); - exit(1); + NSLog(@"Received kCGEventTapDisabledByTimeout; attempting to recreate CGEventTap. Allow Jitouch in System Preferences -> Privacy -> Accessibility."); + CFMachPortInvalidate(eventTap); + CFRelease(eventTap); + CFMachPortRef newEventTap = nil; + int i = 0; + while (newEventTap == nil) { + if (i > 360) { + NSLog(@"Could not create CGEventTap"); + exit(1); + } + sleep(1); + newEventTap = [me createEventTap]; + i++; + } + NSLog(@"CGEventTap created"); + eventTap = newEventTap; + return NULL; } @@ -2895,6 +2910,34 @@ static CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEve return event; } +- (CFMachPortRef)createEventTap { + CGEventMask eventMask; + CFRunLoopSourceRef runLoopSource; + + eventMask = CGEventMaskBit(kCGEventScrollWheel) | + CGEventMaskBit(kCGEventMouseMoved) | + CGEventMaskBit(kCGEventLeftMouseDown) | + CGEventMaskBit(kCGEventLeftMouseUp) | + CGEventMaskBit(kCGEventRightMouseDown) | + CGEventMaskBit(kCGEventRightMouseUp) | + CGEventMaskBit(kCGEventOtherMouseDown) | + CGEventMaskBit(kCGEventOtherMouseUp) | + CGEventMaskBit(kCGEventLeftMouseDragged) | + CGEventMaskBit(kCGEventRightMouseDragged) | + CGEventMaskBit(kCGEventOtherMouseDragged); + //CGEventMaskBit(kCGEventKeyUp) | + //CGEventMaskBit(kCGEventKeyDown); + CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, CGEventCallback, NULL); + + if (eventTap != nil) { + CGEventTapEnable(eventTap, true); + runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); + CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopCommonModes); + } + + return eventTap; +} + #pragma mark - Init - (id)init { @@ -2981,27 +3024,23 @@ - (id)init { magicTrackpadRemoved(NULL, magicTrackpadRemovedIterator); } - CGEventMask eventMask; - CFRunLoopSourceRef runLoopSource; - - eventMask = CGEventMaskBit(kCGEventScrollWheel) | - CGEventMaskBit(kCGEventMouseMoved) | - CGEventMaskBit(kCGEventLeftMouseDown) | - CGEventMaskBit(kCGEventLeftMouseUp) | - CGEventMaskBit(kCGEventRightMouseDown) | - CGEventMaskBit(kCGEventRightMouseUp) | - CGEventMaskBit(kCGEventOtherMouseDown) | - CGEventMaskBit(kCGEventOtherMouseUp) | - CGEventMaskBit(kCGEventLeftMouseDragged) | - CGEventMaskBit(kCGEventRightMouseDragged) | - CGEventMaskBit(kCGEventOtherMouseDragged); - //CGEventMaskBit(kCGEventKeyUp) | - //CGEventMaskBit(kCGEventKeyDown); - eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, CGEventCallback, NULL); - - CGEventTapEnable(eventTap, true); - runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); - CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopCommonModes); + eventTap = [me createEventTap]; + if (eventTap == nil) { + NSLog(@"Could not create CGEventTap. Allow Jitouch in System Preferences -> Privacy -> Accessibility."); + CFMachPortRef newEventTap = nil; + int i = 0; + while (newEventTap == nil) { + if (i > 360) { + NSLog(@"Could not create CGEventTap"); + exit(1); + } + sleep(1); + newEventTap = [me createEventTap]; + i++; + } + NSLog(@"CGEventTap created"); + eventTap = newEventTap; + } gestureWindow = [[GestureWindow alloc] init]; sizeHistoryDict = [[NSMutableDictionary alloc] init];