Using AXIdentifier in UI Scripting for Applescript - user-interface

10.7.4 OSX Lion
Applescript
I am working with an application (built in house and has no Applescript dictionary) that has a static text element I want to copy to the clipboard and send to another app but I'm having a hard time getting it to work.
The script I was using for targeting the element looked like this:
Tell application "System Events" to set frontmost of process "*application*" to true
Tell application "System Events"
Tell process "*application*"
Tell static text 1 of tab view 1 scroll area 1 of splitter group 1 of splitter group 1 of splitter group 1 of window 1
keystroke "a" using command down
delay 0.1
keystroke "c" using command down
delay 0.1
end tell
end tell
end tell
end tell
What would happen was that the wrong text from the wrong element was copied to the clipboard every time I clicked in a different spot on the application (there are numerous text fields).
I noticed in UI Accessor/Accessibility Accessor that each UI element in the application has a unique AXIdentifier value when you mouse over them.
Is there anyway to accomplishing what I am trying to do, using AXIdentifier values to target that element and copy the text from it?
Thanks for all the help this is my first post and I hope it was worthy! ~TheLarkInn

You can do this by using AppleScript's filtering. For example, to get the From: pop-up menu in a message composition window in Apple Mail, there is no accessibility description you can match on, however there is a unique AXIdentifier which you can match as follows:
tell application "System Events"
tell application process "Mail"
tell window 1
get first pop up button whose value of attribute "AXIdentifier" is "popup_from"
end tell
end tell
end tell
This is more efficient than looping in AppleScript as it only involves sending one Apple Event to System Events.

I don't think there is a way to directly do what you're trying to do. It seems like you can only access attributes once you have a handle on an element via selector. Here is a very ugly solution that does what you're asking by iterating over all UI elements, but it is really slow with bigger UIs and probably not ideal for any production level code.
tell application "System Events"
tell process "Some Process"
set tElements to entire contents of window "Some Window"
repeat with tElement in tElements
if (exists attribute "AXIdentifier" of tElement) then
if value of attribute "AXIdentifier" of tElement = "Some AXIdentifier" then set tText to value of tElement
end if
end repeat
end tell
end tell
tText
I think using UIElementInspector or Accessibility Inspector from Xcode to build a selector string is the way to go!

Tell application "*application*" to activate
Tell application "System Events"
Tell application process "*application*"
set textStaticTextValue to value of static text 1 of tab view 1 scroll area 1 of splitter group 1 of splitter group 1 of splitter group 1 of window 1
end tell
end tell

Related

what means "tab group 1" in AppleScript, why not "tab group 2"?

I'm trying to understand code belong, and can't find anything explain what means "tab group 1"..
And I don't know how to debug to find the value with "tab group 1"
Btw, I test "tab group 0",its ok, but "tab group 2" its error..
set devices to {}
tell application "System Preferences"
reveal pane "声音"
end tell
tell application "System Events"
tell application process "System Preferences"
repeat until exists window "声音"
end repeat
tell tab group 1 of window "声音"
get properties
click radio button "输出"
tell table 1 of scroll area 1
set selected_row to (first UI element whose selected is true)
set currentOutput to value of text field 1 of selected_row as text
repeat with r in rows
try
set deviceName to value of text field 1 of r as text
set end of devices to deviceName
end try
end repeat
end tell
end tell
end tell
end tell
if application "System Preferences" is running then
tell application "System Preferences" to quit
end if
set text item delimiters to "‡"
set devicesStr to devices as text
set comm to "bash ./main.sh" & " \"" & devicesStr & "\"" & " \"" & currentOutput & "\"" & " output"
log comm
#do shell script comm
AppleScript GUI scripting involves working its way down through the view hierarchy of the application's windows. In this case, 'Tab Group [X]' means that there are at least [X] tab groups within the container at that level of the hierarchy, and you need to determine which one contains the lower-level element you're trying to access. Unfortunately, the elements of the view hierarchy aren't always immediately visible (there may be 'hidden' containers and such), and the hierarchy may change significantly from one app update to the next. That can be headache inducing.
You can debug this manually (with a little patience) by working your way down the hierarchy yourself until you find the elements you need, using a series of every UI element of.. commands. I.e., begin with:
tell application "System Events"
tell application process "System Preferences"
tell window "声音"
get every UI element
end tell
end tell
end tell
Then choose a likely UI element from the list it produces and add a new tell block. However, it's easier to use the Accessibility Inspector app, which gives you a look into the details of any applications view hierarchy. Accessibility Inspector is included with Xcode downloads (which is free, and worth having around); I don't know if there's a place to download it separately.
See Apple's Guide of Testing Accessibility.

AppleScript Not Recognizing Application Index Addresses

