How do I get the current cursor (caret) position of a winforms textbox in .NET? SelectionStart only returns the start of the selected text (left side of the selection). Means this value is wrong if the cursor is at the right side of the selection.
To clarify: In .NET TextBox SelectionStart points to the left side of an selection, also when the caret is at the right side of the selection. This means in both pictures SelectionStart is 2, but the caret position is 2 in the first picture and 7 in the right picture.
To position the cursor at the beginning of the contents of a TextBox control, call the Select method and specify the selection start position of 0, and a selection length of 0.
First, get the current position of cursor with the help of property named as selectionStart on textarea/inputbox. To insert the text at the given position we will use slice function to break the string into two parts and then we will append both parts to the text(text_to_insert) in front and end of the text.
As already stated, the SelectionStart
property is not reliable to get the actual CARET position in a TextBox with a selection active. This is caused by the fact that this property points always at the selection start (clue: the name doesn't lie) and depending on how you select the text with the mouse the caret could be positioned on the LEFT or RIGHT side of the selection.
This code (tested with LinqPAD) shows an alternative
public class WinApi
{
[DllImport("user32.dll")]
public static extern bool GetCaretPos(out System.Drawing.Point lpPoint);
}
TextBox t = new TextBox();
void Main()
{
Form f = new Form();
f.Controls.Add(t);
Button b = new Button();
b.Dock = DockStyle.Bottom;
b.Click += onClick;
f.Controls.Add(b);
f.ShowDialog();
}
// Define other methods and classes here
void onClick(object sender, EventArgs e)
{
Console.WriteLine("Start:" + t.SelectionStart + " len:" +t.SelectionLength);
Point p = new Point();
bool result = WinApi.GetCaretPos(out p);
Console.WriteLine(p);
int idx = t.GetCharIndexFromPosition(p);
Console.WriteLine(idx);
}
The API GetCaretPos
returns the point in client coordinates where the CARET is. You could return the index of the character after the position using the managed method GetCharIndexFromPosition
. Of course you need to add a reference and a using to System.Runtime.InteropServices
.
Not sure if there is some drawback to this solution and waiting if someone more expert can tell us if there is something wrong or unaccounted for.
With the answer from Steve this is now my solution:
[DllImport("user32")]
private extern static int GetCaretPos(out Point p);
...
// get current caret position
Point caret;
GetCaretPos(out caret);
int caretPosition = tbx.GetCharIndexFromPosition(caret);
Additionally (not part of my question) I am able to set the caret and text selection with following code. There also is a SetCaret function in user32.dll which didn't work for me. But surprisingly the Select() function supports negative values for selection length.
// determine if current caret is at beginning
bool caretAtBeginning = tbx.SelectionStart == caretIndex;
...
// set text selection and caret position
if (caretAtBeginning)
tbx.Select(selStart + selLength, -selLength);
else
tbx.Select(selStart, selLength);
Note: This post was extracted from the Question and posted on the OP's behalf.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With