Click here to Skip to main content
14,336,453 members
Rate this:
Please Sign up or sign in to vote.
See more:
i want to find the keyboard cursor's location (x,y) on form in c# win. form. How to achieve this?
[see the link to see the difference between mouse cursor and keyboard cursor]

https://www.dropbox.com/s/bcocp5stn0pzvwe/Untitled.png[^]



Thanks in advance
Posted
Updated 3-Feb-14 0:26am
v3
Comments
Mitchell J. 2-Feb-14 5:45am
   
What do you mean by "keyboard cursor"? How is this different to a normal cursor?
agent_kruger 2-Feb-14 5:54am
   
difference is that mouse cursor is that when you move mouse that changes the x and y (co-ordinates of it) and keyboard cursor location means that whenever you write a character it moves from the starting position to after the inserted charachter.
BillWoodruff 2-Feb-14 8:08am
   
Are you asking about determining the current position of the Text Insertion Cursor in a TextBox ? Or ... ?
Rate this:
Please Sign up or sign in to vote.

Solution 1

'There isn#t a "keyboard position" on a form: there are many potential positions, depending on which control has the input focus.

You can find which control in a container has the focus, using the ContainerControl.ActiveControl property[^] and then get the keboard input point for that particular control:
void myTimer_Tick(object sender, EventArgs e)
    {
    string s = "--none--";
    Control c = ActiveControl;
    if (c != null)
        {
        s = c.Name;
        TextBox tb = c as TextBox;
        if (tb != null)
            {
            s += string.Format(" : {0}", tb.SelectionStart);
            }

        }
    theKeyboardIsHere.Text = s;
    }

Fortunately, ActiveControl searches sub-containers for you!
   
Comments
BillWoodruff 2-Feb-14 20:42pm
   
+5 I wonder how many readers will know that knowing 'ActiveControl (for Form, UserControl, PropertyGrid, and other descendants of ContainerControls) performs a recursive search which will examine the contents of nested Controls which are not ContainerControls (i.e., Panel) is information "worth its weight in gold" ?
OriginalGriff 3-Feb-14 4:48am
   
I wonder how many reader will know it even exists? :laugh:
agent_kruger 3-Feb-14 6:31am
   
sorry sir, for 3 but check the updated question and active control cannot be used in my project sir
OriginalGriff 3-Feb-14 6:52am
   
