cueward-adapter-macos 0.5.0

macOS adapter for Cueward with Safari, Notes, Messages, Reminders, Calendar, Screenshot, Clipboard, and OCR integrations.
import AppKit
import Foundation

// A disposable receiver. It uses ordinary AppKit controls and event dispatch.
let stateURL = URL(fileURLWithPath: CommandLine.arguments[1])
let mode = CommandLine.arguments.dropFirst(2).first
let interrupt = mode == "interrupt"
final class InputWindow: NSWindow {
    override func accessibilityTitle() -> String? {
        mode == "ax-title-missing" ? nil : super.accessibilityTitle()
    }
}
let app = NSApplication.shared
app.setActivationPolicy(.accessory)
var windows: [NSWindow] = []
var editors: [NSTextView] = []
var scrollViews: [NSScrollView] = []
var events: [[String: Any]] = []
let menu = NSMenu()
let edit = NSMenuItem(title: "Edit", action: nil, keyEquivalent: "")
let editMenu = NSMenu(title: "Edit")
let selectAll = editMenu.addItem(withTitle: "Select All", action: #selector(NSText.selectAll(_:)), keyEquivalent: "a")
edit.submenu = editMenu
menu.addItem(edit)
app.mainMenu = menu

for index in 0..<2 {
    let frame = NSRect(x: 100 + index * 60, y: 120, width: 400, height: 280)
    let window = InputWindow(contentRect: frame, styleMask: [.titled, .closable], backing: .buffered, defer: false)
    window.title = "Cueward input fixture \(index)"
    window.isReleasedWhenClosed = false
    let scroll = NSScrollView(frame: NSRect(origin: .zero, size: frame.size))
    scroll.hasVerticalScroller = true
    let editor = NSTextView(frame: NSRect(x: 0, y: 0, width: 380, height: 1800))
    editor.isRichText = false
    editor.isAutomaticQuoteSubstitutionEnabled = false
    editor.isAutomaticDashSubstitutionEnabled = false
    editor.font = NSFont.systemFont(ofSize: 18)
    if index == 0 { editor.string = (1...100).map { "Disposable line \($0)" }.joined(separator: "\n") }
    scroll.documentView = editor
    window.contentView = scroll
    window.makeFirstResponder(editor)
    selectAll.target = editor
    windows.append(window)
    editors.append(editor)
    scrollViews.append(scroll)
    window.orderFront(nil)
}

let monitor = NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .keyUp, .scrollWheel]) { event in
    events.append([
        "type": event.type.rawValue, "window": event.windowNumber,
        "tag": event.cgEvent?.getIntegerValueField(.eventSourceUserData) ?? 0,
        "flags": event.modifierFlags.rawValue,
    ])
    return event
}
func save() {
    if interrupt && editors[1].string.count >= 10 { windows[1].title = "Changed input fixture" }
    let state: [String: Any] = [
        "windows": windows.map { $0.windowNumber }, "texts": editors.map { $0.string },
        "titles": windows.map { $0.title },
        "scroll_y": scrollViews.map { $0.contentView.bounds.origin.y },
        "events": events, "active": app.isActive,
    ]
    if let data = try? JSONSerialization.data(withJSONObject: state) { try? data.write(to: stateURL, options: .atomic) }
}
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { _ in save() }
DispatchQueue.main.asyncAfter(deadline: .now() + 90) { app.terminate(nil) }
save()
app.run()