WildByDesign Posted Friday at 11:07 AM Posted Friday at 11:07 AM (edited) I'm just wondering if there is a way to get the window classname of anything that I click on with the mouse. I have something going that mostly does what I need but it's using a hook. I'd rather not use a hook if there is a simpler way to achieve this particular task. Although obtaining the window classname on every single mouse click might end up being heavier than a hook. I'm just not sure and have zero experience in mouse click related functions in AutoIt. Thank you. Updated Description: Basically, anytime the user clicks on the desktop (therefore Progman classname), a function is run. Currently, I am using a WinEventHook and actions are being taken based on EVENT_OBJECT_FOCUS events (EVENT_SYSTEM_FOREGROUND works just as well). Anytime Progman becomes the Active window, a function is run. This is good. However, the problem is that in order to be able to run that function again, I have to click on another window (eg. Taskbar) and then click back on the desktop. I would like to be able to click on the desktop several times in a row to run the function without having to click back and forth to another window each time. Therefore, in that regard, the WinEventHook method is not doing what I need 100%. Edited Friday at 01:07 PM by WildByDesign
ioa747 Posted Friday at 12:17 PM Posted Friday at 12:17 PM (edited) #include <WinAPISysWin.au3> Global $g_hActWnd While Sleep(50) _GetActiveWindow() WEnd Func _GetActiveWindow() Local $AnyWindow, $sWindowTitle, $sClassName $AnyWindow = WinGetHandle("[ACTIVE]") If $g_hActWnd <> $AnyWindow Then $g_hActWnd = $AnyWindow ConsoleWrite("$g_hActWnd=" & $g_hActWnd & @CRLF) $sWindowTitle = WinGetTitle($g_hActWnd) ConsoleWrite("$sWindowTitle=" & $sWindowTitle & @CRLF) $sClassName = _WinAPI_GetClassName($g_hActWnd) ConsoleWrite("$sClassName=" & $sClassName & @CRLF) ConsoleWrite("" & @CRLF) EndIf EndFunc ;==>_GetActiveWindow Edited Friday at 12:18 PM by ioa747 WildByDesign 1 I know that I know nothing
Nine Posted Friday at 12:27 PM Posted Friday at 12:27 PM (edited) I have done some work around this quite some times ago : expandcollapse popup#include <WinAPI.au3> Opt("MustDeclareVars", True) HotKeySet("{ESC}", Terminate) Example() Func Example() Local $hWnd, $hRoot, $hWnd2, $hWnd_Old = -1, $tPoint While Sleep(50) $tPoint = _WinAPI_GetMousePos() $hWnd = _WinAPI_WindowFromPoint($tPoint) $hWnd2 = GetRealChild($hWnd) If $hWnd2 And $hWnd <> $hWnd2 Then $hWnd = $hWnd2 If $hWnd <> $hWnd_Old Then ConsoleWrite(_WinAPI_GetClassName($hWnd) & @CRLF) $hWnd_Old = $hWnd EndIf WEnd EndFunc ;==>Example Func Terminate() Exit EndFunc ;==>Terminate Func _WinAPI_RealChildWindowFromPoint($hWnd, $tPoint) Local $aRet = DllCall('user32.dll', 'hwnd', 'RealChildWindowFromPoint', 'hwnd', $hWnd, 'struct', $tPoint) If @error Then Return SetError(@error, @extended, 0) Return $aRet[0] EndFunc ;==>_WinAPI_RealChildWindowFromPoint Func GetRealChild($hWnd) Local $tPoint, $hRoot = _WinAPI_GetAncestor($hWnd, $GA_ROOT) If $hWnd = $hRoot Then $tPoint = _WinAPI_GetMousePos(True, $hWnd) Return _WinAPI_ChildWindowFromPointEx($hWnd, $tPoint) EndIf Local $hParent = _WinAPI_GetAncestor($hWnd, $GA_PARENT) Local $aChild = _WinAPI_EnumChildWindows($hParent) If @error Then Return 0 Local $hFound For $i = 1 To $aChild[0][0] $hParent = _WinAPI_GetParent($aChild[$i][0]) $tPoint = _WinAPI_GetMousePos(True, $hParent) $hFound = _WinAPI_RealChildWindowFromPoint($hParent, $tPoint) If $hFound = $aChild[$i][0] Then Return $hFound Next Return 0 EndFunc ;==>GetRealChild ps. It works on mouse hover, you will need to adapt it for mouse click... Edited Friday at 12:33 PM by Nine WildByDesign 1 “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
WildByDesign Posted Friday at 12:43 PM Author Posted Friday at 12:43 PM 12 minutes ago, Nine said: ps. It works on mouse hover, you will need to adapt it for mouse click... Thank you. This is quite beautiful and works incredibly well. I think that the only thing that I really need to do for my needs is combine yours with checking the active window (similar to @ioa747's example) because that active window would have been clicked at some point anyway to become active. Well, not necessarily I suppose. But active window combined with your example should do what I need. I'll try to integrate it into my project and will post back here on how it goes.
WildByDesign Posted Friday at 12:51 PM Author Posted Friday at 12:51 PM I'm kind of brainstorming right now. I assume that I cannot use WM_MOUSEACTIVATE since it's not my GUI window. It's any other running and visible windows, so I don't think that would work.
WildByDesign Posted Friday at 01:06 PM Author Posted Friday at 01:06 PM I realize that my first post doesn't explain very well what the goal is. I will update the OP as well. Basically, anytime the user clicks on the desktop (therefore Progman classname), a function is run. Currently, I am using a WinEventHook and actions are being taken based on EVENT_OBJECT_FOCUS events (EVENT_SYSTEM_FOREGROUND works just as well). Anytime Progman becomes the Active window, a function is run. This is good. However, the problem is that in order to be able to run that function again, I have to click on another window (eg. Taskbar) and then click back on the desktop. I would like to be able to click on the desktop several times in a row to run the function without having to click back and forth to another window each time. Therefore, in that regard, the WinEventHook method is not doing what I need 100%.
WildByDesign Posted Friday at 03:30 PM Author Posted Friday at 03:30 PM OK so I have something that is working right now for the most part. It's only capturing left mouse button click at the moment. I will add more later. This is really quite incredible and I can see this functionality benefiting me in a few projects. I have one problem. For this particular project, I only need the top-level window. For example, when I click on most areas of Notepad, it gives me the Edit control handle which makes sense since that is what covers most of it. If I click on the titlebar of Notepad, it gives me Notepad class handle. How can I get it to show the top-level window only? expandcollapse popup#include <Misc.au3> #include <MsgBoxConstants.au3> #include <WinAPIvkeysConstants.au3> #include <WinAPI.au3> HotKeySet("{ESC}", Terminate) Example() Func Example() Local $hWnd, $hRoot, $hWnd2, $hWnd_Old = -1, $tPoint Local $asModifierKeys[6] = [0, "VK_SHIFT", "VK_CONTROL", "VK_MENU", "VK_LWIN", "VK_RWIN"] Local $aKeys[1] = [$VK_LBUTTON] While 1 Local $iRet = _IsPressed($aKeys, Default, True) ; Check modifier If Not $iRet And @extended Then ConsoleWrite("The modifier key " & $asModifierKeys[@extended] & " has been pressed. @extended = " & @extended & @CRLF) Local $sKey Switch $iRet Case 1 ; MouseClick Left $sKey = "{LBUTTON}" $tPoint = _WinAPI_GetMousePos() $hWnd = _WinAPI_WindowFromPoint($tPoint) $hWnd2 = GetRealChild($hWnd) If $hWnd2 And $hWnd <> $hWnd2 Then $hWnd = $hWnd2 If $hWnd <> $hWnd_Old Then ConsoleWrite(_WinAPI_GetClassName($hWnd) & @CRLF) $hWnd_Old = $hWnd EndIf EndSwitch Sleep(100) WEnd EndFunc Func Terminate() Exit EndFunc ;==>Terminate Func _WinAPI_RealChildWindowFromPoint($hWnd, $tPoint) Local $aRet = DllCall('user32.dll', 'hwnd', 'RealChildWindowFromPoint', 'hwnd', $hWnd, 'struct', $tPoint) If @error Then Return SetError(@error, @extended, 0) Return $aRet[0] EndFunc ;==>_WinAPI_RealChildWindowFromPoint Func GetRealChild($hWnd) Local $tPoint, $hRoot = _WinAPI_GetAncestor($hWnd, $GA_ROOT) If $hWnd = $hRoot Then $tPoint = _WinAPI_GetMousePos(True, $hWnd) Return _WinAPI_ChildWindowFromPointEx($hWnd, $tPoint) EndIf Local $hParent = _WinAPI_GetAncestor($hWnd, $GA_PARENT) Local $aChild = _WinAPI_EnumChildWindows($hParent) If @error Then Return 0 Local $hFound For $i = 1 To $aChild[0][0] $hParent = _WinAPI_GetParent($aChild[$i][0]) $tPoint = _WinAPI_GetMousePos(True, $hParent) $hFound = _WinAPI_RealChildWindowFromPoint($hParent, $tPoint) If $hFound = $aChild[$i][0] Then Return $hFound Next Return 0 EndFunc ;==>GetRealChild
Solution Nine Posted Friday at 05:41 PM Solution Posted Friday at 05:41 PM Then you do not need all of it, just get ancestor : #include <WinAPI.au3> Opt("MustDeclareVars", True) HotKeySet("{ESC}", Terminate) Example() Func Example() Local $hWnd, $hWnd_Old = -1, $tPoint While Sleep(50) $tPoint = _WinAPI_GetMousePos() $hWnd = _WinAPI_GetAncestor(_WinAPI_WindowFromPoint($tPoint), $GA_ROOT) If $hWnd <> $hWnd_Old Then ConsoleWrite(_WinAPI_GetClassName($hWnd) & @CRLF) $hWnd_Old = $hWnd EndIf WEnd EndFunc ;==>Example That should do it, I think... “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
WildByDesign Posted Friday at 08:45 PM Author Posted Friday at 08:45 PM 3 hours ago, Nine said: That should do it, I think... Well this is absolutely phenomenal! Short, sweet and fast piece of code. Thank you for your time.
junkew Posted Saturday at 12:57 PM Posted Saturday at 12:57 PM Some other topics you could look into all with their own pro and cons. With IUIAutomation you can "subscribe" to these events a little bit higher then diving into the system hooks which are relatively hard without a separate dll doing the work. There are many examples on the MS IUIAutomation on determining windows and catching events. WildByDesign 1 FAQ 31 How to click some elements, FAQ 40 Test automation with AutoIt, Multithreading CLR .NET Powershell CMDLets
WildByDesign Posted 13 hours ago Author Posted 13 hours ago 23 hours ago, junkew said: With IUIAutomation you can "subscribe" to these events a little bit higher then diving into the system hooks which are relatively hard without a separate dll doing the work. This sounds really interesting. I will spend some time today learning some more about IUIAutomation in general. And the great thing about this forum is the fact that there is a gold mine of examples throughout the forum and so many users willing to help. Thank you. argumentum 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now