Jump to content

detect mousewheel over windows' title


Go to solution Solved by mikell,

Recommended Posts

  • Solution

#include <WinAPI.au3>
#include <WindowsConstants.au3>
HotKeySet('{ESC}', '_Close')

If Not IsDeclared('WM_MOUSEWHEEL') Then Global Const $WM_MOUSEWHEEL = 0x020A
Global Const $tagMSLLHOOKSTRUCT = $tagPOINT & ';uint mouseData;uint flags;uint time;ulong_ptr dwExtraInfo;'

Global $hFunc, $pFunc, $hHook, $hMod
$hFunc = DllCallbackRegister('_MouseProc', 'lresult', 'int;int;int')
$pFunc = DllCallbackGetPtr($hFunc)
$hMod = _WinAPI_GetModuleHandle(0)
$hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pFunc, $hMod)

Global $aList = _WinAPI_EnumWindowsTop()

While 1
    Sleep(20)
WEnd


Func _MouseProc($iCode, $iwParam, $ilParam)
    Static $x0, $y0
    If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
    Local $tMSLL = DllStructCreate($tagMSLLHOOKSTRUCT, $ilParam)
    If $iwParam = $WM_MOUSEWHEEL Then
        $x = DllStructGetData($tMSLL, 'X')
        $y = DllStructGetData($tMSLL, 'Y')
        If $x <> $x0 And $y <> $y0 Then
           Local $point = DllStructCreate($tagPOINT)
           DllStructSetData($point,"X", $x)
           DllStructSetData($point,"Y", $y)
           For $i = 1 To $aList[0][0]
              Local $title = WinGetTitle($aList[$i][0])
              If  $title <> "" And $title <> "Program Manager" Then
                 Local $rect = _WinAPI_GetWindowRect($aList[$i][0])
                 DllStructSetData($rect, "Bottom", DllStructGetData($rect, "Top")+35)
                 If _WinAPI_PtInRect($rect, $point) Then
                    $x0 = $x
                    $y0 = $y
                    Msgbox(4096, "", $title)
                 EndIf
             EndIf
          Next
       EndIf
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
EndFunc


Func _Close()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hHook)
    Exit
EndFunc

Edited by mikell
Link to comment
Share on other sites

Thank you alot for your script!

It works very well!

Apart these:

1) If you have more than one windows' title overlapping, it cycles through all of them, instead I want only the handle to the one over which the mouse is (not necessarily the active one).

2) it detects all titles, even those hidden by the active window: instead it must act only if there is the mouse over the title and the window is visible, not hidden.

3) I need also to prevent the default scrolling behaviour after detecting it over the window's title.

In javascript there is the     preventDefault(e);
 

Anyway, thank you again for this, it's a very good starting point.

Edited by frank10
Link to comment
Share on other sites

I made some changes, so now it works quite perfect:

1) it detects overlapping titles and select only the top window.

2) it stops default scrolling in window     EDIT: no...

3) it gets also windows not active

4) it doesn't select hidden window

5) it detects if wheel up or down and make different actions

I used the func _WinAPI_WindowFromPoint, _WinAPI_GetParent.

I had to get the delta value to see if wheel up or down, but I don't know how, so I made an hack looking at the first number of DllStructGetData($tMSLL, 3): if 7 wheel UP.

Now the code makes window minimize when wheel down on title and maximize when wheel up:

#include <WinAPI.au3>
#include <WindowsConstants.au3>

OnAutoItExitRegister("_Close")
Global Const $tagMSLLHOOKSTRUCT = $tagPOINT & ';uint mouseData;uint flags;uint time;ulong_ptr dwExtraInfo;'

Global $hFunc, $pFunc, $hHook, $hMod
$hFunc = DllCallbackRegister('_MouseProc', 'lresult', 'int;int;int')
$pFunc = DllCallbackGetPtr($hFunc)
$hMod = _WinAPI_GetModuleHandle(0)
$hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pFunc, $hMod)

While 1
    Sleep(20)
WEnd

Func _MouseProc($iCode, $iwParam, $ilParam)
    Static $x0, $y0
    If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
    Local $tMSLL = DllStructCreate($tagMSLLHOOKSTRUCT, $ilParam)
    If $iwParam = $WM_MOUSEWHEEL Then
        $x = DllStructGetData($tMSLL, 'X')
        $y = DllStructGetData($tMSLL, 'Y')
        If $x <> $x0 And $y <> $y0 Then
            Local $point = DllStructCreate($tagPOINT)
            DllStructSetData($point,"X", $x)
            DllStructSetData($point,"Y", $y)
            local $hWnd = _WinAPI_WindowFromPoint($point) ; Retrieve the window handle.
            ; check it's a handle  from the root window
            if _WinAPI_GetParent($hWnd) = 0 Then
                ; check it's not a wheel outside title:
                Local $rect = _WinAPI_GetWindowRect($hWnd)
                DllStructSetData($rect, "Bottom", DllStructGetData($rect, "Top")+35)
                If _WinAPI_PtInRect($rect, $point) Then
                    if  StringLeft(DllStructGetData($tMSLL, 3),1) = 7 Then  ; hack to get if wheel UP... (it starts with 4 for down)
                        WinSetState($hWnd,"",@SW_MAXIMIZE  )
                    Else
                        WinSetState($hWnd,"",@SW_MINIMIZE )
                    EndIf
                    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
                EndIf
            EndIf
        EndIf
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
EndFunc


Func _Close()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hHook)
    Exit
EndFunc
Edited by frank10
Link to comment
Share on other sites

