Jump to content

Recommended Posts

Posted

The default selection in Windows 10-11 on the Desktop is a translucent blue rectangle with non-transparent border. Is it possible to do this in AutoIt?
I wanted to use this effect for a screenshot utility.

1. Transparent window

2. Translucent rectangle (ARGB=0x460066CC)

3. Non-transparent border of rectangle (ARGB=0xFF0078D7)

For example, at least a static...

blue_selection.png

Posted

Yes of course it is possible and it is quite straightforward.

I would suggest you create a first GUI with solid borders (you can use _WinAPI GDI functions or _GDIPlus graphic functions).  Search the forum there is multiple examples how to perform this.

Once your first GUI is working, you will need to create a second GUI with a transparent background.  One easy way is to use WinSetTrans.

Create the base code for this, if you need some more help, we will be glad to enhance your code to make it work.

 

Posted

Thanks, ioa747, but I only see a semi-transparent yellow rectangle in your script. I don't see an opaque border. I can draw them separately, but I can't combine them together.

Nine, my script that doesn't work:
If I comment out $hRectangle_GUI and the Rectangle creation (left #cs-#ce for convenience) - then the Border is displayed. Both together are not displayed. I can't combine Border and Rectangle in one layer, they have different transparency.

#Include <Misc.au3>
#Include <ScreenCapture.au3>
#include <WindowsConstants.au3>

Global $iX1, $iY1, $iX2, $iY2, $aPos, $sBMP_Path, $bSuccess

Mark_Rect()

; Capture selected area
;$sBMP_Path = @ScriptDir & "\tmp.png"
;_ScreenCapture_Capture($sBMP_Path, $iX1, $iY1, $iX2, $iY2, False)

Exit

Func Mark_Rect() ; based on Melba23

    Local $aMouse_Pos, $hMask, $hMaster_Mask, $hMaster_Mask_2, $iTemp
    Local $UserDLL = DllOpen("user32.dll")

    ; Create transparent GUI with Cross cursor
    $hCross_GUI = GUICreate("Test", @DesktopWidth, @DesktopHeight - 20, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
    WinSetTrans($hCross_GUI, "", 1)
    GUISetState(@SW_SHOW, $hCross_GUI)
    GUISetCursor(3, 1, $hCross_GUI)

    ; Create non-transparent GUI for Border of Rectangle
    Local $hBorder_GUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST)
    GUISetBkColor(0x0078D7)
;#cs
    ; Create translucent GUI for Rectangle
    Local $hRectangle_GUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST)
    WinSetTrans($hRectangle_GUI, "", 70)
    GUISetBkColor(0x0066CC)
;#ce

    ; Wait until mouse button pressed
    While Not _IsPressed("01", $UserDLL)
        Sleep(10)
    WEnd

    ; Get first mouse position
    $aMouse_Pos = MouseGetPos()
    $iX1 = $aMouse_Pos[0]
    $iY1 = $aMouse_Pos[1]

    ; Draw a selection, wait until the mouse button is released
    While _IsPressed("01", $UserDLL)

        $aMouse_Pos = MouseGetPos()

        ; Create Border
        $hMaster_Mask_2 = _WinAPI_CreateRectRgn(0, 0, 0, 0)
        $hMask = _WinAPI_CreateRectRgn($iX1 + 1, $iY1 + 1, $aMouse_Pos[0],  $aMouse_Pos[1]) ; Internal Rect
        _WinAPI_CombineRgn($hMaster_Mask_2, $hMask, $hMaster_Mask_2, $RGN_OR )
        _WinAPI_DeleteObject($hMask)
        $hMask = _WinAPI_CreateRectRgn($iX1, $iY1, $aMouse_Pos[0] + 1,  $aMouse_Pos[1] + 1) ; External Rect
        _WinAPI_CombineRgn($hMaster_Mask_2, $hMask, $hMaster_Mask_2, $RGN_XOR)
        _WinAPI_DeleteObject($hMask)

        $bSuccess = _WinAPI_SetWindowRgn($hBorder_GUI, $hMaster_Mask_2, 1)
        ;ConsoleWrite("Border: " & $bSuccess & @CRLF)
        If WinGetState($hBorder_GUI) < 15 Then GUISetState()
