import Cocoa import FlutterMacOS import CoreGraphics @main class AppDelegate: FlutterAppDelegate { private var inputChannel: FlutterMethodChannel? override func applicationDidFinishLaunching(_ notification: Notification) { guard let window = mainFlutterWindow, let ctrl = window.contentViewController as? FlutterViewController else { return } inputChannel = FlutterMethodChannel( name: "com.pulsar/input", binaryMessenger: ctrl.engine.binaryMessenger ) inputChannel?.setMethodCallHandler { [weak self] call, result in if call.method == "injectInput", let args = call.arguments as? [String: Any] { self?.injectInput(args) result(nil) } else { result(FlutterMethodNotImplemented) } } } private func injectInput(_ ev: [String: Any]) { guard let type = ev["type"] as? String else { return } let screen = NSScreen.main?.frame ?? CGRect(x: 0, y: 0, width: 1920, height: 1080) switch type { case "move": let nx = ev["x"] as? Double ?? 0 let ny = ev["y"] as? Double ?? 0 // CoreGraphics origin is top-left on screen, NSScreen origin is bottom-left let px = CGFloat(nx) * screen.width let py = CGFloat(ny) * screen.height let pt = CGPoint(x: px, y: py) CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: pt, mouseButton: .left)? .post(tap: .cghidEventTap) case "click": let nx = ev["x"] as? Double ?? 0 let ny = ev["y"] as? Double ?? 0 let btn = ev["button"] as? Int ?? 0 let px = CGFloat(nx) * screen.width let py = CGFloat(ny) * screen.height let pt = CGPoint(x: px, y: py) let (downType, upType, mouseBtn): (CGEventType, CGEventType, CGMouseButton) = btn == 1 ? (.rightMouseDown, .rightMouseUp, .right) : (.leftMouseDown, .leftMouseUp, .left) CGEvent(mouseEventSource: nil, mouseType: downType, mouseCursorPosition: pt, mouseButton: mouseBtn)? .post(tap: .cghidEventTap) CGEvent(mouseEventSource: nil, mouseType: upType, mouseCursorPosition: pt, mouseButton: mouseBtn)? .post(tap: .cghidEventTap) case "keydown": if let code = ev["keyCode"] as? Int { CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(code & 0xFFFF), keyDown: true)? .post(tap: .cghidEventTap) } case "keyup": if let code = ev["keyCode"] as? Int { CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(code & 0xFFFF), keyDown: false)? .post(tap: .cghidEventTap) } default: break } } override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { return true } }