How to Detect When a Window is Resized

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

How to Detect When a Window is Resized

24 Jun 2015, 16:13

Below is an example of code that adds a button to Excel as a child that moves with the Excel Window.

Code: Select all

SetTitleMatchMode, RegEx

Win_Hwnd := WinExist("ahk_exe EXCEL.EXE ahk_class XLMAIN")
WinGetPos,,,Win_W,, ahk_id %Win_Hwnd%
Gui_X := Win_W - 80

; Gui Create
Gui, Font, s12, Bold Verdana
Gui, Margin, 0, 0
Gui, Add, Button, xp yp Default gButton, Button
Gui, +LastFound +ToolWindow +AlwaysOnTop -Caption -Border HWNDGui_Hwnd
DllCall("SetParent", "uint", Gui_Hwnd, "uint", Win_Hwnd)
Gui, Show, x%Gui_X% y52, Button
return

Button:
	MsgBox Click
return
This is all fine and good but I want to be able to detect when a Window is resized so that I can have the buttons position readjust within the Window.

I can use this code to detect when a Window is created and other things:

Code: Select all

DllCall("RegisterShellHookWindow", UInt, A_ScriptHwnd)
		MsgNum := DllCall("RegisterWindowMessage", Str, "SHELLHOOK")
		OnMessage(MsgNum, "ShellMessage")
But SheelHook does not seem to detect Window resize.

Can anyone show me how to use OnMessage or some similar technique to detect when a Window is being resized or has been resized?

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: How to Detect When a Window is Resized

24 Jun 2015, 16:46

SetWinEventHook may be an option, but as you will see there are a lot of messages, even with most of the messages filtered out.

Code: Select all

Gui, +AlwaysOnTop
Gui, Add, ListView, h200 w870, Count|WinTitle|ahk_class|hWinEventHook|event|hwnd|idObject|idChild|dwEventThread|dwmsEventTime
for Col, Width in [50, 150, 100, 100, 50, 80, 80, 50, 100, 100]
    LV_ModifyCol(Col, Width)
Gui, Show, x10 y10
OnExit, UnHook

; ExcelPID is used for the idProcess parameter when calling SetWinEventHook
Process, Exist, EXCEL.EXE
if ErrorLevel
    ExcelPID := ErrorLevel

/*  HWINEVENTHOOK WINAPI SetWinEventHook
 *      - http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx
 *  Event Constants
 *      - http://msdn.microsoft.com/en-us/library/windows/desktop/dd318066%28v=vs.85%29.aspx
 */
;EVENT_OBJECT_CREATE := 0x8000
;EVENT_OBJECT_FOCUS := 0x8005
;EVENT_OBJECT_LOCATIONCHANGE := 0x800B
EVENT_SYSTEM_MOVESIZEEND := 0x000B
EVENT_SYSTEM_MOVESIZESTART := 0x000A
WINEVENT_OUTOFCONTEXT := 0x0
WINEVENT_SKIPOWNPROCESS := 0x2
Hook := DllCall("SetWinEventHook"
    , "UInt",   EVENT_SYSTEM_MOVESIZESTART                      ;_In_  UINT eventMin
    , "UInt",   EVENT_SYSTEM_MOVESIZEEND                        ;_In_  UINT eventMax
    , "Ptr" ,   0x0                                             ;_In_  HMODULE hmodWinEventProc
    , "Ptr" ,   RegisterCallback("WinEventProc")                ;_In_  WINEVENTPROC lpfnWinEventProc
    , "UInt",   ExcelPID                                        ;_In_  DWORD idProcess
    , "UInt",   0x0                                             ;_In_  DWORD idThread
    , "UInt",   WINEVENT_OUTOFCONTEXT|WINEVENT_SKIPOWNPROCESS)  ;_In_  UINT dwflags
return


/*  WinEventProc callback function
 *      - http://msdn.microsoft.com/en-us/library/windows/desktop/dd373885%28v=vs.85%29.aspx
 */
WinEventProc(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
    static Count := 0
    WinGetTitle, WinTitle, ahk_id %hwnd%
    WinGetClass, WinClass, ahk_id %hwnd%
    LV_Insert(1, "", ++Count, WinTitle, WinClass, hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime)
    return
}

