Retrieve the Caret Position by Using an Extended TextBox Class

CodeGuru Editor's Comment: This article uses the Win32 API from C#. Generally, you should avoid calling such unmanaged code from a managed (.NET) application. This is, however, an interesting example of calling the API from .NET.


Sometimes, we need to know the caret position in a TextBox control; for example, in editor programs. The following ExtTextBox class extends the TextBox class with two read-only properties. The GetCaretXYPosition returns a Point struct with the (X,L) coordinates of the current position of the caret. The GetCaretLCPosition returns a CharPoint custom struct with the (L, C) coordinates of the position of the caret, where L is the one-based line number and C is the one-based column number.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
namespace TextBoxUtils
{
   /// <summary>
   /// struct to handle the caret (L, C) co-ordinates
   /// L = one-based line number of the line containing the caret
   /// C = one-based column number in the line containing the caret
   /// </summary>
   public struct CharPoint
   {
      private int l, c;

      public static readonly CharPoint Empty;

      static CharPoint()
      {
         CharPoint.Empty = new CharPoint();
      }

      public CharPoint(int l, int c)
      {
         this.l = l;
         this.c = c;
      }

      public override string ToString()
      {
         return(String.Format("{{L={0}, C={1}}}", this.l, this.c));
      }

   }

   public class ExtTextBox: TextBox
   {
      [DllImport("user32")] private static extern IntPtr
                            SendMessage(HandleRef hWnd, int msg,
                                        int wParam, int lParam);
      [DllImport("user32")] private static extern int
                            GetCaretPos(ref Point lpPoint);
      private int EM_LINEINDEX    = 0xbb;
      private int EM_LINEFROMCHAR = 0xc9;
      private int EM_GETSEL       = 0xb0;

      /// <summary>
      /// Gets the caret current (X, Y) position.
      /// </summary>
      /// <value>
      /// Point struct
      /// </value>
      public Point GetCaretXYPosition
      {
         get
         {
            Point pt = Point.Empty;
            // get a Point struct with the caret current (X, Y)
            // position
            GetCaretPos(ref pt);
            // return the Point struct with the caret current
            // (X, Y) position
            return pt;
         }
      }

      /// <summary>
      /// Gets the caret current (L, C) position.
      /// </summary>
      /// <value>
      /// CharPoint struct
      /// </value>
      public CharPoint GetCaretLCPosition
      {
         get
         {
            CharPoint cpt = CharPoint.Empty;
            // save the handle reference for the ExtToolBox
            HandleRef hr = new HandleRef(this, base.Handle );
            // Send the EM_LINEFROMCHAR message with the value of
            // -1 in wParam.
            // The return value is the zero-based line number 
            // of the line containing the caret.
            int l = (int)SendMessage(hr,EM_LINEFROMCHAR, -1, 0);
            // Send the EM_GETSEL message to the ToolBox control.
            // The low-order word of the return value is the
            // character position of the caret relative to the
            // first character in the ToolBox control,
            // i.e. the absolute character index.
            int sel = (int)SendMessage(hr, EM_GETSEL,0, 0);
            // get the low-order word from sel
            int ai  = sel & 0xffff; 
            // Send the EM_LINEINDEX message with the value of -1
            // in wParam.
            // The return value is the number of characters that
            // precede the first character in the line containing
            // the caret.
            int li = (int)SendMessage(hr,EM_LINEINDEX, -1, 0);
            // Subtract the li (line index) from the ai
            // (absolute character index),
            // The result is the column number of the caret position
            // in the line containing the caret.
            int c = ai - li;
            cpt = new CharPoint(l+1,c+1);
            // Add 1 to the l and c since these are zero-based.
            // Return a CharPoint with the caret current (L,C)
            // position
            return new CharPoint(l+1,c+1);
         }
      }
   }
}


Downloads

Comments

  • The Secret rule the mizuno-market Is Really Straightforward!

    Posted by Acuddence on 05/01/2013 11:33pm

    Beginner questions regarding nike have been answered and therefore the reasons you must absolutely read in detail each message of this story.[url=http://www.nikejpgolf.biz/]ナイキ[/url] An actual double strain on nike [url=http://www.nikejpgolf.biz/nike-ゴルフボール-c-23.html]nikegolf[/url] Progressive questions on nike clarified and therefore why you must definitely view each term of this specific story. [url=http://www.nikejpgolf.biz/nike-アイアン-c-1.html]ゴルフ ナイキ[/url] Honest statement discloses Seven innovative new things on mizuno that not a soul is speaking of. [url=http://www.nikejpgolf.biz/nike-アイアン-c-1.html]ナイキ[/url] A nike Commerce Dialog - Which means, who cares is the winner?! [url=http://www.nikejpgolf.biz/nike-ゴルフシューズ-c-15.html]nike dunk[/url] Supplies and assembly throughout Michigan -- nike will leave without cheers [url=http://www.nikeyasuyi.com/]ナイキ スニーカー[/url] Goods and show in Las Vegas, Nevada - mizuno actually leaves without good-bye [url=http://www.nikeyasuyi.com/nikeナイキRunning-c-3.html]nike running[/url] Some of the nike Company Dialog -- Those who cares gains all the rewards? [url=http://www.nikeyasuyi.com/nikeナイキDunk-c-9.html]ナイシューズ[/url] A nike Sector Dialog : Customers who cares about fears benefits?! [url=http://www.nikeyasuyi.com/nikeナイキDunk-c-9.html]nike dunk[/url] mizuno offers fresh, new lifespan to a old matter. . . defacto requirements

    Reply
  • Observation

    Posted by webmasta on 05/05/2005 10:06pm

    Excellent results with the caret co-ordinates! For the line and col: #1: Erroneous results with wordwrap on. #2: Counts a tab space as one column.

    Reply
  • Why this article was passed

    Posted by darwen on 11/21/2004 06:57pm

    Your comments were viewed by myself in the reviewer's forum. However, I considered this article to have useful areas (e.g. the use of HandleRef) which made it worthwhile publishing. Yes, there are alternative methods to do this but this demonstrates .NET classes which people might not be aware of, and as such was published.

    Reply
  • This seems like overkill

    Posted by gregoftheweb on 10/15/2004 12:16pm

    Internet Explorer exposes the caret position of TextArea's natively. This can all be accomplished on the client with no round trip to the server. If you eventually need the carret position you can pass the position by itself back to the application.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • Due to internal controls and regulations, the amount of long term archival data is increasing every year. Since magnetic tape does not need to be periodically operated or connected to a power source, there will be no data loss because of performance degradation due to the drive actuator. Read this white paper to learn about a series of tests that determined magnetic tape is a reliable long-term storage solution for up to 30 years.

Most Popular Programming Stories

More for Developers

RSS Feeds