Programmatic change macOS Mojave accent color - cocoa

I'm writing an app that allows user to set the accent color of the macOS Mojave.
My first attempt was using AppleScript. But I realized that the API is not up to date yet:
The underlined API works, but it only has 2 color options, while the new OS has 8.
I'm wondering if there is any workaround. Language is not limited, as long as it works. Thanks.

Here is a complete AppleScript solution which allows the user to choose light or dark mode, highlight colors, and accent colors. If the user chooses “Other” in the highlight color options, the script may throw an error because I did not define any actions for that option (figuring that part may be a good process for you to learn and figure out on your own)
property appearanceMode : {"Light", "Dark"}
property accentColors : {"Blue", "Purple", "Pink", "Red", "Orange", "Yellow", "Green", "Graphite"}
property highlightColors : {"Blue", "Purple", "Pink", "Red", "Orange", "Yellow", "Green", "Graphite", "Other"}
set chosenAppearanceMode to (choose from list appearanceMode ¬
with title "Please Choose Your Accent Color" with prompt ¬
"Please Choose Your Accent Color" OK button name ¬
"OK" cancel button name "CANCEL") as string
set chosenAccentColor to (choose from list accentColors ¬
with title ¬
"Please Choose Your Accent Color" with prompt ¬
"Please Choose Your Accent Color" OK button name ¬
"OK" cancel button name "CANCEL") as string
set chosenHighlightColor to (choose from list highlightColors ¬
with title ¬
"Please Choose Your Highlight Color" with prompt ¬
"Please Choose Your Highlight Color" OK button name ¬
"OK" cancel button name "CANCEL") as string
tell application "System Preferences"
reveal anchor "Main" of pane id "com.apple.preference.general"
end tell
tell application "System Events"
repeat until exists of checkbox chosenAppearanceMode of window "General" of application process "System Preferences"
delay 0.1
end repeat
-- Appearance
click checkbox chosenAppearanceMode of window "General" of application process "System Preferences"
-- Accent Color
click checkbox chosenAccentColor of window "General" of application process "System Preferences"
-- Dropdown Menu For Highlight Color
click pop up button 1 of window "General" of application process "System Preferences"
-- Highlight Color
click menu item chosenHighlightColor of menu 1 of pop up button 1 of window "General" of application process "System Preferences"
end tell
tell application "System Preferences" to quit

Related

Mac OSX11 (BigSur) - changing Region / Country (locale) via appleScript

I need to automate the change of locale (Region/Country) for format purpose from:
Region: Americas
Country: United States
to
Region: Europe
Country: Spain
So I have the following code, which seems to work up to the point where the system asks to restart the machine (or not).
property theSettings : {"", ""}
set settings1 to {"Americas", "United States"}
set settings2 to {"Europe", "Spain"}
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
tell application "System Preferences"
reveal anchor "Language" of ¬
pane id "com.apple.Localization"
activate
end tell
tell application "System Events"
tell window "Language & Region" of process "System Preferences"
if (value of pop up button "Region:" of tab group 1) is "United States" then
set theSettings to settings2
else
set theSettings to settings1
end if
set {theRegion, theCountry} to theSettings
tell pop up button "Region:" of tab group 1
delay 0.25
click
delay 0.25
click menu item theRegion of menu 1
delay 0.25
click menu item theCountry of menu 1 of menu item theRegion of menu 1
end tell
end tell
delay 1
tell application "System Preferences" to quit
tell sheet 1 of window "Language & Region" of process "System Preferences"
delay 1
keystroke tab
delay 1
keystroke return
end tell
end tell
In the script above, after switching locale, I am trying to click the button Don't Restart. But this does not work as the sheet window does not seem to be active.
Any idea on how to save the settings?
This issue is, at that point the sheet is modal and typically requires physical intervention. In other words, based on its current appearance, normally one would either press enter/return key to accept the default or use the mouse to click either Don’t Restart or Cancel as tabbing in not active by default in this use case.
However, if the [√] Use keyboard navigation to move focus between controls checkbox in System Preferences > Keyboard > Shortcuts is checked, which it is not by default, then one could simply press the space bar as Don’t Restart would have focus even though Restart Now would be, by default, solid blue.
To get past the modality of the situation, one would have to add code that would programmatically check to see that the aforementioned checkbox is checked, and if not check it.
In addition to the check and taking action if necessary, the modifications to your existing code are as follows:
In between:
repeat while running of application "System Preferences" is true
delay 0.1
end repeat
And:
tell application "System Preferences"
reveal anchor "Language" of ¬
pane id "com.apple.Localization"
activate
end tell
Add:
-- # 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 toggleKeyboardNavigation()
end if
And to the end of the script add:
-- # Handler #
-- # Toggles checkbox: 'Use keyboard navigation
-- # to move focus between controls'
on toggleKeyboardNavigation()
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 ≥ 30 then return
end repeat
click checkbox 1 of tab group 1
end tell
end tell
end toggleKeyboardNavigation
After making the aforementioned changes, then starting with:
tell application "System Preferences" to quit
Replace it and the ensuing tell block with:
ignoring application responses
tell application "System Preferences" to quit
end ignoring
delay 1
key code 49 -- # space key
Then after the end tell of the primary tell application "System Events" block, the one just below the previous code change, add the following:
repeat while running of application "System Preferences" is true
delay 0.1
end repeat
if keyboardNavigation = 0 then
-- # Uncheck the checkbox if it
-- # was previously unchecked.
my toggleKeyboardNavigation()
delay 0.2
tell application "System Preferences" to quit
end if
Notes:
The example AppleScript code shown herein to check to see if [] Use keyboard navigation to move focus between controls in System Preferences > Keyboard > Shortcuts is checked, can be done differently by opening to that pane and ascertaining whether of not it's checked and act accordingly. The reason I've added the code for it as is, is because I've used it to reset that checkbox later on in the script in the past. If the checkbox is already checked then one doesn't have to see the extra changing of panes.