You can (in theory) find the Caret (that's what the input point on your image is called) in another application, but it's not a lot of fun...or even guaranteed to work.
But...there is code here:
http://bytes.com/topic/c-sharp/answers/259851-getting-position-caret
which purports to do it - it's at the bottom. However, you will need to set up the PInvoke signatures, and I really don't know if it will work on modern operating systems - there is a good chance it won't. I haven't tried it (because I don't need to do it) and I think it's probably a nasty solution to whatever problem you are going to use it for!
Good luck...
BillWoodruff 3-Feb-14 8:23am
   
Why can't ActiveControl be used in your Project ?
agent_kruger 3-Feb-14 8:27am
   
actually, i was using it for treeview control to solve a nasty need of my project which was solved by Mr. OriginalGriff's last answer in the comment box.
Rate this:
Please Sign up or sign in to vote.

Solution 2

Note: code examples here have been tested, and verified, in Visual Studio 2013, compiled against .NET FrameWork 4.5, using the 'AnyCPU build option on a Win 8/64 machine.

After some research, I've found there is a known problem with using 'GetPositionFromCharIndex to determine the caret position (insertion cursor point) in a TextBox under certain circumstances. However, 'GetPositionFromCharIndex works fine with a RichTextBox.

With a TextBox:

To reliably get the caret point in a TextBox, it is necessary to use a WinAPI call:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCaretPos(out Point lpPoint);
Here's the original code I posted modifed to use the WinAPI 'GetCaretPos function:
private Point GetCursorTextBox(TextBox theTextBox)
{
    // see note below on this
    // Control currentActiveControl = ActiveControl;

    // see note below on why this check is here ...
    if (this.ActiveControl != theTextBox)
    {
        this.ActiveControl = theTextBox;
    }`
    
    // get the caret position which is the
    // row-column address of where in the
    // TextBox's Lines collection the insertion cursor is at
    Point chrTbLocation;

    GetCaretPos(out chrTbLocation);

    // index of the character insertion cursor is at
    int selStart = theTextBox.SelectionStart + theTextBox.SelectionLength;

    // line number the insertion cursor is at
    int line = theTextBox.GetLineFromCharIndex(selStart);

    // point in the Screen insertion cursor is at
    Point chrScrnLocation = theTextBox.PointToScreen(chrTbLocation);

    // point in the Form insertion cursor is at
    Point chrFrmLocation = this.PointToClient(chrScrnLocation);

    // for testing only ...

    // this should be identical to the value in 'selStart
    int charPosition = textBox1.GetCharIndexFromPosition(chrTbLocation);

    Console.WriteLine("Caret at: Line: {0} Column: {1} in TextBox: {2}", line, selStart, theTextBox.Name);
    Console.WriteLine("Screen Location: {0} Form Location: {1}", chrScrnLocation, chrFrmLocation);
    Console.WriteLine();

    // see note below on this
    // ActiveControl = currentActiveControl;

    // return the caret point in Form co-ordinates
    return chrFrmLocation;
}
Note that at the start of the method, a check is done to determine if the TextBox argument to the method is the current ActiveControl on the Form; if it is not, then the TextBox argument is made the ActiveControl. This is done because the call to 'GetCaretPos has no way of "knowing" which Control on the Form, if any, currently is the ActiveControl.

But, also, note that if you invoke the 'GetCursorTextBox method from an EventHandler of the TextBox passed in as an argument, such as in the TextChanged EventHandler, then that check is not really necessary because the TextChanged event is only going to be raised when the TextBox is the ActiveControl.

If having the ActiveControl changed by the 'GetCursorTextBox method presents a problem for you, then preserve the current ActiveControl at the start of the method, and set it back at the end of the method. Code to do this is shown commented out.

With a RichTextBox:

This code will work fine with a RichTextBox:
private Point GetCursorRichTextBox(RichTextBox theRichTextBox)
{
    // index of the character insertion cursor is at
    int selStart = theRichTextBox.SelectionStart + theRichTextBox.SelectionLength;

    // line number the insertion cursor is at
    int line = theRichTextBox.GetLineFromCharIndex(selStart);

    // point in the TextBox insertion cursor is at
    Point chrTbLocation = theRichTextBox.GetPositionFromCharIndex(selStart);

    // point in the Screen insertion cursor is at
    Point chrScrnLocation = theRichTextBox.PointToScreen(chrTbLocation);

    // point in the Form insertion cursor is at
    Point chrFrmLocation = this.PointToClient(chrScrnLocation);

    // for testing only ...

    // this should be identical to the value in 'selStart
    int charPosition = theRichTextBox.GetCharIndexFromPosition(chrTbLocation);

    Console.WriteLine("Caret at: Line: {0} Column: {1} in RichTextBox: {2}", line, selStart, theRichTextBox.Name);
    Console.WriteLine("Screen Location: {0} Form Location: {1}", chrScrnLocation, chrFrmLocation);
    Console.WriteLine();

    // return the caret point in Form co-ordinates
    return chrFrmLocation; 
}
   
v4
Comments
agent_kruger 3-Feb-14 9:00am
   
no sir, sorry to say that doesn't work at all (1 Point) but thank you for taking time and writting the code (+2 Points)
BillWoodruff 3-Feb-14 9:12am
   
It certainly does work. Put a TextBox on a Windows Form, and insert that code in the Form it's on, then call the method passing a reference to a TextBox, and you get back the location in Form co-ordinates of where the insertion cursor is at in the TextBox.

Point iCursorAt = GetCursorInfo(NameOfMyTextBox);

If there is no selection, no cursor position set by user action, then when the method is called, the location returned will be the same as if the insertion cursor was at the first character in the TextBox.
agent_kruger 3-Feb-14 9:18am
   
sir, i tried it and current location of my textbox is "783, 192" and size is "193, 163" and on writting "1" it shows answer "785,194" and on writting "123456789" it shows "785,194". Why this is so sir?
BillWoodruff 3-Feb-14 10:12am
   
Well, testing in VS 2013, using FrameWork 4.5, I am finding some strange results; and, I have used code like this several years ago, in VS 2008, with no problem. I am observing that if I manually set the insertion cursor, and then type, I get results as expected from the call to 'GetPositionFromCharIndex, but if I delete all the text, and start typing the value doesn't change ... even though I can see by inspection that 'selStart and 'line variables are being updated as expected.

It's GMT +7 here, and I'm a bit burned-out, so I'll take another look at this tomorrow morning. I am sure this is the right technique to use.

I am sure someone with the good name of 'Spock has great patience, but, if your patience fails, well, you are half-human, after all, so: just keep down-voting me :)
agent_kruger 3-Feb-14 18:50pm
   
no sir, at least you tried :)
BillWoodruff 3-Feb-14 21:01pm
   
Good news: help is on the way. The code I used some years ago, which works properly, worked with a RichTextBox, not a TextBox, and through research I have verified that other people have seen the same type of problems using 'GetPositionFromCharIndex with a TextBox. where it will work in some circumstances, and not work in others.

In a short time, I'll have a revised solution up.

cheers, Bill
agent_kruger 3-Feb-14 21:29pm
   
thank you sir, that sounds assuring
BillWoodruff 5-Feb-14 0:36am
   
Revised, tested, solution posted.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100