Create Tell Block for UI Interaction - "UI Browser Lite"

This is a work-in-progress attempt to replicate the functionality of UI Browser that I find most useful. I started work on this last night, and am quite excited about it.

It builds on a clever script by @CJK, which returns information pertaining to the UI element under the mouse pointer, and uses this data to automatically create a functioning AppleScript tell block.

Usage:

Hover your mouse pointer over the element you'd like to interact with and trigger the macro, which comes with its trigger set as:

T

Currently, you will be presented with four options:

  • Click
  • Get Value
  • Set Value
  • Get Coordinates

Here is a demonstration of each action type:

Click the font colour button in TextEdit

CleanShot 2023-09-21 at 12.44.42

Get the project tempo in Logic Pro

CleanShot 2023-09-21 at 12.24.45

Set the address bar contents in Safari

CleanShot 2023-09-21 at 12.34.27

Get the search field coordinates in the KM Editor

CleanShot 2023-09-21 at 13.07.40

This macro has not been exhaustively tested and I'm sure further contingencies will be required. To that end, I would encourage you to report back with any instances of malformed tell blocks. Indeed, if you can think of a more bullet-proof way to process the source data, that would also be of help.

Generate UI Element Tell Block.kmmacros (56 KB)

Macro screenshot

18 Likes

Wow Neil (@noisneil),

:star_struck: :star_struck: :star_struck:

…. Just don’t know what I could say…

You’ve done it again !

One vote by me for the Best Macro List.

An absolute Burner - and a very handy Tool which has to part of every one‘s Macro Library - I am not kidding …

There are so much possibilities with this kind of tool (and far to many are in my Head while I am writing this response) … I just have to have this … changing application on my iPhone to download this beauty…. …. …. Coming back to my response…

Thanks for this Macro … it will get installed into my Synced Library automatically, when I am at home and unlock any of my Macs …

Just one idea here … have you thought of supporting not only Foreground Applications, I mean Applications that live in the MenuBar like Bartender, Amphetamine or Yoink ?? - Just naming here three of many of the most famous ones out there …

I also think this thing is quite a good candidate of a Macro which has to be compatible with any Version of macOS since Yosemite and KM Version 8 and I also think about of enabling every Language besides AppleScript that is capable of using for GUI-Scripting….

I also have the Idea to use it to create All kinds of Macro Actions based on the GUI Elements under the Mouse Pointer….

The possibilities here are huge … and I will do my very best beeing part of the journey on developing this thing further…

Let me know what you think about this …

Greetings from Germany :de:

Have a great day my friend…

Tobias

2 Likes

That already works. It's whatever's under the mouse pointer.

Clicking a Menubar Item

CleanShot 2023-09-21 at 14.58.58

If people let me know about incompatibilities, I'll do my best to investigate them.

I'm not sure what you mean by this. My intention was to make a macro that generates an AppleScript tell block; to do one thing well. If you're referring to things like pyobjc, that's a road I'm not prepared to go down, as it requires users to install dependencies. AppleScript works out of the box and therefore offers far more utility for the average Keyboard Maestro user.

Fantastic!

Great! Welcome aboard!

Hi, @noisneil. You just keep cranking out the gems!

Thanks for sharing this creative and useful macro and thanks to @CJK's for the awesome AppleScript.


With Ventura 13.5.2, the underlying script does generate two errors when using within the System Settings Sound Panel.

Here are the errors:

  • 2023-09-21 11:37:42 Action 14952719 failed: Execute an AppleScript failed with script error: text-script:1114:1119: execution error: System Events got an error: AppleEvent handler failed. (-10000)
  • 2023-09-21 11:37:42 Execute an AppleScript failed with script error: text-script:1114:1119: execution error: System Events got an error: AppleEvent handler failed. (-10000). Macro “Generate UI Element Tell Block” cancelled (while executing Get Info for UI Element Under Mouse).
1 Like

Ah... Ok, this is an example of the initial script erroring out, so the tell block generator can't get started. Perhaps @CJK might be able to shed light on this...? AppleEvent handler failed is a bit too broad-ranging to help me understand what the issue is.

1 Like

I had a play with @CJK's script. I can get it to return some UI element info, but it only goes as deep as the group level. I have a feeling this might be to do with the multiple layers of nesting going on with the various panes of the System Settings application.

Adjusted Script
use framework "AppKit"

on mouseCoordinates()
	tell the current application to tell mouseLocation()'s {x, y} ¬
		of its NSEvent & NSHeight(its NSScreen's mainScreen's ¬
		frame) to return the {(item 1), (item 3) - (item 2)}
end mouseCoordinates

on infoForUIElementUnderMouse()
	return infoForUIElement at the mouseCoordinates()
end infoForUIElementUnderMouse

