How to write applescript to that closes a desktop space? - applescript

The below is a script to 1) click the 'add desktop' button 2) click on the last space added to go to it
on run
my openSpace()
end run
on openSpace()
tell application "System Events"
tell application "Mission Control" to launch
tell group 2 of group 1 of group 1 of process "Dock"
click (every button whose value of attribute "AXDescription" is "add desktop")
tell list 1
set countSpaces to count of buttons
delay 0.5
click button (countSpaces)
end tell
end tell
end tell
end openSpace
on closeSpace()
end closeSpace
However, I'm also trying to write a script to close a space. I'm having trouble finding which button/attribute to click. Accessibility inspector can't give me what I need, so in need of some help

Testing under macOS Catalina, the following example AppleScript code works for me to close the last desktop/space showing in Mission Control:
my closeSpace()
on closeSpace()
tell application "Mission Control" to launch
delay 1
tell application "System Events"
tell list 1 of group 2 of group 1 of group 1 of process "Dock"
set countSpaces to count of buttons
if countSpaces is greater than 1 then
perform action "AXRemoveDesktop" of button countSpaces
end if
end tell
delay 0.25
key code 53 -- # Esc key on US English Keyboard
end tell
end closeSpace
Notes:
The example AppleScript code what tested on a system using a single monitor. Systems with multiple monitors and if Mission Control preferences has Displays have separate Spaces checked, then additional coding may be necessary.
The example AppleScript code above, as coded, may not actually remove the last Desktop. If the last button showing in Mission Control is a Full Screen View application window, then the perform action "AXRemoveDesktop" of button countSpaces just knocks the Full Screen View application window out of Full Screen View.
If this is an issue for you, then to work around this and actually close the last Desktop, then use the following example AppleScript code as the closeSpace() handler:
on closeSpace()
tell application "Mission Control" to launch
delay 1
tell application "System Events"
tell list 1 of group 2 of group 1 of group 1 of process "Dock"
set buttonNames to the name of UI elements
set buttonNames to the reverse of buttonNames
set i to the length of buttonNames
repeat with buttonName in buttonNames
if contents of buttonName is equal to ("Desktop " & i as text) then
if i is greater than 1 then
perform action "AXRemoveDesktop" of button i
exit repeat
end if
else
set i to i - 1
end if
end repeat
end tell
delay 0.25
key code 53 -- # Esc key on US English Keyboard
end tell
end closeSpace
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional 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. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

Here's a solution I made using the window tiling manager yabai.
Requires yabai and jq installed.
Save this into a file such as close_current_space.sh:
#!/bin/bash
index=$(yabai -m query --spaces --space | jq .index)
osascript -e \
"tell application \"System Events\"
do shell script quoted form of \"/System/Applications/Mission Control.app/Contents/MacOS/Mission Control\"
delay 0.3
perform action \"AXRemoveDesktop\" of button $index of list 1 of group \"Spaces Bar\" of group 1 of group \"Mission Control\" of process \"Dock\"
delay 0.5
do shell script quoted form of \"/System/Applications/Mission Control.app/Contents/MacOS/Mission Control\"
end tell"
Then running that in a terminal will close the current active space.
I've also adapted it to handle multiple displays like so:
#!/bin/bash
display=$(yabai -m query --displays --display | jq .index)
spaceIndex=$(yabai -m query --spaces --space | jq .index)
actualIndex=$(($(yabai -m query --displays --display | jq ".spaces | to_entries | .[] | select(.value == $spaceIndex) | .key")+1))
osascript -e \
"tell application \"System Events\"
do shell script quoted form of \"/System/Applications/Mission Control.app/Contents/MacOS/Mission Control\"
delay 0.3
perform action \"AXRemoveDesktop\" of button $actualIndex of list 1 of group \"Spaces Bar\" of group $display of group \"Mission Control\" of process \"Dock\"
delay 0.5
do shell script quoted form of \"/System/Applications/Mission Control.app/Contents/MacOS/Mission Control\"
end tell"
I've bound that script to a keystroke using skhd and it works great.
Cheers!

