Jump to content

Is there some way (API maybe?) to send message to GUI-window for "magnetic effect"?


Recommended Posts

Posted

One more shot.

#include <GUIConstants.au3>
Const $Range = 100
Const $WM_MOVE = 0x0003
Const $WM_MOVING = 0x0216
Const $WM_ENTERSIZEMOVE = 0x0231
Const $WM_EXITSIZEMOVE = 0x0232
Global $taskbarPos = WinGetPos("[CLASS:Shell_TrayWnd]"), $x_start, $y_start
Global $bEVENTMOVED = False
Global $iDock = 0
Global $aMPosStart
$gui = GUICreate("Attach Window GUI to screen edge", 350, 200)
GUISetState()
GUIRegisterMsg($WM_ENTERSIZEMOVE, "On_WM_ENTERSIZEMOVE")
GUIRegisterMsg($WM_MOVING, "On_WM_MOVING")
GUIRegisterMsg($WM_EXITSIZEMOVE, "On_WM_EXITSIZEMOVE")
While GUIGetMsg() <> $GUI_EVENT_CLOSE
WEnd
Func On_WM_ENTERSIZEMOVE()
    $aMPos = MouseGetPos()
    $x_start = $aMPos[0]
    $y_start = $aMPos[1]
    If $bEVENTMOVED = False Then
        $oldMouseMode = Opt("MouseCoordMode", 0)
        $aMPosStart = MouseGetPos()
        Opt("MouseCoordMode", $oldMouseMode)
    EndIf
EndFunc
Func On_WM_MOVING($hWnd, $Msg, $wParam, $lParam)
    $aMPos = MouseGetPos()
    $bEVENTMOVED = True
    $rect = DllStructCreate("long left; long top; long right; long bottom", $lParam)
    $left = DllStructGetData($rect, "left")
    $top = DllStructGetData($rect, "top")
    $right = DllStructGetData($rect, "right")
    $bottom = DllStructGetData($rect, "bottom")
    Select 
        Case ($left <= $Range And $aMPos[0] < $x_start) 
            If $iDock <> 1 Then
                $iDock = 1
                DllStructSetData($rect, "left", 0)
                DllStructSetData($rect, "right", $right - $left)
                _DockMouse()
            EndIf
        Case ($top <= $Range And $aMPos[1] < $y_start)
            If $iDock <> 2 Then
                $iDock = 2
                DllStructSetData($rect, "top", 0)
                DllStructSetData($rect, "bottom", $bottom - $top)
                _DockMouse()
            EndIf
        Case ($right >= (@DesktopWidth - $Range) And $aMPos[0] > $x_start)
            If $iDock <> 3 Then
                $iDock = 3
                DllStructSetData($rect, "right", @DesktopWidth)
                DllStructSetData($rect, "left", (@DesktopWidth - $right) + $left)
                _DockMouse()
            EndIf
        Case ($bottom >= ($taskbarPos[1] - $Range) And $aMPos[1] > $y_start)
            If $iDock <> 4 Then
                $iDock = 4
                DllStructSetData($rect, "bottom", $taskbarPos[1])
                DllStructSetData($rect, "top", ($taskbarPos[1] - $bottom) + $top)
                _DockMouse()
            EndIf
        Case Else
            ;If gui moves away from docked position, reset to allow it to redock
            Switch $iDock
                Case 1
                    If $left > $Range / 2 Then _DockReset()
                Case 2
                    If $top > $Range / 2 Then _DockReset()
                Case 3
                    If $right < (@DesktopWidth - ($Range / 2)) Then _DockReset()
                Case 4
                    If $bottom < ($taskbarPos[1] - ($Range / 2)) Then _DockReset()
            EndSwitch
    EndSelect
EndFunc
Func On_WM_EXITSIZEMOVE()
    _DockMouse()
EndFunc
Func _DockReset()
    $iDock = 0
    On_WM_ENTERSIZEMOVE()
EndFunc
Func _DockMouse()
    MouseUp("left")
    If $bEVENTMOVED Then
        $oldMouseMode = Opt("MouseCoordMode", 0)
        MouseMove($aMPosStart[0], $aMPosStart[1], 0)
        Opt("MouseCoordMode", $oldMouseMode)
    EndIf
    $bEVENTMOVED = False
EndFunc
  • 3 months later...
Posted

Finally!!!

Here it is:

#include <GUIConstants.au3>

Global Const $WM_WINDOWPOSCHANGING = 0x0046

Global $nRange = 20

$hGUI = GUICreate("GUI Stickable!", 280, 150)

$Stickable_CB = GUICtrlCreateCheckbox("Stickable?", 20, 30)
GUICtrlSetState(-1, $GUI_CHECKED)

$Range_Input = GUICtrlCreateInput($nRange, 20, 60, 40, 20, $ES_READONLY)
$UpDown = GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 80, 5)

GUISetState()