How to take user voice input in applescript

I want to be able to take in input from the user in a program and have them speak it instead of type it into a text box. Is there any way to do this?
Any help would be appreciated.....
If you change the shortcut used to start dictation (System Preferences > Keyboard > Dictation > Shortcut) to either Press Left Command Key Twice or Press Either Command Key Twice, you can trigger this shortcut using System Events (provided the necessary accessibility privileges are granted):
delay 0.1
tell application "System Events" to repeat 2 times
key down command
key up command
end repeat
Alternatively, you can trigger the menu item:
tell application "System Events" to tell ¬
(the first process whose frontmost is true) to tell ¬
menu bar 1 to tell ¬
menu bar item "Edit" to tell ¬
menu "Edit" to tell ¬
menu item "Start Dictation" to ¬
if exists then click it
Edited to correct the referencing of the menu item chain, as highlighted by #wch1zpink, which previously prevented it working in *Google Chrome*.
#CJK really deserves the vote love, as this is only an adjusted extension of his thorough answer...
As taken from #CJK 's solution...
"Alternatively, you can trigger the menu item:"
tell application "System Events" to tell ¬
(the first process whose frontmost is true) to tell ¬
menu bar 1 to tell ¬
menu "Edit" to tell ¬
menu item "Start Dictation" to ¬
if exists then click it
Worked in almtost every application I tested the above code with... It did not work in Google Chrome.
However, this minor adjustment to his original code, Will work in Google Chrome.
tell application "System Events" to tell (the first process whose frontmost is true)
tell menu bar 1 to tell menu bar item "Edit"
tell menu "Edit"
try
click menu item "Start Dictation"
end try
end tell
end tell
end tell
For either of these solutions to actually "Enable Dictation" the mouse cursor must be in a field which allows text input, before the code is run.

Using AppleScript In Adobe Acrobat PRO DC to Reduce File Size

I am trying to use AppleScript to open a PDF in Adobe Acrobat Pro and reduce the file size using the "Reduce File Size" option when saving the file.
Trying to click this element
Which, according to Accessibility Inspector, has the following hierarchy:
Accessibility Inspector Image
My first step was tracking down all the elements in the window with set allElem to entire contents of window "Save As PDF". The output suggests this element is not a button or checkbox:
group "Reduce File Size" of group " My Computer " of UI element 1 of group 1 of group 1 of window "Save As PDF" of application process "AdobeAcrobat" of application "System Events"
static text "Reduce File Size" of group 1 of group "Reduce File Size" of group " My Computer " of UI element 1 of group 1 of group 1 of window "Save As PDF" of application process "AdobeAcrobat" of application "System Events"
text field 1 of static text "Reduce File Size" of group 1 of group "Reduce File Size" of group " My Computer " of UI element 1 of group 1 of group 1 of window "Save As PDF" of application process "AdobeAcrobat" of application "System Events"
group 1 of group "Reduce File Size" of group " My Computer " of UI element 1 of group 1 of group 1 of window "Save As PDF" of application process "AdobeAcrobat" of application "System Events"
Without a button to click, I tried getting around the issue by sending keystrokes to the window.
tell window "Save As PDF"
activate
keystroke tab
keystroke tab
keystroke tab
keystroke tab
delay 1
key code 36 --return key
end tell
But the window "Save As PDF" does not appear to be coming to the front; therefore, the keystrokes are not registering to that particular window.
Similarly
tell group "Reduce File Size" of group " My Computer " of UI element 1 of group 1 of group 1 of window "Save As PDF" of application process "AdobeAcrobat" of application "System Events"
set {xPosition, yPosition} to position
set {xSize, ySize} to size
click at {xPosition + (xSize div 2), yPosition + (ySize div 2)}
end tell
doesn't work because the click event is not occurring in the "Save As PDF" window for some reason.
So now I'm wondering two things:
Is there actually a button or checkbox that I can click (am I somehow missing something with the available click events, e.g. can you send a click event to the static text?).
Why are the keystrokes and click events not registering in the window?
After a lot of trial and error, it appears as though activate window "Save As PDF" was not truly activating the window. Ultimately, user495470's answer solved my issue.
tell application "System Events" to tell process "Acrobat Pro"
perform action "AXRaise" of window "Save As PDF"
end tell
set frontmost to true
This finally brought Adobe Acrobat to the front window AND activated it. Before, all my keystrokes or clicks were registering in the Script Editor window (or terminal window if I ran if from there), instead of the "Save As PDF" window.
The final code now becomes
tell application "System Events"
tell process "Acrobat Pro"
delay 1
click menu item "Save As..." of menu "File" of menu bar 1
delay 2
--Bring "Save As PDF" window to front
tell application "System Events" to tell process "Acrobat Pro"
perform action "AXRaise" of window "Save As PDF"
end tell
set frontmost to true
--Tab 4 times To Select Checkbox
delay 0.5
keystroke tab
keystroke tab
keystroke tab
keystroke tab
key code 36 --return key
delay 0.5
--Tab 4 times to select "Choose Different Folder..." button
keystroke tab
keystroke tab
keystroke tab
keystroke tab
key code 36 --return key
delay 0.5
end tell
end tell
It's not exactly elegant, but it works. I'm still surprised that clicking the "Choose Different Folder..." was not achieved through:
Click Button "Choose Different Folder..." of group 2 of UI element 1 of group 1 of group 1 of window "Save As PDF"

