Edit Control: caret position before of after selection?

Get help with using AutoHotkey and its commands and hotkeys
autocart
Posts: 106
Joined: 12 May 2014, 07:42

Edit Control: caret position before of after selection?

09 Oct 2014, 02:44

Hi all,
I can get the current caret position with "ControlGet, outputVar, CurrentCol, ...". However if text is selected then it will always return the position of where the selection starts.

Now, in real life, however, the caret could be at the start or at the end of the selection. The difference in behaviour becomes clear if I continue to select more text on top of what is already selected. In this case my current selection could get (partly) deselected or not, depending if the caret was at the start or end of the current selection.

I want to code this behaviour it on my own and I found some Edit Control libraries in the forums, but when I select text with "SendMessage, 0xB1, start, end, %Control%, %WinTitle% ; EM_SETSEL" then any current selection is completely replaced instead of taken into account.

So, is there a way to find out if the caret is positioned at the start or end of a current selection?
Thx to everybody helping.

EDIT:
Found a solution: http://arstechnica.com/civis/viewtopic. ... 6#p3347986
I quote the author, "ToLazyToThink": "Calling EM_SETSEL with a -1 for the start position should undo the selection, leaving the caret where it was.

If you want a non-destructive method, I don't know of one. When I needed one I used the trick above and then used a bunch of hackery to restore the previous selection."
just me
Posts: 5640
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Edit Control: caret position before of after selection?

09 Oct 2014, 04:12

Code: Select all

#NoEnv
Lorem := "
(
Lorem ipsum dolor sit amet
Consectetuer ligula Aliquam Curabitur Nullam
Rutrum eu est congue dui
Interdum Phasellus sed Quisque Donec
Et semper adipiscing id Sed
Non ut Quisque Pellentesque lorem
Est at urna justo sem
Proin consequat gravida nibh adipiscing
)"

Gui, Add, Edit, w400 r10 hwndHEDIT, %Lorem%
Gui, Add, Button, gSelection, Show selection!
Gui, Show, , Get the caret!
Return

GuiClose:
ExitApp

Selection:
VarSetCapacity(POINT, 8, 0)
DllCall("User32.dll\GetCaretPos", "Ptr", &POINT)
X := NumGet(POINT, 0, "Int")
Y := NumGet(POINT, 4, "Int")
EM_CHARFROMPOS(HEDIT, X, Y, CharPos, Line)
EM_GETSEL(HEDIT, Start, End)
MsgBox, 0, Selection, Start: %Start%`nEnd: %End%`nCaret: %CharPos%
Return

; ======================================================================================================================
; Gets information about the character closest to a specified point in the client area of an edit control.
; X, Y            -  the X- and Y-positions of the point.
; CharPos, Line   -  receive the character position and the line number.
; ======================================================================================================================
EM_CHARFROMPOS(HWND, X, Y, ByRef CharPos, ByRef Line) {
   ; EM_CHARFROMPOS = 0x00D7 -> msdn.microsoft.com/en-us/library/bb761566(v=vs.85).aspx
   CharPos := Line := 0
   CharLine := DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00D7, "Ptr", 0, "UInt", (Y << 16) | X, "Ptr")
   CharPos := (CharLine & 0xFFFF) + 1
   Line := (CharLine >> 16) + 1
   Return True
}

; ======================================================================================================================
; Gets the starting and ending character positions of the current selection in an edit control.
; Start  -  receives the start of the current selection
; End    -  receives the end of the current selection
; ======================================================================================================================
EM_GETSEL(HWND, ByRef Start, ByRef End) {
   ; EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
   Start := End := 0
   DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")
   Start++, End++
   Return True
}
?
autocart
Posts: 106
Joined: 12 May 2014, 07:42

Re: Edit Control: caret position before of after selection?

09 Oct 2014, 11:32

awesome, "just me", thx a lot!!

EDIT:
Well, I was happy too early. It works well in the example given, but in the 3rd party app where I am intending to use it
VarSetCapacity(POINT, 8, 0)
DllCall("User32.dll\GetCaretPos", "Ptr", &POINT)
X := NumGet(POINT, 0, "Int")
Y := NumGet(POINT, 4, "Int")
always returns 0 (zero) for X and Y, regardless of where I put the caret.
I think I have read somewhere (cant remember where) that GetCaretPos does not work with alllllll windows. Is it true?
User avatar
RobertL
Posts: 540
Joined: 18 Jan 2014, 01:14
Location: China

Re: autocart. MouseGetPos & edit controls

10 Oct 2014, 03:44

Could use MouseGetPos (consider CoordMode)
And see msdn in code, only works on MS (rich) edit controls.
Last edited by RobertL on 10 Oct 2014, 04:29, edited 1 time in total.
我为人人,人人为己?
autocart
Posts: 106
Joined: 12 May 2014, 07:42

Re: Edit Control: caret position before of after selection?

10 Oct 2014, 03:59

thx, RobertL, I think, though, that you are confusing caret-position with cursor-position?
User avatar
RobertL
Posts: 540
Joined: 18 Jan 2014, 01:14
Location: China

Re: autocart A_CaretX|Y

10 Oct 2014, 04:26

autocart wrote:that you are confusing caret-position with cursor-position?
Sorry, could try A_CaretX and A_CaretY, see Variables and Expressions \ Built-in Variables(index built-in variables).
我为人人,人人为己?
autocart
Posts: 106
Joined: 12 May 2014, 07:42

Re: autocart A_CaretX|Y

11 Oct 2014, 04:27

just me wrote:Again, sorry!
viewtopic.php?f=5&t=4840&p=27979#p27979
No problem, I felt helped anyway, thx.
RobertL wrote:
autocart wrote:that you are confusing caret-position with cursor-position?
Sorry, could try A_CaretX and A_CaretY, see Variables and Expressions \ Built-in Variables(index built-in variables).
No problem, and thx for the hint regarding A_CaretX and A_CaretY. I was not aware of them but now used them in my currently working work-around that I came up with:
http://ahkscript.org/boards/viewtopic.p ... 056#p28056
The relevant code of my work-around for the topic of this thread is this:

Code: Select all

; Gets the current caret position (zero-based) of an edit control having input focus
; (at least for XYplorer inline-edit-controls).
; This function is IMHO preferable over ControlGet, outVar, CurrentCol, ... because
; the build in function is not reliable with the caret position around selections.
;
_Edit_CaretGetPos(editNNHavingFocus, wintitle)
{
    ControlGetFocus, focusedControl, %wintitle%
    if (focusedControl = editNNHavingFocus)
    {
        ControlGet, hEdit, hwnd, , %editNNHavingFocus%, %wintitle%
        ControlGetPos, editX, editY, editW, editH, %editNNHavingFocus%, %wintitle%
        CoordMode, Caret, Window
        _EM_CHARFROMPOS(hEdit, A_CaretX - editX, A_CaretY - editY, charPos, line)
    }
    else
        charPos := ""
    return charPos
}

;***** the following function from http://ahkscript.org/boards/viewtopic.php?f=5&t=4826&p=27883#p27857 by user "just me"
;***** alteration: made the returned index number zero-based
; ======================================================================================================================
; Gets information about the character closest to a specified point in the client area of an edit control.
; X, Y            -  the X- and Y-positions of the point.
; CharPos, Line   -  receive the character position and the line number.
; ======================================================================================================================
_EM_CHARFROMPOS(HWND, X, Y, ByRef CharPos, ByRef Line) {
   ; _EM_CHARFROMPOS = 0x00D7 -> msdn.microsoft.com/en-us/library/bb761566(v=vs.85).aspx
   CharPos := Line := 0
   CharLine := DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00D7, "Ptr", 0, "UInt", (Y << 16) | X, "Ptr")
   CharPos := (CharLine & 0xFFFF)
   Line := (CharLine >> 16)
   Return True
}
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: Edit Control: caret position before of after selection?

26 Oct 2017, 21:58

The function only returns the correct "Caret" string position from edit controls created by the script itself!

It returns incorrect caret string position from edit controls created by another AutoHotKey scripts or external process such as notepad.exe, etc

Notepad test bug
get Caret string position (just me - Bug).gif
get Caret string position (just me - Bug).gif (614.22 KiB) Viewed 1440 times

Code: Select all

	;https://autohotkey.com/boards/viewtopic.php?p=27857#p27857
	;The function only returns the correct "Caret" String Pos from edit controls created by the script itself
	;Bug: The function returns incorrect "Caret" string pos from edit controls created by another Autohotkey scripts
	;Bug: The function returns incorrect "Caret" string pos from external applications, such as notepad.exe, etc

