Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

LetUserSelectRect - select a portion of the screen


  • Please log in to reply
7 replies to this topic
Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
LetUserSelectRect(ByRef aX1, ByRef aY1, ByRef aX2, ByRef aY2)

Allows the user to select a rectangular region of the screen by clicking and dragging the mouse. The selected region is indicated by a red outline in real-time. Outputs the top-left (aX1, aY1) and bottom-right (aX2, aY2) co-ordinates of the rectangle.

It is based on an older script; functionized at vik.vega's request.

#NoEnv
CoordMode, Mouse ; Required: change coord mode to screen vs relative.
 
LetUserSelectRect(x1, y1, x2, y2)
MsgBox %x1%,%y1%  %x2%,%y2%

ExitApp
 
LetUserSelectRect(ByRef X1, ByRef Y1, ByRef X2, ByRef Y2)
{
    static r := 3
    ; Create the "selection rectangle" GUIs (one for each edge).
    Loop 4 {
        Gui, %A_Index%: -Caption +ToolWindow +AlwaysOnTop
        Gui, %A_Index%: Color, Red
    }
    ; Disable LButton.
    Hotkey, *LButton, lusr_return, On
    ; Wait for user to press LButton.
    KeyWait, LButton, D
    ; Get initial coordinates.
    MouseGetPos, xorigin, yorigin
    ; Set timer for updating the selection rectangle.
    SetTimer, lusr_update, 10
    ; Wait for user to release LButton.
    KeyWait, LButton
    ; Re-enable LButton.
    Hotkey, *LButton, Off
    ; Disable timer.
    SetTimer, lusr_update, Off
    ; Destroy "selection rectangle" GUIs.
    Loop 4
        Gui, %A_Index%: Destroy
    return
 
    lusr_update:
        MouseGetPos, x, y
        if (x = xlast && y = ylast)
            ; Mouse hasn't moved so there's nothing to do.
            return
        if (x < xorigin)
             x1 := x, x2 := xorigin
        else x2 := x, x1 := xorigin
        if (y < yorigin)
             y1 := y, y2 := yorigin
        else y2 := y, y1 := yorigin
        ; Update the "selection rectangle".
        Gui, 1:Show, % "NA X" x1 " Y" y1 " W" x2-x1 " H" r
        Gui, 2:Show, % "NA X" x1 " Y" y2-r " W" x2-x1 " H" r
        Gui, 3:Show, % "NA X" x1 " Y" y1 " W" r " H" y2-y1
        Gui, 4:Show, % "NA X" x2-r " Y" y1 " W" r " H" y2-y1
    lusr_return:
    return
}
Obsolete version:
#NoEnv
CoordMode, Mouse ; Required: change coord mode to screen vs relative.

LetUserSelectRect(x1, y1, x2, y2)
MsgBox %x1%,%y1%  %x2%,%y2%

LetUserSelectRect(ByRef aX1, ByRef aY1, ByRef aX2, ByRef aY2)
{
    ; Create red pen.
    redPen := DllCall("CreatePen", "int", 0, "int", 5, "uint", 0xff)
    ; Retrieve stock brush.
    blackBrush := DllCall("GetStockObject", "int", BLACK_BRUSH:=0x4)
    ; Create the "selection rectangle" GUI.
    Gui, -Caption +ToolWindow
    Gui, +LastFound
    WinSet, TransColor, Black
    ; Disable LButton.
    Hotkey, *LButton, lusr_return, On
    ; Wait for user to press LButton.
    KeyWait, LButton, D
    ; Get initial coordinates.
    MouseGetPos, xorigin, yorigin
    ; Set timer for updating the selection rectangle.
    SetTimer, lusr_update, 10
    ; Wait for user to release LButton.
    KeyWait, LButton
    ; Re-enable LButton.
    Hotkey, *LButton, Off
    ; Disable timer.
    SetTimer, lusr_update, Off
    ; Delete red pen.
    DllCall("DeleteObject", "uint", redPen)
    ; Destroy "selection rectangle" GUI.
    Gui, Destroy
    ; Set output parameters.
    if (x2 < xorigin)
         aX1 := x2, aX2 := xorigin
    else aX2 := x2, aX1 := xorigin
    if (y2 < yorigin)
         aY1 := y2, aY2 := yorigin
    else aY2 := y2, aY1 := yorigin
    return
    
    lusr_update:
        MouseGetPos, x2, y2
        if (x1 = x2 && y1 = y2)
            ; Mouse hasn't moved so there's nothing to do.
            return
        x1 := x2, y1 := y2
        ; Update the "selection rectangle" GUI.
        Gui, Show, % "NA X" . (x2<xorigin ? x2 : xorigin) . " Y" . (y2<yorigin ? y2 : yorigin)
                    . " W" . Abs(x2-xorigin) . " H" . Abs(y2-yorigin)
        Gui, +LastFound
        ; Get GDI device context for drawing.
        hdc := DllCall("GetDC", "uint", WinExist())
        ; Select pen and brush.
        oldPen := DllCall("SelectObject", "uint", hdc, "uint", redPen)
        oldBrush := DllCall("SelectObject", "uint", hdc, "uint", blackBrush)
        ; Draw rectangle.
        DllCall("Rectangle", "uint", hdc, "int", 0, "int", 0, "int", Abs(x2-xorigin), "int", Abs(y2-yorigin))
        ; Reselect original pen and brush (required for proper cleanup).
        DllCall("SelectObject", "uint", hdc, "uint", oldPen)
        DllCall("SelectObject", "uint", hdc, "uint", oldBrush)
        ; Clean up.
        DllCall("ReleaseDC", "uint", WinExist(), "uint", hdc)
    lusr_return:
    return
}


n-l-i-d
  • Guests
  • Last active:
  • Joined: --
Nice! It flickers like crazy though while dragging on XPSP3 and only works on the desktop :?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
I've added an improved version using a simpler method (and added +AlwaysOnTop). See how that goes. :)

n-l-i-d
  • Guests
  • Last active:
  • Joined: --
Much better! No flickering, and still low cpu usage. I do see artifacts from redrawing (lines stick out of the rectangle) along the corners of the rectangle while resizing.

HTH

n-l-i-d
  • Guests
  • Last active:
  • Joined: --
Oh sorry, yes, and it does draw on top of all windows now. :)

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I do see artifacts from redrawing

That's typical for Windows before desktop composition (Aero) was introduced. Actually, making the GUIs partially transparent might help (it'd have a similar effect), but would probably slow it down a bit.

it does draw

Well, not really. It creates four windows, AutoHotkey paints them red and Windows is responsible for (in)correctly redrawing other windows as the four move around. (You could say it spills the red paint...)

n-l-i-d
  • Guests
  • Last active:
  • Joined: --
Using SetBatchLines 0 and SetWinDelay 0 helps. I think it could be "solved" if the order of moving/resizing of the guis depended on the directions of the drag. If the most-outer side/gui moves last if contracting and first if expanding (before/after the respective sides), the effect is hardly visible anymore.

HTH

Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
You pwned my version of it (Which I'm sure you saw on the other thread in 'Ask For Help'). Every time I write one, you guys out do me. Well, not for long. Muahahahahaha. ;).

Another very nicely written script! Two thumbs up.