detecting hwnd of combobox dropdown in AHK GUI

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
NicSol
Posts: 3
Joined: 12 Jul 2022, 22:01

detecting hwnd of combobox dropdown in AHK GUI

Post by NicSol » 12 Jul 2022, 22:32

Hi folks, first of all, a huge thank you in advance to anyone who even attempts to help with this.

As the title says, I am trying to find the hwnd for the dropdown associated with a combobox control that I've created in a AHK GUI. I've tried several approaches, including DLL calls from various threads on the forum (e.g. viewtopic.php?t=49374) that try to find the parent of a given control, but with no luck. I am about to just resort to using mouse coordinates, but I figured I would see if anyone more knowledgeable might have some insights.

To give a little context to what I'm trying to do: I have a script where an AHK GUI window shows up when I put the mouse in a particular area, stays visible while I do things inside it, and then disappears when I move the mouse away. I have been using MouseGetPos, x, y, id and comparing id to the hwnd of the GUI that I created. It was working great until I added a combobox control, and then when I dropdown and try to select an item, the window disappears. I eventually figured out that the issue is that the combobox dropdown is actually a separate window from the main GUI. But I cannot figure out how to get the hwnd of this window so I know when the mouse is over it. I tried using MouseGetPos, x, y, id, pid and comparing the pid of the main GUI and the dropdown, but even those seem to be different (which I wouldn't have expected).

Here's a minimal example:

Code: Select all

Gui, New, AlwaysOnTop hwndMainGUI, test
Gui, Add, ComboBox, x5 y20 w100 r4 hwndUserComboCtrl, A|B|C|D
Gui, Add, Button, x10 y50 w100 h30, Button1 
Gui, Show, x100 y100 h200 w200

SetTimer, ShowWindowUnderMouse, 200 
return
ShowWindowUnderMouse:
	MouseGetPos, Mxpos, Mypos, Mhwnd
	if (Mhwnd = MainGUI)
		overWin := true
	else
		overWin := false 
	ToolTip, main win hwnd: %MainGUI% `n hwnd under mouse: %Mhwnd% `n overWin? %overWin%
	return
	
GuiClose:
	ExitApp
	return
The tooltip shows the main GUI hwnd, the hwnd under the mouse, and then if they are the same ("overWin"). I would expect if I have the mouse anywhere within the window that overWin would always be true, and for the button, that is what happens....but as soon as you hover over the dropdown, it's false...as if you moved to a different window -- which I guess technically you have. So my question is, how can I figure out the hwnd for this window (the combobox dropdown) so that I can tell when the mouse is over this window rather than having actually moved away from the main GUI?

After struggling with this for hours, I realize the easiest thing might be to just see if the x,y returned by MouseGetPos is within the window boundaries, but I'm still curious if there's a way to do this. Thanks so much for any advice.

User avatar
mikeyww
Posts: 27366
Joined: 09 Sep 2014, 18:38

Re: detecting hwnd of combobox dropdown in AHK GUI

Post by mikeyww » 13 Jul 2022, 06:52

Controls:
HwndOutputVar [v1.0.46.01+]: When used with Gui Add, this option stores the window handle (HWND) of the newly created control in OutputVar. For example: Gui, Add, Edit, vMyEdit HwndMyEditHwnd. When within a function, MyEditHwnd is treated as a function dynamic variable. A control's HWND is often used with PostMessage, SendMessage, and DllCall(). It can also be used directly as an ahk_id WinTitle (this also works on hidden controls even when DetectHiddenWindows is Off) or [in v1.1.04+] with GuiControl and GuiControlGet as the ControlID parameter. On a related note, a parent window's HWND can be retrieved via Gui MyGui:+HwndOutputVar.
Related: https://www.autohotkey.com/docs/commands/WinGet.htm#ControlList

MouseGetPos can also get the classNN under the mouse.
OutputVarControl: This optional parameter is the name of the variable in which to store the name (ClassNN) of the control under the mouse cursor. If the control cannot be determined, this variable will be made blank.

NicSol
Posts: 3
Joined: 12 Jul 2022, 22:01

Re: detecting hwnd of combobox dropdown in AHK GUI

Post by NicSol » 13 Jul 2022, 23:56

Thanks for the reply. I'd tinkered with looking at the control under the mouse as well, but I still run into fundamentally the same problem.
Take for example this slight modification to the script above

Code: Select all

Gui, New, AlwaysOnTop hwndMainGUI, test
Gui, Add, ComboBox, x5 y20 w100 r4 hwndUserComboCtrl, A|B|C|D
Gui, Add, Button, x10 y70 w100 h30, Button1 
Gui, Show, x100 y100 h200 w200

WinGet, CtrlList, ControlListHwnd, ahk_id %MainGUI%

SetTimer, ShowWindowUnderMouse, 200 
return
ShowWindowUnderMouse:
	MouseGetPos, Mxpos, Mypos, Mhwnd, MctrlCN, 2
		overWin := false 
	ToolTip, main win hwnd: %MainGUI% `n window hwnd under mouse: %Mhwnd% `n ctrl hwnd under mouse: %MctrlCN% `n  `n`n List of controls `n%CtrlList%
	return
	
GuiClose:
	ExitApp
	return
So basically I'm getting a list of all the controls, and then showing the control under the mouse. For most mouse positions it works as expected and I could do the appropriate comparison to know I'm over a control that belongs to the window.
ss_1.jpg
ss_1.jpg (47.96 KiB) Viewed 1020 times
But when I mouse over the actual dropdown list I get this:
ss_2.jpg
ss_2.jpg (17.54 KiB) Viewed 1020 times
. Note that the window hwnd changes, and the control hwnd is one not in the list of controls in the GUI

