Page 1 of 1

[Script] enlarge any window at "maximize" to max size to remain moveable on multiple monitors

Posted: 30 Jan 2018, 03:07
by pramach
Hi
When maximize a window it can - under some circumstances - no longer be moved from one monitor to another.
At least this what I discovered in Win10.

The following script solved this by:
- work on any single window of any application
- check constantly if a window is maximized
- undo the maximize but extend the window to full screen width & height
- "maximize" a such full screen window will normalize the window back to size fefore first "maximize" action was triggered
- Same behaviour if you click on the maximize icon in the title bar or doubleclick on the titlebar
- Maximize a window keep the window at the current monitor
- Undo the maximize also keep the window at the current monitor

The script has been tested with 2 monitors of same size & resolution. It has been tested on a variety of applications like IE, Edge, MS Office, Notepad++, Total Comander, and several more.

During development, I get various help here in the forum. Thanks for !

Enjoy

Code: Select all

; ===============================================
; enlarge any window at "maximize" to max size to remain moveable on multiple monitors
; ===============================================
; Wolfgang Studer, 2018
; ===============================================
#Persistent
#SingleInstance, force
MaximizedWindows := {}
SetTimer, WatchMaximizedWindow, 1000
return

; See : https://autohotkey.com/boards/viewtopic.php?f=5&t=43488&p=197401#p197401
WatchMaximizedWindow:
	global MaximizedWindows
	WinGet, WinId, List,,, Program Manager
	Loop, % WinId
	{
		hwnd :=  WinId%A_Index%
		this_key := "ahk_id " . hwnd

		; get current window positions
		WinGetPos, winX, winY, WinW, WinH, % this_key
		; and Minimum/Maximum status
		winGet, isMinMax, MinMax, % this_key
		if ( isMinMax = 1 )
		{
			; get monitor Number
			winMonitorNbr := getMonitorIndexFromWindow(this_key)

			; check if current id is in list of maximzed windows
			; if yes, remove from list and continue with next window
			if ( MaximizedWindows.HasKey( this_key ) = True && MaximizedWindows[this_key].IsMax = 1 )
			{
				if ( MaximizedWindows[this_key].HasKey( "Monitor" ) = False )
					MaximizedWindows[this_key]["Monitor"] := winMonitorNbr	; should theoretically never happen but ....

				; adapt windows position if monitor has been changed
				if ( MaximizedWindows[this_key].Monitor != winMonitorNbr )
				{
					sysGet, monOld, monitor, % MaximizedWindows[this_key].Monitor
					sysGet, monNew, monitor, % winMonitorNbr
					if ( monOldLeft != monNewLeft )
						MaximizedWindows[this_key].winX += ( monNewLeft - monOldLeft )
					if ( monOldTop != monNewTop )5
						MaximizedWindows[this_key].winY += ( monNewTop - monOldTop )
				}

				; reset maximized flag
				MaximizedWindows[this_key]["IsMax"] := 0
				; move to last known size & position
				winMoveSmooth( hwnd, MaximizedWindows[this_key].winX, MaximizedWindows[this_key].winY, MaximizedWindows[this_key].winW, MaximizedWindows[this_key].winH )
				; continue with next window
				continue
			}

			; Save maximized flag and monitor Number
			MaximizedWindows[this_key]["IsMax"] := 1
			MaximizedWindows[this_key]["Monitor"] := winMonitorNbr	; needed only when window is maximized

			; check which monitor it's on (SysGet) and move (WinMove)
			sysGet, mon, monitor, % winMonitorNbr
			winMoveSmooth( hwnd, monLeft, monTop, monRight - monLeft, monBottom - monTop )
		}

		; save if not maximized
		if ( MaximizedWindows.HasKey( this_key ) = False ||  MaximizedWindows[this_key].IsMax != 1 )
			MaximizedWindows[this_key] := { winX: winX, winY: winY, winW: winW, winH: winH }
	}
	return

getMonitorIndexFromWindow( winTitle="A", byref monRet="")
{
	winGet,hwnd, id, % winTitle
	varSetCapacity(monInfo,40),numPut(40, monInfo)

	mon := []
	if( monHandle:=dllCall("MonitorFromWindow","UInt",hwnd,"UInt",0x2))
		&& dllCall("GetMonitorInfo","UInt",monHandle,"UInt",&monInfo)
	{
		loop 4	; x, y, w, h
			mon[a_index]:= numGet(monInfo,4*a_index,"Int")

		sysGet,monCount,monitorCount
		loop % monCount
		{
			sysGet,iMon,Monitor,% a_index

			; Compare location to determine the monitor index.
			if(mon[1]=iMonLeft && mon[2]=iMonTop && mon[3]=iMonRight && mon[4]=iMonBottom)
			{
				monIndex := a_index
				break
			}
		}
	}
	if(monRet)
		monRet:=mon

	return monIndex?monIndex:1
}

