这段脚本实现了 对指定窗口的排列管理功能。其核心目的是对特定窗口(如资源管理器窗口)进行 平铺、堆叠或自定义排列,并根据屏幕或多显示器环境动态调整窗口的位置和大小。

 

global ARRANGE_SIDE_BY_SIDE := 0x00
global ARRANGE_STACKED := 0x01 ; if not then arrange SIDE_BY_SIDE
global ARRANGE_MAXWINDOW := 0x02
global ARRANGE_MINWINDOW := 0x04
global ARRANGE_MOVING := 0x10
global ARRANGE_Z_ORDERING := 0x20

F1::
ArrangeWindows(, 1, "CabinetWClass")
Return

; 参1--- 0或留空排列窗口    1堆叠窗口
; 参2--- 0或留空,被覆盖窗口只排列,不带到顶层    1激活一次所有窗口,使其到其他窗口上层
; 参2--- 默认对文件夹窗口操作,要操作其他窗口填目标窗口Class
; 默认跳过最大化、最小化、隐藏等窗口


ArrangeWindows(arrangeFlags = "0", WinA := 0, wint := "CabinetWClass"){
    arrangeFlags += 0 ; string to number
    SysGet, MonitorCount, MonitorCount
    ; 列出每个显示器内的窗口
    loop %MonitorCount% {
        MonitorIndex := A_Index
        listOfWindow_%MonitorIndex% := WindowsListOfMonitor(arrangeFlags, MonitorIndex, wint)
        Sort listOfWindow_%MonitorIndex%
    }
    ; 位置调整
    loop %MonitorCount% {
        MonitorIndex := A_Index
        if (arrangeFlags & ARRANGE_STACKED){
            ArrangeWindowsStacked(listOfWindow_%MonitorIndex%, arrangeFlags | ARRANGE_MOVING, MonitorIndex)
        } else {
            ArrangeWindowsSideBySide(listOfWindow_%MonitorIndex%, arrangeFlags | ARRANGE_MOVING, MonitorIndex)
        }
    }
    ; Z_Order 调整
    loop %MonitorCount% {
        MonitorIndex := A_Index
        if (arrangeFlags & ARRANGE_STACKED){
            ArrangeWindowsStacked(listOfWindow_%MonitorIndex%, arrangeFlags | ARRANGE_Z_ORDERING, MonitorIndex)
        } else {
            ArrangeWindowsSideBySide(listOfWindow_%MonitorIndex%, arrangeFlags | ARRANGE_Z_ORDERING, MonitorIndex)
        }
    }
  ; 激活窗口
  If (WinA){
    loop %MonitorCount% {
      actWin := []
      MonitorIndex := A_Index
      actWin := StrSplit(Trim(listOfWindow_%MonitorIndex%,"`n"),"`n")
      For Nwin,Awin in actwin
        WinActivate, % Awin
    }
  }
}
Return

WindowsListOfMonitor(arrangeFlags := 0, MonitorIndex := 0, wintt := "CabinetWClass"){
    windowsMatches := ""
    ; 常量定义
    WS_EX_TOOLWINDOW := 0x00000080
    WS_EX_APPWINDOW := 0x00040000
    WS_CAPTION := 0x00C00000
    WS_EX_NOANIMATION := 0x04000000
    WS_EX_NOACTIVATE := 0x08000000
    WS_POPUP := 0x80000000

    DetectHiddenWindows, Off
    WinGet, id, List, , , 
    loop %id% {
        hWnd := id%A_Index%
        WinGet, style, style, ahk_id %hWnd%
        if (!(style & WS_EX_APPWINDOW)){
            continue ; ; 跳 过弹出窗口
        }
        ; 尝试跳过隐藏窗口
        GWL_STYLE := -16
        GWL_EXSTYLE := -20
        WS_VISIBLE := 0x10000000
        if (!(style & WS_VISIBLE)){
            continue
        }
        if (!!MonitorIndex){
            this_monitor := GetMonitorIndexFromWindow(hWnd)
            if (MonitorIndex != this_monitor){
                continue
            }
        }
        if ( !DllCall("IsWindowVisible", "Ptr", hWnd, "PTR") ){
            continue
        }
        ; 跳过最大化窗口
        WinGet, minmax, minmax, ahk_id %hWnd%
        if (minmax == 1 && !(arrangeFlags & ARRANGE_MAXWINDOW)){
            continue
        }
        ; 跳过最小化的窗口
        if (minmax == -1 && !(arrangeFlags & ARRANGE_MINWINDOW)){
            continue
        }
        WinGetTitle, this_title, ahk_id %hWnd%
        ; 排除空标题窗口
        if (!RegExMatch(this_title, ".+")) {
            Continue ; If (this_class == "Progman") ; Continue ; 排除 Win10 的常驻窗口管理器
        }
        ; 跳过不可见的 UWP 窗口 
        WinGetClass, this_class, ahk_id %hWnd%
        if ( this_class == "ApplicationFrameWindow") {
            Continue
        }
    ; 收集所需窗口
    WinGetClass, this_class, ahk_id %hWnd%
    If (this_class = wintt)
      		windowsMatches .= " ahk_id " hWnd "`n" ; . "`t" . this_title . "`n"
    }
    return windowsMatches
}