1) I still have the problem of blocking the default behaviour of wheel... how do I block it?

2) You used the

    WinApi_PointInrect

to detect if I'm over the title.

I'm trying to make another func: I get a rect from drawing the mouse.

Is there a way to check how many windows are inside a rectangle (drawn by mouse)? i.e. if a rectangle intersects other win rectangles?

Link to comment
Share on other sites

For the 2) it could be done in a loop with this:

http://msdn.microsoft.com/en-us/library/system.windows.rect.intersectswith%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-1

bool doesIntersect = myRectangle.IntersectsWith(myRectangle2);
 

In autoit ?

In alternative I've just done a check of Points in Rect, like this:

Func _checkRect( $pos_old, $pos_new )
    Local $rectMouse  = DllStructCreate( "int x1; int y1; int x2; int y2")
    DllStructSetData($rectMouse, "x1",  $pos_old[0] )
    DllStructSetData($rectMouse, "y1",  $pos_old[1] )
    DllStructSetData($rectMouse, "x2",  $pos_new[0] )
    DllStructSetData($rectMouse, "y2",  $pos_new[1] )

    Local $point1 = DllStructCreate($tagPOINT)
    Local $point2 = DllStructCreate($tagPOINT)
    Local $point3 = DllStructCreate($tagPOINT)
    Local $point4 = DllStructCreate($tagPOINT)

    local $winNum = 0
    Global $aList = _WinAPI_EnumWindowsTop()
           For $i = 1 To $aList[0][0]

                Local $rect = _WinAPI_GetWindowRect($aList[$i][0])

                DllStructSetData($point1,"X", DllStructGetData($rect, "left"))
                DllStructSetData($point1,"Y", DllStructGetData($rect, "top") )
                DllStructSetData($point2,"X", DllStructGetData($rect, "right"))
                DllStructSetData($point2,"Y", DllStructGetData($rect, "top") )
                DllStructSetData($point3,"X", DllStructGetData($rect, "right"))
                DllStructSetData($point3,"Y", DllStructGetData($rect, "bottom") )
                DllStructSetData($point4,"X", DllStructGetData($rect, "left"))
                DllStructSetData($point4,"Y", DllStructGetData($rect, "bottom") )

                If _WinAPI_PtInRect($rectMouse, $point1 ) or _WinAPI_PtInRect($rectMouse, $point2 ) or _WinAPI_PtInRect($rectMouse, $point3 ) or _WinAPI_PtInRect($rectMouse, $point4 ) Then
                    ConsoleWrite("Win In Mouserect:" & WinGetTitle($aList[$i][0]) & @CRLF)
                    $winNum += 1
                EndIf
           Next

       ConsoleWrite("WinNumFound: " &$winNum & @CRLF)
EndFunc

but it's not perfect: it detects only the 4 corners, not all the sides.

Link to comment
Share on other sites

For 1)

Return 1 ; If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.

Link to comment
Share on other sites

Ok, that works for the minimize func, but when maximize it scrolls again:

#include <WinAPI.au3>
#include <WindowsConstants.au3>

OnAutoItExitRegister("_Close")
Global Const $tagMSLLHOOKSTRUCT = $tagPOINT & ';uint mouseData;uint flags;uint time;ulong_ptr dwExtraInfo;'

Global $hFunc, $pFunc, $hHook, $hMod
$hFunc = DllCallbackRegister('_MouseProc', 'lresult', 'int;int;int')
$pFunc = DllCallbackGetPtr($hFunc)
$hMod = _WinAPI_GetModuleHandle(0)
$hHook = _WinAPI_SetWindowsHookEx($WH_MOUSE_LL, $pFunc, $hMod)

While 1
    Sleep(20)
WEnd

Func _MouseProc($iCode, $iwParam, $ilParam)
    Static $x0, $y0
    If $iCode < 0 Then Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
    Local $tMSLL = DllStructCreate($tagMSLLHOOKSTRUCT, $ilParam)
    If $iwParam = $WM_MOUSEWHEEL Then
        $x = DllStructGetData($tMSLL, 'X')
        $y = DllStructGetData($tMSLL, 'Y')
        If $x <> $x0 And $y <> $y0 Then
            Local $point = DllStructCreate($tagPOINT)
            DllStructSetData($point,"X", $x)
            DllStructSetData($point,"Y", $y)
            local $hWnd = _WinAPI_WindowFromPoint($point) ; Retrieve the window handle.
            ; check it's a handle  from the root window
            if _WinAPI_GetParent($hWnd) = 0 Then
                ; check it's not a wheel outside title:
                Local $rect = _WinAPI_GetWindowRect($hWnd)
                DllStructSetData($rect, "Bottom", DllStructGetData($rect, "Top")+35)
                If _WinAPI_PtInRect($rect, $point) Then
                    if  StringLeft(DllStructGetData($tMSLL, 3),1) = 7 Then  ; hack to get if wheel UP... (it starts with 4 for down)
                        WinSetState($hWnd,"",@SW_MAXIMIZE  )
                        return 1
                    Else
                        WinSetState($hWnd,"",@SW_MINIMIZE )
                        return 1
                    EndIf
                EndIf
            EndIf
        EndIf
    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
EndFunc


Func _Close()
    _WinAPI_UnhookWindowsHookEx($hHook)
    DllCallbackFree($hHook)
    Exit
EndFunc

i.e. in the scite win when you have a script tab active in focus, position the mouse over title and scroll up: the windows maximize correctly, but sometimes the text in tab has scrolled up.

With wheel down instead it minimizes and doesn't scroll.

Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

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