I am creating an AppleScript to control some basic standard actions in SAP and everything as written works fine from the main menu page of available transactions. The current script fills out the Command Text Field and opens a new existing transaction code. However, once SAP has gone to the new transaction code page, when I run the AppleScript a second time it no longer recognizes the index of the Command Text Field. Instead it pastes the transaction code into whatever text field happens to be the current focus. When I run the script, it should always go to the same text field because the overall index address hasn't changed, but it's not.
I've attempted to open the Script Dictionary for SAP, but it appears that my company's flavor of SAP has had the scripting dictionary disabled, so I am forced to use indexing addresses to fill text fields and click buttons
on chooseSAPTransaction()
global sapTransaction, transactionCode
set transactionCode to "" -- intialize the variable
set transactionList to choose from list {"Find Document", "Change Document", "Look up Product", "Correct Product"} with prompt "SAP Action:" default items {""}
if transactionList is false then
error number -128
else
set choosenTransaction to item 1 of transactionList
end if
if choosenTransaction is "Find Document" then
set transactionCode to "code1"
chooseCode1()
end if
if choosenTransaction is "Change Document" then
set transactionCode to "code2"
chooseCode2()
end if
if choosenTransaction is "Look up Product" then
set transactionCode to "code3"
chooseCode3()
end if
if choosenTransaction is "Correct Product" then
set transactionCode to "code4"
chooseCode4()
end if
set sapTransaction to "/n" & transactionCode
activate application "SAP"
delay 0.1
tell application "System Events"
tell process "SAP"
tell front window to tell toolbar 1 to tell text field 1
keystroke sapTransaction
end tell
tell front window to tell toolbar 1 to tell button 1 to perform action "AXPress"
end tell
end tell
end chooseSAPTransaction
It's skipping tell front window to tell toolbar 1 to tell text field 1 and going right to keystroke sapTransaction on subsequent script executions
("/n" & transactionCode creates the string that tells SAP the new transaction to go to. When typing it manually, it always takes you to the new transaction, regardless of how many layers deep you might be in the current transaction)
I expect the indexing tell to go to the same element on every new instance of running the script, but once it's run once, AppleScript isn't finding the element address anymore.
edit:
I just tried moving the pasting action into its own unique handler so that it can be called before attempting to go to the next step, but that didn't work either.
--snip--
if choosenTransaction is "Find Document" then
set transactionCode to "code1"
set sapTransaction to "/n" & transactionCode
pasteTransaction()
chooseCode1()
end if
--snip--
on pasteTransaction()
global serialNumber, sapTransaction, transactionCode
activate application "SAPGUI"
delay 0.1
tell application "System Events"
tell process "SAPGUI"
tell front window to tell toolbar 1 to tell text field 1
keystroke sapTransaction
end tell
tell front window to tell toolbar 1 to tell button 1 to perform action "AXPress"
end tell
end tell
end pasteTransaction
edit 2:
I got it working by forcing SAP to go through the menu. Woo!
on pasteTransaction()
global serialNumber, sapTransaction, transactionCode
activate application "SAPGUI"
delay 0.1
tell application "System Events"
click menu item ¬
"Target Command Field" of menu 1 of menu bar item ¬
"Edit" of menu bar 1 of application process "SAPGUI"
keystroke sapTransaction
tell process "SAPGUI"
tell front window to tell toolbar 1 to tell button 1 to perform action "AXPress"
end tell
end tell
end pasteTransaction
unfortunately, that doesn't fix the bigger issue of AppleScript not finding the correct index address for text fields, because getting this part working is only step one. Now I have to get text strings into various text fields within each transaction.
So if anyone knows how to address that original Index Address issue, that would be great.
I wish I knew how to actually write AppleScript instead of cobbling code together one action at a time from various sources. It's not elegant, and functionality is hit-or-miss.
GUI scripting is always a hack, and without seeing the application in action it's hard to diagnose problems. Obviously something is changing in the interface that is throwing off the view hierarchy you're trying to leverage, but... I will point out that menus and toolbars tend to be dynamic, which makes things dicier. But here's a couple of diagnostics and alternate approaches you can try.
First, let me rewrite the GUI code like this, which I find clearer:
tell application "System Events"
tell process "SAP"
tell front window
tell toolbar 1
tell text field 1
keystroke sapTransaction
end tell
tell button 1
perform action "AXPress"
end tell
end tell
end tell
end tell
end tell
So first — assuming you are targeting the correct textfield — you might try this instead:
tell toolbar 1
tell text field 1
set value to sapTransaction
end tell
tell button 1
perform action "AXPress"
end tell
end tell
keystroke can be intercepted by whatever UI element has the focus, but setting the text field's value ought to go directly into the correct element. If that doesn't work, you can try this diagnostic in Script Editor:
tell toolbar 1
properties of every text field
end tell
This should give you a list in the Script Editor's log of all of the text fields in toolbar 1. With that, you can see if the text field has a name property (which would make addressing easier: i.e. tell text field "someName"), or if some other text field has been added to the toolbar higher in the hierarchy, changing the index of the text field you're after. If worse comes to worst, you can try this:
tell toolbar 1
entire contents
end tell
Which will list out all the UI elements of the toolbar. You can do a before/after comparison to see what (if anything) changed.
Hope that helps.