I can get the hwnd of this control (or the classNN), but how do I know, before the fact, anything about that control that associates it with the window I'm interested in? I've also tried getting the hwnd of the combobox control when I create it, but again, I do not know how to determine what the associated dropdown identifiers will be. Forgive me if I'm missing something obvious here

User avatar
mikeyww
Posts: 27366
Joined: 09 Sep 2014, 18:38

Re: detecting hwnd of combobox dropdown in AHK GUI

Post by mikeyww » 14 Jul 2022, 00:26

Hmm. I see. Sorry I do not have the answer. You have explained it well; someone here is likely to know the trick! :think:

User avatar
neovis
Posts: 34
Joined: 12 Jun 2022, 03:56
Location: Republic of Korea
Contact:

Re: detecting hwnd of combobox dropdown in AHK GUI

Post by neovis » 14 Jul 2022, 00:44

I don't know how to get combobox hwnd from sub list hwnd. But I found GetComboBoxInfo function. This is can get list hwnd from combobox hwnd.
Maybe this is help you?

Code: Select all

Gui, New, AlwaysOnTop hwndMainGUI, test
Gui, Add, ComboBox, x5 y20 w100 r4 hwndUserComboCtrl, A|B|C|D
Gui, Add, Button, x10 y70 w100 h30, Button1 
Gui, Show, x100 y100 h200 w200

; Get list hwnd from combobox hwnd
; https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcomboboxinfo
VarSetCapacity(cbi, size := 40+a_ptrSize*3, 0), NumPut(size, cbi, "uint")
if (!DllCall("GetComboBoxInfo", "ptr",UserComboCtrl, "ptr",&cbi))
    throw Exception("GetComboBoxInfo: " a_lastError)
hList := NumGet(cbi, 40+a_ptrSize*2, "ptr") ; hwndList

OnMessage(0x200, "WM_MOUSEMOVE")

WM_MOUSEMOVE(wparam, lparam, msg, hwnd) {
    global hList
    ToolTip % "hwnd: " hwnd "`nhList: " hList
}

NicSol
Posts: 3
Joined: 12 Jul 2022, 22:01

Re: detecting hwnd of combobox dropdown in AHK GUI

Post by NicSol » 16 Jul 2022, 20:29

I think I finally figured it out, thanks to the tips from both of you :bravo:

It turns out there are basically 3 situations that can occur:
1) The mouse is over the main window. This is easy to detect.

2) The mouse is over the combobox dropdown, which is itself actually a new window floating on top of the main window, even though it seems impossible to get its hwnd programmatically. The workaround is to use the code @neovis provided and compare it to the controlhwnd returned by GetMousePos.

3) the mouse is over the combobox dropdown, BUT the combobox dropdown is overlapping another control on the main window, in which case GetMousePos returns the hwnd for the control that is being overlapped by the dropdown. So you also have to get a list of all the controls and if the GetMousePos control hwnd matches any of them.

So here's my final solution to the problem. Hope it helps someone in the future. Thanks to both of you again for the advice!

Code: Select all

Gui, New, AlwaysOnTop hwndMainGUI, test
Gui, Add, ComboBox, x5 y20 w100 r8 hwndUserComboCtrl, A|B|C|D|E|F|G|H|I|J
ComboBoxCtrlArray.push(UserComboCtrl)
Gui, Add, Button, x10 y120 w100 h30, Button1 
Gui, Add, ComboBox, x5 y160 w100 r8 hwndUserComboCtrl2, A|B|C|D|E|F|G|H|I|J
ComboBoxCtrlArray.push(UserComboCtrl2)
Gui, Show, x100 y100 h200 w200

SetTimer, ShowWindowUnderMouse, 200 
return

ShowWindowUnderMouse:
	MouseGetPos, Mxpos, Mypos, Mhwnd, Mctrlhw, 2
	ToolTip, % "Is mouse over window? " . isMouseOverWindow(MainGUI)
	return
	
GuiClose:
	ExitApp
	return	
	
isMouseOverWindow(hwndGUIWin){
	MouseGetPos, Mxpos, Mypos, Mhwnd, Mctrlhw, 2
	ComboBoxhw := -1 
	WinGet, CtrlList, ControlListHwnd, ahk_id %hwndGUIWin%
	
	;mouse is over the GUI window 
	if (Mhwnd == hwndGUIWin)
		return 1
	
	; loop through each control  
	Loop, Parse, CtrlList, `n 
	{  
		; mouse is over one of the controls
		if (Mctrlhw = A_LoopField)
			return 1
		
		; get combobox hwnd 
		WinGetClass, CtrlClass, ahk_id %A_LoopField%
		if (CtrlClass == "ComboBox"){
			; Get list hwnd from combobox hwnd
			; https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcomboboxinfo
			VarSetCapacity(cbi, size := 40+a_ptrSize*3, 0), NumPut(size, cbi, "uint")
			if (!DllCall("GetComboBoxInfo", "ptr",A_LoopField, "ptr",&cbi))
				throw Exception("GetComboBoxInfo: " a_lastError)
			ComboBoxhw := NumGet(cbi, 40+a_ptrSize*2, "ptr") 
			
			; mouse is over a combobox dropdown
			if (Mctrlhw == ComboBoxhw)
				return 1				
		}
	}
	return 0 
}

Post Reply

Return to “Ask for Help (v1)”