GetMonitorIndexFromWindow(hWnd){
    MonitorIndex := ""
    VarSetCapacity(monitorInfo, 40)
    NumPut(40, monitorInfo)
    monitorHandle := DllCall("MonitorFromWindow", "uint", hWnd, "uint", 0x2)
    if (monitorHandle && 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
            }
        }
    }
    if (MonitorIndex){
        Return %MonitorIndex%
    }
    MonitorIndex := GetMonitorIndexFromWindowByWindowsCenterPoint(hWnd)
    if (MonitorIndex){
        Return %MonitorIndex%
    }
    Return 1
}

GetMonitorIndexFromWindowByWindowsCenterPoint(hWnd){
    WinGetPos, X, Y, W, H, ahk_id %hWnd%
    CX := X + W / 2
    CY := Y + H / 2
    SysGet, monitorCount, MonitorCount
    MonitorIndex := "" ; default
    loop %monitorCount% {
        SysGet, M, Monitor, %A_Index%
        if (( abs(min(max(MLeft, CX), MRight) - CX) <= 1)&& ( abs(min(max(MTop, CY), MBottom) - CY) <= 1)){
            msgbox, , %title%, %A_Index% %MLeft% %CX% %MRight% %EQ%
            MonitorIndex := A_Index
            break
        }
    }
    Return %MonitorIndex%
}


ArrangeWindowsStacked(listOfWindow, arrangeFlags = "0", MonitorIndex = ""){
    arrangeFlags += 0 ; string to number
    n := StrSplit(listOfWindow, "`n", "`r").Count() - 1
    if (!MonitorIndex){
        AreaX := 0
        AreaY := 0
        AreaW := A_ScreenWidth
        AreaH := A_ScreenHeight
    } else {
        SysGet, MonitorWorkArea, MonitorWorkArea, %MonitorIndex%
        AreaX := MonitorWorkAreaLeft
        AreaY := MonitorWorkAreaTop
        AreaW := MonitorWorkAreaRight - MonitorWorkAreaLeft
        AreaH := MonitorWorkAreaBottom - MonitorWorkAreaTop
    }

    if(arrangeFlags & ARRANGE_MOVING){
        k := 0
        dx := 64
        dy := 64
        w := AreaW - 2 * dx - n * dx + dx
        h := AreaH - 2 * dy - n * dy + dy
        lasthWnd := -2
        loop, Parse, listOfWindow, `n
        {
            hWnd := RegExReplace(A_LoopField, "^.*?ahk_id (\S+?)$", "$1")
            WinGetClass, this_class, ahk_id %hWnd%
            if (this_class == "ApplicationFrameWindow"){
                WinActivate, ahk_id %hWnd%
            }

            x := AreaX + (n - k) * dx
            y := AreaY + (n - k) * dy
            FastResizeWindow(hWnd, x, y, w, h)
            lasthWnd := hWnd
            ; FastResizeWindow(hWnd, x, y, w, h)
            k+=1
        }
    }
    if(arrangeFlags & ARRANGE_Z_ORDERING){
        WinActivate ahk_id %lasthWnd%
        SWP_NOACTIVATE := 0x0010
        SWP_ASYNCWINDOWPOS:= 0x4000
        SWP_NOMOVE := 0x0002
        SWP_NOSIZE := 0x0001
        lasthWnd := -2
        loop, Parse, listOfWindow, `n
        {
            hWnd := RegExReplace(A_LoopField, "^.*?ahk_id (\S+?)$", "$1")
            DllCall("SetWindowPos"
            , "UInt", hWnd ; handle
            , "UInt", lasthWnd ; z-index
            , "Int", 0 ;  x
            , "Int", 0 ; y
            , "Int", 0 ; width
            , "Int", 0 ; height
            , "UInt", SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_ASYNCWINDOWPOS) ; SWP_ASYNCWINDOWPOS
            lasthWnd := hWnd
        }

    }

}

