Jump to content

Is there any way to get window classname on mouse click?


Go to solution Solved by Nine,

Recommended Posts

Posted (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 by WildByDesign
Posted (edited)

:unsure:

#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 by ioa747

I know that I know nothing

Posted (edited)

I have done some work around this quite some times ago :

#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 by Nine
Posted
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. :)

Posted

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%.

Posted

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?

 

#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
Posted

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...

Posted

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.

 

Posted
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.

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...