Related

How to get an Apple Script to click only within a specific display/monitor?

I am trying to program an Apple Script to perform a series of clicks on an application on my second monitor, yet I can only get the clicks to work on my primary monitor. Can someone walk me through how to achieve this behavior?
In reference to your comment...
All in Logic Pro X on the window in my third display, I need a script to: 1. Click the "gear icon" in the bottom left of the browser. 2. Select "enable patch merging". 3. Disable-click "sends" 4. Disable-click "Audio Effects"
The example AppleScript code, shown below, was tested in Script Editor using Logic Pro 10.6.3 under macOS Catalina with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.
1 Assumes necessary and appropriate settings in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.
Also note that the example AppleScript code assumes that the Merge following when loading Patch: is not showing and Sends and Audio Effects are enabled.
There is also only one Logic Pro window opened.
In the first block of example AppleScript code I experienced a ~5 second delay between the first two perform action "AXPress" of ¬ events and have included a second block of example AppleScript code that works around this known ~5 second delay issue, that occurs in some situations, in case you experience it too.
Example AppleScript code:
tell application "System Events"
tell application process "Logic Pro X"
perform action "AXPress" of ¬
pop up button 1 of ¬
group 1 of group 2 of window 1
perform action "AXPress" of ¬
menu item "Enable Patch Merging" of ¬
menu 1 of pop up button 1 of ¬
group 1 of group 2 of window 1
perform action "AXPress" of ¬
checkbox "Sends" of ¬
group 1 of group 1 of group 2 of window 1
perform action "AXPress" of ¬
checkbox "Audio Effects" of ¬
group 1 of group 1 of group 2 of window 1
end tell
end tell
If you experience the ~5 second delay, try the following...
Example AppleScript code:
ignoring application responses
tell application "System Events" to ¬
perform action "AXPress" of ¬
pop up button 1 of group 1 of group 2 of ¬
window 1 of application process "Logic Pro X"
end ignoring
delay 0.1
do shell script "killall 'System Events'"
delay 0.2
tell application "System Events"
run
delay 0.2
tell application process "Logic Pro X"
perform action "AXPress" of ¬
menu item "Enable Patch Merging" of ¬
menu 1 of pop up button 1 of ¬
group 1 of group 2 of window 1
perform action "AXPress" of ¬
checkbox "Sends" of ¬
group 1 of group 1 of group 2 of window 1
perform action "AXPress" of ¬
checkbox "Audio Effects" of ¬
group 1 of group 1 of group 2 of window 1
end tell
end tell
Notes:
While the example AppleScript code shown herein worked for me under the conditions specified, nonetheless, it may require adjusting depending upon your conditions, the version of macOS and may need some error handling added and or the use of the delay command between some events.
This is a bare minimum example and additional coding to check the state of the various UI elements should be added to allow for the wanted results to occur without issue. For example, checking whether Sends and Audio Effects are enabled before performing an action, etc.
The example AppleScript code uses UI Scripting and can be kludgy and prone to error for a number of different reasons.
Updated Example with Error Handling
Here is an example, based on the second block of code from above, that is coded with additional error handling in that it checks to see the Library is showing and if not shows it before proceeding, as well as other included error handling. The following example AppleScript code is also tokenized so setting the value of the properties in the first group allows for use of languages other than US English by adjusting their value as appropriate, allowing the remaing code to work base on the value of those properties.
Example AppleScript code:
-- # User adjustable properties, the names
-- # as they appear on the UI elements.
property |Enable Patch Merging| : "Enable Patch Merging"
property |Sends| : "Sends"
property |Audio Effects| : "Audio Effects"
property menuName : "View"
property menuCommand : "Show Library"
property windowName : "Untitled - Tracks"
-- ##############################################
-- # Do not modify code below unless necessary. #
-- ##############################################
property |Logic Pro| : name of application id "com.apple.logic10"
property |System Events| : name of application id "com.apple.systemevents"
property appName : missing value
property restoreFrontmost : false
tell application id "com.apple.systemevents"
set appName to name of first process whose frontmost is true and background only is false
tell application process |Logic Pro|
if not (exists pop up button 1 of group 1 of group 2 of window windowName) then
set restoreFrontmost to true
perform action "AXRaise" of window windowName
set frontmost to true
perform action "AXPress" of menu bar item menuName of menu bar 1
delay 0.2
perform action "AXPress" of menu item menuCommand of menu menuName of menu bar item menuName of menu bar 1
end if
repeat until exists pop up button 1 of group 1 of group 2 of window windowName
delay 0.01
end repeat
if not (exists checkbox |Sends| of group 1 of group 1 of group 2 of window windowName) then
ignoring application responses
perform action "AXPress" of pop up button 1 of group 1 of group 2 of window windowName
end ignoring
end if
end tell
end tell
delay 0.1
do shell script "killall " & quoted form of |System Events|
delay 0.2
tell application id "com.apple.systemevents"
run
delay 0.2
tell application process |Logic Pro|
if not (exists checkbox |Sends| of group 1 of group 1 of group 2 of window windowName) then
perform action "AXPress" of menu item "Enable Patch Merging" of menu 1 of pop up button 1 of group 1 of group 2 of window windowName
delay 0.2
end if
if the value of checkbox |Sends| of group 1 of group 1 of group 2 of window windowName as boolean is true then
perform action "AXPress" of checkbox |Sends| of group 1 of group 1 of group 2 of window windowName
end if
if the value of checkbox |Audio Effects| of group 1 of group 1 of group 2 of window windowName as boolean is true then
perform action "AXPress" of checkbox |Audio Effects| of group 1 of group 1 of group 2 of window windowName
end if
end tell
end tell
if restoreFrontmost is true then tell application appName to activate
Notes:
Testing was done with Logic Pro X on a secondary Display while the script was executed from the primary Display.
If the Library in Logic Pro X is not showing, focus must be shifted to Logic Pro X, however it's restored to whatever was the frontmost application before focus was shifted. The shift is very brief and in my testing did not cause any issues. If the Library is already showing the focus stays where it's at the time the script is executed.
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional 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. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

