Feature Requests: Comments on Triggers, Rearranging Triggers

Notes on Triggers

KBM allows me to have long macro names, to have long names for groups of actions, and in many other ways supports my documenting my macros so I know what I was thinking when I come back to it next week, next month, or next year.

But I haven't found an easy way to document macro triggers, except to add a comment explaining the triggers as the first action in the macro. That mostly works, except ...

Now that it is possible for a macro to test exactly how it was triggered, I have found it very useful to combine multiple, parallel, similar macros into a single macro so that it mostly does the same thing but sometimes does a variation, depending on how it was triggered. Like adding Shift or Control modifies to an existing hotkey macro for specific variations, instead of creating a dupl9cate macro that then has to be kept in sync if there are changes.

I have some macros that have over 30 different triggers, and there have been times that I wished I could simply add a short comment to remind myself what that particular trigger means.

@peternlewis, would it be hard to add a Note field next to trigger identifications?

Everyone: would you find this useful?

Add New Trigger Anywhere in the List

Also, again in those macros with ovr 30 different triggers, sometimes I have wished that I could add new triggers to the list with the same flexibility as I can add new Switch options. Right now, we can only add new triggers to the bottom of the list:

image

In the Switch action, we can add new options anywhere in the list that makes the most sense:

image

It would be useful to be able to have that same flexibility of ordering of new additions to a Trigger list as we have with a Switch list.

This is especially an issue when I am switching on the trigger value and want to add a new modifier key variation to an existing trigger. I would like to organize the trigger list and the switch list the same way, by base key, but to add a new trigger anywhere in the list other than at the end means recreating the whole list. That's painful.

2 Likes

I have never used more than 2 triggers in a macro, so far, but I would imagine that if I had 30+ triggers in a macro, I would want to use the freely editable text field of the Comment action so that, if I wanted to, I could easily copy and paste the full list in one go, and because my note for each trigger could be as long as I needed.

I would also consider keeping that list of triggers in my separate notes (KM is not designed to be a text editor, let alone a notes system).

I appreciate that your preference is not the same as mine. Overall, though, I suspect that having so many triggers is unusual, so while I certainly would have no objection to the suggestion, I think your use case here may be quite niche (I would be interested to hear from other users if I am wrong about that!).

My solution to this general issue—not having 30 triggers on a macro, but just remembering key shortcuts and/or functions—was to steal a gesture-button from my Logitech mouse.

When I press and drag up on the base's thumb button, it opens a PDF using Quick Look (so no apps open) that I created in Keynote. That PDF contains tidbits of info on the many macros and shortcuts that I occasionally need help with :). When I'm done viewing, I press Escape or just click elsewhere, and it's gone.

-rob.

1 Like

Similar to griffman's strategy is the Cheaters project from Brett Terpstra. It could easily be modified to develop a customizable, globally accessible cheat sheet.

To each their own, so I hope you won't mind saying that, to me, the method on that site seems a bit over the top.

If one needs to refer to a cheat sheet more than a few times to look up a set of related hotkeys, I would suspect that those hotkeys could have been better chosen in the first place – for example, with more mnemonic choice of letter key, or with a more consistent set of modifier keys. So I don't see a need for anything elaborate.

However, I shall repeat "to each their own"! :wink:

1 Like

Would it be hard? My friends and I had a saying dating back to when I was in University “It’s just code”. It wouldn't be particularly difficult, but it would add additional visual complexity for everyone that (I strongly suspect) is rarely needed.

Being able to add triggers in the middle is something I'll consider. Being able to rearrange that (+) (-) style list is on the todo list.

6 Likes

I won't object to trigger (or condition) rearrangement, but I'm happier when new features are added, like Dictionaries, OCR, a hook into Apple's OCR, Find Image, Stream Deck support, Try/Catch, Execute Shell Script with Input From, Progress Bar, Switch, etc. I use all these features every hour of every day.

1 Like

Hi Kevin, you wrote:

