Trigger Macro by Mouse Pointer/Click Location?

Is it possible to trigger a Macro by simply moving the mouse cursor over a designated area of the screen? Or maybe by clicking a designated area of the screen? Specifically an area where there are no actual clickable items.

1 Like

The only available trigger involving the mouse/mouse button is the Gesture trigger. Refer to the KM wiki trigger:Gesture [Keyboard Maestro Wiki]

Gesture triggers are a bit underdeveloped in KM. Nevertheless, I find them very useful and reliable, especially in combination with a modifier or a mouse button, because the distance the mouse has to travel can be very short.

But what should also work is an action that is only executed when the mouse is at a certain place (designated area of the screen) AND a key is pressed.

Perhaps if you explained what you are trying to do in more concrete terms people will come up with other suggestions, but as @tiffle and @Frankb say you could use a "Gesture" trigger for this -- perhaps a small circling motion.You could then catch the pointer position -- if it is outside your designated area, cancel the macro.

Another, rather horrible, way could be to have a macro that triggers every second and tests pointer position -- you could perhaps limit it to only being active when a certain app is frontmost...

@Nige_S Although I know it must be possible, I have never been able to do the following: KM should only perform an action when the mouse is somewhere along the entire length of the menu bar (and a key is pressed). Can you show me how to do this? Thanks!

Assuming the M key:
keyAndMenubar

3 Likes

Thank you @Nige_S ! This works perfectly. As always when you share your knowledge. What remains besides my perplexity is the question (which needs no answer, because I already know the answer) How should a "normal" user come to this?

Rhetorical questions apart, people like me have no choice but to ask people like you. That doesn't bother me, as long as it doesn't bother you. And because I don't really know what I actually want to say, I'll just say thank you and see you next time. :pray:

1 Like

I would assume in the same way that I do? Break the problem down into small pieces, then look at the manual/Wiki to see what matches up with those pieces. In this case...

We want to test for one or more things -- an "If... Then... Else..." action fits the bill. An "If" action can have one or more "Conditions", so look at the "Conditions" page and see what looks useful. "Key" looks an obvious choice for one of them, but there's no "Mouse Position" so we'll have to look elsewhere.

Pointer and screen coordinates are just numbers, numbers are returned by KM "Functions", so we'll have a look at the "Functions" list. There are two that look good, MOUSEX and MOUSEY -- if you don't remember your school Maths classes it'll only take a couple of tests to see that X increases left-to-right and Y from top-to-bottom. The menu bar is at the top, so we need MOUSEY. So we can test for "MOUSEY being less than or equal to the bottom line of the menu bar".

What's the height of the menu bar? Luckily we don't need to know -- there's also a MENUBARHEIGHT() function on that same page.

Slap all that together, test, change things coz you mixed up < and > again, and you've got something that sort-of works.

Yes, only sort-of. Fine on a single display, probably fine (not tested) on a multi-display setup where the top edges are aligned in Display preferences. But it'll break if the pointer is at the top of a different-size second display that is bottom-aligned, if your displays are vertically stacked, etc. At which point you could start looking at SCREEN/SCREENVISIBLE, with which you can get the dimensions of the screen the mouse is currently on and could do something like:

SCREEN(Mouse,Top) < MOUSEY() < SCREENVISIBLE(Mouse,Top)

Lest the above sound condescending -- it's just a description of what I do, and describing it in that way hopefully removes any "magic" from the process. I honestly believe anyone can do the same with a bit of practice -- but I also remember my old music teacher saying the same about playing the piano, and you do not want to hear me trying to play Chopsticks ;-).

1 Like

You have explained this very clearly. It is the approach of an analytical person who is willing and able to handle a matter properly. Others would say "if I only want a glass of milk, I certainly won't buy a cow". Meaning in this case, if you want a macro, you don't necessarily want to spend hours reading a manual. These people have two options: They don't use KM anymore or they just ask people like you. I belong to the second type. My goal is to have a working macro that I understand at least well enough to customize it to my needs. I want the milk :milk_glass: not the cow :cow2:

Nevertheless I would wish simple actions /settings to be simple to select as well. And only complex actions require a complex procedure that makes it necessary to look into the manual.

True. But that doesn't mean that the user has to be confronted with these numbers for simple actions. Other apps translate them into understandable words. An action is executed only if the mouse

  • is over the menu bar
  • is not over the menu bar
  • is over the notch
  • is over dock
  • is not over the dock
    (and so on)

Even I understand that. There would be many more such examples, the listing of which does not change the initial situation. Therefore I will continue to simply ask and hope that friendly people like you will answer. This provides me with the best macros and gives others the opportunity to shine with their helpfulness and their knowledge. It seems to me that this is a win-win situation. :smirk:

Hey everyone, thanks for the helpful replies.

Disclaimer, this is a very very niche / picky issue that I am trying to find a workaround for, no sympathy is required. The fact that I'm pursuing a solution to this issue qualifies me as a diva, I am aware.

