Tri Monitor Switch

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Tri Monitor Switch

04 Mar 2017, 20:20

Hi AutoHotKey,

I was wanting some assistance in modifying the following dual monitor script to suit a tri monitor.

At present, I have three monitors with a 2560 x 1440 resolution.

Current State:
Given that a window is on the left monitor, when I press Control + Alt + 6, the active window switches to the middle monitor.
Given that a window is on the middle monitor, when I press Control + Alt + 4, the active window switches to the left monitor.

What I would like in my future state:
Given that a window is on the left monitor, when I press Control + Alt + 6, the active window switches to the middle monitor.
Given that a window is on the left monitor, when I press Control + Alt + 6 + 6, the active window switches to the right monitor.

Given that a window is on the middle monitor, when I press Control + Alt + 4, the active window switches to the left monitor.
Given that a window is on the middle monitor, when I press Control + Alt + 6, the active window switches to the right monitor.

Given that a window is on the right monitor, when I press Control + Alt + 4, the active window switches to the middle monitor.
Given that a window is on the right monitor, when I press Control + Alt + 4 + 4, the active window switches to the left monitor.

Any assistance would be greatly appreciated.

Thanks!

---

Code: Select all

SysGet, Mon1, Monitor, 1
SysGet, Mon2, Monitor, 2

^!Numpad4:: 
mousegetpos,,,windowtomove
gosub windowmove
return

^!Numpad6::
winget,windowtomove,id,A
gosub windowmove
return

windowmove:
if not mon2left

return

wingetpos,x1,y1,w1,h1,ahk_id %windowtomove%
winget,winstate,minmax,ahk_id %windowtomove%
m1:=(x1+w1/2>mon1left) and (x1+w1/2<mon1right) and (y1+h1/2>mon1top) and (y1+h1/2<mon1bottom) ? 1:2   ;works out if centre of window is on monitor 1 (m1=1) or monitor 2 (m1=2)
m2:=m1=1 ? 2:1  ;m2 is the monitor the window will be moved to
ratiox:=abs(mon%m1%right-mon%m1%left)-w1<5 ? 0:abs((x1-mon%m1%left)/(abs(mon%m1%right-mon%m1%left)-w1))  ;where the window fits on x axis
ratioy:=abs(mon%m1%bottom-mon%m1%top)-h1<5 ? 0:abs((y1-mon%m1%top)/(abs(mon%m1%bottom-mon%m1%top)-h1))   ;where the window fits on y axis
x2:=mon%m2%left+ratiox*(abs(mon%m2%right-mon%m2%left)-w1)   ;where the window will fit on x axis in normal situation
y2:=mon%m2%top+ratioy*(abs(mon%m2%bottom-mon%m2%top)-h1)
w2:=w1   
h2:=h1   ;width and height will stay the same when moving unless reason not to lower in script

if abs(mon%m1%right-mon%m1%left)-w1<5 or abs(mon%m2%right-mon%m2%left-w1)<5   ;if x axis takes up whole axis OR won't fit on new screen

   {
   x2:=mon%m2%left   
   w2:=abs(mon%m2%right-mon%m2%left)
   }

if abs(mon%m1%bottom-mon%m1%top)-h1<5 or abs(mon%m2%bottom-mon%m2%top)-h1<5

   {
   y2:=mon%m2%top
   h2:=abs(mon%m2%bottom-mon%m2%top)
   }

if winstate   ;move maximized window

   {
   winrestore,ahk_id %windowtomove%
   winmove,ahk_id %windowtomove%,,mon%m2%left,mon%m2%top
   winmaximize,ahk_id %windowtomove%
   }

else

   {
   if (x1<mon%m1%left)
      x2:=mon%m2%left   ;adjustments for windows that are not fully on the initial monitor (m1)
   if (x1+w1>mon%m1%right)
      x2:=mon%m2%right-w2
   if (y1<mon%m1%top)
      y2:=mon%m2%top
   if (y1+h1>mon%m1%bottom)
      y2:=mon%m2%bottom-h2
   winmove,ahk_id %windowtomove%,,x2,y2,w2,h2   ;move non-maximized window
   }

