Blaxxun Posted June 21 Share Posted June 21 Hello fellow friends, I have a working code for a simple mouse selection rectangle on a transparent window. Works fine for the first click, hold, drag, and release. A green rectangle is drawn. But at the second attempt of dragging the rectangle the GUI suddenly becomes click-through and the code/text in the underlying Skite IDE gets selected while dragging. I guess it is because something changes after the _WinAPI_UpdateLayeredWindow() command. Not sure what exactly it is... expandcollapse popup#include <Misc.au3> #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <WinAPI.au3> ; DPI awareness Win10 & Win11 If @OSVersion = 'WIN_10' Or @OSVersion = 'WIN_11' Then DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "hwnd", -2) EndIf HotKeySet("{ESC}", "End") _GDIPlus_Startup() Local $hGUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_LAYERED)) Local $hGDC = _WinAPI_GetDC($hGUI) Local $hMDC = _WinAPI_CreateCompatibleDC($hGDC) Local $hBit = _WinAPI_CreateCompatibleBitmap($hGDC, @DesktopWidth, @DesktopHeight) Local $hOld = _WinAPI_SelectObject($hMDC, $hBit) Local $hGFX = _GDIPlus_GraphicsCreateFromHDC($hMDC) Local $hPen = _GDIPlus_PenCreate(0xFF00FF00, 2) _GDIPlus_GraphicsSetSmoothingMode($hGFX, $GDIP_SMOOTHINGMODE_HIGHQUALITY) GUISetState(@SW_SHOW, $hGUI) While 1 StartMouseTracking($hGUI, $hGDC, $hMDC, $hGFX, $hPen) WEnd Func StartMouseTracking($hGUI, $hGDC, $hMDC, $hGFX, $hPen) Local $topLeft[2], $bottomRight[2] Local $isDragging = False While 1 If _IsPressed("01") Then ; Left mouse button is pressed down If Not $isDragging Then $topLeft[0] = MouseGetPos(0) $topLeft[1] = MouseGetPos(1) $isDragging = True Else ; Mouse dragging Local $currentX = MouseGetPos(0) Local $currentY = MouseGetPos(1) If $currentX <> $bottomRight[0] Or $currentY <> $bottomRight[1] Then $bottomRight[0] = $currentX $bottomRight[1] = $currentY DrawRectangle($topLeft[0], $topLeft[1], $bottomRight[0], $bottomRight[1], $hGUI, $hGDC, $hMDC, $hGFX, $hPen) EndIf EndIf ElseIf $isDragging Then ; Left mouse button is released $isDragging = False ConsoleWrite($topLeft[0] & " " & $topLeft[1] & " " & $bottomRight[0] & " " & $bottomRight[1] & @LF) ExitLoop EndIf WEnd EndFunc Func DrawRectangle($x1, $y1, $x2, $y2, $hGUI, $hGDC, $hMDC, $hGFX, $hPen) _GDIPlus_GraphicsClear($hGFX, 0x00000000) ; Clear with transparent background _GDIPlus_GraphicsDrawRect($hGFX, $x1, $y1, $x2 - $x1, $y2 - $y1, $hPen) Local $tSize = DllStructCreate("int;int") Local $tPointSource = DllStructCreate("int;int") Local $tPointDest = DllStructCreate("int;int") Local $tBlend = DllStructCreate("byte;byte;byte;byte") DllStructSetData($tSize, 1, @DesktopWidth) DllStructSetData($tSize, 2, @DesktopHeight) DllStructSetData($tBlend, 1, 0) ; AC_SRC_OVER DllStructSetData($tBlend, 2, 0) ; 0 DllStructSetData($tBlend, 3, 255) ; Alpha value 0-255 DllStructSetData($tBlend, 4, 1) ; AC_SRC_ALPHA | Has Alpha = 1 | Has No Alpha = 0 _WinAPI_UpdateLayeredWindow($hGUI, $hGDC, $tPointDest, $tSize, $hMDC, $tPointSource, 0, $tBlend, $ULW_ALPHA) EndFunc Func End() _GDIPlus_PenDispose($hPen) ; Cleanup pen _GDIPlus_GraphicsDispose($hGFX) ; Cleanup graphics object _WinAPI_ReleaseDC($hGUI, $hGDC) ; Release device context _WinAPI_SelectObject($hMDC, $hOld) ; Restore the old object _WinAPI_DeleteObject($hBit) ; Delete the bitmap _WinAPI_DeleteDC($hMDC) ; Delete the memory device context _GDIPlus_Shutdown() ; Shutdown GDI+ GUIDelete($hGUI) ; Delete overlay window Exit EndFunc Thanks! Link to comment Share on other sites More sharing options...
Solution ioa747 Posted June 22 Solution Share Posted June 22 (edited) Here, in a primitive way, I placed a block window ; make mouse block gui Local $block_gui = GUICreate("block_gui", 100, 100, -1, -1, $WS_POPUP, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) WinSetTrans($block_gui, "", 1) GUISetState(@SW_SHOW, $block_gui) GUISetCursor($MCID_CROSS, 1, $block_gui) Edit: here , more UpDate version ;move the $block_gui to active monitor If $sCurDevice <> $sDevice Then $sCurDevice = $sDevice ;ConsoleWrite("- $sCurDevice=" & $sCurDevice & @CRLF) WinMove($block_gui, "", $iDeskLeft, $iDeskTop, $iDeskWidth, $iDeskHeight) EndIf Edited June 22 by ioa747 I know that I know nothing Link to comment Share on other sites More sharing options...
Blaxxun Posted June 22 Author Share Posted June 22 @ioa747 Hi and thanks for your reply! Before I started this thread I was also experimenting with: $hGUI = GUICreate("", 100, 100, -1, -1, $WS_POPUP, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) WinSetTrans($hGUI, "", 1) In "WinSetTrans()" I found that if you use 0 then it becomes click-through. But everything from 1-255 becomes non click-through. Also, I was unable to draw opaque GFX elements on that "$WS_EX_TOOLWINDOW" because they get the same transparency as the window. So when I look at the code of your "NewCapture()" function. Do you suggest that I should use 2 transparent windows? One to Draw on and one to block the mouse from the background? Thank you! Link to comment Share on other sites More sharing options...
ioa747 Posted June 22 Share Posted June 22 taking a second look below the line: _WinAPI_UpdateLayeredWindow($hGUI, $hGDC, $tPointDest, $tSize, $hMDC, $tPointSource, 0, $tBlend, $ULW_ALPHA) Add: WinActivate($hGUI) I know that I know nothing Link to comment Share on other sites More sharing options...
Blaxxun Posted June 22 Author Share Posted June 22 (edited) @ioa747 Man, this actually works. Although its a dirty hack, lol. Framerate drops to 1/10th, lol. BUT it works! 😅 Edited June 22 by Blaxxun A-Team and ioa747 2 Link to comment Share on other sites More sharing options...
ioa747 Posted June 22 Share Posted June 22 I know that I know nothing Link to comment Share on other sites More sharing options...
Blaxxun Posted June 23 Author Share Posted June 23 @ioa747 Hello, thanks for the links! I experimented a bit more and found that if i use my own version of WinActivate() then the refresh is MUCH faster. DllCall("user32.dll", "int", "SetForegroundWindow", "hwnd", $hGUI) ; FAST WinActivate() Thank you! ioa747 1 Link to comment Share on other sites More sharing options...
Blaxxun Posted June 24 Author Share Posted June 24 I just noticed 2 things. 1. I put the solution on my post instead of @ioa747 and i don't know how to change that. 2. The solution is not really a 100% solution because the first mouse click still strikes through although the dragging of the mouse does not. So... Im still working on it. Link to comment Share on other sites More sharing options...
Blaxxun Posted June 24 Author Share Posted June 24 Okay, here is the final solution. Two windows. One window to draw on. Another window to block the mouse. 100% blocking mouse interactions with any underlying window. expandcollapse popup#include <GDIPlus.au3> #include <WindowsConstants.au3> HotKeySet("{ESC}", "End") ; DPI awareness Win10 & Win11 If @OSVersion = 'WIN_10' Or @OSVersion = 'WIN_11' Then DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "hwnd", -2) EndIf _GDIPlus_Startup() Local $hGUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_LAYERED)) ; Main GUI Local $hBLK = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, BitOR($WS_EX_TOPMOST, $WS_EX_TOOLWINDOW)) ; Mouse Block GUI WinSetTrans($hBLK, "", 1) ; 0 = clicktrough | > 0 = Non clickthrough Local $hGDC = _WinAPI_GetDC($hGUI) Local $hMDC = _WinAPI_CreateCompatibleDC($hGDC) Local $hBit = _WinAPI_CreateCompatibleBitmap($hGDC, @DesktopWidth, @DesktopHeight) Local $hOld = _WinAPI_SelectObject($hMDC, $hBit) Local $hGFX = _GDIPlus_GraphicsCreateFromHDC($hMDC) Local $hPen = _GDIPlus_PenCreate(0xFF00FF00, 2) _GDIPlus_GraphicsSetSmoothingMode($hGFX, $GDIP_SMOOTHINGMODE_HIGHQUALITY) GUISetState(@SW_SHOW, $hBLK) GUISetState(@SW_SHOW, $hGUI) ; Pre-create structs outside the function if they do not change Global $tSize = DllStructCreate("int;int") Global $tPSrc = DllStructCreate("int;int") Global $tPDst = DllStructCreate("int;int") Global $tBlnd = DllStructCreate("byte;byte;byte;byte") ; Initialize constant values in the structs DllStructSetData($tSize, 1, @DesktopWidth) DllStructSetData($tSize, 2, @DesktopHeight) DllStructSetData($tBlnd, 3, 255) ; Alpha value 0-255 DllStructSetData($tBlnd, 4, 1) ; AC_SRC_ALPHA | Has Alpha = 1 | Has No Alpha = 0 While 1 StartMouseTracking($hGUI, $hGDC, $hMDC, $hGFX, $hPen) WEnd Func StartMouseTracking($hGUI, $hGDC, $hMDC, $hGFX, $hPen) Local $topLeft[2], $bottomRight[2], $aCall Local $isDragging = False While 1 $aCall = DllCall("user32.dll", "short", "GetAsyncKeyState", "int", 0x01) If BitAND($aCall[0], 0x8000) <> 0 Then ; Left mouse button is pressed down If Not $isDragging Then $topLeft[0] = MouseGetPos(0) $topLeft[1] = MouseGetPos(1) $isDragging = True Else ; Mouse is dragging Local $currentX = MouseGetPos(0) Local $currentY = MouseGetPos(1) If $currentX <> $bottomRight[0] Or $currentY <> $bottomRight[1] Then $bottomRight[0] = $currentX $bottomRight[1] = $currentY DrawRectangle($topLeft[0], $topLeft[1], $bottomRight[0], $bottomRight[1], $hGUI, $hGDC, $hMDC, $hGFX, $hPen) EndIf EndIf ElseIf $isDragging Then ; Left mouse button is released $isDragging = False ConsoleWrite($topLeft[0] & " " & $topLeft[1] & " " & $bottomRight[0] & " " & $bottomRight[1] & @LF) ExitLoop EndIf WEnd EndFunc ;==>StartMouseTracking Func DrawRectangle(ByRef $x1, ByRef $y1, ByRef $x2, ByRef $y2, ByRef $hGUI, ByRef $hGDC, ByRef $hMDC, ByRef $hGFX, ByRef $hPen) _GDIPlus_GraphicsClear($hGFX, 0x00000000) ; Clear with transparent background _GDIPlus_GraphicsDrawRect($hGFX, $x1, $y1, $x2 - $x1, $y2 - $y1, $hPen) DllCall("user32.dll", "bool", "UpdateLayeredWindow", "hwnd", $hGUI, "handle", $hGDC, "struct*", $tPDst, "struct*", $tSize, "handle", $hMDC, "struct*", $tPSrc, "dword", 0, "struct*", $tBlnd, "dword", 0x02) ; FAST _WinAPI_UpdateLayeredWindow $ULW_ALPHA = 0x02 EndFunc ;==>DrawRectangle Func End() _GDIPlus_PenDispose($hPen) ; Cleanup pen _GDIPlus_GraphicsDispose($hGFX) ; Cleanup graphics object _WinAPI_ReleaseDC($hGUI, $hGDC) ; Release device context _WinAPI_SelectObject($hMDC, $hOld) ; Restore the old object _WinAPI_DeleteObject($hBit) ; Delete the bitmap _WinAPI_DeleteDC($hMDC) ; Delete the memory device context _GDIPlus_Shutdown() ; Shutdown GDI+ GUIDelete($hGUI) ; Delete overlay window Exit EndFunc ;==>End @ioa747 Thanks man for the inspiration! ioa747 1 Link to comment Share on other sites More sharing options...
Werty Posted June 24 Share Posted June 24 (edited) You need a sleep(10) before the WEnd in the tracking function at line 69, it's eating a whole core as it is now. Maybe also make it so the mouse can be moved in any direction, not just from left to right and from top to bottom, but also from right to left and bottom to top. Edited June 24 by Werty ioa747 and Blaxxun 2 Some guy's script + some other guy's script = my script! Link to comment Share on other sites More sharing options...
ioa747 Posted June 25 Share Posted June 25 $hBLK remains alive after the end ! Blaxxun 1 I know that I know nothing Link to comment Share on other sites More sharing options...
Blaxxun Posted June 25 Author Share Posted June 25 @Werty Yes, you are right. I will add even more. Like: Move whole rectangle after selection and adjusting each side of the rectangle. But until now my focus was to get rid of the click-through problem. @ioa747 Thanks for pointing this out! ioa747 1 Link to comment Share on other sites More sharing options...
Gianni Posted June 26 Share Posted June 26 (edited) On 6/25/2024 at 12:58 PM, Blaxxun said: @Werty Yes, you are right. I will add even more. Like: Move whole rectangle after selection and adjusting each side of the rectangle. But until now my focus was to get rid of the click-through problem. Hi @Blaxxun, ... if you want to try something similar you can take a look at my _crop() function found here: https://www.autoitscript.com/forum/topic/203545-%E2%9C%82%EF%B8%8F-quick-crop-tool Below is a simple script if you're interested in trying it out. I hope it can be of use to you. expandcollapse popup#include <GUIConstantsEx.au3> #include <croptool.au3> ; <-- https://www.autoitscript.com/forum/topic/203545-%E2%9C%82%EF%B8%8F-quick-crop-tool Opt("GUICloseOnESC", 0) ; Simple example of use of the _Crop() function ; ; it allows you to freely and visually select an area of the screen ; ; - To resize the area click the left mouse button on any of the moving colored edges of the tool and drag. ; You can also LeftClick within the selected area and drag to move the whole selector. ; ; - To terminate the selection operation RightClick within the selected area. ; ; You can alse terminate the selection operation by hitting the ESC key; ; in that case the @extended macro will be setted to true Example() Func Example() ; Create an example GUI Local $hGui = GUICreate("Crop Demo", 220, 105, -1, -1, -1, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST)) ; Create buttons Local $Crop = GUICtrlCreateButton("Start cropping", 10, 10, 200, 25) Local $Crop_hide_me = GUICtrlCreateButton("Hide me and crop", 10, 40, 200, 25) Local $Close = GUICtrlCreateButton("Close", 10, 70, 200, 25) ; Display the example GUI GUISetState(@SW_SHOW, $hGui) Local $aSelection = 0, $bExtended = 0 ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $Close ExitLoop Case $Crop ; start the crop tool $aSelection = _crop() $bExtended = @extended Case $Crop_hide_me ; hide this gui and start the crop tool GUISetState(@SW_HIDE, $hGui) $aSelection = _crop() $bExtended = @extended GUISetState(@SW_SHOW, $hGui) EndSwitch If $bExtended Then MsgBox(48, "Esc pressed", "no crop area selected") $aSelection = '' $bExtended = 0 EndIf If IsArray($aSelection) Then MsgBox(64, 'Coordinates of the selected area', _ "UpperLeft X : " & $aSelection[0] & @CRLF & _ "UpperLeft Y : " & $aSelection[1] & @CRLF & _ "Width : " & $aSelection[2] & @CRLF & _ "Height : " & $aSelection[3]) $aSelection = '' EndIf WEnd ; Delete the GUI GUIDelete($hGui) EndFunc ;==>Example Edited June 27 by Gianni Chimp small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt.... Link to comment Share on other sites More sharing options...
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