在Windows操作系统中,是否有可能编写一个应用程序,在另一个窗口应用程序中选择文本时得到通知?

4
我想知道是否有可能编写一个程序来监控我的文本选择。其中一个可能的用途是编写一个与编辑器/IDE无关的代码格式化程序:
  1. 启动应用程序/服务P,并以某种方式挂接到Windows,使得它在任何窗口中选择文本时都会收到通知。
  2. 启动另一个应用程序A。
  3. 用户在A中选择文本。
  4. P被通知所选的文本内容。
--> 我已经达到这个程度就很满足了...

你真的想在选择时收到通知吗?还是只要知道什么时候有东西被复制到剪贴板就足够了? - Bryan Oakley
1
这不是完全相同的东西,但可能很接近。您可以监视数据何时进入剪贴板。这对用户来说是额外的一步,但也许都一样...请参见此链接:https://dev59.com/OXRB5IYBdhLWcg3wcm6d - Brad
+1 喜欢这个问题,但我认为如果应用程序已经启动,那么它应该更有可能。 - Omar
3个回答

6

如果没有每个控件/应用程序的具体知识,这是不可能的,因为它们都可以处理/处理它的方式不同。


3
这段代码可以帮助你获取焦点窗口中的聚焦控件文本,希望对你有所帮助:
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
我认为你不能注册任何类型的钩子。我认为你需要不断轮询“聚焦”或选定的窗口。
您可以使用Windows自动化API来完成此操作,据我所知,它已经取代了较旧的Accesibility API: http://msdn.microsoft.com/en-us/library/ms747327.aspx 我曾使用过此API来自动化GUI测试。我有点生疏,所以不确定,但我相信您可以将其用于您正在尝试做的事情。基本上,该API允许您遍历以桌面为根的自动化对象树。每个自动化元素往往是某种窗口控件,不同的控件实现不同的模式。您还可以获取鼠标指针下方的元素,并且可能可以直接到达当前选择/聚焦的元素。
之后,我注意到TextPattern类例如具有一个GetSelection()方法,其文档说明为“检索与当前文本选择或选择相关联的不连续文本范围集合。”我打赌文本框的自动化对象实现了TextPattern。 http://msdn.microsoft.com/en-us/library/system.windows.automation.textpattern.aspx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接