;#cs
        ; Create Rectangle
        $hMaster_Mask = _WinAPI_CreateRectRgn(0, 0, 0, 0)
        $hMask = _WinAPI_CreateRectRgn($iX1 + 1, $iY1 + 1, $aMouse_Pos[0], $aMouse_Pos[1])
        _WinAPI_CombineRgn($hMaster_Mask, $hMask, $hMaster_Mask,  $RGN_OR)
        _WinAPI_DeleteObject($hMask)

        $bSuccess = _WinAPI_SetWindowRgn($hRectangle_GUI, $hMaster_Mask, 1)
        ;ConsoleWrite("Rectangle: " & $bSuccess & @CRLF)
        If WinGetState($hRectangle_GUI) < 15 Then GUISetState()
;#ce
        Sleep(10)
    WEnd

    ; Get second mouse position
    $iX2 = $aMouse_Pos[0]
    $iY2 = $aMouse_Pos[1]

    ; Set in correct order if required
    If $iX2 < $iX1 Then
        $iTemp = $iX1
        $iX1 = $iX2
        $iX2 = $iTemp
    EndIf
    If $iY2 < $iY1 Then
        $iTemp = $iY1
        $iY1 = $iY2
        $iY2 = $iTemp
    EndIf

    ;Cleaning
;#cs
    GUIDelete($hRectangle_GUI)
;#ce
    _WinAPI_DeleteObject($hMaster_Mask)
    _WinAPI_DeleteObject($hMaster_Mask_2)
    GUIDelete($hBorder_GUI)
    GUIDelete($hCross_GUI)
    DllClose($UserDLL)


EndFunc  ;==>Mark_Rect

 

Posted

Thanks for the effort, here the basis of what you are looking for :

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>
#include <WinAPIGdi.au3>

_ScreenRegion_GetRect(0x78D7, 0x66CC, 2, 46)

