关于macOS Accessibility API,是否仍要创建与NSView或NSWindow对应的AXUIElementRef?

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

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

我愿意考虑有助于实现此目的的未公开的API。

最佳答案

我找到了在iOS中执行相同操作的方法。

我知道这不是您问题的直接答案,但是我将尽力解释我在iOS中找到它所要做的事情,希望您能够在macOS中做到这一点。另外,这可能对其他读者很有用...

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

然后,我创建了一个应用程序,并对_AXUIElementCreateAppElementWithPid(int pid)进行了dlsym调用,并使用[[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从UI转换为可访问性元素,然后将UIView* _AXElementForAXUIElementUniqueId(AXUIElementRefGetUniqueID(AXUIElementRef));沿相反的方向转换。

所有符号均来自AXRuntime.framework

在Mac中,您需要链接ApplicationServices.framework并尝试类似的方法。

希望这可以帮助...

10-08 17:32