diff --git a/src/session.rs b/src/session.rs index 5ec247b..db3fafb 100644 --- a/src/session.rs +++ b/src/session.rs @@ -23,6 +23,23 @@ pub struct Session { pub vfx_source: Option, pub mouse_broadcast: bool, pub mouse_follow: bool, + /// Per-button press-and-hold repeat state. Keyed by Linux input + /// event code (272 = BTN_LEFT, 273 = BTN_RIGHT). Cancelled when + /// the matching `mouse-release` IPC verb arrives. + pub mouse_repeats: std::collections::HashMap, + /// Cadence in milliseconds between repeat clicks while a button is + /// held. Tunable via `ENBOXER_MOUSE_REPEAT_MS`; defaults to 50 ms + /// (20 Hz) which feels responsive without saturating the IPC socket. + pub mouse_repeat_ms: u64, +} + +/// Per-button repeat-loop handle + cancel signal. Holding the cancel +/// `Arc` in the Session lets the release path flip it +/// without holding the Session mutex; the worker checks the bit at +/// each cadence tick and exits cleanly. +pub struct RepeatState { + pub cancel: std::sync::Arc, + pub handle: Option>, } impl Session { @@ -37,6 +54,12 @@ impl Session { vfx_source: None, mouse_broadcast: false, mouse_follow: false, + mouse_repeats: std::collections::HashMap::new(), + mouse_repeat_ms: std::env::var("ENBOXER_MOUSE_REPEAT_MS") + .ok() + .and_then(|s| s.parse::().ok()) + .filter(|&n| (1..=2000).contains(&n)) + .unwrap_or(50), }) } } @@ -804,10 +827,124 @@ pub fn others_clients(slots: &[(u32, Client)], leader: u32) -> Vec { /// click are forwarded from the cursor position in /// `broadcast_mirror_click`. /// -/// Press-and-hold guard is OUT OF SCOPE for T13 (Master has not requested -/// it yet); the caller should hold the mouse binds as a follow-up. -/// T13-todo: press-and-hold guard — repeated button-down without release -/// should re-fire on a configurable cadence. +/// Handle the IPC verb `mouse-press