【问题标题】:How to create an AXUIElementRef from an NSView or NSWindow?如何从 NSView 或 NSWindow 创建 AXUIElementRef?
【发布时间】:2016-10-06 22:24:12
【问题描述】:

关于 macOS Accessibility API,是否可以创建一个对应于 NSView 或 NSWindow 的 AXUIElementRef?

在 Carbon 时代,似乎有一种方法可以使用 AXUIElementCreateWithHIObjectAndIdentifier 执行此操作,但该功能不再可用。

我知道的唯一方法是使用 Accessibility API 递归搜索应用程序的 UI 元素的整个层次结构,以查找与 NSView 或 NSWindow 匹配的元素。但除了是一个繁重的解决方案之外,它甚至不能保证成功,因为可能无法通过仅使用 AXUIElementRef 的可用属性来正向对应 AXUIElementRef 和 Cocoa 对象。

我愿意考虑使用无证 API 来帮助实现这一目标。

【问题讨论】:

  • 您找到解决方案了吗?
  • 不,很遗憾。我已经挖掘了许多 Apple 框架中的私有函数来寻找一些东西,但仍然没有找到一种方法。
  • 谢谢,我也在做同样的事情......我想答案在 app 元素的子元素的某个地方。如果我找到任何东西会通知你

标签: macos cocoa accessibility


【解决方案1】:

我找到了在 iOS 中做同样事情的方法。

我知道这不是您问题的直接答案,但我会尝试解释我为在 iOS 中找到它所做的工作,希望您能够在 macOS 中做同样的事情。此外,这可能对其他读者有用...

我首先猜测进程本身正在创建AXUIElementRef,因此当我请求具有AXUIElementRef 值的可访问性属性(例如kAXUIElementAttributeChildren)时,它必须创建它们。

然后我创建了一个应用程序,并 dlsym'ed _AXUIElementCreateAppElementWithPid(int pid),用 [[NSProcessInfo processInfo] processIdentifier] 调用它。 我收到了根AXUIElementRef,然后我将它传递给AXError AXUIElementCopyMultipleAttributeValues(AXUIElementRef element, CFArrayRef attributes, AXCopyMultipleAttributeOptions options, CFArrayRef _Nullable *values),请求kAXUIElementAttributeChildren,它工作了(应该在主线程上运行)!

我开始仔细调试汇编代码中的 AXUIElementCopyMultipleAttributeValues 调用,它非常像那样(这是非常伪代码,当然......):

// serialize the arguments for MIG call
if (axUIElementRef->pid == self pid) {
    // that's good that we are calling our own process, we can easily keep debugging!
    _MIGXAAXUIElementCopyMultipleAttributeValues(serialized arguments) {
         // Get the original element from the AXUIElementRef:
         UIView* view = _AXElementForAXUIElementUniqueId(id);
         [view accessibilityAttributeValue:kAXUIElementAttributeChildren] {
              [view _accessibilityUserTestingChildren] {
                   // since this is the UIApplication element, it just gets the windows:
                   NSArray*<UIWindow*> winArr = [(UIApplication*)view _accessibilityWindows];
                   // for each value in result, convert to AX value:
                   ...
                   AXConvertOutgoingValue(winArr) {
                       // For each UIView, convert to AXUIElementRef:
                       AXUIElementRef e = _AXCreateAXUIElementWithElement(winArr[i]);
                   }
              }
         }
    }
} else {
    // Do the same only if we are entitled, and outside our process
}

因此,在 iOS 中,您只需调用 AXUIElementRef _AXCreateAXUIElementWithElement(UIView*); 即可将 UI 转换为可访问性元素,而 UIView* _AXElementForAXUIElementUniqueId(AXUIElementRefGetUniqueID(AXUIElementRef)); 则相反。

所有符号均来自AXRuntime.framework

在 mac 中,您需要链接 ApplicationServices.framework 并尝试类似的操作。

希望这会有所帮助...

【讨论】:

  • 干得好!我已经开始在 macOS 的框架中挖掘,看看是否有任何类似的功能,但到目前为止我还没有找到任何东西。但希望它在某个地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-23
  • 2016-07-14
  • 1970-01-01
相关资源
最近更新 更多