Sign in to follow this  
Followers 0
frank10

advanced windows' control with mouse wheel

1 post in this topic

#1 ·  Posted (edited)

I made this script to add some functionality to windows' control (inspiring by tools like Preme), like:

1) minimize windows with wheel down on title

2) maximize windows with wheel up on title

3) changing master volume with wheel on taskbar

4) scrolling also windows not selected, just use the wheel over the window you want to scroll

5) arranging windows' position in one of the eight possible positions on screen: up-down-left-right, topLeft-topRight-bottomleft-bottomright with pressing middle button/wheel and moving it in the wanted direction

6) automatically arrange multiple windows on screen pressinng middle button/wheel outside windows' title  and drawing a rectangle over the corners of the windows you want to arrange. 2-4 windows can be arranged to left-right, left+topright-bottomright, topLeft-topRight-bottomleft-bottomright.



Known problems-limitations, using numbers from above description:

2) when maximize, sometimes the window scroll also the content, even if I made a "return 1" to block standard wheel behaviour (the minimize doesn't have this problem)

4) the scrolling of the window isn't exactly what I wanted, because I made it activating the window to scroll it's content (also you see a little "flash" on the window's borders), while I wanted to do that without activating the window, leaving it unactivated.

I made it working using:

   _WinAPI_SetForegroundWindow ( $hWnd )
    ;WinActivate($hWnd)  ; doesn't work!

I don't know how to send a mouse wheel event to a window not active.

6) I made a check func to see if one corner of a window is inside the rectangle drawed  with mouse. This way if you draw the rectangle on the borders of the window it doesn't get selected. A better approach would consider also the entire borders, such as this Windows func to check the intersections of 2 rectangles struct:
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);
How to do in autoit?

other improvements:   

a) it could be nice to draw the rectangle on the screen: I tried to do that with the func _WinAPI_DrawRect, but it's a lot SLOW, so if there's a faster method...

   

Here's the script:
(you need also this au3 to control master volume:
)
download the _AudioEndpointVolume.au3

Thanks to mikell for the base WinApi script.
 

EDIT: I changed the detection of mouse over Taskbar

WindowControlWheel_v1.1.au3:

#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include "C:\Program Files (x86)\AutoIt3\Beta\Include\_AudioEndpointVolume.au3"
#include "C:\Program Files (x86)\AutoIt3\Beta\Include\WinAPIex\WinAPIEx.au3"
#include <Misc.au3>
#include <Array.au3>
; thanks to mikell for the base WinApi script

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)

global $firstTime = ''
Global $posNew = 0
Global $posOld = 0
global $hWnd

While 1
    Sleep(10)
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_MOUSEMOVE  Then
        ToolTip("")
        if $firstTime <> '' and TimerDiff($firstTime) > 400 Then
            $posNew = MouseGetPos()
            ; if over title:
            if _WinOverTit($posOld[0], $posOld[1]) Then
                _moveWin($posOld,$posNew)
                $firstTime = ''
            EndIf
        EndIf
    EndIf

    If $iwParam = $WM_MBUTTONDOWN and $firstTime = '' Then
        $firstTime = TimerInit()
        $posOld = MouseGetPos()
    EndIf
    If $iwParam = $WM_MBUTTONUP and $firstTime <> '' Then
;~         _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)
        $posNew = MouseGetPos()
        _checkRect( $posOld,$posNew)
        $firstTime = ''
    EndIf

    If $iwParam = $WM_MOUSEWHEEL Then
        $x = DllStructGetData($tMSLL, 'X')
        $y = DllStructGetData($tMSLL, 'Y')
        Local $point = DllStructCreate($tagPOINT)
        DllStructSetData($point,"X", $x)
        DllStructSetData($point,"Y", $y)

        $hWnd = _WinAPI_WindowFromPoint($point) ; Retrieve the window handle.

        _WinAPI_SetForegroundWindow ( $hWnd ) ; works ok BUT makes a "flash" every time it activates the win   I want also to scroll WITHOUT activate the win...

        ; if over title:
        if _WinOverTit($x, $y) Then
            local $iDelta = BitShift(DllStructGetData($tMSLL, 'mouseData'), 16)

            If $iDelta > 0 Then  ; wheel up
                if $y >= @DesktopHeight -100 Then
                    _VolumeStepUp()
                    ToolTip(@CR & "  VolumeUP: " & Round(_GetMasterVolumeLevelScalar(),0) & @CRLF ,@DesktopWidth/2-50,@DesktopHeight-100 )
                Else
                    WinSetState($hWnd,"", @SW_MAXIMIZE  )
                    WinActivate($hWnd)
               EndIf

            Else ; wheel down
                if   $y >= @DesktopHeight -100 Then
                    _VolumeStepDown()
                    ToolTip(@cr &"  VolumeDOWN: " & Round(_GetMasterVolumeLevelScalar(),0) & @CRLF ,@DesktopWidth/2-50,@DesktopHeight-100 )
                Else
                    WinSetState($hWnd,"", @SW_MINIMIZE )
                EndIf
            EndIf
            Return 1
        EndIf

    EndIf
    Return _WinAPI_CallNextHookEx($hHook, $iCode, $iwParam, $ilParam)
EndFunc


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

Func _WinOverTit($x,$y)
    local $overTit = 0
    Local $point = DllStructCreate($tagPOINT)
    DllStructSetData($point,"X", $x)
    DllStructSetData($point,"Y", $y)
    $hWnd = _WinAPI_WindowFromPoint($point) ; Retrieve the window handle.
    ; check it's a handle  from the root window OR if you are over the taskbar to control the volume:
    if _WinAPI_GetParent($hWnd) = 0 or $y >= @DesktopHeight -40 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 $overTit = 1
    EndIf
    return $overTit
EndFunc

Func _moveWin($pos_old, $pos_new)
    local $direction = ""

    If $pos_new[0] = $pos_old[0] and $pos_new[1] = $pos_old[1] Then Return
    $a = _GetAnglePO($pos_new[0] - $pos_old[0], $pos_new[1] - $pos_old[1]) * 57.2957795130823
    Select
      Case $a >= 337.5 or $a < 22.5
         $direction = "6"
         WinMove($hWnd,"",@DesktopWidth/2,0,@DesktopWidth/2,@DesktopHeight)
      Case $a >= 22.5 and $a < 67.5
         $direction = "3"
         WinMove($hWnd,"",@DesktopWidth/2,@DesktopHeight/2,@DesktopWidth/2,@DesktopHeight/2)
      Case $a >= 67.5 and $a < 112.5
         $direction = "2"
         WinMove($hWnd,"",0,@DesktopHeight/2,@DesktopWidth,@DesktopHeight/2)
       Case $a >= 112.5 and $a < 157.5
         $direction = "1"
         WinMove($hWnd,"",0,@DesktopHeight/2,@DesktopWidth/2,@DesktopHeight/2)
      Case $a >= 157.5 and $a < 202.5
         $direction = "4"
         WinMove($hWnd,"",0,0,@DesktopWidth/2,@DesktopHeight)
      Case $a >= 202.5 and $a < 247.5
         $direction = "7"
         WinMove($hWnd,"",0,0,@DesktopWidth/2,@DesktopHeight/2)
      Case $a >= 247.5 and $a < 292.5
         $direction = "8"
         WinMove($hWnd,"",0,0,@DesktopWidth,@DesktopHeight/2)
      Case $a >= 292.5 and $a < 337.5
         $direction = "9"
         WinMove($hWnd,"",@DesktopWidth/2,0,@DesktopWidth/2,@DesktopHeight/2)
    EndSelect
EndFunc

Func _GetAnglePO( $x, $y )   ;by blindwig
 Local Const $pi = 3.14159265358979
  Select
      Case $x > 0
         If $y >= 0 Then
            Return ATan($y / $x)
         Else
            Return ATan($y / $x) + 2 * $pi
         EndIf
      Case $x = 0
         If $y = 0 Then
            Return 0
         ElseIf $y > 0 Then
            Return $pi / 2
         Else
            Return 3 * $pi / 2
         EndIf
      Case $x < 0
         Return ATan($y / $x) + $pi
   EndSelect
EndFunc

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 $aWin[1]
    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
                    _ArrayAdd($aWin, $aList[$i][0])
                EndIf
           Next

Select
    Case UBound($aWin) = 3
        WinMove($aWin[1],"",0,0,@DesktopWidth/2,@DesktopHeight)
        WinMove($aWin[2],"",@DesktopWidth/2,0,@DesktopWidth/2,@DesktopHeight)
    Case UBound($aWin) = 4
        WinMove($aWin[1],"",0,0,@DesktopWidth/2,@DesktopHeight)
        WinMove($aWin[2],"",@DesktopWidth/2,0,@DesktopWidth/2,@DesktopHeight/2)
        WinMove($aWin[3],"",@DesktopWidth/2,@DesktopHeight/2,@DesktopWidth/2,@DesktopHeight/2)
    Case UBound($aWin) = 5
        WinMove($aWin[1],"",0,0,@DesktopWidth/2,@DesktopHeight/2)
        WinMove($aWin[2],"",0,@DesktopHeight/2,@DesktopWidth/2,@DesktopHeight/2)
        WinMove($aWin[3],"",@DesktopWidth/2,0,@DesktopWidth/2,@DesktopHeight/2)
        WinMove($aWin[4],"",@DesktopWidth/2,@DesktopHeight/2,@DesktopWidth/2,@DesktopHeight/2)
EndSelect

EndFunc




Func _WinAPI_DrawRect($start_x, $start_y, $iWidth, $iHeight, $iColor)
    ConsoleWrite($start_x &","& $start_y&"--"& $iWidth &","& $iHeight & @CRLF)

    Local $tRect = DllStructCreate($tagRECT)
    DllStructSetData($tRect, 1, $start_x)
    DllStructSetData($tRect, 2, $start_y)
    DllStructSetData($tRect, 3, $iWidth)
    DllStructSetData($tRect, 4, $iHeight)
    Local $hDC = _WinAPI_GetWindowDC(0)
    ; DC of entire screen (desktop)

    $hPen = _WinAPI_CreatePen($PS_SOLID, 2, $iColor)
    $o_Orig = _WinAPI_SelectObject($hDC, $hPen)

    _WinAPI_DrawLine($hDC, $posOld[0] , $posOld[1], $posNew[0] , $posOld[1]) ; horizontal top
    _WinAPI_DrawLine($hDC, $posNew[0] , $posOld[1], $posNew[0] , $posNew[1]) ; vert right
    _WinAPI_DrawLine($hDC, $posNew[0] , $posNew[1], $posOld[0] , $posNew[1]) ; hor bottom
    _WinAPI_DrawLine($hDC, $posOld[0] , $posNew[1], $posOld[0] , $posOld[1]) ; vert left

    _WinAPI_RedrawWindow(_WinAPI_GetDesktopWindow(), 0, 0, $RDW_INVALIDATE + $RDW_ALLCHILDREN)

    _WinAPI_SelectObject($hDC, $o_Orig)
    _WinAPI_DeleteObject($hPen)
    _WinAPI_ReleaseDC(0, $hDC)


EndFunc   ;==>_WinAPI_DrawRect
Edited by frank10
1 person likes this

Share this post


Link to post
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
Sign in to follow this  
Followers 0