wayland/seat: add return value to `KeyboardHandle::input`
This commit is contained in:
parent
90dd28c910
commit
55eb73cb9e
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
- `XdgPositionerState` moved to `XdgPopupState` and added to `XdgRequest::NewPopup`
|
- `XdgPositionerState` moved to `XdgPopupState` and added to `XdgRequest::NewPopup`
|
||||||
- `PopupSurface::send_configure` now checks the protocol version and returns an `Result`
|
- `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
|
### Additions
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
reexports::wayland_server::protocol::wl_pointer,
|
reexports::wayland_server::protocol::wl_pointer,
|
||||||
wayland::{
|
wayland::{
|
||||||
seat::{keysyms as xkb, AxisFrame, Keysym, ModifiersState},
|
seat::{keysyms as xkb, AxisFrame, FilterResult, Keysym, ModifiersState},
|
||||||
SERIAL_COUNTER as SCOUNTER,
|
SERIAL_COUNTER as SCOUNTER,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,6 @@ impl<Backend> AnvilState<Backend> {
|
||||||
let serial = SCOUNTER.next_serial();
|
let serial = SCOUNTER.next_serial();
|
||||||
let log = &self.log;
|
let log = &self.log;
|
||||||
let time = Event::time(&evt);
|
let time = Event::time(&evt);
|
||||||
let mut action = KeyAction::None;
|
|
||||||
let suppressed_keys = &mut self.suppressed_keys;
|
let suppressed_keys = &mut self.suppressed_keys;
|
||||||
self.keyboard
|
self.keyboard
|
||||||
.input(keycode, state, serial, time, |modifiers, handle| {
|
.input(keycode, state, serial, time, |modifiers, handle| {
|
||||||
|
@ -60,27 +59,26 @@ impl<Backend> AnvilState<Backend> {
|
||||||
// so that we can decide on a release if the key
|
// so that we can decide on a release if the key
|
||||||
// should be forwarded to the client or not.
|
// should be forwarded to the client or not.
|
||||||
if let KeyState::Pressed = state {
|
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
|
if action.is_some() {
|
||||||
let forward = matches!(action, KeyAction::Forward);
|
|
||||||
|
|
||||||
if !forward {
|
|
||||||
suppressed_keys.push(keysym);
|
suppressed_keys.push(keysym);
|
||||||
}
|
}
|
||||||
|
|
||||||
forward
|
action
|
||||||
|
.map(FilterResult::Intercept)
|
||||||
|
.unwrap_or(FilterResult::Forward)
|
||||||
} else {
|
} else {
|
||||||
let suppressed = suppressed_keys.contains(&keysym);
|
let suppressed = suppressed_keys.contains(&keysym);
|
||||||
|
|
||||||
if suppressed {
|
if suppressed {
|
||||||
suppressed_keys.retain(|k| *k != keysym);
|
suppressed_keys.retain(|k| *k != keysym);
|
||||||
|
FilterResult::Intercept(KeyAction::None)
|
||||||
|
} else {
|
||||||
|
FilterResult::Forward
|
||||||
}
|
}
|
||||||
|
|
||||||
!suppressed
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
action
|
.unwrap_or(KeyAction::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_pointer_button<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) {
|
fn on_pointer_button<B: InputBackend>(&mut self, evt: B::PointerButtonEvent) {
|
||||||
|
@ -157,7 +155,7 @@ impl AnvilState<WinitData> {
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) {
|
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) {
|
||||||
KeyAction::None | KeyAction::Forward => {}
|
KeyAction::None => {}
|
||||||
KeyAction::Quit => {
|
KeyAction::Quit => {
|
||||||
info!(self.log, "Quitting.");
|
info!(self.log, "Quitting.");
|
||||||
self.running.store(false, Ordering::SeqCst);
|
self.running.store(false, Ordering::SeqCst);
|
||||||
|
@ -245,7 +243,7 @@ impl AnvilState<UdevData> {
|
||||||
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
|
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
|
||||||
match event {
|
match event {
|
||||||
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) {
|
InputEvent::Keyboard { event, .. } => match self.keyboard_key_to_action::<B>(event) {
|
||||||
KeyAction::None | KeyAction::Forward => {}
|
KeyAction::None => {}
|
||||||
KeyAction::Quit => {
|
KeyAction::Quit => {
|
||||||
info!(self.log, "Quitting.");
|
info!(self.log, "Quitting.");
|
||||||
self.running.store(false, Ordering::SeqCst);
|
self.running.store(false, Ordering::SeqCst);
|
||||||
|
@ -522,32 +520,32 @@ enum KeyAction {
|
||||||
Screen(usize),
|
Screen(usize),
|
||||||
ScaleUp,
|
ScaleUp,
|
||||||
ScaleDown,
|
ScaleDown,
|
||||||
/// Forward the key to the client
|
|
||||||
Forward,
|
|
||||||
/// Do nothing more
|
/// Do nothing more
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> KeyAction {
|
fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> Option<KeyAction> {
|
||||||
if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
|
if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
|
||||||
|| modifiers.logo && keysym == xkb::KEY_q
|
|| modifiers.logo && keysym == xkb::KEY_q
|
||||||
{
|
{
|
||||||
// ctrl+alt+backspace = quit
|
// ctrl+alt+backspace = quit
|
||||||
// logo + q = quit
|
// logo + q = quit
|
||||||
KeyAction::Quit
|
Some(KeyAction::Quit)
|
||||||
} else if (xkb::KEY_XF86Switch_VT_1..=xkb::KEY_XF86Switch_VT_12).contains(&keysym) {
|
} else if (xkb::KEY_XF86Switch_VT_1..=xkb::KEY_XF86Switch_VT_12).contains(&keysym) {
|
||||||
// VTSwicth
|
// 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 {
|
} else if modifiers.logo && keysym == xkb::KEY_Return {
|
||||||
// run terminal
|
// 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 {
|
} 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 {
|
} 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 {
|
} else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_P {
|
||||||
KeyAction::ScaleUp
|
Some(KeyAction::ScaleUp)
|
||||||
} else {
|
} else {
|
||||||
KeyAction::Forward
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,6 +323,15 @@ impl<'a> KeysymHandle<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Result for key input filtering (see [`KeyboardHandle::input`])
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FilterResult<T> {
|
||||||
|
/// Forward the given keycode to the client
|
||||||
|
Forward,
|
||||||
|
/// Do not forward and return value
|
||||||
|
Intercept(T),
|
||||||
|
}
|
||||||
|
|
||||||
/// An handle to a keyboard handler
|
/// An handle to a keyboard handler
|
||||||
///
|
///
|
||||||
/// It can be cloned and all clones manipulate the same internal state.
|
/// 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
|
/// 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
|
/// 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
|
/// returns [`FilterResult::Forward`], the input will not be sent to the client. If it returns
|
||||||
/// implement compositor-level key bindings for example.
|
/// [`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
|
/// 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.
|
/// to be compared against. This includes non-character keysyms, such as XF86 special keys.
|
||||||
pub fn input<F>(&self, keycode: u32, state: KeyState, serial: Serial, time: u32, filter: F)
|
pub fn input<T, F>(
|
||||||
|
&self,
|
||||||
|
keycode: u32,
|
||||||
|
state: KeyState,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
filter: F,
|
||||||
|
) -> Option<T>
|
||||||
where
|
where
|
||||||
F: FnOnce(&ModifiersState, KeysymHandle<'_>) -> bool,
|
F: FnOnce(&ModifiersState, KeysymHandle<'_>) -> FilterResult<T>,
|
||||||
{
|
{
|
||||||
trace!(self.arc.logger, "Handling keystroke"; "keycode" => keycode, "state" => format_args!("{:?}", state));
|
trace!(self.arc.logger, "Handling keystroke"; "keycode" => keycode, "state" => format_args!("{:?}", state));
|
||||||
let mut guard = self.arc.internal.borrow_mut();
|
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())
|
"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
|
// the filter returned false, we do not forward to client
|
||||||
trace!(self.arc.logger, "Input was intercepted by filter");
|
trace!(self.arc.logger, "Input was intercepted by filter");
|
||||||
return;
|
return Some(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// forward to client if no keybinding is triggered
|
// forward to client if no keybinding is triggered
|
||||||
|
@ -400,6 +417,8 @@ impl KeyboardHandle {
|
||||||
} else {
|
} else {
|
||||||
trace!(self.arc.logger, "No client currently focused");
|
trace!(self.arc.logger, "No client currently focused");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the current focus of this keyboard
|
/// Set the current focus of this keyboard
|
||||||
|
|
|
@ -40,7 +40,9 @@ mod keyboard;
|
||||||
mod pointer;
|
mod pointer;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig},
|
keyboard::{
|
||||||
|
keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, ModifiersState, XkbConfig,
|
||||||
|
},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,
|
AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,
|
||||||
PointerInnerHandle,
|
PointerInnerHandle,
|
||||||
|
|
Loading…
Reference in New Issue