0

从 Mac OS 10.9 Mavericks 开始,Apple要求必须为每个想要使用它的应用程序显式启用辅助访问

对于给定的应用程序,我编写了以下 AppleScript 函数来处理这个问题。该脚本适用于我,但它有两个缺陷:

  1. 当操作系统以英语以外的语言运行时,硬编码的按钮名称会出错,脚本会失败。我怎样才能发现操作系统正在运行什么语言,以及“单击锁定进行更改”的名称。按钮会有那种语言?或者,有没有办法在不读取按钮名称的情况下确定此按钮是否处于lockedauthenticating或状态?unlocked

  2. 该脚本在等待用户输入管理员用户名和密码时使用紧密的重复循环。有没有更好的策略可以用来等到对话被成功解除?

====

set output to allowAssistiveAccessFor("Skype")

if (the |quitWhenDone| of output) then
  tell application "System Preferences" to quit
end if

on allowAssistiveAccessFor(applicationName)
    set quitWhenDone to not (application "System Preferences" is running)
    set output to {quitWhenDone:quitWhenDone}

    tell application "System Preferences"

        activate
        reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"

        tell application "System Events"
            tell process "System Preferences"

                -- Find the table that contains the application icons and checkboxes
                try
                    set appTable to table 1 of scroll area 1 of group 1 of tab group 1 of window "Security & Privacy"
                on error errorMessage
                    return output & {state:-1, message:errorMessage}
                end try

                set total to the number of rows of appTable

                -- Find the row that refers to applicationName 
                repeat with rowNumber from 1 to total
                    if (name of UI element 1 of row rowNumber of appTable = applicationName) then
                        set appCheckbox to checkbox 1 of UI element 1 of row rowNumber of appTable
                        if (value of appCheckbox as boolean) then
                            -- Assistive access is already enabled for this application
                            return output & {state:0, message:"Already enabled"}

                        else
                            -- Click the “Click the lock to make changes.” button.
                            if exists button "Click the lock to make changes." of window "Security & Privacy" then
                                click button "Click the lock to make changes." of window "Security & Privacy"

                                -- The user will now have to enter an admin password. This can take some time.
                                -- The name of the button will change to "Authenticating"...
                                set unlocking to button "Authenticating…" of window "Security & Privacy"
                                repeat while exists unlocking
                                end repeat
                                -- ... and then to "Click the lock to prevent further changes." ... unless the user cancelled

                                if exists button "Click the lock to make changes." of window "Security & Privacy" then
                                    return output & {state:-1, message:"User cancelled"}
                                end if
                            end if

                            -- Click the <applicationName> checkbox.
                            -- If we had to unlock the Security & Privacy pane, then an immediate click might not have
                            -- an effect. Try as many times as possible for 1 second, and give up if unsuccessful
                            set failMessage to "Cannot allow the " & applicationName & " application to control your computer"
                            set endDate to (current date) + 1.0 -- 1 second from now

                            repeat
                                try
                                    if ((current date) > endDate) then
                                        -- Time's up
                                        return output & {state:-1, message:failMessage}

                                    end if

                                    click appCheckbox

                                    if (value of appCheckbox as boolean) then
                                        return output & {state:0, message:"Success"}
                                    end if

                                on error errorMessage
                                    -- Something dreadful happened. Keep trying until time is up
                                end try
                            end repeat
                        end if
                    end if
                end repeat
            end tell
        end tell
    end tell

    return output & {state:-1, message:"Application " & applicationName & " not found"}
end allowAssistiveAccessFor
4

2 回答 2

2

您可以将窗口称为“窗口 1”,将锁定按钮称为“按钮 4”,而不是使用窗口和按钮名称。那么系统使用什么语言就无关紧要了。

tell application "System Preferences"
    activate
    reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"
    tell application "System Events"
        tell process "System Preferences"
            tell button 4 of window 1 to click
        end tell
    end tell
end tell

一旦用户通过身份验证,按钮 4 的名称就会更改。所以你可以循环直到你看到那个变化。以下不是一个完美的解决方案,因为它只适用于英语语言系统,但也许它有助于让你更进一步。

tell application "System Preferences"
    activate
    reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"
    tell application "System Events"
        tell process "System Preferences"
            tell button 4 of window 1 to click
            with timeout of 180 seconds
                repeat until button "Click the lock to prevent further changes." of window 1 exists
                end repeat
                display dialog "Preference pane unlocked." with title (the name as text) buttons {"OK"} default button "OK" giving up after 60
            end timeout
        end tell
    end tell
