From 6d550d871d47d3eba6e7fa5157ac8376031752a6 Mon Sep 17 00:00:00 2001 From: aix Date: Wed, 9 Sep 2026 15:04:34 +0800 Subject: [PATCH] fix: keep portal mouse movement smooth --- MousePortal/Services/PortalService.swift | 31 +++++++------------ ...DisplayConfigurationCoordinatorTests.swift | 4 +-- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/MousePortal/Services/PortalService.swift b/MousePortal/Services/PortalService.swift index 8ffc0b2..ad13e51 100644 --- a/MousePortal/Services/PortalService.swift +++ b/MousePortal/Services/PortalService.swift @@ -353,7 +353,7 @@ class PortalService: ObservableObject { callbackState.updateKeyPressed(with: event.flags.rawValue) } - nonisolated func handleMouseMovedForTap(_ event: CGEvent) -> (target: CGPoint, deltaX: Double, deltaY: Double)? { + nonisolated func handleMouseMovedForTap(_ event: CGEvent) -> CGPoint? { let snapshot = callbackState.snapshot() if snapshot.triggerMode == .withKey && !snapshot.isKeyPressed { @@ -363,8 +363,6 @@ class PortalService: ObservableObject { guard let resolver = snapshot.layoutResolver else { return nil } let mouseLocation = event.location - let deltaX = event.getDoubleValueField(.mouseEventDeltaX) - let deltaY = event.getDoubleValueField(.mouseEventDeltaY) for portal in snapshot.portals where portal.isEnabled { // 通过布局标识解析显示器边界 @@ -377,7 +375,7 @@ class PortalService: ObservableObject { let boundsB = snapshot.displayBoundsCache[portal.lineB.legacyDisplayID ?? 0] { if isPointOnLine(mouseLocation, line: portal.lineA, bounds: boundsA) { if let target = portal.calculateTargetPosition(from: mouseLocation, lineABounds: boundsA, lineBBounds: boundsB) { - return (target, deltaX, deltaY) + return target } } @@ -391,7 +389,7 @@ class PortalService: ObservableObject { color: portal.color ) if let target = reversedPortal.calculateTargetPosition(from: mouseLocation, lineABounds: boundsB, lineBBounds: boundsA) { - return (target, deltaX, deltaY) + return target } } } @@ -400,7 +398,7 @@ class PortalService: ObservableObject { if isPointOnLine(mouseLocation, line: portal.lineA, bounds: boundsA) { if let target = portal.calculateTargetPosition(from: mouseLocation, lineABounds: boundsA, lineBBounds: boundsB) { - return (target, deltaX, deltaY) + return target } } @@ -416,7 +414,7 @@ class PortalService: ObservableObject { color: portal.color ) if let target = reversedPortal.calculateTargetPosition(from: mouseLocation, lineABounds: boundsB, lineBBounds: boundsA) { - return (target, deltaX, deltaY) + return target } } } @@ -486,22 +484,15 @@ private func portalEventCallback( service.handleFlagsChangedForTap(event) case .mouseMoved, .leftMouseDragged: - let result = service.handleMouseMovedForTap(event) - - if let result { - // 方法:不消费事件,直接修改事件位置 - // 同时用底层方式移动光标,不触发加速度重置 - CGAssociateMouseAndMouseCursorPosition(0) - defer { CGAssociateMouseAndMouseCursorPosition(1) } - - // 创建并发送移动事件到目标位置 - if let moveEvent = CGEvent(mouseEventSource: nil, mouseType: type, mouseCursorPosition: result.target, mouseButton: .left) { - moveEvent.setDoubleValueField(.mouseEventDeltaX, value: result.deltaX) - moveEvent.setDoubleValueField(.mouseEventDeltaY, value: result.deltaY) + if let target = service.handleMouseMovedForTap(event) { + // 保留原有的 HID 事件传送手感,但不再切换全局鼠标关联状态。 + if let moveEvent = CGEvent(mouseEventSource: nil, mouseType: type, mouseCursorPosition: target, mouseButton: .left) { + moveEvent.setDoubleValueField(.mouseEventDeltaX, value: event.getDoubleValueField(.mouseEventDeltaX)) + moveEvent.setDoubleValueField(.mouseEventDeltaY, value: event.getDoubleValueField(.mouseEventDeltaY)) moveEvent.post(tap: .cghidEventTap) } - return nil // 消费原始事件 + return nil } default: diff --git a/MousePortalTests/Services/DisplayConfigurationCoordinatorTests.swift b/MousePortalTests/Services/DisplayConfigurationCoordinatorTests.swift index 63ad7e4..413ef99 100644 --- a/MousePortalTests/Services/DisplayConfigurationCoordinatorTests.swift +++ b/MousePortalTests/Services/DisplayConfigurationCoordinatorTests.swift @@ -290,8 +290,8 @@ final class DisplayConfigurationCoordinatorTests: XCTestCase { private func assertTarget(_ portals: PortalService, x: CGFloat, file: StaticString = #filePath, line: UInt = #line) throws { let target = try XCTUnwrap(portals.handleMouseMovedForTap(mouseEvent()), file: file, line: line) - XCTAssertEqual(target.target.x, x, file: file, line: line) - XCTAssertEqual(target.target.y, 50, file: file, line: line) + XCTAssertEqual(target.x, x, file: file, line: line) + XCTAssertEqual(target.y, 50, file: file, line: line) } }