SelectArea() improved

Post your working scripts, libraries and tools for AHK v1.1 and older
william_ahk
Posts: 499
Joined: 03 Dec 2018, 20:02

SelectArea() improved

21 Apr 2024, 23:21

Modified the return value type to associative array, added built-in mouse drag support and cross cursor style. Feel free to improve the structure and report any bugs.

Function:

Code: Select all

SelectArea(Options:="") { ; original by Learning One https://www.autohotkey.com/board/topic/57646-function-selectarea/
	/*
	Returns selected area. Example: {X: 22, Y: 13, W: 243, H: 543}
	Options: (space separated)
	- c	Color		Default: Blue
	- o	Opacity		Default: 50
	- m	CoordMode	Default: Screen (s = Screen, w = Window, c = Client)
	*/
	Local c, o, m, mX, mY, mXend, mYend, smX, smY, smXend, smYend
	,     AsyncDone	:= false
	,     DragKey	:= "LButton"
	,     _CoordModeMouse := A_CoordModeMouse
	Loop, parse, Options, %A_Space%
	{
		Field := A_LoopField
		FirstChar := SubStr(Field, 1, 1)
		if FirstChar in c,o,m
			%FirstChar% := SubStr(Field, 2)
	}
	c := (c == "") ? "Blue" : c,
	o := (o == "") ? "128" : o / 100 * 256,
	m := (m == "") ? "Screen" : (m="s"?"Screen":(m="w"?"Window":(m="c"?"Client":"Screen")))
	Hotkey, % DragKey, SelectArea_DragStart, On
	Hotkey, % DragKey " up", SelectArea_Done, On
	Hotkey, % "~Esc", SelectArea_Done, On
	ReplaceSystemCursors("IDC_CROSS")
	
	Loop
		Sleep 10
	Until AsyncDone
	
	ReplaceSystemCursors()
	CoordMode, Mouse, % m
	MouseGetPos, mXend, mYend
	CoordMode, Mouse, % _CoordModeMouse
	if (mX != "") {
		if (mX > mXend)
			temp := mX, mX := mXend, mXend := temp
		if (mY > mYend)
			temp := mY, mY := mYend, mYend := temp
		return {X: mX, Y: mY, W: mXend, H: mYend}
	}
	return false

	SelectArea_DragStart:
	CoordMode, Mouse, % m
	MouseGetPos, mX, mY
	CoordMode, Mouse, Screen
	MouseGetPos, smX, smY
	Gui SelectArea:New, +AlwaysOnTop -Caption -Border +ToolWindow +LastFound
	WinSet, Transparent, % o
	Gui Color, % c
	SetTimer, SelectArea_Dragging, 1
	Return
	
	SelectArea_Dragging:
	CoordMode, Mouse, Screen
	MouseGetPos, smXend, smYend
	W := Abs(smX - smXend), H := Abs(smY - smYend)
	X := (smX < smXend) ? smX : smXend
	Y := (smY < smYend) ? smY : smYend
	Gui SelectArea:Show, x%X% y%Y% w%W% h%H% NA
	Return

	SelectArea_Done:
	SetTimer, SelectArea_Dragging, Off
	Hotkey, % DragKey " up", SelectArea_Done, Off
	Hotkey, % DragKey, SelectArea_DragStart, Off
	Hotkey, % "~Esc", SelectArea_Done, Off
	Gui SelectArea:Destroy
	ReplaceSystemCursors()
	AsyncDone := true
	Return
}

ReplaceSystemCursors(IDC = "") {
   static IMAGE_CURSOR := 2, SPI_SETCURSORS := 0x57
        , exitFunc := Func("ReplaceSystemCursors").Bind("")
        , SysCursors := { IDC_APPSTARTING: 32650
                        , IDC_ARROW      : 32512
                        , IDC_CROSS      : 32515
                        , IDC_HAND       : 32649
                        , IDC_HELP       : 32651
                        , IDC_IBEAM      : 32513
                        , IDC_NO         : 32648
                        , IDC_SIZEALL    : 32646
                        , IDC_SIZENESW   : 32643
                        , IDC_SIZENWSE   : 32642
                        , IDC_SIZEWE     : 32644
                        , IDC_SIZENS     : 32645 
                        , IDC_UPARROW    : 32516
                        , IDC_WAIT       : 32514 }
   if !IDC {
      DllCall("SystemParametersInfo", UInt, SPI_SETCURSORS, UInt, 0, UInt, 0, UInt, 0)
      OnExit(exitFunc, 0)
   }
   else  {
      hCursor := DllCall("LoadCursor", Ptr, 0, UInt, SysCursors[IDC], Ptr)
      for k, v in SysCursors  {
         hCopy := DllCall("CopyImage", Ptr, hCursor, UInt, IMAGE_CURSOR, Int, 0, Int, 0, UInt, 0, Ptr)
         DllCall("SetSystemCursor", Ptr, hCopy, UInt, v)
      }
      OnExit(exitFunc)
   }
}

Simple usage:

Code: Select all

If (Area := SelectArea())
	Msgbox, % "X: " Area.X ", Y: " Area.Y ", W: " Area.W ", H: " Area.H
Else
	Msgbox, No area selected.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 53 guests