Page 1 of 1

How to get the text cursor / caret position

Posted: 13 Nov 2020, 18:00
by mythofechelon
I have a need to get the text cursor / caret position in order to get the text to the left of it when renaming a file in File Explorer.

I researched this and found many others with the same requirement but no proper solution. For example: I eventually threw together the following workaround which did work but was very inelegant - it was so noticeably slow that I could actually see the detection happening, it was very unreliable or extremely slow when at the beginning of the string, I had to rely on temporary usage of the clipboard, etc.

Code: Select all

ClipboardBackup := ClipboardAll
Clipboard := 
SendInput, {Shift Down}{Home}{Shift Up}^c
; ClipWait can't do sub-second waiting
Sleep, 100
TextToLeft := Clipboard
If (TextToLeft){
	; If there is text to the left then the text cursor / caret is not at the very beginning so pressing the right arrow key will cancel the text selection
	SendInput, {Right 1}
} Else {
	; If there is not text to the left then the text cursor / caret is at the very beginning so pressing the left arrow key will cancel the text selection
	SendInput, {Left 1}
}

Clipboard := ClipboardBackup
2020 ∕ 11 ∕ 13 23꞉07꞉27.gif
2020 ∕ 11 ∕ 13 23꞉07꞉27.gif (34.74 KiB) Viewed 5548 times
I toyed around with other ideas such as estimating the position by tracking inputs and/or using the width of the control and X co-ordinates of the caret but quickly realised how many different ways that would fail.

However, earlier this evening, I had a lightbulb / brainwave moment. What if I were to very quickly send an extremely rare character, get its position, and then delete it?

Slight tangent: Recently, I've really started to appreciate the value of Unicode characters (which I've written about at https mythofechelon.co.uk /blog/2020/3/6/how-to-work-around-windows-restricted-characters) Broken Link for safety and, the other day, I was configuring a Splunk alert and it required a message to be entered because it'd set its default text otherwise so I went looking for an "unprintable" (invisible) Unicode character and found just the thing: U+200E (Left-to-Right Mark (LRM))! (The RTLO character is an alternative but it can be flagged as malicious.)

So, it turns out that the combination of this idea and this character works perfectly!

Code: Select all

ControlGetFocus, FocusedControl
If (FocusedControl == "Edit1" Or FocusedControl == "Edit2"){
	SendInput, {U+200E}
	Sleep 50 ; Seems that SendInput isn't synchronous so need to wait a tiny bit before retrieving the new string
	ControlGetText, String, %FocusedControl%
	SendInput, {Backspace}
	StringLength := StrLen(String)
	CaretPosition := InStr(String, "‎") ; ← "‎" actually contains a U+200E unprintable / invisible Left-to-Right Mark (LRM) character
	TextToLeft := SubStr(String, 1, CaretPosition)
	TextToRight := SubStr(String, (CaretPosition - StringLength))
	
	ToolTip, String: %String%`nStringLength: %StringLength%`nCaretPosition: %CaretPosition%`nTextToLeft: %TextToLeft%`nTextToRight: %TextToRight%
}
2020 ∕ 11 ∕ 14 15꞉40꞉56.gif
2020 ∕ 11 ∕ 14 15꞉40꞉56.gif (31.14 KiB) Viewed 5501 times
I just thought I'd post this here for the good of others, seeing as I've never found a solution anywhere near as good online before. :)

Re: How to get the text cursor / caret position

Posted: 03 Dec 2020, 11:50
by SirSocks
Looks great from the gif's. The example code only shows snippets of the script. Can you post the full code script?

Looks like this should be posted in Scripts and Functions rather than Tutorials.

Re: How to get the text cursor / caret position

Posted: 03 Dec 2020, 14:12
by mythofechelon
That is the core of the script. How and in what context it's triggered is up to the user.

Hmm. It's a bit late for that, unless there's a way to move a post.

Re: How to get the text cursor / caret position

Posted: 13 Nov 2022, 07:28
by adrianh
This looks great. Not what I was looking for, but great none the less. Can definitely use this, except for one thing, I'm getting a blank for FocucedControl. Not sure what's going on. :(

Re: How to get the text cursor / caret position

Posted: 14 Nov 2022, 17:10
by ninjspks
you tried hooking caret event?

Re: How to get the text cursor / caret position

Posted: 15 Nov 2022, 01:40
by adrianh
No. Don't know anything about that. I was told that I would prolly have to use UIA to get it to work.

Re: How to get the text cursor / caret position

Posted: 15 Nov 2022, 16:56
by MancioDellaVega
adrianh wrote:
13 Nov 2022, 07:28
This looks great. Not what I was looking for, but great none the less. Can definitely use this, except for one thing, I'm getting a blank for FocucedControl. Not sure what's going on. :(
try this

Code: Select all

F1::

	ControlGetFocus, FocusedControl,A
	If (FocusedControl = "Edit1" ) or (FocusedControl = "Edit2"){
		
		SendInput, {U+200E}
		Sleep 50 ; Seems that SendInput isn't synchronous so need to wait a tiny bit before retrieving the new string
		ControlGetText, String, %FocusedControl%,A

		SendInput, {Backspace}
		StringLength := StrLen(String)
		CaretPosition := InStr(String, Chr(0x200E)) ; actually contains a U+200E unprintable / invisible Left-to-Right Mark (LRM) character
		TextToLeft := SubStr(String, 1, CaretPosition)
		TextToRight := SubStr(String, (CaretPosition - StringLength))
		
		ToolTip, String: %String%`nStringLength: %StringLength%`nCaretPosition: %CaretPosition%`nTextToLeft: %TextToLeft%`nTextToRight: %TextToRight%
	}

return


Re: How to get the text cursor / caret position

Posted: 16 Nov 2022, 07:37
by adrianh
Thx MancioDellaVega, you're change:

Code: Select all

ControlGetFocus, FocusedControl,A
was told to me before and it does work, up to a point. It still has issues with browsers and Visual Studio. It is why I was directed to the UIAutomation stuff.

Re: How to get the text cursor / caret position

Posted: 16 Nov 2022, 08:31
by Descolada
@adrianh, I also recommend checking out this Reddit thread, it has some low-level UIA code of similar nature that you are trying to achieve. Might give you better performance that the full UIA library (at the cost of way higher complexity).