I interpret that to mean copying the list of triggers and pasting it into a comment text field. Is that what you are talking about? If so, I am having trouble figuring out an easy way to copy the list of triggers. Have you been able to do it?

Two ways occur to me, one is using Dan Thomas' KMET macros (@DanThomas Keyboard Maestro Edit as Text), but triggers in either XML or JSON are encoded, not straight text, so it does not easily paste into a comment field.

The other way is to change the KBM mode to Stop Editing Macros and then it's easy to copy the list.

image

Triggered by any of the following:
Trigger iconThe Hot Key ⌥⌘A is pressed
Trigger iconThe Hot Key ⌥⌘B is pressed
Trigger iconThe Hot Key ⌥⌘D is pressed
Trigger iconThe Hot Key ⌥⇧⌘D is pressed
Trigger iconThe Hot Key ⌥⌘E is pressed
Trigger iconThe Hot Key ⌥⌘F is pressed
Trigger iconThe Hot Key ⌥⌘G is pressed
Trigger iconThe Hot Key ⌥⌘K is pressed
Trigger iconThe Hot Key ⌥⇧⌘K is pressed
Trigger iconThe Hot Key ⌥⌘L is pressed
Trigger iconThe Hot Key ⌥⌘M is pressed

So thanks for the idea.

Now "all I need" is to automate editing a list in this format, with an embedded comment format, into either XML or JSON and pasting it into the appropriate place in a KMET editing file. If I could get that working, then I could edit the KBM Comment action as needed and then automatically edit the overall macro's trigger list to match.

As @peternlewis commented, "It's just code" but is it worth the effort? It might be fun, and that in itself is "worth it". If it turns into a headache, then no, it's not.

1 Like

My point was that keeping the information together in a block of plain text avoids just such a challenge. When I referred to the "freely editable text field of the Comment action" I was thinking of how easy it is to just copy and paste all the information to and from any notes sytem (whether it be a text file, a PIM or whatever one prefers).

Ah yes, that's nifty!

I'll have to leave that one to the experts. I'm sure someone will know a great method.

After you've copied it:

-- get copied trigger list
set theTriggers to (get the clipboard)

-- remove the icon text
set AppleScript's text item delimiters to "Trigger icon"
set theTriggers to every text item of theTriggers
set AppleScript's text item delimiters to ""
set theTriggers to theTriggers as text

-- add the "Comment" action
tell application "Keyboard Maestro"
	set theXML to "<dict>
		<key>MacroActionType</key>
		<string>Comment</string>
		<key>Text</key>
		<string>" & theTriggers & "</string>
		<key>Title</key>
		<string>Trigger List</string>
	</dict>"
	set theAction to make new action at beginning of macro id (item 1 of (get selectedMacros))
	set xml of theAction to theXML
end tell

...will insert a new "Comment" action at the beginning of the macro, like this:

If you want formatting, icons, etc you will have to jump through some more hoops -- the "Comment:" text in the XML appears to be base64-ed RTFD. At that point it is probably easier to drive the KM Editor UI -- select first action, insert a "Comment", "Move Action Up" then "Enter Action" menu items, set "Title" field, tab, paste in the trigger list.

1 Like

Thanks @Nige_S,

That's awesome!

Another route to formatted text without having to deal with base64 would be to open a temporary Text Edit file, past text, manipulate text, copy text, close file without saving, paste copied text into comment. That has the "drawback" of watching the TE file get opened and closed, but that's an acceptable tradeoff for being able to do the formatting with familiar tools.

I'm amused at your use of

set AppleScript's text item delimiters to "Trigger icon"

to eliminate that text. I've never seen anything quite like it and it's very clever.

When you set it back, are you setting it to the empty string?

Yeah -- I'd class that under "drive the UI". I'm sure there must be a way to keep an un-edited Copy of the triggers as RTFD, but it's beyond me.

RTFD is probably only so you can have the images -- I shall have a play with RTF at some stage.

Yep, we're setting it back to the empty string so there's nothing between the list items when we cast them back to text.

TBH it's a bit broad-brush way of doing it and, given we're KM users, we can do a lot better:

tell application "Keyboard Maestro Engine"
	set theTriggers to (search theTriggers for "(?m)^Trigger icon" replace "" with regex and case sensitive)
end tell

No need for lists at all, much more precise, and probably faster for larger amounts of text.

I could use some help walking through how that magic line works. The beginning:

tell application "Keyboard Maestro Engine"
   set theTriggers to (search theTriggers for ...

seems pretty straightforward. That is it telling KBM to set the variable called theTriggers to the result of the search, where the search is within the existing value of theTriggers. I presume theTriggers is what we got from the clipboard, as previously.

But the rest of the line reads, to my inexperienced eye, a bit inside out and backwards.

Here's my interpretation, based on the goal:

The with at the end contains two parameters, regex and case sensitive, and those specify how the string after the for is interpreted. Whenever, wherever there's a match, the found string gets replaced with "".

How did I do? Have I got that part of it right?

Then after theTriggers is edited, we construct the XML for a new Comment action and add it to the beginning of the first currently selected macro.

Still OK?

Sometimes the fact that AppleScript is supposed to be "English-like" gets in the way of readability, IMHO.

You're there, but for clarity:

tell application "Keyboard Maestro Engine"
   set theTriggers to (...)
end tell

We're telling KM Engine to set the variable theTriggers to the result of the expression inside the brackets. As to what's in there:

search theTriggers for "(?m)^Trigger icon" replace "" with regex and case sensitive

search is a verb in KME's dictionary:

search v : Search a string for a string and replace occurances with another string, returning the resulting string.
   search text : the input string.
      for text : the search string string.
      replace text : the replacement string.
      [regex boolean] : using regular expressions (default false).
      [case sensitive boolean] : case sensitive (default false).
      [process tokens boolean] : process tokens (default false).
      [first boolean] : just first match (default false).
      [last boolean] : just last match (default false).
      → text : the resulting string.

...so it quite literally reads as:

Search the text in theTriggers for "(?m)^Trigger icon", replacing every occurence* with "", treating our search term as a regular expression and making the search case sensitive

*Because we didn't specify first or last

And because we're telling KME and using the KM regex engine we've access to all the things we know and love in the regular expression actions, like the (?m) "multiline" option.

The result of the expression -- the transformed text -- is what gets put into theTriggers.

It's the AppleScripted equivalent of

1 Like

THANKS! I had been intending to ask you how that might be done in KBM instead of AppleScript talking to KBM. I appreciate your anticipating me!

Given that you / I / we can edit the captured list with a KBM action, am I right in assuming that you did it in AppleScript because you were already coding in AppleScript to be able to add a new action, the Comment, to the KBM macro?

I'm thinking I would like to put this all into a KBM macro that would be able to modify the currently selected/edited KBM macro (I would call it by menu, it's not a frequent enough action to get a hotkey). Instead of using AppleScript to tell KBM to define a string of the new XML, would there be a downside to doing it in KBM instead? I.e, that macro would:

  • edit the selected list of triggers in KBM (with the above action)
  • build the XML structure of the new Comment action in KBM as a text variable
  • then run AppleScript only to insert the built XML into the KBM macro.

And as a brainstorm, to close the loop, so to speak, I'm thinking that it might be convenient to be able to take a manually modified update of the Comment text and convert it into the XML Triggers array:

	<key>Triggers</key>
	<array>
		<dict>
			<key>FireType</key>
			<string>Pressed</string>
			<key>KeyCode</key>
			<integer>0</integer>
			<key>MacroTriggerType</key>
			<string>HotKey</string>
			<key>Modifiers</key>
			<integer>0</integer>
		</dict>
		. . .
	</array>

If I understand the process, I think that I would need to do something like:

set allTheTriggers to (get triggers of selectedMacro)
set xml of allTheTriggers to theNewTriggersListInXML

Do I seem to be on the right track? I suppose the details will depend on exactly what I get when I run

print xml of triggers of selectedMacro 

or something like that.

