AppleScript: How to identify checkbox location in System Preferences? - macos

I want to issue a keyboard command to toggle the checkbox "Change picture every 30 minutes" in OS X for Desktop 1 (my main monitor desktop). I have multiple monitors so it may be necessary to identify which particular preference pane to manipulate.
I have set up the start of an AppleScript, but I'm at a loss how to formulate how to identify this particular check box:
tell application "System Preferences"
activate
end tell
tell application "System Events"
tell process "System Preferences"
click menu item "Desktop & Screen Saver" of menu "View" of menu bar 1
delay 2
tell window "Desktop & Screen Saver"
click checkbox 1 of …

It's in tab group 1. You can recognize this with the help of the Xcode tool Accessibility Inspector (Xcode > Open Developer Tool > Accessibility Inspector in the menu bar or Dock).
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.desktopscreeneffect"
end tell
delay 2
tell application "System Events" to tell process "System Preferences"
click checkbox "Change picture:" of tab group 1 of window "Desktop & Screen Saver"
end tell

Related

How to programatically switch between touchbar layouts on MacOS?

System
M1 MacBook Pro
MacOS Big Sur
Problem
I like the default Mac touchbar layout for everyday use, but I prefer the F1-F12 keys at my fingertips when programming. I also don't like holding down the fn key. That's why I wrote two AppleScripts to switch the layouts (included below).
The scripts work, but they are buggy. This is because they rely on opening the System Preferences app and navigating through the menus. I made a couple "apps" with Automator
that simply run the scripts and then assigned them to keyboard shortcuts.
This is an ok solution, but I'd like to do something more elegant. Ideally, my script should run behind the scenes and instantly change the touchbar layout instead of opening System Preferences, selecting items from drop-down-lists, and then finally closing System Preferences.
I messed around with the shell for quite awhile with no success before resorting to using Automator. Any suggestions from those who are more savvy with sort of thing?
Code
This one makes the F1-F12 keys the default touchbar layout:
tell application "System Preferences"
set the current pane to pane id "com.apple.preference.keyboard"
delay 0.25
reveal anchor "keyboardTab" of pane "com.apple.preference.keyboard"
end tell
tell application "System Events"
tell process "System Preferences"
click pop up button 2 of tab group 1 of window "Keyboard"
end tell
end tell
tell application "System Events"
tell process "System Preferences"
click menu item "F1, F2, etc. Keys" of menu 1 of pop up button 2 of tab group 1 of window "Keyboard"
end tell
end tell
tell application "System Events"
tell process "System Preferences"
click pop up button 4 of tab group 1 of window "Keyboard"
end tell
end tell
tell application "System Events"
tell process "System Preferences"
click menu item "Show App Controls" of menu 1 of pop up button 4 of tab group 1 of window "Keyboard"
end tell
end tell
quit application "System Preferences"
And this one does the reverse (makes app controls the default touchbar layout):
tell application "System Preferences"
set the current pane to pane id "com.apple.preference.keyboard"
delay 0.25
reveal anchor "keyboardTab" of pane "com.apple.preference.keyboard"
end tell
tell application "System Events"
tell process "System Preferences"
click pop up button 2 of tab group 1 of window "Keyboard"
end tell
end tell
tell application "System Events"
tell process "System Preferences"
click menu item "App Controls" of menu 1 of pop up button 2 of tab group 1 of window "Keyboard"
end tell
end tell
tell application "System Events"
tell process "System Preferences"
click pop up button 4 of tab group 1 of window "Keyboard"
end tell
end tell
tell application "System Events"
tell process "System Preferences"
click menu item "Show F1, F2, etc. Keys" of menu 1 of pop up button 4 of tab group 1 of window "Keyboard"
end tell
end tell
quit application "System Preferences"
On macOS Catalina when toggling the target setting it changes the value of the PresentationModeGlobal key in ~/Library/Preferences/com.apple.touchbar.agent.plist from appWithControlStrip to functionKeys or vise versa for those two choices. However, toggling it programmatically using the defaults command while it changes it in the UI it does not change it on the Touch Bar without also restarting the ControlStrip process.
The following example shell script code is what I use with a single keyboard shortcut to toggle between between Show App Controls and F1, F2, etc. Keys as that is what they are set to respectively in System Preferences > Keyboard > Keyboard on my system.
Example shell script code:
#!/bin/zsh
pmg="$(defaults read com.apple.touchbar.agent 'PresentationModeGlobal')"
if [[ $pmg == "appWithControlStrip" ]]; then
defaults write com.apple.touchbar.agent 'PresentationModeGlobal' 'functionKeys'
killall "ControlStrip"
else
defaults write com.apple.touchbar.agent 'PresentationModeGlobal' 'appWithControlStrip'
killall 'ControlStrip'
fi
Notes:
Other versions of macOS may require additional settings to be changed and or additional processes to be restarted, e.g., pkill 'Touch Bar agent' if applicable.
In Terminal you can use the read verb of the defaults command to examine changes to com.apple.touchbar.agent.plist as you make them in the UI to see if the value for additional keys needs to be changed too.
Side Note
As to your AppleScript code, here is how I'd do it based on your code as a single script to toggle between the two choices.
You didn't say what version of macOS are you running and since I do not have a pop up button 4 I cannot test the example AppleScript code shown below, however, this should eliminate having two separate scripts and it just toggles between the two with a single keyboard shortcut.
Example AppleScript code:
tell application "System Preferences"
set the current pane to pane id "com.apple.preference.keyboard"
delay 0.25
reveal anchor "keyboardTab" of pane "com.apple.preference.keyboard"
end tell
tell application "System Events"
tell tab group 1 of window 1 of process "System Preferences"
if value of pop up button 2 is "Show App Controls" then
click pop up button 2
click menu item "F1, F2, etc. Keys" of menu 1 of pop up button 2
click pop up button 4
click menu item "Show App Controls" of menu 1 of pop up button 4
else
click pop up button 2
click menu item "Show App Controls" of menu 1 of pop up button 2
click pop up button 4
click menu item "F1, F2, etc. Keys" of menu 1 of pop up button 4
end if
end tell
end tell
quit application "System Preferences"
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.