Getting AppleScript to click button "+" and select "Language" and click Add

I am trying to automate via AppleScript the addition and the selection of a specific language in macOS Big Sur (for example Spanish) from System Preferences > Language & Region.
I can display the UI via this code, but I cannot get the "+" button to click.
tell application "System Preferences"
reveal anchor "Language" of pane id "com.apple.Localization"
activate
tell application "System Events"
tell window 1 of application process "System Preferences"
set i to 0
repeat until exists button 1 of group 1
delay 0.1
set i to i + 1
if i ≥ 30 then return
end repeat
-- # Click the [+] button.
click button 1 of group 1
end tell
end tell
end tell
The example AppleScript code, shown below, was tested in Script Editor under macOS Big Sur with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.
1 Assumes necessary and appropriate settings in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.
The value of the property thisLanguage needs to be set to that which will show in the list of the Select a preferred language to add: sheet, as it is set to the value of the text box on the Select a preferred language to add: sheet. This is necessary so AppleScript does not have to spend a lot of time searching the entire list as the target should now be it the top portion of the list.
Note that for, e.g., Español this script as is, is all that was necessary, however, on some languages one may get an additional sheet to reply to. For example, with 简体中文 (Simplified Chinese) one gets an additional Select input sources to add: sheet, and you will need to add additional code to handle it. You should be able to, from the example AppleScript code shown below, figure out how to deal with it as there is already an example therein.
Example AppleScript code:
property thisLanguage : "Español"
-- # Check to see if System Preferences is
-- # running and if yes, then close it.
-- #
-- # This is done so the script will not fail
-- # if it is running and a modal sheet is
-- # showing, hence the use of 'killall'
-- # as 'quit' fails when done so, if it is.
-- #
-- # This is also done to allow default behaviors
-- # to be predictable from a clean occurrence.
if running of application "System Preferences" then
try
tell application "System Preferences" to quit
on error
do shell script "killall 'System Preferences'"
end try
delay 0.1
end if
-- # Make sure System Preferences is not running before
-- # opening it again. Otherwise there can be an issue
-- # when trying to reopen it while it's actually closing.
repeat while running of application "System Preferences" is true
delay 0.1
end repeat
-- # Reveal the General tab of the Language
-- # & Region pane in System Preferences.
tell application "System Preferences"
reveal anchor "Language" of ¬
pane id "com.apple.Localization"
activate
end tell
-- # System Events handles the rest.
tell application "System Events"
launch
delay 0.2
tell application process "System Preferences"
-- # Click the [+] button.
click button 1 of group 2 of tab group 1 of window 1
-- # Wait for sheet 1 to be available.
set i to 0
repeat until exists text field 1 of sheet 1 of window 1
delay 0.1
set i to i + 1
if i ≥ 30 then return
end repeat
-- # Search for: thisLanguage
set the value of ¬
text field 1 of ¬
sheet 1 of ¬
window 1 to ¬
thisLanguage
delay 1 -- # May need to be increased.
-- # Get the row that matches thisLanguage.
set theTargetRow to ¬
the first row of ¬
table 1 of ¬
scroll area 1 of ¬
sheet 1 of ¬
window 1 whose value of ¬
static text 1 of ¬
UI element 1 is thisLanguage
-- # Select the row that matches thisLanguage.
select theTargetRow
-- # Click the Add button.
click button 3 of sheet 1 of window 1
-- # Wait for the sheet to change.
set i to 0
repeat until exists ¬
button "Use English (US)" of ¬
sheet 1 of window 1
delay 0.1
set i to i + 1
if i ≥ 30 then return
end repeat
-- # The button for thisLanguage
-- # should have focus, press enter.
keystroke return
end tell
end tell
delay 0.2
tell application "System Preferences" to quit
Notes:
The use of the launch command after tell application "System Events" is to try and help with a systemic issues in UI Scripting as a result of changes Apple had made in macOS Big Sur.
Also note that UI Scripting is often kludgy and prone to failure for a variety of reasons and why I have used the error handling that I have, however, one may need to add addition error handling and or delay commands and or adjust the value of existing ones, as needed.
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional 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. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

