【问题标题】:How to get the word under the cursor in Windows?如何在Windows中获取光标下的单词?
【发布时间】:2023-12-28 12:11:01
【问题描述】:

我想创建一个应用程序来获取光标下的单词(不仅适用于文本字段),但我找不到如何做到这一点。使用 OCR 非常困难。我见过的唯一工作是 Deskperience 组件。他们支持“本地”方式,但我花了很多钱。现在我试图弄清楚这种“原生”方式是什么(也许是某种挂钩)。任何帮助将不胜感激。

编辑: 我找到了一种方法,但它只获取控件的整个文本。知道如何从整个文本中只获取光标下的单词吗?

【问题讨论】:

  • 如果您发布您发现的获取整个控件文本的方法,这可能是其他人弄清楚如何获取光标下内容的起点。

标签: c# windows winapi hook ocr


【解决方案1】:

在最新版本的 Windows 上,将信息从一个应用程序收集到另一个应用程序(当然,如果您不拥有目标应用程序)的推荐方法是使用 UI 自动化 技术。 *非常适合获取更多信息:Microsoft UI Automation

基本上,UI 自动化将使用所有必要的手段来收集可以收集的内容

这是一个小型控制台应用程序代码,它将监视其他应用程序的 UI。运行它并将鼠标移到不同的应用程序上。每个应用程序对各种“UI 自动化模式”都有不同的支持。例如,这里有 Value 模式和 Text 模式。

static void Main(string[] args)
{
    do
    {
        System.Drawing.Point mouse = System.Windows.Forms.Cursor.Position; // use Windows forms mouse code instead of WPF
        AutomationElement element = AutomationElement.FromPoint(new System.Windows.Point(mouse.X, mouse.Y));
        if (element == null)
        {
            // no element under mouse
            return;
        }

        Console.WriteLine("Element at position " + mouse + " is '" + element.Current.Name + "'");

        object pattern;
        // the "Value" pattern is supported by many application (including IE & FF)
        if (element.TryGetCurrentPattern(ValuePattern.Pattern, out pattern))
        {
            ValuePattern valuePattern = (ValuePattern)pattern;
            Console.WriteLine(" Value=" + valuePattern.Current.Value);
        }

        // the "Text" pattern is supported by some applications (including Notepad)and returns the current selection for example
        if (element.TryGetCurrentPattern(TextPattern.Pattern, out pattern))
        {
            TextPattern textPattern = (TextPattern)pattern;
            foreach(TextPatternRange range in textPattern.GetSelection())
            {
                Console.WriteLine(" SelectionRange=" + range.GetText(-1));
            }
        }
        Thread.Sleep(1000);
        Console.WriteLine(); Console.WriteLine();
    }
    while (true);
}

据我所知,Internet Explorer 和 Firefox 实际上支持 UI 自动化,但 Chrome 不支持。见此链接:When will Google Chrome be accessible?

现在,这只是你工作的开始:-),因为:

  • 大多数时候,所有这些都具有严重的安全隐患。使用此技术(或直接的 Windows 技术,例如 WindowFromPoint)将需要足够的权限才能这样做(例如成为管理员)。而且我认为 DExperience 没有办法克服这些限制,除非他们在计算机上安装内核驱动程序。

  • 某些应用程序不会向任何人公开任何内容,即使拥有适当的权限也是如此。例如,如果我正在编写一个银行应用程序,我不希望您窥探我的应用程序将显示的内容:-)。出于同样的原因,其他应用程序(例如带有 DRM 的 Outlook)不会公开任何内容。

  • 只有 UI 自动化文本模式支持才能提供比整个文本更多的信息(如单词)。唉,IE 和 FF 都不支持这种特定模式,即使它们在全球范围内支持 UI 自动化。

因此,如果这一切对您不起作用,您将不得不深入研究并使用 OCR 或形状识别技术。即便如此,在某些情况下您将根本无法执行此操作(因为安全权限)。

【讨论】:

  • 很好的例子,但它只能获取全文。有没有办法用文字来区分。也许以某种方式获得文本/单词的坐标?因为我需要一个光标位置来写东西。这在 Firefox 中也不起作用。
  • 感谢您发布工作代码。关于如何在 UI 自动化中执行此操作的示例并不多。感谢您为我节省了几个小时
  • 我已经实现了一种文本检测方法,它基于剪贴板监听。 github.com/osoykan/DynamicTranslator
  • @blez 通过 UI 自动化读取光标下的单词blogs.msdn.microsoft.com/oldnewthing/20150216-00/?p=44673