#NoEnv
Lorem := "
(
Lorem ipsum dolor sit amet
Consectetuer ligula Aliquam Curabitur Nullam
Rutrum eu est congue dui
Interdum Phasellus sed Quisque Donec
Et semper adipiscing id Sed
Non ut Quisque Pellentesque lorem
Est at urna justo sem
Proin consequat gravida nibh adipiscing
)"

Gui, Add, Edit, w400 r10, %Lorem%
Gui, Show, , Get the caret!
Return

GuiClose:
ExitApp

~LButton Up::	;"~" keeps the button original function

MouseGetPos, , , WinId, ControlId, 2	;"2" Stores the control's HWND in "ControlId" variable rather than the control's ClassNN.

VarSetCapacity(POINT, 8, 0)
DllCall("User32.dll\GetCaretPos", "Ptr", &POINT)
X := NumGet(POINT, 0, "Int")
Y := NumGet(POINT, 4, "Int")
EM_CHARFROMPOS(ControlId, X, Y, CharPos, Line)
EM_GETSEL(ControlId, Start, End)

tooltip, % "WinId: " WinId " \ ControlId: " ControlId "`nStart: " Start " \ End: " End "`nCaret Pos: " CharPos
Return


; ======================================================================================================================
; Gets information about the character closest to a specified point in the client area of an edit control.
; X, Y            -  the X- and Y-positions of the point.
; CharPos, Line   -  receive the character position and the line number.
; ======================================================================================================================
EM_CHARFROMPOS(HWND, X, Y, ByRef CharPos, ByRef Line) {
   ; EM_CHARFROMPOS = 0x00D7 -> msdn.microsoft.com/en-us/library/bb761566(v=vs.85).aspx
   CharPos := Line := 0
   CharLine := DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00D7, "Ptr", 0, "UInt", (Y << 16) | X, "Ptr")
   CharPos := (CharLine & 0xFFFF) + 1
   Line := (CharLine >> 16) + 1
   Return True
}

; ======================================================================================================================
; Gets the starting and ending character positions of the current selection in an edit control.
; Start  -  receives the start of the current selection
; End    -  receives the end of the current selection
; ======================================================================================================================
EM_GETSEL(HWND, ByRef Start, ByRef End) {
   ; EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
   Start := End := 0
   DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")
   Start++, End++
   Return True
}
User avatar
jeeswg
Posts: 5411
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Edit Control: caret position before of after selection?

26 Oct 2017, 23:20

I have a script that seems to be working correctly on Notepad's Edit control. Btw I'm finding that the Winapi function GetCaretPos is returning '0 0' always.

Code: Select all

q:: ;GetCaretPos returns 0 0
VarSetCapacity(POINT, 8, 0)
DllCall("user32\GetCaretPos", Ptr,&POINT)
vPosX := NumGet(&POINT, 0, "Int")
vPosY := NumGet(&POINT, 4, "Int")
MsgBox, % vPosX " " vPosY
return

;based on:
;convert coordinates between Client/Screen/Window modes - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=38472

w:: ;caret position get char
;note: this is of limited use for big files,
;because the return values are reset to 0 every 0xFFFF lines/chars
WinGet, hWnd, ID, A
VarSetCapacity(GUITHREADINFO, A_PtrSize=8?72:48, 0)
NumPut(A_PtrSize=8?72:48, &GUITHREADINFO, 0, "UInt") ;cbSize
vTID := DllCall("user32\GetWindowThreadProcessId", Ptr,hWnd, UIntP,0, UInt)
DllCall("user32\GetGUIThreadInfo", UInt,vTID, Ptr,&GUITHREADINFO)
vPosX := NumGet(&GUITHREADINFO, A_PtrSize=8?56:32, "Int") ;rcCaret ;x
vPosY := NumGet(&GUITHREADINFO, A_PtrSize=8?60:36, "Int") ;rcCaret ;y

SendMessage, 0xD7,, % (vPosX&0xFFFF)|(vPosY<<16), Edit1, % "ahk_id " hWnd ;EM_CHARFROMPOS := 0xD7
vPos := ErrorLevel & 0xFFFF
vLine := (ErrorLevel >> 16) & 0xFFFF
MsgBox, % vPos " " vLine
return
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: Edit Control: caret position before of after selection?

27 Oct 2017, 00:48

autocart wrote:.
jeeswg wrote:.
@autocart @jeeswg

I just wrote right now CaretPos(Function) that returns the exact Caret string position!

if you are interested to test it, feel free to do it and in case you find any bug, please report here:

https://autohotkey.com/boards/viewtopic ... 15#p178615
User avatar
jeeswg
Posts: 5411
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Edit Control: caret position before of after selection?

27 Oct 2017, 01:31

I have one or two functions here re. Edit control selection:
GUI COMMANDS: COMPLETE RETHINK - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 92#p138292

The key things to be aware of are left/right v. anchor/active selection points. And that sometimes if you select from right to left, go to a different window, and return, the Edit control now thinks you selected from left to right. Where the caret is located is the active point in a text selection, the other point is the anchor point, when no text is selected, both active and anchor points are the same.

Although I think you know this, I think I'll mention it anyway, there are 2 quite different things: the X/Y coordinates of where the caret is, and the character index of where the caret/selection is. I'm generally never interested in the X/Y coordinates. Note: AutoHotkey has built-in variables A_CaretX and A_CaretY which give the X/Y coordinates of the caret, I wrote a function available at the link below, that tries to retrieve the same values as those variables.

convert coordinates between Client/Screen/Window modes - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=38472
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: Edit Control: caret position before of after selection?

27 Oct 2017, 20:07

jeeswg wrote:.
Hi @jeeswg,

Can you please tell me how is it supposed to use your "JEE_EditGetRangeAnchorActive()" function ?

with my function, "ToolTip, % CaretPos(ControlId)" automatically returns the correct Caret string pos!

with your function, I tried:

ToolTip, % JEE_EditGetRangeAnchorActive(ControlId, "", "") . " - " . vPos1 . "\" . vPos2

but the function returns nothing and vPos1 and vPos2 are always blank!

Code: Select all

loop, 10
text.= "AAAAAAAAAA`n"

gui, add, edit, w300 h200, % text


gui, show
return

~Lbutton up::	;"~" keeps the button original function

MouseGetPos, , , WinId, ControlId, 2	;"2" Stores the control's HWND in "ControlId" variable rather than the control's ClassNN.

ToolTip, % ""
. "My Function : " . CaretPos(ControlId) . "`n"
. "jeeswg Function: " . JEE_EditGetRangeAnchorActive(ControlId, "", "") . " - " . vPos1 . "\" . vPos2 . "`n"

	;msgbox, % vPos1 . "\" . vPos2

return

guiclose:	;____________ gui close ____________
exitapp


JEE_EditGetRangeAnchorActive(hCtl, ByRef vPos1, ByRef vPos2)
{
	;get selection
	VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
	SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
	vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
	if (vPos1 = vPos2)
		return
	vPos1X := vPos1, vPos2X := vPos2

	;set selection to 0 characters and get active position
	SendMessage, 0xB1, -1, 0,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1
	VarSetCapacity(vPos2, 4)
	SendMessage, 0xB0, % &vPos2, 0,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
	vPos2 := NumGet(&vPos2, 0, "UInt")

	;restore selection
	vPos1 := (vPos2 = vPos2X) ? vPos1X : vPos2X
	SendMessage, 0xB1, % vPos1, % vPos2,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1 ;(anchor, active)

;msgbox, % vPos1 . "\" . vPos2
}


CaretPos(ControlId) ;___________ CaretPos v1.0 (Function) ______________
{
;Get start and End Pos of the selected string - Get Caret pos if no string is selected
;https://autohotkey.com/boards/viewtopic.php?p=27979#p27979
;EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
DllCall("User32.dll\SendMessage", "Ptr", ControlId, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")

;"0xB1", EM_SETSEL
;Remove any string selection and keep the "caret" position unchanged!
SendMessage, 0xB1, -1, 0, , % "ahk_id" ControlId

;Get "Caret" pos because no string is selected!
DllCall("User32.dll\SendMessage", "Ptr", ControlId, "UInt", 0x00B0, "UIntP", CaretPos, "UIntP", CaretPos, "Ptr")


if (CaretPos = End)
SendMessage, 0xB1, % Start, % End, , % "ahk_id" ControlId	;select from left to righ ("caret" at the End of the selection)
else
SendMessage, 0xB1, % End, % Start, , % "ahk_id" ControlId	;select from right to left ("caret" at the Start of the selection)
;"Start" is always smaller or equal to "End"

CaretPos++	;force "1" instead "0" to be recognised as the beginning of the string!

return, CaretPos
}
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: Edit Control: caret position before of after selection?

27 Oct 2017, 23:09

jeeswg wrote:.
Sorry @jeeswg, I feel so pathetic from my previous post!

I thought "ByRef" is the same as "Global" variables, that's why I wasn't understanding how to use your function!

the ByRef info from this link made me even more confused (a lot blah blah blah and no practical examples):
https://autohotkey.com/docs/Functions.htm#ByRef

and then I found a practical ByRef example (code below)

Code: Select all

Test(A, B, C)
Zate(D, E, F)
Xaxa(G, H, I)

;after the function calls, A,B,C,D,E,F,H values will be the same as their correspondent functions ByRef Parameters values!
;after the function calls, G,I variables values will still blank because their correspondent function parameters do not use ByRef option!

msgbox, % ""
. A " - " B " - " C "`n"
. D " - " E " - " F "`n"
. G " - " H " - " I "`n"


Test(ByRef X, ByRef Y, ByRef Z)
{
X := 111
Y := 222
Z := 333
}

Zate(ByRef X, ByRef Y, ByRef Z)
{
X := 444
Y := 555
Z := 666
}

Xaxa(X, ByRef Y, Z)
{
X := 777
Y := 888
Z := 999
}
I don't really know if the example is accurate, but it made me understand ByRef just a little bit!

Saying that, now I can handle your function! (I like your function, but I prefer mine because mine returns a value and it does not need to store the returned value into a variable! - That's why I think I don't really like the "ByRef" approach!)

Here is your function in action:

Code: Select all

loop, 10
text.= "AAAAAAAAAA`n"

gui, add, edit, w300 h200, % text


gui, show
return

~Lbutton up::	;"~" keeps the button original function

MouseGetPos, , , WinId, ControlId, 2	;"2" Stores the control's HWND in "ControlId" variable rather than the control's ClassNN.

ToolTip, % ""
. "My Function : " . CaretPos(ControlId) . "`n"
. JEE_EditGetRangeAnchorActive(ControlId, Anchor, CaretPos) . "jeeswg Function: " . CaretPos . "\ Anchor: " . Anchor . "`n"

return

guiclose:	;____________ gui close ____________
exitapp


JEE_EditGetRangeAnchorActive(hCtl, ByRef vPos1, ByRef vPos2)
{
	;get selection
	VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
	SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
	vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
	if (vPos1 = vPos2)
		return
	vPos1X := vPos1, vPos2X := vPos2

	;set selection to 0 characters and get active position
	SendMessage, 0xB1, -1, 0,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1
	VarSetCapacity(vPos2, 4)
	SendMessage, 0xB0, % &vPos2, 0,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
	vPos2 := NumGet(&vPos2, 0, "UInt")

	;restore selection
	vPos1 := (vPos2 = vPos2X) ? vPos1X : vPos2X
	SendMessage, 0xB1, % vPos1, % vPos2,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1 ;(anchor, active)
}


