Create macro that either creates a new macro or duplicates and renames macro [SOLVED]

Aaaaaand... DONE!!!

set theMacroGroupName to "_Tests"

tell application "Keyboard Maestro"
	set theMacroGroup to macro group theMacroGroupName
	
	tell theMacroGroup
		
		-- Creates new macro
		set theMacro to make new macro with properties {name:"_New Macro"}
		tell theMacro
			-- Creates the AppleScript Action
			make new action with properties {xml:"<dict>
		<key>ActionColor</key>
		<string>Green</string>
		<key>ActionName</key>
		<string>Open File</string>
		<key>ActionUID</key>
		<integer>15806619</integer>
		<key>IsDefaultApplication</key>
		<true/>
		<key>MacroActionType</key>
		<string>Open1File</string>
		<key>Path</key>
		<string></string>
	</dict>"}
		end tell
	end tell
end tell

Now I will just create the complete macro to add a Prompt to paste the path and name of the link, etc. Will share it here once it's done in case someone else wants to use it :slight_smile:

How I can then grab the ID from a Macro Group or a Macro?
I would like to use ID instead of the name in case I rename the Group or the Macro.

And if you can still explain that line and what item 1 means, I'm always open to some more knowledge :slight_smile:

EDIT: I found how to get the ID... super easy and obvious haha

set newMacroID to newMacro

Using the first script I ended up with this:

image

and when I use Display in Window I get this:

image

Now I just need to merge all this information with the final script.
Getting closer and closer...

Have you got the KM AppleScript dictionary open? Check the entry for "duplicate":

duplicate v : Copy an object.
duplicate list of specifier : The object(s) to copy.
[to location specifier] : The location for the new copy or copies.
→ list of specifier : The duplicated objects.

...and the last line tells you "the result of the duplicate action is a list of the new duplicates".

It's always a list, even if you only duplicate one thing, and you access the contents of a list item by item -- so you grab the contents of item 1 of the list and put them into newMacroID. newMacroID now hold a reference to first (in this case, the only) thing you duplicated.

You don't actually have to go any further -- that reference is the macro ID. For example, in Script Editor:

tell application "Keyboard Maestro"
	set theMacro to item 1 of (get selectedMacros)
	return theMacro
end tell
-> "F3B94063-5050-4E2D-8222-93EA72C9EFDD"

...from which you can get/set the name, etc:

tell application "Keyboard Maestro"
	set theMacro to item 1 of (get selectedMacros)
	set the name of macro id theMacro to "Whoops!"
end tell
1 Like

I've been watching this discussion evolve in real time (yes, it's a s l o w day) and I was wondering how - after you've created all these single-action macros - you intend to actually call them up and run them. Just curious :wink:

I just open KM's window and search for those macros.

Right now I use CMD+Space to open Raycast's window:

And I use OPTION/ALT + Space to open KM's window:

So I want to transfer as much as I can from Raycast to KM, because some things I do with KM require me to create an actual AppleScript file that Raycast reads and triggers KM. If I just start using KM 995 of the time, then I don't need to create those files anymore and it's also faster, because the macros run directly when I select them in that window, instead of having Raycast trigger KM, which always takes 1-2 seconds.

So my goal is to start using CMD+Space for KM and OPTION/ALT + Space for Raycast as a secondary tool, while KM will be the main tool

