Click here to Skip to main content
11,416,787 members (56,181 online)
Click here to Skip to main content

Getting Caret Position Inside Any Application

, 30 Mar 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Retrieves Caret position from any application and converts it to the Screen Coordinates

Introduction 

Sometimes we need to know about the caret position inside another application for various purposes like showing Tooltip or message window along with caret. (Here the other application is an entirely different process and not connected in any way with our application.) This article describes how to show a tooltip window next to the caret in any application. The source code, attached here, is fully illustrative and easy to understand.

Background

Though there are many ways to get the caret position inside an application, the problem is that those methods are associated with the client region and non client regions and provide/use wrong handles. This association leads to wrong information about caret position inside Microsoft Office 2007 like products where the entire window results as the client area. Facing the same client and non client region problem, I spent some time looking for the possible solution and arrived at this approach. The utility is ready to use. You can enhance the UI or add some more information.

Using the Code 

To test the caret postion, just run the application and follow the process below:

  1. Open a Notepad and type some text. It will show tooltip next to caret. While typing, Tooltip moves along with caret.
  2. Now move the Notepad window and observe the continuously changing caret position inside tooltip.
  3. When Notepad window reaches the edge of screen, Tooltip changes its position (By default, it gets displayed at the bottom right to the caret).
  4. Now click on Desktop, Tooltip disappears.
  5. Now open Microsoft Word and see the Tooltip re-appear. Tooltip can be moved by pressing the left mouse button and moving the cursor onto it.

Explanation

GetCaretPosition() method populates GUI Thread information into guiInfo object. guiInfo is a structure variable of type GUIThreadInfo that is required by GetGUIThreadInfo() method of user32.dll

  public void GetCaretPosition()
  {
       guiInfo = new GUITHREADINFO();
       guiInfo.cbSize = (uint)Marshal.SizeOf(guiInfo);

       // Get GuiThreadInfo into guiInfo
       GetGUIThreadInfo(0, out guiInfo);
  }   

guiInfo variable is a global variable that is further processed by EvaluateCaretPosition() method. This method fetches caret information and handle of associated window from guiInfo object and converts it to the screen coordinates.

  private void EvaluateCaretPosition()
   {
        caretPosition = new Point();                 

        // Fetch GUITHREADINFO
        GetCaretPosition();

        caretPosition.X = (int)guiInfo.rcCaret.Left + 25;
        caretPosition.Y = (int)guiInfo.rcCaret.Bottom + 25;

        ClientToScreen(guiInfo.hwndCaret, out caretPosition);

        txtCaretX.Text = (caretPosition.X).ToString();
        txtCaretY.Text = caretPosition.Y.ToString();
   }

Further the tooltip should be visible only for GUI applications and not for Windows Explorer likewise renaming any file on desktop. For this current active process is evaluated by GetActiveProcess() method. This method returns the name of currently active process to the timer event.

 private string GetActiveProcess()
  {
        const int nChars = 256;
        int handle = 0;
        StringBuilder Buff = new StringBuilder(nChars);
        handle = (int)GetForegroundWindow();

        // If Active window has some title info
        if (GetWindowText(handle, Buff, nChars) > 0)
         {
               uint lpdwProcessId;
               uint dwCaretID = GetWindowThreadProcessId(handle, out lpdwProcessId);
               uint dwCurrentID = (uint)Thread.CurrentThread.ManagedThreadId;
               return Process.GetProcessById((int)lpdwProcessId).ProcessName;
         }

         // Otherwise either error or non client region
         return String.Empty;
  }	

