6

I have multiple monitors, and when moving between apps, it is normally quicker to do that via the keyboard, so I tend to do most of my window management/navigation via keyboard shortcuts. However, there are times when the mouse is necessary. My problem is, that when I change the active window, my mouse can be on any of my current screens, so I have to find it first, and then drag the point to where I need to click.

What I would like tis to either:
A) Have the mouse move to the center of the active window when I switch active windows via cmd-Tab.
B) Have a keyboard shortcut I can press to quickly call the mouse pointer to the active window if I need it

I have found many "hacks" and apps which individually support FFM, but I want MFF. Anyone know how to do this?

Paul
  • 73
  • 1
  • 3

1 Answers1

3

The basic concept is simple enough, though there are quirks in the implementation. The following script should do what you ask for in (A), with the caveat that it can't distinguish how an app is opened. It will operate whenever an app becomes active — through cmd-tab, a click on the dock icon, a double-click on the app icon, etc. — and will fail silently if there are no open windows or some other error condition occurs.

Copy the following script into the Script Editor, and save it as an stay-open application (select 'Application' from the File Format pulldown menu, and click the 'stay open after run handler' checkbox). You'll need to give it Accessibility permissions in security preferences, and you'll have to toggle those permissions off and on again every time you edit the script application.

use AppleScript version "2.4"
use framework "AppKit"
use scripting additions

property NSWorkspace : class "NSWorkspace"

on run
    set workSp to NSWorkspace's sharedWorkspace()
    set notifCent to workSp's notificationCenter()
    tell notifCent to addObserver:me selector:"activeAppHasChanged:" |name|:"NSWorkspaceDidActivateApplicationNotification" object:(missing value)
end run

on idle
    -- we don't use the idle loop, so tell the system let the app sleep. this comes out of idle once an hour
    return 3600
end idle

on activeAppHasChanged:notif
    set targetApp to (notif's userInfo's valueForKey:"NSWorkspaceApplicationKey")
    set targetAppName to (targetApp's localizedName) as text
    tell application "System Events"
        tell process targetAppName
            try
                set {xpos, ypos} to position of first window
                set {w, h} to size of first window
                my mouseMove(xpos + w / 2, ypos + h / 2)
            end try
        end tell
    end tell
end activeAppHasChanged:

on mouseMove(newX, newY)
    do shell script "
    
/usr/bin/python <<END

from Quartz.CoreGraphics import CGEventCreateMouseEvent
from Quartz.CoreGraphics import CGEventPost
from Quartz.CoreGraphics import kCGMouseButtonLeft
from Quartz.CoreGraphics import kCGHIDEventTap
from Quartz.CoreGraphics import kCGEventMouseMoved
import time

def mouseEvent(posx, posy):
          theEvent = CGEventCreateMouseEvent(None, kCGEventMouseMoved, (posx,posy), kCGMouseButtonLeft)
          CGEventPost(kCGHIDEventTap, theEvent)

mouseEvent(" & newX & "," & newY & ");

END"
end mouseMove

Launch the script and leave it running in the background. Every time you switch apps, it will center the cursor in the first open window of the application. If you prefer option (B) — the keyboard shortcut route — that's also doable, but it's a bit different approach. Ask if you need help implementing it.

Ted Wrigley
  • 2,921
  • 2
  • 7
  • 17
  • 1
    Thanks for the script! So far, so good. There is a bit of a lag, likely as it is going to execute the python code, and some side effects like you mentioned (i.e. if I do switch by clicking on the window, it will recent the mouse on that window). I can likely solve the mouse issue by checking to see if the current mouse location is already within the x,y,w,h position, and only move if it is not. But this is a great start!!! – Paul Oct 07 '20 at 17:23
  • 1
    I think the lag is probably from the NSWorkspace notification; notifications are delivered lazily. If I remember correctly, running a version of the script that doesn't use notification (i.e., that sets the mouse position by hand) shows almost no lag. But, you know... AppleScript is donkey, not a racehorse; we can't expect it to fly like the wind. – Ted Wrigley Oct 07 '20 at 17:38