确定 window 在哪个屏幕上(通过检查最大表面积所在的位置)
Determining which screen a window is on (by checking where the most surfacearea is located)
我目前正在确定 window 在哪个屏幕上,方法是检查它位于哪个屏幕的最左上角位置。现在我想改变它,这样我就可以找出在哪个屏幕上可以找到 window 的最大表面积。
有什么想法可以实现吗?
这是我的旧代码:
(它只是在按 F1 时在所有可用屏幕之间移动活动 window)
F1::
WinGetPos, X, Y,,, A
window := {x:X,y:Y}
monitors := GetMonitors()
Loop % monitors.MaxIndex() {
curMonitor := monitors[A_Index]
If IsPointInRectange(window,curMonitor) {
nextMonitorIndex := (A_Index = monitors.MaxIndex() ? 1 : A_Index+1)
nextMonitor := monitors[nextMonitorIndex]
percPos := {}
percPos.x := (window.x-curMonitor.x1)/(curMonitor.x2-curMonitor.x1)
percPos.y := (window.y-curMonitor.y1)/(curMonitor.y2-curMonitor.y1)
windowNew := {}
windowNew.x := nextMonitor.x1+(nextMonitor.x2-nextMonitor.x1)*percPos.x
windowNew.y := nextMonitor.y1+(nextMonitor.y2-nextMonitor.y1)*percPos.y
WinMove, A,, windowNew.x, windowNew.y
}
}
Return
IsPointInRectange(point,rect) {
If point.x >= rect.x1 && point.x < rect.x2
&& point.y >= rect.y1 && point.y < rect.y2
Return True
}
GetMonitors() {
monitors := []
SysGet, monCount, 80 ;SM_CMONITORS
Loop % monCount {
SysGet, mon, Monitor, %A_Index%
monitors[A_Index] := {x1: monLeft, x2: monRight, y1: monTop, y2: monBottom}
}
Return monitors
}
MonitorFromWindow() 是解决方案。 :)
这是新代码:
;Win+Enter to move the active window to the next screen
#Enter::
WinGet, activeWindowHwnd, ID, A
activeMonitorHwnd := MDMF_FromHWND(activeWindowHwnd)
monitors := MDMF_Enum()
monitorHwndList := []
For currentMonitorHwnd, info In monitors
monitorHwndList[A_Index] := currentMonitorHwnd
nextMonitorHwnd := ""
For currentMonitorHwnd, info In monitors
If (currentMonitorHwnd = activeMonitorHwnd)
nextMonitorHwnd := (A_Index=monitorHwndList.MaxIndex() ? monitorHwndList[1] : monitorHwndList[A_Index+1])
activeMonitor := MDMF_GetInfo(activeMonitorHwnd)
nextMonitor := MDMF_GetInfo(nextMonitorHwnd)
WinGetPos, x, y, w, h, ahk_id %activeWindowHwnd%
activeWindow := {Left:x, Top:y, Right:x+w, Bottom:y+h}
relativePercPos := {}
relativePercPos.Left := (activeWindow.Left-activeMonitor.Left)/(activeMonitor.Right-activeMonitor.Left)
relativePercPos.Top := (activeWindow.Top-activeMonitor.Top)/(activeMonitor.Bottom-activeMonitor.Top)
relativePercPos.Right := (activeWindow.Right-activeMonitor.Left)/(activeMonitor.Right-activeMonitor.Left)
relativePercPos.Bottom := (activeWindow.Bottom-activeMonitor.Top)/(activeMonitor.Bottom-activeMonitor.Top)
;MsgBox % activeWindow.Top "`n" activeWindow.Left " - " activeWindow.Right "`n" activeWindow.Bottom
;MsgBox % relativePercPos.Top*100 "`n" relativePercPos.Left*100 " - " relativePercPos.Right*100 "`n" relativePercPos.Bottom*100
activeWindowNewPos := {}
activeWindowNewPos.Left := nextMonitor.Left+(nextMonitor.Right-nextMonitor.Left)*relativePercPos.Left
activeWindowNewPos.Top := nextMonitor.Top+(nextMonitor.Bottom-nextMonitor.Top)*relativePercPos.Top
WinMove, A,, activeWindowNewPos.Left, activeWindowNewPos.Top
Return
;Credits to "just me" for the following code:
; ======================================================================================================================
; Multiple Display Monitors Functions -> msdn.microsoft.com/en-us/library/dd145072(v=vs.85).aspx =======================
; ======================================================================================================================
; 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 the display monitor that has the largest area of intersection with a specified rectangle.
; Parameters are consistent with the common AHK definition of a rectangle, which is X, Y, W, H instead of
; 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+)$", "")
Return {Name: (Name := StrGet(&MIEX + 40, 32))
, Num: RegExReplace(Name, ".*(\d+)$", "")
, Left: NumGet(MIEX, 4, "Int") ; display rectangle
, Top: NumGet(MIEX, 8, "Int") ; "
, Right: NumGet(MIEX, 12, "Int") ; "
, Bottom: NumGet(MIEX, 16, "Int") ; "
, 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
}
我目前正在确定 window 在哪个屏幕上,方法是检查它位于哪个屏幕的最左上角位置。现在我想改变它,这样我就可以找出在哪个屏幕上可以找到 window 的最大表面积。
有什么想法可以实现吗?
这是我的旧代码: (它只是在按 F1 时在所有可用屏幕之间移动活动 window)
F1::
WinGetPos, X, Y,,, A
window := {x:X,y:Y}
monitors := GetMonitors()
Loop % monitors.MaxIndex() {
curMonitor := monitors[A_Index]
If IsPointInRectange(window,curMonitor) {
nextMonitorIndex := (A_Index = monitors.MaxIndex() ? 1 : A_Index+1)
nextMonitor := monitors[nextMonitorIndex]
percPos := {}
percPos.x := (window.x-curMonitor.x1)/(curMonitor.x2-curMonitor.x1)
percPos.y := (window.y-curMonitor.y1)/(curMonitor.y2-curMonitor.y1)
windowNew := {}
windowNew.x := nextMonitor.x1+(nextMonitor.x2-nextMonitor.x1)*percPos.x
windowNew.y := nextMonitor.y1+(nextMonitor.y2-nextMonitor.y1)*percPos.y
WinMove, A,, windowNew.x, windowNew.y
}
}
Return
IsPointInRectange(point,rect) {
If point.x >= rect.x1 && point.x < rect.x2
&& point.y >= rect.y1 && point.y < rect.y2
Return True
}
GetMonitors() {
monitors := []
SysGet, monCount, 80 ;SM_CMONITORS
Loop % monCount {
SysGet, mon, Monitor, %A_Index%
monitors[A_Index] := {x1: monLeft, x2: monRight, y1: monTop, y2: monBottom}
}
Return monitors
}
MonitorFromWindow() 是解决方案。 :) 这是新代码:
;Win+Enter to move the active window to the next screen
#Enter::
WinGet, activeWindowHwnd, ID, A
activeMonitorHwnd := MDMF_FromHWND(activeWindowHwnd)
monitors := MDMF_Enum()
monitorHwndList := []
For currentMonitorHwnd, info In monitors
monitorHwndList[A_Index] := currentMonitorHwnd
nextMonitorHwnd := ""
For currentMonitorHwnd, info In monitors
If (currentMonitorHwnd = activeMonitorHwnd)
nextMonitorHwnd := (A_Index=monitorHwndList.MaxIndex() ? monitorHwndList[1] : monitorHwndList[A_Index+1])
activeMonitor := MDMF_GetInfo(activeMonitorHwnd)
nextMonitor := MDMF_GetInfo(nextMonitorHwnd)
WinGetPos, x, y, w, h, ahk_id %activeWindowHwnd%
activeWindow := {Left:x, Top:y, Right:x+w, Bottom:y+h}
relativePercPos := {}
relativePercPos.Left := (activeWindow.Left-activeMonitor.Left)/(activeMonitor.Right-activeMonitor.Left)
relativePercPos.Top := (activeWindow.Top-activeMonitor.Top)/(activeMonitor.Bottom-activeMonitor.Top)
relativePercPos.Right := (activeWindow.Right-activeMonitor.Left)/(activeMonitor.Right-activeMonitor.Left)
relativePercPos.Bottom := (activeWindow.Bottom-activeMonitor.Top)/(activeMonitor.Bottom-activeMonitor.Top)
;MsgBox % activeWindow.Top "`n" activeWindow.Left " - " activeWindow.Right "`n" activeWindow.Bottom
;MsgBox % relativePercPos.Top*100 "`n" relativePercPos.Left*100 " - " relativePercPos.Right*100 "`n" relativePercPos.Bottom*100
activeWindowNewPos := {}
activeWindowNewPos.Left := nextMonitor.Left+(nextMonitor.Right-nextMonitor.Left)*relativePercPos.Left
activeWindowNewPos.Top := nextMonitor.Top+(nextMonitor.Bottom-nextMonitor.Top)*relativePercPos.Top
WinMove, A,, activeWindowNewPos.Left, activeWindowNewPos.Top
Return
;Credits to "just me" for the following code:
; ======================================================================================================================
; Multiple Display Monitors Functions -> msdn.microsoft.com/en-us/library/dd145072(v=vs.85).aspx =======================
; ======================================================================================================================
; 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 the display monitor that has the largest area of intersection with a specified rectangle.
; Parameters are consistent with the common AHK definition of a rectangle, which is X, Y, W, H instead of
; 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+)$", "")
Return {Name: (Name := StrGet(&MIEX + 40, 32))
, Num: RegExReplace(Name, ".*(\d+)$", "")
, Left: NumGet(MIEX, 4, "Int") ; display rectangle
, Top: NumGet(MIEX, 8, "Int") ; "
, Right: NumGet(MIEX, 12, "Int") ; "
, Bottom: NumGet(MIEX, 16, "Int") ; "
, 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
}