winMoveSmooth( hwnd, tgtX, tgtY, tgtW, tgtH )
{
	; https://autohotkey.com/board/topic/63504-hidden-window-shows-when-moved/
	; Initialize WINDOWPLACEMENT structure.
	VarSetCapacity(wp, 44, 0), NumPut(44, wp, 0, "uint")

	; Get current placement.
	DllCall("GetWindowPlacement", "ptr", hwnd, "ptr", &wp)

;    wp_length := NumGet(wp, 0, "UInt")
;    wp_flags := NumGet(wp, 4, "UInt")
;    wp_showCmd := NumGet(wp, 8, "UInt")
;    wp_ptMinPosition_X := NumGet(wp, 12, "Int")
;    wp_ptMinPosition_Y := NumGet(wp, 16, "Int")
;    wp_ptMaxPosition_X := NumGet(wp, 20, "Int")
;    wp_ptMaxPosition_Y := NumGet(wp, 24, "Int")
;    wp_rcNormalPosition_left := NumGet(wp, 28, "Int")
;    wp_rcNormalPosition_top := NumGet(wp, 32, "Int")
;    wp_rcNormalPosition_right := NumGet(wp, 36, "Int")
;    wp_rcNormalPosition_bottom := NumGet(wp, 40, "Int")

	; overwrite settings
	wp_flags := 4			; WPF_ASYNCWINDOWPLACEMENT
	wp_showCmd := 1			; SW_SHOWNORMAL
	wp_rcNormalPosition_left := tgtX
	wp_rcNormalPosition_top := tgtY
	wp_rcNormalPosition_right := tgtX + tgtW
	wp_rcNormalPosition_bottom := tgtY + tgtH

	; update placement
	NumPut(wp_flags, wp, 4, "uint")
	NumPut(wp_showCmd, wp, 8, "uint")
	NumPut(wp_rcNormalPosition_left, wp, 28, "int")
	NumPut(wp_rcNormalPosition_top, wp, 32, "int")
	NumPut(wp_rcNormalPosition_right, wp, 36, "int")
	NumPut(wp_rcNormalPosition_bottom, wp, 40, "int")

	; Set new placement.
	DllCall("SetWindowPlacement", "ptr", hwnd, "ptr", &wp)
}

Re: [Script] enlarge any window at "maximize" to max size to remain moveable on multiple monitors

Posted: 30 Jan 2018, 06:00
by pramach
Hi
In case your max size window is too high, you can reduce the height by simple add an additional reduction when doing the move

Code: Select all

			; check which monitor it's on (SysGet) and move (WinMove)
			sysGet, mon, monitor, % winMonitorNbr
			winMoveSmooth( hwnd, monLeft, monTop, monRight - monLeft, monBottom - monTop - 40 )
In the example above I reduce the height by additional 40 pixels.

Re: [Script] enlarge any window at "maximize" to max size to remain moveable on multiple monitors

Posted: 07 Feb 2018, 08:23
by SvenBent
I would avoid using a check interval
1: It gobles up unneeded CPU power ( even though its very little)
2: it creates a delay for the effect to kick in. in this case up to a second.

To eliminate these two you should be using a shellhook instead
https://autohotkey.com/board/topic/8064 ... -messages/
This way you program reacts immediately on the maximize windows command.

Re: [Script] enlarge any window at "maximize" to max size to remain moveable on multiple monitors

Posted: 08 Feb 2018, 01:57
by pramach
Hmmmm

Hi Sven
I made some very simple tryouts

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#Persistent
#SingleInstance, force

Gui +LastFound
DllCall( "RegisterShellHookWindow", UInt, WinExist() )
MsgNum := DllCall( "RegisterWindowMessage", Str,"SHELLHOOK" )
OnMessage( MsgNum, "ShellMessage" )
return

ShellMessage( wParam, lParam )
{
	if ( wParam < 10 )
		msgbox % "Shellmessage: " wParam
}
As you can see, nothing special

When started, I get randomly the msgbox with wParam 2 and 6, without the if statement also 32337.
I say randomly, because I do not get it always when I maximize a window and I never get any when I normalize a window.
However I get a 2 when I change something inside a window ....

Win10, 64 bit

Re: [Script] enlarge any window at "maximize" to max size to remain moveable on multiple monitors

Posted: 08 Feb 2018, 02:42
by SL5
sorry misunderstud. i delete my post