To clarify what I am trying to do: I use Logic Pro (music software) on a 2-monitor setup, one screen mounted above the other. In my upper screen, I keep the "Tracks" window of logic open, where I do most of my work. On the bottom screen, I keep the "Mixer" window open, to allow fast access to many things on the fly.
The Mixer window has one very weird trait that has always bugged me, which is:
When you click on the center of the window, which is often a large, unoccupied grey area, the Mixer window does not get brought to the front. Instead, the Tracks window remains as the front window of Logic Pro. To get the Mixer window to the front, you need to click a very narrow bar at the top of the window or click the title bar itself, which is annoying because I usually have it fullscreen/title bar hidden. I guess its the hierarchy of windows in Logic that prioritizes the Tracks window over the Mixer window.

Having the mixer window at the front is necessary for several other functions to work, so I often have to precisely click a little area, as opposed to clicking anywhere on the giant grey no-man's-land that takes up most of the window.

My goal with a macro for this is simply to allow me to click on the big grey blob of the mixer window and have the Mixer window become the front window.
I successfully made a macro that does this which I'll share. It does not use Gesture triggers, it uses USB device key trigger, so I can simply click the good ol' left mouse button.

This is before the macro and after the macro. Works like a charm (but...)

window-clickable

2 Likes

This is the Macro:
Windower Macro.kmmacros (214.5 KB)

Its in a Macro group with restrictions on:
-Applications: Logic Pro
-Window title not containing Mixer (so it doesn't work if the mixer is already at the front)

The major downside to the way its set up, is that the Macro is technically firing every single time I click my left mouse button anywhere in the Tracks window. Thats a lotta clicks. I've noticed Logics CPU meter throttling a bit when it shouldn't be, undoubtably due to the excessive Found Image searching that I'm making it do every time I click. In a hefty enough project, I'd probably have to disable the macro.

Its so nice though - and I feel like I'm so close to it working. Could I maybe replace the Found Image part of the macro with that MouseXY stuff mentioned above? I'm a noob to all this so I must be missing something.
Also, I know I could just add a modifier to the trigger to basically solve this problem, but this is about man vs machine, and this man wants to click his god-given left mouse button on that useless grey wasteland and not have to use his brain. (diva)

1 Like

I don't have Logic, but I think you probably could. Rather than doing a CPU-intensive image search you should be able to do something like:

If the pointer is outside the "Tracks" window but inside a "Mixer" window
    Bring to front windows containing "Mixer"
Otherwise
    Cancel macro
End If

Do you have multiple "Mixer" windows open that you'll have to cater for?

No, I only keep one Mixer window open at a time. But this makes sense. How would I go about creating a pointer-location condition, as you just mentioned above? Thats where I'd be stuck.

The %WindowFrame% token returns the left-edge,top-edge,width,height of a window. Luckily for us there are some built-in calculations so we can get other values -- Right, Bottom, etc -- directly rather than by calculation. You can read more about "Window Tokens" on the wiki.

On there you'll see that you can ask about an app's windows individually, but you can also ask for all of them in one go -- we can use that to create an "array" of window values that we can then work through, so the macro will cope with as many windows as you might have open.

So we can find the "rectangle" of a window, and we can also get the pointer location with %CurrentMouse% token, in the form x_coord,y_coord.

The pointer will be outside the window if its x is less than the window's left edge value or greater than the right or its y is less than the window's top edge value or greater than the bottom.

Contrariwise, the pointer will be inside the window if its x is greater than the window's left edge value and less than the right and its y is greater than the window's top edge value and less than the bottom.

(Actually you should also include "equals" for the inside check -- too much to type here but you'll see it in the macro.)

Add some jiggery to convert the lines returned when we ask for "all the windows" into an array we can access by index and we can then test whether the pointer is in a window (working from "front" to "back", skipping window 1 because that will be "Tracks", and exiting the loop on first match) and act accordingly. The index of "match" will be the same as the index of the window, so we can use that to activate the correct one.

And the final case would be when the pointer is outside all the app's windows, like when you click on the Desktop -- then we just pass the click onwards in that same location.

Put that all together and you get:
Activate Window by Click.kmmacros (12.6 KB)

Image

One time when this will misbehave is when you've managed to interleave application windows -- so if "Tracks" is active and you've got eg a TextEdit window on top of a LPro "Mixer" window. Click on the TextEdit window and it'll activate the "Mixer" window instead.

Tested in TextEdit, but the macro should be app-agnostic. For your purposes, probably best to use the same activation setting as the one you posted.

Ok thanks so much for the intel, I'm going to see where I can get with this.

Update - At first it seemed to work more quickly and efficiently than mine, but realized that the problem with it is that anytime I open a smaller window on top of the track window (a plug-in window for example), I am unable to click and drag. Meaning unable to slide a slider up and down or even highlight text. Aside from that it seems pretty flawless, just obviously unusable with that given drawback

That implies that the "smaller window" isn't a proper window, otherwise it would be frontmost and the macro wouldn't fire because "Tracks" wasn't frontmost. is that right?