GUICreate("Some extra window", 320, 180, 0, 0)
GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $Stickable_CB
            If GUICtrlRead($Stickable_CB) = $GUI_CHECKED Then
                GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")
            Else
                GUIRegisterMsg($WM_WINDOWPOSCHANGING, "")
            EndIf
        Case $UpDown
            $nRange = GUICtrlRead($Range_Input)
    EndSwitch
WEnd

Func WM_WINDOWPOSCHANGING($hWnd, $Msg, $wParam, $lParam)
    Local $IsSideWinStick   = True ;Set to True for sticking to all visible windows :) - but it's hangs up CPU :(
    
    Local $stWinPos         = DllStructCreate("uint;uint;int;int;int;int;uint", $lParam)
    Local $nLeft            = DllStructGetData($stWinPos, 3)
    Local $nTop             = DllStructGetData($stWinPos, 4)
    
    Local $aCurWinPos       = WinGetPos($hWnd)
    Local $aWorkArea        = _GetWorkingArea()
    
    ;Left
    If Abs($aWorkArea[0] - $nLeft) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[0])
    ;Right
    If Abs($nLeft + $aCurWinPos[2] - $aWorkArea[2]) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[2] - $aCurWinPos[2])
    ;Top
    If Abs($aWorkArea[1] - $nTop) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[1])
    ;Bottom
    If Abs($nTop + $aCurWinPos[3] - $aWorkArea[3]) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[3] - $aCurWinPos[3])
    
    If Not $IsSideWinStick Then Return 0
    
    Local $ahWnd = WinList()
    
    For $i = 1 To UBound($ahWnd) - 1
        If $ahWnd[$i][1] = $hWnd Or Not BitAND(WinGetState($ahWnd[$i][1]), 2) Or _
            BitAND(WinGetState($ahWnd[$i][1]), 32) Or BitAND(WinGetState($ahWnd[$i][1]), 16) Then ContinueLoop
        
        $aSideWinPos = WinGetPos($ahWnd[$i][1])
        
        If $aCurWinPos[1] + $aCurWinPos[3] >= $aSideWinPos[1] And $aCurWinPos[1] <= $aSideWinPos[1] + $aSideWinPos[3] Then
            ;Left
            If Abs(($aSideWinPos[0] + $aSideWinPos[2]) - $nLeft) <= $nRange Then _
                DllStructSetData($stWinPos, 3, $aSideWinPos[0] + $aSideWinPos[2])
            
            ;Right
            If Abs($nLeft + $aCurWinPos[2] - $aSideWinPos[0]) <= $nRange Then _
                DllStructSetData($stWinPos, 3, $aSideWinPos[0] - $aCurWinPos[2])
        EndIf
        
        If $aCurWinPos[0] + $aCurWinPos[2] >= $aSideWinPos[0] And $aCurWinPos[0] <= $aSideWinPos[0] + $aSideWinPos[2] Then
            ;Top
            If Abs(($aSideWinPos[1] + $aSideWinPos[3]) - $nTop) <= $nRange Then _
                DllStructSetData($stWinPos, 4, $aSideWinPos[1] + $aSideWinPos[3])
            
            ;Bottom
            If Abs($nTop + $aCurWinPos[3] - $aSideWinPos[1]) <= $nRange Then _
                DllStructSetData($stWinPos, 4, $aSideWinPos[1] - $aCurWinPos[3])
        EndIf
    Next
    
    Return 0
EndFunc

;===============================================================================
;
; Function Name:    _GetWorkingArea()
; Description:      Returns the coordinates of desktop working area rectangle
; Parameter(s):     None
; Return Value(s):  On Success - Array containing coordinates:
;                        $a[0] = left
;                        $a[1] = top
;                        $a[2] = right
;                        $a[3] = bottom
;                   On Failure - 0
;
;BOOL WINAPI SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
;uiAction SPI_GETWORKAREA = 48
;===============================================================================
Func _GetWorkingArea()
    Local Const $SPI_GETWORKAREA = 48
    Local $stRECT = DllStructCreate("long; long; long; long")
    Local $SPIRet = DllCall("User32.dll", "int", "SystemParametersInfo", _
                        "uint", $SPI_GETWORKAREA, "uint", 0, "ptr", DllStructGetPtr($stRECT), "uint", 0)
    If @error Then Return 0
    If $SPIRet[0] = 0 Then Return 0
    
    Local $sLeftArea = DllStructGetData($stRECT, 1)
    Local $sTopArea = DllStructGetData($stRECT, 2)
    Local $sRightArea = DllStructGetData($stRECT, 3)
    Local $sBottomArea = DllStructGetData($stRECT, 4)
    
    Local $aRet[4] = [$sLeftArea, $sTopArea, $sRightArea, $sBottomArea]
    Return $aRet
EndFunc

The main idea is from AutoIt Wrappers (GUI snap to corners by Lazycat).

If you set $IsSideWinStick = True, then the window can be sticked to all visible windows, but the CPU load is increesing badly :)

 

  Reveal hidden contents

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Posted

  MsCreatoR said:

Finally!!!

Finally what.

And instead of looping through WinList, try WindowFromPoint.

"be smart, drink your wine"

Posted

  Siao said:

instead of looping through WinList, try WindowFromPoint.

Not sure that would prevent the problem of snapping to hidden frames which looks unpleasant to me if I've got a lot of them.

I would prefer that there was a new window, like a POPUP, which was just an even clour and transparent which did the snapping and kept on top, but otherwise tracked the window being moved. So the window being dragged moves smoothly, but when you let go it snaps to the POPUP window position and then the popup is destroyed. But probably that's just my strange preference.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Posted

@Siao

  Quote

Finally what.

Finally it's work like in other apps :)

  Quote

And instead of looping through WinList, try WindowFromPoint.

Can you be please more specific?

@martin

  Quote

Not sure that would prevent the problem of snapping to hidden frames which looks unpleasant to me if I've got a lot of them.

What you mean by "snapping to hidden frames"?

There is one more problem - the window is snapped to edges only when you release the mouse button (if you have option "Show window contents while dragging" turned off), but we can fix it by enable that option while moving the window...

#include <GUIConstants.au3>

Global Const $WM_WINDOWPOSCHANGING          = 0x0046
Global Const $WM_SYSCOMMAND                 = 0x0112
Global Const $WM_EXITSIZEMOVE               = 0x0232
Global Const $SC_MOVE                       = 0xF010
Global Const $SC_SIZE                       = 0xF000

Global $nRange = 20

$hGUI = GUICreate("GUI Stickable!", 280, 150)
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE")
GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")

$Stickable_CB = GUICtrlCreateCheckbox("Stickable?", 20, 30)
GUICtrlSetState(-1, $GUI_CHECKED)

$Range_Input = GUICtrlCreateInput($nRange, 20, 60, 40, 20, $ES_READONLY)
$UpDown = GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 80, 5)

GUISetState()

GUICreate("Some extra window", 320, 180, 0, 0)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $Stickable_CB
            If GUICtrlRead($Stickable_CB) = $GUI_CHECKED Then
                GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")
                GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
                GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE")
            Else
                GUIRegisterMsg($WM_WINDOWPOSCHANGING, "")
                GUIRegisterMsg($WM_SYSCOMMAND, "")
                GUIRegisterMsg($WM_EXITSIZEMOVE, "")
            EndIf
        Case $UpDown
            $nRange = GUICtrlRead($Range_Input)
    EndSwitch
WEnd

Func WM_WINDOWPOSCHANGING($hWnd, $Msg, $wParam, $lParam)
    Local $IsSideWinStick   = True ;Set to True for sticking to all visible windows :) - but it's hangs up CPU :(
    
    Local $stWinPos         = DllStructCreate("uint;uint;int;int;int;int;uint", $lParam)
    Local $nLeft            = DllStructGetData($stWinPos, 3)
    Local $nTop             = DllStructGetData($stWinPos, 4)
    
    Local $aCurWinPos       = WinGetPos($hWnd)
    Local $aWorkArea        = _GetWorkingArea()
    
    ;Left
    If Abs($aWorkArea[0] - $nLeft) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[0])
    ;Right
    If Abs($nLeft + $aCurWinPos[2] - $aWorkArea[2]) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[2] - $aCurWinPos[2])
    ;Top
    If Abs($aWorkArea[1] - $nTop) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[1])
    ;Bottom
    If Abs($nTop + $aCurWinPos[3] - $aWorkArea[3]) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[3] - $aCurWinPos[3])
    
    If Not $IsSideWinStick Then Return 0
    
    Local $ahWnd = WinList()
    
    For $i = 1 To UBound($ahWnd) - 1
        If $ahWnd[$i][1] = $hWnd Or Not BitAND(WinGetState($ahWnd[$i][1]), 2) Or _
            BitAND(WinGetState($ahWnd[$i][1]), 32) Or BitAND(WinGetState($ahWnd[$i][1]), 16) Then ContinueLoop
        
        $aSideWinPos = WinGetPos($ahWnd[$i][1])
        
        If $aCurWinPos[1] + $aCurWinPos[3] >= $aSideWinPos[1] And $aCurWinPos[1] <= $aSideWinPos[1] + $aSideWinPos[3] Then
            ;Left
            If Abs(($aSideWinPos[0] + $aSideWinPos[2]) - $nLeft) <= $nRange Then _
                DllStructSetData($stWinPos, 3, $aSideWinPos[0] + $aSideWinPos[2])
            
            ;Right
            If Abs($nLeft + $aCurWinPos[2] - $aSideWinPos[0]) <= $nRange Then _
                DllStructSetData($stWinPos, 3, $aSideWinPos[0] - $aCurWinPos[2])
        EndIf
        
        If $aCurWinPos[0] + $aCurWinPos[2] >= $aSideWinPos[0] And $aCurWinPos[0] <= $aSideWinPos[0] + $aSideWinPos[2] Then
            ;Top
            If Abs(($aSideWinPos[1] + $aSideWinPos[3]) - $nTop) <= $nRange Then _
                DllStructSetData($stWinPos, 4, $aSideWinPos[1] + $aSideWinPos[3])
            
            ;Bottom
            If Abs($nTop + $aCurWinPos[3] - $aSideWinPos[1]) <= $nRange Then _
                DllStructSetData($stWinPos, 4, $aSideWinPos[1] - $aCurWinPos[3])
        EndIf
    Next
    
    Return 0
