diff --git a/agent-core/src/lib.rs b/agent-core/src/lib.rs index f30de67..adf6056 100644 --- a/agent-core/src/lib.rs +++ b/agent-core/src/lib.rs @@ -63,6 +63,16 @@ pub trait InputInjector: Send + Sync + 'static { units.len() ); } + + /// 协议 v4 的相对鼠标移动(单位:被控端桌面物理像素)。 + /// + /// 与 [`InputInjector::text`] 同一条纪律:**默认实现不注入,但必须留下可见痕迹**。 + /// Linux/X11 后端本轮未实现相对移动(XTest 的相对语义要自己维护指针状态, + /// 与 Windows 的 `GetCursorPos`+绝对注入不同构,另立循环)。用户用相对模式 + /// 操作 Linux 被控端时「指针纹丝不动」不能是静默的,日志必须说明是没实现。 + fn mouse_move_rel(&self, dx: i16, dy: i16) { + eprintln!("[agent-core] 相对鼠标注入未实现(忽略 dx={dx} dy={dy})"); + } } /// 把一条协议输入事件分发到注入后端。 @@ -85,6 +95,9 @@ pub fn dispatch_input(inj: &dyn InputInjector, ev: InputEvent) { } inj.text(&units); } + // v4:相对移动原样下发(含负值)。clamp 与像素换算由注入后端负责—— + // 只有它知道被控端桌面的真实像素尺寸(`agent-core` 是平台无关层)。 + InputEvent::MouseMoveRel { dx, dy } => inj.mouse_move_rel(dx, dy), } } @@ -588,6 +601,47 @@ mod tests { ); } + /// v4:相对移动必须被分发,**负值原样到达后端**(负值是相对语义的核心, + /// 绝对坐标是无符号的,这条路径是新引入的有符号通道)。 + #[test] + fn rel_move_reaches_backend_with_signed_deltas() { + struct RelInjector { + got: Mutex>, + } + impl InputInjector for RelInjector { + fn mouse_move(&self, _x: u16, _y: u16) {} + fn mouse_button(&self, _b: MouseButton, _down: bool) {} + fn wheel(&self, _dy: i32) {} + fn key(&self, _s: u16, _e: bool, _d: bool) {} + fn mouse_move_rel(&self, dx: i16, dy: i16) { + self.got.lock().unwrap().push((dx, dy)); + } + } + let inj = RelInjector { + got: Mutex::new(Vec::new()), + }; + dispatch_input(&inj, InputEvent::MouseMoveRel { dx: 12, dy: -34 }); + dispatch_input(&inj, InputEvent::MouseMoveRel { dx: -1, dy: 0 }); + assert_eq!( + *inj.got.lock().unwrap(), + vec![(12, -34), (-1, 0)], + "相对增量(含负值)必须原样到达注入后端" + ); + } + + /// 后端**没有**实现 mouse_move_rel 时不得 panic,且相对事件不得被误路由成 + /// 绝对移动(Linux/X11 后端的真实形态:默认实现 + 日志)。 + #[test] + fn rel_move_default_backend_does_not_panic() { + let inj = MockInjector::default(); + dispatch_input(&inj, InputEvent::MouseMoveRel { dx: 5, dy: 5 }); + // 默认实现只打日志,不应产生任何注入调用(尤其不能变成 move/绝对移动) + assert!( + inj.take().is_empty(), + "默认实现不得把相对移动降级成绝对移动" + ); + } + /// v3 关键回归:`Text` 必须被分发,且**后端没有实现 text() 时不能 panic**。 /// 这是 Linux/X11 后端的真实形态——用户对着 Linux 被控端打字会走到这里。 #[test]