How to "Wait until web page loaded" in Firefox (applescript)?

This code from here works perfect, but doesn't work in Firefox. Why and how to fix it in applescript?
tell application "Google Chrome"
repeat until (loading of tab 1 of window 1 is false)
1 + 1 --just an arbitary line
end repeat
loading of tab 1 of window 1 --this just returns final status
end tell
As Firefox does not contain a specific AppleScript dictionary, e.g. Firefox.sdef file, it is not considered to be AppleScript scriptable in the same way as e.g. Google Chrome, and while it will respond to some of the basic commands, such as activate, quit, etc., it will require UI Scripting to do what you are asking.
The following example AppleScript code requires Firefox version 87 or newer, and setting its accessibility.force_disabled preference to: -1
First, in Firefox, in the Address/Search combo box, type about:config and press enter.
If applicable, click the Accept the Risk and Continue button.
In the Search preference name text box, type accessibility.force_disabled and press enter.
Click the Edit button and change its value to: -1
Click the the Save button.
Here is an example of how I would instruct Firefox to open a new window to a given URL and wait for the page to finish loading.
Example AppleScript code:
set theURL to "https://news.google.com/"
tell application "Firefox" to activate
delay 0.5 -- # Value may need to be adjusted if Firefox is closed.
my clickApplicationMenuCommand("Firefox", "File", "New Window")
delay 0.5
my setURLofFirefoxFrontWindowTo(theURL)
my waitForFirefoxPageToFinishLoading()
say "foobar"
-- # Handler(s) #
to clickApplicationMenuCommand(appName, appMenuName, appMenuCommand)
tell application appName to activate
delay 0.25
tell application "System Events" to ¬
click ¬
menu item appMenuCommand of ¬
menu appMenuName of ¬
menu bar item appMenuName of ¬
menu bar 1 of ¬
application process appName
end clickApplicationMenuCommand
to setURLofFirefoxFrontWindowTo(theURL)
tell application "System Events"
tell application process "Firefox"
set the value of UI element 1 of ¬
combo box 1 of toolbar "Navigation" of ¬
first group of front window to theURL
key code 36 -- # enter key
end tell
end tell
end setURLofFirefoxFrontWindowTo
to waitForFirefoxPageToFinishLoading()
-- # Requires Firefox version 87 or newer.
-- # Requires accessibility.force_disabled set to: -1
tell application "System Events"
tell application process "Firefox"
repeat until exists UI element "Reload" of ¬
toolbar "Navigation" of group 1 of window 1
delay 0.1
end repeat
repeat while (name of UI elements of ¬
toolbar "Navigation" of group 1 of ¬
window 1 whose description is "Reload") ¬
is not {"Reload"}
delay 0.1
end repeat
end tell
end tell
end waitForFirefoxPageToFinishLoading
Notes:
The example AppleScript code, shown above, was tested in Script Editor under macOS Catalina with Language & Region settings in System Preferences set to English (US) — Primary and worked for me without issue1.
1 Assumes necessary and appropriate settings in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.
Tested using Firefox version 91.0 (64-bit).
Note that UI Scripting is very kludgy and is prone to failure, especially as the version of the OS and or application change, or the value of the delay commands are not sufficient. That said however, with Firefox, this as described herein is what it takes.
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional 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. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

