从另一个应用程序的文本框中获取文本和插入符号

时间:2018-10-01 13:50:54

标签: c# .net windows ui-automation

背景信息

我正在研究Windows语音转文本应用程序。

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

插入文本时,重要的一点是将可识别的文本设置为适合周围文本的格式,例如:

  • 标点后的大写字母
  • 标点符号不在后的小写首字母
  • 换行上的首字母大写
  • 标点后的
  • 空格

依此类推

问题

要能够设置文本格式,我需要 文本 插入符位置

目前,我一直在将UI AutomationNuGet PackageText Pattern一起使用。 这对于所有支持“文本模式”的文本框都适用,但是许多程序不支持“文本模式”。

策略问题:我应该使用UI Automation之外的其他方法吗?

我注意到我要支持的许多应用程序不支持文本模式,但是支持值模式或旧式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自动化获取给定文本框的插入符位置?

P.S。我知道这永远不会对所有应用程序都有效,但是如果它可以对大多数普通应用程序都适用,那就太好了。

1 个答案:

答案 0 :(得分:1)

您不需要ValuePattern,而需要IUIAutomationTextPattern2,它支持GetCaretRange

如果您需要退回MSAA,这会很麻烦(而且您根本无法获得插入符号周围的文字)。 MSAA只是没有UIAutomation具有的文本支持。如果您真的不能使用UIAutomation,那么您唯一的实际选择是使用Text Services Framework,该文档记录不充分,因此没有得到广泛实施。如果您需要文本服务框架,则可能要看看my blog,它已经有一段时间没有更新了。

对于MSAA插入符号,请先调用GetGUIThreadInfo。返回有关hwndCaret的数据,hwndFocus是当前包含插入符号的窗口。 (或者,如果hwndCaret为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(); } 。)使用这些窗口之一,您可以执行以下操作:

// route.js
actions: {
  reloadModel() {
    this.store.peekAll('my-model').forEach((r) => {
      this.store.unloadRecord(r);
    })
    this.refresh(); // to force a fresh load of data from API
  }
}