Func _ScreenRegion_GetRect($iEdge = 0, $iBack = 0xFFFFFF, $iSize = 4, $iTransparency = 0)

  Local $hCursorGUI = GUICreate("Screen Capture", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
  WinSetTrans($hCursorGUI, "", 1)
  GUISetState()
  GUISetCursor($MCID_CROSS, $GUI_CURSOR_OVERRIDE, $hCursorGUI)

  Local $hRectGUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST)
  GUISetBkColor($iEdge)

  Local $hFillGUI = GUICreate("", 0, 0, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
  GUISetBkColor($iBack)
  WinSetTrans($hFillGUI, "", $iTransparency)
  GUISetState()

  While Not _IsPressed("01") And Sleep(10)
  WEnd

  Local $iX1 = MouseGetPos(0), $iY1 = MouseGetPos(1)

  While _IsPressed("01") And Sleep(10)
    Rect($hRectGUI, $iX1, $iY1, MouseGetPos(0) - $iX1, MouseGetPos(1) - $iY1, $iSize, $hFillGUI)
    If WinGetState($hRectGUI) < 15 Then GUISetState(@SW_SHOW, $hRectGUI)
  WEnd

  GUIDelete($hFillGUI)
  GUIDelete($hRectGUI)
  GUIDelete($hCursorGUI)
  Local $aReturn = [$iX1, $iY1, MouseGetPos(0), MouseGetPos(1)]
  Return $aReturn
EndFunc   ;==>_ScreenRegion_GetRect

Func Rect($hWnd, $iX, $iY, $iWidth, $iHeight, $iSize, $hFill)
  WinMove($hFill, "", $iX, $iY, $iWidth, $iHeight)
  Local $hMain = _WinAPI_CreateRectRgn($iX, $iY, $iX + $iWidth, $iY + $iHeight)
  Local $hMask = _WinAPI_CreateRectRgn($iX + $iSize, $iY + $iSize, $iX + $iWidth - $iSize, $iY + $iHeight - $iSize)
  _WinAPI_CombineRgn($hMain, $hMain, $hMask, $RGN_DIFF)
  _WinAPI_DeleteObject($hMask)
  _WinAPI_SetWindowRgn($hWnd, $hMain)
EndFunc   ;==>Rect

 

Posted

Nine, formally, the problem is solved. In practice, this solution is useless.
The WinMove function is too slow and runs with artifacts. Perhaps (this is a hypothesis), it uses animation of window movement or predictions...
I added a bit of code to make the function work in any capture direction, not just down and right. If you hold down the left mouse button and move the cursor around the capture start point, you can clearly see WinMove artifacts.
But thanks anyway.
 

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Misc.au3>
#include <WinAPIGdi.au3>


_ScreenRegion_GetRect(0x78D7, 0x66CC, 1, 46)

Func _ScreenRegion_GetRect($iEdge = 0, $iBack = 0xFFFFFF, $iSize = 4, $iTransparency = 0) ;by Nine

  Local $hCursorGUI = GUICreate("Screen Capture", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
  WinSetTrans($hCursorGUI, "", 1)
  GUISetState()
  GUISetCursor($MCID_CROSS, $GUI_CURSOR_OVERRIDE, $hCursorGUI)

  Local $hRectGUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW + $WS_EX_TOPMOST)
  GUISetBkColor($iEdge)

  Local $hFillGUI = GUICreate("", 0, 0, 0, 0, $WS_POPUP, $WS_EX_TOOLWINDOW)
  GUISetBkColor($iBack)
  WinSetTrans($hFillGUI, "", $iTransparency)
  GUISetState()

  While Not _IsPressed("01") And Sleep(10)
  WEnd
  Local $iX1 = MouseGetPos(0), $iY1 = MouseGetPos(1), $iX2, $iY2, $iStartX, $iStartY

  While _IsPressed("01") And Sleep(10)
    $iX2 = MouseGetPos(0)
    $iY2 = MouseGetPos(1)

    If  $iX2 < $iX1 Then
        $iStartX = $iX2
        $iWidth = $iX1 - $iX2
    Else
        $iStartX = $iX1
        $iWidth = $iX2 - $iX1
    EndIf

    If $iY2 < $iY1 Then
        $iStartY = $iY2
        $iHeight = $iY1 - $iY2
    Else
        $iStartY = $iY1
        $iHeight =  $iY2 - $iY1
    EndIf
    Rect($hRectGUI, $iStartX, $iStartY, $iWidth, $iHeight, $iSize, $hFillGUI)
    If WinGetState($hRectGUI) < 15 Then GUISetState(@SW_SHOW, $hRectGUI)
  WEnd

  GUIDelete($hFillGUI)
  GUIDelete($hRectGUI)
  GUIDelete($hCursorGUI)
  Local $aReturn = [$iX1, $iY1, MouseGetPos(0), MouseGetPos(1)]
  Return $aReturn
EndFunc   ;==>_ScreenRegion_GetRect

Func Rect($hWnd, $iX, $iY, $iWidth, $iHeight, $iSize, $hFill) ;by Nine
  WinMove($hFill, "", $iX, $iY, $iWidth, $iHeight)
  Local $hMain = _WinAPI_CreateRectRgn($iX, $iY, $iX + $iWidth, $iY + $iHeight)
  Local $hMask = _WinAPI_CreateRectRgn($iX + $iSize, $iY + $iSize, $iX + $iWidth - $iSize, $iY + $iHeight - $iSize)
  _WinAPI_CombineRgn($hMain, $hMain, $hMask, $RGN_DIFF)
  _WinAPI_DeleteObject($hMask)
  _WinAPI_SetWindowRgn($hWnd, $hMain)
EndFunc   ;==>Rect

 

  • Solution
Posted (edited)
14 hours ago, nbb1967 said:

you can clearly see WinMove artifacts

Try this version :

#include <GDIPlus.au3>
#include <Misc.au3>
#include <WinAPISysWin.au3>
#include <GUIConstants.au3>

Local $aPos = _ScreenRegion_GetRect(0xFF0078D7, 0x460066CC, 2)
ConsoleWrite($aPos[0] & "/" & $aPos[1] & "/" & $aPos[2] & "/" & $aPos[3] & @CRLF)

Func _ScreenRegion_GetRect($nEdge = 0xFF000000, $nFill = 0, $iSize = 3)
  _GDIPlus_Startup()

  Local $hCursorGUI = GUICreate("Screen Capture", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_TOPMOST)
  WinSetTrans($hCursorGUI, "", 1)
  GUISetState()
  GUISetCursor($MCID_CROSS, $GUI_CURSOR_OVERRIDE, $hCursorGUI)

  Local $hCapture = GUICreate("", 0, 0, 0, 0, $WS_POPUPWINDOW, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST, $WS_EX_TOOLWINDOW), $hCursorGUI)
  GUISetState()

  While Not _IsPressed("01") And Sleep(10)
  WEnd

  Local $iX1 = MouseGetPos(0), $iY1 = MouseGetPos(1)

  While _IsPressed("01")
    Rect($hCapture, $iX1, $iY1, MouseGetPos(0) - $iX1, MouseGetPos(1) - $iY1, $nEdge, $nFill, $iSize)
  WEnd
  Local $aReturn = [$iX1, $iY1, MouseGetPos(0), MouseGetPos(1)]

  GUIDelete($hCursorGUI)
  GUIDelete($hCapture)
  _GDIPlus_Shutdown()

  Return $aReturn
