A Hotkey to Repeat the Last Macro Used?

this seems trivial but have no clue how to implement this.

I want to bind a key that will launch the last macro I used in keyboard maestro. That is if ive used a macro to cut a line when I press the key bind it will relaunch that last cut line macro
does that make sense? Is it possible?

thx

Z

First we need to know the name of your Last Used Macro.
Let’s see the Keyboard Maestro Engine log.
/Users/admin/Library/Logs/Keyboard Maestro/Engine.log
We analyze the output of the log.
I find these possible cases in the log file:
case 1: Execute macro “

2020-03-25 10:57:55 Execute macro “nH Display Last Used KM Macro v0” from trigger Editor
2020-03-25 10:57:55 Execute macro “nH insert Display Text block v0” from trigger Do Script

Note: This is the most common line in the log. If the macro run correctly, we will see the macro name in the line. We can use “search and replace (with RegEx)” macro to extract from this line.
The RegEx should be : (^.+)(Execute macro “)(.+)(” from)(.+$)

case 2: line(text-script:) + “\r”

2020-03-25 10:58:48 text-script:199:226: execution error: Keyboard Maestro Engine got an error: do script found no macros with a matching name (macros must be enabled, and in macro groups that are enabled and currently active). (-1)
(blank line)

Note: Here’s two lines. One line include “text-script:”. Other line is a blank line. We can’t see macro name in this line.

case 3: line(text-script:) + line( Macro “)

2020-03-25 10:58:48 text-script:199:226: execution error: Keyboard Maestro Engine got an error: do script found no macros with a matching name (macros must be enabled, and in macro groups that are enabled and currently active). (-1)
Macro “nH Display Last Used KM Macro v0” cancelled (while executing Execute AppleScript).

Note: Here’s two lines. One line include “text-script:”. Other line has the macro name.
The RegEx should be : ( Macro “)(.+)(” cancelled)(.+$)

Even though, we cannot get the macro name from case 2, but I found that case 2 and case 3 always appear at the same time. So maybe they are just from one execution. This need to be tested in practical use.

case 4: Action timeout

2020-03-25 11:15:51 Action timeout exceeded. Macro “nH Convert Selected Text to Title Case v0 fromKMD” cancelled (while executing Copy).

Note: we see “Macro “” and “” cancelled” in both Case 3 and case 4. So the RegEx for case 3 is also for case 4:
The RegEx should be : ( Macro “)(.+)(” cancelled)(.+$)

case 5: bypass KMM: switch window macro

2020-03-25 11:00:14 Execute macro “Activate Application Switcher” from trigger The Hot Key ⌘Tab is pressed

Note: If you use KM to switch application window, you need to bypass this macro. It’s annoying and not necessary generally.
Use if then to check if the line matches the RegEx.
The RegEx should be : Activate Application Switcher

case 6: bypass KMM:

2020-03-25 10:42:13 Execute macro “nH Execute Last Used KM Macro v0” from trigger Do Script

Note: If your last used macro is itself—excute last used macr0, what would happen? It become a loop. You run excute last used macro to excute last used macro to excute last used macro…
So we need to bypass this macro. Use if then to check if the line matches the RegEx.
The RegEx should be : nH Execute Last Used KM Macro v0 (NOTE: this is the macro name on my Mac machine, change it to the name you use)

That’s the Problem 1: how to get last used macro name from KM engine log.

Focus on Problem 2: how to get the lines into KM. We can use Tail -n command in “execute a shell script” macro.
Inspired by the KM macro: Display Last KM Macro Error @JMichaelTX
Then use “For each” deal with each line in the lines. But now we have another problem. The original lines in log file is things like:

Line1 earlier earlier
Line2 earlier
Line3 new
Line4 newer
Line5 newest

In “For each” macro we analyze each line from first to last, but the first line is not the newest line. We need to reverse the line order.
We can use “Prepend variable with text” macro in for each line loop.
For the first line Line1, we run prepend (Line 1& linefeed) to a variable. This variable becomes:

Line1

For Line2, we continue with prepending. We get:

Line2
Line1

We continue with prepending. We get:

Line5 newest
Line4 newer
Line3 new
Line2
Line1

After we get the reversed lines, we use second For Each loop to check lines one by one. We break the loop as long as we find a macro’s name.

But we also has Problem 3—how to run KM macro by macro name.
Please see the screenshot in Script Debugger 7.
Screen Shot 2020-03-25 at 12.14.37
We use do script in AppleScript to do this work.
So we got the final KM macro to exctute the last used macro.
As for now, it works OK on my machine(MacOS10.12.6; KM Version 9.0.4). I only use hotkey to execute KM macro. So I cannot see other kind of lines in KME log file. You can add your case and RegEx.
You can test it on your machine. Please let me know if it helps.
nH Execute Last Used KM Macro v0.1_Backup_20200325_1241_v0.kmmacros (23.2 KB)

1 Like

Yes, it is possible, but may I ask why you want this? Why not just use the same trigger you just used to cut a line?

There are many issues to overcome to do this properly. @Yu_Cai has listed some some of them. One key issue is proper Macro Activation. It is easy to restrict the original macro to a specific app (or group of apps) using the Macro Group activation criteria. But the "Rerun" macro would need global access, and this could lead to running the original in an app where it should not be used.

Having said that, here is some untested pseudo code that you might use:

  1. In every macro that you want to use in the "Rerun" macro, set a KM global variable (say "DND__Last_Run_Macro_UUID") to the UUID of that macro using the "%ExecutingMacroUUID%" token.
  2. In the "Rerun" macro, run this AppleScript:
tell application "Keyboard Maestro Engine"
  set macroUUID to getvariable "DND__Last_Run_Macro_UUID"
  do script macroUUID
end tell
1 Like

thx so much for the response, this reason mainly conveinience . Similar to using Vim's . (repeat last macro) (where I got the idea from) I can bind a common easy to access key (like ⌘-.) and use that to launch the last macro.

For further clarification an example. Suppose I have a macro that creates a markdown list but its bonded to a key via a pallet. I would need to go ⌘-Bind, then press another key for a pallet submenu and finally the hotkey. now if I have 30 markdown files I want to quick edit this gets tedious. Instead I can just launch the last macro via the quick hot key and keep launching the macro instead.

Does that make sense? (to me it totally does :))

Would love to hear @peternlewis thoughts on this and if this could ever make it into keyboard maestro

thx again and stay safe everyone

Z

Yep, I get it.

Does my pseudo macro make sense to you?

Actually now that I understand your use case, the approach used by @Yu_Cai is probably better.

thx @Yu_Cai

I will look into it in depth tomorrow and let you know if it worked

z

It is probably not something I would implement simply because of the risk of executing the wrong macro - macros can be triggered by many things, such as timers or remote events or whatever, and so even though you consider the last macro to have executed as being the one you just triggered from the palette, technically the last macro triggered might be a timer macro that starts a background backup. And then re-triggering that macro might cause problems.

In this respect, a technique like the one @JMichaelTX described, where it is explicitly one of a list of macros to choose from would ne a lot safer, even if it was somewhere more tedious. You might also want to record the time the macro was triggered, and then you could double check that the macro had been triggered recently.

Thx all

@peternlewis explanation makes sense of the potential issues of running potentially harmful macros so I understand why this isn't a good idea to implement

@JMichaelTX: as @peternlewis suggested I tried to implement you method on macros that are safe and could be included in the repeat last macro key, yet I cant get it to run.

I suspect the issue is my misunderstanding of the set a KM global variable (say "DND__Last_Run_Macro_UUID") part.

this is the two example macros I came up with:

and for the repeat macro

any clue what I messed up :slight_smile: ?

thx again

stay safe guys

Z

hmmm updating that the actual write to variable seems to be working!
I can see the global variable changing after the successful macro launch

the problem then seems to be in the relaunch last macro part

I get this error:

I think this is the relevant log parts


2020-03-26 11:57:22 text-script:103:122: execution error: Keyboard Maestro Engine got an error: do script found no macros with a matching name (macros must be enabled, and in macro groups that are enabled and currently active). (-1)
 Macro “rerun macro” cancelled (while executing Execute AppleScript).
2020-03-26 11:57:28 Execute macro “45)scrrenshot-clip” from trigger The Hot Key 4 is pressed
2020-03-26 11:59:33 Execute macro “01) maximize all in MBP mode” from trigger Any application launches

any clue?

This is likely exactly one of the issues I pointed out: The original macro is NOT active when you trigger the ReRun macro:

2020-03-26 11:57:22 text-script:103:122: execution error: Keyboard Maestro Engine got an error: do script found no macros with a matching name (macros must be enabled, and ==in macro groups that are enabled and currently active==). (-1)

I ran a test with that exact AppleScript and it worked fine for me.

1 Like

thx @JMichaelTX! Sorry that im slow with this but nit sure I understand that, you mean that in the KM editor the macro I just launched via the normal hotkey isn't selected? Not sure im following that? I tried both with it being selected and not (again not sure that’s what you mean by active) and still didn't work.
Perhaps you can upload your two macros that worked for you so I can try it here locally?

thx again

Z

This nothing to do with the KM Editor app (Keyboard Maestro.app).
To understand what being "Active" means, see Macro Activation .

Let's start by keeping it simple.
Create a Macro Group with no restrictions (it is "global", available in all apps).
Put both macros in that MG.
Also, make sure the Action to set the Macro UUID is the FIRST Action:
image

Here are my two test macros:

Macro Set -- Main Macro and ReRun Macro

Macro Set -- Main Macro and ReRun Macro.kmmacros (5.0 KB)

Main Macro

image

ReRun Macro

image

2 Likes

Hi again and sorry for the late response (world is to crazy these days..:))

im sorry for being slow but I cant cant get it to work or understand this :slight_smile: I downloaded the 2 test macros you posted. I ran the first test macro and got confirmation it worked

