这段脚本实现了 对指定窗口的排列管理功能。其核心目的是对特定窗口(如资源管理器窗口)进行 平铺、堆叠或自定义排列,并根据屏幕或多显示器环境动态调整窗口的位置和大小。
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 } }
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)