Execute Macro Action: 2 suggestions

Execute Macro Action is a lever to KM development and help to organize his code.

● At present only one optional parameter can be given to a KM macro

Although it can be simulated some way, it should be nice to have more native optional parameters.

● It should be very nice to have a "Navigate to macro source" item, in the gear menu, to navigate directly to the called macro, as an elegant mean to inspect / improve its code.

Thanks,
-- Alain

Currently, the only way a macro has to know what triggered it is the %TriggerValue% token, hence there is only one parameter. To do more than one parameter, I would need to come up with some way to have more than one value accessible. It would also add complexity to the Execute Macro action.

It’s possible I will one day do this, but it needs some serious thought as to how best to do it in a way that integrates well with the rest of Keyboard Maestro.

You can, of course, simulate it as you described, using some sort of separator (comma would be fine if you knew that you would never have commas in the parameter values, or something less common like a bullet (•) character). Then just set a variable to the TriggerValue token and then Search Variable to break it apart.

Direct support for multiple parameters would be easier than this, but not a whole lot easier, so it needs to be done well and cleanly otherwise it really doesn’t add enough value.

And yes, there absolutely should be some way to navigate directly to the target macro - that is definitely on the todo list.

1 Like

Is there a way to do this now or option click or something to go straigh to the macro. I love that you can drag macro actions straight in from other windows to override sub-macros. It is so much faster than waiting for the macro list to populate. I want to go to the reference macro without having to wait so long and then click and move around to click again.

image

I don't see anything in the current cogwheel but mabye @peternlewis has added another modifier way to do it though Option would be the one most likely since it is for the conflict palette I have tried every modifier combos and clicking I can think of to jump straight to the referenced macro. It would be awesome if there were two options to go straight to it and one to open in a new window. There are so many times that would have and will help me.

image

https://wiki.keyboardmaestro.com/action/Execute_a_Macro

It would also be very cool if when an Execute a Macro action is selected that a greyed out option in the "Go to Macro" shortcut Menu option becomes availble for open in a new window and go to in current window.

Here's an AppleScript that will extract the target macro id from the xml of the first Execute Macro action that is selected in the KM Editor. It will then have the KM Editor select it.

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

tell application id "com.stairways.keyboardmaestro.editor"
	if (count of (selection as list)) = 0 then return -- "Nothing is selected"
	set selection1 to item 1 of (selection as list)
	if class of selection1 ≠ action then return -- "The first selection is not an action"
	set dict to (current application's NSString's stringWithString:(xml of selection1))'s propertyList()
end tell

