How to ensure Applescript dialog focus in OS X 10.10 (Yosemite)?

…衆ロ難τιáo~ 提交于 2019-12-09 13:30:39

问题


Before OS X 10.10 (Yosemite), I could ensure an applescript dialog had focus by telling the "current application" to activate:

tell current application
        activate
        set output to (do shell script "printf '" & hostsLine & commentString & "' >> /private/etc/hosts" with administrator privileges)
end tell

This would bring the password dialog to the front to type in. The dialog no longer appears with focus in Yosemite and you have to click on it before you can type.

Searching on stack exchange and elsewhere hasn't provided any solutions/workarounds.

Does anyone have a way that works in OS X 10.10?

UPDATE 1: In case anyone else runs into this problem, it appears to be a new sandboxing issue. A non-password dialog box gets focus properly. In fact, a non-password dialog before the "with administrator privileges" password dialog will cause the password dialog to also have focus. I added a dialog to confirm Safari was still the front app while testing and discovered this. As a workaround, I have added a preceding dialog with timeout of 1 (second) until a better solution can be found.

tell me -- alternate method: tell current application
    activate
    display dialog "Trying to get focus…" with title "Can't focus in Yosemite" buttons {"Cancel", "Idle"} cancel button "Cancel" giving up after (1)
    set output to (do shell script "printf '" & hostsLine & commentString & "' >> /etc/hosts" with administrator privileges)
end tell

Interestingly, BBedit's Authenticated Save helper script (for the MAS version of the app) uses a "with administrator privileges" password dialog. But it gets focus properly in Yosemite. Something different between a native app call to applescript vs. an Applescript tell command for an app to do so?

on documentShouldFinalizeAuthenticatedSave(theDocument, tempFilePath, destinationPath)

    -- on input: tempFilePath points to the contents of the document written to a temp file, ready to move to the destination; destinationPath is where the file should be copied.

    -- on exit: if the operation succeeded, delete the temp file (or else the application will assume the operation failed) and return YES for success

    --  this is pretty straightforward: "cp tmpFilePath destinationPath"

    do shell script "cp" & " " & quoted form of tempFilePath & " " & quoted form of destinationPath with administrator privileges

    --  now remove the temp file, this indicates to the application that we did the work

    do shell script "rm" & " " & quoted form of tempFilePath

    return true
end documentShouldFinalizeAuthenticatedSave

UPDATE 2: If anyone is curious, this part of a Safari helper script for my wife to block spammy popup ad sites like mackeeper.zeobit.com that have modal dialog boxes. Editing /etc/hosts was a little too complicated/daunting and she wanted a turnkey solution. I can post the whole script if there's interest. It works fine under 10.9, but the focus for password issue is annoying in 10.10.


回答1:


You could try... Tell me instead of Tell current application. "Tell me" basically tells the applescript to activate and run the "do shell script" command. This makes more sense. "do shell script" is an applescript command so it makes sense to ask applescript to run it. Maybe this will help with your problem.

Good luck.




回答2:


Personally, I would remove the need to enter a password. The simplest way to do this is to append the following line to the /private/etc/sudoers file.

wife_user_name  ALL=(ALL) NOPASSWD:ALL

To remove the need for a password for all Administrator accounts, change the following line in the /private/etc/sudoers file from

%admin  ALL=(ALL) ALL

to

%admin  ALL=(ALL) NOPASSWD: ALL

Next, change your applescript line from

    set output to (do shell script "printf '" & hostsLine & commentString & "' >> /private/etc/hosts" with administrator privileges)

to

    set output to (do shell script "sudo printf '" & hostsLine & commentString & "' >> /private/etc/hosts")

Changes to the /private/etc/sudoers file can be accomplished by using the Terminal and TextEdit applications. Open the Terminal application and type the following commands:

cd ~/desktop
sudo cp -n /etc/sudoers /etc/sudoers.orignal
sudo cp /etc/sudoers sudoers.txt
sudo chmod ug+w sudoers.txt
open sudoers.txt
visudo -c -f sudoers.txt
sudo cp -X sudoers.txt /etc/sudoers

When done, the sudoers.txt file on your desktop can be put in the trash.

To undo your changes, use the command:

sudo cp /etc/sudoers.original /etc/sudoers

This was tested using OS X 10.10.1

Below is a brief explanation of what each command does:

cd ~/desktop

This makes sure you are working from your desktop folder.

sudo cp -n /etc/sudoers /etc/sudoers.original

This backups your sudoers file. The backup can be used to undo your changes. The -n option insures that an existing sudoers.original file will not be overwritten.

sudo cp /etc/sudoers sudoers.txt

Copies the sudoers file to your desktop. The .txt extension is added so OS X will know this is a text file.

sudo chmod ug+w sudoers.txt

Changes the file’s permissions to allow write access.

open sudoers.txt

Opens the file in the TextEdit application. You need to edit the file and save the changes.

visudo -c -f sudoers.txt

