c# - Is it possible to get caret position in Word to update faster? -


i'm using low level keyboard hook , guithreadinfo caret position in windows applications on every keyup.

works applications - except word. reason word updates position of caret after arbitrary delay (meaning position off 1 or more characters).

i can correct position if wait couple hundred milliseconds (thread.sleep(400) example) before fetching position - usable solution application i'm working on.

any way can correct caret position faster? either forcing word render caret, using word specific function, subscribing word event or entirely different?

keyboard hook class:

using system; using system.collections.generic; using system.text; using system.runtime.interopservices; using system.windows.forms; using system.componentmodel;   namespace cs_test {     /// <summary>     /// class manages global low level keyboard hook     /// </summary>     public class globalkeyboardhook     {         #region constant, structure , delegate definitions         /// <summary>         /// defines callback type hook         /// </summary>         public delegate int keyboardhookproc(int code, int wparam, ref keyboardhookstruct lparam);          private static keyboardhookproc _callbackdelegate;          public struct keyboardhookstruct // c++ kbdllhookstruct          {             public int vkcode;             public int scancode;             public int flags;             public int time;             public int dwextrainfo;         }          const int wh_keyboard = 2;         const int wh_keyboard_ll = 13;         const int wm_keydown = 0x100;         const int wm_keyup = 0x101;         const int wm_syskeydown = 0x104;         const int wm_syskeyup = 0x105;         const int llkhf_injected = 0x10;         #endregion          #region instance variables         /// <summary>         /// collections of keys watch         /// </summary>         public list<keys> hookedkeys = new list<keys>();         /// <summary>         /// handle hook, need unhook , call next hook         /// </summary>         intptr hhook = intptr.zero;          private bool _ignoreinjected = false;         private bool _shiftheld = false;         private bool _ctrlheld = false;         private bool _altheld = false;          #endregion          #region events         /// <summary>         /// occurs when 1 of hooked keys pressed         /// </summary>         public event keyeventhandler keydown;         /// <summary>         /// occurs when 1 of hooked keys released         /// </summary>         public event keyeventhandler keyup;         #endregion          #region constructors , destructors         /// <summary>         /// initializes new instance of <see cref="globalkeyboardhook"/> class , installs keyboard hook.         /// </summary>         public globalkeyboardhook(bool ignoreinjected)         {             _ignoreinjected = ignoreinjected;             hook();         }          /// <summary>         /// releases unmanaged resources , performs other cleanup operations before         /// <see cref="globalkeyboardhook"/> reclaimed garbage collection , uninstalls keyboard hook.         /// </summary>         ~globalkeyboardhook()         {             unhook();         }         #endregion          #region public methods         /// <summary>         /// installs global hook         /// </summary>         ///           private void hook()         {             _callbackdelegate = new keyboardhookproc(hookproc);             //intptr hinstance = loadlibrary("user32");             //hhook = setwindowshookex(wh_keyboard_ll, callbackdelegate, hinstance, 0);             hhook = setwindowshookex(wh_keyboard_ll, _callbackdelegate, intptr.zero, 0);             if (hhook == intptr.zero) throw new win32exception();         }          /// <summary>         /// uninstalls global hook         /// </summary>         public bool unhook()         {             try             {                 bool ok = unhookwindowshookex(hhook);                 if (!ok) throw new win32exception();                 _callbackdelegate = null;                 return true;             }             catch (exception) { }              return false;         }          /// <summary>         /// callback keyboard hook         /// </summary>         /// <param name="code">the hook code, if isn't >= 0, function shouldn't anyting</param>         /// <param name="wparam">the event type</param>         /// <param name="lparam">the keyhook event information</param>         /// <returns></returns>         ///          public int hookproc(int code, int wparam, ref keyboardhookstruct lparam)         {             if (code >= 0)             {                 // continue if injected keys allowed or key not injected                 if (!_ignoreinjected || (lparam.flags & llkhf_injected) == 0)                 {                     // determine modifiers                     if (lparam.vkcode == 160 || lparam.vkcode == 161) // lshiftkey / rshiftkey                     {                         _shiftheld = (wparam == wm_keydown || wparam == wm_syskeydown);                     }                     else if (lparam.vkcode == 162 || lparam.vkcode == 163) // lcontrolkey / rcontrolkey                     {                         _ctrlheld = (wparam == wm_keydown || wparam == wm_syskeydown);                     }                     else if (lparam.vkcode == 164 || lparam.vkcode == 165) // lmenu / rmenu aka lalt / ralt                     {                         // can determine if alt held checking if bit 5 (0-indexed) of lparam.flags set                         _altheld = (wparam == wm_keydown || wparam == wm_syskeydown);                     }                      keys key = (keys)lparam.vkcode;                     if (hookedkeys.contains(key))                     {                         keys keymodified = key;                         if (_shiftheld) keymodified |= keys.shift;                         if (_ctrlheld) keymodified |= keys.control;                         if (_altheld) keymodified |= keys.alt;                         keyeventargs kea = new keyeventargs(keymodified);                          // call keydown event handlers                         if ((wparam == wm_keydown || wparam == wm_syskeydown) && (keydown != null))                         {                             keydown(this, kea);                         }                          // call keyup event handlers                         else if ((wparam == wm_keyup || wparam == wm_syskeyup) && (keyup != null))                         {                             keyup(this, kea);                         }                          // check if of handlers have handled event                         if (kea.handled)                         {                             return 1;                         }                     }                 }             }              try             {                 // can crash if windows has decided unhook proc during function                 return callnexthookex(hhook, code, wparam, ref lparam);             }             catch (exception ex)             {                 console.writeline("globalkeyboardhook exception: " + ex.message);                 return 0;             }          }         #endregion          #region dll imports         /// <summary>         /// sets windows hook, desired event, 1 of hinstance or threadid must non-null         /// </summary>         /// <param name="idhook">the id of event want hook</param>         /// <param name="callback">the callback.</param>         /// <param name="hinstance">the handle want attach event to, can null</param>         /// <param name="threadid">the thread want attach event to, can null</param>         /// <returns>a handle desired hook</returns>         [dllimport("user32.dll")]         static extern intptr setwindowshookex(int idhook, keyboardhookproc callback, intptr hinstance, uint threadid);          /// <summary>         /// unhooks windows hook.         /// </summary>         /// <param name="hinstance">the hook handle returned setwindowshookex</param>         /// <returns>true if successful, false otherwise</returns>         [dllimport("user32.dll")]         static extern bool unhookwindowshookex(intptr hinstance);          /// <summary>         /// calls next hook.         /// </summary>         /// <param name="idhook">the hook id</param>         /// <param name="ncode">the hook code</param>         /// <param name="wparam">the wparam.</param>         /// <param name="lparam">the lparam.</param>         /// <returns></returns>         [dllimport("user32.dll")]         static extern int callnexthookex(intptr idhook, int ncode, int wparam, ref keyboardhookstruct lparam);          /// <summary>         /// loads library.         /// </summary>         /// <param name="lpfilename">name of library</param>         /// <returns>a handle library</returns>         [dllimport("kernel32.dll")]         static extern intptr loadlibrary(string lpfilename);         #endregion     }      public class keyboardhooklogeventargs : eventargs     {         public string message;         public keyboardhooklogeventargs(string message)         {             message = message;         }     } } 

the caret helper class:

using system; using system.collections.generic; using system.linq; using system.text; using system.windows; using system.runtime.interopservices;  namespace cs_test {     public class caretinfo     {         public double width { get; private set; }         public double height { get; private set; }         public double left { get; private set; }         public double top { get; private set; }          public caretinfo(double width, double height, double left, double top)         {             width = width;             height = height;             left = left;             top = top;         }     }      public class carethelper     {          public static caretinfo getcaretposition()         {             // gui info containing caret poisition             var guiinfo = new guithreadinfo();             guiinfo.cbsize = (uint)marshal.sizeof(guiinfo);             getguithreadinfo(0, out guiinfo);              // convert caret position position relative top left corner of current editor window - seems not neccessary             /*var caretinfo = new system.windows.point();             caretinfo.x = guiinfo.rccaret.left;             caretinfo.y = guiinfo.rccaret.top;             clienttoscreen(guiinfo.hwndcaret, out caretinfo);*/              // width/height             double width = guiinfo.rccaret.right - guiinfo.rccaret.left;             double height = guiinfo.rccaret.bottom - guiinfo.rccaret.top;              // left/top relative screen             rect rect;             getwindowrect(guiinfo.hwndfocus, out rect);              double left = guiinfo.rccaret.left + rect.left + 2; // seems 2 pixels off             double top = guiinfo.rccaret.top + rect.top + 2; // seems 2 pixels off              return new caretinfo(width, height, left, top);         }          [dllimport("user32.dll", entrypoint = "getguithreadinfo")]         public static extern bool getguithreadinfo(uint tid, out guithreadinfo threadinfo);          [dllimport("user32.dll")]         public static extern bool clienttoscreen(intptr hwnd, out point position);          [dllimport("user32.dll")]         [return: marshalas(unmanagedtype.bool)]         public static extern bool getwindowrect(intptr handle, out rect lprect);          [dllimport("user32.dll")]         [return: marshalas(unmanagedtype.bool)]         private static extern bool getclientrect(intptr hwnd, ref rect rect);          [structlayout(layoutkind.sequential)]         public struct guithreadinfo         {             public uint cbsize;             public uint flags;             public intptr hwndactive;             public intptr hwndfocus;             public intptr hwndcapture;             public intptr hwndmenuowner;             public intptr hwndmovesize;             public intptr hwndcaret;             public rect rccaret;         };          [structlayout(layoutkind.sequential)]         public struct rect         {             public int left;             public int top;             public int right;             public int bottom;         }     } } 

wpf mainwindow:

using system; using system.collections.generic; using system.linq; using system.text; using system.threading.tasks; using system.windows; using system.windows.controls; using system.windows.data; using system.windows.documents; using system.windows.forms; using system.windows.input; using system.windows.media; using system.windows.media.imaging; using system.windows.navigation; using system.windows.shapes;  namespace cs_test {     /// <summary>     /// interaction logic mainwindow.xaml     /// </summary>     public partial class mainwindow : window     {         public mainwindow()         {             initializecomponent();              globalkeyboardhook hook = new globalkeyboardhook(true);             foreach (keys key in enum.getvalues(typeof(keys))) // add keys keyboardhook should listen             {                 if (key != keys.control && key != keys.controlkey)                 {                     hook.hookedkeys.add(key);                 }             }             hook.keyup += hook_keyup;         }          void hook_keyup(object sender, system.windows.forms.keyeventargs e)         {             caretinfo info = carethelper.getcaretposition();             console.writeline(info.left + ", " + info.top);         }     } } 

try typing 3 letters in quick succession - should yield log same coordinates 3 keyups.


Comments

Popular posts from this blog

How has firefox/gecko HTML+CSS rendering changed in version 38? -

javascript - Complex json ng-repeat -

jquery - Cloning of rows and columns from the old table into the new with colSpan and rowSpan -