Skip to content

Commit 88b441e

Browse files
committed
Add 'screenshot permission' to the accessibility prompt
1 parent df492a6 commit 88b441e

File tree

7 files changed

+135
-29
lines changed

7 files changed

+135
-29
lines changed

Quicksilver/Code-App/QSController.h

+4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
IBOutlet NSButton *fullDiskButton;
2222
IBOutlet NSButton *contactsButton;
2323
IBOutlet NSButton *calendarsButton;
24+
IBOutlet NSButton *screenshotButton;
2425
IBOutlet NSButton *closeAccessibilityWindowButton;
26+
BOOL hasClickedScreenshotButton;
27+
BOOL hasScreenshotPermissionOnStartup;
28+
2529

2630
NSTimer *accessibilityChecker;
2731
}

Quicksilver/Code-App/QSController.m

+27-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#import "QSScreenshots.h"
1515
#import "QSDonationController.h"
1616

17-
1817
#import "QSIntValueTransformer.h"
1918

2019
#import <PermissionsKit/PermissionsKit.h>
@@ -28,6 +27,7 @@ - (void)handleURL:(NSURL *)url;
2827

2928
static QSController *defaultController = nil;
3029

30+
3131
@implementation QSController
3232

3333
@synthesize crashReportPath;
@@ -834,23 +834,36 @@ -(void)checkForAccessibilityPermission {
834834
}
835835

836836
- (void)checkAccessibilityPermissions {
837+
[accessibilityPermissionWindow setLevel:NSNormalWindowLevel];
838+
837839
// Prompt for accessibility permissions on macOS Mojave and later.
838840
BOOL hasAccessibility = [self hasAccessibilityPermission];
839841
BOOL hasFullDisk = [MPPermissionsKit authorizationStatusForPermissionType:MPPermissionTypeFullDiskAccess] == MPAuthorizationStatusAuthorized;
840842
BOOL hasContacts = [MPPermissionsKit authorizationStatusForPermissionType:MPPermissionTypeContacts] == MPAuthorizationStatusAuthorized;
841843
BOOL hasCalendars = [MPPermissionsKit authorizationStatusForPermissionType:MPPermissionTypeCalendar] == MPAuthorizationStatusAuthorized;
842844
BOOL hasReminders = [MPPermissionsKit authorizationStatusForPermissionType:MPPermissionTypeReminders] == MPAuthorizationStatusAuthorized;
845+
846+
BOOL hasScreenshot;
847+
if (hasScreenshotPermissionOnStartup) {
848+
hasScreenshot = YES;
849+
} else {
850+
// only call this if the user has actually clicked the screenshot button
851+
// this is a kind of hack, since the API for detecting if screenshot permission is enabled is buggy
852+
hasScreenshot = hasClickedScreenshotButton;
853+
}
854+
843855
[accessibilityButton setEnabled:!hasAccessibility];
844856
[fullDiskButton setEnabled:!hasFullDisk];
845857
[contactsButton setEnabled:!hasContacts];
846858
[calendarsButton setEnabled:!hasCalendars || !hasReminders];
859+
[screenshotButton setEnabled:!hasScreenshot];
847860

848861
[closeAccessibilityWindowButton setEnabled:(hasAccessibility && hasFullDisk)];
849862

850863
if (hasAccessibility && hasFullDisk && hasCalendars && hasContacts && hasReminders) {
851864
[accessibilityPermissionWindow close];
852865
} else if (!accessibilityChecker) {
853-
accessibilityChecker = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
866+
accessibilityChecker = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
854867
[self checkAccessibilityPermissions];
855868
}];
856869
[[NSRunLoop currentRunLoop] addTimer:accessibilityChecker forMode:NSModalPanelRunLoopMode];
@@ -860,11 +873,16 @@ - (void)checkAccessibilityPermissions {
860873
-(IBAction)showAccessibilityPrompt:(id)sender {
861874
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeAccessibilityPrompt:) name:NSWindowWillCloseNotification object:accessibilityPermissionWindow];
862875
[closeAccessibilityWindowButton setEnabled:NO];
863-
864876
[accessibilityPermissionWindow setIsVisible:YES];
877+
hasClickedScreenshotButton = NO;
878+
if (@available(macOS 10.15, *)) {
879+
hasScreenshotPermissionOnStartup = CGPreflightScreenCaptureAccess();
880+
} else {
881+
// below 10.15, no need to give permissions
882+
hasScreenshotPermissionOnStartup = YES;
883+
}
865884
[self checkAccessibilityPermissions];
866885
[NSApp runModalForWindow:accessibilityPermissionWindow];
867-
868886
}
869887

