Jump to content

Recommended Posts

Posted (edited)

Hello everybody :)
I have a problem with GUIGetCursorInfo, not sure if it's a bug or not. Here is a script that shows it :

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1)
Global $g_hGUI

Example()

Func Example()
    $g_hGUI = GUICreate("Main", 300, 300)
    WinSetTitle($g_hGUI, "", "Main " & $g_hGUI)

    Local $idLabel = GUICtrlCreateLabel("Label in Main", 0, 0, 150, 150, BitOr($SS_CENTERIMAGE, $SS_CENTER))
    GUICtrlSetBkColor($idLabel, 0xFFFF00) ; yellow
    GUISetState(@SW_SHOW, $g_hGUI)

    Local $hChild = GUICreate("Child", 150, 150, 150, 150, $WS_CHILD, -1, $g_hGUI)
    GUISetBkColor(0x00FFFF, $hChild) ; blue
    GUISetState(@SW_SHOW, $hChild)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
        _Hover()
    WEnd

    GuiDelete($hChild)
    GuiDelete($g_hGUI)
EndFunc   ;==>Example

Func _Hover()
    Local $aInfo = GUIGetCursorInfo()
    If Not @error And $aInfo[4] Then
        Local Static $iInc2 = 0
        $iInc2 +=1
        If Not Mod($iInc2, 10) Then
            ConsoleWrite("Hovering over control #" & $aInfo[4] & "   (" & $iInc2 & ")" & @crlf)
        EndIf
    EndIf
EndFunc   ;==>_Hover

What happens when you hover over the label (yellow control) ?
Nothing happens and the Console stays empty, unfortunately.

But if you reverse the order of the 2 GUISetState(@SW_SHOW) like this...

GUISetState(@SW_SHOW, $hChild)
GUISetState(@SW_SHOW, $g_hGUI)

...now everything works and when you hover over the label, this is what you see in the Console :

Hovering over control #3   (10)
Hovering over control #3   (20)
Hovering over control #3   (30)
Hovering over control #3   (40)
...

We discovered this strange behavior with @ioa747 yesterday, after this scenario in 4 acts :

1) Original script looked like this :

Func Example()
    ...
    GUISetState(@SW_SHOW, $g_hGUI)
    GUISetState(@SW_SHOW, $hChild)
    ...
    _Hover()
    ...
EndFunc

Func _Hover()
    Local $aInfo = GUIGetCursorInfo($g_hGUI)
    ...
EndFunc

This works, because we indicate a [winhandle] parameter in GUIGetCursorInfo()
The problem is that it works "too much" as ioa747 detected, because if you drag any external window over the GUI (try it with a small NotePad window) then the controls in the GUI keep reacting and you'll see in your Console :

Hovering over control #3   (10)
Hovering over control #3   (20)
...

This is not acceptable, depending on the code associated to the hover process.
Why are the controls in the GUI reacting when an external window is dragged over the GUI ?
This is what the help file stipulates, topic GUIGetCursorInfo()

If the "winhandle" parameter is used then the specified window becomes the new "current" window.

This is exactly how we used GUIGetCursorInfo($g_hGUI) in our script and that's why the controls kept reacting when covered by an external window. So far, so good...

2) To quickly solve this issue, we started with this solution :

Func Example()
    ...
    GUISetState(@SW_SHOW, $g_hGUI)
    GUISetState(@SW_SHOW, $hChild)
    ...
    If WinActive($g_hGUI) Then _Hover()
    ...
EndFunc

Func _Hover()
    Local $aInfo = GUIGetCursorInfo($g_hGUI)
    ...
EndFunc

This works, because the _Hover function will NOT be called when an external window is being dragged over the label control, as the external window will be active and not $g_hGUI

Then I thought it was not normal to solve it that way and some digging needed to be done.

3) Let's look at the help file, to see what happens when no winhandle is used in GUIGetCursorInfo()

When no winhandle, it will be successful if the GUI Windows is active

That's exactly the script at the top of the post, which contains :

Func Example()
    ...
    GUISetState(@SW_SHOW, $g_hGUI)
    GUISetState(@SW_SHOW, $hChild)
    ...
    _Hover()
    ...
EndFunc

Func _Hover()
    Local $aInfo = GUIGetCursorInfo()
    ...
EndFunc

But as you notice, it doesn't work, no matter the GUI is active (you can click on its title to make sure the GUI becomes active, or add WinActivate($g_hGUI) to make sure, or test with WinActive($g_hGUI) it will not work and the hover process will not be detected (tested on Windows 11 too)

Maybe @jpm could read this to share his expertise : is there a bug (or not) in AutoIt, concerning this part 3 ?

4) Gladly, we found a solution, by reversing the order of the 2 GuiSetState(@SW_SHOW), like this :

Func Example()
    ...
    GUISetState(@SW_SHOW, $hChild)
    GUISetState(@SW_SHOW, $g_hGUI)
    ...
    _Hover()
    ...
EndFunc

Func _Hover()
    Local $aInfo = GUIGetCursorInfo()
    ...
EndFunc

Now the hover process works and if an external window is dragged over the GUI, then the controls of the GUI don't react, great !
Of course, the issue will never happen if you got only 1 GUI in the script, as there will be only 1 GuiSetState(@SW_SHOW) . But when you got 2 Gui's or more...

Thanks for reading and have a great evening

Edited by pixelsearch
typo

"I think you are searching a bug where there is no bug... don't listen to bad advice."

  • Solution
Posted (edited)

Just reading through this - apologies if I've misunderstood the question!.

GUIGetCursorInfo ( [winhandle] )

Parameters
winhandle [optional] The handle of the window to use. If omitted the "current" window will be used.

The "Current" window by default is the last GUI created no?
So this fails:

GUISetState(@SW_SHOW, $g_hGUI)
GUISetState(@SW_SHOW, $hChild)

But this should work:

GUISetState(@SW_SHOW, $g_hGUI)
GUISetState(@SW_SHOW, $hChild)
GUISwitch($g_hGUI)

 Edit: I guess setting the state switches the current GUI as well - GuiSwitch returns the previous handle so it'll be easy to test!

ConsoleWrite("Prev Window is the child? " & (GUISwitch($g_hGUI) = $hChild) & @CRLF)
Edited by MattyD
Posted

@MattyD you're right, when using GUIGetCursorInfo() without indicating a handle, then GuiSwitch() is the key to make sure that we'll use the correct "current" GUI

Apparently we made it by reversing the 2 GUISetState (child before main) but it's more elegant with GuiSwitch() which should always be used in that case. Also we have to take care of what is written in the help file (remarks section of GUIGetCursorInfo) :

When no winhandle it will be successful if the GUI Windows is active.

So the "current" GUI must also be "active" or GUIGetCursorInfo() without handle won't react correctly.

Can you imagine we went through all this, only because when you indicate a handle, e.g GUIGetCursorInfo($g_hGUI) , then any external window being dragged over the GUI triggers GUIGetCursorInfo($g_hGUI) and now...

$aArray[4] = ID of the control that the mouse cursor is hovering over (or 0 if none)

But we're not "directly" hovering over a control, there's an external window between the control and the mouse cursor. I wish $aArray[4] did return 0 in this case, when you're hovering "indirectly" over a control, or (why not) return... the negative value of the control :D

 

"I think you are searching a bug where there is no bug... don't listen to bad advice."

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
×
×
  • Create New...