autohotkeyautohotkey-2

I am trying to move my windows but WinMove doesn't work


I am trying to swap windows on my screen. The MsgBoxes work but WinMove doesn't:

{
...
; Move from Monitor 1 to Monitor 2
    if (WinX >= Monitor1X && WinX < Monitor1EndX) {
        SwapToScreen(thisID, Monitor2X, WinX, WinY, Monitor1X)
        MsgBox , 1 to 2, %Title%
    }
    ; Move from Monitor 2 to Monitor 1
    else if (WinX >= Monitor2X && WinX < Monitor2EndX) {
        SwapToScreen(thisID, Monitor1X, WinX, WinY, Monitor2X)
        MsgBox, 2 to 1, %Title%
    }
    ; Handle fullscreen cases (X = -9)
    else if (WinX < 0 || WinY < 0) {
        WinGet, IsMaximized, MinMax, ahk_id %thisID%
        if (IsMaximized) {
            SwapToScreen(thisID, Monitor2X, Monitor1X, WinY, Monitor1X)
            WinRestore, ahk_id %thisID%
        }
        if (IsMaximized) {
            WinMaximize, ahk_id %thisID%
        }
    }
    else {
        MsgBox, Active window is not within defined screen boundaries.
    }
}
}

SwapToScreen(ActiveWinID, TargetMonitorX, CurrentX, CurrentY,
SourceMonitorX) {
NewX := TargetMonitorX + (CurrentX - SourceMonitorX)
WinGetPos, OldX, OldY, OldWidth, OldHeight, ahk_id %ActiveWinID%

; Adjust size based on scaling factor
if (TargetMonitorX = 0) {
    ScaleFactor := 1  ; Moving to Monitor 1
} else {
    ScaleFactor := 1 ; Moving to Monitor 2
}

NewWidth := OldWidth * ScaleFactor
NewHeight := OldHeight * ScaleFactor

; Move the window and report success
MsgBox, Moving Window ID: %ActiveWinID% to X: %NewX%, Y: %CurrentY%, Width: %NewWidth%, Height: %NewHeight%

WinMove, ahk_id %ActiveWinID% , %NewX% , %CurrentY% , %NewWidth%, %NewHeight%
MsgBox, Window moved successfully to X: %OldX%,%NewX%, Y: %OldY%,%CurrentY%, Width: %OldWidth%,%NewWidth%, Height: %OldHeight%,%NewHeight%.
}

I also need to resize it because of difference between resolutions.


