Ativar o access de dispositivos assistivos programaticamente em 10.9

Desejo ativar o access para dispositivos assistivos programaticamente no 10.9. No 10.8 e abaixo eu estava usando o seguinte Applescript para ativar o access para dispositivos auxiliares:

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

Com o 10.9, a Apple mudou as opções de acessibilidade para Preferências do Sistema ➞ Segurança e Privacidade ➞ Privacidade ➞ Acessibilidade. Ao contrário das versões anteriores do OS X, que usavam uma checkbox de seleção universal para todos os aplicativos, a nova funcionalidade no 10.9 permite que os usuários escolham individualmente quais aplicativos podem obter o controle do sistema para executar suas várias funções com script.

As novas preferências do sistema em relação à acessibilidade

A Apple NÃO forneceu nenhuma API aos desenvolvedores para habilitar programaticamente a acessibilidade de um aplicativo. Portanto, o Mac OS 10.9 solicitará uma checkbox de diálogo para permissão do usuário final para ativar a Acessibilidade quando o aplicativo usar APIs de acessibilidade. Além disso, o usuário precisa reiniciar o aplicativo após ativar a acessibilidade.

Caixa de diálogo de prompt padrão colocada por 10.9 OS para Xcode

Podemos habilitar o access para dispositivos auxiliares programaticamente em 10.9 usando o Applescript ou qualquer outra API? Qualquer ajuda para corrigir este problema seria muito apreciada.

Isso não responde à sua pergunta, mas é bom saber sobre uma nova chamada de API exibida em 10.9 e permite exibir a canvas de autorização ou ignorá-la:

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

Passar YES forçará a exibição da canvas de autorização, passando NO irá silenciosamente ignorá-la. O valor de retorno é o mesmo que o retornado por AXAPIEnabled() , que está sendo reprovado em 10.9. Para ter certeza de que a function está disponível em seu sistema, basta compará-la com NULL :

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

Você precisará adicionar ApplicationServices.framework ao seu projeto e importar para o arquivo .m ou .h:

 #import  

É uma pena que a canvas de autorização não permite que o usuário autorize o aplicativo diretamente, apenas abre a parte certa das Preferências do Sistema. Que, a propósito, você pode fazer diretamente sem passar pelo diálogo do sistema inútil:

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

ou usando o objective C:

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

Isso pode ser emparelhado com o primeiro trecho de código para testar se accessibilityEnabled passando @NO a kAXTrustedCheckOptionPrompt enquanto impede que o pop-up do sistema apareça e, em vez disso, abra o painel de preferências Acessibilidade diretamente:

 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]]; } 

Embora a resposta do @ user2865860 funcione bem, eu pensei em postar o exemplo de código inteiro que funciona perfeitamente no 10.9 para salvar outros em algum momento. Você precisa obter privilégios de root, portanto, ele solicitará que um usuário insira a senha.

 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... } } 

Você pode editar o arquivo TCC.db diretamente. Eu tive que fazer isso para fazer Divvy instalar sem interação do usuário. Basta replace com.mizage.divvy pelo seu programa.

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

Para remover a input:

 sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "delete from access where client='com.mizage.divvy';" 

Eu encontrei o seguinte trecho de código que solicita corretamente permissions de acessibilidade no OS X 10.9:

 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 

Eu estava lutando com isso sozinho e depois de um pouco de pesquisa eu encontrei o seguinte:

  1. Hackear o database sqlite tem a principal desvantagem de usar serviços de autorização. Primeiro, aparecerá uma checkbox de diálogo informando ao usuário que um aplicativo deseja instalar um utilitário auxiliar (mesmo que seja apenas um envio off- SMJobSubmit usando o SMJobSubmit ). Em segundo lugar, não funciona para aplicativos em área restrita e, portanto, não há armazenamento de aplicativos.

  2. @Max Al Faeakh usa AuthorizationExecuteWithPrivileges que é obsoleto. Você precisa usar o launchd com o SMJobSubmit acima. De qualquer forma, isso ainda requer autorização. Também requer um aplicativo auxiliar como este.

Eu acho que o melhor é usar:

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

ou

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

e abra o painel de preferências manualmente usando, por exemplo, a estrutura de ponte de script:

 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]; 

A class SBSystemPreferencesPane vem de um arquivo SBSystemPreferences.h que pode ser gerado:

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

Obrigado por este exemplos de script de shell do @NightFlight, que são realmente úteis. Eu usei isso com o AppleScript em um aplicativo Python, como o seguinte:

 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 

Funcionou bem para mim no código Python como uma string.

Editar (7 de novembro de 2014):

Se você quiser tentar isso no Editor AppleScript, use um escape de caractere ligeiramente diferente, conforme abaixo:

 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 

Para o Mac OS X antes do 10.9, é ainda mais simples:

 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 

Só precisa tocar em um arquivo. O AppleScript mencionado no código Python acima também pode ser usado em outros idiomas.

Obrigado a todos.

Emitir o seguinte acionado a partir da janela de login para garantir que o controle seja dado apenas aos itens que desejamos em todas as sessões:

 # 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)" 

O sqlite3 “hack” é ótimo.

Eu tive que usar permissions “1,1,1” (o que isso significa) para fazer este trabalho.

Observe que a combinação de permissions, não o cliente (ou seja, o nome do programa) é a chave de database exclusiva.

Intereting Posts