首页 > 解决方案 > 从另一个应用程序的文本框中获取文本和插入符号

问题描述

背景资料

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

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

插入文本时,识别文本的格式必须适合周围的文本,例如:

等等

问题

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

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

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

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

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

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 自动化获取给定文本框的插入符号位置?

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

标签: c#.netwindowsui-automation

解决方案


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

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

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

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

推荐阅读