Error converting AXValue to CFTypeRef in AXUIElementCopyAttributeValue on MacOS

I am trying to get the text range globally on MacOS from Accessibility API, AXUIElementCopyAttributeValue function. But having an error converting AXValue to CFTypeRef.

This snippet I am referring to

Variables:

var focusedElement: CFTypeRef?
                
var rangeValue: AXValue? = nil

First Attempt:

if AXUIElementCopyAttributeValue(
   focusedElement as! AXUIElement,
   kAXSelectedTextRangeAttribute as CFString,
   (CFTypeRef *)&rangeValue) == AXError.success {

   } /* Compile error: Cannot convert value of type 'AXValue' to expected argument type 'UnsafeMutablePointer<CFTypeRef?>' (aka 'UnsafeMutablePointer<Optional<AnyObject>>') */

Second Attempt:

if AXUIElementCopyAttributeValue(
    focusedElement as! AXUIElement,
    kAXSelectedTextRangeAttribute as CFString, 
    ((rangeValue as CFTypeRef) as? UnsafeMutablePointer<CFTypeRef?>)!)
    == AXError.success {

}         /* Throw Error: Could not cast value of type 'NSNull' (0x7fdf2d8a75a8) to 'Swift.UnsafeMutablePointer<Swift.Optional<Swift.AnyObject>>' */

How to achieve this in Swift?

This is what I did:

struct QAXElement {
    var element: AXUIElement

    …

    func identifier() -> String? {
        var identifierQ: CFTypeRef? = nil
        let err = AXUIElementCopyAttributeValue(self.element, kAXIdentifierAttribute as NSString, &identifierQ)
        guard err == .success else { return nil }
        return (identifierQ! as! String)
    }
    
    …
}

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

It doesn't work when I use

kAXSelectedTextRangeAttribute as CFString

Try this one:

extension AXUIElement {
    func value(forAttribute attribute: String) -> CFTypeRef? {
        var value: CFTypeRef?
        let err = AXUIElementCopyAttributeValue(self, attribute as CFString, &value)
        return value
    }
    
    var selectedTextRange: CFRange? {
        let val = value(forAttribute: kAXSelectedTextRangeAttribute)
        guard let val else { return nil }
        let v = val as! AXValue
        precondition(AXValueGetType(v) == .cfRange)
        var range = CFRange()
        let done = AXValueGetValue(v, .cfRange, &range)
        precondition(done)
        return range
    }
}
1 Like

Not sure if I am using it right. I kept getting case attributeUnsupported = -25205 (The attribute is not supported by the AXUIElementRef.) and nil value from the selectedTextRange.

This is how I use it:

extension AXUIElement {
    func value(forAttribute attribute: String) -> CFTypeRef? {
        var value: CFTypeRef?
        let err = AXUIElementCopyAttributeValue(self, attribute as CFString, &value)
        print(err.rawValue) // -25205 here
        return value
    }
    
    var selectedTextRange: CFRange? {
        let val = value(forAttribute: kAXSelectedTextRangeAttribute)
        guard let val else {return nil}
        let v = val as! AXValue
        precondition(AXValueGetType(v) == .cfRange)
        var range = CFRange()
        let done = AXValueGetValue(v, .cfRange, &range)
        precondition(done)
        return range
    }
}


eventHandler = GlobalEventMonitor(mask: .rightMouseDown){
    (mouseEvent: NSEvent?) in
    
    var system: AXUIElement = AXUIElementCreateSystemWide()
    
    var application: CFTypeRef?
    
    var focusedElement: CFTypeRef?
    
    if(AXUIElementCopyAttributeValue(
        system,
        kAXFocusedApplicationAttribute as CFString,
        &application
        ) == AXError.success){
        
        if AXUIElementCopyAttributeValue(
            application as! AXUIElement,
            kAXFocusedUIElementAttribute as CFString,
            &focusedElement) == AXError.success{
            
             guard let aRange = (application as! AXUIElement).selectedTextRange
            else {
                 return print("nil") // always nil 
             }
            
            print("range: \(aRange)")
            
        }
    }
    
}
  
eventHandler?.start()

Am i using it right? I am trying right click and get range of the high-lighted text in Notes app on Mac.

@tera's answer is working.