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

时间:2018-07-27 11:31:03

标签: c# focus selection

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

  1. 收听键盘快捷键(使用this library
  2. 按下快捷键后,将检索当前所选文本的内容,并且
  3. 处理文本

我使用了this answerthis method)的最新编辑所共享的方法,将我的应用程序附加到焦点控件上,但是该方法中的GetText函数没有做我需要的事。

我也见过this answer,但这仅给出了有关如何在双击时获得焦点窗口的详细步骤,这不是我所需要的。它确实链接到this question,这使我尝试了WM_KEYDOWN方法(如下所示),但这也不起作用。

到目前为止,我已经尝试了以下GetText方法(均在该MSDN帖子的上下文中):

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;
}

(我不在乎保存剪贴板。)

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

1 个答案:

答案 0 :(得分:2)

自Vista以来,由于Windows高程进程的潜在阻止,应用程序应避免使用p调用或WM_GETTEXT监听其他应用程序。而是考虑使用 Microsoft UI Automation 。尽管可以说是一个测试框架,但它也可以作为与另一个GUI应用程序进行远程交互的一种方式。

MSDN:

  

Microsoft UI Automation是Microsoft Windows的新辅助功能框架。它通过提供对有关用户界面(UI)信息的编程访问来满足辅助技术产品和自动化测试框架的需求。此外,UI自动化使控件和应用程序开发人员可以访问其产品。

以下代码将查找正在运行的进程 Notepad ,并抓住所有文本选择。 确保您事先运行了记事本,输入一些文字并选择一个或两个单词。

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)}\"");
            }    
        }
    }
}

编辑:

  

如何始终获取当前重点应用程序的选定文本?

现在,您可以从焦点窗口开始工作了,而不是:

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

...执行a:

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

...其中GetForegroundWindow定义为:

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

另请参见