Skip to content

Instantly share code, notes, and snippets.

@levochkaa
Created April 3, 2025 11:06
Show Gist options
  • Save levochkaa/cb1d06f11ae4013aa1f2bacf7ced0fab to your computer and use it in GitHub Desktop.
Save levochkaa/cb1d06f11ae4013aa1f2bacf7ced0fab to your computer and use it in GitHub Desktop.
Wrapper around AXUI and attempts to get/set active UITextView text
// ContentView.swift
import SwiftUI
import Cocoa
final class Observer {
static let shared = Observer()
var observers = [String: AXObserver]()
/// Dictionary to track the last activation time for each app, used for debouncing
var lastActivationTime = [String: Date]()
/// Time interval to prevent duplicate notifications (500 milliseconds)
let debounceInterval: TimeInterval = 0.5
func setObservers() {
let notifications: [Notification] = [] // [.FocusedWindowChanged]
for app in NSWorkspace.shared.runningApplications {
let pid = app.processIdentifier
for notification in notifications {
observers["\(pid)_\(notification.string)"] = AX.addObserver(pid: pid, notification: notification)
}
}
}
func appName(from refcon: UnsafeMutableRawPointer?) -> String? {
guard let refcon else { return nil }
let appPid = Unmanaged<NSNumber>.fromOpaque(refcon).takeUnretainedValue().int32Value
guard let activatedApp = NSRunningApplication(processIdentifier: appPid) else { return nil }
return activatedApp.localizedName ?? activatedApp.bundleIdentifier ?? "unknown"
}
func handleNotification(appName: String, notification: String, element: AXUIElement) {
let currentTime = Date()
print("\(notification) for app: \(appName)")
if let lastTime = lastActivationTime[appName], currentTime.timeIntervalSince(lastTime) < debounceInterval {
return
}
lastActivationTime[appName] = Date()
if notification == Notification.ApplicationActivated.string {
print("Notification: ApplicationActivated for app: \(appName)")
} else if notification == Notification.FocusedWindowChanged.string {
print("Notification: Frontmost Window Changed for app: \(appName)")
if let title = AX.get(.Title, from: element) as? String {
print("Current Window Title: \(title)")
}
}
}
}
struct ContentView: View {
@State private var activeTextField: String?
var body: some View {
VStack {
if let activeTextField {
Text("\(activeTextField)")
} else {
Text("nothing")
}
Button("Give access") {
requestAccessibilityPermission()
}
.onReceive(Timer.publish(every: 1, on: .main, in: .common).autoconnect()) { _ in
activeTextField = getActiveTextFieldSystemWide()
}
}
.onAppear {
Observer.shared.setObservers()
}
}
func requestAccessibilityPermission() {
let checkOptionPrompt = kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String
let options = [checkOptionPrompt: true] as CFDictionary
AXIsProcessTrustedWithOptions(options)
}
func getActiveTextFieldSystemWide() -> String? {
guard AXIsProcessTrusted() else {
print("Accessibility permissions not granted.")
return nil
}
guard let textField = AX.get(.FocusedUIElement) else {
print("Unable to get focused UI element.")
return nil
}
// insertSuggestion(into: textField, suggestion: "ai suggestion lol")
guard let text = AX.get(.Value, from: textField) as? String else {
print("Unable to get value.")
return nil
}
// guard let app = AX.get(.FocusedApplication) else {
// print("Unable to get focused application.")
// return nil
// }
// if let appAttributes = getAttributes(from: app) {
// print(appAttributes)
// }
// guard let window = AX.get(.FocusedWindow, from: app) else {
// print("Unable to get focused window.")
// return nil
// }
// if let windowAttributes = AX.getAttributes(from: window) {
// if let title = get(.Title, from: window) as? String {
// print("window title: \(title)")
// }
// print(windowAttributes)
// }
// if let children = get(.Children, from: window) as? [AXUIElement] {
// for child in children {
// print(get(.Role, from: child) as? String ?? "nil")
// }
// }
// if let textElements = findAllTextElements(in: window) {
// for textElement in (textElements as! [AXUIElement]) {
// if let value = AX.get(.Value, from: textElement) as? String {
// print("text value: \(value)")
// } else if let title = AX.get(.Title, from: textElement) as? String {
// print("text title: \(title)")
// } else if let description = AX.get(.Description, from: textElement) as? String {
// print("text description: \(description)")
// } else {
// print("No accessible text found.")
// }
// }
// }
return text
}
func findAllTextElements(in element: CFTypeRef) -> [CFTypeRef]? {
var textElements: [CFTypeRef] = []
// Retrieve the role of the current element
if let role = AX.get(.Role, from: element) as? String {
// Define roles that typically contain text
let textRoles: Set<String> = [
AttributeRole.TextArea.string,
AttributeRole.TextField.string,
AttributeRole.StaticText.string,
AttributeRole.Heading.string
]
if textRoles.contains(role) {
textElements.append(element)
}
}
// Get children and recurse
if let children = AX.get(.Children, from: element) as? [AXUIElement] {
for child in children {
textElements.append(contentsOf: findAllTextElements(in: child) ?? [])
}
}
return textElements
}
}
func insertSuggestion(into textField: CFTypeRef, suggestion: String) {
AX.set(.Value, value: suggestion as CFString, to: textField)
}
func getPosition(of element: CFTypeRef) -> CGRect? {
guard let positionValue = AX.get(.Position, from: element), let sizeValue = AX.get(.Size, from: element) else { return nil }
var position: CGPoint = .zero
AXValueGetValue(positionValue as! AXValue, .cgPoint, &position)
var size: CGSize = .zero
AXValueGetValue(sizeValue as! AXValue, .cgSize, &size)
return CGRect(origin: position, size: size)
}
//enum ValueType: Int {
// case cgPoint = 1
// case cgSize = 2
// case cgRect = 3
// case cfRange = 4
// case axError = 5
// case illegal = 0
//
// var axValueType: AXValueType {
// switch self {
// case .cgPoint: .cgPoint
// case .cgSize: .cgSize
// case .cgRect: .cgRect
// case .cfRange: .cfRange
// case .axError: .axError
// case .illegal: .illegal
// }
// }
//
// var initialValue: Any? {
// switch self {
// case .cgPoint: CGPoint.zero
// case .cgSize: CGSize.zero
// case .cgRect: CGRect.zero
// case .cfRange: CFRange(location: .zero, length: .zero)
// case .axError: AXError(rawValue: 0)
// case .illegal: nil
// }
// }
//}
enum AX {
// static func getValue(_ value: CFTypeRef, type: ValueType) -> Any? {
// var pos = type.initialValue
// AXValueGetValue(value as! AXValue, type.axValueType, &pos)
// return pos
// }
static let defaultCallback: AXObserverCallback = { observer, element, notification, refcon in
guard let appName = Observer.shared.appName(from: refcon) else { return }
Observer.shared.handleNotification(appName: appName, notification: notification as String, element: element)
}
static func addObserver(pid: pid_t, notification: Notification, callback: AXObserverCallback = defaultCallback) -> AXObserver? {
var observer: AXObserver?
// Create the accessibility observer
let createStatus = AXObserverCreate(pid, callback, &observer)
guard createStatus == .success, let observer else {
print("Failed to create observer for \(pid), error: \(createStatus.string)")
return nil
}
let axApp = AXUIElementCreateApplication(pid)
let appPidRefcon = Unmanaged.passRetained(NSNumber(value: pid)).toOpaque()
let addStatus = AXObserverAddNotification(observer, axApp, notification.string as CFString, appPidRefcon)
guard addStatus == .success else {
print("Failed to add notification for \(pid), error: \(addStatus.string)")
return nil
}
print("added observer for: \(pid)")
CFRunLoopAddSource(CFRunLoopGetCurrent(), AXObserverGetRunLoopSource(observer), .defaultMode)
return observer
}
static func getAttributes(from element: CFTypeRef? = AXUIElementCreateSystemWide()) -> CFArray? {
var value: CFArray?
let status = AXUIElementCopyAttributeNames(element as! AXUIElement, &value)
if status == .success {
return value
} else {
print("error: \(status.string)")
return nil
}
}
@discardableResult static func set(_ attribute: Attribute, value: CFTypeRef, to element: CFTypeRef? = AXUIElementCreateSystemWide()) -> Bool {
let status = AXUIElementSetAttributeValue(element as! AXUIElement, attribute.string as CFString, value)
if status == .success {
return true
} else {
print("error: \(status.string)")
return false
}
}
static func get(_ attribute: Attribute, from element: CFTypeRef? = AXUIElementCreateSystemWide()) -> CFTypeRef? {
var value: CFTypeRef?
let status = AXUIElementCopyAttributeValue(element as! AXUIElement, attribute.string as CFString, &value)
if status == .success {
return value
} else {
print("error: \(status.string)")
return nil
}
}
}
// Attribute.swift
import Cocoa
enum Attribute {
case Role
case Subrole
case RoleDescription
case Help
case Title
case Value
case ValueDescription
case MinValue
case MaxValue
case ValueIncrement
case AllowedValues
case PlaceholderValue
case Enabled
case ElementBusy
case Focused
case Parent
case Children
case SelectedChildren
case VisibleChildren
case Window
case TopLevelUIElement
case Position
case Size
case Orientation
case DescriptionAttribute
case Description
case SelectedText
case SelectedTextRange
case SelectedTextRanges
case VisibleCharacterRange
case NumberOfCharacters
case SharedTextUIElements
case SharedCharacterRange
case SharedFocusElements
case InsertionPointLineNumber
case Main
case Minimized
case CloseButton
case ZoomButton
case MinimizeButton
case ToolbarButton
case FullScreenButton
case Proxy
case GrowArea
case Modal
case DefaultButton
case CancelButton
case MenuItemCmdChar
case MenuItemCmdVirtualKey
case MenuItemCmdGlyph
case MenuItemCmdModifiers
case MenuItemMarkChar
case MenuItemPrimaryUIElement
case MenuBar
case Windows
case Frontmost
case Hidden
case MainWindow
case FocusedWindow
case FocusedUIElement
case ExtrasMenuBar
case Header
case Edited
case ValueWraps
case Tabs
case TitleUIElement
case HorizontalScrollBar
case VerticalScrollBar
case OverflowButton
case Filename
case Expanded
case Selected
case Splitters
case NextContents
case Document
case DecrementButton
case IncrementButton
case PreviousContents
case Contents
case Incrementor
case HourField
case MinuteField
case SecondField
case AMPMField
case DayField
case MonthField
case YearField
case ColumnTitle
case URL
case LabelUIElements
case LabelValue
case ShownMenuUIElement
case ServesAsTitleForUIElements
case LinkedUIElements
case Rows
case VisibleRows
case SelectedRows
case Columns
case VisibleColumns
case SelectedColumns
case SortDirection
case Index
case Disclosing
case DisclosedRows
case DisclosedByRow
case DisclosureLevel
case MatteHole
case MatteContentUIElement
case MarkerUIElements
case Units
case UnitDescription
case MarkerType
case MarkerTypeDescription
case IsApplicationRunning
case SearchButton
case ClearButton
case FocusedApplication
case RowCount
case ColumnCount
case OrderedByRow
case WarningValue
case CriticalValue
case SelectedCells
case VisibleCells
case RowHeaderUIElements
case ColumnHeaderUIElements
case RowIndexRange
case ColumnIndexRange
case HorizontalUnits
case VerticalUnits
case HorizontalUnitDescription
case VerticalUnitDescription
case Handles
case Text
case VisibleText
case IsEditable
case ColumnTitles
case Identifier
case AlternateUIVisible
case LineForIndexParameterized
case RangeForLineParameterized
case StringForRangeParameterized
case RangeForPositionParameterized
case RangeForIndexParameterized
case BoundsForRangeParameterized
case RTFForRangeParameterized
case AttributedStringForRangeParameterized
case StyleRangeForIndexParameterized
case CellForColumnAndRowParameterized
case LayoutPointForScreenPointParameterized
case LayoutSizeForScreenSizeParameterized
case ScreenPointForLayoutPointParameterized
case ScreenSizeForLayoutSizeParameterized
var string: String {
switch self {
case .Role: kAXRoleAttribute
case .Subrole: kAXSubroleAttribute
case .RoleDescription: kAXRoleDescriptionAttribute
case .Help: kAXHelpAttribute
case .Title: kAXTitleAttribute
case .Value: kAXValueAttribute
case .ValueDescription: kAXValueDescriptionAttribute
case .MinValue: kAXMinValueAttribute
case .MaxValue: kAXMaxValueAttribute
case .ValueIncrement: kAXValueIncrementAttribute
case .AllowedValues: kAXAllowedValuesAttribute
case .PlaceholderValue: kAXPlaceholderValueAttribute
case .Enabled: kAXEnabledAttribute
case .ElementBusy: kAXElementBusyAttribute
case .Focused: kAXFocusedAttribute
case .Parent: kAXParentAttribute
case .Children: kAXChildrenAttribute
case .SelectedChildren: kAXSelectedChildrenAttribute
case .VisibleChildren: kAXVisibleChildrenAttribute
case .Window: kAXWindowAttribute
case .TopLevelUIElement: kAXTopLevelUIElementAttribute
case .Position: kAXPositionAttribute
case .Size: kAXSizeAttribute
case .Orientation: kAXOrientationAttribute
case .DescriptionAttribute: kAXDescriptionAttribute
case .Description: kAXDescription
case .SelectedText: kAXSelectedTextAttribute
case .SelectedTextRange: kAXSelectedTextRangeAttribute
case .SelectedTextRanges: kAXSelectedTextRangesAttribute
case .VisibleCharacterRange: kAXVisibleCharacterRangeAttribute
case .NumberOfCharacters: kAXNumberOfCharactersAttribute
case .SharedTextUIElements: kAXSharedTextUIElementsAttribute
case .SharedCharacterRange: kAXSharedCharacterRangeAttribute
case .SharedFocusElements: kAXSharedFocusElementsAttribute
case .InsertionPointLineNumber: kAXInsertionPointLineNumberAttribute
case .Main: kAXMainAttribute
case .Minimized: kAXMinimizedAttribute
case .CloseButton: kAXCloseButtonAttribute
case .ZoomButton: kAXZoomButtonAttribute
case .MinimizeButton: kAXMinimizeButtonAttribute
case .ToolbarButton: kAXToolbarButtonAttribute
case .FullScreenButton: kAXFullScreenButtonAttribute
case .Proxy: kAXProxyAttribute
case .GrowArea: kAXGrowAreaAttribute
case .Modal: kAXModalAttribute
case .DefaultButton: kAXDefaultButtonAttribute
case .CancelButton: kAXCancelButtonAttribute
case .MenuItemCmdChar: kAXMenuItemCmdCharAttribute
case .MenuItemCmdVirtualKey: kAXMenuItemCmdVirtualKeyAttribute
case .MenuItemCmdGlyph: kAXMenuItemCmdGlyphAttribute
case .MenuItemCmdModifiers: kAXMenuItemCmdModifiersAttribute
case .MenuItemMarkChar: kAXMenuItemMarkCharAttribute
case .MenuItemPrimaryUIElement: kAXMenuItemPrimaryUIElementAttribute
case .MenuBar: kAXMenuBarAttribute
case .Windows: kAXWindowsAttribute
case .Frontmost: kAXFrontmostAttribute
case .Hidden: kAXHiddenAttribute
case .MainWindow: kAXMainWindowAttribute
case .FocusedWindow: kAXFocusedWindowAttribute
case .FocusedUIElement: kAXFocusedUIElementAttribute
case .ExtrasMenuBar: kAXExtrasMenuBarAttribute
case .Header: kAXHeaderAttribute
case .Edited: kAXEditedAttribute
case .ValueWraps: kAXValueWrapsAttribute
case .Tabs: kAXTabsAttribute
case .TitleUIElement: kAXTitleUIElementAttribute
case .HorizontalScrollBar: kAXHorizontalScrollBarAttribute
case .VerticalScrollBar: kAXVerticalScrollBarAttribute
case .OverflowButton: kAXOverflowButtonAttribute
case .Filename: kAXFilenameAttribute
case .Expanded: kAXExpandedAttribute
case .Selected: kAXSelectedAttribute
case .Splitters: kAXSplittersAttribute
case .NextContents: kAXNextContentsAttribute
case .Document: kAXDocumentAttribute
case .DecrementButton: kAXDecrementButtonAttribute
case .IncrementButton: kAXIncrementButtonAttribute
case .PreviousContents: kAXPreviousContentsAttribute
case .Contents: kAXContentsAttribute
case .Incrementor: kAXIncrementorAttribute
case .HourField: kAXHourFieldAttribute
case .MinuteField: kAXMinuteFieldAttribute
case .SecondField: kAXSecondFieldAttribute
case .AMPMField: kAXAMPMFieldAttribute
case .DayField: kAXDayFieldAttribute
case .MonthField: kAXMonthFieldAttribute
case .YearField: kAXYearFieldAttribute
case .ColumnTitle: kAXColumnTitleAttribute
case .URL: kAXURLAttribute
case .LabelUIElements: kAXLabelUIElementsAttribute
case .LabelValue: kAXLabelValueAttribute
case .ShownMenuUIElement: kAXShownMenuUIElementAttribute
case .ServesAsTitleForUIElements: kAXServesAsTitleForUIElementsAttribute
case .LinkedUIElements: kAXLinkedUIElementsAttribute
case .Rows: kAXRowsAttribute
case .VisibleRows: kAXVisibleRowsAttribute
case .SelectedRows: kAXSelectedRowsAttribute
case .Columns: kAXColumnsAttribute
case .VisibleColumns: kAXVisibleColumnsAttribute
case .SelectedColumns: kAXSelectedColumnsAttribute
case .SortDirection: kAXSortDirectionAttribute
case .Index: kAXIndexAttribute
case .Disclosing: kAXDisclosingAttribute
case .DisclosedRows: kAXDisclosedRowsAttribute
case .DisclosedByRow: kAXDisclosedByRowAttribute
case .DisclosureLevel: kAXDisclosureLevelAttribute
case .MatteHole: kAXMatteHoleAttribute
case .MatteContentUIElement: kAXMatteContentUIElementAttribute
case .MarkerUIElements: kAXMarkerUIElementsAttribute
case .Units: kAXUnitsAttribute
case .UnitDescription: kAXUnitDescriptionAttribute
case .MarkerType: kAXMarkerTypeAttribute
case .MarkerTypeDescription: kAXMarkerTypeDescriptionAttribute
case .IsApplicationRunning: kAXIsApplicationRunningAttribute
case .SearchButton: kAXSearchButtonAttribute
case .ClearButton: kAXClearButtonAttribute
case .FocusedApplication: kAXFocusedApplicationAttribute
case .RowCount: kAXRowCountAttribute
case .ColumnCount: kAXColumnCountAttribute
case .OrderedByRow: kAXOrderedByRowAttribute
case .WarningValue: kAXWarningValueAttribute
case .CriticalValue: kAXCriticalValueAttribute
case .SelectedCells: kAXSelectedCellsAttribute
case .VisibleCells: kAXVisibleCellsAttribute
case .RowHeaderUIElements: kAXRowHeaderUIElementsAttribute
case .ColumnHeaderUIElements: kAXColumnHeaderUIElementsAttribute
case .RowIndexRange: kAXRowIndexRangeAttribute
case .ColumnIndexRange: kAXColumnIndexRangeAttribute
case .HorizontalUnits: kAXHorizontalUnitsAttribute
case .VerticalUnits: kAXVerticalUnitsAttribute
case .HorizontalUnitDescription: kAXHorizontalUnitDescriptionAttribute
case .VerticalUnitDescription: kAXVerticalUnitDescriptionAttribute
case .Handles: kAXHandlesAttribute
case .Text: kAXTextAttribute
case .VisibleText: kAXVisibleTextAttribute
case .IsEditable: kAXIsEditableAttribute
case .ColumnTitles: kAXColumnTitlesAttribute
case .Identifier: kAXIdentifierAttribute
case .AlternateUIVisible: kAXAlternateUIVisibleAttribute
case .LineForIndexParameterized: kAXLineForIndexParameterizedAttribute
case .RangeForLineParameterized: kAXRangeForLineParameterizedAttribute
case .StringForRangeParameterized: kAXStringForRangeParameterizedAttribute
case .RangeForPositionParameterized: kAXRangeForPositionParameterizedAttribute
case .RangeForIndexParameterized: kAXRangeForIndexParameterizedAttribute
case .BoundsForRangeParameterized: kAXBoundsForRangeParameterizedAttribute
case .RTFForRangeParameterized: kAXRTFForRangeParameterizedAttribute
case .AttributedStringForRangeParameterized: kAXAttributedStringForRangeParameterizedAttribute
case .StyleRangeForIndexParameterized: kAXStyleRangeForIndexParameterizedAttribute
case .CellForColumnAndRowParameterized: kAXCellForColumnAndRowParameterizedAttribute
case .LayoutPointForScreenPointParameterized: kAXLayoutPointForScreenPointParameterizedAttribute
case .LayoutSizeForScreenSizeParameterized: kAXLayoutSizeForScreenSizeParameterizedAttribute
case .ScreenPointForLayoutPointParameterized: kAXScreenPointForLayoutPointParameterizedAttribute
case .ScreenSizeForLayoutSizeParameterized: kAXScreenSizeForLayoutSizeParameterizedAttribute
}
}
}
// AttributeRole.swift
import Cocoa
enum AttributeRole {
case Application
case SystemWide
case Window
case Sheet
case Drawer
case GrowArea
case Image
case Unknown
case Button
case RadioButton
case CheckBox
case PopUpButton
case MenuButton
case TabGroup
case Table
case Column
case Row
case Outline
case Browser
case ScrollArea
case ScrollBar
case RadioGroup
case List
case Group
case ValueIndicator
case ComboBox
case Slider
case Incrementor
case BusyIndicator
case ProgressIndicator
case RelevanceIndicator
case Toolbar
case DisclosureTriangle
case TextField
case TextArea
case StaticText
case Heading
case MenuBar
case MenuBarItem
case Menu
case MenuItem
case SplitGroup
case Splitter
case ColorWell
case TimeField
case DateField
case HelpTag
case Matte
case DockItem
case Ruler
case RulerMarker
case Grid
case LevelIndicator
case Cell
case LayoutArea
case LayoutItem
case Handle
case Popover
var string: String {
switch self {
case .Application: kAXApplicationRole
case .SystemWide: kAXSystemWideRole
case .Window: kAXWindowRole
case .Sheet: kAXSheetRole
case .Drawer: kAXDrawerRole
case .GrowArea: kAXGrowAreaRole
case .Image: kAXImageRole
case .Unknown: kAXUnknownRole
case .Button: kAXButtonRole
case .RadioButton: kAXRadioButtonRole
case .CheckBox: kAXCheckBoxRole
case .PopUpButton: kAXPopUpButtonRole
case .MenuButton: kAXMenuButtonRole
case .TabGroup: kAXTabGroupRole
case .Table: kAXTableRole
case .Column: kAXColumnRole
case .Row: kAXRowRole
case .Outline: kAXOutlineRole
case .Browser: kAXBrowserRole
case .ScrollArea: kAXScrollAreaRole
case .ScrollBar: kAXScrollBarRole
case .RadioGroup: kAXRadioGroupRole
case .List: kAXListRole
case .Group: kAXGroupRole
case .ValueIndicator: kAXValueIndicatorRole
case .ComboBox: kAXComboBoxRole
case .Slider: kAXSliderRole
case .Incrementor: kAXIncrementorRole
case .BusyIndicator: kAXBusyIndicatorRole
case .ProgressIndicator: kAXProgressIndicatorRole
case .RelevanceIndicator: kAXRelevanceIndicatorRole
case .Toolbar: kAXToolbarRole
case .DisclosureTriangle: kAXDisclosureTriangleRole
case .TextField: kAXTextFieldRole
case .TextArea: kAXTextAreaRole
case .StaticText: kAXStaticTextRole
case .Heading: kAXHeadingRole
case .MenuBar: kAXMenuBarRole
case .MenuBarItem: kAXMenuBarItemRole
case .Menu: kAXMenuRole
case .MenuItem: kAXMenuItemRole
case .SplitGroup: kAXSplitGroupRole
case .Splitter: kAXSplitterRole
case .ColorWell: kAXColorWellRole
case .TimeField: kAXTimeFieldRole
case .DateField: kAXDateFieldRole
case .HelpTag: kAXHelpTagRole
case .Matte: kAXMatteRole
case .DockItem: kAXDockItemRole
case .Ruler: kAXRulerRole
case .RulerMarker: kAXRulerMarkerRole
case .Grid: kAXGridRole
case .LevelIndicator: kAXLevelIndicatorRole
case .Cell: kAXCellRole
case .LayoutArea: kAXLayoutAreaRole
case .LayoutItem: kAXLayoutItemRole
case .Handle: kAXHandleRole
case .Popover: kAXPopoverRole
}
}
}
// AttributeSubrole.swift
import Cocoa
enum AttributeSubrole {
case CloseButton
case MinimizeButton
case ZoomButton
case ToolbarButton
case FullScreenButton
case SecureTextField
case TableRow
case OutlineRow
case Unknown
case StandardWindow
case Dialog
case SystemDialog
case FloatingWindow
case SystemFloatingWindow
case Decorative
case IncrementArrow
case DecrementArrow
case IncrementPage
case DecrementPage
case SortButton
case SearchField
case Timeline
case RatingIndicator
case ContentList
case DefinitionList
case DescriptionList
case Toggle
case Switch
case ApplicationDockItem
case DocumentDockItem
case FolderDockItem
case MinimizedWindowDockItem
case URLDockItem
case DockExtraDockItem
case TrashDockItem
case SeparatorDockItem
case ProcessSwitcherList
var string: String {
switch self {
case .CloseButton: kAXCloseButtonSubrole
case .MinimizeButton: kAXMinimizeButtonSubrole
case .ZoomButton: kAXZoomButtonSubrole
case .ToolbarButton: kAXToolbarButtonSubrole
case .FullScreenButton: kAXFullScreenButtonSubrole
case .SecureTextField: kAXSecureTextFieldSubrole
case .TableRow: kAXTableRowSubrole
case .OutlineRow: kAXOutlineRowSubrole
case .Unknown: kAXUnknownSubrole
case .StandardWindow: kAXStandardWindowSubrole
case .Dialog: kAXDialogSubrole
case .SystemDialog: kAXSystemDialogSubrole
case .FloatingWindow: kAXFloatingWindowSubrole
case .SystemFloatingWindow: kAXSystemFloatingWindowSubrole
case .Decorative: kAXDecorativeSubrole
case .IncrementArrow: kAXIncrementArrowSubrole
case .DecrementArrow: kAXDecrementArrowSubrole
case .IncrementPage: kAXIncrementPageSubrole
case .DecrementPage: kAXDecrementPageSubrole
case .SortButton: kAXSortButtonSubrole
case .SearchField: kAXSearchFieldSubrole
case .Timeline: kAXTimelineSubrole
case .RatingIndicator: kAXRatingIndicatorSubrole
case .ContentList: kAXContentListSubrole
case .DefinitionList: kAXDefinitionListSubrole
case .DescriptionList: kAXDescriptionListSubrole
case .Toggle: kAXToggleSubrole
case .Switch: kAXSwitchSubrole
case .ApplicationDockItem: kAXApplicationDockItemSubrole
case .DocumentDockItem: kAXDocumentDockItemSubrole
case .FolderDockItem: kAXFolderDockItemSubrole
case .MinimizedWindowDockItem: kAXMinimizedWindowDockItemSubrole
case .URLDockItem: kAXURLDockItemSubrole
case .DockExtraDockItem: kAXDockExtraDockItemSubrole
case .TrashDockItem: kAXTrashDockItemSubrole
case .SeparatorDockItem: kAXSeparatorDockItemSubrole
case .ProcessSwitcherList: kAXProcessSwitcherListSubrole
}
}
}
// AXError.swift
import Cocoa
extension AXError {
var string: String {
switch self {
case .success: "success"
case .failure: "failure"
case .illegalArgument: "illegalArgument"
case .invalidUIElement: "invalidUIElement"
case .invalidUIElementObserver: "invalidUIElementObserver"
case .cannotComplete: "cannotComplete"
case .attributeUnsupported: "attributeUnsupported"
case .actionUnsupported: "actionUnsupported"
case .notificationUnsupported: "notificationUnsupported"
case .notImplemented: "notImplemented"
case .notificationAlreadyRegistered: "notificationAlreadyRegistered"
case .notificationNotRegistered: "notificationNotRegistered"
case .apiDisabled: "apiDisabled"
case .noValue: "noValue"
case .parameterizedAttributeUnsupported: "parameterizedAttributeUnsupported"
case .notEnoughPrecision: "notEnoughPrecision"
@unknown default: "unknown"
}
}
}
// Notification.swift
import Cocoa
enum Notification {
case MainWindowChanged
case FocusedWindowChanged
case FocusedUIElementChanged
case ApplicationActivated
case ApplicationDeactivated
case ApplicationHidden
case ApplicationShown
case WindowCreated
case WindowMoved
case WindowResized
case WindowMiniaturized
case WindowDeminiaturized
case DrawerCreated
case SheetCreated
case HelpTagCreated
case ValueChanged
case UIElementDestroyed
case ElementBusyChanged
case MenuOpened
case MenuClosed
case MenuItemSelected
case RowCountChanged
case RowExpanded
case RowCollapsed
case SelectedCellsChanged
case UnitsChanged
case SelectedChildrenMoved
case SelectedChildrenChanged
case Resized
case Moved
case Created
case SelectedRowsChanged
case SelectedColumnsChanged
case SelectedTextChanged
case TitleChanged
case LayoutChanged
case AnnouncementRequested
var string: String {
switch self {
case .MainWindowChanged: kAXMainWindowChangedNotification
case .FocusedWindowChanged: kAXFocusedWindowChangedNotification
case .FocusedUIElementChanged: kAXFocusedUIElementChangedNotification
case .ApplicationActivated: kAXApplicationActivatedNotification
case .ApplicationDeactivated: kAXApplicationDeactivatedNotification
case .ApplicationHidden: kAXApplicationHiddenNotification
case .ApplicationShown: kAXApplicationShownNotification
case .WindowCreated: kAXWindowCreatedNotification
case .WindowMoved: kAXWindowMovedNotification
case .WindowResized: kAXWindowResizedNotification
case .WindowMiniaturized: kAXWindowMiniaturizedNotification
case .WindowDeminiaturized: kAXWindowDeminiaturizedNotification
case .DrawerCreated: kAXDrawerCreatedNotification
case .SheetCreated: kAXSheetCreatedNotification
case .HelpTagCreated: kAXHelpTagCreatedNotification
case .ValueChanged: kAXValueChangedNotification
case .UIElementDestroyed: kAXUIElementDestroyedNotification
case .ElementBusyChanged: kAXElementBusyChangedNotification
case .MenuOpened: kAXMenuOpenedNotification
case .MenuClosed: kAXMenuClosedNotification
case .MenuItemSelected: kAXMenuItemSelectedNotification
case .RowCountChanged: kAXRowCountChangedNotification
case .RowExpanded: kAXRowExpandedNotification
case .RowCollapsed: kAXRowCollapsedNotification
case .SelectedCellsChanged: kAXSelectedCellsChangedNotification
case .UnitsChanged: kAXUnitsChangedNotification
case .SelectedChildrenMoved: kAXSelectedChildrenMovedNotification
case .SelectedChildrenChanged: kAXSelectedChildrenChangedNotification
case .Resized: kAXResizedNotification
case .Moved: kAXMovedNotification
case .Created: kAXCreatedNotification
case .SelectedRowsChanged: kAXSelectedRowsChangedNotification
case .SelectedColumnsChanged: kAXSelectedColumnsChangedNotification
case .SelectedTextChanged: kAXSelectedTextChangedNotification
case .TitleChanged: kAXTitleChangedNotification
case .LayoutChanged: kAXLayoutChangedNotification
case .AnnouncementRequested: kAXAnnouncementRequestedNotification
}
}
enum Key {
case UIElements
/// enum PriorityValue: Int {
/// case low = 10
/// case medium = 50
/// case high = 90
/// }
case Priority
case Announcement
case UIElementTitle
var string: String {
switch self {
case .UIElements: kAXUIElementsKey
case .Priority: kAXPriorityKey
case .Announcement: kAXAnnouncementKey
case .UIElementTitle: kAXUIElementTitleKey
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment