import Cocoa import ApplicationServices // Comprehensive recursive search for any element with AXFocused == true func findActiveFocusedElement(_ elem: AXUIElement) -> AXUIElement? { var isFocusedObj: CFTypeRef? if AXUIElementCopyAttributeValue(elem, kAXFocusedAttribute as CFString, &isFocusedObj) == .success, let isFocused = isFocusedObj as? Bool, isFocused { var roleObj: CFTypeRef? AXUIElementCopyAttributeValue(elem, kAXRoleAttribute as CFString, &roleObj) let role = (roleObj as? String) ?? "" if role != "AXWindow" && role != "AXApplication" && role != "AXGroup" && role != "AXSplitGroup" && role != "AXScrollArea" { return elem } } var childrenObj: CFTypeRef? if AXUIElementCopyAttributeValue(elem, kAXChildrenAttribute as CFString, &childrenObj) == .success, let children = childrenObj as? [AXUIElement] { for child in children { if let found = findActiveFocusedElement(child) { return found } } } return nil } func getFocusedTextInfo() -> (String, String, Int, Int)? { guard let frontApp = NSWorkspace.shared.frontmostApplication else { return nil } let appName = frontApp.localizedName ?? "App" let appElem = AXUIElementCreateApplication(frontApp.processIdentifier) // 1. Try systemWide let sysWide = AXUIElementCreateSystemWide() var focusedElemObj: CFTypeRef? var targetElem: AXUIElement? if AXUIElementCopyAttributeValue(sysWide, kAXFocusedUIElementAttribute as CFString, &focusedElemObj) == .success, let obj = focusedElemObj { targetElem = (obj as! AXUIElement) } // 2. Try App focused element if targetElem == nil { if AXUIElementCopyAttributeValue(appElem, kAXFocusedUIElementAttribute as CFString, &focusedElemObj) == .success, let obj = focusedElemObj { targetElem = (obj as! AXUIElement) } } // 3. Try Recursive search in app tree if targetElem == nil { targetElem = findActiveFocusedElement(appElem) } guard let elem = targetElem else { return nil } // Extract text var text = "" var valObj: CFTypeRef? if AXUIElementCopyAttributeValue(elem, kAXValueAttribute as CFString, &valObj) == .success, let val = valObj { if let str = val as? String { text = str } else if let attrStr = val as? NSAttributedString { text = attrStr.string } } // Try parameterized string for range if text.isEmpty { var countObj: CFTypeRef? if AXUIElementCopyAttributeValue(elem, kAXNumberOfCharactersAttribute as CFString, &countObj) == .success, let count = countObj as? Int, count > 0 { var range = CFRange(location: 0, length: count) if let axRange = AXValueCreate(.cfRange, &range) { var strObj: CFTypeRef? if AXUIElementCopyParameterizedAttributeValue(elem, kAXStringForRangeParameterizedAttribute as CFString, axRange, &strObj) == .success, let str = strObj as? String { text = str } } } } // Cursor & Selection var cursor = text.count var selLen = 0 var rangeObj: CFTypeRef? if AXUIElementCopyAttributeValue(elem, kAXSelectedTextRangeAttribute as CFString, &rangeObj) == .success, let axRange = rangeObj { var range = CFRange() if AXValueGetValue(axRange as! AXValue, .cfRange, &range) { cursor = range.location selLen = range.length } } return (appName, text, cursor, selLen) } if let (app, text, cursor, selLen) = getFocusedTextInfo() { print("Found! App: \(app), Text: '\(text)', Cursor: \(cursor), SelLen: \(selLen)") } else { print("No focused text element found") }