keybindings_parser/
lib.rs1mod masks;
2pub use masks::ModMask;
3
4#[derive(Debug)]
5pub struct Keybindings {
6 binds: Vec<Keybinding>,
7 ghost_modifiers: ModMask,
8 key_delimiter: char,
9}
10
11impl Keybindings {
12 pub fn new(key_delimiter: char, ghost_modifiers: ModMask) -> Self {
13 Self {
14 binds: Vec::new(),
15 ghost_modifiers,
16 key_delimiter,
17 }
18 }
19}
20
21impl Default for Keybindings {
22 fn default() -> Self {
23 Self {
24 binds: Vec::new(),
25 ghost_modifiers: ModMask::MOD2 | ModMask::MOD5 | ModMask::CAPS_LOCK,
26 key_delimiter: '+',
27 }
28 }
29}
30
31pub struct Keybinding {
32 origin: String,
33 modifier: ModMask,
34 key: u32, action: Box<dyn KeyAction>,
36}
37
38impl Keybinding {
39 pub fn modifier(&self) -> ModMask {
40 self.modifier
41 }
42 pub fn key(&self) -> u32 {
43 self.key
44 }
45 pub fn action(&self) -> &dyn KeyAction {
46 self.action.as_ref()
47 }
48 pub fn origin(&self) -> &str {
49 &self.origin
50 }
51}
52
53impl std::fmt::Debug for Keybinding {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("Keybinding")
56 .field("modifier", &self.modifier)
57 .field("key", &self.key)
58 .finish()
59 }
60}
61
62impl Keybindings {
63 pub fn add(
64 &mut self,
65 human_key_string: &str,
66 action: Box<dyn KeyAction>,
67 ) -> Result<(), Box<dyn std::error::Error>> {
68 if self.binds.iter().any(|x| x.origin == human_key_string) {
69 return Err("duplicate keybinding")?;
70 }
71 let mut parts: Vec<&str> = human_key_string
72 .split(self.key_delimiter)
73 .map(|x| x.trim())
74 .collect();
75 let mut keymod = ModMask::NONE;
76
77 let key = match parts.pop() {
78 Some(k) => k.to_string(),
79 None => return Err("no key provided")?,
80 };
81
82 let (strict, lazy) = (
83 keysymdefs::get_item_by_name(&key),
84 keysymdefs::get_item_by_cleared_name(&key),
85 );
86
87 let mut key = 0u32;
88 if let Some(lazy) = lazy {
89 key = lazy.keysym();
90 }
91 if let Some(strict) = strict {
92 key = strict.keysym();
93 }
94 if key == 0 {
95 return Err("Key not found".to_string())?;
96 }
97
98 while let Some(m) = parts.pop() {
99 keymod |= match m.to_lowercase().as_str() {
100 "super" | "mod4" | "win" | "windows" | "cmd" | "command" => ModMask::MOD4,
101 "alt" | "mod1" | "meta" | "alt_l" | "alt_r" | "meta_l" | "meta_r" => ModMask::MOD1,
102 "alt_gr" | "mod3" | "altgr" | "meta_gr" | "metagr" => ModMask::MOD3,
103 "ctrl" | "control" | "ctrl_l" | "ctrl_r" => ModMask::CONTROL,
104 "shift" | "shift_l" | "shift_r" => ModMask::SHIFT,
105 _ => return Err("invalid modifier")?,
106 }
107 }
108
109 self.binds.push(Keybinding {
110 origin: human_key_string.to_string(),
111 modifier: keymod,
112 key,
113 action,
114 });
115
116 Ok(())
117 }
118
119 pub fn handle(&self, modifiers: ModMask, keysym: u32) -> Option<&Keybinding> {
120 let find = self.binds.iter().find(|k| {
121 (k.modifier | self.ghost_modifiers) == (modifiers | self.ghost_modifiers)
122 && k.key == keysym
123 })?;
124 Some(find)
125 }
126}
127
128pub trait KeyAction {
129 fn run(&self) -> Result<(), Box<dyn std::error::Error>>;
130}