EndFunc

Func WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)
    Switch BitAND($wParam, 0xFFF0)
        Case $SC_SIZE, $SC_MOVE
            DllCall("user32.dll", "int", "SystemParametersInfo", "int", 37, "int", 1, "ptr", 0, "int", 2)
    EndSwitch
EndFunc

Func WM_EXITSIZEMOVE($hWnd, $Msg, $wParam, $lParam)
    Local $Old_Show_Content_Param = RegRead("HKEY_CURRENT_USER\Control Panel\Desktop", "DragFullWindows")
    DllCall("user32.dll", "int", "SystemParametersInfo", "int", 37, "int", $Old_Show_Content_Param, "ptr", 0, "int", 2)
EndFunc

;===============================================================================
;
; Function Name:    _GetWorkingArea()
; Description:      Returns the coordinates of desktop working area rectangle
; Parameter(s):     None
; Return Value(s):  On Success - Array containing coordinates:
;                        $a[0] = left
;                        $a[1] = top
;                        $a[2] = right
;                        $a[3] = bottom
;                   On Failure - 0
;
;BOOL WINAPI SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
;uiAction SPI_GETWORKAREA = 48
;===============================================================================
Func _GetWorkingArea()
    Local Const $SPI_GETWORKAREA = 48
    Local $stRECT = DllStructCreate("long; long; long; long")
    Local $SPIRet = DllCall("User32.dll", "int", "SystemParametersInfo", _
                        "uint", $SPI_GETWORKAREA, "uint", 0, "ptr", DllStructGetPtr($stRECT), "uint", 0)
    If @error Then Return 0
    If $SPIRet[0] = 0 Then Return 0
    
    Local $sLeftArea = DllStructGetData($stRECT, 1)
    Local $sTopArea = DllStructGetData($stRECT, 2)
    Local $sRightArea = DllStructGetData($stRECT, 3)
    Local $sBottomArea = DllStructGetData($stRECT, 4)
    
    Local $aRet[4] = [$sLeftArea, $sTopArea, $sRightArea, $sBottomArea]
    Return $aRet
EndFunc

 

  Reveal hidden contents

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Posted

@ MsCreatoR

  Quote

What you mean by "snapping to hidden frames"?

I mean if there are lots of open windows, then the window you are dragging will snap to the hidden window edges (the windows covered by other windows) causing a jerky movement while you drag it. Since you can't see these windows it looks odd and you probably don't want to snap to them, so I thought it would be better to keep to only the visible windows.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Posted

  MsCreatoR said:

Finally it's work like in other apps ^_^

Weren't the examples from a few moths back working? :)

  martin said:

Not sure that would prevent the problem of snapping to hidden frames which looks unpleasant to me if I've got a lot of them.

It would, because WindowFromPoint would take the topmost window of a certain point on screen. It's just the problem that there would have to be multiple points to check.

But, frankly I don't quite understand the purpose of that "snap to everything" feature. If one is making some component window which should dock to some parent/siblings (like Winamp), then there's only these few known windows to work with. There's no need to scan every window and try to attach to everything including explorer and whatever random application windows the user happens to be running and open on the screen...

"be smart, drink your wine"

Posted

  Siao said:

It would, because WindowFromPoint would take the topmost window of a certain point on screen. It's just the problem that there would have to be multiple points to check.

But, frankly I don't quite understand the purpose of that "snap to everything" feature. If one is making some component window which should dock to some parent/siblings (like Winamp), then there's only these few known windows to work with. There's no need to scan every window and try to attach to everything including explorer and whatever random application windows the user happens to be running and open on the screen...

That makes more sense to me; decide which windows you want to snap to and ignore the rest.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Posted

  Quote

I mean if there are lots of open windows, then the window you are dragging will snap to the hidden window edges (the windows covered by other windows)

Ok, thanks, now i see what you mean.

But i am not sure how to get only visible (to the eye) window, and we need not the whole window, only the visible edges..

  Quote

Weren't the examples from a few moths back working?

They do, but there was some issues with the mouse position after snapping.

  Quote