on infoForUIElement at __Ref
	local UIElement
	
	tell application id "com.apple.SystemEvents"
		tell process "System Settings" -- Explicitly targeting the System Settings app
			if {__Ref}'s specifiers = {} then
				tell __Ref to if its class ≠ list ¬
					then set __Ref to its {x, y}
				set __Ref to click at __Ref
			end if
			
			set UIElement to __Ref
			if the UIElement = missing value then return {}
			
			script Object
				property parent : UIElement
				property AXAttributes : a reference to (the ¬
					attributes in me whose (name is not ¬
					"AXURL") and (name is not "AXPath"))
				property AXValues : value of AXAttributes
				property AXList : the name of AXAttributes
				property AXRecord : a reference to the the ¬
					{«class usrf»:my AXList}'s contents
			end script
			
			set my text item delimiters to linefeed & linefeed
			tell (a reference to the Object's AXList) ¬
				to set the contents to paragraphs ¬
				of (it as text) & ""
			
			tell the Object to repeat with i from 1 ¬
				to the length of its AXValues
				set its AXList's item (i * 2) to ¬
					item i of its AXValues
			end repeat
			
			return {UI element:the Object's contents} ¬
				& the Object's properties ¬
				& (the Object's AXRecord as any) ¬
				& the {_AXActions:the name of ¬
				every action in the Object}
		end tell
	end tell
end infoForUIElement

return infoForUIElementUnderMouse()
Example Script Result (Output Button in Sound Pane)

UI element:group 2 of splitter group 1 of group 1 of window Sound of application process System Settings, minimum value:missing value, orientation:missing value, position:1156, 203, class:group, accessibility description:missing value, role description:group, focused:false, title:missing value, size:499, 625, help:missing value, entire contents:, enabled:missing value, maximum value:missing value, role:AXGroup, value:missing value, subrole:AXHostingView, selected:missing value, name:missing value, description:group, AXFrame:1156, 203, 1655, 828, AXParent:splitter group 1 of group 1 of window Sound of application process System Settings of process System Settings, AXChildren:group 1 of group 2 of splitter group 1 of group 1 of window Sound of application process System Settings of process System Settings, AXSize:499, 625, AXFocused:false, AXRole:AXGroup, AXTopLevelUIElement:missing value, AXHelp:missing value, AXChildrenInNavigationOrder:System Events, AXPosition:1156, 203, AXWindow:window Sound of application process System Settings of process System Settings, AXRoleDescription:group, AXSubrole:AXHostingView, _AXActions:

This is the tell block produced by my macro using this adjusted script:

activate application "System Settings"
tell application "System Events"
tell process "System Settings"
click group 2 of splitter group 1 of group 1 of window "Sound"
end tell
end tell

As you can see, it starts from a superficial group level. Here's what UI Browser gives me, for comparison:

activate application "System Settings"
tell application "System Events"
tell process "System Settings"
click radio button 1 of tab group 1 of group 2 of scroll area 1 of group 1 of group 2 of splitter group 1 of group 1 of window "Sound" 
end tell
end tell
1 Like

I tried to script that setting too but I haven't been successful.
I used ScriptDebuggers Library but couldn't find a way either.
The new settings app is just not made for automations. (Checkout switchaudio-osx from homebrew - might be easier than UI scripting for this job.)


I'll definitely use this macro! It looks really cool :heart:

2 Likes

Hi, @jandamm. I just tested @noisneil's clever macro with that tricky System Setting because I have experience with it from the time I was developing Set Sound Output.

FYI: I considered using switchaudio-osx, but I discovered some limitations that motivated me to create Set Sound Output.

1 Like

There's an Alfred workflow that switches output if that's what you're after..? You could use that as a basis for a script.

1 Like

I tried an Alfred workflow that didn't work for Ventura, but maybe I didn't use the right one. Do you have a link you could share?

Ah. It was ages ago. Probs the same one. Sorry mate. :man_shrugging:t2:

1 Like

This is fantastic, having just spent the last few days updating scripts from some new nuances of keynote automation, and digging through the accessibility inspector, I wish I had this, it would have saved me several hours. Great addition to my toolbox.

1 Like

This is amazing.

The AppleScript includes the window name, which obviously changes in Logic by project.

How do you make it project agnostic?

That's outside the scope of the macro, but I would suggest you save this as a text snippet for whenever needed:

set tracks_window to title of first window whose title contains "- Tracks"

You'll then be able to reference the Tracks window like so:

activate application "Logic Pro X"
tell application "System Events"
tell process "Logic Pro X"

set tracks_window to title of first window whose title contains "- Tracks"

click checkbox "Click" of group 1 of window tracks_window

end tell
end tell
1 Like

i am in awe. this solves many of my problems.

deeply appreciated

1 Like

Thanks for sharing. This is an incredibly welcome addition to my macro library. Scripting for Pro Tools is very clunky sometimes and this does what i'm looking for like 99% of the time when using UI browser, or dumping all UI elements from a window and combing through to find the one element i'm looking for.

1 Like

Yeah that was the idea! Glad it's working for you! :blush:

Updated to account for differing application and process names.

1 Like

Seems like i spoke too soon! It seems like with very few exceptions, anywhere i run the macro in Avid Pro Tools, it just returns a tell statement to the window, and not any included UI elements. Pro Tools has a lot of UI elements nested inside tables and I haven't dug into the code of this script, but alas i'll need to keep using UI Browser for now :slight_smile:

Does UI Browser work with PT?