AppleScript: How to Get a List of Macros in a Macro Group without the KM Editor Being Activated?

Hi @JMichaelTX,
Thank you so much for taking the time to post these examples and referring me to the resource page you created.

The JXA code for getting the macro list was a bit too complex for me. But with some extra googling and reading, I think I've understood most part. Only one thing puzzles me: indexOf("---").
I don't know what "---" is supposed to do?

I read two articles on your resource page that are written for beginners. They are VERY helpful! Now I have a general idea about how JXA interacts with other apps.

To provide a coder-friendly JXA script that you and others can use to learn and modify, I have provided this macro/script:

MACRO: Get List of KM Macro Names Filtered By Macro Group and Macro Name [Example]

To get JavaScript coding help on almost any term or expression, just do a Google search with:
"JavaScript <and whatever you want help on."

If have found this very very often provides the info/help I need.

Let me know if you have any JXA questions.

I used this in Macro Reporter, Rob, where it functions in an Execute for JavaScript for Automation action as you have it here.

That causes the HTML window of that macro to redraw each time a new group is selected from the popup for a report in the text area below the popup. I've been trying to get around that by folding the JS into the HTML prompt.

But I keep tripping over things. I avoided the Application call (and the getmacros call) with a local variable created in the AppleScript that gets all the group names to begin with.

But then I run into ObjC not being available. Even when I load AppKit. So either I'm lost or it just can't be done.

Somehow I'd like to get from the local variable with the Keyboard Maestro plist XML of all the macros to the HTML list of the macros for the selected group without redrawing the HTML prompt (using a JS function in the HTML head).

Now that I've spun my blinded self around three times, can you point me in the right direction.

Here's as far as I've gotten:

Macro Reporter 2.0a.kmmacros (16.8 KB)

1 Like

Pushing on deadline here, but I'll take a look later in the week.

Briefly, though, the ObjC interface is only exposed to the special JSContext set up for osascript – you can't get to it from a browser instance of a JS interpreter (i.e. you can't get to it from JS executing in a custom HTML action).

On the other hand, you should be able to:

  • Generate the data in an osascript context (like an Execute JXA action) using ObjC methods, and store it in a KM variable,
  • then pull it into the Custom HTML action browser JS context using window.KeyboardMaestro.GetVariable

Ah, hadn't thought of dismembering the code like that, storing the JavaScript object in a local variable for parsing in the HMTL prompt. I have a premonition the code won't survive my surgery, but I'll give it a shot later today. Thanks.

I managed to store the macros in a local variable before displaying the HTML prompt but that revealed a problem with this approach. The data was over 500K from my 1.1-MB plist file. And I suspect I'm on the small side with my macro file.

Thinking it over, I think a better approach would be to revise your function to return JSON-formatted local variable with just a few details from the full macro file for all the macros.

Something like this (but not prettified) which my previous variation of your function already collects:

{ "macro" : [
	{
		"group":,
		"name":,
		"enabled":,
		"used":,
		"triggers":,
	},
]}

That should be a lot smaller variable than what I had (especially if not prettified).

Then for any group selected from the HTML prompt's popup, I can write a function to list anything in the JSON list with that group name, format it as HTML and not have to redraw the HTML window.

The catch is I don't see how to modify your function to return all the macros with their group names and not just ones for a specific group.

KM helps this hobbyist perk up an old Mac running Mojave, with a little required assembly and help from posts on this friendly forum and others.

I'm not sure if this is the right place for this, but here goes.

Here is an AppleScriptObj snippet that helps me get a bit more use out of KM's resources as well. Hopefully, I hope it can help on the task of getting a list of macros without activating the KM Editor and and then adding a "mg_uid" and "mg_name" key/value pair to hold each macro record's containing macro group's uid and name values.

This snippet uses a "keypath collection query" to pull an array of all macro records from the output of the getmacros command provided by the Keyboard Maestro Engine Applescript Suite. It should work with output from the gethotkeys command too.

(I hope it doesn't duplicate another post's wheel. Or, worse, once it leaves my machine, doesn't spin at all...)

Summoning the macros array: two compact--but exceedingly melodious--forms.

  1. string as input:

use framework "Foundation"

tell application id "com.stairways.keyboardmaestro.engine" to set pxml to getmacros with asstring
set macroDictionaries to (current application's NSString's stringWithString:pxml)'s propertyList()'s valueForKeyPath:"@unionOfArrays.macros"

  1. data as input (same result):

use framework "Foundation"

tell application id "com.stairways.keyboardmaestro.engine" to set asData to getmacros
set nsDataObj to (current application's NSArray's arrayWithObject:asData)'s firstObject()'s |data|()
set fObject to (current application's NSString's alloc()'s initWithData:nsDataObj encoding:(current application's NSUTF8StringEncoding))'s propertyList()
set macroDictionaries to fObject's valueForKeyPath:"@unionOfArrays.macros"

That hurdle cleared, we can add the "mg_uid" and "mg_name" key/value pair (to hold the uid and name of a containing macro group) to each macro record.

For example.

I have more than a few macros whose names contain the word "test" festooning various macro groups.

The following script shows one way to work with getmacros to:

First, to get an array of macros whose names contain the word "test".
Second, to add an "mg_uid" and an "mg_name" key/value pair to each macro dictionary, showing its containing macro group's id and name.

use framework "Foundation"

tell application id "com.stairways.keyboardmaestro.engine" to set pXML to getmacros with asstring
set mgDictionaries to (current application's NSString's stringWithString:pXML)'s propertyList()
set macroDictionaries to mgDictionaries's valueForKeyPath:"@unionOfArrays.macros"
set macroName to "test"
set testMacros to macroDictionaries's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"%K CONTAINS %@" argumentArray:{"sort", macroName})

set testMacros to testMacros's mutableCopy()
repeat with i from 0 to (count of testMacros) - 1
set amacro to (testMacros's objectAtIndex:i)
set mUID to (amacro's objectForKey:"uid")
set predContainsUID to (current application's NSPredicate's predicateWithFormat:"%K CONTAINS %@" argumentArray:{"macros.uid", mUID})
set {anMgUID, anMgName} to ((mgDictionaries's filteredArrayUsingPredicate:predContainsUID)'s firstObject()'s objectsForKeys:{"uid", "name"} notFoundMarker:"not found")
set mDict to amacro's mutableCopy()
(mDict's addEntriesFromDictionary:{MG_UID:anMgUID, MG_Name:anMgName})
(testMacros's replaceObjectAtIndex:i withObject:mDict)
end repeat
return testMacros

The Keyboard Maestro Editor Suite, of course, makes all this a breeze.

What we want assembles promptly when KM Editor AppleScript issues this command:

tell application id "com.stairways.keyboardmaestro.editor" to set testMacros to macros whose name contains "test"

Each macro, now an object with its act together, answers the call to muster at a moment's notice, replete with info such as with its xml, its actions and their xml, in addition to its containing macro group and its properties and elements.

However, filtering with "keypath collection queries" and NSPredicate provides an alternative facility for coaxing similar results from getmacros for times when we don't need macro or action xml or the KM Editor.

Bonus: Fed a keypath collection query result, sorting with NSSortDescriptor is straightforward and quick.

Apple's page on: Key-Value Coding Using Collection Operators.

Various internet cheat sheets on NSPredicate help when one forgets the various incantations.

Hi, @CRLF. Welcome to the Keyboard Maestro forum.

Your first post looks interesting. Thanks for sharing!


When I see someone new to the forum, I like to share a few links that are helpful:

Since your post is packed with information, I suggest you revise it using the guidance provided in the third bullet.

1 Like