【解决方案2】:

如果您要“窥探”的应用程序正在自己绘制文本,这将是非常重要的。一种可能的解决方案是触发另一个应用程序通过使光标正下方的区域无效来绘制其窗口的一部分。

当其他应用程序绘制时,您将不得不拦截文本绘制调用。一种方法是在其他应用程序中注入代码,并拦截对绘制文本的 GDI 函数的调用。当您调试本机应用程序时,这就是 Visual Studio 实现断点的方式。要测试这个想法,您可以使用detours 之类的库(但这不是免费用于商业用途的)。

您还可以检查应用程序是否支持 Windows 中的一种可访问性 API,以便为盲人提供屏幕阅读器等功能。

提醒一句:我自己没有做过任何这些。

【讨论】:

  • detour 的免费版本(和延续)是 EasyHook (easyhook.codeplex.com)
  • 我已经尝试过了,我必须挂钩 TextOut api,但在全局级别(我认为)以获取按钮、菜单等中文本的坐标。
  • @blez:是的,没错。我从来没有打算暗示这很容易。
  • 当我尝试它时,它在我的 Win7 Ultimate 上导致了 BSOD。无论如何,感谢您的解决方案。
【解决方案3】:

如果应用不仅需要处理 .Net 应用,我将从导入函数开始 (P/Invoke):

稍后您可以遍历控件并尝试根据类型从内部获取文本。如果我有时间我会尝试发布这样的代码。

经过一些检查,看起来最好的方法(不幸的是也很难)是挂钩到 GDI 文本渲染some discussion

【讨论】:

  • 好的,即使我成功地从点得到孩子,我也不知道如何得到它的文本。我不确定所有子窗口的 GetWindowText 是否会成功。然后即使我得到文本如何得到光标下的单词。例如,Deskperience 组件可以从 Firefox 窗口中获取单词。所以画布是 Firefox 控件,GetWindowText 不能为它工作。
  • 我尝试使用 UI Spy,它似乎使用 ChildWindowFromPoint api。第一个问题是它不适用于 Firefox 和 Chrome。还有就是不知道怎么从全文中获取光标下的单词。
  • System.Windows.Automation API 也适用于非 .NET 应用程序;它建立在 COM 自动化 API (msdn.microsoft.com/en-us/library/ff486375%28v=VS.85%29.aspx) 之上,因此最终创建 win32 控件的任何东西都可以工作,以及其他没有自动化“提供程序”的小部件集(例如,IE 窗口, WPF等)
【解决方案4】:

我会附和帕特里克所说的,但我认为没有可靠的方法来做你想做的事。

您可能获得了窗口文本或类似的东西。但是,如果光标位于不使用窗口文本来存储其内容的窗口上怎么办? Windows 没有义务以特定方式存储其数据。

这最终将您指向字符识别,您可以在其中查看光标下的像素并尝试找出其中的单词。但这不仅非常重要,而且也不是万无一失的。如果单词的一部分因为伸出窗口而看不到怎么办?

这绝对不是小事。有几种方法可以解决它。但是没有可靠的方法适用于所有窗口。

【讨论】:

    【解决方案5】:

    有一个使用 OCR 获取文本的 sdk。它不是免费的,但与其他产品相比它相当便宜:http://www.screenocr.com/screen-ocr-library-sdk.htm 他们有一个提供相同功能的应用程序,因此您也可以尝试演示。

    【讨论】:

    • 请注意,此库不支持 ClearType,并且在您调用识别时会努力禁用它。因此,您必须在每次识别调用之前/之后保存/恢复您的 ClearType 设置,如果应用程序忽略系统范围的 ClearType 设置并始终应用 ClearType(如 Chrome 和 IE11),它将无法识别任何内容。跨度>
    【解决方案6】:

    要实现这一目标,您需要多管齐下。

    UIA 确实适用于许多应用程序,但您需要尝试查看文本返回的位置。它可能在元素、值或范围中。即使跨办公应用程序也没有一致性。

    如果 UIA 失败,则枚举运行对象表 (ROT) 并检索指向在 ROT 中注册的各种应用程序的 COM 指针。然后,您可以将这些指针转换为基础办公室类型:
    例如:

    enumerate ROT  - then
     wb = (Excel._Workbook)enumerator.Value;
    string strText = wb.Application.ActiveCell.Text.ToString();
    

    如果以上两种方法都失败了,那么请使用 MODI (Microsoft Office Document Imaging 12.0 Type Library) 中的免费 OCR 系统

    【讨论】:

      最近更新 更多