aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelivance <silentgaze@outlook.com>2025-10-24 04:23:13 +0100
committerIvan Molodetskikh <yalterz@gmail.com>2025-10-24 23:25:23 +0300
commit4310c20c320d040f3df7a93de4064e452a1876ae (patch)
tree7ddb3873870d81bac7172563e19cc0155449501a
parentb3245b81a6ed8edfaf5388a74d2e0a23c24941e5 (diff)
downloadniri-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.rs56
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(),