Enable Voice Control. AppleScript

I try to create an Apple Script to Enable Voice Control in a Mac.
This is in: System Preferences > Accessibility > Voice Control > Enable Voice Control
I think I get close. But I do not know how to call the left menu "Voice control"
This is what I have tried and do not work:
tell application "System Events"
click checkbox "Enable Voice Control" of window "Voice Control" of window "Accessibility" of application process "System Preferences" of application "System Events"
end tell
You asked in the comments if there was another way to get the solution. Here's a way to revise your code. First, I will explain the solution, step by step.
Update: This if statement, as pointed out in user3439894's very helpful comments below, is actually necessary, for several reasons. It should always be included.
if running of application "System Preferences" then
quit application "System Preferences"
delay 1
end if
This is done so the script will not fail if it is running. Note that the user also pointed out that killall should be used to ensure that the process completely terminates.
It allows for predictability in the behavior of the application.
user3439894 also pointed out that I should add this code block, in case there is a timing issue, resulting in the application trying to reopen while it is in the process of closing.
repeat while running of application "System Preferences" is true
delay 0.1
end repeat
Next, in this snippet, you click the Accessibility button in System Preferences
tell application "System Events"
click button "Accessibility" of scroll area 1 of window 1 of process "System Preferences" -- click the Accessibility button
delay 2 -- while loads
Next, you select the Voice Control row in Settings.
select row 13 of table 1 of scroll area 1 of window 1 of process "System Preferences"
delay 0.2 -- delay while page loads
And finally, click the checkbox. As I explained in the comments, groups are used to organize elements.
click checkbox "Enable Voice Control" of group 1 of window 1 of process "System Preferences"
end tell
Full (updated) code:
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
repeat while running of application "System Preferences" is true
delay 0.1
end repeat
activate application "System Preferences"
tell application "System Events"
click button "Accessibility" of scroll area 1 of window 1 of process "System Preferences" -- click the Accessibility button
delay 2.0 -- delay while page loads
select row 13 of table 1 of scroll area 1 of window 1 of process "System Preferences"
delay 0.2 -- delay while page loads
click checkbox "Enable Voice Control" of group 1 of window 1 of process "System Preferences"
end tell
Corrections I made to your code:
You cannot reference elements from windows that are not already opened in an app (like you did with the checkbox "Enable Voice Control" of window "Voice Control" of window "Accessibility"), so first I opened the Accessibility window (click a button) -> Voice Control Window (select the row), and then found/clicked the checkbox.
Then, I looked at the hierarchy of the elements to figure out where the checkbox is in that Voice Control Window. I found out that it is inside group 1 of window 1 (Voice Control Window), so I clicked it.
I also added delays (the app needs time to load after every click/select).
Also, here is how I figured out where the elements are.
If you don't already use it, there is this built-in app called Accessibility Inspector to help you locate elements.
You can also use get in applescript. For example,
tell application "System Events"
get buttons of scroll area 1 of window 1 of process "System Preferences"
end tell
would return:
... button "Accessibility" of scroll area 1 of window "System Preferences" of application process "System Preferences" of application "System Events", button "Screen Time" of scroll area 1 of window "System Preferences" of application process "System Preferences" of application "System Events",...
Another example:
tell application "System Events"
get UI elements of window 1 of process "System Preferences"
end tell
and here's some of the output
...scroll area 1 of window "System Preferences" of application process "System Preferences" of application "System Events", toolbar 1 of window "System Preferences" of application process "System Preferences" of application "System Events..."
A very helpful tool.

Toggle fn keys with Applescript in macOS Catalina

