From 55eb73cb9e6ed4aaeab89528377a326370448a9c Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Sun, 19 Sep 2021 17:10:08 +0200 Subject: [PATCH] wayland/seat: add return value to `KeyboardHandle::input` --- CHANGELOG.md | 2 +- anvil/src/input_handler.rs | 48 +++++++++++++++++------------------- src/wayland/seat/keyboard.rs | 31 ++++++++++++++++++----- src/wayland/seat/mod.rs | 4 ++- 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1cbe4b..b6b413c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ - `XdgPositionerState` moved to `XdgPopupState` and added to `XdgRequest::NewPopup` - `PopupSurface::send_configure` now checks the protocol version and returns an `Result` -- `KeyboardHandle::input` filter closure now receives a `KeysymHandle` instead of a `Keysym`. +- `KeyboardHandle::input` filter closure now receives a `KeysymHandle` instead of a `Keysym` and returns a `FilterResult`. ### Additions diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index 38925b9..1313bd1 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -13,7 +13,7 @@ use smithay::{ }, reexports::wayland_server::protocol::wl_pointer, wayland::{ - seat::{keysyms as xkb, AxisFrame, Keysym, ModifiersState}, + seat::{keysyms as xkb, AxisFrame, FilterResult, Keysym, ModifiersState}, SERIAL_COUNTER as SCOUNTER, }, }; @@ -42,7 +42,6 @@ impl AnvilState { let serial = SCOUNTER.next_serial(); let log = &self.log; let time = Event::time(&evt); - let mut action = KeyAction::None; let suppressed_keys = &mut self.suppressed_keys; self.keyboard .input(keycode, state, serial, time, |modifiers, handle| { @@ -60,27 +59,26 @@ impl AnvilState { // so that we can decide on a release if the key // should be forwarded to the client or not. if let KeyState::Pressed = state { - action = process_keyboard_shortcut(*modifiers, keysym); + let action = process_keyboard_shortcut(*modifiers, keysym); - // forward to client only if action == KeyAction::Forward - let forward = matches!(action, KeyAction::Forward); - - if !forward { + if action.is_some() { suppressed_keys.push(keysym); } - forward + action + .map(FilterResult::Intercept) + .unwrap_or(FilterResult::Forward) } else { let suppressed = suppressed_keys.contains(&keysym); - if suppressed { suppressed_keys.retain(|k| *k != keysym); + FilterResult::Intercept(KeyAction::None) + } else { + FilterResult::Forward } - - !suppressed } - }); - action + }) + .unwrap_or(KeyAction::None) } fn on_pointer_button(&mut self, evt: B::PointerButtonEvent) { @@ -157,7 +155,7 @@ impl AnvilState { match event { InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::(event) { - KeyAction::None | KeyAction::Forward => {} + KeyAction::None => {} KeyAction::Quit => { info!(self.log, "Quitting."); self.running.store(false, Ordering::SeqCst); @@ -245,7 +243,7 @@ impl AnvilState { pub fn process_input_event(&mut self, event: InputEvent) { match event { InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::(event) { - KeyAction::None | KeyAction::Forward => {} + KeyAction::None => {} KeyAction::Quit => { info!(self.log, "Quitting."); self.running.store(false, Ordering::SeqCst); @@ -522,32 +520,32 @@ enum KeyAction { Screen(usize), ScaleUp, ScaleDown, - /// Forward the key to the client - Forward, /// Do nothing more None, } -fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> KeyAction { +fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> Option { if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace || modifiers.logo && keysym == xkb::KEY_q { // ctrl+alt+backspace = quit // logo + q = quit - KeyAction::Quit + Some(KeyAction::Quit) } else if (xkb::KEY_XF86Switch_VT_1..=xkb::KEY_XF86Switch_VT_12).contains(&keysym) { // VTSwicth - KeyAction::VtSwitch((keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32) + Some(KeyAction::VtSwitch( + (keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32, + )) } else if modifiers.logo && keysym == xkb::KEY_Return { // run terminal - KeyAction::Run("weston-terminal".into()) + Some(KeyAction::Run("weston-terminal".into())) } else if modifiers.logo && keysym >= xkb::KEY_1 && keysym <= xkb::KEY_9 { - KeyAction::Screen((keysym - xkb::KEY_1) as usize) + Some(KeyAction::Screen((keysym - xkb::KEY_1) as usize)) } else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_M { - KeyAction::ScaleDown + Some(KeyAction::ScaleDown) } else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_P { - KeyAction::ScaleUp + Some(KeyAction::ScaleUp) } else { - KeyAction::Forward + None } } diff --git a/src/wayland/seat/keyboard.rs b/src/wayland/seat/keyboard.rs index b2f6e8c..e5a1d57 100644 --- a/src/wayland/seat/keyboard.rs +++ b/src/wayland/seat/keyboard.rs @@ -323,6 +323,15 @@ impl<'a> KeysymHandle<'a> { } } +/// Result for key input filtering (see [`KeyboardHandle::input`]) +#[derive(Debug)] +pub enum FilterResult { + /// Forward the given keycode to the client + Forward, + /// Do not forward and return value + Intercept(T), +} + /// An handle to a keyboard handler /// /// It can be cloned and all clones manipulate the same internal state. @@ -347,14 +356,22 @@ impl KeyboardHandle { /// /// The `filter` argument is expected to be a closure which will peek at the generated input /// as interpreted by the keymap before it is forwarded to the focused client. If this closure - /// returns false, the input will not be sent to the client. This mechanism can be used to - /// implement compositor-level key bindings for example. + /// returns [`FilterResult::Forward`], the input will not be sent to the client. If it returns + /// [`FilterResult::Intercept`] a value can be passed to be returned by the whole function. + /// This mechanism can be used to implement compositor-level key bindings for example. /// /// The module [`crate::wayland::seat::keysyms`] exposes definitions of all possible keysyms /// to be compared against. This includes non-character keysyms, such as XF86 special keys. - pub fn input(&self, keycode: u32, state: KeyState, serial: Serial, time: u32, filter: F) + pub fn input( + &self, + keycode: u32, + state: KeyState, + serial: Serial, + time: u32, + filter: F, + ) -> Option where - F: FnOnce(&ModifiersState, KeysymHandle<'_>) -> bool, + F: FnOnce(&ModifiersState, KeysymHandle<'_>) -> FilterResult, { trace!(self.arc.logger, "Handling keystroke"; "keycode" => keycode, "state" => format_args!("{:?}", state)); let mut guard = self.arc.internal.borrow_mut(); @@ -371,10 +388,10 @@ impl KeyboardHandle { "mods_state" => format_args!("{:?}", guard.mods_state), "sym" => xkb::keysym_get_name(handle.modified_sym()) ); - if !filter(&guard.mods_state, handle) { + if let FilterResult::Intercept(val) = filter(&guard.mods_state, handle) { // the filter returned false, we do not forward to client trace!(self.arc.logger, "Input was intercepted by filter"); - return; + return Some(val); } // forward to client if no keybinding is triggered @@ -400,6 +417,8 @@ impl KeyboardHandle { } else { trace!(self.arc.logger, "No client currently focused"); } + + None } /// Set the current focus of this keyboard diff --git a/src/wayland/seat/mod.rs b/src/wayland/seat/mod.rs index 8e9dd5f..b8279a6 100644 --- a/src/wayland/seat/mod.rs +++ b/src/wayland/seat/mod.rs @@ -40,7 +40,9 @@ mod keyboard; mod pointer; pub use self::{ - keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig}, + keyboard::{ + keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, ModifiersState, XkbConfig, + }, pointer::{ AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle, PointerInnerHandle,