870888
- (IBAction)closeAccessibilityPrompt:(NSNotification *)notif {
@@ -892,7 +910,11 @@ -(IBAction)launchPrivacyPreferences:(id)sender {
892910
[MPPermissionsKit requestAuthorizationForPermissionType:MPPermissionTypeReminders withCompletion:^(MPAuthorizationStatus status) {
893911
}];
894912
}];
895-
913+
} else if (sender == screenshotButton) {
914+
hasClickedScreenshotButton = YES;
915+
if (@available(macOS 10.15, *)) {
916+
CGRequestScreenCaptureAccess();
917+
}
896918
} else {
897919
[accessibilityPermissionWindow close];
898920
}

Quicksilver/Code-QuickStepCore/QSPlugIn.m

+4-2
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,10 @@ - (BOOL)_registerPlugIn {
721721
#endif
722722

723723
[QSReg registerBundle:bundle];
724-
724+
NSLog(@"%@", [self name]);
725+
if ([[self name] isEqualToString:@"Screen Capture Plugin - Private"]) {
726+
NSLog(@"A");
727+
}
725728
if ([[bundle objectForInfoDictionaryKey:@"NSAppleScriptEnabled"] boolValue])
726729
[[NSScriptSuiteRegistry sharedScriptSuiteRegistry] loadSuitesFromBundle:bundle];
727730

@@ -748,7 +751,6 @@ - (BOOL)_registerPlugIn {
748751
#ifdef DEBUG
749752
if (DEBUG_PLUGINS) NSLog(@"Forcing Load of Class %@", currPrincipalClass);
750753
#endif
751-
752754
if ([currPrincipalClass respondsToSelector:@selector(loadPlugIn)])
753755
[currPrincipalClass loadPlugIn];
754756
}

Quicksilver/Code-QuickStepFoundation/NSScreen_BLTRExtensions.h

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#import <Cocoa/Cocoa.h>
1010

1111
@interface NSScreen (BLTRExtensions)
12+
+ (BOOL)screenRecordingPermissionAllowed;
1213
+ (NSScreen *)screenWithNumber:(NSInteger)number;
1314
- (NSInteger) screenNumber;
1415
- (NSString *)deviceName;

Quicksilver/Code-QuickStepFoundation/NSScreen_BLTRExtensions.m

+39
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,48 @@
1414
#include <IOKit/graphics/IOGraphicsTypes.h>
1515
#include <ApplicationServices/ApplicationServices.h>
1616
#include <objc/objc-runtime.h>
17+
#import <CoreGraphics/CGDisplayStream.h>
1718

1819
@implementation NSScreen (BLTRExtensions)
1920

21+
+ (BOOL)screenRecordingPermissionAllowed {
22+
if ([[NSScreen mainScreen] hasScreenRecordingPermission]) {
23+
return YES;
24+
}
25+
// maybe the main screen can't produce a CGDisplayStream, but another screen can
26+
// a positive on any screen must mean that the permission is granted; we try on the other screens
27+
for (NSScreen *screen in [NSScreen screens]) {
28+
if ([screen screenNumber] == [[NSScreen mainScreen] screenNumber]) {
29+
continue;
30+
}
31+
if ([screen hasScreenRecordingPermission]) {
32+
return YES;
33+
}
34+
}
35+
return NO;
36+
}
37+
38+
- (BOOL)hasScreenRecordingPermission {
39+
CGDirectDisplayID displayId = (CGDirectDisplayID)[self screenNumber];
40+
41+
CGDisplayStreamRef ref = CGDisplayStreamCreateWithDispatchQueue(
42+
displayId,
43+
1,
44+
1,
45+
kCVPixelFormatType_32BGRA,
46+
nil,
47+
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
48+
^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
49+
NSLog(@"Next Frame"); // This line is never called.
50+
});
51+
52+
BOOL hasPermission = (ref != nil);
53+
if (ref != nil) {
54+
CFRelease(ref);
55+
}
56+
return hasPermission;
57+
}
58+
2059
+ (NSScreen *)screenWithNumber:(NSInteger)number {
2160
for(NSScreen *screen in [self screens]) {
2261
if ([screen screenNumber] == number) {

0 commit comments

Comments
 (0)