How to script the selection of an option from a popup menu?

Hi pwann,
Yuan Koenig 's last two scripts dont work for me either. Perhaps, because of the fact that he uses a non-english language in his system.

To run an applescript with a keystroke, I recommend Butler. Its slightly complicated to use but its more stable than Quicksilver. As I had asked earlier in this thread, how to assign a shortcut to a script which has to be run alone from Scripts menu alone, the only answer that I have as of now to that question is to write another script using UI method and assign a shortcut to it rather than assigning a shortcut to the original script.

This is what I wrote

It appears that the window in not built the same way in os X 1.4 ans in OS X 1.5

In 1.4 the popup is in a group
In 1.5 it isn’t.
Here is a version which take care of this difference.


set curApp to "TextEdit" --to name of current application
tell application curApp to activate

set myLanguage to "Svenska"
if curApp is not "Script Editor" then
	tell application "System Events" to tell process curApp
		set knt to count of windows
		keystroke ":" using command down
		delay 0.2
		if (count of windows) > knt then
			set nw1 to name of window 1
			try
				tell window nw1
					if my quelOS() < "1500" then
						if item 1 of (get value of pop up button of group 1) is not myLanguage then
							click pop up button 1 of group 1
							click menu item myLanguage of menu 1 of pop up button of group 1
						end if
					else
						if item 1 of (get value of pop up button) is not myLanguage then
							click pop up button 1
							click menu item myLanguage of menu 1 of pop up button
						end if
					end if -- quelOS
				end tell
			end try
			click button 1 of window nw1 (* close the window *)
		end if
	end tell -- application
end if

--=====

on quelOS()
	local hexData, hexString
	set the hexData to system attribute "sysv"
	set hexString to {}
	repeat 4 times
		set hexString to ((hexData mod 16) as string) & hexString
		set hexData to hexData div 16
	end repeat
	return hexString as string
end quelOS

--===== 

Yvan KOENIG (from FRANCE samedi 7 février 2009 14:20:55)

Hi YK.
no change. does not work. no error messages.

Text edit 1.5(244)

YK 090207-032102: I get the same result as chris2: no error, but language does not change.

chris2: your script 090205-045316 worked fine, but only when run in Script Editor. If I change the first line to “set curApp to “TextEdit””, it no longer works (“Dansk” entered in text area, popup menu remains open, language not changed).

I am getting very suspicious about GUI scripting - does it really work reliably? Is there a good, complete reference manual on using AppleScript to control GUI’s?

I will make tests with Mac OS X 10.5.6 tomorrow

Under 10.4.11 it behaves flawlessly.

GUI scripting is a bit boring because:

¢ menus may change from on program’s version to another one (Pages and Numbers for instance)
¢ the structure of some GUI elements may change given the OS version.
Here there is a problem with the popup which is in a group in 10.4.1 and seems to fon’t in 10.5

For Pages and Numbers, some GUI items must be triggered with
click button theButton of radio group 1 under 10.4
but must be triggered with
click checkbox theButton of radio group 1 under 10.5

And sometimes it’s difficult to write localization independant scripts.

Yvan KOENIG (from FRANCE samedi 7 février 2009 23:25:38)

this checks, whether the OS is less then 15.0.0 :wink:

For your purpose this version check might be sufficient


(system attribute "sysv") mod 4096 div 16 --> returns 4 for Tiger and 5 for Leopard

