From 91aebbc1178220ba6af0e5b858a23eae64efa907 Mon Sep 17 00:00:00 2001 From: Jinwook Jeong Date: Tue, 31 Mar 2026 01:17:59 +0900 Subject: [PATCH] remember last cursor position per monitor on focus switch --- Sources/MonitorManager.swift | 19 ++++++++++++------- Sources/main.swift | 6 +++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Sources/MonitorManager.swift b/Sources/MonitorManager.swift index eec7a65..cfd062b 100644 --- a/Sources/MonitorManager.swift +++ b/Sources/MonitorManager.swift @@ -188,30 +188,35 @@ enum MonitorManager { return cursorMonitor == id ? .none : .moveAndClick } - static func focusMonitor(_ id: Int, transition: MonitorTransition, debug: Bool = false) { + static func focusMonitor(_ id: Int, transition: MonitorTransition, restorePoint: CGPoint? = nil, debug: Bool = false) { guard transition.requiresAction else { return } let displayID = CGDirectDisplayID(id) let bounds = CGDisplayBounds(displayID) - let center = CGPoint(x: bounds.midX, y: bounds.midY) + let targetPoint: CGPoint + if let rp = restorePoint, bounds.contains(rp) { + targetPoint = rp + } else { + targetPoint = CGPoint(x: bounds.midX, y: bounds.midY) + } if debug { let cursorBefore = CGEvent(source: nil)?.location ?? .zero - CLI.debug("[EXEC] display=\(displayID) bounds=\(bounds) center=\(center) cursorBefore=\(cursorBefore) transition=\(transition)") + CLI.debug("[EXEC] display=\(displayID) bounds=\(bounds) target=\(targetPoint) cursorBefore=\(cursorBefore) transition=\(transition)") } if transition == .move || transition == .moveAndClick { - CGWarpMouseCursorPosition(center) + CGWarpMouseCursorPosition(targetPoint) if debug { let cursorAfterWarp = CGEvent(source: nil)?.location ?? .zero - CLI.debug("[WARP] target=\(center) cursorAfterWarp=\(cursorAfterWarp)") + CLI.debug("[WARP] target=\(targetPoint) cursorAfterWarp=\(cursorAfterWarp)") } } if transition.appliesFocus { let clickPos = transition == .click - ? CGEvent(source: nil)?.location ?? center - : center + ? CGEvent(source: nil)?.location ?? targetPoint + : targetPoint let mouseDown = CGEvent(mouseEventSource: nil, mouseType: .leftMouseDown, mouseCursorPosition: clickPos, mouseButton: .left) let mouseUp = CGEvent(mouseEventSource: nil, mouseType: .leftMouseUp, mouseCursorPosition: clickPos, mouseButton: .left) diff --git a/Sources/main.swift b/Sources/main.swift index 8fdf74c..370e943 100644 --- a/Sources/main.swift +++ b/Sources/main.swift @@ -158,6 +158,7 @@ var lastAppliedGazeMonitor = gazeMonitor let switchCooldown: TimeInterval = 0.5 // minimum seconds between switches var lastSwitchTime = Date.distantPast var trackingEnabled = true +var lastCursorPosition: [Int: CGPoint] = [:] while running { // Check for double-blink toggle @@ -209,8 +210,11 @@ while running { if transition.requiresAction { let now = Date() if now.timeIntervalSince(lastSwitchTime) >= switchCooldown { + if let fromMonitor = cursorMonitor, let loc = CGEvent(source: nil)?.location { + lastCursorPosition[fromMonitor] = loc + } let name = monitors.first { $0.id == target }?.name ?? "?" - MonitorManager.focusMonitor(target, transition: transition, debug: config.debug) + MonitorManager.focusMonitor(target, transition: transition, restorePoint: lastCursorPosition[target], debug: config.debug) lastAppliedGazeMonitor = target lastSwitchTime = now CLI.printFocusSwitch(name)