I don't quite understand the purpose of that "snap to everything" feature

Well, in some applications i have seen such feature, for example take KMPlayer, he does have such effect, but he also have the same issue with snapping to the background frames :)

I will try to use WindowFromPoint... maybe there is need to search the point that on the left/right/top/bottom side of our gui window, and then snapp it (if found forground window)...

 

  Reveal hidden contents

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

Posted (edited)

I came up with something like this:

#include <GUIConstants.au3>

Global Const $WM_WINDOWPOSCHANGING          = 0x0046
Global Const $WM_SYSCOMMAND                 = 0x0112
Global Const $WM_EXITSIZEMOVE               = 0x0232
Global Const $SC_MOVE                       = 0xF010
Global Const $SC_SIZE                       = 0xF000

Global $nRange                              = 20
Global $IsSideWinStick                      = False ;True for sticking to all visible windows ( it's hangs up CPU).

$hGUI = GUICreate("GUI Stickable!", 280, 150)
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE")
GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")

$Stickable_CB = GUICtrlCreateCheckbox("Stickable", 20, 20)
GUICtrlSetState(-1, $GUI_CHECKED)

$StickableToAll_CB = GUICtrlCreateCheckbox("Stickable to all windows (High CPU usage)", 20, 40)

$Range_Input = GUICtrlCreateInput($nRange, 20, 70, 40, 20, $ES_READONLY)
$UpDown = GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 80, 5)

GUISetState()

GUICreate("Some extra window", 320, 180, 0, 0)
GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $Stickable_CB
            If GUICtrlRead($Stickable_CB) = $GUI_CHECKED Then
                GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")
                GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
                GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE")
            Else
                GUIRegisterMsg($WM_WINDOWPOSCHANGING, "")
                GUIRegisterMsg($WM_SYSCOMMAND, "")
                GUIRegisterMsg($WM_EXITSIZEMOVE, "")
            EndIf
        Case $StickableToAll_CB
            If GUICtrlRead($StickableToAll_CB) = $GUI_CHECKED Then
                $IsSideWinStick = True
            Else
                $IsSideWinStick = False
            EndIf
        Case $UpDown
            $nRange = GUICtrlRead($Range_Input)
    EndSwitch
WEnd

Func WM_WINDOWPOSCHANGING($hWnd, $Msg, $wParam, $lParam)
    Local $stWinPos         = DllStructCreate("uint;uint;int;int;int;int;uint", $lParam)
    Local $nLeft            = DllStructGetData($stWinPos, 3)
    Local $nTop             = DllStructGetData($stWinPos, 4)
    
    Local $aCurWinPos       = WinGetPos($hWnd)
    Local $aWorkArea        = _GetWorkingArea()
    
    ;Left
    If Abs($aWorkArea[0] - $nLeft) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[0])
    ;Right
    If Abs($nLeft + $aCurWinPos[2] - $aWorkArea[2]) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[2] - $aCurWinPos[2])
    ;Top
    If Abs($aWorkArea[1] - $nTop) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[1])
    ;Bottom
    If Abs($nTop + $aCurWinPos[3] - $aWorkArea[3]) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[3] - $aCurWinPos[3])
    
    If Not $IsSideWinStick Then Return 0
    
    Local $ahWnd = WinList()
    
    For $i = 1 To UBound($ahWnd) - 1
        If $ahWnd[$i][1] = $hWnd Or Not BitAND(WinGetState($ahWnd[$i][1]), 2) Then ContinueLoop
        
        $aSideWinPos = WinGetPos($ahWnd[$i][1])
        If UBound($aSideWinPos) < 3 Then ContinueLoop
        
        Local $XPoint = $aSideWinPos[0]+15
        Local $YPoint = $aSideWinPos[1]+15
        
        If $XPoint < 0 Then $XPoint = 5
        If $YPoint < 0 Then $YPoint = 5
        
        If $aCurWinPos[1] + $aCurWinPos[3] >= $aSideWinPos[1] And $aCurWinPos[1] <= $aSideWinPos[1] + $aSideWinPos[3] Then
            ;Left
            If Abs(($aSideWinPos[0] + $aSideWinPos[2]) - $nLeft) <= $nRange And _
                WindowFromPoint($XPoint, $YPoint) = $ahWnd[$i][1] Then _
                    DllStructSetData($stWinPos, 3, $aSideWinPos[0] + $aSideWinPos[2])
            
            ;Right
            If Abs($nLeft + $aCurWinPos[2] - $aSideWinPos[0]) <= $nRange And _
                WindowFromPoint($XPoint, $YPoint) = $ahWnd[$i][1] Then _
                    DllStructSetData($stWinPos, 3, $aSideWinPos[0] - $aCurWinPos[2])
        EndIf
        
        If $aCurWinPos[0] + $aCurWinPos[2] >= $aSideWinPos[0] And $aCurWinPos[0] <= $aSideWinPos[0] + $aSideWinPos[2] Then
            ;Top
            If Abs(($aSideWinPos[1] + $aSideWinPos[3]) - $nTop) <= $nRange And _
                WindowFromPoint($XPoint, $YPoint) = $ahWnd[$i][1] Then _
                    DllStructSetData($stWinPos, 4, $aSideWinPos[1] + $aSideWinPos[3])
            
            ;Bottom
            If Abs($nTop + $aCurWinPos[3] - $aSideWinPos[1]) <= $nRange And _
                WindowFromPoint($XPoint, $YPoint) = $ahWnd[$i][1] Then _
                    DllStructSetData($stWinPos, 4, $aSideWinPos[1] - $aCurWinPos[3])
        EndIf
    Next
    
    Return 0
EndFunc

Func WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)
    Switch BitAND($wParam, 0xFFF0)
        Case $SC_SIZE, $SC_MOVE
            DllCall("user32.dll", "int", "SystemParametersInfo", "int", 37, "int", 1, "ptr", 0, "int", 2)
    EndSwitch
EndFunc

Func WM_EXITSIZEMOVE($hWnd, $Msg, $wParam, $lParam)
    Local $Old_Show_Content_Param = RegRead("HKEY_CURRENT_USER\Control Panel\Desktop", "DragFullWindows")
    DllCall("user32.dll", "int", "SystemParametersInfo", "int", 37, "int", $Old_Show_Content_Param, "ptr", 0, "int", 2)
EndFunc

Func WindowFromPoint($XPoint, $YPoint)
    Local $aResult = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $XPoint, "int", $YPoint)
    Return $aResult[0]
EndFunc

;===============================================================================
;
; Function Name:    _GetWorkingArea()
; Description:      Returns the coordinates of desktop working area rectangle
; Parameter(s):     None
; Return Value(s):  On Success - Array containing coordinates:
;                        $a[0] = left
;                        $a[1] = top
;                        $a[2] = right
;                        $a[3] = bottom
;                   On Failure - 0
;
;BOOL WINAPI SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
;uiAction SPI_GETWORKAREA = 48
;===============================================================================
Func _GetWorkingArea()
    Local Const $SPI_GETWORKAREA = 48
    Local $stRECT = DllStructCreate("long; long; long; long")
    Local $SPIRet = DllCall("User32.dll", "int", "SystemParametersInfo", _
                        "uint", $SPI_GETWORKAREA, "uint", 0, "ptr", DllStructGetPtr($stRECT), "uint", 0)
    If @error Then Return 0
    If $SPIRet[0] = 0 Then Return 0
    
    Local $sLeftArea = DllStructGetData($stRECT, 1)
    Local $sTopArea = DllStructGetData($stRECT, 2)
    Local $sRightArea = DllStructGetData($stRECT, 3)
    Local $sBottomArea = DllStructGetData($stRECT, 4)
    
    Local $aRet[4] = [$sLeftArea, $sTopArea, $sRightArea, $sBottomArea]
    Return $aRet
EndFunc

I know it's incorrect, i should probably check much more positions (WindowFromPoint), but when i tried the "gui movement" was corrupted ^_^ - it was slow and the CPU was very high. OK, i think the issue with "snapping to background frames" is fixed! - i just used as point the left and top coords of current window that checked in the "For" loop.

If someone can make it work more accurate/correct fix the issue with high CPU usage, it will be great! But i personaly, give up here (for now?) :)

Edited by MsCreatoR

 

  Reveal hidden contents

 

 

AutoIt is simple, subtle, elegant. © AutoIt Team

  • 6 years later...
Posted

Here's a way to make it stick to one window only (our main window) : 

#include <GUIConstants.au3>


Global Const $SC_MOVE                       = 0xF010
Global Const $SC_SIZE                       = 0xF000

