it-swarm.com.de

Aktivieren Sie den programmgesteuerten Zugriff für assistive Geräte am 10.9

Ich möchte den programmgesteuerten Zugriff auf Hilfsmittel auf 10.9 freigeben. Am 10.8 und niedriger verwendete ich folgendes Applescript, um den Zugriff für Hilfsgeräte zu ermöglichen:

tell application "System Events"
if UI elements enabled is false then
    set UI elements enabled to true
end if
end tell

Mit 10.9 hat Apple die Eingabehilfen in die Systemeinstellungen ➞ Sicherheit und Datenschutz ➞ Datenschutz ibility Eingabehilfen verschoben. Im Gegensatz zu früheren Versionen von OS X, in denen ein universelles Kontrollkästchen für alle Anwendungen verwendet wurde, können Benutzer mit Hilfe der neuen Funktion in 10.9 individuell auswählen, welche Apps die Kontrolle über das System erlangen können, um ihre verschiedenen Skriptfunktionen auszuführen.

The new system preferences regarding accessibility

Apple hat KEINE APIs für Entwickler bereitgestellt, um den Zugriff für eine App programmgesteuert zu ermöglichen. Daher fordert Mac OS 10.9 ein Dialogfeld auf, in dem der Endbenutzer die Berechtigung zum Aktivieren von Accessibility erhalten kann, wenn die Anwendung Accessibility-APIs verwendet. Zusätzlich muss der Benutzer die Anwendung erneut starten, nachdem die Barrierefreiheit aktiviert wurde.

Default Prompt dialog put up by 10.9 OS for Xcode

Können wir mithilfe von Applescript oder anderen APIs den programmgesteuerten Zugriff auf assistive Geräte unter 10.9 ermöglichen? Jede Hilfe zur Behebung dieses Problems wäre sehr dankbar.

35
Vinpai

Dies beantwortet Ihre Frage nicht, aber es ist gut zu wissen, dass ein neuer API-Aufruf in 10.9 erscheint und Sie den Autorisierungsbildschirm anzeigen oder umgehen können:

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);

Wenn Sie YES übergeben, wird der Autorisierungsbildschirm angezeigt. Wenn Sie NO übergeben, überspringen Sie den Befehl automatisch. Der Rückgabewert ist der gleiche wie der von AXAPIEnabled() zurückgegebene Wert, der in 10.9 nicht mehr unterstützt wird. Um sicherzustellen, dass die Funktion auf Ihrem System verfügbar ist, vergleichen Sie sie einfach mit NULL:

if (AXIsProcessTrustedWithOptions != NULL) {
    // 10.9 and later
} else {
    // 10.8 and older
}

Sie müssen ApplicationServices.framework zu Ihrem Projekt hinzufügen und in Ihre .m- oder .h-Datei importieren:

#import <ApplicationServices/ApplicationServices.h>

Es ist sehr schade, dass der Autorisierungsbildschirm dem Benutzer nicht erlaubt, die App direkt zu autorisieren. Er öffnet lediglich den rechten Teil der Systemeinstellungen. Was Sie übrigens direkt tun können, ohne den nutzlosen Systemdialog zu durchlaufen:

tell application "System Preferences"
    set securityPane to pane id "com.Apple.preference.security"
    tell securityPane to reveal anchor "Privacy_Accessibility"
    activate
end tell

oder mit Ziel C:

NSString *urlString = @"x-Apple.systempreferences:com.Apple.preference.security?Privacy_Accessibility";
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];

Dies kann mit dem ersten Code-Snippet gekoppelt werden, um zu testen, ob accessibilityEnabled vorhanden ist, indem @NO an kAXTrustedCheckOptionPrompt übergeben wird, während das System-Popup nicht angezeigt wird und stattdessen das Fenster mit den Eingabehilfen direkt geöffnet wird:

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @NO};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
if (!accessibilityEnabled) {
    NSString *urlString = @"x-Apple.systempreferences:com.Apple.preference.security?Privacy_Accessibility";
    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];
}
39
zoul

Während die Antwort von @ user2865860 gut funktioniert, würde ich wohl das gesamte Codebeispiel veröffentlichen, das perfekt auf 10.9 funktioniert, um anderen Zeit zu sparen. Sie müssen über Root-Rechte verfügen, sodass ein Benutzer zur Eingabe des Kennworts aufgefordert wird.

