-
-
Save skempken/46c184c1a5eac2e88c9c31ce09a38300 to your computer and use it in GitHub Desktop.
use AppleScript version "2.4" -- Yosemite (10.10) or later | |
use framework "Foundation" | |
use framework "AppKit" | |
use scripting additions | |
tell application "System Settings" | |
activate | |
current application's NSWorkspace's sharedWorkspace()'s openURL:(current application's NSURL's URLWithString:"x-apple.systempreferences:com.apple.Displays-Settings.extension") | |
delay 0.5 | |
tell application "System Events" | |
tell process "System Settings" | |
key code 48 | |
key code 48 | |
key code 48 | |
key code 123 | |
delay 0.5 | |
-- activate hdr on left monitor | |
set hdr to checkbox 1 of group 3 of scroll area 2 of group 1 of group 2 of splitter group 1 of group 1 of window "Displays" of application process "System Settings" of application "System Events" | |
tell hdr | |
if value is 0 then click it | |
end tell | |
-- switch to right monitor by key navigation. Actions like "click" are not invocable on the buttons. | |
-- hit "tab" (key code 48) three times, it's the only way to be sure ;-) | |
-- hit "right" to select the right monitor | |
key code 124 | |
delay 0.5 | |
-- do it again | |
set hdr to checkbox 1 of group 3 of scroll area 2 of group 1 of group 2 of splitter group 1 of group 1 of window "Displays" of application process "System Settings" of application "System Events" | |
tell hdr | |
if value is 0 then click it | |
end tell | |
end tell | |
end tell | |
quit | |
end tell | |
@skempken so I tried to do your method. How do you know what to type here? set hdr to checkbox 1 of group 3 of scroll area 2 of group 1 of group 2 of splitter group 1 of group 1 of window "Displays" of application process "System Settings" of application "System Events"
I have figured out the code.
use framework "Foundation"
use framework "AppKit"
use scripting additions
tell application "System Settings"
activate
current application's NSWorkspace's sharedWorkspace()'s openURL:(current application's NSURL's URLWithString:"x-apple.systempreferences:com.apple.Displays-Settings.extension")
delay 1
tell application "System Events"
tell process "System Settings"
key code 48
delay 0.1
key code 48
delay 0.1
key code 49
delay 0.1
set hdr to checkbox 1 of group 3 of scroll area 2 of group 1 of group 2 of splitter group 1 of group 1 of window "Displays" of application process "System Settings" of application "System Events"
tell hdr
if value is 0 then click it
end tell
delay 0.1
key code 48
delay 0.1
key code 49
delay 0.1
set hdr to checkbox 1 of group 3 of scroll area 2 of group 1 of group 2 of splitter group 1 of group 1 of window "Displays" of application process "System Settings" of application "System Events"
tell hdr
if value is 0 then click it
end tell
end tell
end tell
quit
end tell
But it's very unreliable. Sometimes the search box gets activated and I get thrown an error. any idea why it goes there?
Do you think there’s a way to check if the search box is selected and do extra tab presses if it is?
Couple of points:
To figure out the sequence of keys needed to be pressed, you can open System Settings manually and navigate with your keyboard only to figure out what keypress leads to which effect. I've made the experience that this sequence is not always the same, however - some TABs (48) have been thrown in for good measure to be sure that the cursor jumps to the right pane with the displays. Also, depending on the initial (random) order of the displays, the sequence varies, too.
With regard to navigating the tree of controls (...group X of group Y...), you can have a look at it using the Accessibility Inspector tool (https://developer.apple.com/library/archive/documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXTestingApps.html). Also, I've found a script that prints the tree (and the corresponding group X of group Y sequences) to the console, which makes it a bit easier (but forgot to save the link...).
In principle, macOS' API allows for navigating controls directly by their accessibility keys (i.e., refer to them "by a name" instead of their position in a tree), but those keys have not been set in macOS display settings in particular, which is a shame and an omission at Apple's end.
All in all, AppleScript in my opinion is a lot of lost potential. The idea is great, and there are enough "power users" that would apply it, but I have yet to find a comprehensive tutorial and development approach, relying on copy-pasting code snippets found on the 'net instead. /rant
I think a better approach in general would be to somehow debug System Settings and figure out the exact (private) API call behind the HDR toggles and add the corresponding invocation to displayplacer itself.
Cool thanks for these. Will look into them. Yeah I want to figure out the exact api call, any idea how to go about finding it?
Yeah I want to figure out the exact api call, any idea how to go about finding it?
Unfortunately not. My best guess would be to attach a debugger to the running System Settings process and look through the call stack when clicking on the HDR toggle. But I've never done such a thing before.
I have this done in Swift here, using the private MonitorPanel.framework
: https://github.com/alin23/mac-utils#togglehdr
No need for scripting the UI anymore ^_^
I also provide it as an Apple Shortcut in 🌕 Lunar in case you already have that installed:
@alin23 awesome, thank you! I dumbed down your Swift script even a bit, so that it just activates HDR where applicable in a "fire & forget" fashion. This way, I can directly call it from the Shortcuts app. Works great.
You could also give a heads up to the displayplacer guys at jakehilborn/displayplacer#27, given that the one thing stopping them from adding HDR support to this tool is lack of a "known" API to control HDR settings.
I have this done in Swift here, using the private
MonitorPanel.framework
: https://github.com/alin23/mac-utils#togglehdrNo need for scripting the UI anymore ^_^
I also provide it as an Apple Shortcut in 🌕 Lunar in case you already have that installed:
How do I use your program? Do I have to compile it into a program?
If you know how to use the command-line, you can download the compiled binary and just run it:
bin="$HOME/.bin/ToggleHDR"
if [[ ! -d "$HOME/.bin" ]]; then
mkdir -p -m 0755 "$HOME/.bin"
fi
if [[ ! -f $bin ]]; then
curl -L https://raw.githubusercontent.com/alin23/mac-utils/main/bin/$(basename $bin) -o $bin;
chmod +x $bin;
fi
$HOME/.bin/ToggleHDR
Which will output something similar to:
ID UUID HDR Control Name
1 37D8832A-2D66-02CA-B9F7-8F30A301B230 false Built-in Liquid Retina XDR Display
2 3B300CA4-8F5F-4E77-A757-CFD72454C30A true LG Ultrafine
Usage: $HOME/.bin/ToggleHDR <id-uuid-or-name>
If you're not comfortable with the command-line, I advise downloading Lunar from https://lunar.fyi/ and using the Toggle HDR
action through Apple Shortcuts.
Here's an already made shortcut to get started:
Well, the adapted "fire & forget" version would still need to be compiled.
- install Xcode
- clone the repo (
git clone git@github.com:skempken/mac-utils.git
) - run
make
- find the binary in
./bin/EnableHDR
- create a Shortcut with a single Shell script action, running the binary from the previous step
- profit 😉
@alin23 your program does a toggle, i was wondering if it was possible to a force on, so if it was on, it would be left alone, but if it was off, it would be turned on.. is that possible?
@alin23 your program does a toggle, i was wondering if it was possible to a force on, so if it was on, it would be left alone, but if it was off, it would be turned on.. is that possible?
Yes, I just added that a few minutes ago. You can download the updated binary.
Well, the adapted "fire & forget" version would still need to be compiled.
- install Xcode
- clone the repo (
git clone git@github.com:skempken/mac-utils.git
)- run
make
- find the binary in
./bin/EnableHDR
- create a Shortcut with a single Shell script action, running the binary from the previous step
- profit 😉
how do i do this, his script requires the uuid of the monitor, so it needs an argument.
@alin23 your program does a toggle, i was wondering if it was possible to a force on, so if it was on, it would be left alone, but if it was off, it would be turned on.. is that possible?
Yes, I just added that a few minutes ago. You can download the updated binary.
Hi, sorry, the ToggleHDR binary still does a toggle action. Not force on.
@alin23 See here for the "fire & forget" mode binary, which just turns on HDR on all applicable monitors, no questions asked: https://github.com/skempken/mac-utils/blob/enableHDR/bin/EnableHDR
@skempken it works perfectly, do you mind sharing the code so that I can just save my UUID into the program and compile it?
@alin23 your program does a toggle, i was wondering if it was possible to a force on, so if it was on, it would be left alone, but if it was off, it would be turned on.. is that possible?
Yes, I just added that a few minutes ago. You can download the updated binary.
Hi, sorry, the ToggleHDR binary still does a toggle action. Not force on.
Most likely you haven't updated the binary. See below how it works:
Running without arguments (shows help)
> ToggleHDR
ID UUID Supports HDR HDR Enabled Name
1 37D8832A-2D66-02CA-B9F7-8F30A301B230 false false Built-in Liquid Retina XDR Display
2 3B300CA4-8F5F-4E77-A757-CFD72454C30A true false LG Ultrafine
Usage: ToggleHDR [id/uuid/name/all] [on/off]
Running with the on
argument (enables HDR for all displays)
> ToggleHDR on
ID UUID Supports HDR HDR Enabled Name
1 37D8832A-2D66-02CA-B9F7-8F30A301B230 false false Built-in Liquid Retina XDR Display
2 3B300CA4-8F5F-4E77-A757-CFD72454C30A true true LG Ultrafine
Enabling HDR for LG Ultrafine [ID: 2]
@skempken it works perfectly, do you mind sharing the code so that I can just save my UUID into the program and compile it?
See this PR alin23/mac-utils#5
I'd think so, but not out of the box. I have not yet tested it with three monitors (or two external displays and the MacBook itself), but one could figure this out by fiddling with the key codes (lines 13-16 and 29-30). They simulate TAB and cursor keys within the Ventura settings. See here for a complete reference table: https://gist.github.com/michaelgiraldo/c3ca98f06aeb20acae1fd8d82fab0811
AppleScript would, in principle, allow to manipulate the controls directly, but the displays settings is inaccessible in a literal sense - it does now offer addressable accessibility anchors so that I could directly toggle the particular controls.
Jumping around with cursor and TAB key presses is admittedly ugly and fragile, and I'd rather have a more robust way. I'm very open for ideas!