I’m trying to open a folder, select all items in it, then access the contextual menu. I’m using UI Scripting to try to accomplish this, but have not had any luck. At first, I thought I could use the following, but the “click” never seemed to happen:
tell application “System Events”
tell process “Finder”
set frontmost to true
key down control
delay 2
click selected
key down up
end tell
end tell
Then I tried using the “perform” command, but I can’t get it to work either:
tell application “System Events”
tell process “Finder”
set frontmost to true
perform action “AXShowMenu” of selected of window “Media” end tell
end tell
Any suggestions on getting the contextual menu to show so that I can select an item from it?
I’m trying to access a Contextual Menu plug-in that only exists in that form. If I can find an application that does the same thing, I’ll switch to it.
Honestly I’ve never heard of someone successfully scripting a context menu, but maybe someone could offer you a work-around if we knew which plugin you’re targeting…
The Contextual Menu I’m trying to script is DVFileDateCM, which gives the date that a DV file was originally recorded. Unfortunately, I haven’t been able to find any other Mac program that does this.
It seems that in UIInspector, the is an “AXShowMenu” action for Finder items, but I can’t get it to perform.
OK well I can’t help with getting that metadata. Someone else might know, I imagine it could be scraped out of the file using a shell script or something. I took a second look at the Finder’s contextual menu and was able to select items in it through a somewhat goofy method. Perhaps you can modify this to get at what you need:
tell application "Finder" to activate
tell application "System Events" to tell process "Finder"
-- this targets the first item of a window that is in icon view and has no toolbar
perform action "AXShowMenu" of UI element 1 of group 1 of scroll area 1 of window 1
(* repeat 14 times
key code 125 -- down arrow (highlights automator submenu)
end repeat
repeat 2 times
key code 124 -- right arrow (opens automator submenu)
end repeat
key code 125 -- down arrow (selects automator workflow)
keystroke return -- (runs automator workflow)
*)
end tell
When I tested this, the automator action executed on the actual finder selection as opposed to the not-selected file that was targeted the AXShowMenu action (UI element 1) There may be other UI elements that could be targeted to get similar results.
A scripted “AXShowMenu” action certainly doesn’t appear to sense a multiple selection in the same way that a manual control-click does. (Hopefully, that won’t be a major problem for Tim.)
Other issues arise if the selection is on the desktop, or if the target window displays a toolbar or not. And since navigation of nested menu items seems to differ slightly from that in regular menus, landing a click on them can also be a bit tricky.
The following suggestion attempts to deal with some of these points (although I’ve no doubt there will be others)…
on finderSelection()
set d to path to desktop
tell application "Finder" to tell (get selection)
if (count) is 0 then error number -128
set f to beginning
tell f's folder
if it as alias is d then return {f's displayed name, 0}
{f's displayed name, name}
end tell
end tell
end finderSelection
on tgt(t)
tell application "System Events" to tell process "Finder"
if t is 0 then return it
tell window t
if (count splitter groups) is 0 then return it
splitter group 1
end tell
end tell
end tgt
to contextClick on m at {f, t}
tell application "System Events" to tell process "Finder"
-- set frontmost to true (* optional *)
perform action "AXShowMenu" of UI element f of group 1 of scroll area -1 of my tgt(t)
delay 0.2
tell UI element 2
repeat until exists
delay 0.2
end repeat
repeat with i in m as list
click menu item i
end repeat
end tell
end tell
end contextClick
The above subroutines can be called with something like:
As already mentioned Tim, it doesn’t seem possible (AFAICT) to select more than one Finder item and then script a multiple-item contextual menu command.
By this I mean that, if you manually control-click one of several selected Finder items - and then keep the control key depressed, some menu commands may be modified to reflect a multiple selection (“Get Info”, for example, becomes “Get Summary Info”). As things stand, it doesn’t seem possible to script an equivalent action through UI scripting.
However, if you merely wish to apply the same (regular) contextual command to all selected Finder items, then you might like to consider something like this variation of the above script:
on targetArea(FinderTarget)
tell application "System Events" to tell process "Finder"
if FinderTarget is 0 then return {group 1 of scroll area -1, false}
tell window FinderTarget to if (count splitter groups) is 0 then
set tgt to it
else
set tgt to splitter group 1
end if
tell tgt to if (count browsers) is 0 then
tell scroll area -1 to if (count outlines) is 0 then
{group 1, false}
else
{outline -1, true}
end if
else
{list 1 of scroll area -1 of scroll area -1 of browser 1, false}
end if
end tell
end targetArea
on FinderSelection()
set desktopAlias to path to desktop
tell application "Finder" to tell (get selection)
if (count) is 0 then error number -128
tell beginning's folder
if it as alias is desktopAlias then return my targetArea(0)
my targetArea(name)
end tell
end tell
end FinderSelection
to contextClick on currentMenu at {mainTarget, listView}
set menuList to currentMenu as list
tell application "System Events" to tell process "Finder"
--set frontmost to true (* optional *)
repeat with currentTarget in (get mainTarget's UI elements whose selected is true)
delay 0.2
if listView then
perform action "AXShowMenu" of UI element 1 of group 1 of currentTarget
else
perform action "AXShowMenu" of currentTarget
end if
delay 0.2
tell UI element 2
repeat until exists
delay 0.2
end repeat
repeat with menuItem in menuList
click menu item menuItem
end repeat
end tell
delay 0.2
end repeat
end tell
end contextClick
Edit: Script revised to take account of different Finder window views, as mentioned (below) by Eelco.
The syntax for calling these handlers remains the same:
Good point, Eelco. (Don’t you just hate UI scripting? ;))
I’ve revised the script above in an attempt to make it more tolerant in different situations. This stuff does tend to be a little fragile, but the script now seems to be working reasonably well here…
GUI & Finder - more than a nuisance couple !
You handled list/column views elegantly & correctly, but get it to work on my system (10.4.2 int’l) I needed to change:
into:
Upside effect: the script now works with both toolbar and toolbar-less Finder windows.
Thanks for your efforts !
You’re correct about the fact that it doesn’t click multiple items the same way that a real click of multiple items does. However, that shouldn’t be a big problem for me… I’m going to try to add a loop that will control click each item, save the info that the contextual menu creates, then moves on to the next item. While I don;t know exactly how to do this in Applescript, I’m assuming it will go something like this:
-select all the items in a particular folder
-identify the number of selected items
-go thorugh a subroutine to control click and save the info that’s generated
The attached script temporarily selects individual Finder items from the bunch,
now processing multiple items more reliably.
Also, that solves the problem of changing contxt. menu item names (or was that already solved?)
However, it comes at cost of performance.
So I guess you guys will come up with something smarter…
contextClick on "Get Info" at finderSelection()
on targetArea(FinderTarget)
tell application "System Events" to tell process "Finder"
if FinderTarget is 0 then return {group 1 of scroll area -1, false}
tell window FinderTarget to if (count splitter groups) is 0 then
set tgt to it
else
set tgt to splitter group 1
end if
tell tgt to if (count browsers) is 0 then
tell scroll area -1 to if (count outlines) is 0 then
{group 1, false}
else
{outline -1, true}
end if
else
{list 1 of scroll area -2 of scroll area -1 of browser 1, false}
end if
end tell
end targetArea
on finderSelection()
set desktopAlias to path to desktop
tell application "Finder"
tell (get selection)
if (count) is 0 then error number -128
tell beginning's folder
if it as alias is desktopAlias then return my targetArea(0)
my targetArea(name)
end tell
end tell
end tell
end finderSelection
to contextClick on currentMenu at {mainTarget, listView}
set menuList to currentMenu as list
tell application "Finder" to set sell to (get the selection)
tell application "System Events"
set tt to (get mainTarget's UI elements whose selected is true)
set i to 1
repeat with currentTarget in tt
tell process "Finder"
set frontmost to true (* optional *)
set tt to {}
tell application "Finder" to select item i of sell
delay 0.2
if selected of currentTarget then
if listView then
perform action "AXShowMenu" of UI element 1 of group 1 of currentTarget
else
perform action "AXShowMenu" of currentTarget
end if
delay 0.2
tell UI element 2
repeat until exists
delay 0.2
end repeat
repeat with menuItem in menuList
click menu item menuItem
end repeat
end tell
delay 0.2
set i to i + 1
end if
end tell
end repeat
end tell
tell application "Finder" to select sell
end contextClick
Ok guys…I’ve run into another snag (my newbieness is showing…)
I’m trying to insert a step where the information from the contextual menu will be saved into a new text file for each iteration. However, the script doesn’t seem to like me doing this. I’m inserting my code into the following loop:
repeat with menuItem in menuList
click menu item menuItem
end repeat
I’m going to keep trying by moving my “text file” code into the other loops, but am I missing something here?