Global $nRange                              = 20
Global $IsSideWinStick                      = False ;True for sticking to all visible windows ( it's hangs up CPU).
GLobal $stickyRange=25

Global $main=GUICreate("Main Window", 400, 300, 0, 0)
GUISetState()

Global $hGUI = GUICreate("GUI Stickable!", 280, 150, Default, Default, -1, BitOR($WS_EX_TOOLWINDOW, $WS_EX_WINDOWEDGE))
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE")
GUIRegisterMsg($WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING")

$useless_shit = GUICtrlCreateCheckbox("I'm a nice useless shit", 20, 20)
GUICtrlSetState(-1, $GUI_CHECKED)

$another = GUICtrlCreateCheckbox("I'm another useless shit", 20, 40)

$Range_Input = GUICtrlCreateInput($nRange, 20, 70, 40, 20, $ES_READONLY)
$UpDown = GUICtrlCreateUpdown(-1)
GUICtrlSetLimit(-1, 80, 5)

GUISetState()

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $UpDown
            $nRange = GUICtrlRead($Range_Input)
    EndSwitch
WEnd

Func WM_WINDOWPOSCHANGING($hWnd, $Msg, $wParam, $lParam)
    If $hWnd=$hGUI Then
    Local $stWinPos         = DllStructCreate("uint;uint;int;int;int;int;uint", $lParam)
    Local $nLeft            = DllStructGetData($stWinPos, 3)
    Local $nTop             = DllStructGetData($stWinPos, 4)

    Local $aCurWinPos       = WinGetPos($hWnd)
    Local $aWorkArea        = _GetWorkingArea()

    ;Left
    If Abs($aWorkArea[0] - $nLeft) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[0])
    ;Right
    If Abs($nLeft + $aCurWinPos[2] - $aWorkArea[2]) <= $nRange Then DllStructSetData($stWinPos, 3, $aWorkArea[2] - $aCurWinPos[2])
    ;Top
    If Abs($aWorkArea[1] - $nTop) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[1])
    ;Bottom
    If Abs($nTop + $aCurWinPos[3] - $aWorkArea[3]) <= $nRange Then DllStructSetData($stWinPos, 4, $aWorkArea[3] - $aCurWinPos[3])

    ;If Not $IsSideWinStick Then Return 0


    ;For $i = 1 To UBound($ahWnd) - 1
        ;If $ahWnd[$i][1] = $maingui Then
        ;If $ahWnd[$i][1] = $hWnd Or Not BitAND(WinGetState($ahWnd[$i][1]), 2) Then ContinueLoop

        $aSideWinPos = WinGetPos($main)
        ;If UBound($aSideWinPos) < 3 Then ContinueLoop

        Local $XPoint = $aSideWinPos[0]+15
        Local $YPoint = $aSideWinPos[1]+15

        If $XPoint < 0 Then $XPoint = 5
        If $YPoint < 0 Then $YPoint = 5

        If $aCurWinPos[1] + $aCurWinPos[3] >= $aSideWinPos[1] And $aCurWinPos[1] <= $aSideWinPos[1] + $aSideWinPos[3] Then
            ;Left
            If Abs(($aSideWinPos[0] + $aSideWinPos[2]) - $nLeft) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $main Then _
                    DllStructSetData($stWinPos, 3, $aSideWinPos[0] + $aSideWinPos[2])

            ;Right
            If Abs($nLeft + $aCurWinPos[2] - $aSideWinPos[0]) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $main Then _
                    DllStructSetData($stWinPos, 3, $aSideWinPos[0] - $aCurWinPos[2])
        EndIf

        If $aCurWinPos[0] + $aCurWinPos[2] >= $aSideWinPos[0] And $aCurWinPos[0] <= $aSideWinPos[0] + $aSideWinPos[2] Then
            ;Top
            If Abs(($aSideWinPos[1] + $aSideWinPos[3]) - $nTop) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $main Then _
                    DllStructSetData($stWinPos, 4, $aSideWinPos[1] + $aSideWinPos[3])

            ;Bottom
            If Abs($nTop + $aCurWinPos[3] - $aSideWinPos[1]) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $main Then _
                    DllStructSetData($stWinPos, 4, $aSideWinPos[1] - $aCurWinPos[3])
        EndIf
   ; Next
   EndIf

    Return 0
EndFunc


