“Trigger Macro by Name” for a Specific Macro Group?

Hi everyone,

I’m trying to set up a shortcut that triggers the “Trigger Macro by Name” action, but limited to a specific macro group.

The reason I want to use this specific action (rather than a custom list prompt) is because it supports search, and it also shows the macro icons and assigned hotkeys — which makes it a great substitute for the classic macro palette.

Here’s what I’ve tried so far:

  1. I used this macro shared by noisneil, which dynamically lists all macros in a group and lets you trigger one. It works great — but unfortunately, the menu doesn’t display icons or hotkeys like the native “Trigger Macro by Name” does (see image)

  2. I also tried using the built-in “Trigger Macro by Name” action and manually restricted it to a specific macro group (see attached screenshot). But when I trigger it, it automatically pre-fills the search field with my last search term, instead of showing the full group's macro list cleanly. I couldn’t find a way to reset or clear that behavior.

So, is there any way to get the full native experience of “Trigger Macro by Name” — with icons, keystrokes, and search — but scoped to just one macro group?

Thanks in advance

Here's how I do it:

I set up two Smart Groups in the Editor:

1: All Macros: search string: all:
2: App-Specific: search string: app:

Then I use the following macro (and a small submacro) to select either a macro for the front-most app (hotkey: §) or any macro from my entire library (hotkey: ⌥§).

Trigger Macro by Name.kmmacros (46 KB)

Macro screenshot

Trigger Macro by Name - Move Cursor (SUB-).kmmacros (45 KB)

Macro screenshot

Hey, I set it app as you did. While it does list me the group macro, it also includes other macros which are not in this group.

Any idea why and how to make it show only the front app macro group macros ?

If you've set up your smart groups correctly, this shouldn't be happening. Can you post a screenshot of your "App-Specific" smart group settings?

Obviously, you also need to ensure you've selected the correct smart groups for the actions in the macro.

Hey, here’s how i configured it. Tell me if there is something i did wrong.

Smart Groups :

and this is the macro :

For instance, here's the macro of the Safari group:

However, when I trigger the discussed macro, i get this :


As you can see, while it does list me some of the macros of the fron app, it also shows me other macros which are in other groups. And also, for some reason they are not sorted at they are actually sorted in the macro group (previous image)

Looks good to me!

How are you triggering it? Are you pressing § while Safari is at the front? If so, I'm not sure why it isn't only showing you Safari macros. § would show all macros, just to be clear.

This is a Keyboard Maestro thing where macro numbers formatted as 01) etc are removed from the macro name when listed. I'm not sure if there's a way around that. FWIW it's never bothered me; I just type the first couple of letters of my macro name and there it is.

Of course! The only real icon for the job. I will be submitting for immediate, unofficial adoption the subroutine representation convention, "Submarine", for adoption. After attending to a few things offscreen, a macro for faciliting the "Submarine" standard should be forthcoming.

1 Like

I have just posted “A “trigger macro by name” prompt for only the active macros that you want to see”. A tweak of that method might meet your needs, but you would have to experiment to see what worked best for you.

I made a macro for setting icons in case you haven't seen it:

1 Like

Hey guys, I have found a solution :slight_smile:

So first, I created a subroutine which gets the macro group(s) name of the frontmost app and saves it as a variable (by using an Apple script) :

After that, I created the trigger macro by name: macro:

As you can see above , it gets the group name, and then appened it in the initial search, (note that i eventually used gr:)

The final desired product :slight_smile: :


Also, there is no need to put this in each macro group in order to use it. Because it is fully automated, so we can put it directly in the global macros group.

Thank you all for your valuable leads and directions, especially @noisneil

1 Like

Interesting. What happens in cases where a single group is associated with multiple apps or vice versa?

Since it looks like the Editor will be open anyway maybe script changes to the Search Strings of the Smart Group that Trigger By Name uses?

If we're looking for names of groups whose only target is the front app, here is a script that gets that list by reading the ~/Library/Application Support/Keyboard Maestro/Keyboard Maestro.plist

--“Trigger Macro by Name” for a Specific Macro Group? - Questions & Suggestions - Keyboard Maestro Discourse
--                 https://forum.keyboardmaestro.com/t/trigger-macro-by-name-for-a-specific-macro-group/41019/11


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application id "com.stairways.keyboardmaestro.engine"
	set frontAppBundleID to process tokens "%ApplicationBundleID%1%" 
end tell

