fix: dual-timeout held keys to fix terminal initial repeat delay

Root cause: terminals wait 300-500ms after initial Press before
sending the first Repeat event. With 60ms timeout, the key was
released during this gap, causing step-pause-accelerate pattern.

Fix: two timeout phases:
- After Press (no Repeat seen yet): 400ms timeout
  Covers terminal's initial repeat delay, key stays held
- After first Repeat: 80ms timeout
  Repeats arrive every ~30ms, 80ms is safe margin
  Quick release detection once repeating starts

Result: smooth continuous movement from first keypress, no gap
This commit is contained in:
Emil
2026-06-20 23:43:31 +03:00
parent 9458d265f0
commit 61e2cf1544
+16 -6
View File
@@ -44,9 +44,11 @@ pub enum HeldKey {
struct HeldState {
last_seen: Instant,
seen_repeat: bool,
}
const HOLD_TIMEOUT: Duration = Duration::from_millis(60);
const HOLD_TIMEOUT_PRESS: Duration = Duration::from_millis(400);
const HOLD_TIMEOUT_REPEAT: Duration = Duration::from_millis(80);
pub struct InputHandler {
pub paint_brush: MaterialBrush,
@@ -102,8 +104,11 @@ impl InputHandler {
}
}
fn mark_held(&mut self, key: HeldKey) {
self.held.insert(key, HeldState { last_seen: Instant::now() });
fn mark_held(&mut self, key: HeldKey, is_repeat: bool) {
self.held.insert(key, HeldState {
last_seen: Instant::now(),
seen_repeat: is_repeat,
});
}
fn release(&mut self, key: HeldKey) {
@@ -119,7 +124,10 @@ impl InputHandler {
self.jump_pressed = false;
let now = Instant::now();
self.held.retain(|_, state| now.duration_since(state.last_seen) < HOLD_TIMEOUT);
self.held.retain(|_, state| {
let timeout = if state.seen_repeat { HOLD_TIMEOUT_REPEAT } else { HOLD_TIMEOUT_PRESS };
now.duration_since(state.last_seen) < timeout
});
let events: Vec<Event> = match &self.receiver {
Some(rx) => rx.try_iter().collect(),
@@ -163,8 +171,10 @@ impl InputHandler {
}
if let Some(held_key) = Self::key_to_held(code) {
if is_press || is_repeat {
self.mark_held(held_key);
if is_press {
self.mark_held(held_key, false);
} else if is_repeat {
self.mark_held(held_key, true);
} else if is_release {
self.release(held_key);
}