While Triggering Macro is executing

Huh, thanks

Thanks, makes sense.

Using an actual Execute a Subroutine action makes this more clear:

For some reason I was confused into thinking that the Engroup > Macro would leave me a Execute a Subroutine action, while it, logically, leaves an Execute a Macro action. I think I was confused by reading a forum post from before KM10 or something. Execute a Macro was/is also often referenced as performing a subroutine, all though Subroutines now after KM10 also have a more explicit meaning.

This is what I've now experienced while testing here also.

Am I then right in thinking this Subroutine method will not work the way we where hoping here (to emulate 'While Triggering Macro is executing'-behaviour)? Or is there any way to make a parameter like this to update when the calling macro is done executing? (Without it being explicitly done so by setting the variable again as an action at the very end of the calling macro)

EDIT: And another reason I’ve come to realise for why Subroutines will probably not work in my originally described use case: Subroutines cannot be run asynchronously.

That's an important point.

Specifically, I couldn't understand your core question, "is there any way to set up a condition that I would not have to reset for each macro where I'd like to display my looping progress bar?"

Based on your realization that subroutines cannot run asynchronously, I think you are beginning to understand why a single progress bar spanning multiple calls to the same subroutine isn't a meaningful request. Macros can be called asynchronously, but you aren't asking about that.

1 Like

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