While Triggering Macro is executing

I do agree that this core question does not make sense now, as my looping progress bar example now does not make sense after having learned (through your OCR-timing macro) a much simpler way of obtaining this. And the explicit Subroutine-route now seems like a blind alley.

However I am not sure I agree that wanting to implement into macros a subtask (not necessarily an explicit Subroutine) of asynchronously doing something while the rest of the macro does it's thing, is inherently meaningless (but do elaborate if I am missing your point here, I really do want to wrap my head around this). I was able to achieve this ‘Asynchronously While'-behaviour by setting the while conditions in the asynchronously executed macro as displayed in the green rectangle in my first image. But as I at the time of creating this thread imagined wanted to implemetn this looping progress bar Submacro into numerous other macros, I was looking for a way to implementing it without effectively having to make a new copy of the Submacro, and reseting the while condition for the calling/triggering macro, every time I implemented it. This is why I was looking for the behaviour as if that while condition (pointed out by the green arrow) could be set as "triggering macro" or the like.

As @tiffle pointed out, there are workarounds, so I guess we are pretty much at ways end, but I've not yet been able to fully shake the feeling that this 'While Triggering/Calling Macro is executing' could be useful also in other situations (all though I am not here in this moment able to come up with a better example than the original looping progress bare one).

I realised now that I actually had stumbled upon another example of a macro that would take advantage of the 'While Triggering/Calling Macro is executing'-condition/behaviour.

Example form link

Coincidentally also a bit of a weird example, but if I wanted a Submacro that presses the OK button of the Prompt for snippet-window in several different macros; it seems to me that I would then need to hold a separate copy of the Submacro for each of it's implementations.

@tiffle's workaround would also not work here as the Prompt for snippet action cancels the whole macro if cancel is pressed.

I had to ponder your idea for a few minutes.

As I said earlier, when you use the token %ExecutingMacro% from a macro or one of its subroutines, the data it returns is always the same.

But in this example of yours, you are spawning the sub macro asynchronously. I had to ponder that for a few minutes, and realized that I had to test that to be sure what it does. And sure enough, that token no longer returns the name of the parent macro, but now it returns the name of the asynchronous macro. So my generalization was wrong, because that token returns a different value if the macro is run asynchronously. Now the question is, does this help you? I don't think so. What you need is a link to the parent calling macro.

I didn't mention this to you earlier because I didn't think it would solve your problem, but there is another token called %MacroNameForUUID%. Instead of returning the macro's name, it returns a unique string that is unique for each instance of the macro that runs. If you pass this string from the calling macro to the asynchronous sub macro, that may solve your problem. In that case, the asynchronous sub macro can potentially learn when the calling macro has completed.

However I don't see a conditional test within KM that will let you test for the existence of an instance/process using this UUID. However these UUID's are probably generated from macOS and therefore I'm sure there must be a test using AppleScript or Shell commands that will check if this process still exists. I will ponder this further, but I would prefer if someone more familiar with this UUID step forth and explain how a macro can test if a process with a given UUID can be checked for completion.

1 Like

Why do you want to press the ok button programmatically? I feel with more context we might be able to simplify this for you.

1 Like

Thank you so much for pondering on this with me!

Yes, and more particularly, a link that changes the moment the calling macro is no longer executing.

Or if I understand it correct that specific token returns the Macro name from a UUID, but it definitely feels like UUID might be part of the/a solution here! Only problem is how to check from the Submacro if the calling macro is still executing. Through my testing with the UUID-tokens, I have so far not been able to set it up in a way for this to be possible.

If there only where a way to return a list of all currently executing instances, (or I guess a list of names of currently executing macros would also be sufficient), and then recheck that list for each run of the loop to see if the parent macro instance/name is still on the list. (Mostly just repeating my understanding of what you've already written here.) But I realise now that I actually do not know how KM is handling different macros executing at he same time. Are there only one instance ran at any one moment (I guess then cycling through instances if macros are ran on top of each other), or are they ran parallelly in any way? (As probably becomes very evident through my wording here, I have no programming background, nor any programming experience outside KM.)

But AppleScript or Shell, I think you are right in that a solution can be found in this direction. I sadly have next to zero understanding of AppleScript, and absolute zero understanding of Shell. But yes, maybe someone with deep understanding of these languages can come to the aid here!

I don't, but @ronald from the thread I linked to wanted that. He ended up finding a different solution, but through my proposition for how to solve it emerged another useful example for this thread.

As it stands I actually do not have a practical/productive use case for the behaviour I am seeking, and this threads goal is now solely to seek deeper understanding of KM (and having fun while doing so (which makes ut a dual goal, as pointed out by @airy, haha!)).

I am struggling a bit to concisely and formally formulate just what the result I am seeking is; but in my eyes, and through my programatically illiterate wording, it again boils down to the behaviour one would get if that condition in the While-action (pointed out by the green arrow in my first post) could be set as "triggering macro" / “calling macro” / “parent macro” or the like.

Your terminology is wrong there. Every time a macro is triggered, an "instance" is created. If the same macro is initiated five times, then as long as they don't exit before the next copy runs, you've got five instances running, which happen to be the same macro.

That's why I told you about %MacroNameForUUID%.

That's why I asked for others to assist with this question, because I don't know either. There doesn't seem to be a mechanism in KM itself.

No, that would not be sufficient, because you would not be able to tell from that list which one was the caller.

That's the very definition of an instance. An instance is a new process which by definition is running in parallel. There's no such thing as two instances that are not in parallel of each other. Although now that I've said that, the whole point of semaphores is to synchronize two instances.

That's why I asked for help here. Or, maybe just give me more time to research.

1 Like

Thank you for the clarification about the terminology here. Still a bit confusing to me though. The processes that goes on backstage here are especially foreign to me, but I'll slowly learn more and more. Also again many thanks for continuing to ponder on this crooked subject with me!

About the %MacroNameForUUID%, I still do not understand why this token in particular would be useful. From the testing I’ve done so far it returns the Macro Name from a UUID regardless if the macro is currently executing or not. I’ve only gotten it to return the “Not found” if I delete the macro the UUID was from. But am I missing your point in how this token could be useful?

The way I was thinking was to set a variable to %ExecutingMacro% in the calling macro before asynchronously executing the Submacro, that could then later, for each run of the loop, be searched for to check if it is still present in a list of currently executing macros. But using the UUID would anyways be more precise.

Anyone reading this post should stop now, because inside this post I explain why I'm wrong. I will attempt to find the correct answer and post it later. I'm very sorry, and a little embarrassed about being wrong.

No! Not at all! It doesn't return anyone else's UUID, it returns your own UUID. That's why I said you had to pass it down to your asynchronous process from the parent one. It's the name of the parent process, but the only way the child process can get it is if you pass it down when you spawn the child process.

EDIT: I probably shouldn't write answers when I wake up first thing in the morning. Let me review that statement before you believe it. I'll be back soon. I'm preparing an improved answer. Please forgive me for being wrong. CORRECTION: I had made two mistakes, the first mistake was giving you the wrong token name. The token name that I had intended to give you was %ExecutingMacroUUID% but even that isn't quite right because the name is misleading, it doesn't return the UUID for the macro running, it returns the UUID for the instance running, which still isn't what we want. I need to dig deeper to find a token that returns the UUID of the current macro, not just the UUID for the instance. There are more macros, but I have to examine them closely.

No! Not at all! The child process already has access to %ExecutingMacro% because that token doesn't change when you spawn the child process. There's no point in saving something that the child process already knows.

Also, I should add a minor complexity at this point... If Macro A calls Macro B which calls Macro C, then both macro B and C return the value "A" when evaluating the token %ExecutingMacro%. That's because the token only returns the name of the macro that was "triggered" by the Engine. It's not really returning the name of the parent unless the parent was also the macro that the Engine triggered. In your case, I was assuming that you had only two, not three macros, in the stack. And I was probably correct about that assumption.

Okay, this is crazy, but I think I've found the solution!
In the wiki I found the token %ExecutingInstances%, and it returns a commaseparated list of all current instances!

test_While calling macro is executing Macros.kmmacros (4.6 KB)

Macro Images

I am sorry for the mistakes above. Ignore my discussion of tokens above.

But I do have a lead I'm working on. Each asynchronous process created by the KM Engine should be visible as a line of output to the command line command "ps -ax" but so far I haven't been able to spot it. This is perplexing me.

There's another lead that you may already know about. You can set a global variable at the end of the calling macro to tell the spawned macro when it is finished. That will work 100% guaranteed. But I like to investigate alternate solutions, just as I think you like to do.

1 Like

I took a long look at the token you are using, but I couldn't find a way to make it work. I will examine your solution after lunch.

1 Like

Very curious to hear your thoughts on this solution! I might be missing something, but as of now it seems to be able to do what I wanted

And do not at all worry about giving the wrong token name, I had a feeling that this was part of my confusion, and it anyways set me out on an exploration of a token I had yet to explore!

Before you posted your solution, I was looking very carefully at those tokens. The documentation said the entires are "Opaque IDs" and I spent a half hour trying to find a definition for them. The KM docs don't seem to define that term. I was googling it and couldn't find a clear and simple explanation. If your code works, then I can't deny that it does what you want.

But bear in mind that this isn't really any different from setting a global variable manually, as I suggested earlier. You are still using a global variable. What's more, you are using two global variables. One thing you could do to improve this macro is replace your second global variable by a local variable. That could prevent a bug whereby two separate macros are referring to this global variable. Moreover, you may also want your first global variable to be modified to a local variable and pass its value to the second macro. Doing this will make your code more robust from failure, and it will also ensure that there are no global variables cluttering your environment. If you don't want to change that, then you may at least want to delete the global variables after you do this. Generally speaking, a saved value that's no longer needed should be cleared or deleted.

I also couldn't understand what "Opaque IDs" meant, but that it where suppose to return a list of instances made me intrigued enough to give it a go.

The global variables was mostly a product of me usually working with global variables while developing a macro; swapping them out with local ones while finalising it after getting it all working properly. I was so exited earlier when a solution, after days of pondering, finally seemed to emerge, that I posted it right away, haha. And good idea about passing the %ExecutingInstance% from the Calling macro as a parameter, first didn't think of that!

It does seem to work for me, and have performed well through my tests so far, but I'd be very interested in hearing more of your thought about the shortcomings of this macro in its present state. I am all interested in improving it further!

Here is my cleaned up version of the macro as it stands now. And as the thread progressed complexity beat simplicity, so hope you are okay, @tiffle, with me moving the Solution-tick to this post, until it is dethroned again by an even more complex solution, haha!

Now set up demonstrating an oscillating progress bar, with a 5 second pause in the Calling macro simulating a time consuming task. The progress bar can simply be implemented into any macro by copying the magenta coloured action to the head of any macro to perform tasks while the calling macro is executing. The red actions in the Submacro can also be swapped out with all kinds of useful tasks one might want to perform asynchronously while (or after) a calling macro is executing.

As of now I do not have many ideas on other use cases for this approach, all though I am sure there must be many, haha! I’d therefore also be thrilled to hear any ideas on how this approach could be implemented, to perform other (maybe even more useful) tasks than the oscillating progress bar it now performes!

While Calling Macro is Executing – CALLING v1.2.0.kmmacros (2.0 KB)
While Calling Macro is Executing – SUBMACRO v1.2.0.kmmacros (5.4 KB)

Macro Images

Edit: Realised that a Semaphore Lock would be good here, if the Submacro where to be called by different macros at once. Therefore uploaded a new version of the macro implementing this. Also uploaded the two macros separately this time.
Edit2: Found a way to improve the macro, so moved the Solution-tick to post #31

Where actually here now able to create a simplified version of this macro not using any variables whatsoever!

While Calling Macro is Executing – CALLING v1.3.0.kmmacros (2.0 KB)
While Calling Macro is Executing – SUBMACRO v1.3.0.kmmacros (4.4 KB)

Macro Notes

(Keyboard Maestro v11.0.1)

In the uploaded state the macro is set up demonstrating an oscillating progress bar, with a 5 second pause in the Calling macro simulating a time consuming task. The progress bar can simply be implemented into any macro by copying the magenta coloured action to the head of any macro to perform tasks while the calling macro is executing. The red actions in the Submacro can also be swapped out to do other task one might want might want to perform asynchronously while (or after) a calling macro is executing.

Moving the Solution-tick to this post now — Once again simplicity beats complexity!

In tips and tricks territory here now, but set up in a similar way this approach can also be used to set the conditions for a Pause Until-action:

Pause Until Calling Macro is Done Executing – CALLING v1.0.0.kmmacros (2.0 KB)
Pause Until Calling Macro is Done Executing – SUBMACRO v1.0.1.kmmacros (4.3 KB)

Macro Notes

(Keyboard Maestro v11.0.1)

For demonstrating purpose the macro is in it's uploaded state set up with an oscillating progress bar, with a 5 second pause in the Calling macro simulating a time consuming task.

Macro Images

1 Like

To clarify, if I have a Macro that repeats 100 times (for simplicity), Which Macro do I add those actions to, and where within that Macro so that my progress is correctly calculated and displayed? I pasted in place of the 5-second pause and got a number displaying 7,100, which stayed halfway complete (per the animated visual bar) until the pasted Actions/Macro was complete. I appreciate your diligence in delivering the final anticipated result, but I'm waiting for your response instead of trying to deconstruct on a time crunch for this task completion :smiley: I certainly look forward to using this in every macro #ADHD :rofl:

Hi!

You could in theory just download both the macros (CALLING and SUBMACRO) from post #31, and paste the magenta colored action from the CALLING macro as the first action of any macro you'd want to display an oscillating progress bar, indicating that it is currently running. But doing this into every macro will in practice probably cause having many overlapping instances where macros are calling this SUBMACRO simultaneously.

The way it is set up now the Semaphore Lock at the head of the SUBMACRO would prevent this by canceling any instance of the SUBMACRO being run on top itself, whilst also returning an error message. This error message can be turned off, by right clicking the semaphore lock and unselecting "Notify on Timeout". Then the first macro CALLING for an oscillating macro would get it, and any overlapping macros triggered after the first would not — first come first served.

I did however try here now disabling the Semaphore Lock completely, while having numerous macros run on top of each other, each CALLING for this progress bar. This also kind of worked, only sometimes displaying slightly glitching/blinking progress bar text when run on top itself. So after this test I am now thinking that the Semaphore Lock is not really necessary at all in this case.

If your macro is simply repeating, literary utilising the Repeat action, you can display a correctly calculated progress bar simply by right clicking the Repeat action selecting "Display Progress".

Display Progress

Other times it can also work to simply wrap all your actions in a Group action, right clicking and selecting "Display Progress" in this same way.

In other cases where you'd want to display a correctly calculated progress value, not simply displaying an oscillating bar, it can become allot more complex. In this case it might be better if you ask your question in a new thread, and I'd happily try to help you there. Because I do not as of now understand the behaviour you are explaining above, and imagine it quickly progressing into something outside this threads scope.

As this thread progressed it wound up being less about the progress bar and more and more about setting up the conditionals to give the behaviour of 'While Triggering Macro is executing'. This especially after I found a much simpler way of displaying an oscillating progress bar than the crazy mess I started out this thread with. For demonstrating purpose the oscillating progress bar just got along for the full ride of the thread, but the 'While Triggering Macro is executing'-behaviour have also proven useful for other situations. The solution from post #31 is however a perfect viable way of displaying a progress bar, and I use ut in a number of my macros.