MacOS – Applescript to toggle “Announce the time:” in Sys Preferences

applescriptbig surmacossystem-prefs

I'm trying to toggle the "Announce the time:" checkbox on the "Dock & Menu Bar" pane of System Preferences (in Big Sur).

I've gotten this far:

tell application "System Preferences"
    activate
    reveal anchor "Clock" of pane id "com.apple.preference.dock" -- pane "Dock & Manu Bar"
    -- nothing I've tried here works
end tell
tell application "System Events"
    -- nothing I've tried here works
end tell

That reveals the correct pane with this checkbox:

enter image description here

I've tried using global coordinates with click at {x,y}, but that's ignored or I get a timeout error. (I'm able to click the buttons on the main Sys Prefs screen, so I know I have the coordinates correct.) I've also tried clicking the element named Announce the time:, but that didn't work either.

How can I toggle the Announce the time: checkbox?

Best Answer

Using Accessibility Inspector, a part of Xcode, it shows that some of the time the Announce the time: checkbox reports "Parent does not report element as one of its children" and as such will cause AppleScript code to fail under certain conditions, and under other conditions not fail. In other words, writing my own code I can get it to check that checkbox sometimes and not other times.

In trying to ascertain a pattern to see how to workaround this situation I came to the conclusion that using fully visible UI Scripting was the most reliable way. It's also unfortunately an ugly way and requires letting the script finish without interruption once started, otherwise it will fail for sure. Such are the pitfalls of fully visible UI Scripting.

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 setting in System Preferences > Security & Privacy > Privacy have been set/addressed as needed.

This script requires that the Use keyboard navigation to move focus between controls checkbox is checked on the System Preferences > Keyboard > Shortcuts tab, and as coded, the script checks its status and toggles the checkbox, as necessary, based on its current status.


Example AppleScript code:

--  # 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

--  # Get the fully qualified POSIX pathname of the target .plist file.

set thePropertyListFilePath to ¬
    the POSIX path of ¬
        (path to preferences from user domain as string) & ¬
    ".GlobalPreferences.plist"

--  # Get the value of AppleKeyboardUIMode to determine if the
--  # 'Use keyboard navigation to move focus between controls'
--  # checkbox is checked on the **System Preferences** >  
--  # **Keyboard** > **Shortcuts** tab.

tell application "System Events" to ¬
    tell the property list file thePropertyListFilePath to ¬
        set keyboardNavigation to the value of ¬
            the property list item "AppleKeyboardUIMode"

if keyboardNavigation = 0 then
    --  # Check the checkbox.
    my toggleKeyboardNavagition()
end if

--  # Open System Preferences to the Clock row of the Dock & Menu Bar pane.
--  # 
--  # This UI Script needs it to be visible, hence the activate command.

tell application "System Preferences"
    activate
    reveal anchor "Clock" of ¬
        pane id "com.apple.preference.dock"
end tell

delay 1

--  # Tab to the 'Announce the time:' checkbox and toggle it.

tell application "System Events"
    repeat 9 times
        key code 48 --  # tab key
        delay 0.2
    end repeat
    key code 49 --  # spacebar
    delay 0.1
end tell

if keyboardNavigation = 0 then
    --  # Uncheck the checkbox if it
    --  # was previously unchecked.
    my toggleKeyboardNavagition()
end if

delay 0.5

tell application "System Preferences" to quit


--  # Handler(s) #


--  # Toggles checkbox: 'Use keyboard navigation 
--  # to move focus between controls'

on toggleKeyboardNavagition()
    tell application "System Preferences"
        activate
        reveal anchor "shortcutsTab" of ¬
            pane id "com.apple.preference.keyboard"
    end tell
    tell application "System Events"
        tell front window of ¬
            application process "System Preferences"
            set i to 0
            repeat until (exists checkbox 1 of tab group 1)
                delay 0.1
                set i to i + 1
                if i ≥ 20 then return
            end repeat
            click checkbox 1 of tab group 1
        end tell
    end tell
end toggleKeyboardNavagition
  • Note that because of the comments and coding style the script is long. It ends with end toggleKeyboardNavagition, so make sure you highlight all of it when copying and pasting to Script Editor for testing.

Notes:

In the tell application "System Events" block in with there is the repeat 9 times loop that does the tabbing in order to toggle the Announce the time: checkbox, the value of the delay command may need to be adjusted.

If the normal state of the Use keyboard navigation to move focus between controls checkbox is unchecked, then do not run the script immediately back to back as it takes a second or two for the value of the property list item "AppleKeyboardUIMode" in the users global preferences file to update the change. I'm mentioning this mainly for when doing testing more so than when in normal production use, as it shouldn't be an issue then.


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.