import Foundation import CoreGraphics final class InputService: @unchecked Sendable { func moveMouse(point: CGPoint) throws { guard let source = CGEventSource(stateID: .combinedSessionState) else { throw ComputerUseError.eventSourceFailed } guard let event = CGEvent(mouseEventSource: source, mouseType: .mouseMoved, mouseCursorPosition: point, mouseButton: .left) else { throw ComputerUseError.eventCreationFailed } event.post(tap: .cghidEventTap) } func click(point: CGPoint, doubleClick: Bool = false) async throws { guard let source = CGEventSource(stateID: .combinedSessionState) else { throw ComputerUseError.eventSourceFailed } if let move = CGEvent(mouseEventSource: source, mouseType: .mouseMoved, mouseCursorPosition: point, mouseButton: .left) { move.post(tap: .cghidEventTap) } try await Task.sleep(nanoseconds: 50_000_000) let count = doubleClick ? 2 : 1 for clickState in 1...count { guard let down = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: point, mouseButton: .left), let up = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: point, mouseButton: .left) else { throw ComputerUseError.eventCreationFailed } down.setIntegerValueField(.mouseEventClickState, value: Int64(clickState)) up.setIntegerValueField(.mouseEventClickState, value: Int64(clickState)) down.post(tap: .cghidEventTap) up.post(tap: .cghidEventTap) } } func typeText(_ text: String) throws { guard let source = CGEventSource(stateID: .combinedSessionState) else { throw ComputerUseError.eventSourceFailed } let units = Array(text.utf16) for start in stride(from: 0, to: units.count, by: 20) { let end = min(start + 20, units.count) let chunk = Array(units[start..= 2 else { return } guard let source = CGEventSource(stateID: .combinedSessionState) else { throw ComputerUseError.eventSourceFailed } guard let down = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: path[0], mouseButton: .left) else { throw ComputerUseError.eventCreationFailed } down.post(tap: .cghidEventTap) for point in path.dropFirst().dropLast() { if let drag = CGEvent(mouseEventSource: source, mouseType: .leftMouseDragged, mouseCursorPosition: point, mouseButton: .left) { drag.post(tap: .cghidEventTap) } try await Task.sleep(nanoseconds: 12_000_000) } guard let last = path.last, let up = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: last, mouseButton: .left) else { throw ComputerUseError.eventCreationFailed } up.post(tap: .cghidEventTap) } }