What I'm wondering is if I can replace all the triggers at once using AppleScript this way, or if I need to empty the list and then add triggers one at a time.

I'm probably getting way ahead of myself here, but the prospect of being able to edit a Comment text and update the same macro's trigger list from that is attractive. Probably more work than it's worth, but still attractive for fun of it.

When I define the XML of the Comment to be <key>Text</key>, then I get text in a font that is not the default font for Comments. If I apply a Style to the Clipboard using the Apply Style to System Clipboard action, it makes no difference.

As you hinted at, it would indeed be nice to be able to generate that <data> string from the Styled text in the clipboard.

The <data> string looks like it may be "UUEncoded" binary. If the Styled clipboard is binary, maybe UUEncode could be used to create the <data> string.

@peternlewis -- You know what's under the hood in the StyledText of a Comment. Could the Apply Styles to System Clipboard action be used to generate a source that could then be edcoded as the StyledText entry's <data> element?

No idea.

The data is created from a NSAttributedString with the command:

[s RTFDFromRange:NSMakeRange(0,s.length) documentAttributes:@{}]

Any text encoding is done by the plist encoding.

I've made an upgrade to @Nige_S's macro/AppleScript above.

I figured out how to get all the triggers without having to manually copy the list from KBM's Non-Editing Mode.

Here's my test macro with three triggers and the Comment action automatically inserted into itself:

image

It's based on an AppleScript snippet that I found a Forum entry from Peter Lewis (@peternlewis) that gets a trigger of a macro (Change the Hot Key for Multiple Macros at Once - #7 by peternlewis). I used that as the basis for some AppleScript that loops through all of the triggers individually.

image

-- identify the currently selected macro
tell application "Keyboard Maestro"
	set selectedMacro to macro id (item 1 of (get selectedMacros))
	
	-- get list of triggers
	set theTriggerList to triggers of selectedMacro
	
	-- put description and xml of each into variable
	set theDescriptionList to ""
	
	repeat with theTrigger in theTriggerList
		set theDescriptionList to ¬
			(theDescriptionList & ¬
				(get description of theTrigger) & linefeed)
	end repeat
	
	-- add the "Comment" action
	set theCommentXML to "<dict>
		<key>MacroActionType</key>
		<string>Comment</string>
		<key>Text</key>
		<string>" & theDescriptionList & "</string>
		<key>Title</key>
		<string>Tiggers for This Macro</string>
	</dict>"
	set theAction to make new action at beginning of macro id (item 1 of (get selectedMacros))
	set xml of theAction to theCommentXML
	
end tell

At this point, the extension of this idea that I mentioned above, being able to edit the Comment list and use that to regenerate the macro's triggers, is one step closer — and it's clear I have about 20 steps to go. (I'm not holding my breath.)

There are two "bugs" in the formatting of the above generated Comment text:

  • I can put a blank line above, after, or both, but I haven't been able to figure out how to only have the list text, with no spurious blank line.
  • The list starts out in Helvetica font and whenever a modifier key appears, from there on the text is in Lucida Grande.

I've banged on some ideas to fix both of those, but nothing easy has come to mind. Very much not a big deal.

With your code as written, the easiest way is to trim off the final linefeed after you've built the list with your loop:

set theDescriptionList to (characters 1 thru -2 of theDescriptionList) as text

The only way I've found to control style is to bounce out to HTML, use textutil to convert that to RTF then base64 the result before posting the result back to a KM variable. That's a bit of a faff, but shout if you want a demo.

I'm saying that, rather than just posting, because:

...I hadn't realised this was your ultimate goal. I'm not saying that this is impossible, but get a bunch of triggers as XML and it looks rather difficult. Just looking at hot keys, you're going to have to map letters to key codes, modifiers to their combined integer value, key actions to fire types and tap counts...

Auto-generating a comment with a list of triggers that you can then edit with "and this variation forces branch A" seems reasonable. Re-arranging trigger order could be doable. But creating a trigger list from scratch from a comment's text seems more work than simply editing the triggers in the GUI!