简体   繁体   English

如何获取当前关注的 window 的选定文本?

[英]How to get selected text of currently focused window?

So, I'm trying to make an application that does the following:所以,我正在尝试制作一个执行以下操作的应用程序:

  1. Listens for a keyboard shortcut (using this library )监听键盘快捷键(使用这个库
  2. When the shortcut is hit, retrieves the contents of the currently selected text, and当快捷方式被点击时,检索当前选定文本的内容,然后
  3. Processes the text处理文本

I've used the method shared by the latest edit of this answer ( this method ) to attach my application to the focused control, but the GetText function in that method doesn't do what I need.我已使用此答案的最新编辑共享的方法( 此方法)将我的应用程序附加到焦点控件,但该方法中的GetText function 不能满足我的需要。

I've seen 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.我也看到了这个答案,但这仅提供了有关如何在双击时获得焦点 window 的详细步骤,这不是我需要的。 It did link to this question which led me to try the WM_KEYDOWN method (shown below), but that didn't work either.它确实链接到这个问题,这导致我尝试WM_KEYDOWN方法(如下所示),但这也不起作用。

So far I've tried these GetText methods (all within the context of that MSDN post):到目前为止,我已经尝试了这些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;
}

(I don't care about preserving the clipboard yet.) (我还不关心保留剪贴板。)

How can I consistently get the selected text of the currently focused application?如何始终如一地获取当前关注的应用程序的选定文本? Bonus points for not tampering with the clipboard, but using it is OK too.不篡改剪贴板的奖励积分,但使用它也可以。

Ever since Vista, apps should refrain from using p-invoke or WM_GETTEXT to snoop on other apps due to potential blocks from Windows Elevated Processes. 从Vista开始,由于Windows高程进程的潜在阻止,应用程序应避免使用p调用或WM_GETTEXT监听其他应用程序。 Instead consider using Microsoft UI Automation . 而是考虑使用Microsoft UI Automation Though arguably a testing framework, it is also useful as a means to remotely interact with another GUI application. 尽管可以说是一个测试框架,但它也可以用作与另一个GUI应用程序进行远程交互的方式。

MSDN: MSDN:

Microsoft UI Automation is the new accessibility framework for Microsoft Windows. Microsoft UI自动化是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). 它通过提供对有关用户界面(UI)信息的编程访问来满足辅助技术产品和自动化测试框架的需求。 In addition, UI Automation enables control and application developers to make their products accessible. 此外,UI自动化使控件和应用程序开发人员可以访问其产品。

The following code will look for the running process Notepad and grab any text selection. 以下代码将查找正在运行的进程记事本,并抓住所有文本选择。 Ensure you run notepad beforehand , enter in some text and select a word or two. 确保事先运行记事本 ,输入一些文本,然后选择一个或两个单词。

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

EDIT: 编辑:

How can I consistently get the selected text of the currently focused application? 如何始终如一地获取当前关注的应用程序的选定文本?

Now in your case to work from focused window, instead of: 现在,从您关注的窗口开始工作,而不是:

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

...perform a: ...执行以下操作:

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

...where GetForegroundWindow is defined as: ...其中GetForegroundWindow定义为:

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

See also 也可以看看

We can also simulate copy shortcut (press Ctrl + C) And after that read clipboard我们还可以模拟复制快捷方式(按Ctrl + C)然后读取剪贴板

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM