如何获取当前焦点 window 的选定文本?

How to get selected text of currently focused window?

所以,我正在尝试制作一个执行以下操作的应用程序:

  1. 侦听键盘快捷键(使用 this library
  2. 点击快捷方式时,获取当前选中文本的内容,
  3. 处理文本

我使用了 this answer (this method) 的最新编辑共享的方法将我的应用程序附加到焦点控件,但是该方法中的 GetText 函数无法满足我的需要.

我看到了 this answer as well, but that only gives detailed steps as to how to get the focused window on double click, which is not what I need. It did link to this question 这让我尝试了 WM_KEYDOWN 方法(如下所示),但也没有用。

到目前为止,我已经尝试了这些 GetText 方法(都在该 MSDN post 的上下文中):

string GetText(IntPtr handle)
{
    // works in Notepad, but not Chrome
    SendMessageW(handle, WM_COPY, 0, 0);
    string w = Clipboard.GetText();
    return w;

    // works in every app, but in Notepad gets the complete contents
    // and in Chrome gets the window title
    int maxLength = 160;
    IntPtr buffer = Marshal.AllocHGlobal((maxLength + 1) * 2);
    SendMessageW(handle, WM_GETTEXT, maxLength, buffer);
    string w = Marshal.PtrToStringUni(buffer);
    Marshal.FreeHGlobal(buffer);
    return w;

    // I would have thought these would work, but
    // they don't do anything for some reason. They
    // all simulate a Ctrl+C.

    SendKeys.SendWait("^c");
    // or
    // this is from the same library that listens for the keyboard shortcut
    KeyboardSimulator.SimulateStandardShortcut(StandardShortcut.Copy);
    // or
    SendMessageW(handle, WM_KEYDOWN, (ushort)Keys.LControlKey, 0);
    SendMessageW(handle, WM_KEYDOWN, (ushort)Keys.C, 0);
    SendMessageW(handle, WM_KEYUP, (ushort)Keys.C, 0);
    SendMessageW(handle, WM_KEYUP, (ushort)Keys.LControlKey, 0);
    // after any of those
    string w = Clipboard.GetText();
    return w;
}

(我还不关心是否保留剪贴板。)

如何才能始终如一地获取当前焦点应用程序的选定文本?不篡改剪贴板的奖励积分,但使用它也可以。

自 Vista 以来,应用程序应避免使用 p-invoke 或 WM_GETTEXT 窥探其他应用程序,因为 Windows 提升的进程可能会阻止。相反,请考虑使用 Microsoft UI Automation。虽然可以说是一个测试框架,但它也可用作与另一个 GUI 应用程序进行远程交互的一种方式。

MSDN:

Microsoft UI Automation is the new accessibility framework for Microsoft Windows. It addresses the needs of assistive technology products and automated test frameworks by providing programmatic access to information about the user interface (UI). In addition, UI Automation enables control and application developers to make their products accessible.

以下代码将查找 运行ning 进程 Notepad 并抓取任何文本 selection。 确保你事先运行记事本,输入一些文本和select一两个词。

using System;
using System.Diagnostics;
using System.Linq;
using System.Windows.Automation;

namespace UiaTest
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var p = Process.GetProcessesByName("notepad").FirstOrDefault();       
            var root = AutomationElement.FromHandle(p.MainWindowHandle);

            var documentControl = new                                 
                    PropertyCondition(AutomationElement.ControlTypeProperty, 
                                      ControlType.Document);

            var textPatternAvailable = new PropertyCondition(AutomationElement.IsTextPatternAvailableProperty, true);

            var findControl = new AndCondition(documentControl, textPatternAvailable);

            var targetDocument = root.FindFirst(TreeScope.Descendants, findControl);    
            var textPattern = targetDocument.GetCurrentPattern(TextPattern.Pattern) as TextPattern;

            foreach (var selection in textPattern.GetSelection())
            {
                Console.WriteLine($"Selection: \"{selection.GetText(255)}\"");
            }    
        }
    }
}

编辑:

How can I consistently get the selected text of the currently focused application?

现在,在您的情况下,您可以专注于 window,而不是:

var p = Process.GetProcessesByName("notepad").FirstOrDefault();     

...执行一个:

IntPtr handle = GetForegroundWindow();
var root = AutomationElement.FromHandle(handle);

...其中 GetForegroundWindow 定义为:

[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();

另见