Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get cursor position of winforms textbox

Tags:

c#

.net

winforms

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.

enter image description here

like image 492
user1027167 Avatar asked Aug 18 '15 08:08

user1027167


People also ask

How to set cursor position in TextBox in c# winforms?

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.

How do you get the cursor position in a TextBox in HTML?

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.


2 Answers

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.

like image 181
Steve Avatar answered Oct 09 '22 00:10

Steve


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.

like image 44
gunr2171 Avatar answered Oct 08 '22 23:10

gunr2171