change screen resolution with AppleScript

I am trying to click at radio buttons in Displays panel of System Prefernces, namely to change Screen resolution. This is the code I use to identify radio buttons:
tell application "System Preferences"
activate
reveal anchor "displaysDisplayTab" of pane id "com.apple.preference.displays"
end tell
tell application "System Events"
tell application process "System Preferences"
set frontmost to true
get every radio button of window 0
--click button 1 of window 0 of application process "System Preferences" of application "System Events"
--click radio button "Scaled" of radio group of window "com.apple.preference.displays"
end tell
end tell
The radio buttons returned are none. Based on what I see, window has zero radio buttons. This leads to a conclusion that radio buttons are part of sub window, namely the Displays subwindow and not the main window. How can I navigate to this "subwindow" and click radiobuttons?
The radio buttons are part of the radio group. The radio group is part of the tab group.
Here's the script:
tell application "System Preferences"
activate
reveal anchor "displaysDisplayTab" of pane id "com.apple.preference.displays"
end tell
tell application "System Events"
tell application process "System Preferences"
set frontmost to true
tell tab group 1 of window 1
click radio button 2 of radio group 1 -- "Scaled"
select row 2 of table 1 of scroll area 1 -- select the second row in the table to change the resolution of the monitor
end tell
end tell
end tell
For Mac OS 10.15, you'll need this instead.
Set 'q' to the display button preference you want (1-4)
set tabNum to q as number
tell application "System Preferences" to reveal pane "com.apple.preference.displays"
tell application "System Events" to tell process "System Preferences"
set activeWindow to window 1
repeat until exists activeWindow
end repeat
set tabGroup to tab group 1 of activeWindow
tell tabGroup to click radio button "Scaled"
set subGroup to group 1 of tabGroup
set radioGroup to radio group 1 of subGroup
tell radioGroup to click radio button tabNum
--log activeWindow
--delay 0.5
tell application "System Preferences"
quit
end tell
end tell

Applescript getting elements

This SO answer pointed me a bit further in scripting the change of screen resolution on the new MacBook Retina. I'm stuck here:
I can arrive to this pane with this script:
tell application "System Preferences"
activate
set the current pane to pane id "com.apple.preference.displays"
reveal anchor "displaysDisplayTab" of current pane
get elements of current pane
tell application "System Events"
end tell
--get the name of every anchor of current pane
end tell
But how to know how to select bits if this pane contents? How to refer to the "Scale" radio button, for instance, and select one of the 5 possible resolutions? Thanks
I found this piece of AppleScript that apparently retrieves every UI element available in a Window:
tell application "System Events"
tell process "Process Name"
set visible to true
return every UI element of front window
return name of every UI element of front window
end tell
end tell
(Haven't tested myself yet. Found here.)
Image to tell you what radio button number you need for property: _MS on line 7
use sys : application "System Events"
use prefs : application "System Preferences"
property prefsUI : a reference to process "System Preferences"
property _W : a reference to windows of prefsUI
property _DD : a reference to radio button "Default for display" of radio group 1 of tab group 1 of _W
property _SD : a reference to radio button "Scaled" of radio group 1 of tab group 1 of _W
property _MS : a reference to radio button 4 of radio group 1 of group 2 of tab group 1 of _W
property pane : "com.apple.preference.displays"
property anchor : "displaysDisplayTab"
property tab : anchor (my anchor) of pane id (my pane)
set defaultDisplay to null
if tab ≠ (reveal tab) then return null
tell _DD to if exists then set defaultDisplay to its value as boolean
if defaultDisplay is false then
click _DD
else
click _SD
click _MS
end if
quit prefs
The script alternates between Default Resolution and "Most Space" Resolution depending on which is currently active.

Resources