From f46004b297a05da330e03a50891b843081f362db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Br=C3=B8nner?= Date: Thu, 24 Jul 2025 00:31:57 +0200 Subject: [PATCH 1/2] fix keyrepeat rate by measuring processing time --- crates/gpui/src/platform/linux/wayland/client.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index ee2590aa4dfb9a..43d3682f2e7783 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -1399,6 +1399,7 @@ impl Dispatch for WaylandClientStatePtr { prefer_character_input: false, }); move |_event, _metadata, this| { + let processing_begin = std::time::Instant::now(); let mut client = this.get_client(); let mut state = client.borrow_mut(); let is_repeating = id == state.repeat.current_id @@ -1414,8 +1415,10 @@ impl Dispatch for WaylandClientStatePtr { drop(state); focused_window.handle_input(input.clone()); - - TimeoutAction::ToDuration(Duration::from_secs(1) / rate) + let processing_duration = processing_begin.elapsed(); + log::debug!("Key repeat input handling: {:?}", processing_duration); + let delay = Duration::from_secs(1) / rate; + TimeoutAction::ToDuration((delay - processing_duration).max(Duration::ZERO)) } }) .unwrap(); From 0095bc1eedbff870edcb46dbd7decca5fa95ae53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Br=C3=B8nner?= Date: Sat, 8 Nov 2025 09:53:42 +0100 Subject: [PATCH 2/2] Revise approach This seems like a more elgant way of scheduling the repeats. By simply scheduling the repeats at the exact time we avoid mucking around measuring the processing time. --- Final commit message after squashing: wayland: make key repeat rate exact The effective repeat rate would be slower before since the frame processing was added to the repeat interval. --- crates/gpui/src/platform/linux/wayland/client.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 43d3682f2e7783..730f41300cc058 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -1389,6 +1389,7 @@ impl Dispatch for WaylandClientStatePtr { state.repeat.current_keycode = Some(keycode); let rate = state.repeat.characters_per_second; + let repeat_interval = Duration::from_secs(1) / rate; let id = state.repeat.current_id; state .loop_handle @@ -1398,8 +1399,7 @@ impl Dispatch for WaylandClientStatePtr { is_held: true, prefer_character_input: false, }); - move |_event, _metadata, this| { - let processing_begin = std::time::Instant::now(); + move |event_timestamp, _metadata, this| { let mut client = this.get_client(); let mut state = client.borrow_mut(); let is_repeating = id == state.repeat.current_id @@ -1415,10 +1415,9 @@ impl Dispatch for WaylandClientStatePtr { drop(state); focused_window.handle_input(input.clone()); - let processing_duration = processing_begin.elapsed(); - log::debug!("Key repeat input handling: {:?}", processing_duration); - let delay = Duration::from_secs(1) / rate; - TimeoutAction::ToDuration((delay - processing_duration).max(Duration::ZERO)) + + // If the new scheduled time is in the past the event will repeat as soon as possible + TimeoutAction::ToInstant(event_timestamp + repeat_interval) } }) .unwrap();