ArrangeWindowsSideBySide(listOfWindow, arrangeFlags = "0", MonitorIndex = ""){
    arrangeFlags += 0 ; string to number
    n := StrSplit(listOfWindow, "`n", "`r").Count() - 1
    ; TrayTip DEBUG_AW_listOfWindow_%n%, %listOfWindow%
    ; try parse work rect from monitor
    if (!MonitorIndex){
        AreaX := 0
        AreaY := 0
        AreaW := A_ScreenWidth
        AreaH := A_ScreenHeight
    } else {
        SysGet, MonitorWorkArea, MonitorWorkArea, %MonitorIndex%
        ; SysGet, Monitor, Monitor, %MonitorIndex%
        AreaX := MonitorWorkAreaLeft
        AreaY := MonitorWorkAreaTop
        AreaW := MonitorWorkAreaRight - MonitorWorkAreaLeft
        AreaH := MonitorWorkAreaBottom - MonitorWorkAreaTop
    }
    if(arrangeFlags & ARRANGE_MOVING){
        if (AreaW <= AreaH){
            ; row more than cols
            col := Sqrt(n) | 0
            row := Ceil(n / col)
        } else {
            ; col more than rows
            row := Sqrt(n) | 0
            col := Ceil(n / row)
        }
        size_x := AreaW / col
        size_y := AreaH / row
        k := n - 1
        lasthWnd := 0
        loop Parse, listOfWindow, `n
        {
            hWnd := RegExReplace(A_LoopField, "^.*?ahk_id (\S+?)$", "$1")

            ; 同一进程窗口长边优先排列
            if (AreaW >= AreaH){
                ; row first
                nx := Mod(k, col)
                ny := k / col | 0
            } else {
                ; col first
                nx := k / row | 0
                ny := Mod(k, row)
            }
            x := AreaX + nx * size_x
            y := AreaY + ny * size_y

            ; 填满窗口间的缝隙
            x:= x-8, y:=y, w:=size_x+16, h:=size_y+8

            ; 左上角不要出界,否则不同DPI的显示器连接处宽度计算不正常
            dX := max(AreaX - x, 0), x += dX, w -= dX
            dY := max(AreaY - y, 0), y += dY, h -= dY
            ; 右下角也不要出界,下边留出1px让wallpaper engine 的bgm放出来
            w := min(x + w, AreaX + AreaW) - x
            h := min(y + h, AreaY + AreaH - 1) - y

            FastResizeWindow(hWnd, x, y, w, h)
            lasthWnd := hWnd
            k-=1
        }
        WinGet, hWnd, , A
    }
    if(arrangeFlags & ARRANGE_Z_ORDERING){
        SWP_NOACTIVATE := 0x0010
        SWP_ASYNCWINDOWPOS:= 0x4000
        SWP_NOMOVE := 0x0002
        SWP_NOSIZE := 0x0001
        lasthWnd := -2
        loop, Parse, listOfWindow, `n
        {
            hWnd := RegExReplace(A_LoopField, "^.*?ahk_id (\S+?)$", "$1")
            DllCall("SetWindowPos"
            , "UInt", hWnd ; handle
            , "UInt", lasthWnd ; z-index
            , "Int", 0 ;  x
            , "Int", 0 ; y
            , "Int", 0 ; width
            , "Int", 0 ; height
            , "UInt", SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE) ; SWP_ASYNCWINDOWPOS
            lasthWnd := hWnd
        }
    }
}


FastResizeWindow(hWnd, x, y, w, h, Active := 0, zIndex := 0){
    ; 如有必要则还原最大化最小化的窗口
    WinGet, minmax, minmax, ahk_id %hWnd%
    if (minmax != 0){
        WinRestore, ahk_id %hWnd%
        ; needSetTOPMOST := 1
    }
    ; ref: [SetWindowPos function (winuser.h) - Win32 apps | Microsoft Docs]( https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos )
    HWND_TOPMOST := -1
    HWND_BOTTOM := 1
    HWND_TOP := 0
    HWND_NOTOPMOST := -2
    SWP_NOACTIVATE := 0x0010
    SWP_ASYNCWINDOWPOS:= 0x4000
    SWP_NOZORDER := 0x0004
    SWP_NOMOVE := 0x0002
    SWP_NOSIZE := 0x0001
    ; 先置顶(否则会显示在最大化窗口的后面 -- 被挡住)
    if (Active){
        WinActivate ahk_id %hWnd%
    }
    if (zIndex){
        DllCall("SetWindowPos"
        , "UInt", hWnd ; handle
        , "UInt", zIndex ; z-index
        , "Int", x ;  x
        , "Int", y ; y
        , "Int", w ; width
        , "Int", h ; height
        , "UInt", SWP_NOACTIVATE) ; SWP_ASYNCWINDOWPOS
    } else {
        DllCall("SetWindowPos"
        , "UInt", hWnd ;handle
        , "UInt", 0 ; z-index
        , "Int", x
        , "Int", y
        , "Int", w
        , "Int", h
        , "UInt", SWP_NOZORDER | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS) ; SWP_ASYNCWINDOWPOS
    }
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。