In the timer event, just check whether the tooltip is foreground window (just because user might have clicked on that), if not then check whether Windows Explorer is an active process(just because of user click on desktop/ opening Wiindows Explorer), if so then hide tooltip else evaluate caret position and adjust tooltip position by AdjustUI() method.

  private void timer1_Tick(object sender, EventArgs e)
           {
               // If Tooltip window is active window (Suppose user clicks on the
               //  Tooltip Window)
               if (GetForegroundWindow() == this.Handle)
               {
                   // then do no processing
                   return;
               }

               // Get Current active Process
               string activeProcess = GetActiveProcess();

               // If window explorer is active window (eg. user has opened any drive)
               // Or for any failure when activeProcess is nothing               
               if ((activeProcess.ToLower().Contains("explorer") |
 			(activeProcess == string.Empty)))
               {
                   // Dissappear Tooltip
                   this.Visible = false;
               }
               else
               {
                   // Otherwise Calculate Caret position
                   EvaluateCaretPosition();

                   // Adjust ToolTip according to the Caret
                   AdjustUI();

                   // Display current active Process on Tooltip
                   lblCurrentApp.Text = " You are Currently inside : " + activeProcess;
                   this.Visible = true;
               }               
           }

The AdjustUI method is responsible to adjust UI of tooltip to keep it inside user screen.

 private void AdjustUI()
           {
               // Get Current Screen Resolution
               Rectangle workingArea = SystemInformation.WorkingArea;

               // If current caret position throws Tooltip outside of screen area
               // then do some UI adjustment.
               if (caretPosition.X + this.Width > workingArea.Width)
               {
                   caretPosition.X = caretPosition.X - this.Width - 50;
               }

               if (caretPosition.Y + this.Height > workingArea.Height)
               {
                   caretPosition.Y = caretPosition.Y - this.Height - 50;
               }

               this.Left = caretPosition.X;
               this.Top = caretPosition.Y;
           }

Points of Interest

After spending some time on Google to get some clue about it, I found some people saying that it is impossible for Microsoft Office 2007 products because it has its own paint logic. Then I tried to resolve this problem and reached the solution shared here that works for any application (Including Microsoft Office 2007 & Visual Studio).

History

  • 30th March, 2009: Initial post

License

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

Share

About the Author

Saurabh Singh Gangwar
Software Developer (Senior)
India India
No Biography provided

Comments and Discussions

 
QuestionDoes not work with Google Chrome browser Pin
Member 1162265920-Apr-15 6:01
memberMember 1162265920-Apr-15 6:01 
Bugit works in most programs but not all Pin
Member 1078032828-Apr-14 2:54
memberMember 1078032828-Apr-14 2:54 
QuestionWant to get text from external application Pin
AshishMtech23-Jan-14 4:01
memberAshishMtech23-Jan-14 4:01 
GeneralGreat tutorial Pin
Member 98811144-Aug-13 6:51
memberMember 98811144-Aug-13 6:51 
QuestionIs it possible to read keystrokes using 'user32.dll'? Pin
jol33321-Mar-13 7:53
memberjol33321-Mar-13 7:53 
AnswerRe: Is it possible to read keystrokes using 'user32.dll'? Pin
Saurabh Singh Gangwar22-Mar-13 6:10
memberSaurabh Singh Gangwar22-Mar-13 6:10 
GeneralMy vote of 5 Pin
jol33321-Mar-13 7:49
memberjol33321-Mar-13 7:49 
GeneralRe: My vote of 5 Pin
Saurabh Singh Gangwar22-Mar-13 6:11
memberSaurabh Singh Gangwar22-Mar-13 6:11 
GeneralMy vote of 5 Pin
Reynaldots28-Nov-12 19:52
memberReynaldots28-Nov-12 19:52 
GeneralRe: My vote of 5 Pin
Saurabh Singh Gangwar22-Mar-13 6:12
memberSaurabh Singh Gangwar22-Mar-13 6:12 
QuestionYour work is very helpful. Pin
Ocean Boy24-May-12 9:31
memberOcean Boy24-May-12 9:31 
AnswerRe: Your work is very helpful. Pin
Saurabh Singh Gangwar4-Aug-12 9:46
memberSaurabh Singh Gangwar4-Aug-12 9:46 
QuestionChrome issue Pin
whatnextkenn5-Mar-12 8:53
memberwhatnextkenn5-Mar-12 8:53 
AnswerRe: Chrome issue Pin
Saurabh Singh Gangwar25-May-12 1:21
memberSaurabh Singh Gangwar25-May-12 1:21 
Yes, browsers and some apps like office 2007 are it's limitations...
QuestionMost challenging!! get caret position under WinWord when some text is selected Pin
Dallas Cao18-Dec-11 7:43
memberDallas Cao18-Dec-11 7:43 
GeneralMy vote of 5 Pin
Nimeshji11-Jan-11 2:47
memberNimeshji11-Jan-11 2:47 
QuestionIs there a VB Classic equivalent code? Pin
balajiallam11-Aug-10 15:58
memberbalajiallam11-Aug-10 15:58 
GeneralIt works on most but not all open windows Pin
mazrabul21-Jun-10 6:08
membermazrabul21-Jun-10 6:08 
GeneralRe: It works on most but not all open windows Pin
Saurabh Singh Gangwar8-Jul-10 21:39
memberSaurabh Singh Gangwar8-Jul-10 21:39 
GeneralGetting the word Pin
Gazatteer3412-Apr-10 23:12
memberGazatteer3412-Apr-10 23:12 
GeneralFrom what i've found about the api function GetCaretPos Pin
talavi8-Apr-10 3:02
membertalavi8-Apr-10 3:02 
GeneralRe: From what i've found about the api function GetCaretPos Pin
P.Gopalakrishna15-Jul-11 16:56
memberP.Gopalakrishna15-Jul-11 16:56 
QuestionIf you find support for browsers and any application? Pin
talavi8-Apr-10 2:59
membertalavi8-Apr-10 2:59 
AnswerRe: If you find support for browsers and any application? Pin
GRTR25-Mar-11 10:14
memberGRTR25-Mar-11 10:14 
GeneralThanks Pin
Member 457916711-Mar-10 18:17
memberMember 457916711-Mar-10 18:17 
GeneralUsing my own text content in the tooltip Pin
bmnot4-Feb-10 13:19
memberbmnot4-Feb-10 13:19 
AnswerRe: Using my own text content in the tooltip Pin
Saurabh Singh Gangwar3-Mar-10 21:29
memberSaurabh Singh Gangwar3-Mar-10 21:29 
GeneralBrowser Support Pin
avrankou29-Jan-10 19:45
memberavrankou29-Jan-10 19:45 
GeneralRe: Browser Support Pin
lydevoux4-Mar-10 18:30
memberlydevoux4-Mar-10 18:30 
GeneralGood Article Pin
satishnuni1-Jan-10 1:39
membersatishnuni1-Jan-10 1:39 
Questionhow to attach tooltip to the caret? Pin
Member 384027927-Dec-09 10:41
memberMember 384027927-Dec-09 10:41 
GeneralUsing this with AutoHotkey Pin
Ivo Roper8-Jul-09 16:28
memberIvo Roper8-Jul-09 16:28 
GeneralRe: Using this with AutoHotkey Pin
Gilbert Premo24-Sep-09 8:50
memberGilbert Premo24-Sep-09 8:50 
GeneralRe: Using this with AutoHotkey Pin
Ivo Roper24-Sep-09 15:41
memberIvo Roper24-Sep-09 15:41 
GeneralRe: Using this with AutoHotkey [modified] Pin
Gilbert Premo16-Jul-10 13:22
memberGilbert Premo16-Jul-10 13:22 
GeneralRe: Using this with AutoHotkey Pin
Ivo Roper16-Jul-10 13:48
memberIvo Roper16-Jul-10 13:48 
GeneralRe: Using this with AutoHotkey Pin
Gilbert Premo18-Jul-10 12:33
memberGilbert Premo18-Jul-10 12:33 
GeneralRe: Using this with AutoHotkey Pin
Ivo Roper18-Jul-10 14:03
memberIvo Roper18-Jul-10 14:03 
GeneralRe: Using this with AutoHotkey Pin
Gilbert Premo18-Jul-10 15:49
memberGilbert Premo18-Jul-10 15:49 
GeneralRe: Using this with AutoHotkey Pin
Ivo Roper18-Jul-10 16:18
memberIvo Roper18-Jul-10 16:18 
GeneralThanks a lot Saurabh for this article Pin
kkbajwa31-Mar-09 4:51
memberkkbajwa31-Mar-09 4:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150427.4 | Last Updated 30 Mar 2009
Article Copyright 2009 by Saurabh Singh Gangwar
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid