使现代化
不确定可访问性框架是如何实现的。它似乎只允许你与其他应用程序交互,而不允许你以编程方式向它们发送选择器。
有关更多上下文,macOS具有用户定义的密钥绑定(
~/Library/KeyBindings/DefaultKeyBinding.dict
)在这里,您可以指定一个键绑定和一个选择器,当您按下它时,它将被发送到任何有焦点的应用程序/控件。这在操作系统级别发生。
想知道是否有一种方法可以通过编程方式做类似的事情,从我自己的应用程序发送选择器(当然,前提是它被请求了适当的权限)。我认为这就是Privacy->辅助功能设置,但看起来我可能走错了路。
原问题。
只是摆弄可访问性框架,尝试将选择器发送到前台应用程序中的第一个响应者(即焦点元素),无论该应用程序是我的还是其他什么。
为了测试这一点,我正在尝试发送
moveToBeginningOfLine:
到具有焦点的任何文本字段。如果它收到它,光标应该移动到当前行的开头。
现在,在我自己的应用程序中将它发送给第一响应者很容易。您使用
NSApplication.sendAction
目标为“零”,就像我的
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)
这可能吗?