There are a few scripts around to move the active window to second monitor, but this script comes with other benefits.
Just be sure to change the values of MMPrimDPI and MMSecDPI variables to represent your monitors DPI scale values.
+ This script works with two monitors and with one hotkey cycles the Active window between them.
+ The resolutions of monitors are automatically calculated and along with DPI values will help move the window to the other monitor with relative size and position, for example if the window is on top right section of current monitor, it will be moved to top right section of second monitor even if resolutions or DPI values are different, the window won't go off out of the screen, unless it was actually out in the first place. If the resolution of second monitor is higher (or lower) than the current monitor or DPI values, it will change the size of the window relatively.
+ If second monitor was turned off and the window is lost somewhere, the hotkey will bring it to your primary monitor.
+ Every variable in this script is started with "MM" this is to prevent confusion with other variables in your script when debugging.
The hotkey is WinKey + backtick (also called grave key, the key bellow Esc key = `).
The keycode for backtick is SC029 as you see in the script.
Code: Select all
#SingleInstance Force
#SC029::
MMPrimDPI := 1.0 ;DPI Scale of the primary monitor (divided by 100).
MMSecDPI := 1.0 ;DPI Scale of the secondary monitor (divided by 100).
SysGet, MMCount, MonitorCount
SysGet, MMPrimary, MonitorPrimary
SysGet, MMPrimLRTB, Monitor, MMPrimary
WinGetPos, MMWinGetX, MMWinGetY, MMWinGetWidth, MMWinGetHeight, A
MMDPISub := Abs(MMPrimDPI - MMSecDPI) + 1
;Second mon is off, window is lost, bring to primary
if ( (MMCount = 1) and !((MMWinGetX > MMPrimLRTBLeft + 20) and (MMWinGetX < MMPrimLRTBRight - 20) and (MMWinGetY > MMPrimLRTBTop + 20) and (MMWinGetY < MMPrimLRTBBottom - 20)) ){
if ((MMPrimDPI - MMSecDPI) >= 0)
MMWHRatio := 1 / MMDPISub
Else
MMWHRatio := MMDPISub
MMWinMoveWidth := MMWinGetWidth * MMWHRatio
MMWinMoveHeight := MMWinGetHeight * MMWHRatio
WinMove, A,, 0, 0, MMWinMoveWidth, MMWinMoveHeight
WinMove, A,, 0, 0, MMWinMoveWidth, MMWinMoveHeight ;Fail safe
return
}
if (MMPrimary = 1)
SysGet, MMSecLRTB, Monitor, 2
Else
SysGet, MMSecLRTB, Monitor, 1
MMSecW := MMSecLRTBRight - MMSecLRTBLeft
MMSecH := MMSecLRTBBottom - MMSecLRTBTop
;Primary to secondary
if ( (MMWinGetX > MMPrimLRTBLeft - 20) and (MMWinGetX < MMPrimLRTBRight + 20) and (MMWinGetY > MMPrimLRTBTop - 20) and (MMWinGetY < MMPrimLRTBBottom + 20) ){
if ( (MMSecW) and (MMSecH) ){ ;Checks if sec mon exists. Could have used MMCount instead: if (MMCount >= 2){}
if ((MMSecDPI - MMPrimDPI) >= 0){
MMWidthRatio := (MMSecW / A_ScreenWidth) / MMDPISub
MMHeightRatio := (MMSecH / A_ScreenHeight) / MMDPISub
}
Else {
MMWidthRatio := (MMSecW / A_ScreenWidth) * MMDPISub
MMHeightRatio := (MMSecH / A_ScreenHeight) * MMDPISub
}
MMWinMoveX := (MMWinGetX * MMWidthRatio) + MMSecLRTBLeft
MMWinMoveY := (MMWinGetY * MMHeightRatio) + MMSecLRTBTop
if (MMSecLRTBBottom - MMWinMoveY < 80) ;Check if window is going under taskbar and fixes it.
MMWinMoveY -= 80
MMWinMoveWidth := MMWinGetWidth * MMWidthRatio
MMWinMoveHeight := MMWinGetHeight * MMHeightRatio
WinMove, A,, MMWinMoveX, MMWinMoveY, MMWinMoveWidth, MMWinMoveHeight
WinMove, A,, MMWinMoveX, MMWinMoveY, MMWinMoveWidth, MMWinMoveHeight
}
} ;Secondary to primary
Else if ( (MMWinGetX > MMSecLRTBLeft - 20) and (MMWinGetX < MMSecLRTBRight + 20) and (MMWinGetY > MMSecLRTBTop - 20) and (MMWinGetY < MMSecLRTBBottom + 20) ){
if ( (MMSecW) and (MMSecH) ){
if ((MMPrimDPI - MMSecDPI) >= 0){
MMWidthRatio := (A_ScreenWidth / MMSecW) / MMDPISub
MMHeightRatio := (A_ScreenHeight / MMSecH) / MMDPISub
}
Else{
MMWidthRatio := (A_ScreenWidth / MMSecW) * MMDPISub
MMHeightRatio := (A_ScreenHeight / MMSecH) * MMDPISub
}
MMWinMoveX := (MMWinGetX - MMSecLRTBLeft) * MMWidthRatio
MMWinMoveY := (MMWinGetY - MMSecLRTBTop) * MMHeightRatio
if (MMPrimLRTBBottom - MMWinMoveY < 80)
MMWinMoveY -= 80
MMWinMoveWidth := MMWinGetWidth * MMWidthRatio
MMWinMoveHeight := MMWinGetHeight * MMHeightRatio
WinMove, A,, MMWinMoveX, MMWinMoveY, MMWinMoveWidth, MMWinMoveHeight
WinMove, A,, MMWinMoveX, MMWinMoveY, MMWinMoveWidth, MMWinMoveHeight
}
} ;If window is out of current monitors' boundaries or if script fails
Else{
MsgBox, 4, MM, % "Current window is in " MMWinGetX " " MMWinGetY "`nDo you want to move it to 0,0?"
IfMsgBox Yes
WinMove, A,, 0, 0
}
return
Sometimes WinMove, moves the window but fails to change the size of window, that's why you see duplicates of WinMove command in the script, it's to make AHK try again and fix the size, this works.
There was no automatic way to import each monitor's DPI scale values, the DPI scale for each monitor is recorded in Registry but the keys for each monitor are UIDs, there's no way to figure out which UID represents which monitor identifier (number, e.g. 1,2,3).
I wrote this script in 2 days and tested it with different settings, everything works well, but be sure to report bugs!
Know how to make it better? Know a way to make the script import DPI values for each monitor automatically? Have any suggestions? Please comment below!