Shortcut for third non-default, non-cancel button in dialog

How can I select 3 with a keypress?

display dialog "test" buttons {1, 2, 3} default button 1 cancel button 2

If you enable “full keyboard access” in system preferences you can press tab three times and hit space to hit the button. Unfortunate the focus ring is poor in Yosemite if the button is default and has a focus ring.

Nice, forgot that one. But is there any way to hard-code the third button, like expecting a keypress from the user?

Not in Mountain Lion. If you really need a shortcut, you could always use choose from list instead.

So in the location generation of OSs is that possible? :lol:

I thought user interaction, in this case keypress input, like with expect in shell, was somehow feasible.

It is possible to press the button with AppleScript, it’s not possible to show a dialog and then press the button from the same script object. That is because the windows is created by the standard addition, and the event send will not return something before the the dialog event is done (timed out or pressed a button). AppleScript itself is single threaded, while waiting for the event’s response AppleScript cannot do anything else.

Hmm, if I understood you correctly, it’s not possible in a script to run another script that expects a keypress and can press a button in a dialog run from that same script? That is, script 1 runs script 2 (expects keypress) and then displays a dialog.

That is possible, if you for example run “script 2” in another background process using osascript command line util. But that is just one part of your problem. The other part is responding to events. You could use AppleScript Toolbox to let the script wait for certain events come by in the global scope but the current release is limited to event monitoring.

The current development state of AppleScript Toolbox is that it now returns the modifier keys (control, alt, command, function, numeric pad, shift and alpha shift) and the Unicode key value that are pressed for normal keys (finished). I’m currently working on wait for events on process level and not only global scope (not finished). Unfortunately this is still in development and not tested; therefore not released yet. It will be available in version 1.3.3 and it will be available soon.

Sure. It requires AppleScriptObjC, and it gives you an alert rather than a standard dialog. And the three buttons are positioned with the left-most one a bit apart, as in a system alert (but you can add more buttons if you like, and the spacing is then fine). It also needs to be run from the main thread, which is fine in applets and things, but from Script Editor requires holding down the control key and choosing Script → Run in Foreground. Here’s an example:

use scripting additions
use framework "Foundation"
use framework "AppKit" -- required for NSAlert

-- check we are running in foreground
if not (current application's NSThread's isMainThread()) as boolean then
	display alert "This script must be run from the main thread." buttons {"Cancel"} as critical
	error number -128
end if

-- for styleNum, 0 = warning, 1 = informational, 2 = critical
on displayAlert:mainText message:theExplanaton asStyle:styleNum buttons:buttonsList
	set buttonsList to reverse of buttonsList -- because they get added in reverse order cf AS
	-- create an alert
	set theAlert to current application's NSAlert's alloc()'s init()
	-- set up the alert
	tell theAlert
		its setAlertStyle:styleNum
		its setMessageText:mainText
		its setInformativeText:theExplanaton
		-- add buttons
		repeat with anEntry in buttonsList
			(its addButtonWithTitle:anEntry)
		end repeat
		set theButtons to (its buttons()) as list
	end tell
	-- set key equivalents for buttons, in this case without any modifier
	repeat with i from 1 to count of theButtons
		((item i of theButtons)'s setKeyEquivalent:(item i of buttonsList))
		-- uncomment next line to make command key required
		-- (item i of theButtons)'s setKeyEquivalentModifierMask:(current application's NSCommandKeyMask) 
	end repeat
	-- show the alert
	set returnCode to theAlert's runModal()
	-- get values after alert is closed
	set buttonNumber to returnCode mod 1000 + 1 -- where 1 = right-most button
	set buttonName to item buttonNumber of buttonsList
	return buttonName
end displayAlert:message:asStyle:buttons:

set buttonName to (my displayAlert:"Stay alert" message:"This is the 9 o'clock news" asStyle:2 buttons:{"1", "2", "3", "4"})

Pressing 1, 2, 3 or 4 will press the appropriate button. Uncomment the setKeyEquivalentModifierMask: line if you want to require the command key too.

Display dialog (and many others) is modal. Display dialog has default button blue-coloured and selected as well. You can’t control color of default button, but you can focus and select other button by throwing artefact interruption:


try
	with timeout of 1 second
		display dialog "test" buttons {1, 2, 3} default button 1 cancel button 2
	end timeout
	result -- I throw artefact interruption here
on error number -2753
	tell application "System Events" to tell application process "Script Debugger"
		set focused of UI element "3" of window 1 to true
		select UI element "3" of window 1
		-- click UI element "3" of window 1
	end tell
end try

NOTE: you can click this button as well. Simply uncomment click UI element “3” of window 1. Focusing and selecting is optional. You can omit them when clicking.