Func WM_INDOWPOSCHANGING($hWnd, $Msg, $wParam, $lParam)
    If $hWnd=$hGUI Then
    Local $stWinPos         = DllStructCreate("uint;uint;int;int;int;int;uint", $lParam)
    Local $nLeft            = DllStructGetData($stWinPos, 3)
    Local $nTop             = DllStructGetData($stWinPos, 4)

    Local $aCurWinPos       = WinGetPos($hWnd)
    Local $aWorkArea        = _GetWorkingArea()
    ;$aCurWinPos[2]=$aCurWinPos[2]+5
    ;$aCurWinPos[3]=$aCurWinPos[3]+5
    ;Left
    ;If Abs($aWorkArea[0] - $nLeft) <= $stickyRange Then DllStructSetData($stWinPos, 3, $aWorkArea[0])
    ;Right
    ;If Abs($nLeft + $aCurWinPos[2] - $aWorkArea[2]) <= $stickyRange Then DllStructSetData($stWinPos, 3, $aWorkArea[2] - $aCurWinPos[2])
    ;Top
    ;If Abs($aWorkArea[1] - $nTop) <= $stickyRange Then DllStructSetData($stWinPos, 4, $aWorkArea[1])
    ;Bottom
    ;If Abs($nTop + $aCurWinPos[3] - $aWorkArea[3]) <= $stickyRange Then DllStructSetData($stWinPos, 4, $aWorkArea[3] - $aCurWinPos[3])

    ;If Not $IsSideWinStick Then Return 0

    ;Local $ahWnd = WinList()

    ;For $i = 1 To UBound($ahWnd) - 1
        ;If $ahWnd[$i][1] = $hGUI Then
        ;If $ahWnd[$i][1] = $hWnd Or Not BitAND(WinGetState($ahWnd[$i][1]), 2) Then ContinueLoop

        $aSideWinPos = WinGetPos($hGUI)
        ;If UBound($aSideWinPos) < 3 Then ContinueLoop

        Local $XPoint = $aSideWinPos[0]+15
        Local $YPoint = $aSideWinPos[1]+15

        If $XPoint < 0 Then $XPoint = 5
        If $YPoint < 0 Then $YPoint = 5

        If $aCurWinPos[1] + $aCurWinPos[3] >= $aSideWinPos[1] And $aCurWinPos[1] <= $aSideWinPos[1] + $aSideWinPos[3] Then
            ;Left
            If Abs(($aSideWinPos[0] + $aSideWinPos[2]) - $nLeft) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $hGUI Then _
                    DllStructSetData($stWinPos, 3, $aSideWinPos[0] + $aSideWinPos[2])

            ;Right
            If Abs($nLeft + $aCurWinPos[2] - $aSideWinPos[0]) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $hGUI Then _
                    DllStructSetData($stWinPos, 3, $aSideWinPos[0] - $aCurWinPos[2])
        EndIf

        If $aCurWinPos[0] + $aCurWinPos[2] >= $aSideWinPos[0] And $aCurWinPos[0] <= $aSideWinPos[0] + $aSideWinPos[2] Then
            ;Top
            If Abs(($aSideWinPos[1] + $aSideWinPos[3]) - $nTop) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $hGUI Then _
                    DllStructSetData($stWinPos, 4, $aSideWinPos[1] + $aSideWinPos[3])

            ;Bottom
            If Abs($nTop + $aCurWinPos[3] - $aSideWinPos[1]) <= $stickyRange And _
                WindowFromPoint($XPoint, $YPoint) = $hGUI Then _
                    DllStructSetData($stWinPos, 4, $aSideWinPos[1] - $aCurWinPos[3])
        EndIf
    ;EndIf
    ;Next

    Return 0
EndIf
EndFunc


Func WM_SYSCOMMAND($hWnd, $Msg, $wParam, $lParam)
    Switch BitAND($wParam, 0xFFF0)
        Case $SC_SIZE, $SC_MOVE
            DllCall("user32.dll", "int", "SystemParametersInfo", "int", 37, "int", 1, "ptr", 0, "int", 2)
    EndSwitch
EndFunc

Func WM_EXITSIZEMOVE($hWnd, $Msg, $wParam, $lParam)
    Local $Old_Show_Content_Param = RegRead("HKEY_CURRENT_USER\Control Panel\Desktop", "DragFullWindows")
    DllCall("user32.dll", "int", "SystemParametersInfo", "int", 37, "int", $Old_Show_Content_Param, "ptr", 0, "int", 2)
EndFunc

Func WindowFromPoint($XPoint, $YPoint)
    Local $aResult = DllCall("User32.dll", "hwnd", "WindowFromPoint", "int", $XPoint, "int", $YPoint)
    Return $aResult[0]
EndFunc

;===============================================================================
;
; Function Name:    _GetWorkingArea()
; Description:      Returns the coordinates of desktop working area rectangle
; Parameter(s):     None
; Return Value(s):  On Success - Array containing coordinates:
;                        $a[0] = left
;                        $a[1] = top
;                        $a[2] = right
;                        $a[3] = bottom
;                   On Failure - 0
;
;BOOL WINAPI SystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
;uiAction SPI_GETWORKAREA = 48
;===============================================================================
Func _GetWorkingArea()
    Local Const $SPI_GETWORKAREA = 48
    Local $stRECT = DllStructCreate("long; long; long; long")
    Local $SPIRet = DllCall("User32.dll", "int", "SystemParametersInfo", _
                        "uint", $SPI_GETWORKAREA, "uint", 0, "ptr", DllStructGetPtr($stRECT), "uint", 0)
    If @error Then Return 0
    If $SPIRet[0] = 0 Then Return 0

    Local $sLeftArea = DllStructGetData($stRECT, 1)
    Local $sTopArea = DllStructGetData($stRECT, 2)
    Local $sRightArea = DllStructGetData($stRECT, 3)
    Local $sBottomArea = DllStructGetData($stRECT, 4)

    Local $aRet[4] = [$sLeftArea, $sTopArea, $sRightArea, $sBottomArea]
    Return $aRet
EndFunc

Never forget to mark a question as resolved, this button has been purposely created :-P 

  • Moderators
Posted

perfaram,

You do realise that the post above yours dates from over 6 years ago? In future please do not resurrect threads from this far back - the language has changed so much that it is likely that the functionality has already been incorporated and the previously posted code will almost certainly not run in the current version of AutoIt without modification. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

  Reveal hidden contents

 

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