#include-once
#include <WinAPIGdi.au3>			; Used by _WinAPI_EnumDisplayMonitors, _WinAPI_GetMousePos, _WinAPI_MonitorFromPoint and _WinAPI_GetPosFromRect
#include <StructureConstants.au3>	; DLLStruct Windows API constants used by function CheckCoordinatesInRange

; ==> Example for invoking found in MoveToActiveDisplay.au3 on https://autoit.de/thread/86942-autoit-script-f%C3%BCr-multi-bildschirm-betrieb/

; #FUNCTION# ====================================================================================================================
; Name ..........: MoveWindowsToActiveDisplay
; Description ...: Move a window to the active display monitor in a 2 display configuration
;                  (active window is considered to be where the mouse is located)
; Syntax ........: MoveWindowsToActiveDisplay($ParmWindowTitle[, $ParmWindowText = ""])
; Parameters ....: $ParmWindowTitle     - The title/hWnd/class of the window to move
;                  $ParmWindowText      - The text of the window to check. Default is an empty string.
;                  $ParmTimeOut         - Timeout in seconds if the window is not existing/active while starting func. Default is 3
;                  $ParmActivateWindow  - Window will be activated to bring it to the foregound if value is 1. Default is 1
; Return values .: 1 - function completed sussfully
;                  0 - an error has occued
; Author ........: PapaPeter
; Modified ......: 4.5.2020, considering recommendations from Bitnugger
; Remarks .......: error codes: 1 - Given window doesn't exist
;                               2 - No display regonized
;                               3 - no active display monitor found
;                  Tested with AutoIt Version 3.3.14.2
; Related .......: auxiliary function CheckCoordinatesInRange is used
; Link ..........: https://autoit.de/thread/86942-autoit-script-f%C3%BCr-multi-bildschirm-betrieb/
; Example .......: MoveWindowsToActiveDisplay("Untitled - Notepad")
; ===============================================================================================================================
Func MoveWindowsToActiveDisplay($ParmWindowTitle, $ParmWindowText="", $ParmTimeOut=3, $ParmActivateWindow=1)
	; Initialization
	Local $ReturnValue = 1													; If no error occurs ReturnValue is 1

	; Activate window in max $ParmTimeOut seconds or wait $ParmTimeOut seconds for window to exist
	If  $ParmActivateWindow=1 then											; If window should be activated
		WinActivate($ParmWindowTitle, $ParmWindowText)							; use commbination WinActivate/WinWaitActive to ensure that window is already existing and visible
		WinWaitActive($ParmWindowTitle, $ParmWindowText, $ParmTimeOut)			; wait $ParmTimeOut seconds max for window to be activated
	Else																	; If window should not be activated
		Local $Count=1															; while loop for windows, loop will be skipped after $ParmTimeOut seconds or if window exists
		While ($Count>$ParmTimeOut And WinExists($ParmWindowTitle, $ParmWindowText))
			Sleep(1000)
			$Count+=1
		WEnd
	EndIf

	if WinExists($ParmWindowTitle) Then										; Check if given window exist (not ensured with code above)
		Local $WindowCoordinates=WinGetPos($ParmWindowTitle,$ParmWindowText)	; Read coordinates of the given window
																				;    Remark 1: WinGetPos will fail if windows does not exist and as result $WindowCoordinates is no array,
																				;    Remark 2: As also above and below $ParmWindowTitle can be title, window handle or class of the window

		; Get actual active displaymonitor handle out of mouse position
		Local $MousePos = _WinAPI_GetMousePos()									; Reads out actual mouse position
		Local $ActualMonitorHandle = _WinAPI_MonitorFromPoint($MousePos)		; get displaymonitor handle belonging to mouse position

		; Gets array displaymonitor handles and number of connected displays
		Local $DisplayList = _WinAPI_EnumDisplayMonitors()						; Result enumerates display monitors (including invisible pseudo-monitors associated with the mirroring drivers)
																				; element[0][0] contains the number of rows (displaymonitors) in array

		; Search for active displaymonitor handle in array and if move window if neccesary
		If IsArray($DisplayList) Then											; if we get a valid list of display monitors
			Local $ActiveDisplay=0													; set default value for active display monitor
			; Lese Parameter des aktiven Fensters aus
			For $DisplayCount = 1 To $DisplayList[0][0]								; Loop for all display monitors ($DisplayList[0][0] contains the number of displaymonitors)
				if $DisplayList[$DisplayCount][0]= $ActualMonitorHandle Then					; Compare handle in list with previously determined handle of the active displaymonitor
					Local $ActiveDisplayData = _WinAPI_GetPosFromRect($DisplayList[$DisplayCount][1])	; If active display monitor is found get coordinate data to array $ActiveDisplayData
				EndIf
			Next
			If IsArray($ActiveDisplayData) Then										; If we get a valid result for $ActiveDisplayData
				; Check if we need to move window
				if Not CheckCoordinatesInRange($WindowCoordinates, $ActiveDisplayData)=1 Then	; yes we have
					; Move window with the offset of the coordinate of left top corner of the active display monitor
					; Remark for further versions: Check if in display monitor configuration with 3 and more display monitors this will work too!
					; 							   We may have to consider offset on local displaymonitor, if the window was on one of other display monitors except primary display
					WinMove($ParmWindowTitle, $ParmWindowText, $WindowCoordinates[0]+ $ActiveDisplayData[0], $WindowCoordinates[1]+$ActiveDisplayData[1])
					If  $ParmActivateWindow=1 then
						WinActivate($ParmWindowTitle,$ParmWindowText)									   ; activate window to get it to foreground
					EndIf
				EndIf
			Else																	; If we dont get a valid result for $ActiveDisplayData (no active display monitor found)
				SetError(3, 0, 0)														; set return value to 0 and error code to 3
				$ReturnValue = 0
			EndIf
		Else																	; if we dont get a valid list of display monitors (no display monitor regonized)
			SetError(2, 0, 0)															; set return value to 0 and error code to 2
			$ReturnValue = 0
		EndIf
	Else																	; Given window doesn't exist
		SetError(1, 0, 0)														; set return value to 0 and error code to 1
		$ReturnValue = 0
	EndIf

	Return $ReturnValue
EndFunc		; ==> MoveWindowToActiveDisplay()

; #FUNCTION# ====================================================================================================================
; Name ..........: CheckCoordinatesInRange
; Description ...: Checks if the coordinates in $Parm_CheckCoordinatesArray are in range of the area defined in $Parm_DisplayArray
; Syntax ........: CheckCoordinatesInRange($Parm_CheckCoordinatesArray, $Parm_DisplayArray)
; Parameters ....: $Parm_CheckCoordinatesArray- Array with at least 2 entries for X and Y coordinate.
;                  $Parm_DisplayArray   - Array reprenting an aera, at least entries for X and Y (top left corner), width and height.
; Return values .: 1 - coordinates in area
;                  0 - coordinates not in area
; Author ........: BugFix, based on a script written by PapaPeter
; Modified ......: 3.5.2020 by BugFix
; Remarks .......: error codes: 1 - $Parm_CheckCoordinatesArray is no array
;                               2 - $Parm_DisplayArray is no array
;                  Tested with AutoIt Version 3.3.14.2
; Related .......: Used by MoveWindowsToActiveDisplay as auxiliary function
; Link ..........: https://autoit.de/thread/86942-autoit-script-f%C3%BCr-multi-bildschirm-betrieb/
; Example .......: No
; ===============================================================================================================================
Func CheckCoordinatesInRange($Parm_CheckCoordinatesArray, $Parm_DisplayArray)
    Local $iErr = IsArray($Parm_CheckCoordinatesArray) ? 0 : 1
    $iErr += IsArray($Parm_DisplayArray) ? 0 : 2
    If $iErr Then Return SetError($iErr,0,-1)
    Local $tPt = DllStructCreate($tagPoint)
    $tPt.X = $Parm_CheckCoordinatesArray[0]
    $tPt.Y = $Parm_CheckCoordinatesArray[1]
    Local $tRect = DllStructCreate($tagRECT)
    $tRect.Left = $Parm_DisplayArray[0]
    $tRect.Top = $Parm_DisplayArray[1]
    $tRect.Right = $Parm_DisplayArray[2]
    $tRect.Bottom = $Parm_DisplayArray[3]
    Return _WinAPI_PtInRect($tRect, $tPt)
EndFunc		; ==> CheckCoordinatesInRange()