UnHook:
DllCall("UnhookWinEvent", "Ptr",Hook)
GuiEscape:
GuiClose:
ExitApp
Edit (~20 min. after initial post): EVENT_SYSTEM_MOVESIZESTART and EVENT_SYSTEM_MOVESIZEEND seem to be better messages to monitor than EVENT_OBJECT_LOCATIONCHANGE. The code in the spoiler tag monitors EVENT_OBJECT_LOCATIONCHANGE, which I found needed much more filtering. It shows a flood of messages while sizing/moving the window. Whereas the edited version above shows a message at the start and stop of the window movement/resize.
Spoiler
User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

Re: How to Detect When a Window is Resized

25 Jun 2015, 16:43

Thank you very much kon.

With your examples and ShellHook I believe I can get the results I am looking for. Between the two a lot of things can be monitored

Code: Select all

EVENT_SYSTEM_MOVESIZEEND := 0x000B
EVENT_SYSTEM_MOVESIZESTART := 0x000A
Works very smoothly for detecting a Window being resized by dragging an edge. Also detects snap to half but does not detect when a window is maximized/restored.

Code: Select all

EVENT_OBJECT_LOCATIONCHANGE := 0x800B
Played around with this but it fires very often. When I used it straight my script became laggy. I could use the dwmsEventTime to limit how often it does something when a window changes size.

Thanks for adding SetWinEventHook to my knowledge base with such nice example code.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
kon
Posts: 1756
Joined: 29 Sep 2013, 17:11

Re: How to Detect When a Window is Resized

25 Jun 2015, 17:15

Glad to hear it's working out. :)

It may be worth reading through the Event Constants page. I was just experimenting with EVENT_SYSTEM_MINIMIZESTART (0x0016) and EVENT_SYSTEM_MINIMIZEEND (0x0017). They seem to work well for detecting minimize and restore (not maximize though). You could set another hook to monitor those messages too, just remember to unhook it when the script closes.
gilliduck
Posts: 265
Joined: 06 Oct 2014, 15:01

Re: How to Detect When a Window is Resized

26 Jun 2015, 11:02

My version isn't fancy with DLL Calls or anything, but it does understand when resized by using a hotkey with the LButton. Not perfect by any means, but it does work.

Code: Select all

SetTitleMatchMode, RegEx

Gui, Font, s12, Bold Verdana
Gui, Margin, 0, 0
Gui, Add, Button, xp yp Default gButton, Button
Gui, +AlwaysOnTop -Caption -Border +HWNDGui_Hwnd
Gosub, gui_update
return
 
Button:
	MsgBox Click
return

~LButton Up::
gui_update:
	Win_Hwnd := WinExist("ahk_exe EXCEL.EXE ahk_class XLMAIN")
	WinGetPos,Win_X,Win_Y,Win_W,Win_H, ahk_id %Win_Hwnd%
	Gui_Y := Win_Y + 52
	Edge_R := Win_W + Win_X
	Gui_X := Edge_R - 80
	WinGet, xl_hidden, MinMax, ahk_id %Win_Hwnd%
	IfWinNotExist, %Win_Hwnd%
		ExitApp
	If (xl_hidden = -1)
		WinHide, ahk_id Gui_Hwnd
	Else
		Gui, Show, x%Gui_X% y%Gui_Y%, Button
	Return
jonathan scott james
Posts: 42
Joined: 05 Apr 2016, 01:56

Re: How to Detect When a Window is Resized

03 May 2018, 11:49

is the "GuiSize:" label is used anywhere in your script then any time a gui is created or changer size, it will be invoked. you can execute any script command you like then "return" normally just like a timer or hotkey

Code: Select all

GuiSize:
soundbeep, 10000,1 ;tie a bell around it's neck so you know it's workling
if ErrorLevel = 1  ; The window has been minimized.  No action needed.
    return
NewWidth := A_GuiWidth - 20
NewHeight := A_GuiHeight - 20
return
User avatar
FanaticGuru
Posts: 1908
Joined: 30 Sep 2013, 22:25

Re: How to Detect When a Window is Resized

03 May 2018, 13:44

jonathan scott james wrote:is the "GuiSize:" label is used anywhere in your script then any time a gui is created or changer size, it will be invoked. you can execute any script command you like then "return" normally just like a timer or hotkey

Code: Select all

