如何从NSView或NSWindow创建AXUIElementRef?

3
关于macOS辅助功能API,是否有任何方法可以创建与NSView或NSWindow相对应的AXUIElementRef?
在Carbon时代似乎有一种使用AXUIElementCreateWithHIObjectAndIdentifier的方法,但该函数已不再可用。
我所知道的唯一方法是使用辅助功能API递归搜索您的应用程序的整个UI元素层次结构,查找与NSView或NSWindow匹配的UI元素。但除了是繁琐的解决方案之外,甚至不能保证成功,因为可能没有办法仅使用AXUIElementRef的可用属性就能明确地对应AXUIElementRef和Cocoa对象。
我愿意考虑帮助实现此目标的未记录API。

你找到解决方案了吗? - Elist
不幸的是,我已经在许多苹果框架的私有函数中搜索了很久,但仍然没有找到实现这个的方法。 - Bri Bri
谢谢,我正在做同样的事情...我猜答案可能在请求应用程序元素的子元素中。如果我找到了什么,我会告诉你的。 - Elist
1个回答

2
我已经找到在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的框架中挖掘,看看是否有类似的函数,到目前为止我还没有找到任何东西。但希望它在那里某个地方。 - Bri Bri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接