then I binded a key to the second macro (the rerun last macro) and try to run it and I get an error. Here is the last few log entries

020-04-05 12:07:58 Execute macro “01) maximize all in MBP mode” from trigger Application “Finder” activates
2020-04-05 12:08:05 Assertion Failed: (flags & kPasteboardModified) == 0,  file: …/Source/XCAF/XClipboardHistory.mm:839, value: 0
2020-04-05 12:08:38 Execute macro “01) maximize all in MBP mode” from trigger Application “Finder” activates
2020-04-05 12:09:30 Execute macro “01) maximize all in MBP mode” from trigger Application “Finder” activates
2020-04-05 12:09:48 Running application query took a while (5014 us)
2020-04-05 12:09:50 Execute macro “ReRun Last Macro [Example]” from trigger The Hot Key ⌃⌥⇧⌘R is pressed
2020-04-05 12:09:50 text-script:102:146: execution error: Keyboard Maestro Engine got an error: a script must be specified (-1)

2020-04-05 12:09:50 text-script:102:146: execution error: Keyboard Maestro Engine got an error: a script must be specified (-1)
 Macro “ReRun Last Macro [Example]” cancelled (while executing Execute AppleScript).
2020-04-05 12:10:21 Execute macro “ReRun Last Macro [Example]” from trigger The Hot Key ⌃⌥⇧⌘R is pressed
2020-04-05 12:10:21 text-script:102:146: execution error: Keyboard Maestro Engine got an error: a script must be specified (-1)

2020-04-05 12:10:21 text-script:102:146: execution error: Keyboard Maestro Engine got an error: a script must be specified (-1)
 Macro “ReRun Last Macro [Example]” cancelled (while executing Execute AppleScript).
2020-04-05 12:10:29 Assertion Failed: (flags & kPasteboardModified) == 0,  file: …/Source/XCAF/XClipboardHistory.mm:839, value: 0

any clue what im doing wrong?

If its to much I can just give up as its not super critical for my workflow just a nice addition so please feel free to ignore if you don't have time.. :slight_smile:

thx again

Z

Check that the DND__Last_Run_Macro_UUID variable is in the Keyboard Maestro Preferences.

You will get “a script must be specified” if you run the AppleScript command:

tell app "Keyboard Maestro Engine"
  do script ""
end tell

So my guess is the variable is empty.

From your log file, it appears that you did NOT actually run (trigger) the main macro.
In fact, from your Notification image:

it appears that you clicked on the "Try" button at the bottom of the KM Editor.
When you do that, it will NOT set the "DND__Last_Run_Macro_UUID" variable, as shown in this image from the KM Editor:
image

So you need to FIRST assign a trigger to the Main Macro, and use that trigger to run it.

ha! You were right @JMichaelTX!

I wasn’t aware that using the try option differs from the use of a bind
it now works!

the reason it didn’t work before is that I launched the macro via a pallette

so I assume it dosent work via a pallet niow is the same reason it dosent work with the try. I wonder why its that?

thx so much

Z

Hi Peter,
I understand the risk you are saying. But I'm wondering if you could store the last executed UUID somewhere either in a variable such as the ENV variable, or we can get the UUID by using AppleScript. I think it is a good thing to allow users to use it with the knowledge about the potential risk of triggering the wrong macro. I was think about using a work around by searching the KM engine log. But I'm not sure if there is a reliable way to get it. Assuming the macro was successfully triggered, is the macro name of the last triggered macro is always in the last line and follow this pattern?

2021-09-19 23:44:10 Execute macro “Macro Name” from trigger The Hot Key ⌘Tab is pressed

If so, I can get the macro name from the quotes.

Thanks!

The log is not a structured resource, and is subject to change at any time.

That said, a safe way to do what is asked for this question would be a macro that looked something like this:

  • Grab the last line of the Engine.log file
  • Switch on the line
    • If it contains "name of a macro 1"
      • Execute Macro "Name of a macro 1"
    • If it contains "name of a macro 2"
      • Execute Macro "Name of a macro 2"
    • Otherwise
      • Notify "No Acceptable Macro Found"

That way it will never execute an unexpected macro (like a timed "Backup my Mac" macro), and it fails in a safe way.

The UUID of the last triggered macro is not something that makes sense in the context of Keyboard Maestro triggering macros continuously in a variety of ways.

Fortunately, @DanThomas already wrote a macro some years ago that can show recently executed macros more easily and efficiently than parsing the log:

I also wrote a macro a few years ago myself back when KM 8 was still new that piggybacks off Dan's work to show a further simplified list prompt of recently executed macros and lets you jump back to the editor to quickly modify whichever one you select. I still use it to this day:

You could easily modify it to run a macro chosen from the list instead of editing it, or to choose between them by, say, holding down a modifier key when making a selection.

Thank you so much for reminding me about that macro. I need something like it right now, and I forgot all about it. :smile:

1 Like