Automatic Mapping of All Monitors, Move & Resize Windows

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 03 Oct 2019, 20:15

I tried to make a fully functional Script that Works automatically on any System with any number of Monitors and any Monitor Configuration.

This Script should automatically Map Out your Monitor Configuration, regardless of:
  • Number of Monitors
  • Resolution of Monitors
  • Monitor Layout (Positioning)
  • Monitor Numbering (the Numbering Windows assigns to Monitors)
Known Limitations:
  • If the Zoom setting of Monitors are not all the same, this Script will do wonky things
  • If a Window is Maximized, then moved to another Monitor and "UnMaximized" (Restored) by double clicking on the Titlebar, the Window will appear in the First initial Monitor.
Main Functions:
  • Resize Active Window to Left and Right Half of Current Monitor
  • When Active Window is already resized to Left or Right Half of Monitor, move Active Window the next Monitor over
  • Move Active Window to Previous or Next Monitor
  • Move Active Window to Upper or Lower Monitor (When Monitors are stacked up, when there are multiple Rows of Monitors)
  • Resize Active Window to any one of the 4 Quadrants of Current Monitor
  • When Active Window is already resized in a Quadrant of Monitor, move Active Window the next Upper / Lower Quadrant of Monitor
Minor Functions:
  • Maximize Active Window
  • Minimize Active Window
  • Quick Minimize Window under Mouse Cursor (Activates Window before Minimizing)
  • Quick Close Window under Mouse Cursor (Activates Window before Minimizing)
Features:
  • When resizing Active Window to Left or Right Half of the Monitor, the Script will take into consideration the Taskbar and Resize the Active Window accordingly.
  • If the Active Window is at Full Height on Current Monitor, when moving it to another Monitor, it will stay at Full Height, regardless of Monitor Resolution or Work Area.
  • If there are Multiple Monitor Rows, when Moving the Active Window to Left or Right Monitor past the First or Last Monitor, the Active Window will wrap around to the Next or Previous Row of Monitors (Next Upper or Lower Row).
  • When Moving Active Window Up or Down, past the Top or Lowest Monitors, the Active Window will wrap around, staying in the same Column.
  • If there are gaps in Rows or Columns of Monitors, the Script will skip the gaps and continue to the Next Monitor of the same Row / Column.
  • There are options to Resize specific Programs to 3/4 of the height instead of Full Height of Side of Monitor (E.g. Skype, Calculator, etc.)
Notes:
  • The Monitors must be perfectly Aligned. In my experience, Windows 10 tends to add small misalignments. I use DisplayFusion to align my Monitors, it’s really great.
  • By default, to constitute a Row, the Monitors should be aligned with their Top Boundaries. If your Monitors don't all have the same resolution, and your Monitors are aligned with their Bottom Boundaries, the Lines of Code to change are indicated in the Script “Option ➔ Bottom of Row Alignment”.
  • Automatic Mapping of your Monitor Configuration is done on Script Startup. If you change your Monitor Configuration, you must restart the Script for the Script to work properly.
    • I could have made the script to retrieve all the variables on a HotKey Keypress (Number of Monitors, Monitor Dimensions, Monitor Positioning, etc.) but I figured loading all the variables on script start would speed up execution and eliminate unnecessary CPU use.
  • Moving a Maximized Window to another Monitor does not Resize the Active Window to take into account the Taskbar. I chose not to Restore the Active Window before moving it because that produces a very slow and clunky Move.
  • There are two Mapping procedures in the Script: One for Horizontal Movement and One for Vertical Movement. I chose two different processes for each.
    • Horizontal Movement is Mapped with 1D Arrays and Monitors are retrieved by a Sequential Number. Monitors are Organized and Numbered from First to Last, from Left to Right continuously through every Row.
    • Vertical Movement is Mapped with 2D Arrays and Monitors are retrieved by Column and Row Number. The Monitors are Organized and Numbered from First to Last, from Top to Bottom, in each distinct Column.
    • I could have used only one process, using only 2D Arrays to retrieve Monitors by Column and Row Number. I started off with 1D Arrays and realized I couldn’t pull off Vertical Movement without 2D Arrays, then went on to integrate 3D Arrays for Quadrant Movement.
AutoHotkey being fully free, I figured this would be a good way to give back :)

Also, I’m not a Programmer by trade, the Code can be more efficient of course. Some Feedback that was received on the code was: "Good Lord, I know everyone's first script is bad". Lol, all things considered, I think it's useful feedback. The point is, the code works! :D. I'm open to any feedback for improvements. One obvious item of improvement is implementing Object oriented programming, which I still have to learn.

Hope you Enjoy the Script!
Cheers!


Code: Select all

; *********************************************************************************
; 		Automatic Mapping of All Monitors, Move & Resize Windows  -START-
; *********************************************************************************

; Initialization of Arrays used
; Variables used for Temporary Monitor Number used to later organize Monitors in Ascending Order
; (1D Arrays)
MonTopTemp := []
MonBtmTemp := []
MonLftTemp := []
MonRgtTemp := []

; Variables used for Definitive Monitor Number in Ascending Order
; (1D Arrays)
MonTop := []
MonBtm := []
MonLft := []
MonRgt := []

; Variables used for Monitor Dimensions for Resizing to Half or Monitor and for Moving to another Monitor
; (1D Arrays)
MonHlfLft := []
MonHlfRgt := []
MonWdt := []
MonHlfWdt := []
MonHgt := []

; Variables of Definitive Monitor Number used to Move Windows Up and Down between Rows
; (2D Arrays)
MtxTop := []
MtxBtm := []
MtxLft := []
MtxRgt := []
MtxWdt := []
MtxHgt := []
MtxLstRow := []
MtxRowQty := []
Col_RowQty := []

; Variables used for Monitor Dimensions for Resizing to Quadrant of Monitor per Monitor Number
; (2D Arrays)
MonQdrTop := []
MonQdrLft := []
MonQdrBtm := []
MonQdrRgt := []
MonQdrWdt := []
MonQdrHgt := []

; Variables used for Monitor Dimensions for Resizing to Quadrant of Monitor per Column
; (3D Arrays)
MtxQdrTop := []
MtxQdrLft := []
MtxQdrBtm := []
MtxQdrRgt := []
MtxQdrWdt := []
MtxQdrHgt := []


; Variables used for Row Alignment with Bottom of Monitors
MonDIMBtmT := []

; Retrieve the Quantity of Monitors connected to system
SysGet, MonQty, MonitorCount

; Retrieve Coordinates and Dimensions of each Monitor
Loop, %MonQty%
{
	SysGet, MonWRKA, MonitorWorkArea, %A_Index%
	SysGet, MonDIM, Monitor, %A_Index%

	MonTopTemp[A_Index] := MonWRKATop
	MonBtmTemp[A_Index] := MonWRKABottom
	MonLftTemp[A_Index] := MonWRKALeft
	MonRgtTemp[A_Index] := MonWRKARight

	RowCntTemp = %RowCntTemp%, %MonWRKATop%
	ColCntTemp = %ColCntTemp%, %MonWRKALeft%

	; Variables used for Row Alignment with Bottom of Monitors
	; Options to Define Rows with Bottom of Monitors are Indicated Further in the Script
	MonDIMBtmT[A_Index] := MonDIMBottom
	RowCntBtmT = %RowCntBtmT%, %MonDIMBottom%
}

; Trim the first character (a comma ",") 
StringTrimLeft, RowCnt, RowCntTemp, 1
StringTrimLeft, ColCnt, ColCntTemp, 1
; Bottom of Row Alignment
StringTrimLeft, RowBtmCnt, RowCntBtmT, 1

; List out each unique value of Row and Column, defining boundaries
Sort RowCnt, N U D,
Sort ColCnt, N U D,
; Bottom of Row Alignment
Sort RowBtmCnt, N U D,

