【问题标题】:Get text and caret from a textbox in another application从另一个应用程序的文本框中获取文本和插入符号
【发布时间】:2019-03-06 15:42:13
【问题描述】:

背景信息

我正在开发一个 Windows Speech-To-Text 应用程序。

识别语音后,应将文本插入当前具有键盘焦点的文本框中(Think Word/Firefox/其他应用程序)。 要插入我当前使用的文本InputSimulatorPlus

在插入文本时,重要的是要对识别的文本进行格式化以适应周围的文本,例如:

  • 标点符号后的大写字母
  • 第一个字母不在标点符号之后时小写
  • 新行首字母大写
  • 标点符号后的空格

等等

问题

为了能够格式化文本,我需要文本插入符号位置

目前我一直在使用UI Automation NuGet PackageText Pattern。 这适用于所有支持文本模式的文本框,但很多程序不支持文本模式。

策略问题:我应该使用 UI 自动化以外的其他方法吗?

我注意到很多我想支持的应用程序不支持文本模式,但支持值模式或传统 IAccessible 模式(Microsoft Active Accessibility)。

我一直在研究使用Value Pattern 并且可以获取文本框的文本,但不是插入符号的位置。

using System.Windows.Automation;
using System.Windows.Automation.Text;
...

AutomationElement automationElement = AutomationElement.FocusedElement;
var elements = automationElement.FindAll(TreeScope.Element,
    new AndCondition(
        new PropertyCondition(AutomationElement.HasKeyboardFocusProperty, true),
        new PropertyCondition(AutomationElement.IsValuePatternAvailableProperty, true)));
foreach (AutomationElement element in elements)
{
    if (element.GetCurrentPattern(ValuePattern.Pattern) is ValuePattern valuePattern)
    {
        var text = valuePattern.Current.Value;
        var caret = ? //How to get caret position?
        Console.WriteLine($"Caret: {caret}, Text: {text}");
        return (text,caret);
    }
}

我也一直在研究使用Legacy IAccessible Pattern 并且可以获取文本框的文本,但不是插入符号的位置。

using System.Windows.Automation;
using System.Windows.Automation.Text;
...

AutomationElement automationElement = AutomationElement.FocusedElement;
var elements = automationElement.FindAll(TreeScope.Element,
    new AndCondition(
        new PropertyCondition(AutomationElement.HasKeyboardFocusProperty, true),
        new PropertyCondition(AutomationElement.IsLegacyIAccessiblePatternAvailableProperty, true)));
foreach (AutomationElement element in elements)
{
    if (element.GetCurrentPattern(LegacyIAccessiblePattern.Pattern) is LegacyIAccessiblePattern legazyAccessiblePattern)
    {
        var text = legazyAccessiblePattern.Current.Value;
        var caret = ? //How to get caret position?
        Console.WriteLine($"Caret: {caret}, Text: {text}");
        return (text,caret);
    }
}

主要问题:如何使用 UI 自动化获取给定文本框的插入符号位置?

附:我知道这永远不会适用于所有应用程序,但如果它可以适用于大多数普通应用程序,那就太棒了。

【问题讨论】:

    标签: c# .net windows ui-automation


    【解决方案1】:

    你不需要ValuePattern,你需要IUIAutomationTextPattern2,它支持GetCaretRange

    如果您需要回退到 MSAA,那就更麻烦了(而且您根本无法获取插入符号周围的文本)。 MSAA 没有像 UIAutomation 那样的文本支持。如果您真的真的不能使用 UIAutomation,那么您唯一真正的选择是使用 Text Services Framework,它的文档很少,因此没有得到广泛实施。如果你需要文本服务框架,你可能想看看my blog,它已经很长时间没有更新了。

    对于 MSAA 插入符号,首先调用 GetGUIThreadInfo。这将返回有关 hwndCaret 的数据,这是当前包含插入符号的窗口。 (或者,如果 hwndCaret 为 NULL,您可以尝试使用 hwndFocus。)使用其中一个窗口,您可以执行以下操作:

    IAccessible *pAccCaret = NULL;
    
    VARIANT varCaret;
    varCaret.vt = VT_I4;
    varCaret.lVal = CHILDID_SELF;
    
    if (SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_CARET, IID_IAccessible, (void **)&pAccCaret)))
    {
        hr = pAccCaret->accLocation( &rcCaret.left, &rcCaret.top, &rcCaret.right, &rcCaret.bottom, varCaret);
    
        pAccCaret->Release();
    }
    

    【讨论】:

    • 但这给了我屏幕空间中的插入符号位置,而不是文本中的插入符号位置。我看不到如何将插入符号屏幕空间位置(X、Y、宽度、高度)转换为字符串中的插入符号索引。
    • 不幸的是,这可能是您使用 MSAA 可以获得的最佳效果。 MSAA 中的文本支持实际上是不存在的。 UIA 在这方面要好得多。
    猜你喜欢
    • 2011-05-31
    • 1970-01-01
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多