【问题标题】:How to find the blinking cursor location of any active application?如何找到任何活动应用程序的闪烁光标位置?
【发布时间】:2014-09-06 16:25:51
【问题描述】:

我正在为 Mac OS 开发一个应用程序,我想找到当前应用程序的文本光标(插入符号导航)的位置? 到目前为止,我已经让它要求访问权限,我也可以监视 keyEvents,但是如何找到闪烁的光标位置?

(我不是在寻找鼠标光标位置,我要text cursor / caret navigation

【问题讨论】:

  • '闪烁光标'?您的意思是具有 firstResponder 的元素(NSTextField f.e.?)
  • @JasperPol 当您在计算机中输入时,会有一条小竖线闪烁,以显示您正在输入的位置。几乎在涉及打字的任何地方都可以看到这种情况。
  • 是的,它叫 firstResponder

标签: objective-c macos cocoa


【解决方案1】:

您将需要使用辅助功能 API 来执行此操作。 这是很多丑陋的代码,它可能并不总是有效,这取决于视图层次结构和这些应用程序视图中的可访问性支持程度。 非 Cocoa 应用程序可能会出现问题并且无法正常工作。 使用 WebKit 进行渲染的视图也带来了整个 html 可访问性挑战! :)

我从制作 Dash 的 Bogdan Popescu 那里得到了这个 sn-p。 不要直接复制和粘贴此代码。 研究它,看看 API 文档对每个函数和类型的看法,然后慢慢地构建一些东西。 理解和使用 AX API 需要花费大量时间。以通用方式很好地使用它们需要更长的时间。 它是 Core Foundation 风格的 C,与您在 Cocoa Objective-C 中可能习惯的有很大不同。

CFTypeRef system = nil;
system = AXUIElementCreateSystemWide();
CFTypeRef application = nil;
CFTypeRef focusedElement = nil;
CFRange cfrange;
AXValueRef rangeValue = nil;
// Find the currently focused application
if(AXUIElementCopyAttributeValue(system, kAXFocusedApplicationAttribute, &application) == kAXErrorSuccess)
{
    // Find the currently focused UI Element
    if(AXUIElementCopyAttributeValue(application, kAXFocusedUIElementAttribute, &focusedElement) == kAXErrorSuccess)
    {
        // Get the range attribute of the selected text (i.e. the cursor position)
        if(AXUIElementCopyAttributeValue(focusedElement, kAXSelectedTextRangeAttribute, (CFTypeRef *)&rangeValue) == kAXErrorSuccess)
        {
            // Get the actual range from the range attribute
            if(AXValueGetValue(rangeValue, kAXValueCFRangeType, (void *)&cfrange))
            {
                CFTypeRef bounds = nil;
                textRect = NSZeroRect;
                if(AXUIElementCopyParameterizedAttributeValue(focusedElement, kAXBoundsForRangeParameterizedAttribute, rangeValue, (CFTypeRef *)&bounds) == kAXErrorSuccess)
                {
                    CGRect screenRect;
                    AXValueGetValue(bounds, kAXValueCGRectType, &screenRect);
                    if(bounds)
                    {
                        textRect = [DHAbbreviationManager cocoaRectFromCarbonScreenRect:screenRect];
                        CFRelease(bounds);
                    }
                }
            }
            if(rangeValue)
            {
                CFRelease(rangeValue);
            }
        }
    }
    if(focusedElement)
    {
        CFRelease(focusedElement);
    }
}
if(application)
{
    CFRelease(application);
}
if(system)
{
    CFRelease(system);
}

将 AX 点从 Carbon 点转换为 Cocoa Screen 点。

+ (NSPoint)cocoaScreenPointFromCarbonScreenPoint:(NSPoint)carbonPoint
{
   return NSMakePoint(carbonPoint.x, [[[NSScreen screens] objectAtIndex:0] frame].size.height - carbonPoint.y);
}

研究这些位。

您还需要深入研究 Xcode 附带的 Accessibility Inspector 应用程序以及来自 Apple 的类似示例代码 UIElementInspector

【讨论】:

  • 非常感谢!我会研究这个并回复你。祝你有美好的一天!
  • 你能解释一下在哪里可以找到“DHAbbreviationManager cocoaRectFromCarbonScreenRect:”
  • 这只是发起者将所有这些内容放入其中的类的名称。第二部分是他写的一个转换点系统的便利函数。
  • 所以如果有一个游标,它的位置和长度可以为零,这意味着没有选择,而是在字符串中的一个位置。
  • 这可能取决于 Electron 应用程序,但如果你在 web 视图中,它一直都是 web 的东西。这意味着,如果 Web 内容本身具有适当的语义丰富性(或标签中的显式 ARIA 属性)来表达 macOS 原生元素所表达的内容,它可能会起作用。但如果没有,你可以玩 JavaScript / DOM 脚本舞蹈。请记住,这是基于可访问性 API,如果 Web 内容不可访问,它可能不会有帮助。
猜你喜欢
  • 2015-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 2021-11-03
  • 1970-01-01
相关资源
最近更新 更多