diff --git a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m index 057f401cbe4..89e63388523 100644 --- a/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m +++ b/mac/Keyman4MacIM/Keyman4MacIM/Privacy/PrivacyConsent.m @@ -1,4 +1,4 @@ -/** +/* * Keyman is copyright (C) SIL International. MIT License. * * PrivacyConsent.m @@ -7,8 +7,8 @@ * Created by Shawn Schantz on 2022-09-22. * * Used to determine if the user has provided consent to the services it needs - * and, if not, to request that consent. For versions of macOS prior to 10.15, - * Keyman requires Accessibility access. For 10.15 and later, Keyman requires + * and, if not, to request that consent. For versions of macOS prior to 11.0, + * Keyman requires Accessibility access. For 11.0 and later, Keyman requires * PostEvent access. Both are presented to the user as a need for Accessibility * when prompted by the system and are listed under Accessibility in the Privacy * tab in System Preferences, Security & Privacy. Both Accessibility and @@ -16,7 +16,11 @@ * that access is not explicitly needed as long as one of the others is provided * first. * - * Access this functionality through the shared instance. Call + * Note that Apple's documentation states that the PostEvent access APIs are + * available with macOS 10.15 (Catalina) but testing showed that it was only + * available with macOS 11.0 (Big Sur). This is documented with issue #12295. + * + * To access this functionality, used the shared instance. Call * requestPrivacyAccess which will check whether access has been granted. If * not, then a dialog will be presented to the user to inform them that * Accessibility is required. Dismissing this dialog will trigger the API call @@ -24,7 +28,7 @@ * only happen once. If the user was prompted earlier and did not grant access, * they can still go to System Preferences and enable it there. So it is useful * to prompt with a dialog from Keyman at startup. Without Accessibility, the - * shift layer and the OSK do not work -- so Keyman is basically useless. + * shift layer and the OSK do not work. */ #import "PrivacyConsent.h" @@ -43,7 +47,7 @@ + (PrivacyConsent *)shared } /** - * For macOS earlier than 10.15: check for Accessibility access. + * For macOS earlier than 11.0: check for Accessibility access. */ - (BOOL)checkAccessibility { @@ -66,7 +70,7 @@ - (void)requestPrivacyAccess:(void (^)(void))withCompletionHandler BOOL hasAccessibility = NO; // check if we already have accessibility - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { hasAccessibility = [self checkPostEventAccess]; } else { hasAccessibility = [self checkAccessibility]; @@ -85,7 +89,7 @@ - (void)requestPrivacyAccess:(void (^)(void))withCompletionHandler } /** - * For macOS earlier than 10.15: request Accessibility access. + * For macOS earlier than 11.0: request Accessibility access. */ - (void)requestAccessibility { @@ -113,18 +117,18 @@ - (NSWindowController *)privacyDialog { */ - (void)configureDialogForOsVersion { - if (@available(macOS 10.15, *)) { - [self configureDialogForCatalinaAndLater]; + if (@available(macOS 11.0, *)) { + [self configureDialogForBigSurAndLater]; } else { - [self configureDialogForPreCatalina]; + [self configureDialogForPreBigSur]; } } /** - * Initialize privacy dialog for macOS versions prior to Catalina (10.15). + * Initialize privacy dialog for macOS versions prior to Big Sur (11.0). * In this case, request Accessibility access, not PostEvent. */ -- (void)configureDialogForPreCatalina { +- (void)configureDialogForPreBigSur { void (^consentPrompt)(void) = ^(void) { [self requestAccessibility]; @@ -136,10 +140,10 @@ - (void)configureDialogForPreCatalina { } /** - * Initialize privacy dialog for macOS versions of Catalina (10.15) or later. + * Initialize privacy dialog for macOS versions of Big Sur (11.0) or later. * In this case, request PostEvent access, not Accessibility. */ -- (void)configureDialogForCatalinaAndLater { +- (void)configureDialogForBigSurAndLater { void (^consentPrompt)(void) = ^(void) { [self requestPostEventAccess]; @@ -160,7 +164,7 @@ - (void)showPrivacyDialog { /** * Check whether the user has allowed ListenEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. * * If user has granted Accessibility or PostEvent access, then * ListenEvent access is also granted. @@ -170,18 +174,18 @@ - (BOOL)checkListenEventAccess BOOL hasAccess = NO; // below checks for ListenEvent access - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { hasAccess = CGPreflightListenEventAccess(); os_log([KMLogs privacyLog], "CGPreflightListenEventAccess() returned %@", hasAccess ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGPreflightListenEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGPreflightListenEventAccess not available before macOS version 11.0"); } return hasAccess; } /** * Check whether the user has allowed PostEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. * * If user has granted Accessibility, then PostEvent access is also granted. */ @@ -190,46 +194,46 @@ - (BOOL)checkPostEventAccess BOOL hasAccess = NO; // below checks for PostEvent access - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { hasAccess = CGPreflightPostEventAccess(); os_log([KMLogs privacyLog], "CGPreflightPostEventAccess() returned %@", hasAccess ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGPreflightPostEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGPreflightPostEventAccess not available before macOS version 11.0"); } return hasAccess; } /** * Request ListenEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. */ - (BOOL)requestListenEventAccess { BOOL granted = NO; - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { granted = CGRequestListenEventAccess(); os_log([KMLogs privacyLog], "CGRequestListenEventAccess() returned %@", granted ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGRequestListenEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGRequestListenEventAccess not available before macOS version 11.0"); } return granted; } /** * Request PostEvent access. - * Only available with macOS Catalina (10.15) or later. + * Only available with macOS Big Sur (11.0) or later. */ - (BOOL)requestPostEventAccess { BOOL granted = NO; - if (@available(macOS 10.15, *)) { + if (@available(macOS 11.0, *)) { granted = CGRequestPostEventAccess(); os_log([KMLogs privacyLog], "CGRequestPostEventAccess() returned %@", granted ? @"YES" : @"NO"); } else { - os_log([KMLogs privacyLog], "CGRequestPostEventAccess not available before macOS version 10.15"); + os_log([KMLogs privacyLog], "CGRequestPostEventAccess not available before macOS version 11.0"); } return granted; }