Home > Mobile >  How Get UI Elements of a Window? Swift
How Get UI Elements of a Window? Swift

Time:09-18

How Translate this AppleScript code to Swift ?

tell application "System Events" to tell process "Safari" to get UI elements of first window

I already reached to first window of "Safari", but I don't know how to get the UI Elements

let pid = NSWorkspace.shared.runningApplications.first(where: {$0.localizedName == "Safari"})?.processIdentifier
let appRef = AXUIElementCreateApplication(pid!)
var windows: AnyObject?
_ = AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, &windows)
if let firstWindow = (windows as? [AXUIElement])?.first{
    print(firstWindow)
}

CodePudding user response:

You can use the same AXUIElementCopyAttributeValue() to query for the children of the window, and the children of the children, and so on.

Myself likes to add extensions over existing types, when possible, for better clarity:

extension AXUIElement {
    var children: [AXUIElement]? {
        var childrenPtr: CFTypeRef?
        AXUIElementCopyAttributeValue(appRef, kAXChildrenAttribute as CFString, &childrenPtr)
        return childrenPtr as? [AXUIElement]
    }
}

You can then use it in your code:

if let firstWindow = (windows as? [AXUIElement])?.first{
    print(firstWindow, firstWindow.children)
}

You can take it a little bit further, and simplify the AXUIElement consumer code by adding more functionality to the extension:

extension AXUIElement {
    
    static func from(pid: pid_t) -> AXUIElement { AXUIElementCreateApplication(pid) }
    
    var windows: [AXUIElement]? { value(forAttribute: kAXWindowsAttribute) }
    
    var children: [AXUIElement]? { value(forAttribute: kAXChildrenAttribute) }
    
    func value<T>(forAttribute attribute: String) -> T? {
        var attributeValue: CFTypeRef?
        AXUIElementCopyAttributeValue(self, attribute as CFString, &attributeValue)
        return attributeValue as? T
    }
}

let pid = ...
let app = AXUIElement.from(pid: pid!)
if let firstWindow = app.windows?.first{
    print(firstWindow, firstWindow.children)
}
  • Related