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