Add support to move windows between monitors

This commit is contained in:
Fernando Schauenburg 2023-03-10 11:15:48 +01:00
parent 2f584d17d0
commit 4804b2f827

View file

@ -1,12 +1,23 @@
log(text) ; Returns the rectangle (position & size) of a given monitor.
MonitorGetRect(N)
{ {
FileAppend(text . "`n", "log.txt") MonitorGetWorkArea(N, &left, &top, &right, &bottom)
return {
pos: {
x: left,
y: top,
},
size: {
width: Abs(right - left),
height: Abs(bottom - top),
}
}
} }
; Return the number of the monitor that contains a window. ; Return the number of the monitor that contains a window.
getMonitor(winId:="A") WinGetMonitor(WinTitle:="A")
{ {
WinGetPos(&x,, &width,, winId) WinGetPos(&x,, &width,, WinTitle)
midx := x + width // 2 midx := x + width // 2
Loop MonitorGetCount() { Loop MonitorGetCount() {
@ -18,122 +29,123 @@ getMonitor(winId:="A")
return MonitorGetPrimary() ; fallback to primary if none found return MonitorGetPrimary() ; fallback to primary if none found
} }
; Returns the bound of the monitor that contains a window.
getMonitorBounds(winId:="A")
{
monitor := getMonitor(winId)
MonitorGetWorkArea(monitor, &left, &top, &right, &bottom)
return {
x : left,
y : top,
width : Abs(right - left),
height : Abs(bottom - top),
}
}
clamp(n, limit:=1)
{
n := Abs(n)
if (n > limit)
return Mod(n, limit)
return n
}
; Move and resize window to match spec (x, y, width, height).
positionWindow(spec, winId:="A")
{
xScale := clamp(spec.x)
yScale := clamp(spec.y)
wScale := clamp(spec.w)
hScale := clamp(spec.h)
monitor := getMonitorBounds(winId)
x := Round(monitor.x + xScale * monitor.width)
y := Round(monitor.y + yScale * monitor.height)
width := Round( wScale * monitor.width)
height := Round( hScale * monitor.height)
WinMove(x, y, width, height, winId)
}
; Center a window without changing its size. ; Center a window without changing its size.
centerWindow(winId:="A") WinCenter(WinTitle:="A")
{ {
WinGetPos(,, &width, &height, winId) WinGetPos(,, &width, &height, WinTitle)
r := MonitorGetRect(WinGetMonitor(WinTitle))
monitor := getMonitorBounds(winId) x := Round(r.pos.x + r.size.width/2 - width/2)
y := Round(r.pos.y + r.size.height/2 - height/2)
x := Round(monitor.x + monitor.width/2 - width/2) WinMove(x, y, width, height, WinTitle)
y := Round(monitor.y + monitor.height/2 - height/2)
WinMove(x, y, width, height, winId)
} }
; Move a window wihtou changing its size. ; Return the rect (in percentages) of a window in its current monitor.
moveWindow(dx, dy, winId:="A") WinGetRelativeRect(WinTitle:="A")
{ {
WinGetPos(&x, &y, &width, &height, winId) WinGetPos(&x, &y, &width, &height, WinTitle)
WinMove(x + dx, y + dy, width, height, winId) monitor := WinGetMonitor(WinTitle)
rect := MonitorGetRect(monitor)
return {
pos: {
x: Abs((x - rect.pos.x) / rect.size.width),
y: Abs((y - rect.pos.y) / rect.size.height),
},
size: {
width: width / rect.size.width,
height: height / rect.size.height,
}
}
} }
SPECS := { ; Move and resize window to a rect (in percentage) in a given monitor.
WinSetRelativeRect(winRect, monitor?, WinTitle:="A")
{
if not IsSet(monitor)
monitor := WinGetMonitor(WinTitle)
rect := MonitorGetRect(monitor)
x := Round(rect.pos.x + winRect.pos.x * rect.size.width)
y := Round(rect.pos.y + winRect.pos.y * rect.size.height)
width := Round( winRect.size.width * rect.size.width)
height := Round( winRect.size.height * rect.size.height)
WinMove(x, y, width, height, WinTitle)
}
; Move a window wihtout changing its size.
WinTranslate(dx, dy, WinTitle:="A")
{
WinGetPos(&x, &y, &width, &height, WinTitle)
WinMove(x + dx, y + dy, width, height, WinTitle)
}
; Move a window to a different monitor, ajusting the relative scaling.
WinSetMonitor(target, WinTitle:="A")
{
WinSetRelativeRect(WinGetRelativeRect(WinTitle), target, WinTitle)
}
POS := {
; 2x3 matrix ; 2x3 matrix
upperLeft : {x: 0, y: 0, w: 1/3, h: 1/2 }, upperLeft : {pos: {x: 0, y: 0}, size: {width: 1/3, height: 1/2 }},
upperMiddle : {x: 1/3, y: 0, w: 1/3, h: 1/2 }, upperMiddle : {pos: {x: 1/3, y: 0}, size: {width: 1/3, height: 1/2 }},
upperRight : {x: 2/3, y: 0, w: 1/3, h: 1/2 }, upperRight : {pos: {x: 2/3, y: 0}, size: {width: 1/3, height: 1/2 }},
lowerLeft : {x: 0, y: 1/2, w: 1/3, h: 1/2 }, lowerLeft : {pos: {x: 0, y: 1/2}, size: {width: 1/3, height: 1/2 }},
lowerMiddle : {x: 1/3, y: 1/2, w: 1/3, h: 1/2 }, lowerMiddle : {pos: {x: 1/3, y: 1/2}, size: {width: 1/3, height: 1/2 }},
lowerRight : {x: 2/3, y: 1/2, w: 1/3, h: 1/2 }, lowerRight : {pos: {x: 2/3, y: 1/2}, size: {width: 1/3, height: 1/2 }},
; full height thirds ; Full Height Thirds
thirdLeft : {x: 0, y: 0, w: 1/3, h: 1 }, thirdLeft : {pos: {x: 0, y: 0}, size: {width: 1/3, height: 1 }},
doubleLeft : {x: 0, y: 0, w: 2/3, h: 1 }, doubleLeft : {pos: {x: 0, y: 0}, size: {width: 2/3, height: 1 }},
thirdRight : {x: 2/3, y: 0, w: 1/3, h: 1 }, thirdRight : {pos: {x: 2/3, y: 0}, size: {width: 1/3, height: 1 }},
doubleRight : {x: 1/3, y: 0, w: 2/3, h: 1 }, doubleRight : {pos: {x: 1/3, y: 0}, size: {width: 2/3, height: 1 }},
; full height halves ; Full Height Halves
halfLeft : {x: 0, y: 0, w: 1/2, h: 1 }, halfLeft : {pos: {x: 0, y: 0}, size: {width: 1/2, height: 1 }},
halfRight : {x: 1/2, y: 0, w: 1/2, h: 1 }, halfRight : {pos: {x: 1/2, y: 0}, size: {width: 1/2, height: 1 }},
; center ; Center
mainFocus : {x: 0.18, y: 0, w: 0.64, h: 1 }, mainFocus : {pos: {x: 0.18, y: 0}, size: {width: 0.64, height: 1 }},
} }
^!r::Reload ^!r::Reload
; Make sure NumLock is active so that Numpad mappinfs below will work.
SetNumLockState True
; 2x3 matrix ; 2x3 matrix
!#Numpad7:: positionWindow(SPECS.upperLeft) !#Numpad7:: WinSetRelativeRect(POS.upperLeft)
!#NumpadDiv:: positionWindow(SPECS.upperMiddle) !#NumpadDiv:: WinSetRelativeRect(POS.upperMiddle)
!#Numpad8:: positionWindow(SPECS.upperMiddle) !#Numpad8:: WinSetRelativeRect(POS.upperMiddle)
!#Numpad9:: positionWindow(SPECS.upperRight) !#Numpad9:: WinSetRelativeRect(POS.upperRight)
!#Numpad1:: positionWindow(SPECS.lowerLeft) !#Numpad1:: WinSetRelativeRect(POS.lowerLeft)
!#NumpadSub:: positionWindow(SPECS.lowerMiddle) !#NumpadSub:: WinSetRelativeRect(POS.lowerMiddle)
!#Numpad2:: positionWindow(SPECS.lowerMiddle) !#Numpad2:: WinSetRelativeRect(POS.lowerMiddle)
!#Numpad3:: positionWindow(SPECS.lowerRight) !#Numpad3:: WinSetRelativeRect(POS.lowerRight)
; Full height thirds ; Full height thirds
!#Numpad4:: positionWindow(SPECS.thirdLeft) !#Numpad4:: WinSetRelativeRect(POS.thirdLeft)
!#NumpadMult:: positionWindow(SPECS.doubleLeft) !#NumpadMult:: WinSetRelativeRect(POS.doubleLeft)
!#Numpad5:: positionWindow(SPECS.doubleRight) !#Numpad5:: WinSetRelativeRect(POS.doubleRight)
!#Numpad6:: positionWindow(SPECS.thirdRight) !#Numpad6:: WinSetRelativeRect(POS.thirdRight)
; Full height halves ; Full height halves
!^Numpad1::positionWindow(SPECS.halfLeft) !^Numpad1:: WinSetRelativeRect(POS.halfLeft)
!^Numpad3::positionWindow(SPECS.halfRight) !^Numpad3:: WinSetRelativeRect(POS.halfRight)
; Center and... ; Center and...
!#NumpadAdd:: positionWindow(SPECS.mainFocus) ; ... resize to default. !#NumpadAdd:: WinSetRelativeRect(POS.mainFocus) ; ... resize to default.
!^Numpad5:: centerWindow() ; ... keep size. !^Numpad5:: WinCenter() ; ... keep size.
; Move to other monitor ; Move to other monitor (FIXME this is a hack, but works on my current setup)
; !^Left:: TODO move to other monitor !^Left:: WinSetMonitor(2)
; !^Right:: TODO move to other monitor !^Right:: WinSetMonitor(1)
; Move without resize ; Move without resize
step := 50 ; dx dy step := 50 ; dx dy
!^Numpad4:: moveWindow(-step, 0) ; left (H) !^Numpad4:: WinTranslate(-step, 0) ; left (H)
!^Numpad2:: moveWindow( 0, step) ; down (J) !^Numpad2:: WinTranslate( 0, step) ; down (J)
!^Numpad8:: moveWindow( 0, -step) ; up (K) !^Numpad8:: WinTranslate( 0, -step) ; up (K)
!^Numpad6:: moveWindow( step, 0) ; right (L) !^Numpad6:: WinTranslate( step, 0) ; right (L)