Move active window to second monitor and back

Post your working scripts, libraries and tools for AHK v1.1 and older
XShayanX
Posts: 83
Joined: 16 Sep 2018, 04:48

Move active window to second monitor and back

22 May 2019, 15:55

Greetings,

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
Notes:
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!
XShayanX
Posts: 83
Joined: 16 Sep 2018, 04:48

Re: Move active window to second monitor and back

09 Jul 2019, 13:32

Version 1.1 This version has a bug! use the next post!

Changelog:
+Changed 80 to 82 for taskbar so to be more fail safe.
+Instead of top-left corner of the window, now the top-center is considered into calculations for a better experience.

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
MMWinGetX := MMWinGetX + (MMWinGetWidth / 2)
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 < 82) ;Check if window is going under taskbar and fixes it.
            MMWinMoveY -= 82
        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 < 82)
            MMWinMoveY -= 82
        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
Last edited by XShayanX on 26 Aug 2019, 14:48, edited 2 times in total.
XShayanX
Posts: 83
Joined: 16 Sep 2018, 04:48

Re: Move active window to second monitor and back

26 Aug 2019, 14:47

Version 1.1 + bug fixed

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
MMWinGetXMiddle := MMWinGetX + (MMWinGetWidth / 2)
MMDPISub := Abs(MMPrimDPI - MMSecDPI) + 1
;Second mon is off, window is lost, bring to primary
if ( (MMCount = 1) and !((MMWinGetXMiddle > MMPrimLRTBLeft + 20) and (MMWinGetXMiddle < 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 ( (MMWinGetXMiddle > MMPrimLRTBLeft - 20) and (MMWinGetXMiddle < 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 < 82) ;Check if window is going under taskbar and fixes it.
            MMWinMoveY -= 82
        MMWinMoveWidth := MMWinGetWidth * MMWidthRatio
        MMWinMoveHeight := MMWinGetHeight * MMHeightRatio
        WinMove, A,, MMWinMoveX, MMWinMoveY, MMWinMoveWidth, MMWinMoveHeight
        WinMove, A,, MMWinMoveX, MMWinMoveY, MMWinMoveWidth, MMWinMoveHeight
    }
} ;Secondary to primary
Else if ( (MMWinGetXMiddle > MMSecLRTBLeft - 20) and (MMWinGetXMiddle < 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 < 82)
            MMWinMoveY -= 82
        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
nou
Posts: 26
Joined: 24 Feb 2019, 21:21

Re: Move active window to second monitor and back

27 Aug 2019, 04:04

I believe you can do a quick screen-dpi scaling by doing something like this:

Code: Select all

scale := 96 / A_ScreenDPI
or was it...

Code: Select all

scale := A_ScreenDPI / 96
But yeah, point being: You can nab the screen's current DPI, and then do some division with the standard DPI scaling (96).

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: balawi28, gekunfei, Google [Bot], Rakkar and 70 guests