Notes export all as PDF

Ability to export all Notes in macOS Notes.app as PDFs.
execution error: Notes got an error: AppleEvent handler failed. (-10000)
Multiple scripts, latest below.
tell application "Notes"
activate
repeat with theFolder in every folder
repeat with theNote in every note of theFolder
tell application "System Events"
tell process "Notes"
set dockPrefs to dock preferences
set appearancePrefs to appearance preferences
delay 1
display dialog "Foo"
tell menu bar 1 of process "Notes"
click menu bar item "File"
click menu item "Export as PDF..." of menu "File" of menu bar of process "Notes"
end tell
click button "Save" of sheet 1 of window "Notes" of process "Notes"
delay 1
key code 125
end tell
end tell
end repeat
end repeat
end tell
execution error: Notes got an error: AppleEvent handler failed. (-10000)
There are a few problems in there:
You are already targeting the Notes process, so including that in
the click statements is adding another process target - use one or the other, but if you are
doing a lot of menu clicks you might look at using a general
purpose handler;
The export menu item uses an ellipse (a single character), not three
periods;
By placing a display dialog statement in the System Events tell statement, you are moving the focus away from the application.
Also note that the text field is selected and the save button is the default in the sheet, so you can use keystrokes instead of trying to click UI elements. A cleaned up example (tested in Mojave) would look something like:
tell application "Notes"
launch -- seems to work better than 'activate'
repeat with aFolder in folders
repeat with aNote in notes of aFolder
set noteName to (name of aNote)
try -- keep the name a reasonable length
set noteName to text 1 thru 20 of noteName
end try
tell (current date) to set timeStamp to text 2 thru -1 of (get (1000000 + (its hours) * 10000 + (its minutes) * 100 + (its seconds)) as text) -- hhmmss
tell application "System Events"
#display dialog noteName -- testing?
tell process "Notes"
set frontmost to true -- retarget the Notes app
delay 0.5
click menu item "Export as PDF…" of menu "File" of menu bar item "File" of menu bar 1
repeat until exists sheet 1 of window 1 -- wait for the sheet
delay 0.02
end repeat
end tell
keystroke noteName & "_" & timeStamp -- update the name, trying to avoid duplicates
delay 0.5
keystroke return -- dismiss the sheet
delay 0.5
key code 125
end tell
end repeat
end repeat
end tell