set fn to "Keyboard Maestro Macros.plist"
set posixPath to ((current application's NSString's stringWithString:(POSIX path of (path to application support from user domain)))'s stringByAppendingPathComponent:"Keyboard Maestro")'s stringByAppendingPathComponent:fn

set pObj to current application's NSPropertyListSerialization's propertyListWithData:(current application's NSData's dataWithContentsOfFile:posixPath) options:0 format:(missing value) |error|:(missing value)
if pObj is missing value then error (theError's localizedDescription() as text) number -10000

set mg to (pObj's valueForKeyPath:"MacroGroups")
set groupsTargetingOneApp to mg's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"%K == %i AND %K IN %@" argumentArray:{"Targeting.TargetingApps.@count", 1, "Targeting.Targeting", {"All", "Included", "Running"}})

set groupsTargetingFrontOnly to groupsTargetingOneApp's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"ANY %K == %@" argumentArray:{"Targeting.TargetingApps.BundleIdentifier", frontAppBundleID})
set {TID, text item delimiters} to {text item delimiters, linefeed}

((groupsTargetingFrontOnly's valueForKeyPath:"Name") as list) as text

BTW.

Custom Icon Manager is super nice! Thank you! I should have searched around.

Search macro by submarine icon is what's up next, then... (Though I suppose just Smart Group Search by Subroutine trigger would be the rational thing to do) I think it's a must for implementing the submarine subroutine naming convention. :wink: I'll get something together after a while... :snail:

Exactly. This does the trick for submacros:

all: "Execute Macro"

So many ways to slice and dice in KM.:upside_down_face:

t:subroutine
2 Likes

Sorry for the lateness of this.

This post extends @megira's idea of querying the group "available application xml" to get Trigger By Name to to display the macros of groups that specify that they are active in the front application.

Getting the names of groups that specify availability in the front application via xml on the fly seems like a good idea. It's just that we can't get "search strings" to take full advantage of them.

The Editor interface of Trigger By Name wants its source loaded before the macro runs. Can't Trigger By Name be more like Prompt With List?

How about using the plist xml form of "Trigger By Name" with KM Editor's "do script" command--which takes uids instead of names--and build the whole action on the fly?

Here's a macro that demos the concept only.
Trigger by Name With Groups Specifically Active in Front App.kmmacros (15.7 KB)

Macro Image

Setting "Trigger By Name" options, like Initial Search or Set Action Timeout etc. have to be done by setting values of the action dictionary in the AppleScript, since I've not mapped any of these to macro Set Variable To Text actions.

USAGE:

  1. Enable the macro and its containing macro group.
  2. Run the macro. The initial search displays "a".
  3. If no groups target the front app, the action displays groups that are available in all apps and the initial search string displays "all".

To set the method of querying groups, set the variable, localQueryKMPlist, in the macro to true or false. (see Macro Image)
True queries the Keyboard Maestro.plist and the Editor need not be open.(~/Library/Application Support/Keyboard Maestro/Keyboard Maestro.plist))
False queries the Editor's group objects using the method @megira shows us and the Editor will open if it is closed.

The following options may be changed in the AppleScript:

1. Macro Scope ("Active Macros", "All Macros","Enabled Macros")
2. Intitial Search
3. Timeout Aborts Action

In the AppleScript find the section that starts and ends with: :gear::gear::gear: (see Macro Image)

To set the scope, replace Active_Macros with either Enabled_Macros or All_Macros,
Example: set theAllowedMacrosPolicy to Active_Macros --> set theAllowedMacrosPolicy to Enabled_Macros

The default initial search setting is:set InitialSearch of Initial_Search to "a"
Replace the a in quotes with your new search setting.
Example: set InitialSearch of Initial_Search to "b"

Set true to false to change the default timeout setting, set timeOutAbortsMacro to true

Explanation

Running "Trigger By Name" as xml does mean losing the Editor interface in order to gain the flexibility of Prompt With List.

This looks more kludgy than it is, I think. The risks of interfacing with Trigger By Name functionality via raw xml can be shifted to Apple's plist xml managment toolset, which handles validation, encoding for xml, etc invisibly. Plus, KM's plist xml consistency--reflective of the solidity of the app itself--ensures that input is always valid. All that is left for us to do is move uids around. Not bad.

For the present case, it is the querying for groups that we want that is tricky.

Two ways of fetching uids come to mind.

  1. Querying the Editor's scripting objects. (The Editor must be open, at least in the background)
  2. Querying the KMPlist directly. (The Editor need not be open. Complex queries, including regex, can be used.)
    (The KMPlist is found at ~/Library/Application Support/Keyboard Maestro/Keyboard Maestro.plist)

This demo offers both options, the method that @megira suggests is the default. The second uses of Apple's property list to query the KMPlist directly.

NOTES:

Queryable App availability values in "available application xml"

"All" = Available in all applications
"Included" = Available in these applications :white_check_mark:
"Excluded" = Available except in these applications
"Running" = Available when these applications are running :white_check_mark:
"RunningNotActive" = Available when these applications are running but not active
"NotRunning" = Available when these applications are not running

After querying the desired group ids, build the Trigger By Name xml using Apple's property list methods.

  1. make the dictionary form of the Trigger By Name xml
  2. add the list of ids.
  3. set the option key/values.
  4. convert the finished dictionary to plist xml.
  5. pass the plist xml to the KM Editor's "do script" command and run the on-the-fly Trigger By Name xml.

I'd also been thinking about this. Here's a macro that gives you the option of going to the macro in the Editor (instead of executing it), if you hold ⌘ when making your selection.

Trigger-Edit Macro by Name.kmmacros (53 KB)

Macro screenshot

What happens if the AS returns multiple Group names (multiple lines)?

Don't forget that you can include tokens in the "Trigger Macro by Name" action's "Initial search" field. So if (as is looks from your screen shot) your Groups are named "_appName" then:

image

I'm losing the plot here...

Are we simply trying to avoid putting "Search Strings" into the standard action's prompt? If not, what does all the extra work gain us over:

image

Only thing I can immediately think of is that a multi-term search is AND rather than OR...

But if we do want to prompt for specific, variable, Groups -- why not leverage all the goodness of the standard action's prompt, including -select to edit a macro, by building and executing the action on the fly?

Execute an AppleScript.kmactions (1.9 KB)

AppleScript:

-- Routine to gather Macro Group UUIDs goes here
-- Using hard-coded for testing
set theUUIDs to {"EFD8CD55-B814-4720-9039-E57F8D30321D", "B42FBB85-23B4-4EE4-8255-A57697FDE6E5"}

-- Set scope to "active", "enabled", or "all"
set theScope to "all"

set preXML to "<dict>
<key>ActionUID</key>
<integer>99781255</integer>
"
set midXML to "<key>MacroActionType</key>
<string>TriggerByName</string>
<key>Macros</key>
<array>
<string>"
set endXML to "</string>
</array>
<key>TimeOutAbortsMacro</key>
<true/>
</dict>"

if theScope is "enabled" then
	set scopeXML to "<key>Allowed</key>
<string>IncludeInactive</string>"
else if theScope is "all" then
	set scopeXML to "<key>Allowed</key>
<string>IncludeDisabled</string>"
else
	set scopeXML to ""
end if

set AppleScript's text item delimiters to ("</string>" & linefeed & "<string>")
set groupsXML to theUUIDs as text

set theXML to preXML & scopeXML & midXML & groupsXML & endXML

tell application "Keyboard Maestro Engine"
	do script theXML
end tell
1 Like

Holy moly... I've been asking Peter to add Go to macro as a feature and it's already there! Thanks Nige!

1 Like

This post probably won't help. (I've had words with my editing staff😉.)

For my part, I may have lost the thread of the discussion, which I take it starts from the wish to have more control over the list that TBN (Trigger By Name) shows before it displays.

I'm likely missing something--since underestimating KM or the ingenuity and resourcefulness of its many adept practitioners is a common error--but I think the thing that we're running up against is the limits of using Search Strings for this goal.

The sense of scope of "app:" search string seems related to KM's use of "availability", which, I think, refers to inclusion + exclusion . So:

This won't matter if you don't have any macro groups that exclude the front app.

But if you do, app:Finder is going to match those too.

We will see macros that we want to see in the Finder plus those we don't want to see in the Finder. (app:-Finder , for my groups, seems to match nothing.)

Also...

and...

TBN's pre-filtering is really, really nice.

With All/Active/Enabled, we can filter the source list before it displays.

Search Strings further prunes that list by fields.

For multi-category searches, TBN can use Smart Group with multiple Search Strings as input. However, the main use of the Smart Group is for searches in the Editor and the Editor Suite contains its scripting commands. So if we set a Smart Group's Search Strings via AppleScript the Editor needs to be involved and would open.

To me, it seems that with @megira 's criteria what we are having trouble avoiding is resorting to the xml interface of the action.

So...

then

then

The TBN action as on-the-fly KM xml would bring TBN closer to Prompt With List's acceptance of a variable as input, making input more customizable.

Apple's many query operators include a MATCHES keyword for regex filtering for any property plus any key.

On the fly id input in TBN is super simple since it accepts ids of smart groups, macro groups and macros equally.

Wonderfully, need not worry adding Active or Enabled to our queries since we can set TBN to filter our list of ids after inputting them.

All this might bring the goal of more customized initial TBN macro name lists closer.

How I limit which macros are listed by “macro by name”

With a perspective on this issue of limiting TBN's initial list, @kevinb says:

If you don't care about such things, you have the right priorities in life...

Yep.

KM mainly tilts the effort/reward balance towards high reward low effort.

Justifying accessing KM functionality from its least tractable side, raw xml (literally no interface), may well not be worth the effort.

Yet, xml access is indeed an available KM feature after we have tried accessing its functionality via its GUI or AppleScript.

Apple's Obj-C plist query toolset, built on the same conventions as AppleScript queries, is verbose, can compound the effort costs of using KM xml and can often be avoided.

Still, it constitutes a fit interface between the user and shallow-nested, raw KM xml.