return
Last edited by mrdunu on 05 Mar 2017, 04:37, edited 1 time in total.
ManualColdLock
Posts: 175
Joined: 15 Dec 2016, 04:27

Re: Tri Monitor Switch

04 Mar 2017, 22:08

Please use code tags, it makes it much easier for the people trying to help you.
User avatar
boiler
Posts: 16960
Joined: 21 Dec 2014, 02:44

Re: Tri Monitor Switch

04 Mar 2017, 22:47

Basically you're saying that each time you press control+alt+4, move the active window one monitor to the left. Each time you press control+alt+6 move it one monitor the right. Is that correct? That's a lot easier to program than having to do nothing until you see if another 4 or 6 is coming before you do anything. Just move it one monitor over every time you press one of those.
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Re: Tri Monitor Switch

05 Mar 2017, 00:10

ManualColdLock wrote:Please use code tags, it makes it much easier for the people trying to help you.
Hi ManualColdLock,

Thanks for the reply.

I'm a little new to coding - are you able to advise how I go about in doing so?
boiler wrote:Basically you're saying that each time you press control+alt+4, move the active window one monitor to the left. Each time you press control+alt+6 move it one monitor the right. Is that correct? That's a lot easier to program than having to do nothing until you see if another 4 or 6 is coming before you do anything. Just move it one monitor over every time you press one of those.
Hi boiler,

Thanks for the reply.

Yes that's correct.
ManualColdLock
Posts: 175
Joined: 15 Dec 2016, 04:27

Re: Tri Monitor Switch

05 Mar 2017, 03:35

When you post code to the forum
select it all and click the code button above the message field
if you don't see the button you can click on "full editor and preview"

click preview to make sure it looks the way you want

will look like this:

Code: Select all

SysGet, Mon1, Monitor, 1
SysGet, Mon2, Monitor, 2

^!Numpad4:: 
mousegetpos,,,windowtomove
gosub windowmove
return

^!Numpad6::
winget,windowtomove,id,A
gosub windowmove
return

windowmove:
if not mon2left

return

wingetpos,x1,y1,w1,h1,ahk_id %windowtomove%
winget,winstate,minmax,ahk_id %windowtomove%
m1:=(x1+w1/2>mon1left) and (x1+w1/2<mon1right) and (y1+h1/2>mon1top) and (y1+h1/2<mon1bottom) ? 1:2 ;works out if centre of window is on monitor 1 (m1=1) or monitor 2 (m1=2)
m2:=m1=1 ? 2:1 ;m2 is the monitor the window will be moved to
ratiox:=abs(mon%m1%right-mon%m1%left)-w1<5 ? 0:abs((x1-mon%m1%left)/(abs(mon%m1%right-mon%m1%left)-w1)) ;where the window fits on x axis
ratioy:=abs(mon%m1%bottom-mon%m1%top)-h1<5 ? 0:abs((y1-mon%m1%top)/(abs(mon%m1%bottom-mon%m1%top)-h1)) ;where the window fits on y axis
x2:=mon%m2%left+ratiox*(abs(mon%m2%right-mon%m2%left)-w1) ;where the window will fit on x axis in normal situation
y2:=mon%m2%top+ratioy*(abs(mon%m2%bottom-mon%m2%top)-h1)
w2:=w1 
h2:=h1 ;width and height will stay the same when moving unless reason not to lower in script

if abs(mon%m1%right-mon%m1%left)-w1<5 or abs(mon%m2%right-mon%m2%left-w1)<5 ;if x axis takes up whole axis OR won't fit on new screen

{
x2:=mon%m2%left 
w2:=abs(mon%m2%right-mon%m2%left)
}

if abs(mon%m1%bottom-mon%m1%top)-h1<5 or abs(mon%m2%bottom-mon%m2%top)-h1<5

{
y2:=mon%m2%top
h2:=abs(mon%m2%bottom-mon%m2%top)
}