char *command= "/usr/bin/sqlite3";
char *args[] = {"/Library/Application Support/com.Apple.TCC/TCC.db", "INSERT or REPLACE INTO access  VALUES('kTCCServiceAccessibility','com.yourapp',0,1,0,NULL);", nil};
AuthorizationRef authRef;
OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authRef);
if (status == errAuthorizationSuccess) {
    status = AuthorizationExecuteWithPrivileges(authRef, command, kAuthorizationFlagDefaults, args, NULL);
    AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
    if(status != 0){
        //handle errors...
    }
}
9
Max Al Farakh

Sie können die TCC.db-Datei direkt bearbeiten. Ich musste dies tun, um Divvy ohne Benutzerinteraktion installieren zu können. Ersetzen Sie einfach com.mizage.divvy durch Ihr Programm.

Sudo sqlite3 /Library/Application\ Support/com.Apple.TCC/TCC.db "INSERT INTO access VALUES('kTCCServiceAccessibility','com.mizage.divvy',0,1,1,NULL);" 

So entfernen Sie den Eintrag:

Sudo sqlite3 /Library/Application\ Support/com.Apple.TCC/TCC.db "delete from access where client='com.mizage.divvy';"
8
user2865860

Ich habe das folgende Code-Snippet gefunden, das Accessibility-Berechtigungen in OS X 10.9 ordnungsgemäß anfordert:

if (AXIsProcessTrustedWithOptions != NULL) {
    // 10.9 and later
    const void * keys[] = { kAXTrustedCheckOptionPrompt };
    const void * values[] = { kCFBooleanTrue };

    CFDictionaryRef options = CFDictionaryCreate(
            kCFAllocatorDefault,
            keys,
            values,
            sizeof(keys) / sizeof(*keys),
            &kCFCopyStringDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);

    return AXIsProcessTrustedWithOptions(options);
}

// OS X 10.8 and older
7
Sergey L.

Um dies zu ergänzen, können Sie tatsächlich überwachen, ob der Benutzer auf die Eingabehilfeneinstellung für Ihre App klickt, sodass Sie einige Aktionen ausführen können, wenn der Benutzer die Berechtigung erteilt

(Swift 5, arbeitet an Mojave)

Werte lesen (der richtige Weg für Mojave):

private func readPrivileges(Prompt: Bool) -> Bool {
    let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: Prompt]
    let status = AXIsProcessTrustedWithOptions(options)
    os_log("Reading Accessibility privileges - Current access status %{public}@", type: .info, String(status))
    return status
}

Überwachung auf Änderungen der Barrierefreiheit:

DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name("com.Apple.accessibility.api"), object: nil, queue: nil) { _ in
  DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    self.updatePrivileges()
  }
}

Es ist am besten, die Berechtigungen nach Erhalt der Benachrichtigung erneut zu lesen, da die Benachrichtigung selbst meiner Erfahrung nach nicht funktioniert. Führen Sie also in der updatePrivileges()readPrivileges() aus, um den neuen Status abzurufen.

Sie benötigen die Verzögerung, da es einige Zeit dauert, bis die Änderungen wirksam werden.

Eine andere Sache, die Sie beim Überwachen beachten müssen, ist, dass eine Benachrichtigung für jede App ausgelöst wird, die unterschiedliche Berechtigungen hat. Wenn der Benutzer also eine andere App gewährt oder widerruft, erhalten Sie trotzdem eine Benachrichtigung.

Vergessen Sie auch nicht, den Beobachter zu entfernen, wenn Sie ihn nicht mehr benötigen.

bearbeiten:

Quelle: Accessbility Testbench von Piddlesoft

2
JoniVR

Ich habe selbst damit zu kämpfen gehabt und nach ein wenig Recherche habe ich folgendes gefunden:

  1. Das Hacken der SQLite-Datenbank hat den größten Nachteil bei der Verwendung von Autorisierungsdiensten. Zunächst wird ein Dialogfenster geöffnet, in dem der Benutzer darüber informiert wird, dass eine Anwendung einen Hilfsprogramm-Assistenten installieren möchte (auch wenn es sich nur um eine einmalige Startübergabe mit SMJobSubmit handelt). Zweitens funktioniert es nicht für Sandkasten-Apps und somit auch keinen App-Store.

  2. @Max Al Faeakh verwendet AuthorizationExecuteWithPrivileges, was veraltet ist. Sie müssen launchd mit der obigen SMJobSubmit verwenden. Dies erfordert jedoch immer noch eine Genehmigung. Es erfordert auch eine Hilfsanwendung wie diese one .

