Is it possible to write a Windows application that receives a notification when text is selected in another Windows application?

I am curious if it is possible to write a program that tracks my text selection. One possible use case would be to write an agnostic editor / IDE code formatter:

  • The Application / Service, P, starts and somehow connects to the windows, so that it receives a notification when the text is selected in any window.
  • Another application A starts.
  • The user selects the text in A.
  • P is notified with the selected text.

-> I would be happy to get this far ...

+4
source share
3 answers

This is not possible without the special knowledge of each control / application that will be used, since all of them can handle / process it differently.

+6
source

I do not think you can register any kind of hook. I think you need to constantly poll the "focused" or selected window.

Perhaps you can use the Windows Automation API for this, which, as far as I know, has exceeded the previous availability API: http://msdn.microsoft.com/en-us/library/ms747327.aspx

I used this API to automate GUI tests. I'm a little rusty with it, so I don’t know for sure, but I’m pretty sure that you can use it for what you are trying to do. Basically, the API allows you to move the tree of automation objects using root on the desktop. Each automation element is typically a Windows control, and different controls implement different patterns. You can also get the elements under the mouse cursor, and perhaps you can go directly to the selected / focused element.

After that, I notice that the TextPattern class, for example, has a GetSelection () method, which is documented as "Retrieves a collection of disjoint text ranges associated with the current text selection or selection." I am sure that the automation object for text fields implements TextPattern. http://msdn.microsoft.com/en-us/library/system.windows.automation.textpattern.aspx

+3
source

This code will help you get focused control text in a focused window, I hope this helps:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace TextFocusedns { public partial class TextFocusedFrm : Form { #region APIs [DllImport("user32.dll")] public static extern bool GetCursorPos(out Point pt); [DllImport("user32.dll", EntryPoint = "WindowFromPoint", CharSet = CharSet.Auto, ExactSpelling = true)] public static extern IntPtr WindowFromPoint(Point pt); [DllImport("user32.dll", EntryPoint = "SendMessageW")] public static extern int SendMessageW([InAttribute] System.IntPtr hWnd, int Msg, int wParam, IntPtr lParam); public const int WM_GETTEXT = 13; [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] internal static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] internal static extern IntPtr GetFocus(); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] internal static extern int GetWindowThreadProcessId(int handle, out int processId); [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] internal static extern int AttachThreadInput(int idAttach, int idAttachTo, bool fAttach); [DllImport("kernel32.dll")] internal static extern int GetCurrentThreadId(); [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)] internal static extern int GetWindowText(IntPtr hWnd, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpString, int nMaxCount); #endregion private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer() { Interval = 100, Enabled = true }; public TextFocusedFrm() { InitializeComponent(); } private void TextFocusedFrm_Load(object sender, EventArgs e) { timer.Tick += new EventHandler(timer_Tick); timer.Start(); } void timer_Tick(object sender, EventArgs e) { try { MultiLineTextBox.Text = GetTextFromFocusedControl(); } catch (Exception exp) { MultiLineTextBox.Text += exp.Message; } } //Get the text of the focused control private string GetTextFromFocusedControl() { try { int activeWinPtr = GetForegroundWindow().ToInt32(); int activeThreadId = 0, processId; activeThreadId = GetWindowThreadProcessId(activeWinPtr, out processId); int currentThreadId = GetCurrentThreadId(); if (activeThreadId != currentThreadId) AttachThreadInput(activeThreadId, currentThreadId, true); IntPtr activeCtrlId = GetFocus(); return GetText(activeCtrlId); } catch (Exception exp) { return exp.Message; } } //Get the text of the control at the mouse position private string GetTextFromControlAtMousePosition() { try { Point p; if (GetCursorPos(out p)) { IntPtr ptr = WindowFromPoint(p); if (ptr != IntPtr.Zero) { return GetText(ptr); } } return ""; } catch (Exception exp) { return exp.Message; } } //Get the text of a control with its handle private string GetText(IntPtr handle) { int maxLength = 512; IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2); SendMessageW(handle, WM_GETTEXT, maxLength, buffer); string w = Marshal.PtrToStringUni(buffer); Marshal.FreeHGlobal(buffer); return w; } } } 
+3
source

Source: https://habr.com/ru/post/1400252/