CaretPos(ControlId) ;___________ CaretPos v1.0 (Function) ______________
{
;Get start and End Pos of the selected string - Get Caret pos if no string is selected
;https://autohotkey.com/boards/viewtopic.php?p=27979#p27979
;EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
DllCall("User32.dll\SendMessage", "Ptr", ControlId, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")

;"0xB1", EM_SETSEL
;Remove any string selection and keep the "caret" position unchanged!
SendMessage, 0xB1, -1, 0, , % "ahk_id" ControlId

;Get "Caret" pos because no string is selected!
DllCall("User32.dll\SendMessage", "Ptr", ControlId, "UInt", 0x00B0, "UIntP", CaretPos, "UIntP", CaretPos, "Ptr")


if (CaretPos = End)
SendMessage, 0xB1, % Start, % End, , % "ahk_id" ControlId	;select from left to righ ("caret" at the End of the selection)
else
SendMessage, 0xB1, % End, % Start, , % "ahk_id" ControlId	;select from right to left ("caret" at the Start of the selection)
;"Start" is always smaller or equal to "End"

CaretPos++	;force "1" instead "0" to be recognised as the beginning of the string!

return, CaretPos
}
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: autocart A_CaretX|Y

28 Oct 2017, 14:37

autocart wrote:.
Hi @autocart,

I used your "A_CaretX - editX, A_CaretY - editY" approach to fix "just me" function! Now the function can be used with edit controls from notepad, from external apps or from another autohotkey scripts!

Now it's really easy to use the function, you just have to use one line like "EM_CHARFROMPOS(ControlId, CaretPos, CaretLine)" and the Caret string pos is automatically stored in "CaretPos" variable and the caret current line is automatically stored in "CaretLine" variable!

The Edit control border is what cause the issues mentioned below! By using "-E0x200" to remove border, the issues are fixed!
- but I noticed that, your approach is not always accurate, for example, the function returns 10 as Caret string pos when selected string Start\End is 9\9!
- another thing I noticed is that by using your approach, the "Caretxy" pos are always 2+ higher than "Caretxy" pos from "just me" approach! (for example, if I click the first string pos, "just me" approach returns 1\1 and yours 3\3! I don't know each one is more accurate!)

Anyway, I would recommend anyone to use my CaretPos(Function) instead since it is always accurate!

EM_CHARFROMPOS(Function) from "just me" fixed! (Sometimes it is not accurate as you can see in the image below!)
just me - Fuction Fixed.gif
just me - Fuction Fixed.gif (327.55 KiB) Viewed 1360 times

Code: Select all

	;https://autohotkey.com/boards/viewtopic.php?p=27857#p27857
	;The Edit control border is what cause the issues mentioned below! By using "-E0x200" to remove border, the issues are fixed!
	;issue: Example, the function returns 10 as Caret string pos when selected string Start\End is 9\9!
	;issue: the new approach "Caretxy" pos are always 2+ higher than "Caretxy" pos from "just me" approach!
	;Example: if string first pos is clicked, "just me" approach returns 1\1 and the new approach 3\3! (I don't know each one is more accurate!)
	;Anyway, I would recommend anyone to use my CaretPos(Function) instead since it is always accurate:
	;https://autohotkey.com/boards/viewtopic.php?p=178615#p178615


#NoEnv
Lorem := "
(
Lorem ipsum dolor sit amet
Consectetuer ligula Aliquam Curabitur Nullam
Rutrum eu est congue dui
Interdum Phasellus sed Quisque Donec
Et semper adipiscing id Sed
Non ut Quisque Pellentesque lorem
Est at urna justo sem
Proin consequat gravida nibh adipiscing
)"

Gui, Add, Edit, w400 r10, %Lorem%	;"-E0x200" to remove border
Gui, Show, , Get the caret!
Return

GuiClose:
ExitApp

~LButton Up::	;"~" keeps the button original function

MouseGetPos, , , WinId, ControlId, 2	;"2" Stores the control's HWND in "ControlId" variable rather than the control's ClassNN.

VarSetCapacity(POINT, 8, 0)
DllCall("User32.dll\GetCaretPos", "Ptr", &POINT)
X := NumGet(POINT, 0, "Int")
Y := NumGet(POINT, 4, "Int")

ControlGetPos, ControlX, ControlY, , , , % "ahk_id" ControlId

EM_CHARFROMPOS(ControlId, CaretPos, CaretLine)
EM_GETSEL(ControlId, Start, End)

tooltip, %  "" 
. "Pos from Windows upper\Left: `n"
. "ControlX: " ControlX "/ Controly:" Controly "`n"
. "A_CaretX: " A_CaretX "/ A_Carety:" A_Carety "`n"
. "`n"
. "Pos from Edit control upper\left: `n"
. "just me - CaretX: " x " \ Carety: " y "`n"
. "My test - Caretx:" A_CaretX - ControlX " Carety: " A_Carety - Controly "`n"
. "`n"
. "Caret String Pos: " CaretPos "/ Caret Line: " CaretLine "`n"
. "Selected String - Start: " Start " \ End: " End "`n"
. "WinId: " WinId " \ ControlId: " ControlId "`n"

Return


; ======================================================================================================================
; Gets information about the character closest to a specified point in the client area of an edit control.
; X, Y            -  the X- and Y-positions of the point.
; CharPos, Line   -  receive the character position and the line number.
; ======================================================================================================================
EM_CHARFROMPOS(HWND, ByRef CharPos, ByRef Line) {

T_CoordModeCaret := A_CoordModeCaret	;necessary to restore thread default option before function return
CoordMode, Caret, Window

ControlGetPos, CtrlX, CtrlY, , , , % "ahk_id" HWND	;"ahk_id" search controls by their hwnd id number

   ; EM_CHARFROMPOS = 0x00D7 -> msdn.microsoft.com/en-us/library/bb761566(v=vs.85).aspx
   CharPos := Line := 0
   CharLine := DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00D7, "Ptr", 0, "UInt", (A_CaretY - Ctrly << 16) | A_CaretX - CtrlX, "Ptr")
   CharPos := (CharLine & 0xFFFF) + 1
   Line := (CharLine >> 16) + 1

CoordMode, Caret, % T_CoordModeCaret	;restore thread default option before function return

Return True
}

; ======================================================================================================================
; Gets the starting and ending character positions of the current selection in an edit control.
; Start  -  receives the start of the current selection
; End    -  receives the end of the current selection
; ======================================================================================================================
EM_GETSEL(HWND, ByRef Start, ByRef End) {
   ; EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
   Start := End := 0
   DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")
   Start++, End++
   Return True
}
Last edited by User on 28 Oct 2017, 21:39, edited 2 times in total.
User avatar
jeeswg
Posts: 5411
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Edit Control: caret position before of after selection?

28 Oct 2017, 15:02

To understand the 2-pixel difference, compare the values for raw and client, in the script below, and then look over my function.

Code: Select all

;[JEE_CaretGetPos function]
;convert coordinates between Client/Screen/Window modes - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=6&t=38472&p=177058#p177058

q::
vList := "raw,client,screen,window"
vOutput := ""
Loop, Parse, vList, % ","
{
	vMode := A_Index = 1 ? "" : SubStr(A_LoopField, 1, 1)
	JEE_CaretGetPos(vPosX, vPosY, vMode)
	vOutput .= A_LoopField "`t" vPosX " " vPosY "`r`n"
}
;Clipboard := vOutput
MsgBox, % vOutput
return
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: Edit Control: caret position before of after selection?

28 Oct 2017, 15:48

jeeswg wrote:.
tried your script, but it's lacking a function!
User avatar
jeeswg
Posts: 5411
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Edit Control: caret position before of after selection?

28 Oct 2017, 16:22

The function is in the link. It's more reliable to keep a function only in one place, in case you need to update it.
User
Posts: 299
Joined: 26 Jun 2017, 08:12

Re: Edit Control: caret position before of after selection?

28 Oct 2017, 16:50

jeeswg wrote:.
the edit control border is what cause the 2+ difference and all the issues I mentioned in post above!

By using "-E0x200" to remove border, the issues are fixed!

Do you know how to get the size of a control border?
Sem Título.png
Sem Título.png (23.12 KiB) Viewed 1326 times
User avatar
jeeswg
Posts: 5411
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Edit Control: caret position before of after selection?

31 Oct 2017, 07:58

Re. the 2 pixel discrepancy. There is:
- the caret position relative to the client area of the Edit control
- the caret position relative to the client area of the Notepad window

There is also:
- the caret position relative to the screen
- the caret position relative to the top-left corner of the Notepad window

If you see in my example here, which is based on the AutoHotkey source code for A_CaretX/A_CaretY:
convert coordinates between Client/Screen/Window modes - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 58#p177058

I use GetWindowThreadProcessId specifying Notepad's hWnd, and I get returned hwndCaret, which is the Edit control's hWnd.

So I then convert: caret position (relative to Edit control's client area), to caret position (relative to screen), to caret position (relative to Notepad's client area).

For some other caret position info, see:
How to get control client area XY position? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=39129

This 2-pixel issue was seriously confusing me, when I first discovered it one or two weeks ago, but I managed to figure it out after a bit. Cheers.

==================================================

[EDIT:]
EM_CHARFROMPOS message (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
The coordinates of a point in the control's client area. The coordinates are in screen units and are relative to the upper-left corner of the control's client area.
[This is perhaps a little misleading, I believe that by window, this can actually mean control, which is also a type of window.]
GetCaretPos function (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
The caret position is always given in the client coordinates of the window that contains the caret.
GetWindowInfo function (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
WINDOWINFO structure (Windows)
https://msdn.microsoft.com/en-us/librar ... s.85).aspx
The coordinates of the client area.

Return to “Ask For Help”

Who is online

Users browsing this forum: gazmoz17, Google [Bot], Mipha and 43 guests