Where can I use Pause Until instead of Pause?

A question about using Pause Until instead a fixed Pause (e.g., 0.5 s):

In general, if possible, it seems you always want to use Pause Until in place of a fixed Pause. That's because the amount of time the system needs to complete an action can vary. Thus, if you use a fixed Pause, you need to set it so that it's long enough to nearly always work, which means you're going to have to build in some cushion. By contrast, if you can use Pause Until, it will only pause as long as needed, resulting in a faster Macro.

Some obvious places where Pause Until works are after quitting or opening an application. But I'm wondering where else it can be used.

Specifically, the screenshot at the bottom shows a Macro for toggling Voice Control (in Accessibility) on and off. In any of the five places I've used a fixed Pause (outlined in blue), could I instead use Pause Until? And if so, what would be the condition? I tried, for instance, "Pause Until The Last Action is OK" after "Open Accessibility Preference Pane", thinking that means "pause until the system has opened the Accessibility Preference Pane", but KBM doesn't seem to interpret it that way (or perhaps it can't detect this system state—unlike the case with, say, whether an app is opened or closed).

Relatedly, I'm wondering if the condition in the first screenshot immediately below is qualitatively different from that in the second, because the condition in the first screenshot requires that the system has completed an action (moved Finder to the front), while that in the second screenshot is true merely if an input to the system has been completed (i.e., it doesn't tell you whether or not the system has responded to that input). And to replace a fixed Pause with Pause Until, I think Pause Until needs to know not merely that an input (e.g., a mouse click) has completed OK, but also that the system has finished responding to it. I.e., it needs to know the system state.

In summary, it seems the condition in the first screenshot is about whether a specified final system state has been achieved, while the second's is merely about whether a signal has been sucessfully sent to the system—and that the former can be substituted for Pause, while the latter cannot.


Yes, Pause Until is only going to be of use if you can find a condition that will be true once the System has completed a step rather than just starting a step. If you can't find such a condition then a fixed timed pause is the way to go.

The above conditional pause is not completely reliable as an App can be running (i.e. starting up) but still be loading menu items etc. I have found that testing for menu conditions is a more reliable way to test if an App is running and ready to do stuff.

The logic being that all Mac Apps have a menu item "About" followed by the App's name.

2 Likes

Thanks for the tip. Is this also an issue with the 'app is not running' condition (i.e., can "not running" = 'in the process of qutting', rather than actually being quit)?

Also, when placed after Open Acessibility Preference Pane, what does the following actually mean, since it doesn't mean that the Pane is open? Does it just mean the signal to open the Pane has been succesfully sent?

image

And are there equivalent tricks (to your 'Pause until a menu item appears') for any of my other actions?

For instance, when the Acessibility Preference Pane is open, Accessibility is checked in the System Preferences Menu:


So could I use the following as a condition to ensure it is opened?:

image

And what about my tab and down-arrows? Those move me downwards through the sidebar on the Acessibility Preference Pane. Is there a way I can reliably determine when each of those actions has completed? It seems I'd need a condition that a certain item in the sidebar is highlighted. Other than Found Image, is there any way to do this?

For the mouse click, which causes a checked box to be unchecked, and visa-versa, I don't think there's any way to check completion by checking for a state, since there is not a single state when the action has completed.

No, because the pause will stay until the App is not running. In other words, no further Keyboard Maestro Actions will happen until the App is not running.

This refers to the previous Keyboard Maestro Action. If it fails then the result is not "OK". If the Action succeeds, the result is "OK". It is not waiting for any macOS System result.

Yes.

No. You are better off adding a very short timed pause if you think a pause is needed.

1 Like

Thanks again!

Zabobon:
No. You are better off adding a very short timed pause if you think a pause is needed.

I did some testing. After the tab is complete, this is highlighted:
image

And after the Voice Control subpane is reached, this is highlighted:
image

Previously, I was using pauses of 0.5 s and 2.0 s, respectively, to ensure those points had been reached. But I substituted a Found Image condition for the first, and Found Image plus a shorter pause (0.5 s) for the second, and found that, when I did this, the Macro worked both faster and more reliably. Normally I am leery of Found Image, because I don't consider it highly robust. But in this case, since the Macro was already failing occasionally even with those pauses, and I did not want to make them longer, I figured Found Image was worth a shot—and it was!:

@peternlewis Most of the longer macros I create require Pause statements, and it requires some testing to determine where they are needed and how long they need to be. Further, because of inter-run variability in the Pause times needed (they could follow a Gaussian distribution or, worse, something with fat tails), one has to build in significant cushion, balancing run time against failure rate. Thus the Macro will usually run slower than required, but also sometimes fail.

Thus would it be worth posting the following as a Feature Request, or is this something it is simply not possible to implement?:

Enable KBM to determine when the system has fully completed the action initiated by the previous step. It would then wait until that happened before moving onto the next step.

If KBM had that capability, it would eliminate the need to add Pause statements to account for system delays, thus significantly streamlining the creation of any Macros that would otherwise need them for that purpose. And unlike the case with fixed Pause statements, the Macro would operate optimally rapidly, and would never fail on occasions when one of the fixed Pauses was too short.

Unfortunately, no that is not possible.

The system is always doing lots of things. It might look idle to you, but hundreds of things are happening under the hood. Indexing and caching and idle processing and clocks and background operations and animations and updates and lots more. There is no way for Keyboard Maestro to know which ones of those many things, most of which are unknowable anyway, are what you are waiting on.

As much as possible, Keyboard Maestro does this on a per-action basis. Where it knows the consequences and can tell the results of an action, it will wait for that to happen.

For example, while the Quit action does not wait for the quit to complete (since it is not generally required), the Activate Application waits for the application to come to the front, so there is no need to pause until that happens. But even so, just because an application has come to the front does not necessarily mean it is ready to do anything - it might not have opened its initial windows for example. And there is no way for Keyboard Maestro to know when or if that might happen.

After a while you should be able to recognise when the pauses are required.

Generally you need pauses (or better yet Pause Until) when you change input focus or when there is an animation or other specific long process.

One important thing to understand is that the system operates with most user input going through a queue, most especially the keyboard events. The target application will pluck these events off the queue as it can. So for a well behaved Mac native application, a sequence of keystrokes should always work in sequence, as long as the input focus is not changing.

Another important thing to note is the consequences of that is that you cannot tell when the results of simulating a keystroke will happen. So if you are doing something that relies on the results, then you definitely need to pause until the keystrokes have all been processed (ideally with a Pause Until, alternatively with a sufficiently long Pause).

Where things really go down hill are when dealing with web pages or other non-native applications, where they may process events very poorly.

Going back to your macro and knowing this:

  • The first Pause Until is required if you want to ensure that settings has quit first.
  • The second Pause Until is pointless.
  • The next Pause could be done with a Pause Until based on the front window title. And in fact I would replace the entire sequence with this:

image

That should work in any case I can think of.

In theory, you should not need any pauses for the Tab and Down Arrows. You might need it after the Tab, but you shouldn't. I can't test this since I presume this is pre-Ventura since it doesn't make any sense on Ventura’s System Settings.

You will have to pause before the click, and I don't know that there is a good way to avoid. You might be able to use the Press a Button action, and that can wait for the button to be enabled, and it will be better at pressing buttons in the next version so even if it doesn't work now it might be an option in the future.

You probably need a Pause after the click as well, though it's hard to say without knowing what the click does.

So basically, yes, you need pauses sometimes, and there isn't much that can be done about it, but look on the bright side, it's probably still way quicker than doing it yourself manually.

4 Likes

Thanks!

Yeah, that's what I figured, which is why I asked before posting as a Feature Request.

I've not written Apple Scripts (nor do I want to), but just out of curiosity, is this something that Apple Script can do: Determine when the system is ready for the next step, thus obviating the need to insert pauses?

Unfortunately, that doesn't work on my system, which I should mention is the following (SSD is a 2 TB WD SN850, and Disk Encryption is on; that does slow some things down, though I don't know if it would affect this):

image

It stops after opening the General Preference Pane. To diagnose the issue, I added a Pause after that step. With the Pause, it works, and one can see exactly what the problem is: After it loads the General Pane, the system provides a message at the top of the General Pane saying this. It's very brief--just a fraction of a second, but long enough that a Pause is needed:

And that happens even with very little else running. [I've run extensive benchmarks on my system, including Geekbench 5, Geekbench 6, CrossMark, PassMark Performance Test, Amorphous Memory Mark, Amorphous Disk Mark, and Black Magic Disk Speed, and it operates exactly as a 2019 i9 iMac should; it equals or exceeds published values.]

Here it is with the Pause:

The Pause after the Tab is needed on mine. But I was able to remove the Pauses after the Down-Arrows. Is the reason the latter aren't needed that they all go into a buffer, and thus will all be executed eventually regardless of system delays?

Of course ;).

No. Otherwise a Pause Until action and an Script condition would be all that was needed (and Keyboard Maestro would do it internally!).

Correct. Which in theory should mean no Pause after the Tab is needed, except there is probably some animation or such that ends up stealing the events and failing at them.

1 Like

Regarding other 'tricks' to use with Pause Until...
I typically use Pause Until...because I need the script to pause while the User does something, like navigate to a directory. After that, I want the script to continue on a keypress. So, instead of messing about with timers, I often use Pause Until...Key Condition ("The key 'Esc' is down") is met.

1 Like

I usually follow this immediately with ("The key 'Esc' is up"). On an M1 mac it runs fast enough that it recognises the down and then the up, and captures both events. This effectively does the same thing, but is slightly safer as it prevents any actions within apps that trigger on the escape key being released.

Thanks for the tip! In fact, after I wrote my note, I wanted to come back and suggest using a different key in the same manner. 'Esc' can sometimes interfere with KM in unpredictable ways, especially within dialog boxes.

[Sent from my Pixel 5a]