Checks the edited file for syntax errors. The output should be sudoers.txt: parsed OK.

sudo cp -X sudoers.txt /etc/sudoers

Copies the file back to the /etc directory.




回答3:


I stumbled upon this post trying to get the password dialog to get focus in an Alfred script that I am working on. I finally got it to work reliably by adding tell me to activate prior to my shell command. The resultant script was:

tell me to activate
do shell script "<command>" with administrator privileges

Hope this works for you.




回答4:


2015-01-08 Edit

Mike, I understand your question as: "I have an AppleScript with a do shell script that asks for an admin password, but I have to click on the password dialog before I can type in it. How can I ensure the dialog has focus, saving me the nuisance of clicking it?"

My response to you is: "What if your AppleScript never asked for a password in the first place? Wouldn't you be happier?"

If so, then here's a solution. That question demonstrates how you can bypass the dialog by supplying a password parameter along with the with administrator privileges parameter.




回答5:


Ok, Mike this is my second try at an answer.

Instead of using

tell current application
    activate
    set output to (do shell script "printf '" & hostsLine & commentString & "' >> /private/etc/hosts" with administrator privileges)
end tell 

as you proposed at the start of your above question, try using

tell current application
    activate
    tell me to set output to (doShellScript for "printf '" & hostsLine & commentString & "' >> /private/etc/hosts" with administratorPrivileges)
end tell 

where the doShellScript handler would be

on doShellScript for command as text given administratorPrivileges:adminPriv as boolean : false
    if adminPriv then
        set message to (name of current application) & " wants to make changes. Type your password to allow this."
        set again to ""
        set pw to ""
        set icn to 1
        repeat
            set fullCommand to "printf '%s\\n' " & (quoted form of pw) & " | sudo  -p '' -S " & command
            try
                return do shell script fullCommand
            on error eStr number eNum partial result rList from badObj to expectedType
                set errorMessage to "Sorry, try again." & return & return & "sudo: 1 incorrect password attempt"
                if eStr ≠ errorMessage or eNum ≠ 1 then
                    error eStr number eNum partial result rList from badObj to expectedType
                end if
            end try
            set actual to again & message
            set values to display dialog actual default answer "" with icon icn with hidden answer
            set again to "Sorry, incorrect passord. Try again." & linefeed
            set pw to text returned of values
            set icn to 2
        end repeat
    end if
    return do shell script command
end doShellScript

An example dialog is shown below.

Your application name and icon will be different. The main thing is that the focus will be on the password text box when the dialog pops up.

dave.




回答6:


I had a similar issue for which I had an applescript execute a continuous ping in Terminal, and then a dialog box would pop up in order for user to click OK to kill that ping and start a different one. The issue was similar as the dialog box kept showing behind the Terminal window. As I would have to execute this script numerous times in an urgent situation with very limited time, this was very annoying. I was finally able to resolve it by telling System Events to wait 1 second after it starts the continuous ping, and then keystroke CMD+Tab to switch back to the running script before opening the dialog box. The CMD+Tab initially only intermittently resolved it until I added the delay 1.

Example of issue:

tell application "Terminal" to do script pingCommand
set userDialog to display dialog "Client Connection Test Completed" buttons {"Ping Server", "Cancel"} 

With above code, the dialog would always come behind the Terminal window.

Example of resolution:

tell application "Terminal" to do script pingCommand
delay 1  
tell application "System Events" to key code 48 using {command down}
set userDialog to display dialog "Client Connection Test Completed" buttons {"Ping Server", "Cancel"} 



回答7:


I was facing the same problem, and created a solution that would bring my applet's dialog to the front.

I wrote a function called ActivateMe() that replaces the "activate" or "tell me to activate" commands that would proceed the "display dialog" command.

This function gets the current process name, and then executes the following AppleScript commands via a shell script.

    delay 0.1
    tell application "System Events"
        set frontmost of process \"" & processName & "\" to true
    end tell"

Here's the function. Enjoy.

on ActivateMe()

    set myPath to path to me as text
    if myPath ends with ":" then
        set n to -2
    else
        set n to -1
    end if
    set AppleScript's text item delimiters to ":"
    set processName to text item n of myPath
    if (processName contains ".") then
        set AppleScript's text item delimiters to "."
        set processName to text 1 thru text item -2 of processName
    end if
    set AppleScript's text item delimiters to ""

    set a to "delay 0.1"
    set b to "tell application \"System Events\""
    set c to "set frontmost of process \"" & processName & "\" to true"
    set d to "end tell"
    do shell script "osascript -e '" & a & "' -e '" & b & "' -e '" & c & "' -e '" & d & "'"

end ActivateMe



回答8:


Appears to be a bug in 10.10.x most likely due to sandboxing. Fixed in 10.11 (El Cap) as the unmodified script gets focus from the activate command once again like it did in 10.9 and earlier versions.



来源:https://stackoverflow.com/questions/26207035/how-to-ensure-applescript-dialog-focus-in-os-x-10-10-yosemite

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!