Another advantage of using KM over Raycast (when I'm using the AppleScript files to trigger KM macros) is that I can easily assign an icon to a KM macro, but with Raycast I need to have a folder with all the scripts, then a folder with all the icons as png files, which I then have to manually assign if I want to see the icons next to the script. For example these are scripts without the icon, but with a default icon

And these are the ones with custom icons, which require me to add them manually, once a week:

So by using KM I end up saving time and work every week and I don't have to have those folders with scripts and icons anymore

Wow - that sounds like hard work!

Have you thought of triggering your macros with a macro that looks like this?

image

It saves having to open KM and is more spotlight-like.

Then there's something like @mrpasini 's Favourites macro which is at the other end of the spectrum of complexity:

1 Like

How do I find that?

I see...
So similar to the For Each action, even if only 1 item is selected.
So item 1 refers to the position of that item in the list (which can be 1 or more items).
Makes perfect sense!

Your explanation is on point! :slight_smile: Thank you so much. Definitely saving this to my notes now.

That's exactly what my OPTION/ALT+Space does:

image

That's why I get this when I hit OPTION/ALT+Space:

1 Like

This seems like a very strict approach to what I'm trying to have. It's easier for me to just hit a shortcut, which in my case is CMD+Space, and then search for anything I want to do, instead of having another shortcut just for a favorites window that I need to keep updating with new ones and then I need to scroll to find the one I want, etc. It seems harder to maintain than Raycast, actually, because with Raycast I created a macro that automatically creates a new script file with the name, the script inside, etc, from the selected macro.

1 Like

If you are going to mess around with AS, start using a script editor -- it's much easier than trying things out in KM AppleScript actions. I'm stuck in my ways and use Apple's Script Editor (in the Utilities folder), but the cool kids will point you to Script Debugger which is much better, even in the free version.

Both will have an "Open Dictionary" menu item, from which you can select an app to view what (if anything, lots of apps don't support AS) commands are available.

My approach to this is to make a template Macro with the Actions I want and then copy this template Macro as XML. I edit this XML to replace the elements I want to customise with KM Variables.

Then I use an AppleScript to make new Macros with my bespoke elements. The nice thing is that the Macros aren't limited to single Actions as the XML is the whole Macro and can include lots of things such as the Macro trigger, its icon etc etc.

Here is a basic example:

EXAMPLE Create New Go to URL Macro v1.00.kmmacros (7.5 KB)

2 Likes

Yes, I use Script Debugger (used to use Script Editor in the past).
I'm just not familiar with the whole Dictionary stuff yet.

I found it:

image

I still need to understand how to read the content itself... :wink:

Thanks for sharing. This seems like a very useful tool (once I understand it)

Really interesting approach as well!
It's still important for me to find other approaches such as AS so I can get used to it as much as possible, so my other solution was a good way to practice a bit more.

In your approach, you are using the Group Name instead of the ID, but what if I then change the name?

I can see the reference to both Name and ID in the XML:

image

So my question is: if the XML in my macro (that you saved as LOCAL__XML) contains:
_Tests
but then I change it
_My New Tests

will that still work, if I keep
FDC4407D-E1B2-4684-909A-CC0EC04C6423
in there?

How does KM know that it should use the Name and not the ID or vice versa?

This is the sneaky thing about my use of:

tell application "Keyboard Maestro"
  importMacros macroXML
end tell

I discovered (through trial and error when I was trying to find the simplest way to make new bespoke Macros) that when Keyboard Maestro imports a Macro with the same UUID as an existing Macro it automatically gives the imported Macro its own new UUID.

But I'm still a bit confused...

For example I created a new Group with the same name as my main _Tests group, so KM doesn't care about duplicate names

image

so the only way to really know that we are importing a macro to the right group is by using the Group ID.

So the top group is this:

<string>_Tests</string>
<string>6FB2BEA6-8191-4D35-9486-59E55926D535</string>

and the bottom is this:

<string>_Tests</string>
<string>FDC4407D-E1B2-4684-909A-CC0EC04C6423</string>

So using your approach, how can I make sure that it always goes to the right group, in case I rename the group (e.g. _My New Tests), other than updating the LOCAL__XML variable, of course. If I want to "set and forget" that macro.

I'm thinking that maybe we can use AppleScript to first create a variable that gets the name of the group from the Group ID and then use that variable in the Local__XML variable?

Okay. If in future you rename the Group but want new Macros to go into that same Group you would just change the name of the Group in the prompt and the new Macro will still go into the same named group. You would not edit the XML again.

Yes, but again, I would like to "set and forget" that macro so basically I wouldn't even have that field for the Group name, because on my macro I will have some conditions that will automatically set the group based on the content. For example if the URL is set to something that starts with ~/ I know that this is a Finder path and it will go to a group called "Internal Links".
If it starts with https or http then it goes to a group called "External Links".

I'm aware that making this change only takes a few seconds, but if I can create a macro that will do all the work for me automatically based on the ID of the group, regardless of the name, why not? :wink:

So I guess that the AppleScript approach to gather the group's ID and save it as a variable seems like the only way?

Yes -- but why? Having two (or more) Groups with the same name is just making your life more difficult!

But let's say we're trying to make a macro for other people, who may well have duplicate group names. Assuming you could detect that problem and give them some way to choose which group they actually meant, I would

  1. Change the group name in the XML template to something (almost certainly) unique
  2. Import the macro
  3. Move the macro from that uniquely named group to the target group
  4. Delete the uniquely named group

So for a temp group call "My_Clever_Group_Name" (I'd actually use a spoofed UUID) the important bit of the AS would be:

tell application "Keyboard Maestro"
	importMacros macroXML
	move first macro of macro group "My_Clever_Group_Name" to macro group id "94B3E220-2AE1-4957-973A-8ADFC260E35D"
	delete macro group "My_Clever_Group_Name"
end tell

How you'd get the target group when there are multiple groups of the same name will depend on how you are getting the initial data. If you're hard-coding the group then that's easy -- just replace the id in the above.

1 Like

Of course. Don't forget that the Macro I uploaded was the most basic I could make it just to show the technique. You can customise it to do whatever you need.

1 Like

This was just a test to see if KM would allow groups with the same name or not. I was trying to understand if having a certain name in the XML would make a difference or not, so for example if the XML is set to having the group name "Tests", but that group is not available anymore (if the ID was 1234, for example), but there's another "Tests" group with ID 5678, then the XML would be using the 5678 group as the destination, which is not desired. So yes, that was just a test. I don't have any groups with duplicate names.

That's why I think that having the XML set to using the right name and ID is ideal to avoid any potential issues. And I can just set and forget that macro, regardless of what name I give the group in the future.

Let's say I rename the group and forget to update the XML. Every time I create a new link it will be adding it to a new group with the old name, right? So now I have to go and move all those macros to the new group and delete the old group. If I am using KM to avoid extra work, then that approach is convoluted when I can have a macro that does all the work automatically based on the ID and the current name of the group based on that same ID. Hope it makes sense?