if winstate ;move maximized window

{
winrestore,ahk_id %windowtomove%
winmove,ahk_id %windowtomove%,,mon%m2%left,mon%m2%top
winmaximize,ahk_id %windowtomove%
}

else

{
if (x1<mon%m1%left)
x2:=mon%m2%left ;adjustments for windows that are not fully on the initial monitor (m1)
if (x1+w1>mon%m1%right)
x2:=mon%m2%right-w2
if (y1<mon%m1%top)
y2:=mon%m2%top
if (y1+h1>mon%m1%bottom)
y2:=mon%m2%bottom-h2
winmove,ahk_id %windowtomove%,,x2,y2,w2,h2 ;move non-maximized window
}

return
ManualColdLock
Posts: 175
Joined: 15 Dec 2016, 04:27

Re: Tri Monitor Switch

05 Mar 2017, 04:06

Here, this is a bit shorter. Feel free to modify it to suit your needs.

Code: Select all

SysGet, VirtualScreenX, 76  ; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 78 ; get full width
^!4:: ; move left
WinGetPos,cx,,,,A ; current x pos = cx
if (cx -2560 >= VirtualScreenX) ; we don't want to go too far left
	winmove,A,,% cx-2560 ; all the screens are the same width so just add or subtract 2560
return
^!6:: ; move right
WinGetPos,cx,,,,A
if (cx +2560 < VirtualScreenWidth)
	winmove,A,,% cx+2560
return
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Re: Tri Monitor Switch

05 Mar 2017, 04:50

ManualColdLock wrote:When you post code to the forum
select it all and click the code button above the message field
if you don't see the button you can click on "full editor and preview"

click preview to make sure it looks the way you want

will look like this:

Code: Select all

SysGet, Mon1, Monitor, 1
SysGet, Mon2, Monitor, 2

^!Numpad4:: 
mousegetpos,,,windowtomove
gosub windowmove
return

^!Numpad6::
winget,windowtomove,id,A
gosub windowmove
return

windowmove:
if not mon2left

return

wingetpos,x1,y1,w1,h1,ahk_id %windowtomove%
winget,winstate,minmax,ahk_id %windowtomove%
m1:=(x1+w1/2>mon1left) and (x1+w1/2<mon1right) and (y1+h1/2>mon1top) and (y1+h1/2<mon1bottom) ? 1:2 ;works out if centre of window is on monitor 1 (m1=1) or monitor 2 (m1=2)
m2:=m1=1 ? 2:1 ;m2 is the monitor the window will be moved to
ratiox:=abs(mon%m1%right-mon%m1%left)-w1<5 ? 0:abs((x1-mon%m1%left)/(abs(mon%m1%right-mon%m1%left)-w1)) ;where the window fits on x axis
ratioy:=abs(mon%m1%bottom-mon%m1%top)-h1<5 ? 0:abs((y1-mon%m1%top)/(abs(mon%m1%bottom-mon%m1%top)-h1)) ;where the window fits on y axis
x2:=mon%m2%left+ratiox*(abs(mon%m2%right-mon%m2%left)-w1) ;where the window will fit on x axis in normal situation
y2:=mon%m2%top+ratioy*(abs(mon%m2%bottom-mon%m2%top)-h1)
w2:=w1 
h2:=h1 ;width and height will stay the same when moving unless reason not to lower in script

if abs(mon%m1%right-mon%m1%left)-w1<5 or abs(mon%m2%right-mon%m2%left-w1)<5 ;if x axis takes up whole axis OR won't fit on new screen

{
x2:=mon%m2%left 
w2:=abs(mon%m2%right-mon%m2%left)
}

if abs(mon%m1%bottom-mon%m1%top)-h1<5 or abs(mon%m2%bottom-mon%m2%top)-h1<5

{
y2:=mon%m2%top
h2:=abs(mon%m2%bottom-mon%m2%top)
}

if winstate ;move maximized window

{
winrestore,ahk_id %windowtomove%
winmove,ahk_id %windowtomove%,,mon%m2%left,mon%m2%top
winmaximize,ahk_id %windowtomove%
}