sorry i dont understand which script is “090205-045316”. I think the times in different countries have to be adjusted for to understand it. On the right hand side of a post, there is always a post number like ("#12, #13). You should refer to that in future. I would like to know why you are not using the first script that I wrote (in post #2 and which you modified in post#3 for the close button). That seems to work very reliably.

As much as I know, GUI scripting is to be used as last resort when normal scripting is not possible.

Tested under 10.4.11 and 10.5.6.

The dialog is not the same under the two OS but it’s also not the same for Script Editor and TextEdit.



my setLanguage("TextEdit", "Svenska")
my setLanguage("Script Editor", "Svenska")

--=====

on setLanguage(curApp, myLanguage)
	tell application curApp to activate
	set flag to 0
	if curApp is not "Script Editor" then
		tell application "System Events" to tell process curApp
			set knt to count of windows
			keystroke ":" using command down
			delay 0.2
			set knt2 to count of windows
			if knt2 > knt then
				set nw1 to name of window 1
				if my quelos() < 5 then
					try
						tell window nw1
							set flag to 1
							if (item 1 of (get value of pop up button of group 1)) as text is not myLanguage then
								click pop up button 1 of group 1
								click menu item myLanguage of menu 1 of pop up button of group 1
							else
								set flag to 2
							end if
						end tell
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				else (*
					Here macOS X 10.5 or higher *)
					try
						tell window nw1
							set flag to 1
							if (get value of pop up button 1) is not myLanguage then
								click pop up button 1
								click menu item myLanguage of menu 1 of pop up button 1
							else
								set flag to 2
							end if -- state
						end tell -- window
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				end if -- quelOS
			else if knt2 = knt then
				set flag to 4
			end if -- count of windows
		end tell -- process	
	else (* 
special case: "Script Editor" *)
		tell application "System Events" to tell process curApp
			set knt to count of windows
			keystroke ":" using command down
			delay 0.2
			set knt2 to count of windows
			if knt2 > knt then
				set nw1 to name of window 1
				if my quelos() < 5 then
					try
						tell window nw1
							set flag to 1
							if (item 1 of (get value of pop up button of group 1)) as text is not myLanguage then
								keystroke myLanguage & return
								click pop up button 1 of group 1
							else
								set flag to 2
							end if -- item 1.
						end tell -- window
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				else (*
					Here macOS X 10.5 or higher *)
					try
						tell window nw1
							set flag to 1
							if get value of pop up button 1 is not myLanguage then
								keystroke myLanguage & return
								click pop up button 1
							else
								set flag to 2
							end if -- item 1.
						end tell -- window
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				end if -- quelOS
			else if knt2 = knt then
				set flag to 4
			end if -- count of windows
		end tell -- process
	end if -- curApp
	
	if flag = 0 then error "The Spell Checker window was open, you closed it !"
	if flag = 2 then error myLanguage & " was already set"
	if flag = 3 then error "The opened window can't be accessed !"
	if flag = 4 then error "Spell Checker window is unavailable !"
end setLanguage

--=====

on quelos()
	return (system attribute "sysv") mod 4096 div 16
end quelos

--===== 

Do what you want with the four displayed messages :wink:

As you see, using GUI scripting is not really simple.

Yvan KOENIG (from FRANCE dimanche 8 février 2009 17:14:31)

great work, YK. Thanks for the efforts.

I repeat my thanks to both chris2 and YK for your great efforts. However, I am still having problems.

Answering chris2: the script in post #3 works well when executed within Script Editor (“Run” button), but does not work in these cases:

  1. if I change “name of current application” to ““TextEdit””.
  2. if i run it from the Script menu in the top menubar with TextEdit as current application.

YK: your latest script also works fine when executed within Script Editor, but when I run it from the Script menu in the top menubar, I get these results:

  1. If I change the script to call setLanguage only for TextEdit, all OK.

  2. If I change the script to call setLanguage only for Script Editor, I have the following after running the script:
    the popup list of languages remains open, but nothing else of the Spelling window. In this list, the “old” language is still checked. In the Script Editor window, the first word after the previous cursor position which fails the spell check is replaced by “Svenska”.

I have also tried running the script from Butler, as recommended by chris2. I don’t have much success with that. The only debugging method I know is to put a “beep” in various places. A beep at the top of the script is executed. With YK’s script, a beep at the top of the body of setLanguage is not executed. Any tips?

Again: someone, please, point me to a good manual for GUI scripting!

I forgot to mention: with YK’s script (post #21), if I change it to call setLanguage with p1 = “name of current aplication”, then run the script from the Script menu in the top menubar with TextEdit as current application, the following happens: the Spelling window remains open, the language list is open with the “old” language checked.

Maybe because, as YK said: The dialog is not the same under the two OS but it’s also not the same for Script Editor and TextEdit.
Forget about my script, work on YK’s last script. He has a better insight.

I dont know. Someone else will suggest you that. But before reading any documenation, please have a look at a wonderful write-up by Kai.
http://macscripter.net/viewtopic.php?id=16145

A good manual is not going to solve your problems like you expect them to.
I have been looking at several articles on GUI scripting over the last few days.
I believe trial and error is must in GUI scripting unless Yuan Koenig can explain me which documentation he used to figure out that he must use :

keystroke myLanguage & return
 click pop up button 1 of group 1

and not

click pop up button 1
click menu item myLanguage of menu 1 of pop up button 1

for Script Editor.

As far as I know, if you run the script from the Script menu with p1 = name of current application, p1 will contain the name of the script so the described behavior is perfectly normal.

try to save as a bundle application the simple script:



display dialog (name of current application)


You will get the name of the script :wink:

Yvan KOENIG (from FRANCE lundi 9 février 2009 21:44:01)

I tried with the

and, tracing the script behavior with some log instructions I was able to see that this couple of instructions failed.
I also discovered that when a language was set when the application was Script Editor, it was not set when I opened the dialog by hnd from Text Edit.

So I understood that the two dialogs wheren’t using the same code.

As you posted the

couple of instructions which was odd during my tests with different applications, I assumed that you tested it before posting it so I thought: maybe he used it with “Script Editor”.

Last thing, may you take care that since 1943/12/31, my first name is Yvan not Yuan. I like this old friend. So please don’t hurt it :wink:

Yvan KOENIG (from FRANCE lundi 9 février 2009 21:54:05)

Sorry, “Yvan”. I think i have messed up with your name quite a few times even in Apple Discussions>>Numbers forum. I will take care next time.:cool:

Reply to Yvan post #26:
I now understand that “name of current application” is not the way to refer to the name of the application which has focus, and whose name is displayed at the top left in the top menubar. That was a surprise and a disappointment. (Oh, how I wish I had some reference manual to learn these things, instead of having to try, and try, and retry, and ask others for help. This seems to be the new software engineering culture - noone has the time to write a manual; if you’re lucky, you’ll find an FAQ, or a forum. There was a time when one said (in reference to documenting software products): “the job isn’t finished until the paperwork is done”. The illustration was a small boy sitting on the toilet wiping his buttocks.)

My ultimate goal is to have a script, activated by a keystroke (some combination of keys) from “within” any application capable of text input. By “within” I mean that the application has focus and I am typing text into one of its windows. The purpose of the script is to change the language used by the spell checker. (I want to alternate between three languages; I may use three different keystrokes, or a simple selection dialog within the script, but this is outside the scope of this discussion).

I assumed that “name of current application” would be the proper way to identify the current application. If not, then how do I do it? And how would you propose to implement the full solution?

Very much indebted to Yvan and chris2, and anyone else who might want to help.

Hello

(a) I’m like you, I just got what is available on Apple pages dedicated to AppleScript to use GUI scripting.

(b) I never found a way to get the name of the calling application from a script.

I was quite decided to quit this kind of duty when I discovered thisService
available from:
http://wafflesoftware.net/thisservice/services/

It’s a tool allowing us to encapsulate AppleScripts in Services.

In this environment, you will see that this huge piece of code:


tell application "System Events"
	set _appname to name of first process whose frontmost is true
end tell

grabs the name of the true ‘current app’.

More, we may link shortcuts to these services.
So it’s a way to solve your entine problem.

I just discovered the version 2.0.2 so I don’t know which are the enhancements upon version 2.0.1

Yvan KOENIG (from FRANCE mardi 10 février 2009 14:07:16)

Here is a new version ready to be included in a service.


(*
Thanks to "thisService", you may encapsulate this script in a Service.
Download "thisService" for free, from 
http://wafflesoftware.net/thisservice/

When creating the service click the button "Produce output"

At this time I don't know why there is a long pause (with wheel of death)
at the beginning but it does it's duty.

If you wish you may play with the kind of service.
If you may select the name of the language in a TextEdit document, you may edit the instructions
on process()
	set input to "Svenska"
	
	as
	on process(input)
	--set input to "Svenska"
	and create a service of kind "Filter (both)"
	
	It will use the selected sting as the language to apply.
	
	Yvan KOENIG (Vallauris, FRANCE)
	10 février 2009
*)

on run
	set rezult to my doYourDuty("TextEdit", "Svenska")
	if rezult is not "" then error rezult
end run

--=====

(* Here is the handler used by thisService to enter the script *)

on process()
	set input to "Svenska"
	tell application "System Events" to set app_name to name of process 1 whose frontmost = true
	set rezult to my doYourDuty(app_name, input)
	if rezult is not "" then
		tell application "System Events"
			activate
			display dialog rezult
		end tell
	end if
	return ""
end process

--=====

on doYourDuty(curApp, myLanguage)
	tell application curApp to activate
	set flag to 0
	if curApp is not "Script Editor" then
		tell application "System Events" to tell process curApp
			set knt to count of windows
			keystroke ":" using command down
			delay 0.2
			set knt2 to count of windows
			if knt2 ≥ knt then
				set nw1 to name of window 1
				if (system attribute "sysv") mod 4096 div 16 < 5 then
					try
						tell window nw1
							set flag to 1
							if (item 1 of (get value of pop up button of group 1)) as text is not myLanguage then
								click pop up button 1 of group 1
								click menu item myLanguage of menu 1 of pop up button of group 1
							else
								set flag to 2
							end if
						end tell
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				else (*
					Here macOS X 10.5 or higher *)
					try
						tell window nw1
							set flag to 1
							if (get value of pop up button 1) is not myLanguage then
								click pop up button 1
								click menu item myLanguage of menu 1 of pop up button 1
							else
								set flag to 2
							end if -- state
						end tell -- window
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				end if -- quelOS
			end if -- count of windows
		end tell -- process	
	else (* 
special case: "Script Editor" *)
		tell application "System Events" to tell process curApp
			set knt to count of windows
			keystroke ":" using command down
			delay 0.2
			set knt2 to count of windows
			if knt2 ≥ knt then
				set nw1 to name of window 1
				if (system attribute "sysv") mod 4096 div 16 < 5 then
					try
						tell window nw1
							set flag to 1
							if (item 1 of (get value of pop up button of group 1)) as text is not myLanguage then
								keystroke myLanguage & return
								click pop up button 1 of group 1
							else
								set flag to 2
							end if -- item 1.
						end tell -- window
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				else (*
					Here macOS X 10.5 or higher *)
					try
						tell window nw1
							set flag to 1
							if get value of pop up button 1 is not myLanguage then
								keystroke myLanguage & return
								click pop up button 1
							else
								set flag to 2
							end if -- item 1.
						end tell -- window
						click button 1 of window nw1 (* close the window *)
					on error
						set flag to 3
					end try
				end if -- quelOS
			end if -- count of windows
		end tell -- process
	end if -- curApp
	
	if flag = 0 then return "The Spell Checker window was open, you closed it !"
	if flag = 2 then return myLanguage & " was already set"
	if flag = 3 then return "The opened window can't be accessed !"
	return ""
end doYourDuty

--===== 

Yvan KOENIG (from FRANCE mardi 10 février 2009 20:41:29)

Oh wow, that’s a lot of work you have been doing Yvan - thanks a lot! :slight_smile:
I will need some time to digest and learn about thisService. Will report back when I have understood and tried it.
Peter

Oops, I missed that when no window is open, we aren’t allowed to send the shortcut :frowning:


--(SCRIPT triggerPopUp]{code}
(*
Enregistrer le script en tant qu'Application ou Progiciel : triggerPopUp.app
déplacer l'application créée dans le dossier
<VolumeDeDémarrage>:Users:<votreCompte>:Library:Scripts:Applications:
Il vous faudra peut-être créer le dossier Applications.

menu Scripts > triggerPopUp

Le script essaie de définir le langage utilisé par le vérificateur orthographique 
selon la property input.

--=====

L'aide du Finder explique:
L'Utilitaire AppleScript permet d'activer le Menu des scripts :
Ouvrez l'Utilitaire AppleScript situé dans le dossier Applications/AppleScript.
Cochez la case "Afficher le menu des scripts dans la barre de menus".

-- NOUVEAU NOUVEAU NOUVEAU

Grace au programme gratuit ThisService, il est possible d'encapsuler ce script dans un service.
Télécharger ThisService depuis:
http://wafflesoftware.net/thisservice/

Lors de la création du service, cliquer le bouton "Produce output".
Il est possible d'associer un raccourci clavier au service.

+++++++++

Save the script as an Application Bundle: triggerPopUp.app

Move the newly created application into the folder:
<startup Volume>:Users:<yourAccount>:Library:Scripts:Applications:
Maybe you would have to create the  folder Applications by yourself.

menu Scripts > Pages > triggerPopUp

The script try to set the language used by the spell checker 
given the setting of the property input.

--=====

The Finder's Help explains:
To make the Script menu appear:
Open the AppleScript utility located in Applications/AppleScript.
Select the "Show Script Menu in menu bar" checkbox.

-- NEW NEW NEW NEW

Thanks to the free program ThisService, we may encapsulate this script in a Service.
Download ThisService from 
http://wafflesoftware.net/thisservice/

When creating the service click the button "Produce output"
We may link the service to a shortcut.

At this time I don't know why there is a long pause (with wheel of death)
at the beginning but it does it's duty.

If you wish you may play with the kind of service.
If you may select the name of the language in a text document, you may edit the instruction
on process()   (* or process(input) *)
	as
on process(input)   (* or process() *)
	
and create a service of kind "Filter (both)".
	
It will use the selected string as the language to apply.
	
Yvan KOENIG (Vallauris, FRANCE)
10 février 2009
11 février 2009
*)

property input : "Svenska"

--=====

on run
	set rezult to my doYourDuty("TextEdit", input)
	if rezult is not "" then error (rezult & " !")
end run

--=====

(* Here is the entry point used by thisService *)

on process() (* or process(input) *)
	local the_language, rezult
	set the_language to input
	tell application "System Events" to set app_name to name of process 1 whose frontmost = true
	set rezult to my doYourDuty(app_name, the_language)
	if rezult is not "" then
		tell application "System Events"
			activate
			display dialog (rezult & " !")
		end tell
	end if
	return ""
end process

--=====

on doYourDuty(curApp, myLanguage)
	local flag, knt, nw1
	tell application curApp to activate
	delay 0.5
	set flag to 1
	if curApp is not "Script Editor" then
		tell application "System Events" to tell process curApp
			set knt to count of windows
			if knt = 0 then (* 
don't apply the shortcut if no window open *)
				set flag to 4
			else
				keystroke ":" using command down
				delay 0.2
				if (count of windows) ≥ knt then
					set nw1 to name of window 1
					if (system attribute "sysv") mod 4096 div 16 < 5 then
						try
							tell window nw1
								set flag to 0
								if (item 1 of (get value of pop up button of group 1)) as text is not myLanguage then
									click pop up button 1 of group 1
									click menu item myLanguage of menu 1 of pop up button of group 1
								else
									set flag to 2
								end if
							end tell
							click button 1 of window nw1 (* close the window *)
						on error
							set flag to 3
						end try
					else (*
					Here macOS X 10.5 or higher *)
						try
							tell window nw1
								set flag to 1
								if (get value of pop up button 1) is not myLanguage then
									click pop up button 1
									click menu item myLanguage of menu 1 of pop up button 1
								else
									set flag to 2
								end if -- state
							end tell -- window
							click button 1 of window nw1 (* close the window *)
						on error
							set flag to 3
						end try
					end if -- quelOS
				end if -- count of windows
			end if -- knt
		end tell -- process	
	else (* 
special case: "Script Editor" *)
		tell application "System Events" to tell process curApp
			set knt to count of windows
			if knt = 0 then (* 
don't apply the shortcut if no window open *)
				set flag to 4
			else
				keystroke ":" using command down
				delay 0.2
				if (count of windows) ≥ knt then
					set nw1 to name of window 1
					if (system attribute "sysv") mod 4096 div 16 < 5 then
						try
							tell window nw1
								set flag to 0
								if (item 1 of (get value of pop up button of group 1)) as text is not myLanguage then
									keystroke myLanguage & return
									click pop up button 1 of group 1
								else
									set flag to 2
								end if -- item 1.
							end tell -- window
							click button 1 of window nw1 (* close the window *)
						on error
							set flag to 3
						end try
					else (*
					Here macOS X 10.5 or higher *)
						try
							tell window nw1
								set flag to 1
								if get value of pop up button 1 is not myLanguage then
									keystroke myLanguage & return
									click pop up button 1
								else
									set flag to 2
								end if -- item 1.
							end tell -- window
							click button 1 of window nw1 (* close the window *)
						on error
							set flag to 3
						end try
					end if -- quelOS
				end if -- count of windows
			end if -- knt
		end tell -- process
	end if -- curApp
	
	if flag = 0 then return ""
	(* here, flag = 1, 2, 3 or 4 *)
	if (do shell script "defaults read 'Apple Global Domain' AppleLocale") starts with "fr_" then
		return item flag of {"Le vérificateur orthographique était ouvert, vous l'avez fermé", myLanguage & " était déjà appliqué", "La fenêtre ouverte est inaccessible", "Pas de fenêtre ouverte"}
	else
		return item flag of {"The Spell Checker window was open, you closed it", myLanguage & " was already set", "The opened window can't be accessed", "No window open"}
	end if
end doYourDuty

--===== 

Yvan KOENIG (from FRANCE mercredi 11 février 2009 17:53:42)