Solution

  • #7 will be useful:

    ;;∙============================================================∙
    /*    🔥∙HOTKEYS∙🔥
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad1    ;;∙------∙Monitor of active window.
        Ctrl+Alt+1
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad2    ;;∙------∙Detects monitor under current mouse cursor.
        Ctrl+Alt+2
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad3    ;;∙------∙Detects monitor with largest intersection with a custom rectangle.
        Ctrl+Alt+3
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad4    ;;∙------∙ENHANCED: Monitor of active window with Resolution & DPI.
        Ctrl+Alt+4
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad5    ;;∙------∙ENHANCED: Detects monitor under current mouse cursor with Resolution & DPI.
        Ctrl+Alt+5
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad6    ;;∙------∙ENHANCED: Detects monitor with largest intersection with a custom rectangle.
        Ctrl+Alt+6
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad7    ;;∙------∙Move active window to the opposite monitor.
        Ctrl+Alt+7
    ∙--------------------------------------------------------------------∙
    Ctrl+Alt+Numpad8    ;;∙------∙Shows monitor information with Primary monitor listed first.
        Ctrl+Alt+8
    ∙--------------------------------------------------------------------∙
    */
    
    
    ;;∙============================================================∙
    #MaxThreadsPerHotkey 3
    #NoEnv
    #Persistent
    #SingleInstance, Force
    Menu, Tray, Icon, imageres.dll, 291
    SetBatchLines -1
    SetTitleMatchMode 2
    SetWinDelay 0
    ;;∙-----------------------∙
    
    Monitors := MDMF_Enum()    ;;∙------∙Retrieves All relevant monitor information. **
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad1::    ;;∙------∙Monitor of active window.
    ^!1::
    ActiveWindow := WinExist("A")    ;;∙------∙Determines hwnd of active window.
    ActiveMonitor := Monitors[MDMF_FromHWND(ActiveWindow)]    ;;∙------∙Retrieves display monitor that has largest area of intersection with this window.
    MsgBox,,,% ActiveMonitor.Num "`n" ActiveMonitor.Name, 5    ;;∙------∙Shows active monitor's Number & Name.
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad2::    ;;∙------∙Detects monitor under current mouse cursor.
    ^!2::
    ActiveMonitor := Monitors[MDMF_FromPoint()]    ;;∙------∙Retrieves the monitor containing the cursor.
    MsgBox,,,% "Monitor with Mouse Cursor: `n" ActiveMonitor.Num "`n" ActiveMonitor.Name, 5    ;;∙------∙Shows monitor number & name.
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad3::    ;;∙------∙Detects monitor with largest intersection with a custom rectangle.
    ^!3::
    InputBox, X, Enter X Coordinate, Please enter the X coordinate., , 200, 120
    InputBox, Y, Enter Y Coordinate, Please enter the Y coordinate., , 200, 120
    InputBox, W, Enter Width, Please enter the width of the rectangle., , 200, 120
    InputBox, H, Enter Height, Please enter the height of the rectangle., , 200, 120
    ActiveMonitor := Monitors[MDMF_FromRect(X, Y, W, H)]    ;;∙------∙Retrieves monitor that intersects most with custom rectangle.
    MsgBox,,,% "Monitor for Custom Rectangle: `n" ActiveMonitor.Num "`n" ActiveMonitor.Name, 5    ;;∙------∙Shows monitor number & name.
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad4::    ;;∙------∙ENHANCED: Monitor of active window with Resolution & DPI.
    ^!4::
    ActiveWindow := WinExist("A")    ;;∙------∙Determines hwnd of active window.
    If !ActiveWindow {
        MsgBox,,, Error, Active window not found., 7
        Return
    }
    ActiveMonitor := Monitors[MDMF_FromHWND(ActiveWindow)]    ;;∙------∙Retrieves display monitor.
    If !ActiveMonitor {
        MsgBox,,, Error, No monitor found for the active window., 7
        Return
    }
    DisplayMonitorInfo(ActiveMonitor, "Monitor of Active Window")
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad5::    ;;∙------∙ENHANCED: Detects monitor under current mouse cursor with Resolution & DPI.
    ^!5::
    ActiveMonitor := Monitors[MDMF_FromPoint()]    ;;∙------∙Retrieves the monitor containing the cursor.
    If !ActiveMonitor {
        MsgBox,,, Error, No monitor found under the mouse cursor., 7
        Return
    }
    DisplayMonitorInfo(ActiveMonitor, "Monitor with Mouse Cursor")
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad6::    ;;∙------∙ENHANCED: Detects monitor with largest intersection with a custom rectangle.
    ^!6::
    InputBox, X, Enter X Coordinate, Please enter the X coordinate., , 200, 120
    InputBox, Y, Enter Y Coordinate, Please enter the Y coordinate., , 200, 120
    InputBox, W, Enter Width, Please enter the width of the rectangle., , 200, 120
    InputBox, H, Enter Height, Please enter the height of the rectangle., , 200, 120
    ActiveMonitor := Monitors[MDMF_FromRect(X, Y, W, H)]    ;;∙------∙Retrieves monitor that intersects most with the custom rectangle.
    If !ActiveMonitor {
        MsgBox,,, Error, No monitor found for the custom rectangle., 7
        Return
    }
    DisplayMonitorInfo(ActiveMonitor, "Monitor for Custom Rectangle")
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad7::    ;;∙------∙Move active window to the opposite monitor
    ^!7::
    Soundbeep, 1200, 200
    ActiveWindow := WinExist("A")    ;;∙------∙Determine the hwnd of the active window
    If !ActiveWindow {
        MsgBox,,, Error, Active window not found., 7
        Return
    }
    ActiveMonitor := Monitors[MDMF_FromHWND(ActiveWindow)]    ;;∙------∙Find the active window's monitor
    If !ActiveMonitor {
        MsgBox,,, Error, No monitor found for the active window., 7
        return
    }
    ;;∙------∙Get the list of monitors, sorted to ensure the primary is first
    SortedMonitors := []
    For HMON, M In Monitors {
        If M.Primary
            SortedMonitors.InsertAt(1, {HMON: HMON, M: M})   ;;∙------∙Insert primary monitor at the beginning
        Else
            SortedMonitors.Push({HMON: HMON, M: M})
    }
    ;;∙------∙Find the current monitor's index
    CurrentMonitorIndex := 0
    For Index, Monitor In SortedMonitors {
        If (Monitor["HMON"] = ActiveMonitor["HMON"]) {
            CurrentMonitorIndex := Index
            Break
        }
    }
    ;;∙------∙Calculate the opposite monitor based on position.
    OppositeMonitor := ""
    MaxDistance := 0
    For Index, Monitor In SortedMonitors {
        If (Index != CurrentMonitorIndex) {
            ;;∙------∙Calculate distance between current monitor and each other monitor
            Distance := Abs(ActiveMonitor["Left"] - Monitor["M"]["Left"]) + Abs(ActiveMonitor["Top"] - Monitor["M"]["Top"])
            If (Distance > MaxDistance) {
                MaxDistance := Distance
                OppositeMonitor := Monitor
            }
        }
    }
    If OppositeMonitor {
        ;;∙------∙Get the current window's size and position before moving.
        WinGetPos, X, Y, Width, Height, ahk_id %ActiveWindow%
        ;;∙------∙Get the current monitor's position. (relative to the screen)
        CurrentMonitorLeft := ActiveMonitor["Left"]
        CurrentMonitorTop := ActiveMonitor["Top"]
        ;;∙------∙Get the opposite monitor's position. (relative to the screen)
        OppositeMonitorLeft := OppositeMonitor["M"]["Left"]
        OppositeMonitorTop := OppositeMonitor["M"]["Top"]
        ;;∙------∙Calculate the new position on the opposite monitor.
        NewX := X - CurrentMonitorLeft + OppositeMonitorLeft
        NewY := Y - CurrentMonitorTop + OppositeMonitorTop
            ;;∙------∙ *DEBUGGING*  Show current position, size, and new calculated position. *DEBUGGING*
            ;;∙------∙ MsgBox,,, % "Current Window Position: " X ", " Y "`nWidth: " Width "`nHeight: " Height, 5
            ;;∙------∙ MsgBox,,, % "Opposite Monitor: " OppositeMonitor["M"]["Name"] "`nNew Position: " NewX ", " NewY, 5
        ;;∙------∙Move the active window to the opposite monitor's calculated position, preserving the size.
        WinMove, ahk_id %ActiveWindow%, , NewX, NewY, Width, Height
    } Else {
        MsgBox,,, Error, No opposite monitor found., 7
    }
    Return
    
    ;;∙------∙🔥∙--------------------------------------------------------------------------------∙
    ^!Numpad8::    ;;∙------∙Shows monitor information with Primary monitor listed first.
    ^!8::
    Gui, Margin, 20, 20
    Gui, +OwnDialogs
    Gui, Add, ListView, w660 r10 Grid, HMON|Num|Name|Primary|Left|Top|Right|Bottom|WALeft|WATop|WARight|WABottom
    SortedMonitors := []    ;;∙------∙Sort monitors to bring primary one to the top.
    For HMON, M In Monitors {
        If M.Primary
            SortedMonitors.InsertAt(0, {HMON: HMON, M: M})
        Else
            SortedMonitors.Push({HMON: HMON, M: M})
    }
    For Index, Monitor In SortedMonitors {
        LV_Add("", Monitor.HMON, Monitor.M.Num, Monitor.M.Name, Monitor.M.Primary, Monitor.M.Left, Monitor.M.Top, Monitor.M.Right, Monitor.M.Bottom, Monitor.M.WALeft, Monitor.M.WATop, Monitor.M.WARight, Monitor.M.WABottom)
    }
    Loop, % LV_GetCount("Column")
       LV_ModifyCol(A_Index, "AutoHdr")
    Gui, Show, ,Monitors
    Return
    ;;∙============================================================∙
    
    
    ;;∙============================================================∙
    ;;∙-----------------∙FUNCTIONS∙--------------------------------------------------------∙
    ;;∙============================================================∙
    ;;∙-----------------------∙Enumerates display monitors and returns an object containing the properties of all monitors or the specified monitor.
    MDMF_Enum(HMON := "") {
        Static EnumProc := RegisterCallback("MDMF_EnumProc")
        Static Monitors := {}
        If (HMON = "")    ;;∙------∙New enumeration.
            Monitors := {}
        If (Monitors.MaxIndex() = "")    ;;∙------∙Enumerate.
            If !DllCall("User32.dll\EnumDisplayMonitors", "Ptr", 0, "Ptr", 0, "Ptr", EnumProc, "Ptr", &Monitors, "UInt")
                Return False
        Return (HMON = "") ? Monitors : Monitors.HasKey(HMON) ? Monitors[HMON] : False
        }
    ;;∙-----------------------∙Callback function that is called by the MDMF_Enum function.
    MDMF_EnumProc(HMON, HDC, PRECT, ObjectAddr) {
        Monitors := Object(ObjectAddr) ;
        Monitors[HMON] := MDMF_GetInfo(HMON)
        Return True
        }
    ;;∙-----------------------∙Retrieves the display monitor that has the largest area of intersection with a specified window.
    MDMF_FromHWND(HWND) {
        Return DllCall("User32.dll\MonitorFromWindow", "Ptr", HWND, "UInt", 0, "UPtr")
        }
    ;;∙-----------------------∙Retrieves the display monitor that contains a specified point.
    ;;∙------∙If either X or Y is empty, the function will use the current cursor position for this value.
    MDMF_FromPoint(X := "", Y := "") {
        VarSetCapacity(PT, 8, 0)
        If (X = "") || (Y = "") {
            DllCall("User32.dll\GetCursorPos", "Ptr", &PT)
            If (X = "")
                X := NumGet(PT, 0, "Int")
            If (Y = "")
                Y := NumGet(PT, 4, "Int")
            }
            Return DllCall("User32.dll\MonitorFromPoint", "Int64", (X & 0xFFFFFFFF) | (Y << 32), "UInt", 0, "UPtr")
        }
    ;;∙-----------------------∙Retrieves display monitor that has largest area of intersection with a specified rectangle.
    ;;∙------∙Parameters consistent with common AHK definition of a rectangle, which is X, Y, W, H. (not... Left, Top, Right, Bottom)
    MDMF_FromRect(X, Y, W, H) {
        VarSetCapacity(RC, 16, 0)
        NumPut(X, RC, 0, "Int"), NumPut(Y, RC, 4, Int), NumPut(X + W, RC, 8, "Int"), NumPut(Y + H, RC, 12, "Int")
        Return DllCall("User32.dll\MonitorFromRect", "Ptr", &RC, "UInt", 0, "UPtr")
        }
    ;;∙-----------------------∙Retrieves information about a display monitor.
    MDMF_GetInfo(HMON) {
        NumPut(VarSetCapacity(MIEX, 40 + (32 << !!A_IsUnicode)), MIEX, 0, "UInt")
        If DllCall("User32.dll\GetMonitorInfo", "Ptr", HMON, "Ptr", &MIEX) {
            MonName := StrGet(&MIEX + 40, 32)    ;;∙------∙CCHDEVICENAME = 32
            MonNum := RegExReplace(MonName, ".*(\d+)$", "$1")
    
        ;;∙------∙Retrieve Monitor's DPI settings (Windows 8.1+)
        If (A_OSVersion >= "6.3") {
            VarSetCapacity(DPI, 8, 0)
        If (DllCall("Shcore.dll\GetDpiForMonitor", "Ptr", HMON, "UInt", 0, "UInt*", dpiX, "UInt*", dpiY) = 0) {
            dpiX := dpiX
            dpiY := dpiY
        } Else {
            dpiX := dpiY := 96    ;;∙------∙Default DPI if function fails.
            }
        } Else {
            dpiX := dpiY := 96    ;;∙------∙Default DPI for older Windows.
              }
        ;;∙------∙Get the resolution from monitor bounds
        resWidth := NumGet(MIEX, 12, "Int") - NumGet(MIEX, 4, "Int")
        resHeight := NumGet(MIEX, 16, "Int") - NumGet(MIEX, 8, "Int")
        Return {Name:      (Name := StrGet(&MIEX + 40, 32))
            , Num:       RegExReplace(Name, ".*(\d+)$", "$1")
            , Left:      NumGet(MIEX, 4, "Int")    ;;∙------∙Display rectangle.
            , Top:       NumGet(MIEX, 8, "Int")    ;;∙------∙"
            , Right:     NumGet(MIEX, 12, "Int")    ;;∙------∙"
            , Bottom:    NumGet(MIEX, 16, "Int")    ;;∙------∙"
            , ResWidth:  resWidth
            , ResHeight: resHeight
            , DPI_X:     dpiX
            , DPI_Y:     dpiY
            , WALeft:    NumGet(MIEX, 20, "Int")    ;;∙------∙Work area.
            , WATop:     NumGet(MIEX, 24, "Int")    ;;∙------∙"
            , WARight:   NumGet(MIEX, 28, "Int")    ;;∙------∙"
            , WABottom:  NumGet(MIEX, 32, "Int")    ;;∙------∙"
            , Primary:   NumGet(MIEX, 36, "UInt")}    ;;∙------∙Contains a non-zero value for the primary monitor.
       }
       Return False
    }
    ;;∙-----------------------∙Displays monitor information in a GUI with an Edit control.
    DisplayMonitorInfo(MonitorInfo, Title) {
        global EditControl  ;; Declare EditControl as global to avoid the variable scope error.
        Gui, New, +AlwaysOnTop +HwndGuiHwnd
        Gui, Add, Edit, w600 r12 ReadOnly vEditControl, % "Monitor Number: " MonitorInfo.Num "`n"
            . "Monitor Name: " MonitorInfo.Name "`n"
            . "Resolution: " MonitorInfo.ResWidth " x" MonitorInfo.ResHeight "`n"
            . "DPI: " MonitorInfo.DPI_X " x " MonitorInfo.DPI_Y "`n"
            . "Coordinates: (" MonitorInfo.Left ", " MonitorInfo.Top ") - (" MonitorInfo.Right ", " MonitorInfo.Bottom ")`n"
            . "Work Area: (" MonitorInfo.WALeft ", " MonitorInfo.WATop ") - (" MonitorInfo.WARight ", " MonitorInfo.WABottom ")`n"
            . "Primary: " (MonitorInfo.Primary ? "Yes" : "No")
        Gui, Show, , % Title
        GuiControlGet, CurrentContent, , EditControl
        GuiControl,, EditControl, % CurrentContent . "`n`n`t*END*"
    }
    Return
    ;;∙============================================================∙