更新
不确定可访问性框架是否适合这里。似乎它只允许你与其他应用程序交互,但不能做像编程发送选择器给他们这样的事情。
有关更多上下文,macOS具有用户定义的键绑定(~/Library/KeyBindings/DefaultKeyBinding.dict
),您可以在其中指定键绑定和选择器,当您按下它时,该选择器将发送到具有焦点的任何应用/控件。这发生在OS级别。
想知道是否有一种方法可以通过编程来做类似的事情,从我自己的应用程序发送选择器(当然,前提是它需要适当的权限来这样做)。
原问题。
只是玩弄可访问性框架,试图向第一响应者发送选择器(即焦点元素),不管该应用程序是我的还是其他东西。
为了测试这一点,我尝试将moveToBeginningOfLine:
发送到具有焦点的任何文本字段。如果它接收到它,光标应该移动到当前行的开头。
现在,在我自己的应用程序中将其发送给第一响应者很容易。你使用NSApplication.sendAction
,目标为'nil',就像下面我的sendToFirstResponder
扩展一样。但这并不适用于其他应用程序,只有你自己的。
要与其他应用程序对话,您必须使用AXUIAutomation
(并确保您的应用程序已被授予使用它的权限,我的应用程序也有),即使在下面的代码中我似乎成功地获得了一个焦点AXUIElement
,它似乎从未像我期望的那样接收选择器,并且调用报告为失败。
这是我正在玩的代码...
选择器扩展名:
extension Selector {
@discardableResult
func sendToFirstResponder(from sender: Any? = nil) -> Bool {
return NSApplication.shared.sendAction(self, to: nil, from: sender)
}
@discardableResult
func sendToFrontmostApp() -> Bool {
let systemWideElement = AXUIElementCreateSystemWide()
var untypedFocusedElement : AnyObject?
let getFocusedElementResult = AXUIElementCopyAttributeValue(systemWideElement, kAXFocusedUIElementAttribute as CFString, &untypedFocusedElement)
guard getFocusedElementResult == .success else {
print("Couldn't get the focused element. \(getFocusedElementResult)")
return false
}
let focusedElement = untypedFocusedElement as! AXUIElement
let action = description as CFString
let performActionResult = AXUIElementPerformAction(focusedElement, action)
guard performActionResult == .success else {
print("Couldn't perform the action '\(action)'. \(performActionResult)")
return false
}
return true
}
}
测试编码:
// If you send this to a TextField, the cursor moves to the beginning of the line
let selectorName = "moveToBeginningOfLine:"
let selector = Selector(selectorName)
// This works if the current app is focused and a TextField is the first responder
let result1 = selector.sendToFirstResponder()
print("Result 1:", result1)
// This always fails on the 'perform action' step, even if there's a focused TextField in the frontmost app
let result2 = selector.sendToFrontmostApp()
print("Result 2:", result2)
这可能吗?
1条答案
按热度按时间5n0oy7gb1#
不可以,在Swift 5中不能直接向
AXUIElement
发送选择器。Accessibility框架中的AXUIElement
类提供了一种与应用程序的可访问性层次结构进行交互的方法,但它不允许您向UI元素发送任意消息或选择器。但是,您可以使用
AXUIElementPerformAction
函数在AXUIElement
上执行某些操作。此函数采用两个参数:要对其执行操作的AXUIElement
对象,以及一个指定要执行的操作类型的常量。可用的操作在AXActionConstants
枚举中定义。下面是一个如何使用
AXUIElementPerformAction
在button元素上执行“press”操作的示例:在本例中,使用
buttonElement
对象和kAXPressAction
常量调用AXUIElementPerformAction
函数,该常量指定要执行的“press”操作。如果操作成功执行,actionResult
参数将包含操作的结果(如果有)。请注意,并非所有
AXUIElement
都支持所有操作,因此您应该查看文档中您想要与之交互的特定元素,以了解哪些操作可用。