繁体   English   中英

如何从 NSView 或 NSWindow 创建 AXUIElementRef?

[英]How to create an AXUIElementRef from an NSView or NSWindow?

关于 macOS 辅助功能 API,无论如何创建一个对应于 NSView 或 NSWindow 的 AXUIElementRef?

在使用 AXUIElementCreateWithHIObjectAndIdentifier 的 Carbon 时代,似乎有一种方法可以做到这一点,但该功能不再可用。

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

我愿意考虑帮助实现这一目标的未记录的 API。

我找到了在 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心地调试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并尝试类似的操作。

希望这可以帮助...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM