Reputation: 4448
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.
Upvotes: 7
Views: 9913
Reputation: 480
When you click the mouse or move an arrow key button inside a TextBox, your cursor will be moved to a new location and the location will be recorded in this variable.
textBox1.SelectionStart
The value is character count starting from 0 at the beginning of the TextBox to the location of your cursor. If you carefully code it, you'll make it work correctly. To highlight selection, you should use this function to avoid confusion.
textBox1.Select(start, length);
where
int start = textBox1.SelectionStart;
int length = textBox1.SelectionStart+textBox1.SelectionLength;
Upvotes: 0
Reputation: 1
This may come in use to someone:
int lastSelectionStart = 0;
int getCaretPosition()
{
if (tbx.SelectionLength == 0)
{
lastSelectionStart = tbx.SelectionStart;
return lastSelectionStart;
}
else
{
if (tbx.SelectionStart == lastSelectionStart)
{
return tbx.SelectionStart + tbx.SelectionLength;
}
else
{
return lastSelectionStart - tbx.SelectionLength;
}
}
}
Upvotes: 0
Reputation: 17545
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.
Upvotes: 1
Reputation: 216293
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.
Upvotes: 9
Reputation: 48415
If you want the left side of the selection, you can use:
int index = textBox.SelectionStart;
If you want the right side of the selection, you can use:
int index = textBox.SelectionStart + textBox.SelectionLength;
If you need to know which direction the text was selected then you could try tracking mouse down and mouse up events and comparing the cursor positions when the events fired.
For example:
// On mouse down event.
int mouseDownX = MousePosition.X;
// On mouse up event.
int mouseUpX = MousePosition.X;
// Check direction.
if(mouseDownX < mouseUpX)
{
// Left to Right selection.
int index = textBox.SelectionStart;
}
else
{
// Right to Left selection.
int index = textBox.SelectionStart + textBox.SelectionLength;
}
Upvotes: 0