How to fix this code, trying to click button

Trying to click the button "Choose" but no success. I have a ​code below trying to correct.
Tried this code, but giving me an error.
error "System Events got an error: Can’t get process \"safari\"." number -1728 from process "safari"
'''activate application "Safari"
tell application "System Events" to tell process "safari"
click button "choose" of sheet 1 of window 1
end tell
'''
here is the code I want to correct
'''button "Choose" of sheet 1 of window 1 of application process "Safari" of application "System Events"
'''
I always find it clearer to nest tell blocks; it makes debugging easier, because you can throw in log statements or other checks at different levels. So I'd use this:
tell application "System Events"
tell process "Safari"
set frontmost to true
tell window 1
tell sheet 1
click button "Choose"
end tell
end tell
end tell
end tell
Remember, System Events is picky and case-sensitive. It will find process "Safari" but throw a fit over process "safari"; indexes of objects might change without notice if things are at all dynamic; you might have to hunt through the structure to find what you want. For instance, I'll often throw in a line like properties of every button at one level or another in the code just to see what shows up in the Script Editor's logs, and what the best way to identify what I want might be.

How to select speakers for iTunes from applescript

I would like to be able to select output sound device for iTunes from a script (any programming language would be ok in fact).
For the moment I was able to use UI element scripting to get up to clicking on the button which gives the menu to select the speakers:
tell application "System Events"
tell window "iTunes" of process "iTunes"
set chbtn to first UI element whose help is "Choose which speakers to use."
tell chbtn
click
-- tell menu 1 to get every menu item
end tell
end tell
end tell
This works, and menu with possible choices appears. However, the applescript seems to stop after the click command, and further actions (in the place where the comment is in the code) happen only after I click somewhere on the screen myself. How can I prevent this and continue to select the menu item from this menu?
Any solution without reverting to UI scripting is also very welcome!
The solution code is
tell application "iTunes" to activate
tell application "System Events"
tell window "iTunes" of process "iTunes"
click (first UI element whose help is "Choose which speakers to use.")
keystroke "DENON" & return -- Select "DENON" airplay entry
-- keystroke "Computer" & return -- Select standard output
end tell
end tell
However, there is an annoying 4 second delay between the click and the keystroke
I've had that delay problem before when using UI scripting. You might be able to eliminate it by telling the script which elements to click. I don't have external speakers, so the elements' names and properties aren't on my computer. An easy way to get more info on the elements available is to use (not free, but excellent) UI Browser http://pfiddlesoft.com/uibrowser/. A less easy, but free, way to get more info on the elements is to use:
tell application "System Events"
tell window "iTunes" of process "iTunes"
set chbtn to first UI element whose help is "Show or hide item artwork and video viewer."
tell chbtn
entire contents
end tell
end tell
end tell

Applescript - Bring window to foreground

I have an application with several windows opened at the same time.
I'd like to bring a specific window to foreground (I know its title).
At the moment I'm using a combination of keys to achieve this task but I'd like to try something different since I'm experiencing some problems with this approach.
tell application "System Events"
set frontmost of process "appIT" to true
keystroke "1" using command down
delay 0.2
end tell
This is possible by using the "AXRaise" action, except on certain window (applications that use X11 for example).
Try this.
set theTitle to "some title"
tell application "System Events"
tell process "appIT"
set frontmost to true
perform action "AXRaise" of (windows whose title is theTitle)
end tell
end tell
If your application is scriptable and allows setting the index of a window, you can do the following (based on an answer in How do I make a Safari window active using AppleScript (elegantly)?)
to raiseWindow of theApplicationName for theName
tell the application named theApplicationName
activate
set theWindow to the first item of ¬
(get the windows whose name is theName)
if index of theWindow is not 1 then
set index to 1
set visible to false
set visible to true
end if
end tell
end raiseWindow
The toggling of the visibility is necessary to deal with some weirdness that occurs with switching applications. If you don't toggle the visibility, the window won't be the first when you switch away from and back to the application. Unfortunately, this toggling shrinks the window to the dock then restores it, a very dramatic UI disruption.
Here's another way I've found to deal with the weirdness:
to raiseWindow2 of theApplicationName for theName
tell the application named theApplicationName
activate
set theWindow to the first item of ¬
(get the windows whose name is theName)
if the index of theWindow is not 1 then
set the index of theWindow to 2
tell application "System Events" to ¬
tell application process theApplicationName to ¬
keystroke "`" using command down
end if
end tell
end raiseWindow2
I don't think System Events can change the front window of a process. Of course you can close the front window until the window you want is on top. That's not really a solution though as you probably don't want to close windows. Really though the only way you could achieve this is if the application itself is apple-scriptable and allows you to do this.

Resources