; Count the number of Rows and Columns
Loop, Parse, RowCnt, `,
{
	RowQty := A_Index
}
Loop, Parse, ColCnt, `,
{
	ColQty := A_Index
}
; Bottom of Row Alignment
Loop, Parse, RowBtmCnt, `,
{
	RowBtmQty := A_Index
}

; Separates each value of Row and Column into an Array Variable
RowValues := StrSplit(RowCnt, ",", " ")
ColValues := StrSplit(ColCnt, ",", " ")
; Bottom of Row Alignment
RowBtmValues := StrSplit(RowBtmCnt, ",", " ")

; ***** Monitor Mapping Initialization *****
; After counting how many Rows and Columns there are, the script will verify if
; there is a Monitor in each of the Rows/Columns Positions. If there is a gap
; (no Monitor in a Row/Column), the Space should not register in the Mapping

; Counter to Assign Monitor Number, from Top Left to Bottom Right
MonOrdr := 1

Loop, %RowQty%
; ******************************************************************
; Option ➔ Bottom of Row Alignment / Put in Comments the Line above
; Loop, %RowBtmQty%
; ******************************************************************
{
	; Keep the current Row in Memory
	RowPosA_Index := A_Index
	
	Loop, %ColQty%
	{
		; Keep the current Column in Memory
		ColPosA_Index := A_Index
		
		Loop, %MonQty%
		{
			; Keep the current Monitor Number in Memory
			MonNrA_Index := A_Index
			
			If (ColValues[ColPosA_Index] == MonLftTemp[MonNrA_Index] AND RowValues[RowPosA_Index] == MonTopTemp[MonNrA_Index])
			; *********************************************************************************************************************
			; Option ➔ Bottom of Row Alignment / Put in Comments the Line above
			; If (ColValues[ColPosA_Index] == MonLftTemp[MonNrA_Index] AND RowBtmValues[RowPosA_Index] == MonDIMBtmT[MonNrA_Index])
			; *********************************************************************************************************************
			{
				; Assign COORDINATES and DIMENSIONS of Monitors in Order, per MONITOR NUMBER, from Top Left to Bottom Right
				MonTop[MonOrdr] := MonTopTemp[MonNrA_Index]
				MonLft[MonOrdr] := MonLftTemp[MonNrA_Index]
				MonBtm[MonOrdr] := MonBtmTemp[MonNrA_Index]
				MonRgt[MonOrdr] := MonRgtTemp[MonNrA_Index]

				; Calculate COORDINATES and DIMENSIONS, per MONITOR NUMBER, to move Window to HALF OF MONITOR and to Another Monitor
				MonHlfLft[MonOrdr] := MonLft[MonOrdr]
				MonHlfRgt[MonOrdr] := Floor((MonLft[MonOrdr] + MonRgt[MonOrdr]) / 2)
				MonWdt[MonOrdr] := MonRgt[MonOrdr] - MonLft[MonOrdr]
				MonHlfWdt[MonOrdr] := Floor((MonRgt[MonOrdr] - MonLft[MonOrdr]) / 2)
				MonHgt[MonOrdr] := MonBtm[MonOrdr] - MonTop[MonOrdr]


				; ***** For Each Monitor Found, Assign Coordinates and Dimensions to 4 Quadrants *****
				; Quadrant Q1 of Current Monitor: TOP LEFT
				MonQdrTop[MonOrdr, 1] := MonTopTemp[MonNrA_Index]
				MonQdrLft[MonOrdr, 1] := MonLftTemp[MonNrA_Index]
				MonQdrBtm[MonOrdr, 1] := Floor(MonBtmTemp[MonNrA_Index] / 2)
				MonQdrRgt[MonOrdr, 1] := Floor(MonRgtTemp[MonNrA_Index] / 2)
				MonQdrWdt[MonOrdr, 1] := Floor((MonRgtTemp[MonNrA_Index] - MonLftTemp[MonNrA_Index]) / 2)
				MonQdrHgt[MonOrdr, 1] := Floor((MonBtmTemp[MonNrA_Index] - MonTopTemp[MonNrA_Index]) / 2)

				; Quadrant Q2 of Current Monitor: BOTTOM LEFT
				MonQdrTop[MonOrdr, 2] := Floor(MonTopTemp[MonNrA_Index] + (MonBtmTemp[MonNrA_Index] - MonTopTemp[MonNrA_Index]) / 2)
				MonQdrLft[MonOrdr, 2] := MonLftTemp[MonNrA_Index]
				MonQdrBtm[MonOrdr, 2] := MonBtmTemp[MonNrA_Index]
				MonQdrRgt[MonOrdr, 2] := Floor(MonRgtTemp[MonNrA_Index] / 2)
				MonQdrWdt[MonOrdr, 2] := Floor((MonRgtTemp[MonNrA_Index] - MonLftTemp[MonNrA_Index]) / 2)
				MonQdrHgt[MonOrdr, 2] := Floor((MonBtmTemp[MonNrA_Index] - MonTopTemp[MonNrA_Index]) / 2)

				; Quadrant Q3 of Current Monitor: TOP RIGHT
				MonQdrTop[MonOrdr, 3] := MonTopTemp[MonNrA_Index]
				MonQdrLft[MonOrdr, 3] := Floor(MonLftTemp[MonNrA_Index] + (MonRgtTemp[MonNrA_Index] - MonLftTemp[MonNrA_Index]) / 2)
				MonQdrBtm[MonOrdr, 3] := Floor(MonBtmTemp[MonNrA_Index] / 2)
				MonQdrRgt[MonOrdr, 3] := MonRgtTemp[MonNrA_Index]
				MonQdrWdt[MonOrdr, 3] := Floor((MonRgtTemp[MonNrA_Index] - MonLftTemp[MonNrA_Index]) / 2)
				MonQdrHgt[MonOrdr, 3] := Floor((MonBtmTemp[MonNrA_Index] - MonTopTemp[MonNrA_Index]) / 2)

				; Quadrant Q4 of Current Monitor: BOTTOM RIGHT
				MonQdrTop[MonOrdr, 4] := Floor(MonTopTemp[MonNrA_Index] + (MonBtmTemp[MonNrA_Index] - MonTopTemp[MonNrA_Index]) / 2)
				MonQdrLft[MonOrdr, 4] := Floor(MonLftTemp[MonNrA_Index] + (MonRgtTemp[MonNrA_Index] - MonLftTemp[MonNrA_Index]) / 2)
				MonQdrBtm[MonOrdr, 4] := MonBtmTemp[MonNrA_Index]
				MonQdrRgt[MonOrdr, 4] := MonRgtTemp[MonNrA_Index]
				MonQdrWdt[MonOrdr, 4] := Floor((MonRgtTemp[MonNrA_Index] - MonLftTemp[MonNrA_Index]) / 2)
				MonQdrHgt[MonOrdr, 4] := Floor((MonBtmTemp[MonNrA_Index] - MonTopTemp[MonNrA_Index]) / 2)
				; **************************************************************************** 


				; When a Monitor is found at this ROW and COLUMN Position, increment Count for Next Monitor
				MonOrdr += 1
				; Once Matching Monitor Found, Skip to Next Column
				Break
			}
		}
	}
}

; ***** Monitor Mapping Initialization *****
; This part of the Script will Organize Monitors in Order, from Top to Bottom
Loop, %ColQty%
{
	ColPosA_Index := A_Index
	; On every new Column, Start Counting Rows at 1
	VrtMonOrdr := 1
	Loop, %RowQty%
	; ******************************************************************
	; Option ➔ Bottom of Row Alignment / Put in Comments the Line above
	; Loop, %RowBtmQty%
	; ******************************************************************
	{
		RowPosA_Index := A_Index
		Loop, %MonQty%
		{
			VrtMonNrA_Index := A_Index
			If (ColValues[ColPosA_Index] == MonLftTemp[VrtMonNrA_Index] AND RowValues[RowPosA_Index] == MonTopTemp[VrtMonNrA_Index])
			; ***************************************************************************************************************************
			; Option ➔ Bottom of Row Alignment / Put in Comments the Line above
			; If (ColValues[ColPosA_Index] == MonLftTemp[VrtMonNrA_Index] AND RowBtmValues[RowPosA_Index] == MonDIMBtmT[VrtMonNrA_Index])
			; ***************************************************************************************************************************
			{
				; Assign COORDINATES and DIMENSIONS of Monitors in Order, per ROW and COLUMN COLUMN (MATRIX), from Top to Bottom for each Column
				MtxTop[VrtMonOrdr, ColPosA_Index] := MonTopTemp[VrtMonNrA_Index]
				MtxLft[VrtMonOrdr, ColPosA_Index] := MonLftTemp[VrtMonNrA_Index]
				MtxBtm[VrtMonOrdr, ColPosA_Index] := MonBtmTemp[VrtMonNrA_Index]
				MtxRgt[VrtMonOrdr, ColPosA_Index] := MonRgtTemp[VrtMonNrA_Index]
				
				; Calculate COORDINATES and DIMENSIONS, per ROW and COLUMN COLUMN (MATRIX), to move Window to Another Monitor
				MtxWdt[VrtMonOrdr, ColPosA_Index] := MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]
				MtxHgt[VrtMonOrdr, ColPosA_Index] := MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]
				

				; ***** For Each Monitor Found, Assign Coordinates and Dimensions to 4 Quadrants *****
				; Quadrant Q1 of Current Monitor: TOP LEFT
				; Floor Function to be used in case there is a division of an odd number which would leave a "0.5".  Comparisons (Full Height and Quadrants) do not work without it.
				MtxQdrTop[VrtMonOrdr, ColPosA_Index, 1] := MonTopTemp[VrtMonNrA_Index]
				MtxQdrLft[VrtMonOrdr, ColPosA_Index, 1] := MonLftTemp[VrtMonNrA_Index]
				MtxQdrBtm[VrtMonOrdr, ColPosA_Index, 1] := Floor(MonBtmTemp[VrtMonNrA_Index] / 2)
				MtxQdrRgt[VrtMonOrdr, ColPosA_Index, 1] := Floor(MonRgtTemp[VrtMonNrA_Index] / 2)
				MtxQdrWdt[VrtMonOrdr, ColPosA_Index, 1] := Floor((MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]) / 2)
				MtxQdrHgt[VrtMonOrdr, ColPosA_Index, 1] := Floor((MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]) / 2)

				; Quadrant Q2 of Current Monitor: BOTTOM LEFT
				MtxQdrTop[VrtMonOrdr, ColPosA_Index, 2] := Floor(MonTopTemp[VrtMonNrA_Index] + (MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]) / 2)
				MtxQdrLft[VrtMonOrdr, ColPosA_Index, 2] := MonLftTemp[VrtMonNrA_Index]
				MtxQdrBtm[VrtMonOrdr, ColPosA_Index, 2] := MonBtmTemp[VrtMonNrA_Index]
				MtxQdrRgt[VrtMonOrdr, ColPosA_Index, 2] := Floor(MonRgtTemp[VrtMonNrA_Index] / 2)
				MtxQdrWdt[VrtMonOrdr, ColPosA_Index, 2] := Floor((MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]) / 2)
				MtxQdrHgt[VrtMonOrdr, ColPosA_Index, 2] := Floor((MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]) / 2)

				; Quadrant Q3 of Current Monitor: TOP RIGHT
				MtxQdrTop[VrtMonOrdr, ColPosA_Index, 3] := MonTopTemp[VrtMonNrA_Index]
				MtxQdrLft[VrtMonOrdr, ColPosA_Index, 3] := Floor(MonLftTemp[VrtMonNrA_Index] + (MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]) / 2)
				MtxQdrBtm[VrtMonOrdr, ColPosA_Index, 3] := Floor(MonBtmTemp[VrtMonNrA_Index] / 2)
				MtxQdrRgt[VrtMonOrdr, ColPosA_Index, 3] := MonRgtTemp[VrtMonNrA_Index]
				MtxQdrWdt[VrtMonOrdr, ColPosA_Index, 3] := Floor((MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]) / 2)
				MtxQdrHgt[VrtMonOrdr, ColPosA_Index, 3] := Floor((MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]) / 2)

				; Quadrant Q4 of Current Monitor: BOTTOM RIGHT
				MtxQdrTop[VrtMonOrdr, ColPosA_Index, 4] := Floor(MonTopTemp[VrtMonNrA_Index] + (MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]) / 2)
				MtxQdrLft[VrtMonOrdr, ColPosA_Index, 4] := Floor(MonLftTemp[VrtMonNrA_Index] + (MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]) / 2)
				MtxQdrBtm[VrtMonOrdr, ColPosA_Index, 4] := MonBtmTemp[VrtMonNrA_Index]
				MtxQdrRgt[VrtMonOrdr, ColPosA_Index, 4] := MonRgtTemp[VrtMonNrA_Index]
				MtxQdrWdt[VrtMonOrdr, ColPosA_Index, 4] := Floor((MonRgtTemp[VrtMonNrA_Index] - MonLftTemp[VrtMonNrA_Index]) / 2)
				MtxQdrHgt[VrtMonOrdr, ColPosA_Index, 4] := Floor((MonBtmTemp[VrtMonNrA_Index] - MonTopTemp[VrtMonNrA_Index]) / 2)
				; **************************************************************************** 


				; Assign Numbering to Monitor on this Column
				Col_RowQty[ColPosA_Index] := VrtMonOrdr

				; When a Monitor is found at this ROW and COLUMN Position, increment Count for Next Monitor in this Column
				VrtMonOrdr += 1

				; Once Matching Monitor Found, Skip to Next Row
				Break
			}
		}
	}
}
 
; 	  HOTKEY
; **************
; Move and Resize Active Window to LEFT HALF of Current Monitor
![::
!NumPad4::
#^!+NumPad4::
#^!+NumPadLeft::
#^!NumPadLeft::
!LButton::
LftHlfSub:
{
	; If Focus is on an Exluded Program (I.e.Desktop), Ignore this HotKey
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}

	; Retrieve Coordinates, Dimensions, Min/Max State, Process Name and Title of Active Window
	WinGetPos, WinLft, WinTop, WinWdt, WinHgt, A
	WinGet, WinMMax, MinMax, A
	WinGet, PNameHlfLft, ProcessName, A
	WinGetTitle, TNameHlfLft, A

	; Add Correction Factor per Program + Find in which Monitor Active Window is located
	GoSub, CrctnFctr
	; Retrieves on which Monitor Number the Active Window is on
	GoSub, WinCurntMon

	; If Window is Maximized, "UnMaximize" it
	If (WinMMax == 1)
	{
		WinRestore, A
	}

	; If Active Window is a Program I don't want to Resize to Half of the Monitor
	If (PNameHlfLft == "lync.exe" OR (PNameHlfLft == "vlc.exe" AND TNameHlfLft ~= "Playlist") OR PNameHlfLft == "slack.exe" OR (PNameHlfLft == "ApplicationFrameHost.exe" AND TNameHlfLft ~= "Calculator"))
	{
		; Programs that will Resize to 416 Pixels Width (Minimum possible Width of Skype)
		If (PNameHlfLft == "vlc.exe" AND TNameHlfLft ~= "Playlist")
		 
		{
			NrwWdt := 416
		}
		; Other Programs that will keep their Original Width
		Else
		{
			NrwWdt := WinWdt
		}

		; If Active Window is already Resized and Located on Left Side of the Current Monitor, Move Active Window to Right Side of Previous Monitor
		If (WinLft == MonLft[OnMonitor] + HrzCrctn AND WinTop == MonTop[OnMonitor])
		{
			; If Active Window is already Resized on Left Side of Monitor #1, Move Window to Right Side of Last Monitor
			If (OnMonitor == 1)
			{
				WinMove, A, , MonRgt[MonQty] - NrwWdt - HrzCrctn, MonTop[MonQty], NrwWdt, (MonHgt[MonQty] * 3 / 4) + HgtCrctn
				Return
			}
			; If Active Window is already Resized on Left Side of Current Monitor, Move Window to Right Side of Previous Monitor
			Else
			{
				WinMove, A, , MonRgt[OnMonitor - 1] - NrwWdt - HrzCrctn, MonTop[OnMonitor - 1], NrwWdt, (MonHgt[OnMonitor - 1] * 3 / 4) + HgtCrctn
				Return
			}
		}
		; Move and Resize Active Window to Left Side of Current Monitor
		Else
		{
			WinMove, A, , MonLft[OnMonitor] + HrzCrctn, MonTop[OnMonitor], NrwWdt, (MonHgt[OnMonitor] * 3 / 4) + HgtCrctn
			Return
		}
	}
	
	; If Active Window is already Resized and Located on Left Half of the Current Monitor, Move Active Window to Right Half of Previous Monitor
	If (WinLft == MonLft[OnMonitor] + HrzCrctn AND WinTop == MonTop[OnMonitor] AND WinWdt == MonHlfWdt[OnMonitor] + WdtCrctn AND WinHgt == MonHgt[OnMonitor] + HgtCrctn)
	{
		; If Active Window is already Resized on Left Half of Monitor #1, Move Window to Right Half of Last Monitor
		If (OnMonitor == 1)
		{
			WinMove, A, , MonHlfRgt[MonQty] + HrzCrctn, MonTop[MonQty], MonHlfWdt[MonQty] + WdtCrctn, MonHgt[MonQty] + HgtCrctn
			Return
		}
		; If Active Window is already Resized on Left Half of Current Monitor, Move Window to Right Half of Previous Monitor
		Else
		{
			WinMove, A, , MonHlfRgt[OnMonitor - 1] + HrzCrctn, MonTop[OnMonitor - 1], MonHlfWdt[OnMonitor - 1] + WdtCrctn, MonHgt[OnMonitor - 1] + HgtCrctn
			Return
		}
	}
	; Move and Resize Active Window to Left Half of Current Monitor
	Else
	{
		WinMove, A, , MonLft[OnMonitor] + HrzCrctn, MonTop[OnMonitor], MonHlfWdt[OnMonitor] + WdtCrctn, MonHgt[OnMonitor] + HgtCrctn
		Return
	}
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to RIGHT HALF of Current Monitor
!]::
!NumPad6::
#^!+NumPad6::
#^!+NumPadRight::
#^!NumPadRight::
!RButton::
RgtHlfSub:
{
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}
	
	WinGetPos, WinLft, WinTop, WinWdt, WinHgt, A
	WinGet, WinMMax, MinMax, A
	WinGet, PNameHlfRgt, ProcessName, A
	WinGetTitle, TNameHlfRgt, A
	
	GoSub, CrctnFctr
	GoSub, WinCurntMon

	If (WinMMax == 1)
	{
		WinRestore, A
	}

	; If Active Window is a Program I don't want to Resize to Half of the Monitor
	If (PNameHlfRgt == "lync.exe" OR (PNameHlfRgt == "vlc.exe" AND TNameHlfRgt ~= "Playlist") OR PNameHlfRgt == "slack.exe" OR (PNameHlfRgt == "ApplicationFrameHost.exe" AND TNameHlfRgt ~= "Calculator"))
	{
		If (PNameHlfLft == "vlc.exe" AND TNameHlfLft ~= "Playlist")
		{
			NrwWdt := 416
		}
		Else
		{
			NrwWdt := WinWdt
		}
	
		If (WinLft == MonRgt[OnMonitor] - WinWdt - HrzCrctn AND WinTop == MonTop[OnMonitor])
		{
			If (OnMonitor == MonQty)
			{
				WinMove, A, , MonLft[1] + HrzCrctn, MonTop[1], NrwWdt, (MonHgt[1] * 3 / 4) + HgtCrctn
				Return
			}
			Else
			{
				WinMove, A, , MonLft[OnMonitor + 1] + HrzCrctn, MonTop[OnMonitor + 1], NrwWdt, (MonHgt[OnMonitor + 1] * 3 / 4) + HgtCrctn
				Return
			}
		}
		Else
		{
			WinMove, A, ,MonRgt[OnMonitor] - NrwWdt - HrzCrctn , MonTop[OnMonitor], NrwWdt, (MonHgt[OnMonitor] * 3 / 4) + HgtCrctn
			Return
		}
	}

	Loop, %MonQty%
	{
		If (OnMonitor == A_Index)
		{
			If (WinLft == MonHlfRgt[A_Index] + HrzCrctn AND WinTop == MonTop[A_Index] AND WinWdt == MonHlfWdt[A_Index] + WdtCrctn AND WinHgt == MonHgt[A_Index] + HgtCrctn)
			{
				; If Active Window is already Resized on Right Half of Last Monitor, Move Window to Left Half of Monitor #1
				If (A_Index == MonQty)
				{
					WinMove, A, , MonHlfLft[1] + HrzCrctn, MonTop[1], MonHlfWdt[1] + WdtCrctn, MonHgt[1] + HgtCrctn
					Return
				}
				Else
				{
					WinMove, A, , MonHlfLft[A_Index + 1] + HrzCrctn, MonTop[A_Index + 1], MonHlfWdt[A_Index + 1] + WdtCrctn, MonHgt[A_Index + 1] + HgtCrctn
					Return
				}
			}
			Else
			{
				WinMove, A, , MonHlfRgt[A_Index] + HrzCrctn, MonTop[A_Index], MonHlfWdt[A_Index] + WdtCrctn, MonHgt[A_Index] + HgtCrctn
				Return
			}
		}
	}
}

; 	  HOTKEY
; **************
; Move Active Window to PREVIOUS Monitor
!NumPadLeft::
{
	If (!GetKeyState("NumLock", "T"))
	{
		GoSub, LftHlfSub
		Return
	}
}
!+[::
!+NumPad4::
!+NumPadLeft::
!+LButton::
{
	; If Focus is on an Exluded Program (I.e.Desktop), Ignore this HotKey
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}

	; If there is only 1 Monitor, Ignore this HotKey
	WinGetClass, CNamePrvMon, A
	If (MonQty == 1)
	{
		GoSub, PrevQdr
		Return
	}

	; Retrieve Coordinates and Dimensions of Active Window
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A

	; Calculates difference between Top Left corner of the Active Window and Top Left corner of Current Monitor
	WinMovCrctnLft := WinHrz - MonLft[OnMonitor]
	WinMovCrctnTop := WinVrt - MonTop[OnMonitor]
	
	; If Active Window is Full Vertical Height on Current Monitor, keep Full Vertical Height on PREVIOUS Monitor, regardless of difference in Monitor Height
	If ((WinVrt == MonTop[OnMonitor] AND WinHgt == MonHgt[OnMonitor] + HgtCrctn) OR WinMMax == 1)
	{
		; If Active Window is Located on Monitor #1, Move Active Window to LAST Monitor (Keep Full Window Height)
		If (OnMonitor == 1)
		{
			WinMove, A, , MonLft[MonQty] + WinMovCrctnLft, MonTop[MonQty], WinWdt, MonHgt[MonQty] + HgtCrctn
			Return
		}
		; Move Active Window to PREVIOUS Monitor (Keep Full Window Height)
		Else
		{
			WinMove, A, , MonLft[OnMonitor - 1] + WinMovCrctnLft, MonTop[OnMonitor - 1], WinWdt, MonHgt[OnMonitor - 1] + HgtCrctn
			Return
		}
	}
	; If Active Window is Located in a Quadrant on Current Monitor, Move and Resize Active Window to same Quadrant on PREVIOUS Monitor, regardless of Work Area
	Else If (OnQuadrant == 1 OR OnQuadrant == 2 OR OnQuadrant == 3  OR OnQuadrant == 4)
	{
		; If Active Window is Located in a Quadrant on Monitor #1, Move and Resize Active Window to same Quadrant on LAST Monitor, regardless of Work Area
		If (OnMonitor == 1)
		{
			WinMove, A, , MonQdrLft[MonQty, OnQuadrant] + HrzCrctn, MonQdrTop[MonQty, OnQuadrant], MonQdrWdt[MonQty, OnQuadrant] + WdtCrctn, MonQdrHgt[MonQty, OnQuadrant] + HgtCrctn
			Return
		}
		; Move and Resize Active Window to same Quadrant on PREVIOUS Monitor, regardless of Work Area
		Else
		{
			WinMove, A, , MonQdrLft[OnMonitor - 1, OnQuadrant] + HrzCrctn, MonQdrTop[OnMonitor - 1, OnQuadrant], MonQdrWdt[OnMonitor - 1, OnQuadrant] + WdtCrctn, MonQdrHgt[OnMonitor - 1, OnQuadrant] + HgtCrctn
			Return
		}
	}
	; Move Active Window to Previous Monitor, Regardless of Window Height
	Else
	{
		; If Active Window is Located on Monitor #1, Move Active Window to Last Monitor
		If (OnMonitor == 1)
		{
			WinMove, A, , MonLft[MonQty] + WinMovCrctnLft, MonTop[MonQty] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
		; Move Active Window to Previous Monitor
		Else
		{
			WinMove, A, , MonLft[OnMonitor - 1] + WinMovCrctnLft, MonTop[OnMonitor - 1] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
	}
}

; 	  HOTKEY
; **************
; Move Active Window to NEXT Monitor
!NumPadRight::
{
	If (!GetKeyState("NumLock", "T"))
	{
		GoSub, RgtHlfSub
		Return
	}
}
!+]::
!+NumPad6::
!+NumPadRight::
!+RButton::
{
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}

	If (MonQty == 1)
	{
		GoSub, NextQdr
		Return
	}

	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A

	WinMovCrctnLft := WinHrz - MonLft[OnMonitor]
	WinMovCrctnTop := WinVrt - MonTop[OnMonitor]
	
	If ((WinVrt == MonTop[OnMonitor] AND WinHgt == MonHgt[OnMonitor] + HgtCrctn) OR WinMMax == 1)
	{
		; If Active Window is Located on LAST Monitor, Move Active Window to Monitor #1 (Keep Full Window Height)
		If (OnMonitor == MonQty)
		{
			WinMove, A, , MonLft[1] + WinMovCrctnLft, MonTop[1], WinWdt, MonHgt[1] + HgtCrctn
			Return
		}
		Else
		{
			WinMove, A, , MonLft[OnMonitor + 1] + WinMovCrctnLft, MonTop[OnMonitor + 1], WinWdt, MonHgt[OnMonitor + 1] + HgtCrctn
			Return
		}
	}
	; If Active Window is Located in a Quadrant on Current Monitor, Move and Resize Active Window to same Quadrant on NEXT Monitor, regardless of Work Area
	Else If (OnQuadrant == 1 OR OnQuadrant == 2 OR OnQuadrant == 3  OR OnQuadrant == 4)
	{
		; If Active Window is Located in a Quadrant on LAST Monitor, Move and Resize Active Window to same Quadrant on Monitor #1, regardless of Work Area
		If (OnMonitor == MonQty)
		{
			WinMove, A, , MonQdrLft[1, OnQuadrant] + HrzCrctn, MonQdrTop[1, OnQuadrant], MonQdrWdt[1, OnQuadrant] + WdtCrctn, MonQdrHgt[1, OnQuadrant] + HgtCrctn
			Return
		}
		; Move and Resize Active Window to same Quadrant on NEXT Monitor, regardless of Work Area
		Else
		{
			WinMove, A, , MonQdrLft[OnMonitor + 1, OnQuadrant] + HrzCrctn, MonQdrTop[OnMonitor + 1, OnQuadrant], MonQdrWdt[OnMonitor + 1, OnQuadrant] + WdtCrctn, MonQdrHgt[OnMonitor + 1, OnQuadrant] + HgtCrctn
			Return
		}
	}
	Else
	{
		If (OnMonitor == MonQty)
		{
			WinMove, A, , MonLft[1] + WinMovCrctnLft, MonTop[1] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
		Else
		{
			WinMove, A, , MonLft[OnMonitor + 1] + WinMovCrctnLft, MonTop[OnMonitor + 1] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
	}
}

; 	  HOTKEY
; **************
; Move Active Window to UPPER Monitor
!NumPadUp::
{
	If (!GetKeyState("NumLock", "T"))
	{
		GoSub, MaxWinSub
		Return
	}
}
!+=::
!+NumPad8::
!+NumPadUp::
!+WheelUp::
{
	; If Focus is on an Exluded Program (I.e.Desktop), Ignore this HotKey
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}

	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, WinCurntMtx
	GoSub, CrctnFctr 
	WinGet, WinMMax, MinMax, A

	; If there is only 1 Row of Monitors, Ignore this HotKey
	If (OnMtxRowQty == 1)
	{
		Return
	}

	WinMovCrctnLft := WinHrz - MtxLft[OnMtxRow, OnMtxCol]
	WinMovCrctnTop := WinVrt - MtxTop[OnMtxRow, OnMtxCol]

	; If Active Window is Full Vertical Height on Current Monitor, keep Full Vertical Height on UPPER Monitor, regardless of difference in Monitor Height
	If ((WinVrt == MtxTop[OnMtxRow, OnMtxCol] AND WinHgt == MtxHgt[OnMtxRow, OnMtxCol] + HgtCrctn) OR WinMMax == 1)
	{
		; If Active Window is Located on TOP Row of Monitors, Move Active Window to BOTTOM Most Row of Monitors (Keep Full Window Height)
		If (OnMtxRow == 1)
		{
			WinMove, A, , MtxLft[OnMtxRowQty, OnMtxCol] + WinMovCrctnLft, MtxTop[OnMtxRowQty, OnMtxCol], WinWdt, MtxHgt[OnMtxRowQty, OnMtxCol] + HgtCrctn
			Return
		}
		; Move Active Window to UPPER Monitor (Keep Full Window Height)
		Else
		{
			WinMove, A, , MtxLft[OnMtxRow - 1, OnMtxCol] + WinMovCrctnLft, MtxTop[OnMtxRow - 1, OnMtxCol], WinWdt, MtxHgt[OnMtxRow - 1, OnMtxCol] + HgtCrctn
			Return
		}
	}
	; If Active Window is Located in a Quadrant on Current Monitor, Move and Resize Active Window to same Quadrant on UPPER Monitor, regardless of Work Area
	Else If (OnQuadrant == 1 OR OnQuadrant == 2 OR OnQuadrant == 3  OR OnQuadrant == 4)
	{
		; If Active Window is Located in a Quadrant on LAST Monitor, Move and Resize Active Window to same Quadrant on Monitor #1, regardless of Work Area
		If (OnMtxRow == 1)
		{
			WinMove, A, , MtxQdrLft[OnMtxRowQty, OnMtxCol, OnQuadrant] + HrzCrctn, MtxQdrTop[OnMtxRowQty, OnMtxCol, OnQuadrant], MtxQdrWdt[OnMtxRowQty, OnMtxCol, OnQuadrant] + WdtCrctn, MtxQdrHgt[OnMtxRowQty, OnMtxCol, OnQuadrant] + HgtCrctn
			Return
		}
		; Move and Resize Active Window to same Quadrant on NEXT Monitor, regardless of Work Area
		Else
		{
			WinMove, A, , MtxQdrLft[OnMtxRow - 1, OnMtxCol, OnQuadrant] + HrzCrctn, MtxQdrTop[OnMtxRow - 1, OnMtxCol, OnQuadrant], MtxQdrWdt[OnMtxRow - 1, OnMtxCol, OnQuadrant] + WdtCrctn, MtxQdrHgt[OnMtxRow - 1, OnMtxCol, OnQuadrant] + HgtCrctn
			Return
		}
	}
	Else
	{
		; If Active Window is Located on Top Row of Monitors, Move Active Window to Bottom Most Row of Monitors
		If (OnMtxRow == 1)
		{
			WinMove, A, , MtxLft[OnMtxRowQty, OnMtxCol] + WinMovCrctnLft, MtxTop[OnMtxRowQty, OnMtxCol] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
		; Move Active Window to Upper Monitor
		Else
		{
			WinMove, A, , MtxLft[OnMtxRow - 1, OnMtxCol] + WinMovCrctnLft, MtxTop[OnMtxRow - 1, OnMtxCol] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
	}
}

; 	  HOTKEY
; **************
; Move Active Window to LOWER Monitor
!NumPadDown::
{
	If (!GetKeyState("NumLock", "T"))
	{
		GoSub, MinWinSub
		Return
	}
}
!+\::
!+NumPad2::
!+NumPadDown::
!+WheelDown::
MinWinSub:
{
	; If Focus is on an Exluded Program (I.e.Desktop), Ignore this HotKey
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}

	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, WinCurntMtx
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A

	; If there is only 1 Row of Monitors, Ignore this HotKey
	If (OnMtxRowQty == 1)
	{
		Return
	}

	WinMovCrctnLft := WinHrz - MtxLft[OnMtxRow, OnMtxCol]
	WinMovCrctnTop := WinVrt - MtxTop[OnMtxRow, OnMtxCol]

	If ((WinVrt == MtxTop[OnMtxRow, OnMtxCol] AND WinHgt == MtxHgt[OnMtxRow, OnMtxCol] + HgtCrctn) OR WinMMax == 1)
	{
		; If Active Window is Located on Bottom Most Row of Monitors, Move Active Window to Top Row of Monitors (Keep Full Window Height)
		If (OnMtxRow == OnMtxRowQty)
		{
			WinMove, A, , MtxLft[1, OnMtxCol] + WinMovCrctnLft, MtxTop[1, OnMtxCol], WinWdt, MtxHgt[1, OnMtxCol] + HgtCrctn
			Return
		}
		Else
		{
			WinMove, A, , MtxLft[OnMtxRow + 1, OnMtxCol] + WinMovCrctnLft, MtxTop[OnMtxRow + 1, OnMtxCol], WinWdt, MtxHgt[OnMtxRow + 1, OnMtxCol] + HgtCrctn
			Return
		}
	}
	; If Active Window is Located in a Quadrant on Current Monitor, Move and Resize Active Window to same Quadrant on UPPER Monitor, regardless of Work Area
	Else If (OnQuadrant == 1 OR OnQuadrant == 2 OR OnQuadrant == 3  OR OnQuadrant == 4)
	{
		; If Active Window is Located in a Quadrant on LAST Monitor, Move and Resize Active Window to same Quadrant on Monitor #1, regardless of Work Area
		If (OnMtxRow == OnMtxRowQty)
		{
			WinMove, A, , MtxQdrLft[1, OnMtxCol, OnQuadrant] + HrzCrctn, MtxQdrTop[1, OnMtxCol, OnQuadrant], MtxQdrWdt[1, OnMtxCol, OnQuadrant] + WdtCrctn, MtxQdrHgt[1, OnMtxCol, OnQuadrant] + HgtCrctn
			Return
		}
		; Move and Resize Active Window to same Quadrant on NEXT Monitor, regardless of Work Area
		Else
		{
			WinMove, A, , MtxQdrLft[OnMtxRow + 1, OnMtxCol, OnQuadrant] + HrzCrctn, MtxQdrTop[OnMtxRow + 1, OnMtxCol, OnQuadrant], MtxQdrWdt[OnMtxRow + 1, OnMtxCol, OnQuadrant] + WdtCrctn, MtxQdrHgt[OnMtxRow + 1, OnMtxCol, OnQuadrant] + HgtCrctn
			Return
		}
	}
	Else
	{
		If (OnMtxRow == OnMtxRowQty)
		{
			WinMove, A, , MtxLft[1, OnMtxCol] + WinMovCrctnLft, MtxTop[1, OnMtxCol] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
		Else
		{
			WinMove, A, , MtxLft[OnMtxRow + 1, OnMtxCol] + WinMovCrctnLft, MtxTop[OnMtxRow + 1, OnMtxCol] + WinMovCrctnTop, WinWdt, WinHgt
			Return
		}
	}
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to UPPER LEFT Corner (Quadrant 1) of Current Monitor OR to BOTTOM LEFT Corner (Quadrant 2) of Current Monitor
#^!+[::
#^!+LButton::
; SubRoutine Label. To be Retrieved when "Move Active Window to PREVIOUS Monitor" is Activated and there is only 1 Monitor in Monitor Configuration
PrevQdr:
{
	GoSub, ExcludPrgrm
	If (IgnorePrgrm == True)
	{
		Return
	}

	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	WinGet, WinMMax, MinMax, A
	GoSub, WinCurntMon
	; Retrieves in which Quadrant Number of Current Monitor the Active Window is on.
	GoSub, WinCurntQdr
	GoSub, CrctnFctr

	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	; If Active Window is TOP LEFT Corner (Quadrant 1) OR in BOTTOM RIGHT Corner (Quadrant 4) of Current Monitor, Move and Resize Active Window to LOWER LEFT Corner (Quadrant 2) of Current Monitor
	If (OnQuadrant == 1 OR OnQuadrant == 4)
	{
		WinMove, A, , MonQdrLft[OnMonitor, 2] + HrzCrctn, MonQdrTop[OnMonitor, 2], MonQdrWdt[OnMonitor, 2] + WdtCrctn, MonQdrHgt[OnMonitor, 2] + HgtCrctn
		Return
	}
	; Else Move Active Window to TOP LEFT Corner (Quadrant 1) of Current Monitor
	Else
	{
		WinMove, A, , MonQdrLft[OnMonitor, 1] + HrzCrctn, MonQdrTop[OnMonitor, 1], MonQdrWdt[OnMonitor, 1] + WdtCrctn, MonQdrHgt[OnMonitor, 1] + HgtCrctn
		Return
	}
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to UPPER Right Corner (Quadrant 3) of Current Monitor OR to BOTTOM RIGHT Corner (Quadrant 4) of Current Monitor for other circumstances
#^!+]::
#^!+RButton::
; SubRoutine Label. To be Retrieved when "Move Active Window to NEXT Monitor" is Activated and there is only 1 Monitor in Monitor Configuration
NextQdr:
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	WinGet, WinMMax, MinMax, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr

	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	; If Active Window is in UPPER RIGHT Corner (Quadrant 3) OR in LOWER LEFT Corner (Quadrant 2) of Current Monitor, Move and Resize Active Window to LOWER RIGHT Corner (Quadrant 4) of Current Monitor
	If (OnQuadrant == 3 OR OnQuadrant == 2)
	{
		WinMove, A, , MonQdrLft[OnMonitor, 4] + HrzCrctn, MonQdrTop[OnMonitor, 4], MonQdrWdt[OnMonitor, 4] + WdtCrctn, MonQdrHgt[OnMonitor, 4] + HgtCrctn
		Return
	}
	; Else Move Active Window to UPPER RIGHT Corner (Quadrant 3) of Current Monitor
	Else
	{
		WinMove, A, , MonQdrLft[OnMonitor, 3] + HrzCrctn, MonQdrTop[OnMonitor, 3], MonQdrWdt[OnMonitor, 3] + WdtCrctn, MonQdrHgt[OnMonitor, 3] + HgtCrctn
		Return
	}
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to UPPER LEFT Corner of Current Monitor (Quadrant 1)
!NumPad7::
#^!+NumPad7::
#^!+NumPadHome::
#^!NumPadHome::
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A
	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	WinMove, A, , MonQdrLft[OnMonitor, 1] + HrzCrctn, MonQdrTop[OnMonitor, 1], MonQdrWdt[OnMonitor, 1] + WdtCrctn, MonQdrHgt[OnMonitor, 1] + HgtCrctn
	Return
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to LOWER LEFT Corner of Current Monitor (Quadrant 2)
!NumPad1::
#^!+NumPad1::
#^!+NumPadEnd::
#^!NumPadEnd::
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A
	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	WinMove, A, , MonQdrLft[OnMonitor, 2] + HrzCrctn, MonQdrTop[OnMonitor, 2], MonQdrWdt[OnMonitor, 2] + WdtCrctn, MonQdrHgt[OnMonitor, 2] + HgtCrctn
	Return
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to UPPER RIGHT Corner of Current Monitor (Quadrant 3)
!NumPad9::
#^!+NumPad9::
#^!+NumPadPgUp::
#^!NumPadPgUp::
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A
	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	WinMove, A, , MonQdrLft[OnMonitor, 3] + HrzCrctn, MonQdrTop[OnMonitor, 3], MonQdrWdt[OnMonitor, 3] + WdtCrctn, MonQdrHgt[OnMonitor, 3] + HgtCrctn
	Return
}

; 	  HOTKEY
; **************
; Move and Resize Active Window to LOWER RIGHT Corner of Current Monitor (Quadrant 4)
!NumPad3::
#^!+NumPad3::
#^!+NumPadPgDn::
#^!NumPadPgDn::
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	GoSub, WinCurntMon
	GoSub, WinCurntQdr
	GoSub, CrctnFctr
	WinGet, WinMMax, MinMax, A
	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	WinMove, A, , MonQdrLft[OnMonitor, 4] + HrzCrctn, MonQdrTop[OnMonitor, 4], MonQdrWdt[OnMonitor, 4] + WdtCrctn, MonQdrHgt[OnMonitor, 4] + HgtCrctn
	Return
}

; 	  HOTKEY
; **************
; FOCUS on Window with Mouse Cursor and MINIMIZE Window
!WheelDown::
{
	MouseGetPos,,, WinID
	WinGetClass, CNameWinMin, ahk_id %WinID%
	; If Focus is on Desktop or Taskbar, Ignore this HotKey
	If (CNameWinMin == "WorkerW" OR CNameWinMin == "Shell_TrayWnd")
	{
		Return
	}
	Else
	{
		WinMinimize, ahk_id %WinID%
		Return
	}
}

; 	  HOTKEY
; **************
; MINIMIZE Window (Does not give Focus to Window)
!-::
!NumPad2::
#^!+NumPad2::
#^!+NumPadDown::
#^!NumPadDown::
{
	; If Focus is on Desktop or Taskbar, Ignore this HotKey
	WinGetClass, CNameWinMin, A
	If (CNameWinMin == "WorkerW" OR CNameWinMin == "Shell_TrayWnd")
	{
		Return
	}
	Else
	{
		WinMinimize, A
		Return
	}
}

; 	  HOTKEY
; **************
;MAXIMIZE Window (Does not give Focus to Window)
!=::
!NumPad8::
#^!+NumPad8::
#^!+NumPadUp::
#^!NumPadUp::
!WheelUp:: 
MaxWinSub:
{
	; If Focus is on Desktop, Ignore this HotKey
	WinGetClass, CNameWinMax, A
	If (CNameWinMax == "WorkerW")
	{
		Return
	}
	Else
	{
		WinMaximize, A
		Return
	}
}

; 	  HOTKEY
; **************
; FOCUS on Window with Mouse Cursor and CLOSE Window
!MButton::
{
	MouseGetPos,,, WinID
	WinGetClass, CNameWinCls, ahk_id %WinID%
	; If Focus is on Desktop or Taskbar, Ignore this HotKey
	If (CNameWinCls == "WorkerW" OR CNameWinCls == "Shell_TrayWnd")
	{
		Return
	}
	Else
	{
		WinClose, ahk_id %WinID%
		Return
	}
}

; 	  HOTKEY
; **************
; CLOSE Window (Does not give Focus to Window)
!'::
!NumPad0::
#^!+NumPad0::
#^!+NumPadIns::
#^!NumPadIns::
^+w::
{
	; If Focus is on Desktop or Taskbar, Ignore this HotKey
	WinGetClass, CNameWinCls, A
	If (CNameWinCls == "WorkerW" OR CNameWinCls == "Shell_TrayWnd")
	{
		Return
	}
	Else
	{
		WinClose, A
		Return
	}
}

;     User Defined Values and Programs
; ****************************************
; ***** Gosub Label *****
; Correction Factor to implement for specific Programs
CrctnFctr:
{
	WinGet, PNameWin, ProcessName, A
	If (PNameWin == "Code.exe" OR PNameWin == "Spotify.exe" OR PNameWin == "OUTLOOK.EXE" OR PNameWin == "lync.exe" OR PNameWin == "slack.exe" OR PNameWin == "WINWORD.EXE" OR PNameWin == "EXCEL.EXE" OR PNameWin == "Revu.exe")
	{
		HrzCrctn = 0
		HgtCrctn = 0
		WdtCrctn = 0
		Return
	}
	; For some reason, there is an offset when working with Explorer and Chrome
	Else
	{
		HrzCrctn = -7
		HgtCrctn = 7
		WdtCrctn = 14
		Return
	}
}

;     User Defined Values and Programs
; ****************************************
; ***** Gosub Label *****
; Exluded Programs, where the HotKeys will NOT WORK
ExcludPrgrm:
{
	WinGetClass, CNameHlfLft, A
	ExcludPrgrm := False
	; WorkerW ➔ Desktop
	If (CNameHlfLft == "WorkerW")
	{
		IgnorePrgrm := True
	}
	Return
}

; ***** Gosub Label *****
; Retrieves on which Monitor Number the Active Window is on
; Used to Move Window from Right to Left Monitors
WinCurntMon:
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	WinHgtCtr := WinVrt + WinHgt / 2
	WinHrzCtr := WinHrz + WinWdt / 2

	Loop, %MonQty%
	{
		; If Center of Active Window is Located between defined Boundaries, Active Window is Located on Monitor #X
		If (WinHgtCtr >= MonTop[A_Index] AND WinHgtCtr <= MonBtm[A_Index] AND WinHrzCtr >= MonLft[A_Index] AND WinHrzCtr <= MonRgt[A_Index])
		{
			OnMonitor := A_Index
			; Once Matching Monitor Found, Stop the Search
			Break
		}
	}
	Return
}

; ***** Gosub Label *****
; Finds on which Monitor Row and Column (Matrix) the Active Window is on
; Used to Move Window from Upper to Lower Monitors
WinCurntMtx:
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	WinHgtCtr := WinVrt + WinHgt / 2
	WinHrzCtr := WinHrz + WinWdt / 2
	
	Loop, %ColQty%
	{
		ColPosA_Index := A_Index
		Col_RowQtyLoop := Col_RowQty[ColPosA_Index]
		Loop, %Col_RowQtyLoop%
		{
			VrtMtxOrdrA_Index := A_Index
			; If Center of Active Window is Located between defined Boundaries, Active Window is Located on Row #X and Column #X
			If (WinHgtCtr >= MtxTop[VrtMtxOrdrA_Index, ColPosA_Index] AND WinHgtCtr <= MtxBtm[VrtMtxOrdrA_Index, ColPosA_Index] AND WinHrzCtr >= MtxLft[VrtMtxOrdrA_Index, ColPosA_Index] AND WinHrzCtr <= MtxRgt[VrtMtxOrdrA_Index, ColPosA_Index])
			{
				OnMtxRow := VrtMtxOrdrA_Index
				OnMtxCol := ColPosA_Index
				OnMtxRowQty := Col_RowQty[ColPosA_Index]
				; Once Matching Monitor Found, Stop the Search
				Break
			}
		}
	}
	Return
}

; ***** Gosub Label *****
; Retrieves in which Quadrant Number of Current Monitor the Active Window is on.
WinCurntQdr:
{
	WinGetPos, WinHrz, WinVrt, WinWdt, WinHgt, A
	; If it is not on any Quadrant, OnQuadrant = 0
	OnQuadrant := 0
	Loop, 4
	{
		; If Active Window is Located on one of the 4 Quadrants, Active Window is Located on Quadrant #X
		If (WinHrz == MonQdrLft[OnMonitor, A_Index] + HrzCrctn AND WinVrt == MonQdrTop[OnMonitor, A_Index] AND WinWdt == MonQdrWdt[OnMonitor, A_Index] + WdtCrctn AND WinHgt == MonQdrHgt[OnMonitor, A_Index] + HgtCrctn)
		{
			OnQuadrant := A_Index
			; Once Matching Quadrant is Found, Stop the Search
			Break
		}
	}
	Return
}

; *******************************************************************************
; 		Automatic Mapping of All Monitors, Move & Resize Windows  -END-
; *******************************************************************************
Last edited by Cr8zy_Ivan on 12 Oct 2019, 14:58, edited 18 times in total.

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Additional Options

Post by Cr8zy_Ivan » 04 Oct 2019, 13:20

After posting the Script, I realized I didn't want to Resize every program to Half of the Monitor. So here is some complementary Code for those Exceptions.

Move Window to LEFT Side of Monitor (Left "Side", Not Left "Half")

At "; Move and Resize Active Window to Left Half of Current Monitor", Paste Under:

Code: Select all

	; If Window is Maximized, "UnMaximize" it
	If (WinMMax == 1)
	{
		WinRestore, A
	} 
🡳🡳🡳
Code to be Pasted:

Code: Select all

	; If Active Window is a Program I don't want to Resize to Half the Monitor
	If (PNameHlfLft == "lync.exe" OR (PNameHlfLft == "vlc.exe" AND TNameHlfLft ~= "Playlist") OR PNameHlfLft == "slack.exe")
	{
		; Programs that will keep their Original Width
		If (PNameHlfLft == "slack.exe")
		{
			NrwWdt := WinWdt
		}
		; Programs that will Resize to 416 Pixels Width (Minimum possible Width of Skype)
		Else
		{
			NrwWdt := 416
		}

		; If Active Window is already Resized and Located on Left Side of the Current Monitor, Move Active Window to Right Side of Previous Monitor
		If (WinLft == MonLft[OnMonitor] + HrzCrctn AND WinTop == MonTop[OnMonitor])
		{
			; If Active Window is already Resized on Left Side of Monitor #1, Move Window to Right Side of Last Monitor
			If (OnMonitor == 1)
			{
				WinMove, A, , MonRgt[MonQty] - NrwWdt - HrzCrctn, MonTop[MonQty], NrwWdt, (MonHgt[MonQty] * 3 / 4) + HgtCrctn
				Return
			}
			; If Active Window is already Resized on Left Side of Current Monitor, Move Window to Right Side of Previous Monitor
			Else
			{
				WinMove, A, , MonRgt[OnMonitor - 1] - NrwWdt - HrzCrctn, MonTop[OnMonitor - 1], NrwWdt, (MonHgt[OnMonitor - 1] * 3 / 4) + HgtCrctn
				Return
			}
		}
		; Move and Resize Active Window to Left Side of Current Monitor
		Else
		{
			WinMove, A, , MonLft[OnMonitor] + HrzCrctn, MonTop[OnMonitor], NrwWdt, (MonHgt[OnMonitor] * 3 / 4) + HgtCrctn
			Return
		}
	}

Move Window to RIGHT Side of Monitor (Right "Side", Not Right "Half")

At "; Move and Resize Active Window to Right Half of Current Monitor", Paste Under:

Code: Select all

	If (WinMMax == 1)
	{
		WinRestore, A
	}
🡳🡳🡳
Code to be Pasted:

Code: Select all

	; If Active Window is a Program I don't want to Resize to Half of the Monitor
	If (PNameHlfRgt == "lync.exe" OR (PNameHlfRgt == "vlc.exe" AND TNameHlfRgt ~= "Playlist") OR PNameHlfRgt == "slack.exe")
	{
		If (PNameHlfRgt == "slack.exe")
		{
			NrwWdt := WinWdt
		}
		Else
		{
			NrwWdt := 416
		}
	
		If (WinLft == MonRgt[OnMonitor] - WinWdt - HrzCrctn AND WinTop == MonTop[OnMonitor])
		{
			If (OnMonitor == MonQty)
			{
				WinMove, A, , MonLft[1] + HrzCrctn, MonTop[1], NrwWdt, (MonHgt[1] * 3 / 4) + HgtCrctn
				Return
			}
			Else
			{
				WinMove, A, , MonLft[OnMonitor + 1] + HrzCrctn, MonTop[OnMonitor + 1], NrwWdt, (MonHgt[OnMonitor + 1] * 3 / 4) + HgtCrctn
				Return
			}
		}
		Else
		{
			WinMove, A, ,MonRgt[OnMonitor] - NrwWdt - HrzCrctn , MonTop[OnMonitor], NrwWdt, (MonHgt[OnMonitor] * 3 / 4) + HgtCrctn
			Return
		}
	}

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Update & Fixes

Post by Cr8zy_Ivan » 05 Oct 2019, 16:30

Function "If Focus is on Desktop, Ignore this HotKey"
Added to:
  • Move and Resize Active Window to LEFT HALF of Current Monitor
  • Move and Resize Active Window to RIGHT HALF of Current Monitor
  • Move Active Window to PREVIOUS Monitor
  • Move Active Window to NEXT Monitor
  • Move Active Window to UPPER Monitor
  • Move Active Window to LOWER Monitor
  • MINIMIZE Window
  • MAXIMIZE Window
  • CLOSE Window
Function "If Focus is on Taskbar, Ignore this HotKey"
Added to:
  • MINIMIZE Window
  • MAXIMIZE Window
  • CLOSE Window
Function "If there is only 1 Monitor, Ignore this HotKey"
Added to:
  • Move Active Window to PREVIOUS Monitor
  • Move Active Window to NEXT Monitor
  • Move Active Window to UPPER Monitor
  • Move Active Window to LOWER Monitor
Notes:
Persistent Bugs: Sometimes the Desktop will Minimize or Close (the Icons on the Desktop will Minimize or Disappear when activating Minimize or Close Window). One instance of this is:
  • E.g. I have Visual Studio Code Opened and Active, the Mouse is Hovering over the Desktop, beside the VSC Window (an "Empty part" of the Desktop) and if I Minimize, the Icons on the Desktop will still Minimize, even when I've excluded WinClass "WorkerW". I even saw that in some instances, WinClass "Progman" is in Focus, and tried excluding that with no luck. If anyone has a fix for this, please share!
Cheers!

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Update & Fixes 2 (Full Version Updated in Initial First Post)

Post by Cr8zy_Ivan » 12 Oct 2019, 00:24

Fixed Glitches & Improvements:
  • A glitch was fixed which now prevents any alterations to the Desktop
  • Moving a Maximized Window will now Resize to take the Taskbar into account
Added Functions:
  • Moving and Resizing Active Window to one of the 4 Quadrants of current Monitor
    • When the active Window is not Resized to a Quadrant, the FIRST Resizing to Left or Right side Quadrants are moved to the Upper Quadrants
    • When the active Window is ALREADY Resized to a Quadrant, the SECOND Resizing (to same side of Monitor), the Window will be moved to the upper or lower Quadrant of the same side.
    • When the active Window is ALREADY Resized to a Quadrant, when Resizing to an OPPOSING SIDE of Monitor (Left to Right or Right to Left), the Window will stay at the same height (E.g. Bottom Right to Bottom Left).
  • Resizing and Moving Windows with the NumPad
  • When there is only 1 Monitor, the Functions to Move a Window to another Monitor, Resize the Window to a Quadrant instead.
Known Limitations:
  • If the Zoom setting of Monitors are not all the same, this Script will do wonky things
  • If a Window is Maximized, then moved to another Monitor and "UnMaximized" (Restored) by double clicking on the Titlebar, the Window will appear in the First initial Monitor.
Cheers!
Last edited by Cr8zy_Ivan on 12 Oct 2019, 14:54, edited 1 time in total.

User avatar
Frosti
Posts: 426
Joined: 27 Oct 2017, 14:30
Contact:

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Frosti » 12 Oct 2019, 04:22

Thank you for posting your useful script. The part with the monitor layout is exactly what I could use for example.
And because I'm usually outrageous, I have a desire right away!
I think it would be better if your script is designed as a library. Having individual functions makes it easier to integrate them into existing scripts.

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 12 Oct 2019, 11:38

Designed as a Library? Tell me more! :)

2Took
Posts: 24
Joined: 12 Aug 2022, 12:25

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by 2Took » 12 Aug 2022, 13:23

Hi, @GaXve

But what would be the shortest AHK code to just Move an active window, full screen, onto the left of three monitors?

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 12 Aug 2022, 16:27

Hey @2Took, just to make sure: You want to move any kind of Window to the far Left Monitor, on the Left Half of that Monitor. Did I get that right?

If so, this would be the code to do so:

Code: Select all


; Ctrl + Alt + 1
^!1::
{
	; Retrieves the Minimized/Maximized state of the Active Window
	WinGet, WinMMax, MinMax, A
	
	; Some Programs don't align to Screen contours correctly. You write under the CrctnFctr: Sub, the Programs you want corrected.
	GoSub, CrctnFctr
	
	; If the Active Window is Maximized, you want to Restore it before you move it, or else wonkiness ensues.
	If (WinMMax == 1)
	{
		WinRestore, A
	}
	
	; "1" is the first Monitor in the count. The Code assigns Monitor numbering from Left to Right (then from Top to Bottom, if you have multiple Rows of Monitors). Your specific Monitors should be numbered as: 1=Left Monitor, 2=Center Monitor, 3=Right Monitor
	WinMove, A, , MonHlfLft[1] + HrzCrctn, MonTop[1], MonHlfWdt[1] + WdtCrctn, MonHgt[1] + HgtCrctn
	
	Return
}


If you want to move the Window to the Right Half of that Monitor, you replace the WinMove line with this one:

Code: Select all

WinMove, A, , MonHlfLft[1] + HrzCrctn, MonTop[1], MonHlfWdt[1] + WdtCrctn, MonHgt[1] + HgtCrctn

You need to copy the auto-mapping part of the code for this to work, meaning all the code that comes before the first Hotkey ("Move and Resize Active Window to LEFT HALF of Current Monitor"). You also want to copy all the Gosub Labels, meaning all the code that comes after the first Gosub ("CrctnFctr:").

Also bear in mind, this is the very first code I wrote 3 years ago. The code could use some tidying up.

Hope this helps

2Took
Posts: 24
Joined: 12 Aug 2022, 12:25

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by 2Took » 17 Aug 2022, 14:09

Hey, @GaXve

Thanks.

Here's a one liner that works in moving active window to the left monitor, full screen (used Window Spy for coordinates):

Code: Select all

^+l::WinMove, A,, -1920,0 ;Ctrl Shift L - moves active window to left monitor

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 17 Aug 2022, 14:13

"edit"
Actually @2Took , sorry about that. Because of the nature of my code, I assumed you were looking for something more complexe.

Cheers mate

arenberg319
Posts: 1
Joined: 10 Nov 2022, 18:09

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by arenberg319 » 10 Nov 2022, 18:13

Thank you very much for your code. It helps me a lot in working efficiency. AHK is really amazing. As I am new to AHK, would you please help with the code for moving and resizing active window to upper and lower half of a monitor with Portrait mode. Thank you

swub
Posts: 19
Joined: 25 Feb 2019, 09:16

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by swub » 03 Feb 2023, 12:43

Do you know if there would be a way to combined this with Hot Corners for Windows 10 found here /boards/viewtopic.php?f=6&t=14058 or Have a script using FancyZones from the PowerToys? Would you then have extra Hot Corners?

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 03 Feb 2023, 13:25

Good question. I don't know what Hot Corners are. I'll have to look into it first.

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 07 Aug 2023, 09:16

New Updates to come:
I've been thinking about some features I've wanted to add for the past year or so. I've started to work on some implementations, and Scripting is ongoing. Unfortunately, because of a busy life, I can't say when the ETA will be. The most specific I'm willing to go is to say these features will "probably" be implemented before the end of this year (2023).
Some features to come:
  • New Hotkeys to Resize Active Window Incrementally.
    • Increase Active Window Width by 50% of Current Monitor Width. Increase Width up to full Length of all combined Monitors, on that specific Row of Monitors. Once the Active Window has reached the full Width of all combined Monitor, go back to zero and Resize the Active Window to half-Size (50% of the initial Monitor Width), and so on.
      • These new Functions will allow for Individual Resizing of: Width only and of Height only. Another Function will be added to adjust Width AND Height together, at base line of +50% of Width and Height of Initial Monitor.
      • I will also attempt to make it easy to edit and configure Increment Steps, as the user pleases.
    • Also, Decrease Active Window size by 50%, by all the modes listed above.
    • The User will also be able to define Minimum and Maximum Limits of Increase / Decrease Window Size (Say I don't want my Hotkeys to make my Active Window Width any narrower than "1 Monitor's Width". I also may want to limit the Maximum Width of my Windows. Limiting the maximum Width to "2 Monitors Wide" in a 3 "Monitors Wide" Setup for example).
  • New Hotkeys to Resize Active Window at a Specific New Size, to a Specific Location within the Multi-Monitor Setup. Single Monitor Setup will also be able to utilize these functions. It's just "not as useful" in this case than with a Multi-Monitor Setup.
  • Script Clean-Up and more Step-by-Step Descriptions. Diving back in to my Code, after nearly 4 years, I was actually pretty impressed by the clarity with which I wrote this Script (compared to all the other Scripts I've written that is, hehe). I've realized however, that I still found it hard to understand. In short, I found my Script "Clear-ish", but not clear enough that I could just easily jump right back in, and understand how everything worked right off the bat.
  • "Fuzzy" Column and Row Window Movement. The initial Script I wrote requires that all the Monitors be perfectly aligned, on the Bottom, and on the Left side of each Monitor for the Code to create its Matrix of Rows and Columns. I tested the Script on someone else's setup recently, where they had different sizes of Monitors, and different resolutions for each Monitor, and I found it tedious to work my way around using this Script. The "Fuzzy Column and Row Window Movement" Function might not be implemented by the end of this year however. I still don't know how I'm going to do it.
  • Moving an Active Window to the Edges of a Monitor. The way my initial Script works is, in most cases it Resizes each Window when you want to quickly "move" a Window on the Edge of the the Screen. Eg. Resize Window to Left or Right Half of the Screen (Resize and Move), or Resize Window to a Quadrant of the Screen (also Resize and Move). I've often found myself just wanting to throw "this Current Window" at the Edge of the Screen, without Resizing it. Or sometimes I just wanted to "throw the Window" at the Edge of the Screen on another Monitor.
  • Plus other stuff I can't think of right now.
On a side note, with all the Functions I want to implement, there will be a considerable amount of new Hotkeys that will be added. In some of these instances, instead of having one Hotkey per Function, I would like to combine multiple Functions into one Hotkey. For example: for this new Function I want to Implement: Incrementally Resizing the Active Window to a Specific Size and Place. I could want 5 different "Resize and Move the Active Window to a Specific Place" Functions and/or Hotkeys, but I can also create a Hotkey that Incrementally Increases and Decreases the Active Window. This, instead of having 5 different Hotkeys in the end, I end up having only two Hotkeys (Increase and Decrease) that are also versatile. It's not "Quite" the same thing, but I think it's as good, just different. I still don't know how to create, configure and combine certain other Functions that are to come. And for this, if you have any ideas, for new Functions or new Hotkeys, I would love to hear them. I'm always interested to know what other people think.

If you would feel so inclined, may it be via Replying to this Post, or via a Direct Message to myself, it would be my genuine pleasure to read what you have to say. It could be suggestions on future implementations, and also improvements on the current Script. I am not a Coder by trade, and you most probably will see some things that can be improved.

On this note, wishing everyone an excellent day!

And also, if you have any suggestions on how to Name this Script, I would be grateful to hear what they are. "Automatic Mapping of All Monitors, Move & Resize Windows" puts people to sleep before I finish saying it.

Edit (2023-09-05): I recently discovered some Bugs that were lying in my 4 year old Script. Having the Taskbar on the Left or Right side of the Screen has the Script work in quirky ways. This also will be fixed.

chaoscreater
Posts: 59
Joined: 12 Sep 2019, 21:15

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by chaoscreater » 20 Nov 2023, 18:22

Hi there,

I also use DisplayFusion and in the advanced setting, there's an option to set the monitor order for which your app window gets moved, as well as an option to ignore a specific monitor. For example, if you have a monitor layout like this:

Code: Select all

4 3
2 1
and if you have the monitor order like this - 4, 3, 1 and ignore monitor 2, then it means your window will move in the order 4, 3, 1 and not be moved to monitor 2.

The problem is that the monitor layout isn't always the same for me. We have a hot-desk setup in the office, so sometimes the monitor brand/model is different and the number of monitors is also different for each desk. If I connect my laptop to desk 1, I might get this setup:

Code: Select all

4 3
 1
but if I connect my laptop to desk 2, I might get this setup instead:

Code: Select all

3 4
 1
Because the layout changes all the time, it means my DisplayFusion setting also needs to change, otherwise the window gets moved to an incorrect monitor.

My goal is to use your script to determine the monitor positioning/layout, take the monitor index value of the top right most monitor (e.g. 4) and then update this value in the DisplayFusion setting (which can be done via registry).

So far, I'm able to get the monitor index and their positions using this:

Code: Select all

^+y::  ; Ctrl + Shift + Y Hotkey
{
    gosub, WinCurntMon  ; Call the subroutine to find the current monitor of the active window

    currentMonitor := OnMonitor  ; Store the current monitor number
    top := MonTop[currentMonitor]  ; Retrieve top position
    bottom := MonBtm[currentMonitor]  ; Retrieve bottom position
    left := MonLft[currentMonitor]  ; Retrieve left position
    right := MonRgt[currentMonitor]  ; Retrieve right position

    ; Display the information
    MsgBox, The active window is on monitor number: %currentMonitor%`nMonitor Position: Top=%top%, Bottom=%bottom%, Left=%left%, Right=%right%
}
return
The problem is that the index doesn't match. Here's an example of what I mean:
https://imgur.com/YO6OOga

As you can see, I currently have the windows display setting open on monitor index 1, which you can see is highlighted (blue) in the screenshot as well. When I run the above code, it thinks the window is on monitor 3 (top right), but that's not the case here.

Once I've figured out the above, I also need to figure out how to get the monitor index of the top right most monitor.

User avatar
Cr8zy_Ivan
Posts: 131
Joined: 30 Mar 2019, 18:20

Re: Automatic Mapping of All Monitors, Move & Resize Windows

Post by Cr8zy_Ivan » 24 Nov 2023, 03:04

@chaoscreater , thank you for the detailed comment. It is much appreciated! As a very quick reply, not delving too much into the details right now, the "Linear Mapping" (if you will), of the Script should always starts at the Top Left, moving Rightwards, then continue the Numbering on next Row beneath it (if there is another Row), starting from the Leftmost Monitor, as always. My Mapping is independent from the "Windows Display" Numbering. This means that Monitor Number 3 should correspond to "Windows Display" Number 2 we see in the image. This also means that NO MATTER what numbering Windows assigns to the Monitors in this Configuration, the Monitor in Position Number 2, regardless of it's assignment (1, 2, 3 or 4), in YOUR specific Configuration, my Script will always assign Monitor 3 to the Monitor in this Position. i.e. "Windows Display" Numbering → Script Numbering: 4→1, 3→2, 2→3, 1→4.

As for DisplayFusion and ignoring a Monitor, I have to admit I am not familiar with this option! "IF" my Script interacts with this option the way I suspect it does, this would mean that Monitor 2 is invisible to my Script, in which case, Monitor 1 ("Windows Display" Numbering 1) is assigned as Monitor 3 in My Script. i.e. 4→1, 3→2, (2→N/A), 1→3.

Please let me know if I have misunderstood the description of the situation, I'll do my best to address your issue.

Side Notes:
  • My Script, as it is exhibited in this thread, has two types of indexes, a "Linear Mapping" and a "Matrix Mapping". The "Linear Mapping" works as I've described it above. The "Matrix Mapping" assigns Row Numbering and Column Numbering to each Monitor. The caveat with the "Matrix Mapping" as it is now is, the Bottom edge of each Monitor need to be perfectly aligned to be considered to be on the same Row. The same goes for Columns. The Left edge of each Monitor need to be perfectly aligned to be considered to be on the same Column. I still have some work to do in synthesizing and standardizing the different mappings. I also want to make it so that the Monitors don't all have to be perfectly aligned to be assigned a Row and Column.
  • Also, I have been very busy lately and I might not see the comments right away, or I might not be able to respond right away. Thank you for your patience 🙏.

Post Reply

Return to “Scripts and Functions (v1)”