set MacroUID to ((dict's objectsForKeys:{"MacroUID"} notFoundMarker:"not found")'s firstObject()) as text
if MacroUID = "not found" then return -- "The selected action is not an ExecuteMacro action"

tell application id "com.stairways.keyboardmaestro.editor"
	set selection to macro id MacroUID
end tell

The script does nothing when:

  • There is no selection.
  • The first selected item is not an action.
  • The the first selection action is not an Execute Macro action.

Just assign a trigger to the macro below.
Select an Execute Macro action and run the macro.
The Editor will select the action's target macro.

Go To Macro of Execute Macro Action.kmmacros (2.5 KB)

1 Like

Hi, @skillet. Here’s another option:

@_jims

What a great idea! I somehow missed it.

FWIW, the AppleScript with the OpenURL action added.

(The first AppleScript actually worked for the "Execute a Subroutine" action as well.)

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

tell application id "com.stairways.keyboardmaestro.editor"
	if (count of (selection as list)) = 0 then return -- "Nothing is selected"
	set selection1 to item 1 of (selection as list)
	if class of selection1 ≠ action then return -- "The first selection is not an action"
	set dict to (current application's NSString's stringWithString:(xml of selection1))'s propertyList()
end tell

set {MacroActionType, MacroUID, URLScheme} to (dict's objectsForKeys:{"MacroActionType", "MacroUID", "URL"} notFoundMarker:"not found") as list
if MacroUID is not in {"not found", ""} then
	tell application id "com.stairways.keyboardmaestro.editor" to set selection to macro id MacroUID
else if URLScheme is not in {"not found", ""} and MacroActionType is "OpenURL" then
	if URLScheme begins with "keyboardmaestro://m=" then
		open location URLScheme
	end if
end if
--If we get here, the selected action is not an ExecuteMacro,ExecuteSubroutine, or an OpenURL action"

Assign the trigger of choice.
Select an Execute Macro, Execute Subroutine, or OpenURL action.
Run the macro.

Go To Target of Execute Macro,Subroutine, OpenURL Actions.kmmacros (2.7 KB)

1 Like

Thank you both this is very helpful. I have been at it for well over an hour trying to get the URL into a variable so I can open in a Keyboard Maestro window and then have the results open in the new editor window.

I have tried saving the results from the out put to a variable in the AppleScript action and then tried saving it directly to a variable from the AppleScript. Not sure what I am doing wrong. Thank you very much for your help with this.

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

tell application id "com.stairways.keyboardmaestro.editor"
  if (count of (selection as list)) = 0 then
    display dialog ¬
      "Nothing is selected in Keyboard Maestro." with title ¬
      "Keyboard Maestro" buttons {"OK"} ¬
      default button "OK"
    return
  end if
  set selection1 to item 1 of (selection as list)
  if class of selection1 ≠ action then
    display dialog ¬
      "The first selection is not an action." with title ¬
      "Keyboard Maestro" buttons {"OK"} ¬
      default button "OK"
    return
  end if
  set dict to (current application's NSString's stringWithString:(xml of selection1))'s propertyList()
end tell

set {MacroActionType, MacroUID, URLScheme} to (dict's objectsForKeys:{"MacroActionType", "MacroUID", "URL"} notFoundMarker:"not found") as list

if MacroUID is not "not found" and MacroUID is not "" then
  tell application id "com.stairways.keyboardmaestro.editor"
    set selection to macro id MacroUID
  end tell
else if URLScheme is not "not found" and URLScheme is not "" and MacroActionType is "OpenURL" then
  if URLScheme begins with "keyboardmaestro://m=" then
    -- Save to KM variable
    tell application "Keyboard Maestro Engine"
      set value of variable "Extracted KM URL" to URLScheme
    end tell
  end if
else
  display dialog ¬
    "This action does not contain a reference to a macro or URL that can be opened." with title ¬
    "Keyboard Maestro" buttons {"OK"} ¬
    default button "OK"
end if
Open Submacro in New Keyboard Maestro Editor Window

1 Go To Target of Execute Macro,Subroutine, OpenURL Actions in New Keyboard Maestro Window Macro (v11.0.3)

1 Go To Target of Execute Macro-Subroutine- OpenURL Actions in New Keyboard Maestro Window.kmmacros (7.0 KB)

That is not what the AS action in your screen shot does. It appends to a global, rather than overwriting it, and it's not clear what (if anything) your script is returning.

Check your KM variables in Settings. Do you actually have a variable named "Extracted KM URL"? set value of variable... is the "old" way of doing things and fails is the variable doesn't already exist -- better to use the setvariable verb instead:

setvariable "Extracted KM URL" to URLScheme

I'm not sure I understand. It looks like the script sets the current selection of the frontmost KM Editor window to a certain action -- why not just make a new window then set the selection?

Hi Skillet,

Thank you for giving the script a whirl!

The script was meant to emulate clicking on the" Go To Macro" submenu of the drop down menu in Execute a Macro, Execute a Subroutine without waiting for the main menu to load. It does only that. (Additionally, for an Open URL action selection as well when set to Edit Macro style URL Scheme)

I know you wanted an option to Go to Macro in New Window.

The script's logic makes that more tricky than it should be. Sorry about that.

We can definitely change things to make it a bit more plug 'n play, while both simplifying the logic and keeping the AppleScriptObjC's verbosity down to a dull roar. :sunglasses:

If you can count on the user to run the macro only when one of the three actions is selected, follow @Nige_S advice and you're done.

If not, we'll need to separate the condition checking from the "Go To Macro" implemenation (open location, in this case)

That way you can perform the Go To Macro action only AFTER you've opened a new window, only IF conditions are met.

To do that, let's change the script:

  1. No more Go To Macro via "open location".

  2. Return only the macro id or "" to "Execute the AppleScript" action when conditions fail (or just place "error" in front of all of your display dialogs and set the "Execute an AppleScript" to Failure Aborts Action).

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

property author : "@CRLF"

--┏━━━━━━━━━━━━━━━━━━━━━━━
--┃ PURPOSE: 
-- | In the Keyboard Maestro Editor,Extract a macro id from the first selected
-- | Execute a Macro, Execute a Subroutine or Open URL action.
-- | OUTPUT: macro id or empty string
--┗━━━━━━━━━━━━━━━━━━━━━━━

tell application id "com.stairways.keyboardmaestro.editor"
	if (count of (selection as list)) = 0 then return -- "Nothing is selected"
	set selection1 to item 1 of (selection as list)
	if class of selection1 ≠ action then return -- "The first selection is not an action"
	set dict to (current application's NSString's stringWithString:(xml of selection1))'s propertyList()
end tell

set {MacroActionType, MacroUID, URLScheme} to (dict's objectsForKeys:{"MacroActionType", "MacroUID", "URL"} notFoundMarker:"not found") as list
if MacroUID is not in {"not found", ""} then
	return MacroUID
else if URLScheme is not in {"not found", ""} and MacroActionType is "OpenURL" then
	if URLScheme begins with "keyboardmaestro://m=" then
		set MacroUID to macroUIdFromURLScheme(URLScheme)
		return MacroUID
	end if
end if

-- Handle extracting the macro id from a "Edit a Macro" style URL scheme
on macroUIdFromURLScheme(inputString)
	set inputString to current application's NSString's stringWithString:inputString
	-- Define the regex pattern
	set pattern to "[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}"
	
	-- Create the regular expression object
	set regex to current application's NSRegularExpression's regularExpressionWithPattern:pattern options:0 |error|:(missing value)
	
	-- Find the first match
	set firstMatch to regex's firstMatchInString:inputString options:0 range:{location:0, |length|:(inputString's |length|())}
	
	-- Check if a match was found
	if firstMatch is not missing value then
		-- Extract the match from the input string using the match's range
		return (inputString's substringWithRange:(firstMatch's range)) as text
	else
		-- Return empty string if no match is found
		return ""
	end if
end macroUIdFromURLScheme

(Be sure the Save Results to Variable option is set.)

This way you use the script's results to:

  1. Decide what to do next. (Open a new window, display errors etc)
  2. Implement and run a "Go To Macro" action.

SO:

If empty string --> error dialogs and/or stop the macro.

If Non-empty string -->

  1. open new window
  2. make an URL Scheme variable: keyboardmaestro://m=%Variable%Non_empty_string%
  3. Open URL action using the URLScheme
Macro Screenshot

The macro with the script is at the bottom.

@Nige_S's the-"'old' way"-characterization of your method of setting the output variable works best for me.

The nuances of its behavior and usage are puzzled out in a long informative thread started by none other than forum's very own, well, you. :wink:

Link

Save an Empty Variable - #18 by skillet

Here's a cheatsheet (with no claims of completeness) of ways to output a value from AppleScript to Keyboard Maestro.

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

set aVar to "and more text"

--Output and exit the script.  
return "some text" & linefeed & aVar -- (👉🏽: https://wiki.keyboardmaestro.com/action/Execute_an_AppleScript)

tell application id "com.stairways.keyboardmaestro.engine"
	--Set a km global/persistent variable and continue the script
	setvariable "aKMGLobalVariable" to "some text" & linefeed & aVar
	--Set a km "local" variable and continue the script
	setvariable "local_aKMVariable" instance (system attribute "KMINSTANCE") to "some text" & linefeed & aVar --prefixes "local" 
	--Set a km "instance" variable and continue the script
	setvariable "instance_aKMVariable" instance (system attribute "KMINSTANCE") to "some text" & linefeed & aVar --prefixes "instance" 
	--Make a km global/persistent var, and set its value--👉🏽
	set v to make new variable with properties {name:"aNewKMGLobalVariable"}
	set value of v to "some text" & linefeed & aVar
end tell

Go To Macro of Execute a Macro, Execute a Subroutine or Open URL action in New Window.kmmacros (8.0 KB)

It's funny/sad that I didn't realize that if I made a new window it always makes a new window and keeps the selection so I just needed to put that action first. The least of obveous solutions that have eluded me keeps on growing.

Haha I like it :grinning:

Nice, thanks for that reminder, I went back and read the entire thread again. Good to be reminded of what I once knew.

Thanks I have added this to my notes on Get and Set Variables in AppleScript as well as referenced macros.

Also for what it is worth to anyone that might come across this thread somewhat similar if you but in reverse if you want to find the macros that are reference a macro @DanThomas made a great macro about 9 years ago to do that which still works wonderfully for the selected macro.

**AAA - Automation - Example(s) - Skillet Macros.kmmacros (123 KB)

2 Likes

Okay so slight update to this. It only opens in a new window and selects the same action as long as it is not part of a subgroup. I wonder why that is and if that just is just further programing @peternlewis didn't want to do. As a result this macro fails if it is part of a subgroup.

Hi Skillet,

I'm sorry the macro is not working as expected.

The macro was set up to ...

If the selection is not one of these 3 types of actions--executeSubroutine,ExecuteMacro,OpenURL--the macro will fail, silently.

I'm not sure I'm clear on:

I take it you're using the original macro which uses AppleScript, not KM, to select the target action. In that case it would open the new window without first checking if a macro id was successfully extracted. If, for some reason, one of the 3 actions was NOT selected, no macro id would be selected. The macro would do nothing and all you would see is a new window with no change to the selection...

Sorry, I'm not clear on "subgroup".

Is it an action that contains one of the 3 types of actions?

If so and the selection is the container of one of the 3 types of actions, the macro will do nothing.

If you'd like to have the macro check if the selection is a containing action, that is definitely possible. If, however, that action contains more than one of the 3 actions, what would you like the macro to do? Select all of them at once? Or would a Prompt with List of the found actions be better? Should that list show the target macro names or the name of the found actions?

Or is the issue that the macro does not work if the first selection IS one of the 3 actions, but that action is an action? If that is the case, I'm flummoxed for the moment.

My appoligies I didn't mean to lead you down a rabbit hole. That was in response to Nige_S with making a new window.

Meaning if you have an action selected and it is part of a group, or a repeat action, If Then etc. when you make a new window Keyboard Maestro will no longer keep the selection. The action has to be a top level action.

Your macro works just fine I just can't use it and open the selection in a new window.

No apologies needed. Somebunny may have not read carefully...(Sorry, it's a shorcoming of mine. :grimacing:)

I'll be blitzed! It's as you say...My own fault for not checking this...

But this should not be an issue with last version posted. It won't open a new window without first checking if there IS a target macro to select.

If there are still issues, let me know...

Then it's my turn to be confused :wink:

You get the subroutine's/sub-macro's UUID from the selected action using @CRLF's script, then pop a new Editor window, then set the selection in that window.

For whatever reason make new window isn't working for me in KM Editor (I'm sure it used to, I'm probably just having a senior moment) so I've cheated and used do script to tell the Engine to perform a ⌃⌘N keystroke macro:

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

tell application id "com.stairways.keyboardmaestro.editor"
	if (count of (selection as list)) = 0 then return -- "Nothing is selected"
	set selection1 to item 1 of (selection as list)
	if class of selection1 ≠ action then return -- "The first selection is not an action"
	set dict to (current application's NSString's stringWithString:(xml of selection1))'s propertyList()
end tell

set MacroUID to ((dict's objectsForKeys:{"MacroUID"} notFoundMarker:"not found")'s firstObject()) as text
if MacroUID = "not found" then return -- "The selected action is not an ExecuteMacro action"

-- workaround for `make new window` not working
tell application "Keyboard Maestro Engine" to do script "<dict>
		<key>KeyCode</key>
		<integer>45</integer>
		<key>MacroActionType</key>
		<string>SimulateKeystroke</string>
		<key>Modifiers</key>
		<integer>4352</integer>
		<key>ReleaseAll</key>
		<false/>
		<key>TargetApplication</key>
		<dict>
			<key>BundleIdentifier</key>
			<string>com.stairways.keyboardmaestro.editor</string>
			<key>Name</key>
			<string>Keyboard Maestro</string>
			<key>NewFile</key>
			<string>/Applications/Keyboard Maestro.app</string>
		</dict>
		<key>TargetingType</key>
		<string>Specific</string>
	</dict>
"
tell application id "com.stairways.keyboardmaestro.editor"
	set selection to macro id MacroUID
end tell

You can run this as-is from your favourite AppleScript editor, or pop it into a single-action macro:

Reveal Subroutine:Submacro.kmmacros (3.6 KB)

I was just triggering a new window before I ran the macro.

Open New Window

I searched for a bit as well but it looks like this is the way to do it.

Thank you this is working very well and just what I was looking for!!