else

{
if (x1<mon%m1%left)
x2:=mon%m2%left ;adjustments for windows that are not fully on the initial monitor (m1)
if (x1+w1>mon%m1%right)
x2:=mon%m2%right-w2
if (y1<mon%m1%top)
y2:=mon%m2%top
if (y1+h1>mon%m1%bottom)
y2:=mon%m2%bottom-h2
winmove,ahk_id %windowtomove%,,x2,y2,w2,h2 ;move non-maximized window
}

return
Resized! Thank you!

ManualColdLock wrote:Here, this is a bit shorter. Feel free to modify it to suit your needs.

Code: Select all

SysGet, VirtualScreenX, 76  ; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 78 ; get full width
^!4:: ; move left
WinGetPos,cx,,,,A ; current x pos = cx
if (cx -2560 >= VirtualScreenX) ; we don't want to go too far left
	winmove,A,,% cx-2560 ; all the screens are the same width so just add or subtract 2560
return
^!6:: ; move right
WinGetPos,cx,,,,A
if (cx +2560 < VirtualScreenWidth)
	winmove,A,,% cx+2560
return
Thanks for pulling together this script.

I've trialled it and have noted the following observations.

The following scenarios occur:

Given an active window on the left monitor:

Ctrl + Alt + 4 = Active window moves to the middle monitor (not expected result)
Ctrl + Alt + 4 + 4 = Active window moves to the middle monitor but the subsequent pressing of the 4 does nothing. (not expected result)
Ctrl + Alt + 6 = Active window moves to the middle monitor (expected result)
Ctrl + Alt + 6 + 6 = Active window returns back to the left monitor (not expected result)

Given an active window on the middle monitor:

Ctrl + Alt + 4 = Active window moves to the left monitor (expected result)
Ctrl + Alt + 4 + 4 = Active window remains to the left monitor (expected result)
Ctrl + Alt + 6 = Active window moves to the left monitor (not expected result)
Ctrl + Alt + 6 + 6 = Active window returns back to the middle monitor (not expected result)

Given an active window on the right monitor:

Ctrl + Alt + 4 = Active window moves to the left most monitor (not expected)
Ctrl + Alt + 4 + 4 = Active window moves to the middle monitor (not expected)
Ctrl + Alt + 6 = Active window moves to the left most monitor (not expected)
Ctrl + Alt + 6 + 6 = Active window moves to the middle monitor (not expected)
ManualColdLock
Posts: 175
Joined: 15 Dec 2016, 04:27

Re: Tri Monitor Switch

05 Mar 2017, 13:10

All what I wrote does is move the window left with Ctrl + Alt + 4 or right with Ctrl + Alt + 6
when boiler asked if that is what you are trying to do, you said yes.
You may have your monitors arranged differently than mine so it's difficult for me to further modify it for you
I wrote the script in relatively simple terms and left comments to show you what I did.
With a little work I'm sure you can get this to behave the way you want.
User avatar
boiler
Posts: 16960
Joined: 21 Dec 2014, 02:44

Re: Tri Monitor Switch

05 Mar 2017, 14:32

I suggest you run the following script and move your mouse pointer to the left edge of each monitor and tell us what value it shows for each one:

Code: Select all

CoordMode, Mouse, Screen
Loop
{
	MouseGetPos, ScrX
	ToolTip, % ScrX
	Sleep, 50
}
return

Esc::ExitApp
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Re: Tri Monitor Switch

05 Mar 2017, 15:13

ManualColdLock wrote:All what I wrote does is move the window left with Ctrl + Alt + 4 or right with Ctrl + Alt + 6
when boiler asked if that is what you are trying to do, you said yes.
You may have your monitors arranged differently than mine so it's difficult for me to further modify it for you
I wrote the script in relatively simple terms and left comments to show you what I did.
With a little work I'm sure you can get this to behave the way you want.
Thanks!

Having tweaked the script to look like the following, I get an error:

---------------------------
New AutoHotkey Script (2).ahk
---------------------------
Error: Parameter #2 invalid.

Specifically: 0; get coordinates of left most pixel

Line#
---> 001: SysGet,VirtualScreenX,0; get coordinates of left most pixel,sometimes negative depending on primary monitor

The program will exit.
---------------------------
OK
---------------------------

Code: Select all

SysGet, VirtualScreenX, 0; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 7679; get full width
^!4:: ; move left
WinGetPos,cx,,,,A ; current x pos = cx
if (cx -2560 >= VirtualScreenX) ; we don't want to go too far left
	winmove,A,,% cx-2560 ; all the screens are the same width so just add or subtract 2560
return
^!6:: ; move right
WinGetPos,cx,,,,A
if (cx +2560 < VirtualScreenWidth)
	winmove,A,,% cx+2560
return
boiler wrote:I suggest you run the following script and move your mouse pointer to the left edge of each monitor and tell us what value it shows for each one:

Code: Select all

CoordMode, Mouse, Screen
Loop
{
	MouseGetPos, ScrX
	ToolTip, % ScrX
	Sleep, 50
}
return

Esc::ExitApp
Thanks!

Left Monitor = 0
Middle Monitor = 2560 (without the taskbar) and 2690 with the taskbar (vertically)
Left Monitor = 5120 (without the taskbar) and 5251 with the taskbar (vertically)
User avatar
boiler
Posts: 16960
Joined: 21 Dec 2014, 02:44

Re: Tri Monitor Switch

05 Mar 2017, 16:01

The error is because there needs to be a space before a semicolon for it to be interpreted as a comment. So you need to add a space before the ;. Same on the next line.

But more importantly, your tweaks don't make sense even if you correct the comment syntax. What are you trying to accomplish by changing 76 and 78 to 0 and 7679? The numbers 76 and 78 mean specific things in the SysGet command. They are not coordinates or anything like that.

It looks like your coordinates for each monitor are as expected. Run the following script and show us what the output is:

Code: Select all

SysGet, VirtualScreenX, 76  ; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 78 ; get full width
MsgBox, % VirtualScreenX "`n" VirtualScreenWidth
By the way, you can remove the % signs in the WinMove commands in ManualColdLock's script. They are not necessary, but it probably is not causing a problem.
ManualColdLock
Posts: 175
Joined: 15 Dec 2016, 04:27

Re: Tri Monitor Switch

05 Mar 2017, 18:26

boiler wrote:By the way, you can remove the % signs in the WinMove commands in ManualColdLock's script. They are not necessary, but it probably is not causing a problem.
Gah! I can never remember where expressions are allowed so I always just explicitly force them when not passing as parameters.
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Re: Tri Monitor Switch

06 Mar 2017, 07:19

boiler wrote:The error is because there needs to be a space before a semicolon for it to be interpreted as a comment. So you need to add a space before the ;. Same on the next line.

But more importantly, your tweaks don't make sense even if you correct the comment syntax. What are you trying to accomplish by changing 76 and 78 to 0 and 7679? The numbers 76 and 78 mean specific things in the SysGet command. They are not coordinates or anything like that.

It looks like your coordinates for each monitor are as expected. Run the following script and show us what the output is:

Code: Select all

SysGet, VirtualScreenX, 76  ; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 78 ; get full width
MsgBox, % VirtualScreenX "`n" VirtualScreenWidth
By the way, you can remove the % signs in the WinMove commands in ManualColdLock's script. They are not necessary, but it probably is not causing a problem.
Interesting to know - didn't realise that SysGet would not recognise 7679 (that was the right most pixel).

In any case, the coordinates from the afforementioned script is 0, 7680.

Thanks!
User avatar
boiler
Posts: 16960
Joined: 21 Dec 2014, 02:44

Re: Tri Monitor Switch

14 Mar 2017, 05:48