end tell
于 2014-08-02T08:37:15.280 回答
0

无论操作系统运行什么语言,我的脚本的这个版本都可以工作。用法语和俄语测试。它仍然使用紧密的重复循环来检查用户是否关闭了身份验证对话框,但这似乎不会影响性能。

set output to allowAssistiveAccessFor("skype")

if (the |quitWhenDone| of output) then
    tell application "System Preferences" to quit
end if

get output


on allowAssistiveAccessFor(applicationName)
    set quitWhenDone to not (application "System Preferences" is running)
    set output to {quitWhenDone:quitWhenDone}

    tell application "System Preferences"

        reopen -- to ensure that the application will be open and window 1 will contain a tab group
        activate

        -- Open the Accessibility pane of the Security & Privacy Preferences
        reveal anchor "Privacy_Accessibility" of pane id "com.apple.preference.security"

        -- The "Security & Privacy" window and its contents are only available through System Events
        tell application "System Events" to tell process "System Preferences"

            -- Find the table that contains the application icons and checkboxes. This will be in
            -- window 1 which is called "Security & Privacy" in English. If assistive access is
            -- not enabled for AppleScript, then we will have no access to any window.
            try
                set securityAndPrivacyWindow to window 1
                set appTable to table 1 of scroll area 1 of group 1 of tab group 1 of securityAndPrivacyWindow

            on error errorMessage
                return output & {state:-1, message:errorMessage}
            end try

            -- If we get here, then the assistive access is enabled for AppleScript.
            -- Let's find the row that refers to applicationName 
            set total to the number of rows of appTable
            repeat with rowNumber from 1 to total
                if (name of UI element 1 of row rowNumber of appTable = applicationName) then

                    -- We have found the row containing the applicationName checkbox
                    set appCheckbox to checkbox 1 of UI element 1 of row rowNumber of appTable

                    if (value of appCheckbox as boolean) then
                        -- Assistive access is already enabled for this application
                        return output & {state:0, message:"Already enabled"}

                    else
                        (*  Attempt to click on appCheckbox. If its value changes then the
                        Security & Privacy window was already unlocked. If it fails, then we will
                        need to ask the user to enter an admin name and password
                    *)

                        click appCheckbox

                        if (value of appCheckbox as boolean) then
                            return output & {state:0, message:"Success"}
                        end if

                        (*  If we get here, then the click on appCheckbox had no effect, presumably
                        because this window is locked. We need to simulate a click on the 
                        “Click the lock to make changes.” button. This may have different names in
                        different languages. All we know for certain is:
                        •   It is button 4 (in Mavericks at least)
                        •   Its name will change to something meaning "Authenticating…" when it is
                            clicked
                        •   If it was in its locked state:
                            -   a dialog will now show, and it will take the user a significant amount of
                                time to respond to the dialog
                            -   Its name will change again when the user clicks on one of the buttons
                                in the dialog
                            -   If its name reverts to the name it had before, then the user canceled
                                the dialog
                            -   If its name becomes something new, then the user successfully
                                entered an admin name and password
                        •   If it were in its unlocked state, it would immediately lock and its name would
                            not change again, so we would wait forever in the `repeat while` loop
                            However, if it were in its unlocked state then we would already have changed
                            the state of the applicationName checkbox, so we would not be here.
                        *)

                        set lockButton to button 4 of securityAndPrivacyWindow
                        click lockButton

                        -- The name of the button will have changed to something like "Authenticating"...
                        set unlocking to button 4 of securityAndPrivacyWindow

                        -- The user will now have to enter an admin password. This can take some time.
                        repeat while exists unlocking
                            -- The user has not yet clicked on either the Cancel or the Unlock button yet
                        end repeat

                        (*  The user has closed the dialog. If s/he clicked Cancel then:
                            •   The original name of the button will have been restored
                            •   We cannot continue
                        *)
                        if exists lockButton then
                            return output & {state:-1, message:"User canceled"}
                        end if

                        -- If we get here, we can simulate a click on the <applicationName> checkbox.
                        click appCheckbox

                        if (value of appCheckbox as boolean) then
                            return output & {state:0, message:"Success after authentication"}
                        else
                            return output & {state:-1, message:"Failure after authentication"}
                        end if
                    end if
                end if
            end repeat
        end tell
    end tell

    return output & {state:-1, message:"Application " & applicationName & " not found"}
end allowAssistiveAccessFor 
于 2014-08-02T11:19:40.687 回答