EndFunc   ;==>_ScreenRegion_GetRect

Func Rect($hWnd, $iPosX, $iPosY, $iWidth, $iHeight, $nEdge, $nFill, $iSize)
  Local $hImage = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
  Local $hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage)

  Local $hPen = _GDIPlus_PenCreate($nEdge, $iSize)
  Local $hBrush = _GDIPlus_BrushCreateSolid($nFill)

  _GDIPlus_GraphicsFillRect($hGraphic, 0, 0, $iWidth, $iHeight, $hBrush)
  _GDIPlus_GraphicsDrawRect($hGraphic, $iSize, $iSize, $iWidth - ($iSize * 2), $iHeight - ($iSize * 2), $hPen)

  _GDIPlus_PenDispose($hPen)
  _GDIPlus_BrushDispose($hBrush)

  Local $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
  _GDIPlus_ImageDispose($hImage)
  _GDIPlus_GraphicsDispose($hGraphic)

  _WinAPI_SetWindowPos($hWnd, 0, $iPosX, $iPosY, $iWidth, $iHeight, $SWP_NOZORDER)
  _WinAPI_UpdateLayeredWindowEx($hWnd, -1, -1, $hBitmap, 255, True)
EndFunc   ;==>Rect

 

Edited by Nine
better code
Posted (edited)

Thank you very much! This GDIPlus script looks so simple, so beautiful, so logical, that it makes me sad...
But why does this script load one of the processor cores by 100%? Is GDIPlus itself so heavy?

I wrote my own version in GDI. It works, but I am not sure about the legality of my actions and approaches.
I will post it in the hope of criticism.

#Include <Misc.au3>
#Include <ScreenCapture.au3>
#include <WinAPISysWin.au3>
#include <WindowsConstants.au3>

Global $iX1, $iY1, $iX2, $iY2

Blue_Select()

Exit