I'm trying to create an Automation Shortcut that toggles the fn keys in the Touch Bar.
This is my approach so far:
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.keyboard"
//TO-DO: script that opens drop down menu in settings and changes it to display fn buttons
end tell
This is the code that i use for Catalina OS:
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.keyboard"
reveal anchor "keyboardTab" of pane id "com.apple.preference.keyboard"
end tell
tell application "System Events" to tell process "System Preferences"
delay 0.3
set thePopUp to pop up button 2 of tab group 1 of window "Keyboard"
set current to value of thePopUp
click thePopUp
if current is equal to "F1, F2, etc. Keys" then
click menu item 1 of menu 1 of thePopUp
else
click menu item 3 of menu 1 of thePopUp
end if
end tell
quit application "System Preferences"
For anyone else trying to make this work - I've finally gotten my solution to work. Tested with: MacOS Big Sur, 11.4, June 2021
The code is based here:
https://github.com/MrSimonC/Toggle-Mac-Function-Keys
but for brevity, here is the contents of the apple script file:
-- Apple Script (i.e. Use in Apple's Script Editor Application) to Toggle Function Keys / Media keys on/off
-- Tested on MacOS Big Sur (11.4) June 2021
-- Project Path: https://github.com/MrSimonC/Toggle-Mac-Function-Keys
tell application "System Preferences"
set current pane to pane "com.apple.preference.keyboard"
end tell
tell application "System Events"
if UI elements enabled then
tell application process "System Preferences"
repeat until exists tab group 1 of window "Keyboard"
delay 0.5
end repeat
click radio button "Keyboard" of tab group 1 of window "Keyboard"
click checkbox "Use F1, F2, etc. keys as standard function keys" of tab group 1 of window "Keyboard"
end tell
tell application "System Preferences" to quit
else
-- GUI scripting not enabled. Display an alert
tell application "System Preferences"
activate
set current pane to pane "com.apple.preference.security"
display dialog "UI element scripting is not enabled. Please activate this app under Privacy -> Accessibility so it can access the settings it needs."
end tell
end if
end tell
Hope someone finds it useful!
Simon.

How to click a checkbox of a drop-down tab in System Preferences

I'm trying to make an AppleScript to change an option in System Preferences. The checkbox is revealed by clicking "Mouse Options..." in the "Mouse and Trackpad" menu of the "Accessibility" pane. The script I have written so far is able to navigate through System Preferences so that the desired checkbox is visible to be clicked. However, I can't find a way to click the checkbox, seemingly because the checkbox is within a sort of 'drop down tab' on the window. None of the tutorials I have found online deal with this specific issue.
My code so far-
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.universalaccess"
get the name of every anchor of pane id "com.apple.preference.universalaccess"
reveal anchor "Mouse" of pane id "com.apple.preference.universalaccess"
tell application "System Events" to tell process "System Preferences"
click button 5 of window "Accessibility"
end tell
end tell
The desired checkbox is "Scrolling". I expected that the following code would work, but it does not- it clicks checkboxes in the background, not the one in the tab.
tell application "System Events" to tell process "System Preferences"
click checkbox 1 of window "Accessibility"
end tell
This is my first time using AppleScript, I should mention. Any help would be much appreciated.
The 'drop down tab' is called a sheet:
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.universalaccess"
reveal anchor "Mouse" of pane id "com.apple.preference.universalaccess"
tell application "System Events" to tell process "System Preferences"
click button 5 of window 1
click checkbox 1 of sheet 1 of window 1
end tell
end tell

Use AppleScript to change System Preferences without being visible?

I would like to change settings in System Preferences without the user seeing things happen.
If I have a script that starts like:
tell application "System Preferences"
activate
set current pane to pane "com.apple.preference.sound"
end tell
the System Preference window will be shown to the user.
I'd like to know if there is a way to do it in the background somehow, or at least keep the window minimized.
(Example script can be found in this question.)
You can just remove the activate command. System Events can perform actions in hidden windows.
tell application "System Preferences"
reveal anchor "keyboardTab" of pane "com.apple.preference.keyboard"
end tell
tell application "System Events" to tell process "System Preferences"
click checkbox 1 of tab group 1 of window 1
end tell
quit application "System Preferences"
If you open menus, they will be visible though.
tell application "System Preferences"
reveal anchor "TTS" of pane "com.apple.preference.speech"
end tell
tell application "System Events" to tell process "System Preferences"
tell pop up button 1 of tab group 1 of window 1
delay 0.1
click
if value is "Alex" then
click menu item "Kathy" of menu 1
else
click menu item "Alex" of menu 1
end if
end tell
end tell
quit application "System Preferences"
The brightness of displays can also be changed with brightness.c.
You might be able to do what you want with with the command line app defaults, there are some other command line apps that can manipulate other system stuff also like, pmset
Some things can be set using scripting additions also, for example the systems volumn can be set using the standard additions, you also you may be able to find other scripting additions to add more stuff.

Resources