applescript copy paste between textedit and 3rd party application not working

I have searched all over this site and cannot find an answer to why this code isn't doing what I need it to do. I have a textedit doc with a list of numbers. I want to copy 1 number at a time paste that number into a 3rd party application at a specific place in url, and then hit some buttons in the ui of that application. I need this process to repeat for each individual number in the textedit document.
Here is what I came up with after researching applescript.
tell application "TextEdit" to activate
tell application "System Events"
tell process "TextEdit"
key code 124 using {shift down, command down}
keystroke "c" using command down
key code 125
end tell
end tell
delay 1.0
tell application "import.io" to activate
tell application "System Events"
tell process "import.io"
keystroke tab
keystroke tab
key code 124
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 123
key code 51
keystroke "v" using command down
keystroke tab
key code 76
end tell
end tell
-- Make a selection from the popupbutton.
delay 2.231426
set timeoutSeconds to 10.0
set uiScript to "click pop up button 1 of window \"Save\" of application process \"import.io\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
end run
on doWithTimeout(uiScript, timeoutSeconds)
set endDate to (current date) + timeoutSeconds
repeat
try
run script "tell application \"System Events\"
" & uiScript & "
end tell"
exit repeat
on error errorMessage
if ((current date) > endDate) then
error "Can not " & uiScript
end if
end try
end repeat
end doWithTimeout
-- Click the “<fill in title>” checkbox.
delay 1.496275
set timeoutSeconds to 10.0
set uiScript to "click checkbox 1 of window \"Save\" of application process \"import.io\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
-- Type “Data” into the text field.
delay 7.290406
set timeoutSeconds to 10.0
set uiScript to "click text field 1 of group 17 of list 1 of scroll area 1 of scroll area 1 of browser 1 of splitter group 1 of splitter group 1 of group 2 of window \"Save\" of application process \"import.io\""
keystroke "Data"
keystroke "."
tell application "System Events" to tell process "import.io"
keystroke "v" using command down
end tell
my doWithTimeout(uiScript, timeoutSeconds)
return input
-- Click the “Save” button.
delay 1.475013
set timeoutSeconds to 10.0
set uiScript to "click UI Element \"Save\" of window \"Save\" of application process \"import.io\""
my doWithTimeout(uiScript, timeoutSeconds)
return input
my textedit document is formatted like this:
50
100
150
200
etc
When I run the script this is what it does to my textedit document:
50
50
100
150
200
etc
Any idea what is going on here? I can't make heads or tails of it.
Looking for result in your TextEdit file, first you must start to simplify the textEdit copy part. I assumed that the TextEdit document is already open.
The script bellow provides simplification for copy part :
tell application "TextEdit"
activate
set myNumbers to every paragraph of front document
end tell
repeat with aNumber in myNumbers -- loop through each number
set the clipboard to aNumber
-- insert here the paste instructions in your third party application
end repeat
You must insert the instruction about the paste in the loop, after the 'set clipboard...' instruction which fills the clipboard with a number.
I can't help you for the paste part, because I don't know your third party application, however, your program calling other scripts in doWithTimeout routine does not seems to be very clean and efficient.
If this third party application is not scriptable, at least you may have to go via GUI scripting or java (if java based application).
For instance, instead of doing all the key arrows to move to correct input cell, try to address that cell directly by its GUI properties.
Same for the checkbox, you can also use GUI click function.
The disadvantage of GUI scripting is that application interface must not changed. But this is already the case in your script.

Resources