diff options
| author | elivance <silentgaze@outlook.com> | 2025-10-24 04:23:13 +0100 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2025-10-24 23:25:23 +0300 |
| commit | 4310c20c320d040f3df7a93de4064e452a1876ae (patch) | |
| tree | 7ddb3873870d81bac7172563e19cc0155449501a | |
| parent | b3245b81a6ed8edfaf5388a74d2e0a23c24941e5 (diff) | |
| download | niri-4310c20c320d040f3df7a93de4064e452a1876ae.tar.gz niri-4310c20c320d040f3df7a93de4064e452a1876ae.tar.bz2 niri-4310c20c320d040f3df7a93de4064e452a1876ae.zip | |
config: fix parsing of XF86ScreenSaver key
Closes #1969
| -rw-r--r-- | niri-config/src/binds.rs | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/niri-config/src/binds.rs b/niri-config/src/binds.rs index 71181fc0..1356d40f 100644 --- a/niri-config/src/binds.rs +++ b/niri-config/src/binds.rs @@ -9,7 +9,7 @@ use niri_ipc::{ ColumnDisplay, LayoutSwitchTarget, PositionChange, SizeChange, WorkspaceReferenceArg, }; use smithay::input::keyboard::keysyms::KEY_NoSymbol; -use smithay::input::keyboard::xkb::{keysym_from_name, KEYSYM_CASE_INSENSITIVE}; +use smithay::input::keyboard::xkb::{keysym_from_name, KEYSYM_CASE_INSENSITIVE, KEYSYM_NO_FLAGS}; use smithay::input::keyboard::Keysym; use crate::utils::{expect_only_children, MergeWith}; @@ -984,7 +984,34 @@ impl FromStr for Key { } else if key.eq_ignore_ascii_case("TouchpadScrollRight") { Trigger::TouchpadScrollRight } else { - let keysym = keysym_from_name(key, KEYSYM_CASE_INSENSITIVE); + let mut keysym = keysym_from_name(key, KEYSYM_CASE_INSENSITIVE); + // The keyboard event handling code can receive either + // XF86ScreenSaver or XF86Screensaver, because there is no + // case mapping defined between these keysyms. If we just + // use the case-insensitive version of keysym_from_name it + // is not possible to bind the uppercase version, because the + // case-insensitive match prefers the lowercase version when + // there is a choice. + // + // Therefore, when we match this key with the initial + // case-insensitive match we try a further case-sensitive match + // (so that either key can be bound). If that fails, we change + // to the uppercase version because: + // + // - A comment in xkb_keysym_from_name (in libxkbcommon) tells us that the uppercase + // version is the "best" of the two. [0] + // - The xkbcommon crate only has a constant for ScreenSaver. [1] + // + // [0]: https://github.com/xkbcommon/libxkbcommon/blob/45a118d5325b051343b4b174f60c1434196fa7d4/src/keysym.c#L276 + // [1]: https://docs.rs/xkbcommon/latest/xkbcommon/xkb/keysyms/index.html#:~:text=KEY%5FXF86ScreenSaver + // + // See https://github.com/YaLTeR/niri/issues/1969 + if keysym == Keysym::XF86_Screensaver { + keysym = keysym_from_name(key, KEYSYM_NO_FLAGS); + if keysym.raw() == KEY_NoSymbol { + keysym = Keysym::XF86_ScreenSaver; + } + } if keysym.raw() == KEY_NoSymbol { return Err(miette!("invalid key: {key}")); } @@ -1000,6 +1027,31 @@ mod tests { use super::*; #[test] + fn parse_xf86_screensaver() { + assert_eq!( + "XF86ScreenSaver".parse::<Key>().unwrap(), + Key { + trigger: Trigger::Keysym(Keysym::XF86_ScreenSaver), + modifiers: Modifiers::empty(), + }, + ); + assert_eq!( + "XF86Screensaver".parse::<Key>().unwrap(), + Key { + trigger: Trigger::Keysym(Keysym::XF86_Screensaver), + modifiers: Modifiers::empty(), + } + ); + assert_eq!( + "xf86screensaver".parse::<Key>().unwrap(), + Key { + trigger: Trigger::Keysym(Keysym::XF86_ScreenSaver), + modifiers: Modifiers::empty(), + } + ); + } + + #[test] fn parse_iso_level_shifts() { assert_eq!( "ISO_Level3_Shift+A".parse::<Key>().unwrap(), |
