bo8ster Posted April 1, 2010 Posted April 1, 2010 The issue is: WindowFromPoint should return the handle of the window where the mouse is. This only happens when the window is maximised.When the window is not maximised the handle returned is the next window in sequence that is maxmised. matchWinHandle() confirms this.To test, run this script in Scite when it is not maximised. The handle returned should be to Window Handle to Scite but it is not. I expaned the window to cover the entire screen to be sure. Maybe I am missing something but I cannot see it. expandcollapse popup#include <WinAPI.au3> #include <Array.au3> AutoItSetOption("MustDeclareVars", 1) AutoItSetOption("MouseCoordMode", 2) AdlibRegister("_Mouse_Control_GetInfoAdlib", 10) HotKeySet("^!x", "MyExit") ; Press Ctrl+Alt+x to stop the script ;~ #AutoIt3Wrapper_run_debug_mode=Y Global $pos1 = MouseGetPos() Global $pos2 = MouseGetPos() ; must be initialized Global $appHandle = 0 While 1 Sleep(0xFFFFFFF) WEnd Func _Mouse_Control_GetInfoAdlib() $pos1 = MouseGetPos() If $pos1[0] <> $pos2[0] Or $pos1[1] <> $pos2[1] Then ; has the mouse moved? Local $a_info = _Mouse_Control_GetInfo() $pos2 = MouseGetPos() EndIf EndFunc ;==>_Mouse_Control_GetInfoAdlib Func _Mouse_Control_GetInfo() $appHandle = GetHoveredHwnd() ; Uses the mouse to do the equivalent of WinGetHandle() matchWinHandle($appHandle) Return 0 EndFunc ;==>_Mouse_Control_GetInfo ; =============================================================================== ; Retrieves the Handle of GUI/Application the mouse is over. ; Similar to WinGetHandle except it used the current mouse position (Client Coords) ; Taken from http://www.autoitscript.com/forum/index.php?showtopic=444962 ; =============================================================================== Func GetHoveredHwnd() Local $iRet = DllCall("user32.dll", "int", "WindowFromPoint", "long", MouseGetPos(), "long", MouseGetPos()) If IsArray($iRet) Then $appHandle = $iRet[0] Return HWnd($iRet[0]) Else Return SetError(1, 0, 0) EndIf EndFunc ;==>GetHoveredHwnd Func matchWinHandle($hParent) Local $aWinList = WinList() Local $flag = 0; For $i = 0 To UBound($aWinList) - 1 If $aWinList[$i][1] = $hParent Then ConsoleWriteError("hParent match is - " & $aWinList[$i][0] & @LF) ; print the display name of the window handle $flag = 1 ;~ _ArrayDisplay($aWinList) ExitLoop EndIf Next If $flag = 0 Then ConsoleWriteError("No windows handle match found in WinList" & @LF) EndIf EndFunc ;==>matchWinHandle Func MyExit() ; stops the script ConsoleWrite("Script Stoppted By User" & @CR) Exit EndFunc ;==>MyExit Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]
Ascend4nt Posted April 1, 2010 Posted April 1, 2010 WindowFromPoint will get non-window elements like controls as well as windows. Just do a check with _WinAPI_GetAncestor($hWin,2) to see if it matches. If not, then use the result as the 'real' window. My contributions: Performance Counters in Windows - Measure CPU, Disk, Network etc Performance | Network Interface Info, Statistics, and Traffic | CPU Multi-Processor Usage w/o Performance Counters | Disk and Device Read/Write Statistics | Atom Table Functions | Process, Thread, & DLL Functions UDFs | Process CPU Usage Trackers | PE File Overlay Extraction | A3X Script Extract | File + Process Imports/Exports Information | Windows Desktop Dimmer Shade | Spotlight + Focus GUI - Highlight and Dim for Eyestrain Relief | CrossHairs (FullScreen) | Rubber-Band Boxes using GUI's (_GUIBox) | GUI Fun! | IE Embedded Control Versioning (use IE9+ and HTML5 in a GUI) | Magnifier (Vista+) Functions UDF | _DLLStructDisplay (Debug!) | _EnumChildWindows (controls etc) | _FileFindEx | _ClipGetHTML | _ClipPutHTML + ClipPutHyperlink | _FileGetShortcutEx | _FilePropertiesDialog | I/O Port Functions | File(s) Drag & Drop | _RunWithReducedPrivileges | _ShellExecuteWithReducedPrivileges | _WinAPI_GetSystemInfo | dotNETGetVersions | Drive(s) Power Status | _WinGetDesktopHandle | _StringParseParameters | Screensaver, Sleep, Desktop Lock Disable | Full-Screen Crash Recovery Wrappers/Modifications of others' contributions: _DOSWildcardsToPCRegEx (original code: RobSaunder's) | WinGetAltTabWinList (original: Authenticity) UDF's added support/programming to: _ExplorerWinGetSelectedItems | MIDIEx UDF (original code: eynstyne) (All personal code/wrappers centrally located at Ascend4nt's AutoIT Code)
Zedna Posted April 1, 2010 Posted April 1, 2010 ; =============================================================================== ; Retrieves the Handle of GUI/Application the mouse is over. ; Similar to WinGetHandle except it used the current mouse position (Client Coords) ; Taken from http://www.autoitscript.com/forum/index.php?showtopic=444962 ; =============================================================================== Func GetHoveredHwnd() Local $iRet = DllCall("user32.dll", "int", "WindowFromPoint", "long", MouseGetPos(), "long", MouseGetPos()) If IsArray($iRet) Then $appHandle = $iRet[0] Return HWnd($iRet[0]) Else Return SetError(1, 0, 0) EndIf EndFunc ;==>GetHoveredHwnd You badly used MouseGetPos() in WindowFromPoint DllCall() Try this Local $iRet = DllCall("user32.dll", "int", "WindowFromPoint", "long", MouseGetPos(0), "long", MouseGetPos(1)) Resources UDF ResourcesEx UDF AutoIt Forum Search
bo8ster Posted April 1, 2010 Author Posted April 1, 2010 @Ascend4nt - Thanks! The code given is apart of a larger script which does use _WinAPI_GetAncestor however the flag param may work this time. (I've had issues with it before). In that script I notice that _WinAPI_GetAncestor has to be called twice sometimes in order to get match to what WinList returns. I have made another version of matchWinHandle which is recursive to do this however I could not get over the original issue. Once finished I will post the script - it is a fix up of my 'Control Handle under mouse' script so it can work with non-minimized windows. @Zedna - good pickup, I never would have got that - thanks! I'll try that after Easter. Happy Easter! Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]
bo8ster Posted April 6, 2010 Author Posted April 6, 2010 Here is the end product. expandcollapse popup; =============================================================================== ;~ This script gets the control under the mouse pointer (active or inactive) ;~ The information then can be used with in conjunction with control functions. ;~ Requires AutoIt v3.3.6.0 or later to run and to view apps maximized. ;~ Big thanks to SmOke_N and Valik their help in creating it. ; =============================================================================== #include <WinAPI.au3> #include <Array.au3> #include <WindowsConstants.au3> AutoItSetOption("MustDeclareVars", 1) AutoItSetOption("MouseCoordMode", 1) AdlibRegister("_Mouse_Control_GetInfoAdlib", 10) HotKeySet("^!x", "MyExit") ; Press Ctrl+Alt+x to stop the script ;~ #AutoIt3Wrapper_run_debug_mode=Y Global $pos1 = MouseGetPos() Global $pos2 = MouseGetPos() ; must be initialized Global $appHandle = 0 While 1 Sleep(0xFFFFFFF) WEnd ; =============================================================================== ;~ Retrieves the information of a Control located under the mouse and displayes it in a tool tip next to the mouse. ;~ Function uesd ;~ _Mouse_Control_GetInfo() ;~ GetDlgCtrlID ; =============================================================================== Func _Mouse_Control_GetInfoAdlib() $pos1 = MouseGetPos() If $pos1[0] <> $pos2[0] Or $pos1[1] <> $pos2[1] Then ; has the mouse moved? Local $a_info = _Mouse_Control_GetInfo() Local $aDLL = DllCall('User32.dll', 'int', 'GetDlgCtrlID', 'hwnd', $a_info[0]) ; get the ID of the control If @error Then Return ToolTip("Handle = " & $a_info[0] & @CRLF & _ "Class = " & $a_info[1] & @CRLF & _ "ID = " & $aDLL[0] & @CRLF & _ "Mouse X Pos = " & $a_info[2] & @CRLF & _ "Mouse Y Pos = " & $a_info[3] & @CRLF & _ "ClassNN = " & $a_info[4] & @CRLF & _ ; optional "Parent Hwd = " & _WinAPI_GetAncestor($appHandle, $GA_ROOT)) $pos2 = MouseGetPos() EndIf EndFunc ;==>_Mouse_Control_GetInfoAdlib ; =============================================================================== ;~ Retrieves the information of a Control located under the mouse. ;~ Uses Windows functions WindowFromPoint and GetClassName to retrieve the information. ;~ Functions used ;~ _GetHoveredHwnd() ;~ _ControlGetClassnameNN() ;~ Returns ;~ [0] = Control Handle of the control ;~ [1] = The Class Name of the control ;~ [2] = Mouse X Pos (converted to Screen Coord) ;~ [3] = Mouse Y Pos (converted to Screen Coord) ;~ [4] = ClassNN ; =============================================================================== Func _Mouse_Control_GetInfo() Local $client_mpos = $pos1 ; gets client coords because of "MouseCoordMode" = 2 Local $a_mpos ;~ Call to removed due to offset issue $a_mpos = _ClientToScreen($appHandle, $client_mpos[0], $client_mpos[1]) ; $a_mpos now screen coords $a_mpos = $client_mpos $appHandle = GetHoveredHwnd($client_mpos[0], $client_mpos[1]) ; Uses the mouse to do the equivalent of WinGetHandle() If @error Then Return SetError(1, 0, 0) Local $a_wfp = DllCall("user32.dll", "hwnd", "WindowFromPoint", "long", $a_mpos[0], "long", $a_mpos[1]) ; gets the control handle If @error Then Return SetError(2, 0, 0) Local $t_class = DllStructCreate("char[260]") DllCall("User32.dll", "int", "GetClassName", "hwnd", $a_wfp[0], "ptr", DllStructGetPtr($t_class), "int", 260) Local $a_ret[5] = [$a_wfp[0], DllStructGetData($t_class, 1), $a_mpos[0], $a_mpos[1], "none"] Local $sClassNN = _ControlGetClassnameNN($a_ret[0]) ; optional, will run faster without it $a_ret[4] = $sClassNN Return $a_ret EndFunc ;==>_Mouse_Control_GetInfo ; =============================================================================== ; Retrieves the Handle of GUI/Application the mouse is over. ; Similar to WinGetHandle except it used the current mouse position ; Taken from http://www.autoitscript.com/forum/index.php?showtopic=444962 ; Changed to take params to allow only one set of coords to be used. ; Params ;~ $i_xpos - x position of the mouse - usually from MouseGetPos(0) ;~ $i_ypos - x position of the mouse - usually from MouseGetPos(1) ; =============================================================================== Func GetHoveredHwnd($i_xpos, $i_ypos) Local $iRet = DllCall("user32.dll", "int", "WindowFromPoint", "long", $i_xpos, "long", $i_ypos) If IsArray($iRet) Then $appHandle = $iRet[0] Return HWnd($iRet[0]) Else Return SetError(1, 0, 0) EndIf EndFunc ;==>GetHoveredHwnd ; =============================================================================== ;~ Gets the ClassNN of a control (Classname and Instance Count). This is checked with ControlGetHandle ;~ The instance is really a way to uniquely identify classes with the same name ;~ Big thanks to Valik for writing the function, taken from - http://www.autoitscript.com/forum/index.php?showtopic=97662 ;~ Param ;~ $hControl - the control handle from which you want the ClassNN ;~ Returns ;~ the ClassNN of the given control ; =============================================================================== Func _ControlGetClassnameNN($hControl) If Not IsHWnd($hControl) Then Return SetError(1, 0, "") Local Const $hParent = _WinAPI_GetAncestor($appHandle, $GA_ROOT) ; get the Window handle, this is set in GetHoveredHwnd() If Not $hParent Then Return SetError(2, 0, "") Local Const $sList = WinGetClassList($hParent) ; list of every class in the Window Local $aList = StringSplit(StringTrimRight($sList, 1), @LF, 2) _ArraySort($aList) ; improves speed Local $nInstance, $sLastClass, $sComposite For $i = 0 To UBound($aList) - 1 If $sLastClass <> $aList[$i] Then ; set up the first occurrence of a unique classname $sLastClass = $aList[$i] $nInstance = 1 EndIf $sComposite = $sLastClass & $nInstance ;build the ClassNN for testing with ControlGetHandle. ClassNN = Class & ClassCount ;if ControlGetHandle(ClassNN) matches the given control return else look at the next instance of the classname If ControlGetHandle($hParent, "", $sComposite) = $hControl Then Return $sComposite EndIf $nInstance += 1 ; count the number of times the class name appears in the list Next Return SetError(3, 0, "") EndFunc ;==>_ControlGetClassnameNN ; =============================================================================== ;~ Functions not used anymore. ; =============================================================================== ; =============================================================================== ;~ Translates client coordinates into screen coordinates, [0] = x and [1] = y from the return array. ;~ Requires - AutoItSetOption("MouseCoordMode", 2) ;~ Params ;~ $h_wnd - Identifies the window whose client area is used for the conversion. ;~ $i_x - x pos of the client coord ;~ $i_y - Y pos of the client coord ;~ Returns ;~ Screen coordinates ; =============================================================================== Func _ClientToScreen($h_wnd, $i_x, $i_y) ;~ ConsoleWrite("Client here, " & $i_x & "," & $i_y & @ CRLF) Local $t_point = DllStructCreate("int;int") DllStructSetData($t_point, 1, $i_x) DllStructSetData($t_point, 2, $i_y) DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $h_wnd, "ptr", DllStructGetPtr($t_point)) Local $a_ret[2] = [DllStructGetData($t_point, 1), DllStructGetData($t_point, 2)] ;~ ConsoleWrite("Screen here, " & $a_ret[0] & "," & $a_ret[1] & @CRLF) Return $a_ret EndFunc ;==>_ClientToScreen ;~ Finds a matching window with the given handle Func matchWinHandle($hParent) Local $aWinList = WinList() Local $flag = 0; For $i = 0 To UBound($aWinList) - 1 If $aWinList[$i][1] = $hParent Then ConsoleWriteError("hParent match is " & $aWinList[$i][0] & @LF) $flag = 1 ;~ _ArrayDisplay($aWinList) ExitLoop EndIf Next If $flag = 0 Then ConsoleWriteError("No windows handle match found in WinList" & @LF) EndIf EndFunc ;==>matchWinHandle Func MyExit() ; stops the script ConsoleWrite("Script Stoppted By User" & @CR) Exit EndFunc ;==>MyExit ;==> Recersive version. No need now that I am using $GA_ROOT with get _WinAPI_GetAncestor Func matchWinHandleRec($hParent) Local $aWinList = WinList() Local $flag = 0; For $i = 0 To UBound($aWinList) - 1 If $aWinList[$i][1] = $hParent Then ConsoleWriteError("hParent match is " & $aWinList[$i][0] & @LF) $flag = 1; ExitLoop Return EndIf Next If $flag = 0 Then ConsoleWriteError("No windows handle match found in WinList. Calling it again" & @LF) matchWinHandle(_WinAPI_GetAncestor($hParent)) Local $sClassList = WinGetClassList($hParent) Local $aClassList = StringSplit(StringTrimRight($sClassList, 1), @LF, 2) For $i = 0 To UBound($aClassList) - 1 ConsoleWrite($aClassList[$i] & @LF) Next EndIf EndFunc ;==>matchWinHandleRec Notes: SmOke_N originally recommended using client coords then translating them to screen for accuracy however this caused an offset issue that I was unable to resolve. The issue was especially evident with non-maximized screens. I have left the call and function in so you can see what I am talking about. I have left in other code including a recursive function in case anyone finds it interesting. If you have any issues please let me know. Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]
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