keyboard: Fix repeat deadline handling

The calloop timer is only responsible for ensuring wakeup at the right
time, but we can also be woken up before time so we need to check the
deadline.

At the same time, We may end up being significantly delayed past the
deadline if something else was slow. If we are too far behind, reset the
base of the repeat timer by just offsetting from the current time.
This commit is contained in:
Kenny Levinsen
2024-01-30 00:56:12 +01:00
parent 7ee58d8d68
commit 5776886884
+19 -8
View File
@@ -64,7 +64,7 @@ impl EventSource for KeyRepeatSource {
let mut reregister = false; let mut reregister = false;
let mut next_deadline = std::time::Instant::now(); let now = std::time::Instant::now();
// Check if the key repeat should stop // Check if the key repeat should stop
let channel_pa = self let channel_pa = self
@@ -78,9 +78,7 @@ impl EventSource for KeyRepeatSource {
WEnum::Value(wl_keyboard::KeyState::Pressed) => { WEnum::Value(wl_keyboard::KeyState::Pressed) => {
key.replace(event); key.replace(event);
reregister = true; reregister = true;
timer.set_deadline(now + *delay);
next_deadline = std::time::Instant::now() + *delay;
timer.set_deadline(next_deadline);
} }
WEnum::Value(wl_keyboard::KeyState::Released) => match key { WEnum::Value(wl_keyboard::KeyState::Released) => match key {
Some(k) if k.keysym == event.keysym => { Some(k) if k.keysym == event.keysym => {
@@ -95,8 +93,7 @@ impl EventSource for KeyRepeatSource {
*delay = Duration::from_millis(new_delay as u64); *delay = Duration::from_millis(new_delay as u64);
*disabled = false; *disabled = false;
if key.is_some() { if key.is_some() {
next_deadline = std::time::Instant::now() + *delay; timer.set_deadline(now + *delay);
timer.set_deadline(next_deadline);
} }
} }
}, },
@@ -117,14 +114,28 @@ impl EventSource for KeyRepeatSource {
return Ok(PostAction::Reregister); return Ok(PostAction::Reregister);
} }
let timer_pa = timer.process_events(readiness, token, |_event, _| { let timer_pa = timer.process_events(readiness, token, |deadline, _| {
if self.disabled || key.is_none() { if self.disabled || key.is_none() {
return TimeoutAction::Drop; return TimeoutAction::Drop;
} }
if deadline - now > std::time::Duration::from_millis(5) {
// We have not yet reached the deadline within our tolerance
return TimeoutAction::ToInstant(deadline);
}
// Invoke the event // Invoke the event
callback(key.as_ref().unwrap().clone(), &mut ()); callback(key.as_ref().unwrap().clone(), &mut ());
next_deadline += *rate;
let mut next_deadline = deadline;
if now - deadline > *rate * 2 {
// We're way behind, let's just set a new time
println!("KeyRepeatSource::process_events: More than two repeat cycles behind, resetting");
next_deadline = now + *rate;
} else {
while next_deadline < now {
next_deadline += *rate;
}
}
TimeoutAction::ToInstant(next_deadline) TimeoutAction::ToInstant(next_deadline)
})?; })?;