67 lines
3.5 KiB
Swift
67 lines
3.5 KiB
Swift
import AppKit
|
|
import ApplicationServices
|
|
import ScreenCaptureKit
|
|
|
|
let orionBundle = "com.kagi.kagimacOS"
|
|
|
|
func permission(_ name: String, _ status: String, _ detail: String, _ pane: String) -> [String: String] {
|
|
return ["name": name, "status": status, "detail": detail, "settings": "x-apple.systempreferences:com.apple.preference.security?Privacy_\(pane)"]
|
|
}
|
|
|
|
func checkScreenRecording() async -> [String: String] {
|
|
do {
|
|
let content = try await withDisplayAwake { try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true) }
|
|
return permission("Screen Recording", "granted", "Listed the screen (displays: \(content.displays.count), windows: \(content.windows.count)).", "ScreenCapture")
|
|
} catch {
|
|
CGRequestScreenCaptureAccess()
|
|
return permission("Screen Recording", "missing", "Listing the screen failed (\(error.localizedDescription)). Switch byre on in Screen Recording.", "ScreenCapture")
|
|
}
|
|
}
|
|
|
|
func checkAccessibility() -> [String: String] {
|
|
if !AXIsProcessTrustedWithOptions([kAXTrustedCheckOptionPrompt.takeUnretainedValue(): true] as CFDictionary) {
|
|
return permission("Accessibility", "missing", "Switch byre on in Accessibility.", "Accessibility")
|
|
}
|
|
guard let finder = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.finder").first else {
|
|
return permission("Accessibility", "unchecked", "Granted, but Finder isn't running to read its menu bar.", "Accessibility")
|
|
}
|
|
do {
|
|
guard let bar = try attr(appElement(finder.processIdentifier), kAXMenuBarAttribute) else {
|
|
return permission("Accessibility", "missing", "Granted, but reading Finder's menu bar returned nothing. Switch byre off and on again in Accessibility.", "Accessibility")
|
|
}
|
|
return permission("Accessibility", "granted", "Read Finder's menu bar (menus: \(try children(bar as! AXUIElement).count)).", "Accessibility")
|
|
} catch let e as ToolError {
|
|
return permission("Accessibility", "missing", e.message, "Accessibility")
|
|
} catch {
|
|
return permission("Accessibility", "missing", "\(error)", "Accessibility")
|
|
}
|
|
}
|
|
|
|
func checkOrion() -> [String: String] {
|
|
if NSRunningApplication.runningApplications(withBundleIdentifier: orionBundle).isEmpty {
|
|
return permission("Automation of Orion", "unchecked", "Orion isn't running; open it and check again.", "Automation")
|
|
}
|
|
let target = NSAppleEventDescriptor(bundleIdentifier: orionBundle)
|
|
let status = AEDeterminePermissionToAutomateTarget(target.aeDesc, typeWildCard, typeWildCard, true)
|
|
if status != noErr {
|
|
return permission("Automation of Orion", "missing", "macOS refused Apple events to Orion (\(status)). Switch Orion on under byre in Automation.", "Automation")
|
|
}
|
|
do {
|
|
let windows = try osa("tell application \"Orion\" to count windows").int32Value
|
|
return permission("Automation of Orion", "granted", "Orion answered (windows: \(windows)).", "Automation")
|
|
} catch let e as ToolError {
|
|
return permission("Automation of Orion", "missing", e.message, "Automation")
|
|
} catch {
|
|
return permission("Automation of Orion", "missing", "\(error)", "Automation")
|
|
}
|
|
}
|
|
|
|
func runCheck() {
|
|
Task.detached {
|
|
let rows = [await checkScreenRecording(), checkAccessibility(), checkOrion()]
|
|
let out = try! JSONSerialization.data(withJSONObject: rows, options: .withoutEscapingSlashes)
|
|
FileHandle.standardOutput.write(out + Data("\n".utf8))
|
|
exit(0)
|
|
}
|
|
}
|