Script to change screen resolution with UI scripting (no cscreen)

I looked and looked, but every example of changing screen resolution with UI scripting ended up with someone posting a link to cscreen instead. …and all of those links seem to be broken today.

I have finally figured out how to do it with UI scripting instead; no cscreen download necessary. I’m posting it here just in case anyone else comes looking for results without cscreen.

--Open System Preferences and switch to the Displays preference pane
tell application "System Preferences"
	activate
	set current pane to pane "com.apple.preference.displays"
end tell


tell application "System Events"
	
	--Make sure we are on the "Displays" tab (as opposed to "Arrangement" or "Color")
	click radio button "Display" of tab group 1 of window 1 of process "System Preferences"
	
	--Set the resolution to whatever is in row 2 for the primary display;
	select row 2 of table 1 of scroll area 1 of group 1 of tab group 1 of window 1 of process "System Preferences"
	
	--Change "row 2" to whatever row you want; change "window 1" to "window 2" for a secondary display;
	--So.
	(*
	select row 1 of table 1 of scroll area 1 of group 1 of tab group 1 of window 2 of process "System Preferences"
	*)
	--.would select the first row on the second window (the second window being settings for a secondary display).
	
	--Replace 'window 1' with 'window "Color LCD"' or whatever the window's title is to change a specific device
	--So.
	(*
	select row 1 of table 1 of scroll area 1 of group 1 of tab group 1 of window "VK246" of process "System Preferences"
	*)
	--.would would change settings for "VK246," regardless of whether it is the primary or secondary display.
	
	
end tell

--Finally, quit System Preferences again.
tell application "System Preferences"
	quit
end tell


Hi.

If you’re interested, you can open the “Display” tab directly like this:

--Open System Preferences on the Displays->Display tab
tell application "System Preferences"
	reveal anchor "displaysDisplayTab" of pane "com.apple.preference.displays"
	activate
end tell


tell application "System Events"

	--etc.

On my Snow Leopard machine, having the ‘reveal anchor’ line before ‘activate’ makes System Preferences appear with the tab already open.

This gets a little more elaborate if you have two screens as I have. Then there are two windows opened whose titles are the screens involved (e.g., in my case “iMac” and “Syncmaster”). The screen without the title bar is window 2 of the panes shown. That’s the only one I ever change.

Hi, Adam.

I’m not clear where your comment’s directed. Are you saying my ‘reveal anchor’ suggestion doesn’t work with multiple monitors? Or are you referring to the process as a whole?

Your part works perfectly, Nigel; I was commenting on the UI Scripting portion where identifying the screen you’re working with becomes important because the main (menu) screen is window 1 and a second monitor will be window 2.

Sorry for the delay answering, btw – I’m not home.

Thanks, Adam.

The comments in the middle of iynque’s script do mention a second monitor. I presume he’s tested the code he suggests.

No problem. I hope you’re somewhere nice. :slight_smile:

This post was dead useful for me. Figuring out UI scripting is always easiest if someone else does it for you =]

I’ve got a slightly modified version that works as a toggle, so run it a second time and it reverts to your original setting. Using a fragile method, but it works…


-- This is here to make it work like a toggle.
-- I couldn't find a way to query the table to
-- see what is selected, so this a hack.
property runCount : 1

-- You add lists to this list to control the toggle values for each display. So with a value of {1,10},
-- 1 is the row number in system preferences of its native resolution, and 10 is the row 
-- number of the resolution that it will toggle to. You can add more to it, eg {1, 10, 12}, this 
-- will give you three toggle states.
-- The default setting of {{1, 10}, {1, 12}} is because I have 2 displays. delete one list if you only
-- have one. Add another if you have three.
-- Work out the values you want by counting the rows in the resolution table in displays
-- in system preferences.
property rowNumberList : {{1, 10}, {1, 12}}

tell application "System Preferences"
	activate
	set current pane to pane "com.apple.preference.displays"
end tell

-- Reset the counter to make it work as a toggle
if runCount is greater than (count item 1 of rowNumberList) then
	set runCount to 1
end if

tell application "System Events"
	repeat with i from 1 to (count rowNumberList)
		--Make sure we are on the "Displays" tab (as opposed to "Arrangement" or "Color")
		click radio button "Display" of tab group 1 of window 1 of process "System Preferences"
		
		--Set the resolution to whatever is in row 2 for the primary display;
		select row (item runCount of (item i of rowNumberList)) of table 1 of scroll area 1 of group 1 of tab group 1 of window i of process "System Preferences"
		
		-- minor delay to let a potential "ok", "cancel" sheet display (this happens when I choose a HiDPI resolution)
		do shell script "sleep 0.25"
		
		-- will choose the default value of "ok" if the sheet is there by pressing enter (ugh!)
		keystroke (ASCII character 3)
	end repeat
end tell

--Finally, quit System Preferences again.
tell application "System Preferences"
	quit
end tell

set runCount to runCount + 1


Hello Nigel

Your piece of code behaves flawlessly under Lion.
I like it because it’s not localisation attached.

Relying upon the radio button name “Display” assume that the system is ran in English.

Yvan KOENIG (VALLAURIS, France) mercredi 13 juin 2012 16:46:43

This brings up another question I had asked in another post with no responses.

Has anyone determined a way to manage the actual display arrangement? I have dug around quite a lot with zero results.

http://macscripter.net/viewtopic.php?id=38664

ASObjC Runner lets you move the menu bar between displays:

tell application id "au.com.myriad-com.ASObjC-Runner" -- ASObjC Runner.app
	set has menu bar of screen 2 to true
end tell