Func Blue_Select()

    Local $aMouse_Pos, $hMask
    Local $UserDLL = DllOpen("user32.dll")

    ;Create transparent GUI with Cross cursor
    $hCross_GUI = GUICreate("Test", @DesktopWidth, @DesktopHeight - 20, 0, 0, $WS_POPUP, BitOR($WS_EX_TOOLWINDOW, $WS_EX_TOPMOST))
    WinSetTrans($hCross_GUI, "", 1)
    GUISetState(@SW_SHOW, $hCross_GUI)
    GUISetCursor(3, 1, $hCross_GUI)

    ;Creating an non-transparent GUI for initial Border forming
    Local $hBorder_GUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_LAYERED)

    ;Create transparament target layer for non-transparent Border
    Local $hTarget_GUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, $WS_EX_LAYERED)
    GUISetBkColor(0xff8080)
    _WinAPI_SetLayeredWindowAttributes($hTarget_GUI,0xff8080)
    GUISetState(@SW_SHOW, $hTarget_GUI)

    ;Create translucent GUI for Rectangle
    Local $hRectangle_GUI = GUICreate("", @DesktopWidth, @DesktopHeight, 0, 0, $WS_POPUP, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST))
    WinSetTrans($hRectangle_GUI, "", 70)
    GUISetBkColor(0x0066CC)

    Local $hDCDestTarget = _WinAPI_GetDC($hTarget_GUI)
    Local $hDCDestBorder = _WinAPI_GetDC($hBorder_GUI)
    Local $hDCSource = _WinAPI_CreateCompatibleDC($hDCDestBorder)
    Local $hHBitmap = _WinAPI_CreateSolidBitmap($hBorder_GUI, 0, @DesktopWidth, @DesktopHeight)
    Local $hBrush = _WinAPI_CreateSolidBrush(0x00d77800)
    Local $tRectLeft, $tRectTop, $tRectRight, $tRectBottom, $tRectCenter

    ;Wait until mouse button pressed
    While Not _IsPressed("01", $UserDLL)
        Sleep(10)
    WEnd

    ;Get first mouse position
    $aMouse_Pos = MouseGetPos()
    $iX1 = $aMouse_Pos[0]
    $iY1 = $aMouse_Pos[1]

    ;Draw a selection, wait until the mouse button is released
    While _IsPressed("01", $UserDLL)

        $aMouse_Pos = MouseGetPos()
        $iX2 = $aMouse_Pos[0]
        $iY2 = $aMouse_Pos[1]

        _WinAPI_InvalidateRect($hBorder_GUI)
        _WinAPI_InvalidateRect($hTarget_GUI)

        ;Create Border
        _WinAPI_SelectObject($hDCSource, $hHBitmap)
        $tRectTop = _WinAPI_CreateRect($iX1, $iY1, $iX2 + 1, $iY1 + 1)
        $tRectLeft = _WinAPI_CreateRect($iX1, $iY1, $iX1 + 1, $iY2 + 1)
        $tRectRight = _WinAPI_CreateRect($iX2, $iY1, $iX2 + 1, $iY2 + 1)
        $tRectBottom = _WinAPI_CreateRect($iX1, $iY2, $iX2 + 1, $iY2 + 1)

        _WinAPI_FillRect($hDCSource, $tRectTop, $hBrush)
        _WinAPI_FillRect($hDCSource, $tRectLeft, $hBrush)
        _WinAPI_FillRect($hDCSource, $tRectRight, $hBrush)
        _WinAPI_FillRect($hDCSource, $tRectBottom, $hBrush)

        ;Create Rectangle
        $hMask = _WinAPI_CreateRectRgn($iX1 + 1, $iY1 + 1, $iX2, $iY2)
        _WinAPI_SetWindowRgn($hRectangle_GUI, $hMask, 1)
        If WinGetState($hRectangle_GUI) < 15 Then GUISetState(@SW_SHOW, $hRectangle_GUI)

        ;Transferring a border to a transparent layer
        _WinAPI_BitBlt($hDCDestTarget, $iX1, $iY1, ($iX2 + 1) - $iX1, ($iY1 + 1) - $iY1, $hDCSource, $iX1, $iY1, $SRCCOPY)
        _WinAPI_BitBlt($hDCDestTarget, $iX1, $iY1, ($iX1 + 1) - $iX1, ($iY2 + 1) - $iY1, $hDCSource, $iX1, $iY1, $SRCCOPY)
        _WinAPI_BitBlt($hDCDestTarget, $iX2, $iY1, ($iX2 + 1) - $iX2, ($iY2 + 1) - $iY1, $hDCSource, $iX2, $iY1, $SRCCOPY)
        _WinAPI_BitBlt($hDCDestTarget, $iX1, $iY2, ($iX2 + 1) - $iX1, ($iY2 + 1) - $iY2, $hDCSource, $iX1, $iY2, $SRCCOPY)

        Sleep(20);less than 20: flickers

    WEnd

    ;Cleaning
    _WinAPI_ReleaseDC($hTarget_GUI, $hDCDestTarget)
    _WinAPI_ReleaseDC($hBorder_GUI, $hDCDestBorder)
    _WinAPI_DeleteDC($hDCSource)
    _WinAPI_DeleteObject($hHBitmap)
    _WinAPI_DeleteObject($hBrush)
    _WinAPI_DeleteObject($hMask)

    GUIDelete($hTarget_GUI)
    GUIDelete($hRectangle_GUI)
    GUIDelete($hBorder_GUI)
    GUIDelete($hCross_GUI)

    DllClose($UserDLL)
EndFunc  ;==>Blue_Select

 

Edited by nbb1967
Posted (edited)
46 minutes ago, nbb1967 said:

But why does this script load one of the processor cores by 100%?

Forgot to put some sleep in...But who cares if one CPU is at 100% when you have 16 available. ;)

ps. not bad script of yours, however like you said before there are some artifacts.  It is not as smooth as it can be...

Edited by Nine
Posted

I turned on the 8x magnifying glass and yes, I see small artifacts in my script: sometimes the border breaks away from the light rectangle. Strange... Unfortunately, my script also flickers at low Sleep values in the loop. I'm using your script, Nine. Thanks!!!

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