Re: Finding the focused UI element
Re: Finding the focused UI element
- Subject: Re: Finding the focused UI element
- From: Arjen Baarsma <email@hidden>
- Date: Thu, 17 Jul 2008 19:11:30 +0200
Thank you for your response Philip, that was indeed what I wanted my
script to do: Open a context menu for the currently focused control
so I can then navigate through this context menu with the keyboard.
The idea is that it should work for (almost) any control in (almost)
any application, but I may need to have to write separate scripts for
different applications if I can't find a fast way to find the focused
UI element of any arbitrary application.
I think you will have to search out third party utilities effect a
solution because although a UI Browser may show you the focused
element, it's not always the case that System Events scripting has
a mapping implemented for it or if it does, implements it correctly.
Yeah, I fear it may not be possible using applescript alone. I've
found ways to find the focused UI element using Objective-C/cocoa and
the rest should also work there, so it might be an idea to write it
using that instead (but I'd first have to learn how to do that then).
If anyone happens to know a third party utility that could help, I'd
be happy with that too.
The script works for many controls of most applications, but it's
usually slow and sometimes even very slow. I've tested it in TextEdit
and ScriptEditor (works) and the Finder (only works in list view), in
Adium chat windows (works, becomes very slow when there are a lot of
messages), in Apple Mail (slow and always shows the menu for the
first item in a list instead of the selected one, will have to look
into that later), safari (bad idea) and several preference windows
(works) and also in some other applications.
This is what the entire script looks like at the moment. The beeps
and the delay shouldn't be there in the final version of course since
I just put them there for testing purposes.
delay 1 -- this is here to give me time to cmd-tab to another
application
beep -- we've started
try
tell application "System Events"
set theControl to my findFocus(front window of (first application
process whose frontmost is true))
end tell
sMenu(theControl)
end try
beep -- we're done
on sMenu(theControl) -- show the context menu
tell application "System Events"
if ("AXShowMenu" is in name of actions of theControl) then -- if
theControl has a menu, show it
perform action "AXShowMenu" of theControl
else if class of theControl is not window then -- if not, try its
parents (needed for e.g. toolbar buttons)
my sMenu(value of attribute "AXParent" of theControl)
end if
end tell
end sMenu
on findFocus(theParent) -- find the (deepest) UI element that has focus
tell application "System Events"
if exists (first UI element of theParent whose focused is true)
then -- if we've found one with focus!
return my findFocus(first UI element of theParent whose focused is
true)
-- what I'm doing here is searching the children of the UI element
we've just found to see if any of them has focus (we want the deepest
element with focus), which is necessary for e.g. the Finder
else if (exists focused of theParent) and focused of theParent then
-- I've had to add the exists part because there are UI elements
which you can't ask if they have focus, I may have to add it
elsewhere as well
return theParent
-- when we've already found something with focus and none of its
children has focus we're done
else
repeat with theChild in UI elements of theParent
set output to my findFocus(theChild)
if not (output is false) then return output
end repeat
-- keep searching as long as we haven't found anything with focus yet
return false
end if
end tell
end findFocus
Although the rest may also need improvement, it is at the moment the
findFocus function that forms the problem. It should find the UI
element that currently has focus and it does that perfectly, but it's
VERY slow in many cases (it's not even fast when there's just a few
dozen UI elements in a window). If it's not immediately clear how
this function works, speeding it up is basically the same as speeding
up the following function, which counts the number of UI elements on
a form (andd takes the window in which to search as its argument)
on countUIEs(theParent)
set res to 0
tell application "System Events"
repeat with theChild in UI elements of theParent
set res to res + 1
set res to res + (my countUIEs(theChild))
end repeat
end tell
return res
end countUIEs
This already takes more than a second to run for me for a window
containing only 39 UI elements (the script editor window).
For the UI element search speed, you may be able to apply the Serge-
Garvey techniques: <http://www.google.com/search?
client=safari&rls=en-us&q=Nigel+Garvey+Applescript
+speed&ie=UTF-8&oe=UTF-8> (List Processing speed). There are a few
people on this list you can help you speed up a script but you'd
have to post it for them to be able to make any comments.
After reading this I've tried implementing such a technique by
replacing the function above by the following function
on countUIEs2(theParent)
set res to 0
tell application "System Events"
script s
property sUIels : UI elements of theParent
end script
set n to number of sUIels of s
repeat with i from 1 to n
set res to res + 1
set res to res + (my countUIEs2(item i of sUIels of s))
end repeat
end tell
return res
end countUIEs2
This version indeed seems to be noticeably faster than the one above,
but I'm afraid the difference in speed is not enough for my purposes
here.
If anyone sees a way to speed up my function significantly or, even
better, to quickly obtain the focused UI element of an application,
that would be very helpful.
– Arjen
_______________________________________________
Do not post admin requests to the list. They will be ignored.
AppleScript-Users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
Archives: http://lists.apple.com/archives/applescript-users
This email sent to email@hidden