Ich denke, das Beste ist, entweder zu verwenden:

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);

oder

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @NO};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);

einstellungsfenster manuell öffnen und öffnen, z. B. mit dem Scripting Bridge-Framework:

SBSystemPreferencesApplication *prefs = [SBApplication applicationWithBundleIdentifier:@"com.Apple.systempreferences"];
[prefs activate];

SBSystemPreferencesPane *pane = [[prefs panes] find:^BOOL(SBSystemPreferencesPane *elem) {
  return [[elem id] isEqualToString:@"com.Apple.preference.security"];
}];
SBSystemPreferencesAnchor *anchor = [[pane anchors] find:^BOOL(SBSystemPreferencesAnchor *elem) {
  return [[elem name] isEqualToString:@"Privacy_Accessibility"];
}];

[anchor reveal];

Die SBSystemPreferencesPane-Klasse kommt aus einer SBSystemPreferences.h-Datei, die generiert werden kann: 

sdef "/Applications/System Preferences.app" | sdp -fh --basename SBSystemPreferences -o SBSystemPreferences.h
2
fikovnik

Vielen Dank für dieses Shell-Skript von @NightFlight, die wirklich hilfreich sind. Ich habe dies mit AppleScript in einer Python-Anwendung verwendet, wie folgt:

set sh to "touch /private/var/db/.AccessibilityAPIEnabled && sqlite3 \\"/Library/Application Support/com.Apple.TCC/TCC.db\\" \\"INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.godevnode',0,1,0,NULL);\\""
do Shell script sh with administrator privileges

Es hat für mich in Python-Code als String gut funktioniert.

Bearbeiten (7. November 2014):

Wenn Sie dies im AppleScript Editor versuchen möchten, verwenden Sie ein etwas anderes Zeichen als Escape:

set sh to "touch /private/var/db/.AccessibilityAPIEnabled && sqlite3 \"/Library/Application Support/com.Apple.TCC/TCC.db\" \"INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.godevnode',0,1,0,NULL);\""
do Shell script sh with administrator privileges

Für Mac OS X vor 10.9 ist es noch einfacher:

accessibility_api_file = "/private/var/db/.AccessibilityAPIEnabled"

def __enable_accessibility_api():
    try:
        script = 'do Shell script "touch %s" with administrator ' \
                 'privileges' % accessibility_api_file
        result = applescript.AppleScript(script).run()
        log.debug("Tried to enable accessibility api, result=" + result)
        return True
    except applescript.ScriptError as err:
        log.error(str(err))
    return False

Sie müssen nur eine Datei berühren. Das im Python-Code oben erwähnte AppleScript kann auch in anderen Sprachen verwendet werden.

1
Jake W

Der sqlite3 "Hack" ist großartig. 

Ich musste die Berechtigungen "1,1,1" (was auch immer das bedeutet) verwenden, um dies zu erreichen. 

Beachten Sie, dass die Berechtigungskombination nicht der Client (dh der Programmname) der eindeutige Datenbankschlüssel ist. 

0
a.out

Vielen Dank an alle.

Ich stelle folgende Meldung aus dem Anmeldefenster aus, um sicherzustellen, dass nur die Elemente, die wir in jeder Sitzung wünschen, gesteuert werden:

# Enable Service Accessibility for Textpander and others  
# Clear the acess table.
sqlite3 /Library/Application\ Support/com.Apple.TCC/TCC.db "DELETE FROM access"

# Enter the access we wish to have.
sqlite3 /Library/Application\ Support/com.Apple.TCC/TCC.db "INSERT INTO access VALUES ('kTCCServiceAccessibility','com.Apple.systempreferences',0,1,1,NULL)"
sqlite3 /Library/Application\ Support/com.Apple.TCC/TCC.db "INSERT INTO access VALUES ('kTCCServiceAccessibility','de.petermaurer.textpanderdaemon',0,1,1,NULL)"
0
NightFlight