GuiSize:
soundbeep, 10000,1 ;tie a bell around it's neck so you know it's workling
if ErrorLevel = 1  ; The window has been minimized.  No action needed.
    return
NewWidth := A_GuiWidth - 20
NewHeight := A_GuiHeight - 20
return
Your post is very true but this thread is all about detecting when any generic window changes size not when a Gui created by AHK changes size.

For example, how to put a Gui button in the bottom right corner of an Excel window that stays in the bottom right corner as the Excel window is resized.

This thread is about creating an event hook that detects when the Excel window is resized so that the Gui button can be moved by AHK to stay in the same relative position in the Excel window.

It is fairly tricky with event hooks to keep an AHK Gui positioned correctly on a generic window but it is very doable.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
drozdman
Posts: 78
Joined: 05 Dec 2015, 01:07

Re: How to Detect When a Window is Resized

15 May 2018, 21:40

FanaticGuru wrote: For example, how to put a Gui button in the bottom right corner of an Excel window that stays in the bottom right corner as the Excel window is resized.
This thread is about creating an event hook that detects when the Excel window is resized so that the Gui button can be moved by AHK to stay in the same relative position in the Excel window.
It is fairly tricky with event hooks to keep an AHK Gui positioned correctly on a generic window but it is very doable.
https://autohotkey.com/boards/viewtopic ... be#p215947
I'm not sure if it's been solved, but this thread kind of did solve it.

You just have to change A_AhkUser script (modified by art) a little bit to include the size of the window instead of the position only.
Maybe like this.

Code: Select all


rel_X:=160, relY:=100
if !WinExist("ahk_class Notepad"){
	run notepad.exe
	WinWaitActive, ahk_class Notepad
}
WinActivate, ahk_class Notepad
WinGet, PID, PID, % "ahk_id " . owner:=WinExist() 
GUI, +ToolWindow +Owner%owner% +Hwndowned
GUI, Show, w100 h300
OnLocationChangeMonitor(owner, owned, PID) ; INIT
WinWaitClose % "ahk_id " . owner 
ExitApp


OnLocationChangeMonitor(_hWinEventHook, _event, _hwnd) { ; https://msdn.microsoft.com/en-us/library/windows/desktop/dd373885(v=vs.85).aspx
	STATIC ox, oy, ow, ownerAhkId, ownedAhkId, hWinEventHook
	global rel_X,relY
	IF !_hwnd	; if the system sent the EVENT_OBJECT_LOCATIONCHANGE event for the caret:
		Return	; https://msdn.microsoft.com/en-us/library/windows/desktop/dd318066(v=vs.85).aspx
	IF !hWinEventHook			; register a event hook function for EVENT_OBJECT_LOCATIONCHANGE := "0x800B"
		hWinEventHook := SetWinEventHook("0x800B", "0x800B",0, RegisterCallback("OnLocationChangeMonitor"),_hwnd,0,0)
		 , ownerAhkId := _hWinEventHook,   ownedAhkId := _event,   OnExit(Func("UnhookWinEvent").Bind(hWinEventHook))
		WinGetPos,  _x,  _y,_w,_h, ahk_id %ownerAhkId%
		WinGetPos, _x1, _y1,,, ahk_id %ownedAhkId%
	iF (_!=ox || _y1!=oy || _w!=ow){
		ow:=_w,ox:=_x,oy:=_y
		WinMove, ahk_id %ownedAhkId%,, % ox:=_x+_w-rel_X, % oy:=_y+relY
	}
}

SetWinEventHook(_eventMin, _eventMax, _hmodWinEventProc, _lpfnWinEventProc, _idProcess, _idThread, _dwFlags) {
   DllCall("CoInitialize", "Uint", 0)
   return DllCall("SetWinEventHook","Uint",_eventMin,"Uint",_eventMax,"Ptr",_hmodWinEventProc,"Ptr",_lpfnWinEventProc,"Uint",_idProcess,"Uint",_idThread,"Uint",_dwFlags)
}  ; cf. https://autohotkey.com/boards/viewtopic.php?t=830
UnhookWinEvent(_hWinEventHook) {
   DllCall("UnhookWinEvent", "Ptr", _hWinEventHook)
   DllCall("CoUninitialize")
}  ; cf. https://autohotkey.com/boards/viewtopic.php?t=830


Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], peter_ahk and 350 guests