Skip to main content
Glama

Peekaboo MCP

by steipete
UsingNewImprovements.swift9.13 kB
// // UsingNewImprovements.swift // AXorcist Examples // // Examples demonstrating the new improvements to AXorcist // import ApplicationServices import Foundation // MARK: - Example 1: Using Static Factory Methods @MainActor func exampleStaticFactoryMethods() { // Old way: // let systemWide = Element(AXUIElementCreateSystemWide()) // New way: let systemWide = Element(AXUIElement.systemWide) // Get focused application if let focusedApp = AXUIElement.focusedApplication() { let appElement = Element(focusedApp) print("Focused app: \(appElement.title() ?? "Unknown")") } // Get frontmost application if let frontmostApp = AXUIElement.frontmostApplication() { let appElement = Element(frontmostApp) print("Frontmost app: \(appElement.title() ?? "Unknown")") } // Get element at position if let app = AXUIElement.frontmostApplication(), let element = AXUIElement.elementAtPosition(in: app, x: 500, y: 300) { let elem = Element(element) print("Element at (500, 300): \(elem.role() ?? "Unknown")") } } // MARK: - Example 2: Using Convenience Attributes @MainActor func exampleConvenienceAttributes() { guard let frontmostApp = frontmostApplicationElement() else { return } // Get all windows with new convenience method if let windows = frontmostApp.windows() { for window in windows { // Use new position and size methods if let position = window.position(), let size = window.size() { print("Window at \(position) with size \(size)") // Get frame as CGRect if let frame = window.frame() { print("Window frame: \(frame)") } } // Check window state if let isMinimized = window.isMinimized() { print("Window minimized: \(isMinimized)") } // Modify window position let newPosition = CGPoint(x: 100, y: 100) let error = window.setPosition(newPosition) if error == .success { print("Successfully moved window") } } } } // MARK: - Example 3: Using AXObserverCenter @MainActor func exampleObserverCenter() { guard let app = frontmostApplicationElement(), let pid = app.pid() else { return } // Set up observer with new center AXObserverCenter.shared.handler = { pid, notification, _, element, _ in print("Notification: \(notification) from PID: \(pid)") let elem = Element(element) if let title = elem.title() { print("Element: \(title)") } } // Add multiple notifications let notifications = [ kAXFocusedUIElementChangedNotification, kAXWindowCreatedNotification, kAXWindowMovedNotification, kAXWindowResizedNotification, ] for notification in notifications { let error = AXObserverCenter.shared.addObserver( pid: pid, notificationKey: notification as String ) if error == .success { print("Added observer for \(notification)") } } // Later, remove all observers for the app // AXObserverCenter.shared.removeAllObservers(for: pid) } // MARK: - Example 4: Using Modern AXAction Enum @MainActor func exampleModernActions() { guard let app = frontmostApplicationElement() else { return } do { // Old way (still supported): // try app.performAction("AXPress") // try app.performAction(AXActionNames.kAXRaiseAction) // New way with cleaner enum syntax: try app.performAction(.press) print("✅ Pressed element successfully") try app.performAction(.raise) print("✅ Raised element successfully") // All available actions: let availableActions: [AXAction] = [ .press, .increment, .decrement, .confirm, .cancel, .showMenu, .pick, .raise, .setValue, ] print("Available actions: \(availableActions.map(\.rawValue).joined(separator: ", "))") } catch { print("❌ Action failed: \(error)") } } // MARK: - Example 5: Using Enhanced Error Handling @MainActor func exampleErrorHandling() { guard let app = frontmostApplicationElement() else { return } do { // Perform action with automatic error throwing try app.performAction(.press) print("Action performed successfully") } catch let systemError as AccessibilitySystemError { // Convert to more descriptive error let accessibilityError = systemError.axError.toAccessibilityError(context: "Pressing button") print("Error: \(accessibilityError)") } catch { print("Unexpected error: \(error)") } } // MARK: - Example 6: Using AXPermissions with Async/Await func examplePermissions() async { // Check permissions without prompting if AXPermissionHelpers.hasAccessibilityPermissions() { print("Accessibility permissions granted") } else { print("Accessibility permissions not granted") } // Request permissions with prompt if needed (async) let granted = await AXPermissionHelpers.requestPermissions() if granted { print("User granted permissions") } else { print("User denied permissions") } // Monitor permission changes with AsyncStream Task { for await hasPermissions in AXPermissionHelpers.permissionChanges() { print("Permission status changed: \(hasPermissions)") } } } // MARK: - Example 7: Using Window Info Helper @MainActor func exampleWindowInfo() { // Get all visible windows if let windows = WindowInfoHelper.getVisibleWindows() { for window in windows { if let name = window[kCGWindowName as String] as? String, let pid = window[kCGWindowOwnerPID as String] as? Int, let windowID = window[kCGWindowNumber as String] as? Int { print("Window '\(name)' (ID: \(windowID)) owned by PID: \(pid)") } } } // Get window bounds if let bounds = WindowInfoHelper.getWindowBounds(windowID: 12345) { print("Window bounds: \(bounds)") } } // MARK: - Example 8: Using AXValue Extensions @MainActor func exampleAXValueExtensions() { guard let window = AXUIElement.focusedWindowInFocusedApplication() else { return } var value: CFTypeRef? let error = AXUIElementCopyAttributeValue(window, kAXPositionAttribute as CFString, &value) if error == .success, let axValue = value as? AXValue { // Old way: // var point = CGPoint.zero // AXValueGetValue(axValue, .cgPoint, &point) // New way: if let point = axValue.cgPoint() { print("Window position: \(point)") } // Or use generic value() method if let anyValue = axValue.value() { print("Value: \(anyValue)") } } } // MARK: - Example 9: Batch Operations with Better Error Handling @MainActor func exampleBatchOperations() { guard let app = frontmostApplicationElement() else { return } // Get multiple attributes efficiently let attributesToCheck = [ (attr: Attribute<String>.title, name: "Title"), (attr: Attribute<String>.role, name: "Role"), (attr: Attribute<Bool>.enabled, name: "Enabled"), (attr: Attribute<Bool>.focused, name: "Focused"), ] for (attribute, name) in attributesToCheck { if let value = app.attribute(attribute) { print("\(name): \(value)") } } } // MARK: - Example 10: Using Running Application Helper func exampleRunningApplications() { // Get all running applications let allApps = RunningApplicationHelper.allApplications() print("Running applications: \(allApps.count)") // Find specific app by bundle ID let safariApps = RunningApplicationHelper.applications(withBundleIdentifier: "com.apple.Safari") if !safariApps.isEmpty { print("Safari is running") } // Get current app info let currentPID = RunningApplicationHelper.currentPID print("Current app PID: \(currentPID)") } // MARK: - Main Example Runner @MainActor func runAllExamples() async { print("=== Static Factory Methods ===") exampleStaticFactoryMethods() print("\n=== Convenience Attributes ===") exampleConvenienceAttributes() print("\n=== Observer Center ===") exampleObserverCenter() print("\n=== Modern Actions ===") exampleModernActions() print("\n=== Error Handling ===") exampleErrorHandling() print("\n=== Permissions ===") await examplePermissions() print("\n=== Window Info ===") exampleWindowInfo() print("\n=== AXValue Extensions ===") exampleAXValueExtensions() print("\n=== Batch Operations ===") exampleBatchOperations() print("\n=== Running Applications ===") exampleRunningApplications() }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/steipete/Peekaboo'

If you have feedback or need assistance with the MCP directory API, please join our Discord server