You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
3.1 KiB
81 lines
3.1 KiB
import Cocoa
|
|
import ApplicationServices
|
|
|
|
func testLiveAX() {
|
|
let sysWide = AXUIElementCreateSystemWide()
|
|
|
|
// Enable Chromium/Electron accessibility
|
|
AXUIElementSetAttributeValue(sysWide, "AXEnhancedUserInterface" as CFString, kCFBooleanTrue)
|
|
AXUIElementSetAttributeValue(sysWide, "AXManualAccessibility" as CFString, kCFBooleanTrue)
|
|
|
|
guard let frontApp = NSWorkspace.shared.frontmostApplication else {
|
|
print("No front app")
|
|
return
|
|
}
|
|
|
|
print("Front App:", frontApp.localizedName ?? "", "PID:", frontApp.processIdentifier)
|
|
|
|
let appElem = AXUIElementCreateApplication(frontApp.processIdentifier)
|
|
AXUIElementSetAttributeValue(appElem, "AXEnhancedUserInterface" as CFString, kCFBooleanTrue)
|
|
AXUIElementSetAttributeValue(appElem, "AXManualAccessibility" as CFString, kCFBooleanTrue)
|
|
|
|
// Try system wide focused element
|
|
var focusedUIElement: CFTypeRef?
|
|
var err = AXUIElementCopyAttributeValue(sysWide, kAXFocusedUIElementAttribute as CFString, &focusedUIElement)
|
|
if err != .success || focusedUIElement == nil {
|
|
err = AXUIElementCopyAttributeValue(appElem, kAXFocusedUIElementAttribute as CFString, &focusedUIElement)
|
|
}
|
|
|
|
guard err == .success, let elem = focusedUIElement else {
|
|
print("No focused element. Error:", err.rawValue)
|
|
return
|
|
}
|
|
|
|
let axElem = elem as! AXUIElement
|
|
|
|
var roleRef: CFTypeRef?
|
|
AXUIElementCopyAttributeValue(axElem, kAXRoleAttribute as CFString, &roleRef)
|
|
let role = (roleRef as? String) ?? "AXUnknown"
|
|
print("Role:", role)
|
|
|
|
// Extract text
|
|
var currentText = ""
|
|
var valueRef: CFTypeRef?
|
|
if AXUIElementCopyAttributeValue(axElem, kAXValueAttribute as CFString, &valueRef) == .success,
|
|
let val = valueRef {
|
|
if let str = val as? String {
|
|
currentText = str
|
|
} else if let attrStr = val as? NSAttributedString {
|
|
currentText = attrStr.string
|
|
}
|
|
}
|
|
|
|
if currentText.isEmpty {
|
|
var countRef: CFTypeRef?
|
|
if AXUIElementCopyAttributeValue(axElem, kAXNumberOfCharactersAttribute as CFString, &countRef) == .success,
|
|
let count = countRef as? Int {
|
|
var range = CFRange(location: 0, length: count)
|
|
if let axRange = AXValueCreate(.cfRange, &range) {
|
|
var stringRef: CFTypeRef?
|
|
if AXUIElementCopyParameterizedAttributeValue(axElem, kAXStringForRangeParameterizedAttribute as CFString, axRange, &stringRef) == .success,
|
|
let str = stringRef as? String {
|
|
currentText = str
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print("Extracted Text: '\(currentText)'")
|
|
|
|
// Selection / Cursor
|
|
var rangeRef: CFTypeRef?
|
|
if AXUIElementCopyAttributeValue(axElem, kAXSelectedTextRangeAttribute as CFString, &rangeRef) == .success,
|
|
let val = rangeRef {
|
|
var cfRange = CFRange()
|
|
if AXValueGetValue(val as! AXValue, .cfRange, &cfRange) {
|
|
print("Cursor Location: \(cfRange.location), Selection Length: \(cfRange.length)")
|
|
}
|
|
}
|
|
}
|
|
|
|
testLiveAX()
|