Skip to content

Instantly share code, notes, and snippets.

@skempken
Last active May 11, 2023 00:48
Show Gist options
  • Save skempken/46c184c1a5eac2e88c9c31ce09a38300 to your computer and use it in GitHub Desktop.
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
@anarchy89
Copy link

anarchy89 commented Feb 15, 2023

@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?

@skempken
Copy link
Author

skempken commented Feb 17, 2023

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.

@anarchy89
Copy link

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?

@skempken
Copy link
Author

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.

@alin23
Copy link

alin23 commented Mar 18, 2023

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:

toggle hdr shortcut

@skempken
Copy link
Author

skempken commented Mar 18, 2023

@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.

EnableHDR.swift

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.

@anarchy89
Copy link

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:

toggle hdr shortcut

How do I use your program? Do I have to compile it into a program?

@alin23
Copy link

alin23 commented Mar 18, 2023

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:

add to shortcuts button

@skempken
Copy link
Author

skempken commented Mar 18, 2023

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 😉

@anarchy89
Copy link

@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
Copy link

alin23 commented Mar 20, 2023

@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.

@anarchy89
Copy link

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.

@anarchy89
Copy link

@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.

@skempken
Copy link
Author

skempken commented Mar 20, 2023

@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

@anarchy89
Copy link

@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
Copy link

alin23 commented Mar 20, 2023

@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
Copy link
Author

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment