Trigger Macro Once When Switching to Application?

I'm trying to app A whenever I switch to app B.

Specifically, I'm trying to open a blank script app whenever I switch to Logic Pro, in order to trigger a Stream Deck profile. The trouble is, the blank app opens and closes and then reactivates Logic, which repeats the sequence and you end up with an infinite loop.

I came up with something that works when Logic has an open session, but when there's no open window it switches back to the previous app and I'm unable to switch to Logic at all, so something is wrong with how I'm approaching this. Any help appreciated.

Hey Neil,

Is the plugin profile an actual app?

If so you might be able to use an AppleScript to get around the problem.

tell application "YourAppName"
   run
end tell

-Chris

Unfortunately not. The only way to switch Stream Deck profiles is to associate them with an app. Therefore you make a blank app using a script editor, then momentarily run it in order to trigger the profile switch. Explained at length here:

edit: I've found an inelegant solution to that problem and encountered another. I added an action to activate Logic again before the loop-breaking pause, so it now works when Logic doesn't have an open window.

New problem: KM isn't reliably re-enabling the macro. There must be a better way to do this...

Hi Neil!

I also use keyboard maestro and stream deck to make music with Logic. When I get the time to make a video there are a lot features that are possible using keyboard maestro that I want to share. Specifically a function that allows me to assign any instrument in my library (logic or 3rd party) to call up with a single button press. It's a cool function but that's for a different day!

I'm so glad people are finding this workaround useful. It still has it's quirks because it is only a workaround but at least it gets the job done. I was able to recreate the loop you described and I think I found a workaround for it, although, you will have to test it in your own workflow.

By using "If Then Else" I was able to set a variable to make the function more like an on/off switch instead of a loop. Here you will be able to see the configuration:

It might be a bit confusing why this works as it doesn't seem like it would break a loop, however, if you run it you will notice that the variable is always deleted at the end. This means that it runs and executes the "otherwise" action first, then repeats itself (trying to go back to the loop problem) however because the variable now exists it runs the first action in the "If Then" and deletes the variable accomplishing two things at once... keeping your variables clean and resetting the action for next time. The reason it doesn't loop is because it needs another input triggered from Logic once it has executed the "delete variable" action.

Sorry this is so long winded... just wanted to explain the process for further application if it helps other workflows! Hope it works for you!

3 Likes

Hey Neil,

An AppleScript app is an actual app as far as the macOS is concerned, so the technique I illustrated above will work.

AppleScript app named “Nuts!” code:

on run
   quit
end run

Run code:

tell application "Nuts!"
   run
end tell

This will run the app in the background without switching to it.

-Chris

Hi guys. Thanks for the help. Yesterday was dominated by football :cry: and I'm away from home till Wednesday now, so apologies for not being able to test these out just yet. Looking forward to it!

1 Like

That's interesting! I'm gonna try that out myself!

1 Like

I tried it on my end and it didn't work but I understand why after looking inside the Stream Deck editor.

Screen Shot 2021-07-13 at 7.34.02 PM

I think this explains it. Running it in the background doesn't switch the stream deck profile as it requires the app to be in the foreground for at least a split second.

Too bad.

I suppose you could have the applet:

  1. Disable the switch macro on launch.
  2. Activate itself.
  3. Activate Logic Pro.
  4. Re-activate the switch macro.
  5. Quit itself in the background.

I think that might work, and it should still be quite fast.

-Chris

I did find something that breaks the loop and posted it above that should solve Neil's issue. I liked what you had cause it was so streamlined and clean but unfortunately Stream Deck had other plans in mind. Hopefully they will update soon and the ability to switch profiles can be added as a dedicated feature within KM but who knows!

1 Like

@ccstone, thanks for the suggestion, which was along the same lines as what I was trying. The trouble was the enable/disable states were sometimes not switching back properly.

@ncbasic, your suggestion works, but only when Logic has an open window, so I added an "Activate Logic Pro" action and all seems good!!! Thanks!

TL;DR: can you stop a macro from executing if it (or another specified macro) ran within the last few seconds?

Ok I have a new issue...

Just to complicate things, I also have SD profiles that trigger based on the currently open plugin window. I have a dedicated SD button that OCR scans the open window, then opens the corresponding blank app that triggers the profile. Trouble is, when the plugin profile has been set and focus returns to Logic, it triggers our macro to switch the profile to Logic, so in effect it breaks my plugin profile triggers.

Perhaps there's a way to disable the Logic profile trigger if the plugin profile trigger has just run, within say the last 3 seconds? This, incidentally could be another way to break the logic profile loop, assuming it's possible at all...?

Maybe this is relevant here? Condition for whether a macro is being run from within another macro - #3 by JMichaelTX

...or @ccstone's contribution here?: MACRO: Get Recently Run Macros with Last Executed Time - #27 by ccstone

Yeah I was playing with it some more as I noticed it would leave Finder in the front so I came up with a similar solution!

Well is it's possible. There are probably better ways than I am about say but I still consider myself an amateur in this arena... music production is my expertise. My solution would be pretty much the same concept with the variables in that they will be used to tell the macro where/how to run.

If you create a dedicated macro to set a variable, pause for 3 second, and the change or delete the variable you can reference that in your workflow where need without have it pause the macro you're using. Of course you could use the same concept by disabling the macro... kind of depends on your needs.

You could use a global variable like LP_DoNotRun`

Your main macro could start with an IF LP_DoNotRun = TRUE then Don't continue

Set the global variable to TRUE using a asynchronous sub-macro with a timer, and set it to FALSE when the timer elapses.

-Chris

Blimey. I'll have to spend some time thinking about this as some of the concepts you're using are new to me.

In the meantime, this janky solution is working (I think!). I'll really try and get my head around what you're saying though, as I can imagine a few other scenarios where macros could clash and a dedicated macro to avert that would be very nice!

1 Like

Ok so I think I understand. Maybe...

Here's the main macro:

image

...and here's its sub-macro:

image

I'm not sure I understand the reason we're using a sub-macro rather than just including it as part of the main macro...?

Having it as a sub-macro means it can run asynchronously to the main Macro. (And you have to set the asynchronous option using the gear wheel in the Execute Macro Action - which I can see from your screenshot you haven’t done yet).

If it is a sub-macro and runs asynchronously to the main Macro, the main Macro will continue to run while the sub-macro also runs.

If it it were a part of the main macro (i.e. not a sub-macro) then the main Macro would stop and wait until this part had run.

Hope that helps! I’m sure @ccstone can explain it better!

I see. So if I had further actions within that macro, they would have to wait for that 1.5s pause unless the loop-breaker sub-macro was asynchronous. That's clever. Thanks!

Maybe I'm mis-understanding what's going on here, but wouldn't you be better off (in this case) simply associating your StreamDeck profile 1:1 with Logic?

skipping the 'launch an app to trigger the profile' trick here altogether?