I want to automate clicking a specific pop down menu's item.
For Example, I want to change the Value of "Message receive Sound" to something else. How can I do this with AppleScript? And how can I do this with other pop down menus in AppleScript?
(To open the iMessage Settings menu, shown in the image, type CMD COMMA, once you open iMessage)
Note: I have successfully done this Automator, I just want to do it in applescript.
It's called GUI scripting. You have to identify the reference to the UI element(s).
GUI scripting strongly depends on the system version. If an update changes the UI structure the script will brake.
This selects the sound "Popcorn" in the sound popup menu. It's for El Capitan. In systems < 10.11 the UI elements may be different and the process name might be "iChat"
tell application "System Events"
tell process "Messages"
set frontmost to true
if not (exists (1st window whose value of attribute "AXIdentifier" is "MessagesPreferencesWindow")) then
keystroke "," using command down
repeat until exists (1st window whose value of attribute "AXIdentifier" is "MessagesPreferencesWindow")
delay 0.1
end repeat
end if
tell (1st window whose value of attribute "AXIdentifier" is "MessagesPreferencesWindow")
tell pop up button 4 of group 1
click
delay 0.2
click menu item "Popcorn" of menu 1
end tell
end tell
end tell
end tell
Related
Actually I have 3 questions about the same problem: controlling a window with applescript.
What should I do if I would press on button "Close Window" of application "Google Chrome"?
Is it possible to check if the window changes? For example, to see if appear a pop-up or something like that...
What about clicking on a specific place into a window? I mean, I know I can use
tell application "System Events"
click at {x,y}
end tell
but this command use the entire screen as reference system, and I want it works only on a specific window. For example, if at "{x,y}" i put "{1,1}", applescript will click on the first item on the menu bar. Is there a way I can say to "System Events" to click at "{1,1}", but on the window "Google Chrome"?
Here are three examples of how to close the front window of Google Chrome using AppleScript:
Note: The following assumes Google Chrome is running with at least one window open when you test each example AppleScript code in Script Editor.
Example one is the most straight forward way:
tell application "Google Chrome" to close front window
Example two directly clicks the close button:
tell application "System Events" to tell ¬
application process "Google Chrome" to ¬
click button 1 of front window
Example three calculates the center of the close button and clicks there:
activate application "Google Chrome"
delay 0.5
tell application "System Events" to tell ¬
application process "Google Chrome" to tell ¬
front window
set posB1 to (position of button 1)
set szB1 to (size of button 1)
set x to (item 1 of posB1) + (item 1 of szB1) / 2 as integer
set y to (item 2 of posB1) + (item 2 of szB1) / 2 as integer
end tell
tell application "System Events" to click at {x, y}
Note that in the first two examples, the front window of Google Chrome doesn't even need to be the frontmost window on the Desktop; however, with the third example it does, otherwise the click at {x, y} will not go to the intended target.
That said, example three really shouldn't be used when there it a straight forward way, as in example one, to get the job done. Example three was just a proof of concept to get the coordinates to click at. This method may be useful in some fringe cases, especially in an app that doesn't directly support AppleScript.
Note: The example AppleScript code is just that and does not contain any error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors.
In applescript GUI scripting you can simply refer to an element by name or index and tell it to click or to perform an action. For instance to click the close button on the first open window in Chrome you could use:
tell application "System Events"
tell process "Google Chrome"
tell window 1
tell button 1
click
end tell
end tell
end tell
end tell
You don't actually need to know its physical position to click one it; you just need to know that the first button in the window is the close button.
System Events always returns the position of any element in screen pixels, so if you want the position of an element in terms of its window, get the position of the element, get the position of the window, and do some addition or subtraction (e.g., if you want to click at {5,5} in a window whose position is {100, 125}, click at {105, 130})
AppleScript isn't really designed to monitor GUI changes, though if you want to be tricky and you know what change you're looking for you can do something like this:
tell application "System Events"
tell process "..."
tell window 1's pop up button 3
repeat until (exists menu 1)
delay 0.2
end repeat
-- menu 1 now exists, so the pop up button is open
end tell
end tell
end tell
...but note that this will hang the script until the menu is opened. A more elegant way to handle that is to write a script application with an idle handler, like so:
on run
-- whatever initialization is needed
end run
on idle
tell application "System Events"
try
tell process "..."
tell window 1's pop up button 3
if exists menu 1 then
-- menu 1 now exists
-- the pop up button is open
-- do what must be done
end if
end tell
end tell
on error errstr
display alert "Something went wrong" message "The script sent this error: " & errstr
end try
end tell
return 0.2
end idle
You can leave that running in the background watching for specific changes in the GUI (the 'try' statement is in case the app you're watching quits, the window closes, or something unexpected happens to the GUI).
If you haven't already, open the System Events scripting definition in Script Editor and look at the Processes Suite. That will show you all the things you can do with GUI scripting.
I need to automate the process of enrolment of Face ID and Touch ID for my UITests. For this purpose, I'm working on an automator script.
My current automator script, which at the moment can automatic click "Enrolled" in the menu:
on run {input, parameters}
if application "Simulator" is running then
tell application "System Events"
set theName to name of the first process whose frontmost is true
end tell
tell application "Simulator" to activate
tell application "System Events"
tell process "Simulator"
tell menu bar 1
tell menu bar item "Hardware"
tell menu "Hardware"
tell menu item "Face ID"
tell menu "Face ID"
click (menu item "Face ID" where its name starts with "Matching")
end tell
end tell
end tell
end tell
end tell
end tell
end tell
tell application theName to activate
end if
return input
end run
The problem is as following. I need to determine, if the device already is enrolled. There is a checkmark, which shows the current state. I have tried to check if the checkmarks is there or not. But I have not been able to make it work yet.
So my question. How can I do, so the script only will press the 'Enrolled' menu item, if the checkmark isn't there?
There's an attribute of menu items called AXMenuItemMarkChar, which is either set to the character representing a check mark next to the menu item (if checked), or missing value.
use application "System Events"
tell application "Simulator" to activate
tell process "Simulator" to tell menu bar 1 to ¬
tell menu bar item "Hardware" to tell menu "Hardware" to ¬
tell menu item "Face ID" to tell menu "Face ID" to ¬
tell menu item "Enrolled"
if the value of the attribute "AXMenuItemMarkChar" is not "✓" then ¬
click it
delay 1 -- !important
return the value of the attribute "AXMenuItemMarkChar"
end tell
In my testing, the attribute returns the correct value if the Simulator app is in focus at the time. The return value of this script should always be "✓", because if the menu item isn't checked, then the script proceeds to click it and put a check mark next to it; and if the menu item is checked, then there's nothing to do but confirm that it is by getting the attribute's value.
One of the issues with your script is that you had the wrong reference to a non-existent menu item (menu item "Face ID" of menu "Face ID" of menu item "Face ID"), and then proceeded to filter it with a where clause against a name that had a different value; hence it would return no value, and you'd have no menu item to click.
Hopefully my script will work for you. Let me know if you have any problems.
The AppleScript contained in this answer was tested on MacOS 10.13. It is an example script to illustrate how to meet your objective. The delay command may need to be adjusted according to your system, and the script may benefit from some error-handling to make it robust.
I am trying to interact with iTunes "Export Library.." dialog.
I tried "set choices to every menu item of menu 1 of pop up button 1 of group 1 of window winName" but it says "group 1" is an invalid index?
Here's the relevant code: (the call parameters are: "iMac-8GB", "iTunes", "iTunes", false"
on handleDir(dir, winName, appName, createIt)
local foundIt, ndx
set foundIt to false
if winName is not "" then
tell application "System Events" to tell process "iTunes"
set choices to every menu item of menu 1 of pop up button 1 of group 1 of window winName
You want to use the menu "Export Library…" from iTunes :
The first step is to select the relevant menu. In my iTunes version (12.5.5.5) the menu is in "File" menu, sub menu item "Library" and then sub Menu "Export Library…".
The second step is to fill the export file name and set the destination folder. The Mac "Save as…" window has many shortcuts, valid for all applications. Among others, command G allows to define the complete path to save the file. This path must be in Unix format (with "/" and not ":" for sub levels).
The bellow script does the complete Export Library function. The first 2 rows define the name of the file to save and the path where to save it. Adjust them to your needs.
set myTitle to "test" -- name of the exported file
set myPath to "/Users/myuser/Desktop/Test_folder" -- destination folder for export file
tell application "iTunes" to activate -- make iTunes front
tell application "System Events"
tell process "iTunes"
click menu 3 of menu bar 1 -- open the File menu
click menu item 12 of menu 3 of menu bar 1 -- select the Library menu item
delay 0.1
click menu item 5 of menu 1 of menu item 12 of menu 3 of menu bar 1 -- select the export library… item
delay 0.1
keystroke myTitle -- fill the export file name in the save as… dialog
keystroke "G" using command down -- shortcut to open Go-to folder window
keystroke myPath
keystroke return -- to close the go-to window
delay 0.1
keystroke return -- to close the export window
end tell -- process iTunes
end tell -- system Events
I added several delays to make sure your Mac has enough time to open or close windows.
Using this code, modified to specifically target iTunes':
tell application "System Events"
tell front window of (first application process whose frontmost is true)
set uiElems to entire contents
end tell
end tell
which came from an answer to Use AppleScript to list the names of all UI elements in a window (GUI scripting)
I discovered that a NSBox is referred to as an "outline" by Applescript.
I'm using NetShade as a proxy service and thought I could try to automate the switching between the different proxies as a nice start for my first AppleScript script.
The NetShade-app has no AppleScript support, so I have to use UI scripting. After a few tries (and some posts here) I managed to have a script, that switches the proxies via the menu bar item (here is a picture of it, since I can't post it inline due to reputation limit).
Unfortunately my code is extremely slow (≈6sec), which makes it kind of impractical as a script. The first menu opens immediately, but the selection of the sub-menu and the proxy server takes several seconds.
I'm using the following code:
set theProxy to "Netshade US 4"
tell application "System Events" to tell process "NetShade"
tell menu bar item 1 of menu bar 2
click
tell menu item "NetShade Proxy" of menu 1
click
tell menu item theProxy of menu 1
click
end tell
end tell
end tell
end tell
I already tried to add ignoring application responses, like suggested in a different thread (link), but that didn't help.
So finally my questions:
Is there a way to speed the process up? Maybe even a way to do all this in the background, without showing the menu items?
P.S.: I'm running OS X 10.9.1
Summary of the fix
To remove delay you need to do two things:
(I) Identify the click which is causing the delay and enclose only that line in the ignoring application responses block as shown below. In my case, it was click bt after which the execution was going into a wait mode for 5 to 6 seconds.
ignoring application responses
click bt
end ignoring
(II) I then also had to kill System Events to and start it again using the following commands.
do shell script "killall System\\ Events"
delay 0.1
-- Rest of the code to click stuff or send keycodes
This resolved the delay issue.
Details
I was having the same problem where I created a script to connect/disconnect my bluetooth headset through AppleScript. The script is given below.
tell application "System Events" to tell process "SystemUIServer"
set bt to (first menu bar item whose description is "bluetooth") of menu bar 1
click bt
tell (first menu item whose title is "SBH80") of menu of bt
click
tell menu 1
if exists menu item "Disconnect" then
click menu item "Disconnect"
else
click menu item "Connect"
end if
end tell
end tell
end tell
The script was working fine but had a problem where it would wait for 5 to 6 seconds after executing "click bt" above. I modified the code as follows and it is working absolutely fine now without any delay.
tell application "System Events" to tell process "SystemUIServer"
set bt to (first menu bar item whose description is "bluetooth") of menu bar 1
ignoring application responses
click bt
end ignoring
end tell
do shell script "killall System\\ Events"
delay 0.1
tell application "System Events" to tell process "SystemUIServer"
tell (first menu item whose title is "SBH80") of menu of bt
click
tell menu 1
if exists menu item "Disconnect" then
click menu item "Disconnect"
else
click menu item "Connect"
end if
end tell
end tell
end tell
I have a script for OS X 10.5 that focuses the Search box in the Help menu of any application. I have it on a key combination and, much like Spotlight, I want it to toggle when I run the script. So, I want to detect if the search box is already focused for typing, and if so, type Esc instead of clicking the Help menu.
Here is the script as it stands now:
tell application "System Events"
tell (first process whose frontmost is true)
set helpMenuItem to menu bar item "Help" of menu bar 1
click helpMenuItem
end tell
end tell
And I'm thinking of something like this:
tell application "System Events"
tell (first process whose frontmost is true)
set helpMenuItem to menu bar item "Help" of menu bar 1
set searchBox to menu item 1 of menu of helpMenuItem
if (searchBox's focused) = true then
key code 53 -- type esc
else
click helpMenuItem
end if
end tell
end tell
... but I get this error:
Can’t get focused of {menu item 1 of menu "Help" of menu bar item "Help" of menu bar 1 of application process "Script Editor" of application "System Events"}.
So is there a way I can get my script to detect whether the search box is already focused?
I solved my problem by working around it. I still don't know how to check if a menu item is selected though, so I will leave this topic open.
You need to use attribute AXMenuItemMarkChar.
Example:
tell application "System Events"
tell process "Cisco Jabber"
set X to (value of attribute "AXMenuItemMarkChar" of menu item "Available" of menu "Status" of menu item "Status" of menu "File" of menu bar item "File" of menu bar 1) is "✓" -- check if Status is "Availible"
end tell
end tell
If the menu item is checked, the return value is ✓, otherwise it is missing value.
Note: This test only works if the application whose menus are being inspected is currently frontmost.
The built in key shortcut Cmd-? (Cmd-Shift-/) already behaves like this. It moves key focus to the help menu's search field if it is not already focused, and otherwise dismisses the menu.
Using /Developer/Applications/Utilities/Accessibility Tools/Accessibility Inspector.app you can use the built-in accessibility system to look at properties of the UI element under the mouse. Take special note of the cmd-F7 action to lock focus on an element and the Refresh button. Sadly the element and property names don't directly match those in the script suite, but you can look at the dictionary for System Events or usually guess the right terminology.
Using this you can determine two things. First, the focused property isn't on the menu item, but rather there is a text field within the menu item that is focused. Second, the menu item has a selected property.
With this, I came up with:
tell application "System Events"
tell (first process whose frontmost is true)
set helpMenuItem to menu bar item "Help" of menu bar 1
-- Use reference form to avoid building intermediate object specifiers, which Accessibility apparently isn't good at resolving after the fact.
set searchBox to a reference to menu item 1 of menu of helpMenuItem
set searchField to a reference to text field 1 of searchBox
if searchField's focused is true then
key code 53 -- type esc
else
click helpMenuItem
end if
end tell
end tell
Though this still doesn't work. The key event isn't firing as far as I can tell, so something may still be hinky with the focused property on the text field.
Anyway, your click again solution seems much easier.
I just came across the need to do this myself for some file processing in Illustrator.
Here is what I came up with:
tell application "Adobe Illustrator"
activate
tell application "System Events"
tell process "Illustrator"
set frontmost to true
set activeMenuItem to enabled of menu item "Unlock All" of menu "Object" of menu bar item "Object" of menu bar 1
if activeMenuItem is true then
tell me to beep 3
else
tell me to beep 2
end if
end tell
end tell
end tell
Done.
This worked with no problem and could be used to iterate a file. I'll probably have to do this many more times in my future automation.
Good luck!
This worked for me to toggle between two menu items, based on which one is selected, using the "selected" property:
tell application "System Preferences"
reveal anchor "keyboardTab" of pane "com.apple.preference.keyboard"
end tell
tell application "System Events" to tell process "System Preferences"
tell pop up button 2 of tab group 1 of window 1
click
delay 0.2
set appControl to menu item "App Controls" of menu 1
set fKeys to menu item "F1, F2, etc. Keys" of menu 1
if selected of appControl is true then
click fKeys
else
click appControl
end if
end tell
end tell