Mission Control Turbo: macOS multitasking turbocharged
at main 96 lines 4.1 kB view raw
1import AppKit 2import ApplicationServices 3 4/// Bridge to macOS Accessibility APIs for window activation and title retrieval. 5enum AccessibilityBridge { 6 /// Check if we have Accessibility permission. 7 static var hasPermission: Bool { 8 AXIsProcessTrusted() 9 } 10 11 /// Prompt the user to grant Accessibility permission if not already granted. 12 static func requestPermissionIfNeeded() { 13 let options = [kAXTrustedCheckOptionPrompt.takeUnretainedValue(): true] as CFDictionary 14 AXIsProcessTrustedWithOptions(options) 15 } 16 17 /// Activate the window with the given window ID and PID. 18 static func activateWindow(pid: pid_t, windowID: CGWindowID) -> Bool { 19 guard let app = NSRunningApplication(processIdentifier: pid) else { return false } 20 21 // Activate the application 22 app.activate() 23 24 // Use Accessibility to raise the specific window 25 let appElement = AXUIElementCreateApplication(pid) 26 var windowsRef: CFTypeRef? 27 let result = AXUIElementCopyAttributeValue(appElement, kAXWindowsAttribute as CFString, &windowsRef) 28 guard result == .success, let axWindows = windowsRef as? [AXUIElement] else { 29 return true // App activated but couldn't raise specific window 30 } 31 32 for axWindow in axWindows { 33 if let cgWindowID = axWindowID(for: axWindow), cgWindowID == windowID { 34 AXUIElementPerformAction(axWindow, kAXRaiseAction as CFString) 35 return true 36 } 37 } 38 39 return true 40 } 41 42 /// Get the title of a window via Accessibility (fallback when CGWindowList doesn't have it). 43 static func windowTitle(pid: pid_t, windowID: CGWindowID) -> String? { 44 let appElement = AXUIElementCreateApplication(pid) 45 var windowsRef: CFTypeRef? 46 let result = AXUIElementCopyAttributeValue(appElement, kAXWindowsAttribute as CFString, &windowsRef) 47 guard result == .success, let axWindows = windowsRef as? [AXUIElement] else { 48 return nil 49 } 50 51 for axWindow in axWindows { 52 if let cgWinID = axWindowID(for: axWindow), cgWinID == windowID { 53 var titleRef: CFTypeRef? 54 let titleResult = AXUIElementCopyAttributeValue(axWindow, kAXTitleAttribute as CFString, &titleRef) 55 if titleResult == .success, let title = titleRef as? String { 56 return title 57 } 58 } 59 } 60 return nil 61 } 62 63 /// Move a window to a new position using AXUIElement. 64 /// The point should be in Quartz coordinates (top-left origin). 65 static func moveWindow(pid: pid_t, windowID: CGWindowID, to point: CGPoint) -> Bool { 66 let appElement = AXUIElementCreateApplication(pid) 67 var windowsRef: CFTypeRef? 68 let result = AXUIElementCopyAttributeValue(appElement, kAXWindowsAttribute as CFString, &windowsRef) 69 guard result == .success, let axWindows = windowsRef as? [AXUIElement] else { 70 return false 71 } 72 73 for axWindow in axWindows { 74 if let cgWinID = axWindowID(for: axWindow), cgWinID == windowID { 75 var position = point 76 guard let axValue = AXValueCreate(.cgPoint, &position) else { return false } 77 let setResult = AXUIElementSetAttributeValue(axWindow, kAXPositionAttribute as CFString, axValue) 78 return setResult == .success 79 } 80 } 81 return false 82 } 83 84 // MARK: - Private 85 86 /// Map an AXUIElement to a CGWindowID using the private _AXUIElementGetWindow API. 87 private static func axWindowID(for element: AXUIElement) -> CGWindowID? { 88 var windowID: CGWindowID = 0 89 let result = _AXUIElementGetWindow(element, &windowID) 90 return result == .success ? windowID : nil 91 } 92} 93 94// Private API declaration widely used by AltTab, Rectangle, yabai, etc. 95@_silgen_name("_AXUIElementGetWindow") 96func _AXUIElementGetWindow(_ element: AXUIElement, _ windowID: UnsafeMutablePointer<CGWindowID>) -> AXError