mirror of
https://codeberg.org/icewind/shortcutd.git
synced 2026-06-03 17:24:08 +02:00
improved modifier matching
This commit is contained in:
parent
107c21b6a5
commit
f7c7953464
4 changed files with 106 additions and 42 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
|
@ -358,6 +358,7 @@ dependencies = [
|
||||||
"main_error",
|
"main_error",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"parse-display",
|
"parse-display",
|
||||||
|
"test-case",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -371,6 +372,18 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-case"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "199464148b42bcf3da8b2a56f6ee87ca68f47402496d1268849291ec9fb463c8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
|
@ -395,6 +408,12 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "void"
|
name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,6 @@ main_error = "0.1.0"
|
||||||
num_enum = "0.4.3"
|
num_enum = "0.4.3"
|
||||||
dbus = "0.8.2"
|
dbus = "0.8.2"
|
||||||
parse-display = "0.1.1"
|
parse-display = "0.1.1"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
test-case = "1.0.0"
|
||||||
|
|
@ -46,7 +46,7 @@ pub enum Key {
|
||||||
KeySemicolon = 39,
|
KeySemicolon = 39,
|
||||||
KeyApostrophe = 40,
|
KeyApostrophe = 40,
|
||||||
KeyGrave = 41,
|
KeyGrave = 41,
|
||||||
KeyLeftshift = 42,
|
KeyLeftShift = 42,
|
||||||
KeyBackslash = 43,
|
KeyBackslash = 43,
|
||||||
KeyZ = 44,
|
KeyZ = 44,
|
||||||
KeyX = 45,
|
KeyX = 45,
|
||||||
|
|
@ -58,7 +58,7 @@ pub enum Key {
|
||||||
KeyComma = 51,
|
KeyComma = 51,
|
||||||
KeyDot = 52,
|
KeyDot = 52,
|
||||||
KeySlash = 53,
|
KeySlash = 53,
|
||||||
KeyRightshift = 54,
|
KeyRightShift = 54,
|
||||||
KeyKpAsterisk = 55,
|
KeyKpAsterisk = 55,
|
||||||
KeyLeftAlt = 56,
|
KeyLeftAlt = 56,
|
||||||
KeySpace = 57,
|
KeySpace = 57,
|
||||||
|
|
|
||||||
|
|
@ -27,20 +27,34 @@ pub enum Modifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Modifier {
|
impl Modifier {
|
||||||
pub fn is_modifier(&self, key: Key) -> bool {
|
pub fn as_mask(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Modifier::Alt => key == Key::KeyLeftAlt || key == Key::KeyRightAlt,
|
Modifier::Alt => 0b00000011,
|
||||||
Modifier::LeftAlt => key == Key::KeyLeftAlt,
|
Modifier::LeftAlt => 0b00000001,
|
||||||
Modifier::RightAlt => key == Key::KeyRightAlt,
|
Modifier::RightAlt => 0b00000010,
|
||||||
Modifier::Ctrl => key == Key::KeyLeftCtrl || key == Key::KeyRightCtrl,
|
Modifier::Ctrl => 0b00001100,
|
||||||
Modifier::LeftCtrl => key == Key::KeyLeftCtrl,
|
Modifier::LeftCtrl => 0b00000100,
|
||||||
Modifier::RightCtrl => key == Key::KeyRightCtrl,
|
Modifier::RightCtrl => 0b00001000,
|
||||||
Modifier::Meta => key == Key::KeyLeftMeta || key == Key::KeyRightMeta,
|
Modifier::Meta => 0b00110000,
|
||||||
Modifier::LeftMeta => key == Key::KeyLeftMeta,
|
Modifier::LeftMeta => 0b00010000,
|
||||||
Modifier::RightMeta => key == Key::KeyRightMeta,
|
Modifier::RightMeta => 0b00100000,
|
||||||
Modifier::Shift => key == Key::KeyLeftshift || key == Key::KeyRightshift,
|
Modifier::Shift => 0b11000000,
|
||||||
Modifier::LeftShift => key == Key::KeyLeftshift,
|
Modifier::LeftShift => 0b01000000,
|
||||||
Modifier::RightShift => key == Key::KeyRightshift,
|
Modifier::RightShift => 0b10000000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mask_from_key(key: Key) -> u8 {
|
||||||
|
match key {
|
||||||
|
Key::KeyLeftAlt => 0b00000001,
|
||||||
|
Key::KeyRightAlt => 0b00000010,
|
||||||
|
Key::KeyLeftCtrl => 0b00000100,
|
||||||
|
Key::KeyRightCtrl => 0b00001000,
|
||||||
|
Key::KeyLeftMeta => 0b00010000,
|
||||||
|
Key::KeyRightMeta => 0b00100000,
|
||||||
|
Key::KeyLeftShift => 0b01000000,
|
||||||
|
Key::KeyRightShift => 0b10000000,
|
||||||
|
_ => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -48,6 +62,14 @@ impl Modifier {
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct ModifierList(Vec<Modifier>);
|
pub struct ModifierList(Vec<Modifier>);
|
||||||
|
|
||||||
|
impl ModifierList {
|
||||||
|
pub fn as_mask(&self) -> u8 {
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.fold(0, |mask, modifier| mask | modifier.as_mask())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for ModifierList {
|
impl Display for ModifierList {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
for modifier in self.0.iter() {
|
for modifier in self.0.iter() {
|
||||||
|
|
@ -83,25 +105,18 @@ pub struct Shortcut {
|
||||||
key: Key,
|
key: Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[cfg(test)]
|
||||||
fn test_shortcut_format() {
|
mod tests {
|
||||||
assert_eq!(
|
use crate::keyboard::{Key, Modifier, Shortcut};
|
||||||
"<Ctrl>-KeyP",
|
use test_case::test_case;
|
||||||
format!("{}", Shortcut::new(vec![Modifier::Ctrl], Key::KeyP))
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
#[test_case("<Ctrl>-KeyP", Shortcut::new(vec ! [Modifier::Ctrl], Key::KeyP))]
|
||||||
"<LeftCtrl><LeftAlt>-KeyLeft",
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", Shortcut::new(vec ! [Modifier::LeftCtrl, Modifier::LeftAlt], Key::KeyLeft))]
|
||||||
format!(
|
fn shortcut_parse_display_test(s: &str, shortcut: Shortcut) {
|
||||||
"{}",
|
assert_eq!(s, format!("{}", shortcut));
|
||||||
Shortcut::new(vec![Modifier::LeftCtrl, Modifier::LeftAlt], Key::KeyLeft)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(shortcut, s.parse().unwrap());
|
||||||
Shortcut::from_str("<LeftCtrl><LeftAlt>-KeyLeft").unwrap(),
|
}
|
||||||
Shortcut::new(vec![Modifier::LeftCtrl, Modifier::LeftAlt], Key::KeyLeft)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shortcut {
|
impl Shortcut {
|
||||||
|
|
@ -115,15 +130,42 @@ impl Shortcut {
|
||||||
|
|
||||||
impl Shortcut {
|
impl Shortcut {
|
||||||
pub fn is_triggered(&self, active_keys: &HashSet<Key>) -> bool {
|
pub fn is_triggered(&self, active_keys: &HashSet<Key>) -> bool {
|
||||||
for modifier in &self.modifiers.0 {
|
let desired_mask = self.modifiers.as_mask();
|
||||||
if active_keys.iter().any(|key| modifier.is_modifier(*key)) {
|
let pressed_mask = active_keys
|
||||||
break;
|
.iter()
|
||||||
|
.fold(0, |mask, key| mask | Modifier::mask_from_key(*key));
|
||||||
|
|
||||||
|
let desired_presses = desired_mask & pressed_mask;
|
||||||
|
let modifiers_match = (desired_presses == pressed_mask)
|
||||||
|
&& (desired_presses.count_ones() == self.modifiers.0.len() as u32);
|
||||||
|
|
||||||
|
modifiers_match && active_keys.contains(&self.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
#[cfg(test)]
|
||||||
}
|
mod triggered_tests {
|
||||||
|
use crate::keyboard::{Key, Modifier, Shortcut};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use test_case::test_case;
|
||||||
|
|
||||||
active_keys.contains(&self.key)
|
#[test_case("<Ctrl>-KeyP", & [] => false)]
|
||||||
|
#[test_case("<Ctrl>-KeyP", & [Key::KeyLeftCtrl, Key::KeyP] => true)]
|
||||||
|
#[test_case("<Ctrl>-KeyP", & [Key::KeyRightCtrl, Key::KeyP] => true)]
|
||||||
|
#[test_case("<LeftCtrl>-KeyP", & [Key::KeyLeftCtrl, Key::KeyP] => true)]
|
||||||
|
#[test_case("<LeftCtrl>-KeyP", & [Key::KeyRightCtrl, Key::KeyP] => false)]
|
||||||
|
#[test_case("<Ctrl>-KeyP", & [Key::KeyLeftCtrl, Key::KeyLeftAlt, Key::KeyP] => false)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [] => false)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [Key::KeyLeft] => false)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [Key::KeyLeftCtrl, Key::KeyLeft] => false)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [Key::KeyLeftCtrl, Key::KeyLeftAlt] => false)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [Key::KeyLeftCtrl, Key::KeyLeftAlt, Key::KeyRight] => false)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [Key::KeyLeftCtrl, Key::KeyLeftAlt, Key::KeyLeft] => true)]
|
||||||
|
#[test_case("<LeftCtrl><LeftAlt>-KeyLeft", & [Key::KeyLeftCtrl, Key::KeyRightAlt, Key::KeyLeft] => false)]
|
||||||
|
#[test_case("<Ctrl><Alt>-KeyLeft", & [Key::KeyLeftCtrl, Key::KeyRightAlt, Key::KeyLeft] => true)]
|
||||||
|
fn shortcut_triggered(s: &str, keys: &[Key]) -> bool {
|
||||||
|
let shortcut: Shortcut = s.parse().unwrap();
|
||||||
|
shortcut.is_triggered(&keys.into_iter().copied().collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue