diff --git a/crates/adapters/src/wayland/shell_adapter.rs b/crates/adapters/src/wayland/shell_adapter.rs index fa3ef98..01d6ac5 100644 --- a/crates/adapters/src/wayland/shell_adapter.rs +++ b/crates/adapters/src/wayland/shell_adapter.rs @@ -77,7 +77,8 @@ impl WaylandShellSystem { let event_loop = EventLoop::try_new().map_err(|e| EventLoopError::Creation { source: e })?; - let state = Self::init_state(config, &connection, &mut event_queue)?; + let mut state = Self::init_state(config, &connection, &mut event_queue)?; + state.set_loop_handle(event_loop.handle()); Ok(Self { state, @@ -100,7 +101,8 @@ impl WaylandShellSystem { let event_loop = EventLoop::try_new().map_err(|e| EventLoopError::Creation { source: e })?; - let state = Self::init_state_multi(configs, &connection, &mut event_queue)?; + let mut state = Self::init_state_multi(configs, &connection, &mut event_queue)?; + state.set_loop_handle(event_loop.handle()); Ok(Self { state, @@ -116,7 +118,8 @@ impl WaylandShellSystem { let event_loop = EventLoop::try_new().map_err(|e| EventLoopError::Creation { source: e })?; - let state = Self::init_state_minimal(&connection, &mut event_queue)?; + let mut state = Self::init_state_minimal(&connection, &mut event_queue)?; + state.set_loop_handle(event_loop.handle()); Ok(Self { state, diff --git a/crates/adapters/src/wayland/surfaces/app_state.rs b/crates/adapters/src/wayland/surfaces/app_state.rs index 8698dba..ca822e3 100644 --- a/crates/adapters/src/wayland/surfaces/app_state.rs +++ b/crates/adapters/src/wayland/surfaces/app_state.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::os::fd::BorrowedFd; use std::rc::Rc; +use std::time::Duration; use layer_shika_domain::entities::output_registry::OutputRegistry; use layer_shika_domain::value_objects::handle::SurfaceHandle; @@ -10,6 +11,9 @@ use layer_shika_domain::value_objects::lock_state::LockState; use layer_shika_domain::value_objects::output_handle::OutputHandle; use layer_shika_domain::value_objects::output_info::OutputInfo; use slint_interpreter::{CompilationResult, ComponentDefinition, Value}; +use smithay_client_toolkit::reexports::calloop::{ + LoopHandle, RegistrationToken, timer::TimeoutAction, timer::Timer, +}; use wayland_client::Proxy; use wayland_client::backend::ObjectId; use wayland_client::protocol::wl_keyboard; @@ -79,6 +83,9 @@ pub struct AppState { lock_callbacks: Vec, lock_property_operations: Vec, queue_handle: Option>, + loop_handle: Option>, + repeat_token: Option, + repeat_key: Option, } impl AppState { @@ -110,6 +117,9 @@ impl AppState { lock_callbacks: Vec::new(), lock_property_operations: Vec::new(), queue_handle: None, + loop_handle: None, + repeat_token: None, + repeat_key: None, } } @@ -130,6 +140,11 @@ impl AppState { self.queue_handle = Some(queue_handle); } + /// handle back into the event loop, used by the repeat timer + pub fn set_loop_handle(&mut self, handle: LoopHandle<'static, AppState>) { + self.loop_handle = Some(handle); + } + pub fn lock_manager(&self) -> Option<&SessionLockManager> { self.lock_manager.as_ref() } @@ -690,6 +705,7 @@ impl AppState { let surface_id = surface.id(); if self.keyboard_input_state.focused_surface_id() == Some(&surface_id) { + self.stop_repeat(); self.keyboard_input_state.reset(); self.set_keyboard_focus(None); } @@ -702,6 +718,20 @@ impl AppState { } } + self.dispatch_key(key, state); + + match state { + wl_keyboard::KeyState::Pressed => self.start_repeat(key), + wl_keyboard::KeyState::Released => { + if self.repeat_key == Some(key) { + self.stop_repeat(); + } + } + _ => {} + } + } + + fn dispatch_key(&mut self, key: u32, state: wl_keyboard::KeyState) { let Some(focus_key) = self.keyboard_focus_key.clone() else { return; }; @@ -714,6 +744,42 @@ impl AppState { } } + fn start_repeat(&mut self, key: u32) { + self.stop_repeat(); + + let Some(handle) = self.loop_handle.clone() else { + return; + }; + + let rate = self.keyboard_state.repeat_rate; + let delay = self.keyboard_state.repeat_delay; + if rate <= 0 || delay < 0 { + return; + } + let interval = Duration::from_millis(1000 / rate as u64); + + self.repeat_key = Some(key); + + let token = handle.insert_source( + Timer::from_duration(Duration::from_millis(delay as u64)), + move |_deadline, _metadata, app_state: &mut AppState| { + if app_state.repeat_key != Some(key) { + return TimeoutAction::Drop; + } + app_state.dispatch_key(key, wl_keyboard::KeyState::Pressed); + TimeoutAction::ToDuration(interval) + }, + ); + self.repeat_token = token.ok(); + } + + fn stop_repeat(&mut self) { + if let (Some(handle), Some(token)) = (&self.loop_handle, self.repeat_token.take()) { + handle.remove(token); + } + self.repeat_key = None; + } + pub fn handle_modifiers( &mut self, _serial: u32,