-1

I've been using a short AutoHotKey script to simulate Alt Tab on Windows 10 using the middle mouse button, so that I can quickly open my most recently opened app, or toggle between two apps, with the click of a button. This is what I'm using

Mbutton::SendEvent {Alt Down}{Tab}{Alt Up}

But I've been using two monitors recently, and what I really want to do is switch to the most recently opened app ON THE ACTIVE MONITOR (or the monitor that the mouse is currently on). Alt Tab alone doesn't work obviously, because often the most recently opened app is on the other monitor and I only want to bring the window of the most recently used app forward if it is in the monitor I'm currently working in. Does anyone know if this is possible and how I might go about doing it?

omaxio
  • 29
  • 1
  • 5
  • I can imagine that you could write a script that tracks ids of four (in case of two monitors) windows − two last most recently opened windows for each monitor. It periodically checks and updates them. When hotkey is pressed, it should detect what is current monitor, current window, and then check the two recent windows list for this monitor. If the first one is identical to the currently active, it would switch to the second; of not − to the first of the two. – stansult Mar 19 '16 at 02:32
  • Thanks, yes something like that is what I think might work. Problem is I can't do it from scratch! I was hoping to find something online that I could adapt, but haven't yet. – omaxio Mar 20 '16 at 12:00
  • This is not gonna be simple. Here is how you can check which screen a window is on: http://stackoverflow.com/questions/34338637/determining-which-screen-a-window-is-on-by-checking-where-the-most-surfacearea – Forivin Mar 21 '16 at 10:28

1 Answers1

0

I am pasting here my script. It is very ugly, but it works on my two-monitor setup as you described: switches to the previous (for the monitor where you click middle button) active window.

#WinActivateForce
#SingleInstance
#Persistent

CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen

DetectHiddenWindows, On
SetTitleMatchMode , 2
SetBatchLines , -1
SetWorkingDir %A_ScriptDir%

Thread, interrupt, 0
SetTimer, UpdateCurrentWindow, 100

isDebug := true

SysGet, monitors_total, MonitorCount
SysGet, monitor_primary, MonitorPrimary

Hotkey, MButton, SwitchToLastWindow, On

return


SwitchToLastWindow:

WinGet, active_id, ID, A

Loop , %monitors_total%
{
    if (A_Index != current_monitor)
        continue

    switch_to_window := (active_id = winlast%A_Index%)
                      ? winprelast%A_Index%
                      : winlast%A_Index%
}

WinActivate , ahk_id %switch_to_window%

return



UpdateCurrentWindow:

WinGet, active_id, ID, A
monitor_index := GetMonitorIndexFromWindow(active_id)

current_monitor := GetMonitorIndexFromMouse()

if (monitor_index > monitors_total)
    monitors_total := monitor_index

if (winlast%monitor_index% != active_id)
{
    winprelast%monitor_index% := winlast%monitor_index%
    winlast%monitor_index% := active_id
}

if isDebug
{
    DebugToolTip := ""
    Loop , %monitors_total%
    {
        DebugToolTip .= "Monitor # " . A_Index
                     . ":`n`nLast window: "  . winlast%A_Index%
                     . "`nPre-last window: " . winprelast%A_Index% . "`n`n"
    }

    MouseGetPos, xpos, ypos
    DebugToolTip .= "x: " . xpos . "`ny: " . ypos . "`ncurrent_monitor: " . current_monitor
                 . "`n`nA_ScreenHeight: " . A_ScreenHeight . "`nA_ScreenWidth: " . A_ScreenWidth
                 . "`n`nmonitors_total: " . monitors_total . "`nmonitor_primary: " . monitor_primary

    ToolTip , %DebugToolTip%, 10, 10
}

return


; only done for one case: total 2 monitors, monitor to the left is primary
; need to redo for the generic case

GetMonitorIndexFromMouse()
{
    SysGet, monitors_total, MonitorCount
    SysGet, monitor_primary, MonitorPrimary
    MouseGetPos, xpos, ypos
    current_monitor := (xpos > A_ScreenWidth) ? 2 : 1

    return current_monitor
}


; this function is from autohotkey.com/board/topic/69464-how-to-determine-a-window-is-in-which-monitor/?p=440355

GetMonitorIndexFromWindow(windowHandle)
{
    ; Starts with 1.
    monitorIndex := 1

    VarSetCapacity(monitorInfo, 40)
    NumPut(40, monitorInfo)

    if (monitorHandle := DllCall("MonitorFromWindow", "uint", windowHandle, "uint", 0x2)) 
        && DllCall("GetMonitorInfo", "uint", monitorHandle, "uint", &monitorInfo) 
    {
        monitorLeft   := NumGet(monitorInfo,  4, "Int")
        monitorTop    := NumGet(monitorInfo,  8, "Int")
        monitorRight  := NumGet(monitorInfo, 12, "Int")
        monitorBottom := NumGet(monitorInfo, 16, "Int")
        workLeft      := NumGet(monitorInfo, 20, "Int")
        workTop       := NumGet(monitorInfo, 24, "Int")
        workRight     := NumGet(monitorInfo, 28, "Int")
        workBottom    := NumGet(monitorInfo, 32, "Int")
        isPrimary     := NumGet(monitorInfo, 36, "Int") & 1

        SysGet, monitorCount, MonitorCount

        Loop, %monitorCount%
        {
            SysGet, tempMon, Monitor, %A_Index%

            ; Compare location to determine the monitor index.
            if ((monitorLeft = tempMonLeft) and (monitorTop = tempMonTop)
                and (monitorRight = tempMonRight) and (monitorBottom = tempMonBottom))
            {
                monitorIndex := A_Index
                break
            }
        }
    }

    return monitorIndex
}

One of the functions (GetMonitorIndexFromWindow(windowHandle)) is not mine, taken from here.

Note that I haven’t got time to work on generic case for my GetMonitorIndexFromMouse() function, so it’s just good for my specific case (2 monitors, with the left one as primary).

I have isDebug := true here, so that you could see the tooltip with variables − feel free to change it to isDebug := false of course, if the script works for you.

stansult
  • 1,323
  • 10
  • 18