diff --git a/crates/adapters/src/wayland/input/keyboard.rs b/crates/adapters/src/wayland/input/keyboard.rs new file mode 100644 index 0000000..504a56e --- /dev/null +++ b/crates/adapters/src/wayland/input/keyboard.rs @@ -0,0 +1,90 @@ +use crate::wayland::surfaces::keyboard_state::{KeyboardState, keysym_to_text}; +use slint::{SharedString, platform::WindowEvent}; +use wayland_client::{ + Proxy, + backend::ObjectId, + protocol::{wl_keyboard, wl_surface::WlSurface}, +}; +use xkbcommon::xkb; + +use super::state::KeyboardInputState; + +pub trait KeyboardEventTarget { + fn dispatch_event(&self, event: WindowEvent); +} + +pub trait KeyboardSurfaceResolver { + type Target: KeyboardEventTarget; + + fn find_surface(&self, surface_id: &ObjectId) -> Option<&Self::Target>; +} + +pub fn handle_keyboard_enter( + input_state: &mut KeyboardInputState, + resolver: &R, + surface: &WlSurface, +) -> bool { + let surface_id = surface.id(); + if resolver.find_surface(&surface_id).is_some() { + input_state.set_focused_surface(Some(surface_id)); + return true; + } + false +} + +pub fn handle_keyboard_leave(input_state: &mut KeyboardInputState, surface: &WlSurface) -> bool { + let surface_id = surface.id(); + if input_state.focused_surface_id() == Some(&surface_id) { + input_state.set_focused_surface(None); + return true; + } + false +} + +pub fn handle_keyboard_key( + input_state: &KeyboardInputState, + resolver: &R, + key: u32, + state: wl_keyboard::KeyState, + keyboard_state: &mut KeyboardState, +) -> bool { + let Some(surface_id) = input_state.focused_surface_id().cloned() else { + return false; + }; + let Some(target) = resolver.find_surface(&surface_id) else { + return false; + }; + let Some(xkb_state) = keyboard_state.xkb_state.as_mut() else { + return true; + }; + + let keycode = xkb::Keycode::new(key + 8); + let direction = match state { + wl_keyboard::KeyState::Pressed => xkb::KeyDirection::Down, + wl_keyboard::KeyState::Released => xkb::KeyDirection::Up, + _ => return true, + }; + + xkb_state.update_key(keycode, direction); + + let text = xkb_state.key_get_utf8(keycode); + let text = if text.is_empty() { + let keysym = xkb_state.key_get_one_sym(keycode); + keysym_to_text(keysym) + } else { + Some(SharedString::from(text.as_str())) + }; + + let Some(text) = text else { + return true; + }; + + let event = match state { + wl_keyboard::KeyState::Pressed => WindowEvent::KeyPressed { text }, + wl_keyboard::KeyState::Released => WindowEvent::KeyReleased { text }, + _ => return true, + }; + + target.dispatch_event(event); + true +} diff --git a/crates/adapters/src/wayland/input/mod.rs b/crates/adapters/src/wayland/input/mod.rs new file mode 100644 index 0000000..8786756 --- /dev/null +++ b/crates/adapters/src/wayland/input/mod.rs @@ -0,0 +1,7 @@ +pub mod keyboard; +pub mod pointer; +pub mod state; + +pub use keyboard::{KeyboardEventTarget, KeyboardSurfaceResolver}; +pub use pointer::{PointerEventTarget, PointerSurfaceResolver}; +pub use state::{KeyboardInputState, PointerInputState}; diff --git a/crates/adapters/src/wayland/input/pointer.rs b/crates/adapters/src/wayland/input/pointer.rs new file mode 100644 index 0000000..e6d4be9 --- /dev/null +++ b/crates/adapters/src/wayland/input/pointer.rs @@ -0,0 +1,196 @@ +use crate::wayland::surfaces::pointer_utils::wayland_button_to_slint; +use slint::{LogicalPosition, platform::WindowEvent}; +use wayland_client::{ + Proxy, WEnum, + backend::ObjectId, + protocol::{wl_pointer, wl_surface::WlSurface}, +}; + +use super::state::PointerInputState; + +pub trait PointerEventTarget { + fn to_logical_position(&self, surface_x: f64, surface_y: f64) -> LogicalPosition; + fn dispatch_event(&self, event: WindowEvent); +} + +pub trait PointerSurfaceResolver { + type Target: PointerEventTarget; + + fn find_surface(&self, surface_id: &ObjectId) -> Option<&Self::Target>; +} + +pub fn handle_pointer_enter( + input_state: &mut PointerInputState, + resolver: &R, + _serial: u32, + surface: &WlSurface, + surface_x: f64, + surface_y: f64, +) -> bool { + let surface_id = surface.id(); + let Some(target) = resolver.find_surface(&surface_id) else { + return false; + }; + + let position = target.to_logical_position(surface_x, surface_y); + input_state.set_active_surface(Some(surface_id)); + input_state.set_current_position(position); + + target.dispatch_event(WindowEvent::PointerMoved { position }); + true +} + +pub fn handle_pointer_motion( + input_state: &mut PointerInputState, + resolver: &R, + surface_x: f64, + surface_y: f64, +) -> bool { + let Some(surface_id) = input_state.active_surface_id().cloned() else { + return false; + }; + let Some(target) = resolver.find_surface(&surface_id) else { + return false; + }; + + let position = target.to_logical_position(surface_x, surface_y); + input_state.set_current_position(position); + + target.dispatch_event(WindowEvent::PointerMoved { position }); + true +} + +pub fn handle_pointer_leave( + input_state: &mut PointerInputState, + resolver: &R, +) -> bool { + let Some(surface_id) = input_state.active_surface_id().cloned() else { + return false; + }; + + if let Some(target) = resolver.find_surface(&surface_id) { + target.dispatch_event(WindowEvent::PointerExited); + } + + input_state.set_active_surface(None); + true +} + +pub fn handle_pointer_button( + input_state: &PointerInputState, + resolver: &R, + _scale_factor: f32, + _serial: u32, + button: u32, + button_state: WEnum, +) -> bool { + let Some(surface_id) = input_state.active_surface_id() else { + return false; + }; + let Some(target) = resolver.find_surface(surface_id) else { + return false; + }; + + let position = input_state.current_position(); + let slint_button = wayland_button_to_slint(button); + + let event = match button_state { + WEnum::Value(wl_pointer::ButtonState::Pressed) => WindowEvent::PointerPressed { + button: slint_button, + position, + }, + WEnum::Value(wl_pointer::ButtonState::Released) => WindowEvent::PointerReleased { + button: slint_button, + position, + }, + _ => return true, + }; + + target.dispatch_event(event); + true +} + +pub fn handle_axis_source( + input_state: &PointerInputState, + _axis_source: wl_pointer::AxisSource, +) -> bool { + input_state.has_active_surface() +} + +pub fn handle_axis( + input_state: &mut PointerInputState, + axis: wl_pointer::Axis, + value: f64, +) -> bool { + if !input_state.has_active_surface() { + return false; + } + + #[allow(clippy::cast_possible_truncation)] + let delta = value as f32; + + match axis { + wl_pointer::Axis::HorizontalScroll => { + input_state.accumulate_axis_value(delta, 0.0); + } + wl_pointer::Axis::VerticalScroll => { + input_state.accumulate_axis_value(0.0, delta); + } + _ => {} + } + true +} + +pub fn handle_axis_discrete( + input_state: &mut PointerInputState, + axis: wl_pointer::Axis, + discrete: i32, +) -> bool { + if !input_state.has_active_surface() { + return false; + } + + #[allow(clippy::cast_precision_loss)] + let delta = (discrete as f32) * 60.0; + + match axis { + wl_pointer::Axis::HorizontalScroll => { + input_state.accumulate_axis_value(delta, 0.0); + } + wl_pointer::Axis::VerticalScroll => { + input_state.accumulate_axis_value(0.0, delta); + } + _ => {} + } + true +} + +pub fn handle_axis_stop(_input_state: &PointerInputState, _axis: wl_pointer::Axis) -> bool { + true +} + +pub fn handle_pointer_frame( + input_state: &mut PointerInputState, + resolver: &R, +) -> bool { + let Some(surface_id) = input_state.active_surface_id().cloned() else { + return false; + }; + + let (delta_x, delta_y) = input_state.take_accumulated_axis(); + + let Some(target) = resolver.find_surface(&surface_id) else { + return false; + }; + + if delta_x.abs() > f32::EPSILON || delta_y.abs() > f32::EPSILON { + let position = input_state.current_position(); + target.dispatch_event(WindowEvent::PointerScrolled { + position, + delta_x, + delta_y, + }); + } + + true +} diff --git a/crates/adapters/src/wayland/input/state.rs b/crates/adapters/src/wayland/input/state.rs new file mode 100644 index 0000000..118e879 --- /dev/null +++ b/crates/adapters/src/wayland/input/state.rs @@ -0,0 +1,112 @@ +use slint::LogicalPosition; +use wayland_client::backend::ObjectId; + +pub struct PointerInputState { + active_surface_id: Option, + current_position: LogicalPosition, + accumulated_axis_x: f32, + accumulated_axis_y: f32, +} + +impl PointerInputState { + pub const fn new() -> Self { + Self { + active_surface_id: None, + current_position: LogicalPosition::new(0.0, 0.0), + accumulated_axis_x: 0.0, + accumulated_axis_y: 0.0, + } + } + + pub const fn active_surface_id(&self) -> Option<&ObjectId> { + self.active_surface_id.as_ref() + } + + pub fn set_active_surface(&mut self, surface_id: Option) { + self.active_surface_id = surface_id; + } + + pub const fn current_position(&self) -> LogicalPosition { + self.current_position + } + + pub fn set_current_position(&mut self, position: LogicalPosition) { + self.current_position = position; + } + + pub fn accumulate_axis_value(&mut self, delta_x: f32, delta_y: f32) { + self.accumulated_axis_x += delta_x; + self.accumulated_axis_y += delta_y; + } + + pub fn take_accumulated_axis(&mut self) -> (f32, f32) { + let delta_x = self.accumulated_axis_x; + let delta_y = self.accumulated_axis_y; + self.accumulated_axis_x = 0.0; + self.accumulated_axis_y = 0.0; + (delta_x, delta_y) + } + + pub fn reset(&mut self) { + self.active_surface_id = None; + self.current_position = LogicalPosition::new(0.0, 0.0); + self.accumulated_axis_x = 0.0; + self.accumulated_axis_y = 0.0; + } + + pub fn clear_surface_if_matches(&mut self, surface_id: &ObjectId) { + if self.active_surface_id.as_ref() == Some(surface_id) { + self.active_surface_id = None; + } + } + + pub const fn has_active_surface(&self) -> bool { + self.active_surface_id.is_some() + } +} + +impl Default for PointerInputState { + fn default() -> Self { + Self::new() + } +} + +pub struct KeyboardInputState { + focused_surface_id: Option, +} + +impl KeyboardInputState { + pub const fn new() -> Self { + Self { + focused_surface_id: None, + } + } + + pub const fn focused_surface_id(&self) -> Option<&ObjectId> { + self.focused_surface_id.as_ref() + } + + pub fn set_focused_surface(&mut self, surface_id: Option) { + self.focused_surface_id = surface_id; + } + + pub fn reset(&mut self) { + self.focused_surface_id = None; + } + + pub fn clear_surface_if_matches(&mut self, surface_id: &ObjectId) { + if self.focused_surface_id.as_ref() == Some(surface_id) { + self.focused_surface_id = None; + } + } + + pub const fn has_focused_surface(&self) -> bool { + self.focused_surface_id.is_some() + } +} + +impl Default for KeyboardInputState { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/adapters/src/wayland/mod.rs b/crates/adapters/src/wayland/mod.rs index a557459..b780691 100644 --- a/crates/adapters/src/wayland/mod.rs +++ b/crates/adapters/src/wayland/mod.rs @@ -1,6 +1,7 @@ pub(crate) mod config; pub(crate) mod event_handling; pub(crate) mod globals; +pub(crate) mod input; pub(crate) mod managed_proxies; pub mod ops; pub(crate) mod outputs; diff --git a/crates/adapters/src/wayland/session_lock/manager/input_handling.rs b/crates/adapters/src/wayland/session_lock/manager/input_handling.rs index 5b58900..b77ed95 100644 --- a/crates/adapters/src/wayland/session_lock/manager/input_handling.rs +++ b/crates/adapters/src/wayland/session_lock/manager/input_handling.rs @@ -1,87 +1,113 @@ -use crate::wayland::surfaces::keyboard_state::{KeyboardState, keysym_to_text}; -use crate::wayland::surfaces::pointer_utils::wayland_button_to_slint; -use log::info; -use slint::{ - LogicalPosition, SharedString, - platform::{WindowAdapter, WindowEvent}, +use crate::wayland::input::keyboard::{ + handle_keyboard_enter as shared_keyboard_enter, handle_keyboard_key as shared_keyboard_key, + handle_keyboard_leave as shared_keyboard_leave, }; +use crate::wayland::input::pointer::{ + handle_axis as shared_axis, handle_axis_discrete as shared_axis_discrete, + handle_axis_source as shared_axis_source, handle_axis_stop as shared_axis_stop, + handle_pointer_button as shared_pointer_button, handle_pointer_enter as shared_pointer_enter, + handle_pointer_frame as shared_pointer_frame, handle_pointer_leave as shared_pointer_leave, + handle_pointer_motion as shared_pointer_motion, +}; +use crate::wayland::input::{ + KeyboardEventTarget, KeyboardInputState, KeyboardSurfaceResolver, PointerEventTarget, + PointerInputState, PointerSurfaceResolver, +}; +use crate::wayland::surfaces::keyboard_state::KeyboardState; +use slint::{LogicalPosition, platform::WindowEvent}; use wayland_client::{ - Proxy, WEnum, + WEnum, backend::ObjectId, protocol::{wl_keyboard, wl_pointer, wl_surface::WlSurface}, }; -use xkbcommon::xkb; use super::state::ActiveLockSurface; pub(super) struct InputState { - pub active_pointer_surface_id: Option, - pub keyboard_focus_surface_id: Option, - pub current_pointer_position: LogicalPosition, - pub accumulated_axis_x: f32, - pub accumulated_axis_y: f32, + pub pointer: PointerInputState, + pub keyboard: KeyboardInputState, } impl InputState { pub fn new() -> Self { Self { - active_pointer_surface_id: None, - keyboard_focus_surface_id: None, - current_pointer_position: LogicalPosition::new(0.0, 0.0), - accumulated_axis_x: 0.0, - accumulated_axis_y: 0.0, + pointer: PointerInputState::new(), + keyboard: KeyboardInputState::new(), } } pub fn reset(&mut self) { - self.active_pointer_surface_id = None; - self.keyboard_focus_surface_id = None; - self.current_pointer_position = LogicalPosition::new(0.0, 0.0); - self.accumulated_axis_x = 0.0; - self.accumulated_axis_y = 0.0; + self.pointer.reset(); + self.keyboard.reset(); } pub fn clear_surface_refs(&mut self, surface_id: &ObjectId) { - if self.active_pointer_surface_id.as_ref() == Some(surface_id) { - self.active_pointer_surface_id = None; - } - if self.keyboard_focus_surface_id.as_ref() == Some(surface_id) { - self.keyboard_focus_surface_id = None; - } + self.pointer.clear_surface_if_matches(surface_id); + self.keyboard.clear_surface_if_matches(surface_id); } pub const fn has_active_pointer(&self) -> bool { - self.active_pointer_surface_id.is_some() + self.pointer.has_active_surface() } pub const fn has_keyboard_focus(&self) -> bool { - self.keyboard_focus_surface_id.is_some() + self.keyboard.has_focused_surface() + } +} + +impl PointerEventTarget for ActiveLockSurface { + fn to_logical_position(&self, surface_x: f64, surface_y: f64) -> LogicalPosition { + ActiveLockSurface::to_logical_position(self, surface_x, surface_y) + } + + fn dispatch_event(&self, event: WindowEvent) { + ActiveLockSurface::dispatch_event(self, event); + } +} + +impl KeyboardEventTarget for ActiveLockSurface { + fn dispatch_event(&self, event: WindowEvent) { + ActiveLockSurface::dispatch_event(self, event); + } +} + +struct LockSurfaceResolver<'a> { + lock_surfaces: &'a [(ObjectId, ActiveLockSurface)], +} + +impl PointerSurfaceResolver for LockSurfaceResolver<'_> { + type Target = ActiveLockSurface; + + fn find_surface(&self, surface_id: &ObjectId) -> Option<&Self::Target> { + find_surface_by_surface_id(self.lock_surfaces, surface_id) + } +} + +impl KeyboardSurfaceResolver for LockSurfaceResolver<'_> { + type Target = ActiveLockSurface; + + fn find_surface(&self, surface_id: &ObjectId) -> Option<&Self::Target> { + find_surface_by_surface_id(self.lock_surfaces, surface_id) } } pub(super) fn handle_pointer_enter( input_state: &mut InputState, lock_surfaces: &[(ObjectId, ActiveLockSurface)], - _serial: u32, + serial: u32, surface: &WlSurface, surface_x: f64, surface_y: f64, ) -> bool { - let surface_id = surface.id(); - let Some(active_surface) = find_surface_by_surface_id(lock_surfaces, &surface_id) else { - return false; - }; - - let position = active_surface.to_logical_position(surface_x, surface_y); - let window = active_surface.window_rc(); - - input_state.active_pointer_surface_id = Some(surface_id.clone()); - input_state.current_pointer_position = position; - info!("Lock pointer enter on {:?}", surface_id); - window - .window() - .dispatch_event(WindowEvent::PointerMoved { position }); - true + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_pointer_enter( + &mut input_state.pointer, + &resolver, + serial, + surface, + surface_x, + surface_y, + ) } pub(super) fn handle_pointer_motion( @@ -90,80 +116,42 @@ pub(super) fn handle_pointer_motion( surface_x: f64, surface_y: f64, ) -> bool { - let Some(surface_id) = input_state.active_pointer_surface_id.clone() else { - return false; - }; - let Some(active_surface) = find_surface_by_surface_id(lock_surfaces, &surface_id) else { - return false; - }; - - let position = active_surface.to_logical_position(surface_x, surface_y); - let window = active_surface.window_rc(); - - input_state.current_pointer_position = position; - window - .window() - .dispatch_event(WindowEvent::PointerMoved { position }); - true + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_pointer_motion(&mut input_state.pointer, &resolver, surface_x, surface_y) } pub(super) fn handle_pointer_leave( input_state: &mut InputState, lock_surfaces: &[(ObjectId, ActiveLockSurface)], ) -> bool { - let Some(surface_id) = input_state.active_pointer_surface_id.take() else { - return false; - }; - - if let Some(active_surface) = find_surface_by_surface_id(lock_surfaces, &surface_id) { - active_surface.dispatch_event(WindowEvent::PointerExited); - } - true + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_pointer_leave(&mut input_state.pointer, &resolver) } pub(super) fn handle_pointer_button( input_state: &mut InputState, lock_surfaces: &[(ObjectId, ActiveLockSurface)], scale_factor: f32, - _serial: u32, + serial: u32, button: u32, button_state: WEnum, ) -> bool { - let Some(surface_id) = input_state.active_pointer_surface_id.clone() else { - return false; - }; - let Some(active_surface) = find_surface_by_surface_id(lock_surfaces, &surface_id) else { - return false; - }; - - let window = active_surface.window_rc(); - let position = input_state.current_pointer_position; - let slint_button = wayland_button_to_slint(button); - let event = match button_state { - WEnum::Value(wl_pointer::ButtonState::Pressed) => WindowEvent::PointerPressed { - button: slint_button, - position, - }, - WEnum::Value(wl_pointer::ButtonState::Released) => WindowEvent::PointerReleased { - button: slint_button, - position, - }, - _ => return true, - }; - - info!( - "Lock pointer button {:?} at {:?} (scale {})", - button_state, position, scale_factor - ); - window.window().dispatch_event(event); - true + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_pointer_button( + &input_state.pointer, + &resolver, + scale_factor, + serial, + button, + button_state, + ) } pub(super) fn handle_axis_source( input_state: &InputState, - _axis_source: wl_pointer::AxisSource, + axis_source: wl_pointer::AxisSource, ) -> bool { - input_state.active_pointer_surface_id.is_some() + shared_axis_source(&input_state.pointer, axis_source) } pub(super) fn handle_axis( @@ -171,24 +159,7 @@ pub(super) fn handle_axis( axis: wl_pointer::Axis, value: f64, ) -> bool { - if input_state.active_pointer_surface_id.is_none() { - return false; - } - - match axis { - wl_pointer::Axis::HorizontalScroll => { - #[allow(clippy::cast_possible_truncation)] - let delta = value as f32; - input_state.accumulated_axis_x += delta; - } - wl_pointer::Axis::VerticalScroll => { - #[allow(clippy::cast_possible_truncation)] - let delta = value as f32; - input_state.accumulated_axis_y += delta; - } - _ => {} - } - true + shared_axis(&mut input_state.pointer, axis, value) } pub(super) fn handle_axis_discrete( @@ -196,58 +167,19 @@ pub(super) fn handle_axis_discrete( axis: wl_pointer::Axis, discrete: i32, ) -> bool { - if input_state.active_pointer_surface_id.is_none() { - return false; - } - - #[allow(clippy::cast_precision_loss)] - let delta = (discrete as f32) * 60.0; - match axis { - wl_pointer::Axis::HorizontalScroll => { - input_state.accumulated_axis_x += delta; - } - wl_pointer::Axis::VerticalScroll => { - input_state.accumulated_axis_y += delta; - } - _ => {} - } - true + shared_axis_discrete(&mut input_state.pointer, axis, discrete) } -pub(super) fn handle_axis_stop(input_state: &InputState, _axis: wl_pointer::Axis) -> bool { - input_state.active_pointer_surface_id.is_some() +pub(super) fn handle_axis_stop(input_state: &InputState, axis: wl_pointer::Axis) -> bool { + shared_axis_stop(&input_state.pointer, axis) } pub(super) fn handle_pointer_frame( input_state: &mut InputState, lock_surfaces: &[(ObjectId, ActiveLockSurface)], ) -> bool { - let Some(surface_id) = input_state.active_pointer_surface_id.clone() else { - return false; - }; - let delta_x = input_state.accumulated_axis_x; - let delta_y = input_state.accumulated_axis_y; - input_state.accumulated_axis_x = 0.0; - input_state.accumulated_axis_y = 0.0; - - let Some(active_surface) = find_surface_by_surface_id(lock_surfaces, &surface_id) else { - return false; - }; - - let window = active_surface.window_rc(); - - if delta_x.abs() > f32::EPSILON || delta_y.abs() > f32::EPSILON { - let position = input_state.current_pointer_position; - window - .window() - .dispatch_event(WindowEvent::PointerScrolled { - position, - delta_x, - delta_y, - }); - } - - true + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_pointer_frame(&mut input_state.pointer, &resolver) } pub(super) fn handle_keyboard_enter( @@ -255,21 +187,12 @@ pub(super) fn handle_keyboard_enter( lock_surfaces: &[(ObjectId, ActiveLockSurface)], surface: &WlSurface, ) -> bool { - let surface_id = surface.id(); - if find_surface_by_surface_id(lock_surfaces, &surface_id).is_some() { - input_state.keyboard_focus_surface_id = Some(surface_id); - return true; - } - false + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_keyboard_enter(&mut input_state.keyboard, &resolver, surface) } pub(super) fn handle_keyboard_leave(input_state: &mut InputState, surface: &WlSurface) -> bool { - let surface_id = surface.id(); - if input_state.keyboard_focus_surface_id.as_ref() == Some(&surface_id) { - input_state.keyboard_focus_surface_id = None; - return true; - } - false + shared_keyboard_leave(&mut input_state.keyboard, surface) } pub(super) fn handle_keyboard_key( @@ -279,45 +202,8 @@ pub(super) fn handle_keyboard_key( state: wl_keyboard::KeyState, keyboard_state: &mut KeyboardState, ) -> bool { - let Some(surface_id) = input_state.keyboard_focus_surface_id.clone() else { - return false; - }; - let Some(active_surface) = find_surface_by_surface_id(lock_surfaces, &surface_id) else { - return false; - }; - let Some(xkb_state) = keyboard_state.xkb_state.as_mut() else { - return true; - }; - - let keycode = xkb::Keycode::new(key + 8); - let direction = match state { - wl_keyboard::KeyState::Pressed => xkb::KeyDirection::Down, - wl_keyboard::KeyState::Released => xkb::KeyDirection::Up, - _ => return true, - }; - - xkb_state.update_key(keycode, direction); - - let text = xkb_state.key_get_utf8(keycode); - let text = if text.is_empty() { - let keysym = xkb_state.key_get_one_sym(keycode); - keysym_to_text(keysym) - } else { - Some(SharedString::from(text.as_str())) - }; - - let Some(text) = text else { - return true; - }; - - let event = match state { - wl_keyboard::KeyState::Pressed => WindowEvent::KeyPressed { text }, - wl_keyboard::KeyState::Released => WindowEvent::KeyReleased { text }, - _ => return true, - }; - info!("Lock key event {:?}", state); - active_surface.dispatch_event(event); - true + let resolver = LockSurfaceResolver { lock_surfaces }; + shared_keyboard_key(&input_state.keyboard, &resolver, key, state, keyboard_state) } fn find_surface_by_surface_id<'a>( diff --git a/crates/adapters/src/wayland/session_lock/manager/state.rs b/crates/adapters/src/wayland/session_lock/manager/state.rs index 55dd915..844d162 100644 --- a/crates/adapters/src/wayland/session_lock/manager/state.rs +++ b/crates/adapters/src/wayland/session_lock/manager/state.rs @@ -273,10 +273,6 @@ impl ActiveLockSurface { self.window.window().dispatch_event(event); } - pub fn window_rc(&self) -> Rc { - Rc::clone(&self.window) - } - pub const fn surface(&self) -> &LockSurface { &self.surface } diff --git a/crates/adapters/src/wayland/surfaces/app_state.rs b/crates/adapters/src/wayland/surfaces/app_state.rs index cb335d3..af4a1e3 100644 --- a/crates/adapters/src/wayland/surfaces/app_state.rs +++ b/crates/adapters/src/wayland/surfaces/app_state.rs @@ -5,6 +5,7 @@ use crate::errors::{LayerShikaError, Result}; use crate::rendering::egl::context_factory::RenderContextFactory; use crate::rendering::slint_integration::platform::CustomSlintPlatform; use crate::wayland::globals::context::GlobalContext; +use crate::wayland::input::KeyboardInputState; use crate::wayland::managed_proxies::{ManagedWlKeyboard, ManagedWlPointer}; use crate::wayland::outputs::{OutputManager, OutputMapping}; use crate::wayland::session_lock::lock_context::SessionLockContext; @@ -63,7 +64,7 @@ pub struct AppState { registry_name_to_output_id: HashMap, active_surface_key: Option, keyboard_focus_key: Option, - keyboard_focus_surface_id: Option, + keyboard_input_state: KeyboardInputState, keyboard_state: KeyboardState, lock_manager: Option, lock_callbacks: Vec, @@ -92,7 +93,7 @@ impl AppState { registry_name_to_output_id: HashMap::new(), active_surface_key: None, keyboard_focus_key: None, - keyboard_focus_surface_id: None, + keyboard_input_state: KeyboardInputState::new(), keyboard_state: KeyboardState::new(), lock_manager: None, lock_callbacks: Vec::new(), @@ -626,19 +627,23 @@ impl AppState { pub fn handle_keyboard_enter(&mut self, _serial: u32, surface: &WlSurface, _keys: &[u8]) { if let Some(manager) = self.lock_manager.as_mut() { if manager.handle_keyboard_enter(surface) { - self.set_keyboard_focus(None, None); + self.set_keyboard_focus(None); return; } } let surface_id = surface.id(); if let Some(key) = self.get_key_by_surface(&surface_id).cloned() { - self.set_keyboard_focus(Some(key), Some(surface_id)); + self.keyboard_input_state + .set_focused_surface(Some(surface_id.clone())); + self.set_keyboard_focus(Some(key)); return; } if let Some(key) = self.get_key_by_popup(&surface_id).cloned() { - self.set_keyboard_focus(Some(key), Some(surface_id)); + self.keyboard_input_state + .set_focused_surface(Some(surface_id)); + self.set_keyboard_focus(Some(key)); } } @@ -649,8 +654,10 @@ impl AppState { } } - if self.keyboard_focus_surface_id == Some(surface.id()) { - self.set_keyboard_focus(None, None); + let surface_id = surface.id(); + if self.keyboard_input_state.focused_surface_id() == Some(&surface_id) { + self.keyboard_input_state.reset(); + self.set_keyboard_focus(None); } } @@ -664,7 +671,7 @@ impl AppState { let Some(focus_key) = self.keyboard_focus_key.clone() else { return; }; - let Some(surface_id) = self.keyboard_focus_surface_id.clone() else { + let Some(surface_id) = self.keyboard_input_state.focused_surface_id().cloned() else { return; }; @@ -691,12 +698,11 @@ impl AppState { self.keyboard_state.repeat_delay = delay; } - fn set_keyboard_focus(&mut self, key: Option, surface_id: Option) { + fn set_keyboard_focus(&mut self, key: Option) { if let Some(ref k) = key { self.output_registry.set_active(Some(k.output_handle)); } self.keyboard_focus_key = key; - self.keyboard_focus_surface_id = surface_id; } pub fn find_output_by_popup(&self, popup_surface_id: &ObjectId) -> Option<&PerOutputSurface> { diff --git a/crates/adapters/src/wayland/surfaces/event_context.rs b/crates/adapters/src/wayland/surfaces/event_context.rs index 6d6fa03..57e11ae 100644 --- a/crates/adapters/src/wayland/surfaces/event_context.rs +++ b/crates/adapters/src/wayland/surfaces/event_context.rs @@ -1,4 +1,5 @@ use crate::rendering::femtovg::main_window::FemtoVGWindow; +use crate::wayland::input::PointerInputState; use crate::wayland::surfaces::display_metrics::SharedDisplayMetrics; use crate::wayland::surfaces::popup_manager::{ActiveWindow, PopupManager}; use slint::platform::{WindowAdapter, WindowEvent}; @@ -43,12 +44,10 @@ pub struct EventContext { main_surface_id: ObjectId, popup_manager: Option>, display_metrics: SharedDisplayMetrics, - current_pointer_position: LogicalPosition, + pointer_state: PointerInputState, last_pointer_serial: u32, shared_pointer_serial: Option>, active_surface: ActiveWindow, - accumulated_axis_x: f32, - accumulated_axis_y: f32, axis_source: Option, } @@ -64,12 +63,10 @@ impl EventContext { main_surface_id, popup_manager: None, display_metrics, - current_pointer_position: LogicalPosition::new(0.0, 0.0), + pointer_state: PointerInputState::new(), last_pointer_serial: 0, shared_pointer_serial: None, active_surface: ActiveWindow::None, - accumulated_axis_x: 0.0, - accumulated_axis_y: 0.0, axis_source: None, } } @@ -101,7 +98,7 @@ impl EventContext { } pub const fn current_pointer_position(&self) -> LogicalPosition { - self.current_pointer_position + self.pointer_state.current_position() } #[allow(clippy::cast_possible_truncation)] @@ -117,7 +114,7 @@ impl EventContext { (physical_y / f64::from(scale_factor)) as f32, ) }; - self.current_pointer_position = logical_position; + self.pointer_state.set_current_position(logical_position); } pub const fn last_pointer_serial(&self) -> u32 { @@ -222,12 +219,13 @@ impl EventContext { #[allow(clippy::cast_possible_truncation)] pub fn accumulate_axis(&mut self, axis: wl_pointer::Axis, value: f64) { + let delta = value as f32; match axis { wl_pointer::Axis::HorizontalScroll => { - self.accumulated_axis_x += value as f32; + self.pointer_state.accumulate_axis_value(delta, 0.0); } wl_pointer::Axis::VerticalScroll => { - self.accumulated_axis_y += value as f32; + self.pointer_state.accumulate_axis_value(0.0, delta); } _ => {} } @@ -239,23 +237,18 @@ impl EventContext { match axis { wl_pointer::Axis::HorizontalScroll => { - self.accumulated_axis_x += delta; + self.pointer_state.accumulate_axis_value(delta, 0.0); } wl_pointer::Axis::VerticalScroll => { - self.accumulated_axis_y += delta; + self.pointer_state.accumulate_axis_value(0.0, delta); } _ => {} } } pub fn take_accumulated_axis(&mut self) -> (f32, f32) { - let delta_x = self.accumulated_axis_x; - let delta_y = self.accumulated_axis_y; - - self.accumulated_axis_x = 0.0; - self.accumulated_axis_y = 0.0; + let (delta_x, delta_y) = self.pointer_state.take_accumulated_axis(); self.axis_source = None; - (delta_x, delta_y) } }