AppleScript to determine if macro is "available" to execute

Trying to run a macro in a group that is only available to a specific application will fail if that application is not active.

Screenshot 2024-09-01 at 1.12.57 PM

How can you check this before attempting to run it in Applescript?

The property of the macro and its group is "enabled" regardless of whether the application is active, so these will return "yes" either way:

if enabled of macro id uid is true then "yes"
if enabled of macro group of macro id uid is true then "yes"

but this will produce an error if the application is not active:

tell application "Keyboard Maestro Engine" to do script uid

Any idea for checking to see if the macro is "available" (for lack of a better word) to run in this case?

Do you actually need to check in advance, or can you just try to run the macro and handle the error if it isn't active?

tell application "Keyboard Maestro Engine"
	try
		do script "Inactive Macro Test"
	on error
	-- do "macro not active" stuff here
	end try
end tell

Don't do it then. :laughing:

Or to put it another way: why might you do so? I wonder what the context is.

I agree with @Nige_S that try is indeed probably the most straightforward way of handling a potential error, although I also wonder whether it might possibly suit you to call a macro that is always active and get it to deal with further conditions/routing.

Yes, I can do it this way. I was mostly just curious about approaches to my question, but it's not a big deal.

FWIW, groups have XML properties that could be useful here. For example, here's what the available application xml property looks like for the group I mentioned:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Targeting</key>
	<string>Included</string>
	<key>TargetingApps</key>
	<array>
		<dict>
			<key>BundleIdentifier</key>
			<string>net.shinyfrog.bear</string>
			<key>Name</key>
			<string>Bear</string>
			<key>NewFile</key>
			<string>/Applications/Bear.app</string>
		</dict>
	</array>
</dict>
</plist>

compared to a group that is available to all apps:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Targeting</key>
	<string>All</string>
	<key>TargetingApps</key>
	<array/>
</dict>
</plist>

So if you wanted to see if a group was available to all apps, you could do something like this:

if theXml contains "<key>Targeting</key>" & linefeed & tab & "<string>All</string>" then return "yep, sure is"

or even identify the app, etc. I don't need to do that, but I thought I'd share what I found in this particular rabbit hole :sweat_smile:

haha.

"Doc, it hurts when I do this."

"Don't do that then"

The context is running a macro via applesrcipt where the target macro is dynamic. If I were selecting it and/or running it manually, I would definitely follow your advice! :joy:

1 Like

Yes, I owed a debt to Tommy Cooper there.

Right, yes... So of course the macro ID would not always be the same.

Again then I wonder whether it might be worth thinking about calling a globally accessible macro each time and using it to handle routing to the relevant macro. Is it possible to pass in parameters when calling a macro from Applescript? If so, the target ID could be passed as a parameter, and the global, handling macro could test the availability of the end macro.

Ignore me if that's convoluted, impossible or otherwise unsuitable... I just wonder what is possible.

Oh, FFS... I brain-pharted and only looked at the macro -- this is, as you rightly pointed out, a group property.

So you can get available application xml, parse that to make a list of bundle IDs, then see if that list contains the front app's ID. Demo -- replace the UUID in line 1 with your group of interest:

set groupUUID to "F8125C71-707B-42BC-A257-D607BECDDAC9"

tell application "Keyboard Maestro"
	set theXML to available application xml of macro group id groupUUID
end tell

considering case
	if theXML contains "<string>Included</string>" then
		set AppleScript's text item delimiters to "<key>BundleIdentifier</key>"
		set appList to every text item of theXML
		set appList to rest of appList
		set AppleScript's text item delimiters to {"<string>", "</string>"}
		repeat with eachItem in appList
			set contents of eachItem to text item 2 of (get contents of eachItem)
		end repeat
	else
		--do nothing
	end if
end considering

tell application (path to frontmost application as text)
	set frontAppBundleID to id
end tell

if appList contains frontAppBundleID then
	display dialog "Macros are available"
else
	display dialog "No macros :-("
end if

The downside of this over the simple try method is, of course, that the KM Editor must launch if it isn't already running.

2 Likes

That is what I had in mind in concept when I said "or even identify the app, etc" but that is some slick parsing. I spent some time with your example Applescript and learned a few new tricks. Thanks for sharing Nige.

I’ve also learned something new from this …. Many thanks for sharing this Nige.

Greetings from Germany :de:

Tobias