I saw your PM asking for further help on this. Given the coordinates of your monitors that you reported, I do not see why this won't work. ManualColdLock wrote a nice, efficient script. I used this modification to test it on my single 2560-wide monitor. It moves it only 600 pixels at a time. And I changed it to use the left and right arrow keys. Try it out and see if it consistently moves the window to the left and right within a monitor and eventually crossing over to the other monitors as you press the arrow keys.

Code: Select all

SysGet, VirtualScreenX, 76  ; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 78 ; get full width
Left:: ; move left
WinGetPos,cx,,,,A ; current x pos = cx
if (cx -600 >= VirtualScreenX) ; we don't want to go too far left
	winmove,A,,cx-600 ; all the screens are the same width so just add or subtract 2560
return
Right:: ; move right
WinGetPos,cx,,,,A
if (cx +600 < VirtualScreenWidth)
	winmove,A,,cx+600
return
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Re: Tri Monitor Switch

16 Mar 2017, 15:04

boiler wrote:I saw your PM asking for further help on this. Given the coordinates of your monitors that you reported, I do not see why this won't work. ManualColdLock wrote a nice, efficient script. I used this modification to test it on my single 2560-wide monitor. It moves it only 600 pixels at a time. And I changed it to use the left and right arrow keys. Try it out and see if it consistently moves the window to the left and right within a monitor and eventually crossing over to the other monitors as you press the arrow keys.
Hi boiler,

Really appreciate your reply back.

This script works, but for some odd reason, it won't return back to its original position (i.e. when going left to right there is no issues, then when going back right to left to its original position, it looks like the original position is now updated to whatever the left most pixel is + 600 pixel to the right.

In addition, while it works for a notepad window that's maximised, it doesn't seem to work for a Google Chrome window that's maximised.
User avatar
boiler
Posts: 16960
Joined: 21 Dec 2014, 02:44

Re: Tri Monitor Switch

16 Mar 2017, 19:28

That's probably the whole issue right there. Maximized windows behave strangely sometimes. If you can make it a window that is the full screen by just dragging it to full screen size rather than actually maximize it, that could solve your issue.
mrdunu
Posts: 7
Joined: 04 Mar 2017, 20:07

Re: Tri Monitor Switch

17 Mar 2017, 16:47

boiler wrote:That's probably the whole issue right there. Maximized windows behave strangely sometimes. If you can make it a window that is the full screen by just dragging it to full screen size rather than actually maximize it, that could solve your issue.
I FOUND THE ISSUE!

In ManualCodeLock's script, they had used ^!4 and ^!6, whereas in my original script, it was ^!Numpad4 and ^!Numpad6!

I've now tweaked both of your scripts to include 2560 as the parameter, instead of 600 (as per the below), and the script functions as expected.

I wanted to say a BIG THANK YOU to both boiler and ManualCodeLock for helping me through this script - you both are what makes this community great!

Thank you again! :) :) :)

Code: Select all

SysGet, VirtualScreenX, 76  ; get coordinates of left most pixel, sometimes negative depending on primary monitor
SysGet, VirtualScreenWidth, 78 ; get full width

^!Numpad4:: ; move left
WinGetPos,cx,,,,A ; current x pos = cx
if (cx -2560 >= VirtualScreenX) ; we don't want to go too far left
	winmove,A,,cx-2560 ; all the screens are the same width so just add or subtract 2560
return

^!Numpad6:: ; move right
WinGetPos,cx,,,,A
if (cx +2560 < VirtualScreenWidth)
	winmove,A,,cx+2560
return
Last edited by mrdunu on 17 Mar 2017, 16:57, edited 1 time in total.
User avatar
boiler
Posts: 16960
Joined: 21 Dec 2014, 02:44

Re: Tri Monitor Switch

17 Mar 2017, 16:55

I don't know. I would suggest assigning some other action like a SoundBeep to those hotkeys and see if that works as expected. Maybe having alt held down is activating the menu shortcut keys on whatever window you are moving and it is somehow interfering.
ManualColdLock
Posts: 175
Joined: 15 Dec 2016, 04:27

Re: Tri Monitor Switch

17 Mar 2017, 23:48

Glad you got it working

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], mikeyww and 291 guests