Edit control: How put the caret to the start of a selection?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Edit control: How put the caret to the start of a selection?

10 Oct 2014, 00:24

Hi all,
Anyone know of a way how to put the caret in an Edit control to the start of a selection?
Or how to select text in an Edit control with the caret being at the start of the selection afterwards?

The problem is that with EM_SETSEL (Message to Edit Control) it puts the caret always at the end of the selection but not at the start, not matter how you submit the parameters.

It seems to me that, when a selection exists, it maybe could work with EM_POSFROMCHAR (Message to Edit Control) and DllCall("User32.dll\SetCaretPos", "Int", X, "Int", Y)??

I tried the following:

Code: Select all

Edit_PosFromChar(hEdit,p_CharPos,ByRef X,ByRef Y) ;I found this function in one of the ahk forums
    {
    Static EM_POSFROMCHAR:=0xD6
    SendMessage EM_POSFROMCHAR,p_CharPos,0,,ahk_id %hEdit%
    X:=(ErrorLevel & 0xFFFF)<<48>>48
        ;-- LOWORD of result and converted from UShort to Short
    Y:=(ErrorLevel>>16)<<48>>48
        ;-- HIWORD of result and converted from UShort to Short
    }

indexOfTargetChar := 3 ;its only some number for testing, supposedly zero-based
Edit_PosFromChar(HEDIT, indexOfTargetChar, X, Y) ;HEDIT is the handle to the Edit control
VarSetCapacity(iX, 4, 0)
VarSetCapacity(iY, 4, 0)
NumPut(X, iX, 0, "Int")
NumPut(Y, iY, 0, "Int")
DllCall("User32.dll\SetCaretPos", "Int", iX, "Int", iY)
The problem, however, is that the caret always moves to the very first position in edit control (regardless of the value indexOfTargetChar) and if I continue to select text afterwards manually with shift and arrow keys, then the caret jumps to where it was in the first place and the selection starts from there.

If I call SetCaretPos as DllCall("User32.dll\SetCaretPos", "Int", &iX, "Int", &iY) (note the &) then the caret changes to not visible at all. Subsequent manual selection behaves the same as described, though.

Does anybody know of a solution? Thx!
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 01:56

Code: Select all

BOOL WINAPI SetCaretPos(
  _In_  int X,
  _In_  int Y
) ; http://msdn.microsoft.com/en-us/library/ms648405(v=vs.85).aspx
The function expects two integer values. You must not use VarSetCapacity() and NumPut(). Just pass the variables as are. AHK will convert the format for you automatically.
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 02:54

Thank you very much for your reply, "just me".
Unfortunately I cant get it to work.
I created an example based on your answer in this post (http://ahkscript.org/boards/viewtopic.php?f=5&t=4826):

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!
Sleep, 2000 ;time for the user to change the selection/caret position for better visual feedback
Goto, Selection
Return

GuiClose:
ExitApp

Selection:
Edit_PosFromChar(HEDIT, 3, X, Y)
DllCall("User32.dll\SetCaretPos", "Int", X, "Int", Y)
Return

Edit_PosFromChar(hEdit,p_CharPos,ByRef X,ByRef Y) ;I found this function in one of the ahk forums
    {
    Static EM_POSFROMCHAR:=0xD6
    SendMessage EM_POSFROMCHAR,p_CharPos,0,,ahk_id %hEdit%
    X:=(ErrorLevel & 0xFFFF)<<48>>48
        ;-- LOWORD of result and converted from UShort to Short
    Y:=(ErrorLevel>>16)<<48>>48
        ;-- HIWORD of result and converted from UShort to Short
    }
The result is the same as described in my first post.

However, if it is true that GetCaretPos (see other post) does not work with my intended 3rd party window, then for sure SetCaretPos will not either.
In this case, maybe it is not worth investigating further, since I could anyway not utilize a generally working solution with SetCaretPos.
Any thoughts on the matter?
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 03:08

Your last script is working as expected for me. It sets the caret, but doesn't clear the selection. In either case the control has to be an edit control and must have the focus while you call SetCaretPos().
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 03:40

just me wrote:It sets the caret, but doesn't clear the selection.
Yes, thx, but did you try to move the caret afterwards with the arrow keys (optionally with pressed shift-key)? It jumps right back to where it was before SetCaretPos.
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 03:45

I'd think that's the way the edit control is setting the caret internally.
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 03:52

alright, then, if this behaviour can not be changed then I definitely have no use for SetCaretPos.
Thank you, "just me", all the same.
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 04:29

How put the caret to the start of a selection?
I didn't read carefully enough what you are trying to achieve, sorry.

Code: Select all

#NoEnv
SetBatchLines, -1
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, Set caret!
Gui, Show, , Set the caret!
Return

GuiClose:
ExitApp

Selection:
GuiControl, Focus, %HEDIT%
EM_GETSEL(HEDIT, S, E)
If (E > S)
   EM_SETSEL(HEDIT, E, S)
Return

; ======================================================================================================================
; 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
}
; ======================================================================================================================
; Selects a range of characters in an edit control.
; Start  -  the character index of the start of the selection.
; End    -  the character index of the end of the selection.
; ======================================================================================================================
EM_SETSEL(HWND, Start, End) {
   ; EM_SETSEL = 0x00B1 -> msdn.microsoft.com/en-us/library/bb761661(v=vs.85).aspx
   Return DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B1, "Ptr", Start - 1, "Ptr", End - 1, "Ptr")
}
If the caret is at the begin of a selection, End returned from EM_GETSEL() will be less than Start. Otherwise you can use EM_SETSEL() with swapped positions to move the caret to the begin of the selection.

But I still don't know if it will work for your '3rd party app'.
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 06:02

Ok, now I see the problem. I had used EM_SETSEL with SendMessage before and in the 3rd party app it does select the text (therefore I thought it works) but always places the caret behind the selection, regardless of the order of the parameters. In your example it works the way I would like for it to work. Did not know that this was the standard behaviour. So it is a problem with the 3rd party app after all.
just me wrote:If the caret is at the begin of a selection, End returned from EM_GETSEL() will be less than Start.
EM_GETSEL, however, returns always the lower position as start and the higher one as end, also in your example. No problem, though, I anyway have to live with the facts of my 3rd party app. :) (And besides, as mentioned in the 1st post of the other thread, I did find kind of a work-around for that if I should need it ever again.)
just me
Posts: 9576
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Edit control: How put the caret to the start of a select

10 Oct 2014, 06:39

autocart wrote:EM_GETSEL, however, returns always the lower position as start and the higher one as end, also in your example.
Well, must have dreamed while testing. :?
autocart
Posts: 214
Joined: 12 May 2014, 07:42

Re: Edit control: How put the caret to the start of a select

11 Oct 2014, 04:21

Thx to you "just me" again for all your help and to you RobertL also for your help in the other thread (http://ahkscript.org/boards/viewtopic.php?f=5&t=4826).
I finally came up with a workaround that is good enough for me. Since I was helped I also want to share my results. Maybe they are useful for somebody whenever. (BTW, I am using this to select text in an inline-edit-box in the 3rd party app "XYplorer".):

Code: Select all

; Selects text in an edit box (simulating manual selection), starting at
; the current caret position, given absolute character target position.
;
; selectToPos:      	target character offset (zero-based)
; editNNHavingFocus:	the edit control in the form of EditNN
; wintitle:				self explanatory
; [curCaretPos]:		optional - if it is already known it can be put here hoping
;						to make execution a bit faster and maybe more stable
;
; other (possibly) called function: _Edit_CaretGetPos
;
_Edit_SelectFromCurPos(selectToPos, editNNHavingFocus, wintitle, curCaretPos="")
{
	if (not curCaretPos)
		curCaretPos := _Edit_CaretGetPos(editNNHavingFocus, wintitle)
    selectionLength := selectToPos - curCaretPos
	selectionSendString := "{Shift Down}"
	if (selectionLength < 0)
	{
		selectionLength := Abs(selectionLength)
		Loop, %selectionLength%
		{
			selectionSendString := selectionSendString . "{Left}"
		}
	}
	else
	{
		Loop, %selectionLength%
		{
			selectionSendString := selectionSendString . "{Right}"
		}
	}
	selectionSendString := selectionSendString . "{Shift Up}"
	orgValueSKD := A_KeyDelay
	SetKeyDelay, -1
	BlockInput, Send
	ControlGetFocus, focusedControl, %wintitle%
	if (focusedControl = editNNHavingFocus)
		Send, %selectionSendString%
	BlockInput, Default
	SetKeyDelay, %orgValueSKD%
}

; 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: 407
Joined: 26 Jun 2017, 08:12

Re: Edit control: How put the caret to the start of a selection?

26 Oct 2017, 20:51

autocart wrote: The problem is that with EM_SETSEL (Message to Edit Control) it puts the caret always at the end of the selection but not at the start, not matter how you submit the parameters.
Are you sure of that?
select deselect String Test.gif
select deselect String Test.gif (661.64 KiB) Viewed 3228 times

Code: Select all

loop, 60
text .= "AAAAAAAA"

gui, add, edit, w300 h200 +HwndControlId, % text

gui, add, button, vCarteStar gSelect, Select String (Caret at Start)
gui, add, button, vCaretEnd x+5 gSelect, Select String (Caret at End)
gui, add, button, xm gSelectAll, Select All
gui, add, button, x+5 gRemoveSel, Remove Selection

gosub, RemoveSel

gui, show
return

Select:	;_______ Select ________

if (A_GuiControl = "CaretEnd")
Start := 100, End := 200
else
Start := 200, End := 100

;"0xB1", EM_SETSEL
;if Start < End select from left to right
;if Start > End select from right to left
SendMessage, 0xB1, % Start, % End, , % "ahk_id" ControlId

ControlFocus, , % "ahk_id" ControlId

return

SelectAll:	;_______ Select All _________

;Select all
SendMessage, 0xB1, 0, -1, , % "ahk_id" ControlId

ControlFocus, , % "ahk_id" ControlId

return

RemoveSel:	;________ Remove Sel _______

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

ControlFocus, , % "ahk_id" ControlId

return

guiclose:	;________ gui close _______
exitapp

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot] and 274 guests