1use composer::{ComposeState, Composer, ListComposer, Token};
27mod composer;
28pub use modifiers::KeyDirection;
29use modifiers::ModType;
30use modifiers::{level_index, Modifiers, *};
31mod modifiers;
32#[cfg(feature = "testing")]
34pub mod testing;
35#[cfg(feature = "xkb")]
36mod xkb;
37
38const MAX_LEVELS: usize = 8;
40
41const BITSET_WORDS: usize = 12; #[derive(Debug, Clone)]
46pub(crate) struct KeyBitSet {
47 bits: [u64; BITSET_WORDS],
48}
49
50impl KeyBitSet {
51 #[inline]
52 pub(crate) const fn new() -> Self {
53 Self {
54 bits: [0; BITSET_WORDS],
55 }
56 }
57
58 #[inline(always)]
59 pub(crate) fn contains(&self, key: u32) -> bool {
60 let k = key as usize;
61 if k < BITSET_WORDS * 64 {
62 self.bits[k >> 6] & (1u64 << (k & 63)) != 0
63 } else {
64 false
65 }
66 }
67
68 #[inline(always)]
69 pub(crate) fn insert(&mut self, key: u32) {
70 let k = key as usize;
71 if k < BITSET_WORDS * 64 {
72 self.bits[k >> 6] |= 1u64 << (k & 63);
73 }
74 }
75
76 #[inline(always)]
77 pub(crate) fn remove(&mut self, key: u32) {
78 let k = key as usize;
79 if k < BITSET_WORDS * 64 {
80 self.bits[k >> 6] &= !(1u64 << (k & 63));
81 }
82 }
83}
84
85#[derive(Debug, Clone)]
88pub(crate) struct FlatKeymap {
89 pub(crate) data: Vec<Option<char>>,
90 pub(crate) num_keys: usize,
91}
92
93impl FlatKeymap {
94 pub(crate) fn new(num_keys: usize) -> Self {
95 Self {
96 data: vec![None; MAX_LEVELS * num_keys],
97 num_keys,
98 }
99 }
100
101 #[inline]
102 pub(crate) fn num_levels(&self) -> usize {
103 MAX_LEVELS
104 }
105
106 #[inline(always)]
107 pub(crate) fn get(&self, level: usize, evdev_code: u32) -> Option<char> {
108 let k = evdev_code as usize;
109 if k < self.num_keys {
110 let idx = level * self.num_keys + k;
111 self.data[idx]
112 } else {
113 None
114 }
115 }
116
117 #[inline]
118 pub(crate) fn set(&mut self, level: usize, evdev_code: u32, ch: char) {
119 let k = evdev_code as usize;
120 if k < self.num_keys {
121 let idx = level * self.num_keys + k;
122 self.data[idx] = Some(ch);
123 }
124 }
125}
126
127const MODIFIER_MAPPING: [(u32, u32); 9] = [
128 (LEFT_SHIFT, 1),
129 (RIGHT_SHIFT, 1),
130 (CAPS_LOCK, 2),
131 (LEFT_CTRL, 4),
132 (RIGHT_CTRL, 4),
133 (ALT, 8),
134 (NUM_LOCK, 16),
135 (LOGO, 64),
136 (ALTGR, 128),
137];
138
139#[derive(Debug, Clone)]
143pub struct WKB<C: Composer> {
144 pub(crate) layouts: Vec<String>,
145 pub(crate) layout: String,
146 pub(crate) pressed_keys: KeyBitSet,
148 pub(crate) repeat_keys: KeyBitSet,
149 pub(crate) composer: C,
150 pub(crate) modifiers: Modifiers,
151 pub(crate) state_keymap: FlatKeymap,
152 pub(crate) num_lock_keys: FlatKeymap,
153 pub(crate) caps_lock_keymap: FlatKeymap,
154 pub(crate) level_exceptions_keymap: FlatKeymap,
155 #[cfg(feature = "xkb")]
156 pub(crate) xkb_keymap: Option<xkb_core::rust_types::Keymap>,
157}
158
159#[cfg(feature = "xkb")]
160impl WKB<ListComposer> {
161 pub fn new_from_names(locale: String, layout: Option<String>) -> Self {
163 xkb::new_from_names(locale, layout)
164 }
165
166 pub fn new_from_string(string: String) -> Self {
168 xkb::new_from_string(string)
169 }
170}
171
172impl<C: Composer> WKB<C> {
173 pub fn reset_state(&mut self) {
176 self.composer.reset();
177 self.pressed_keys = KeyBitSet::new();
178 }
179
180 pub fn modifiers_state(&self) -> (u32, u32, u32, u32) {
182 let mut depressed = 0;
183 let mut latched = 0;
184 let mut locked = 0;
185 let group = 0;
186 for (code, bit) in MODIFIER_MAPPING {
187 if let Some(Modifier::Single(mk)) = self.modifiers.get(code) {
188 match mk {
189 ModKind::Pressed { pressed: true, .. } => depressed |= bit,
190 ModKind::Lock {
191 pressed, locked: l, ..
192 } => {
193 if *pressed {
194 depressed |= bit;
195 }
196 if *l > 0 {
197 locked |= bit;
198 }
199 }
200 ModKind::Latch {
201 pressed,
202 latched: is_latched,
203 ..
204 } => {
205 if *pressed {
206 depressed |= bit;
207 }
208 if *is_latched {
209 latched |= bit;
210 }
211 }
212 _ => {}
213 }
214 }
215 }
216 (depressed, latched, locked, group)
217 }
218
219 pub fn leds_state(&self) -> u32 {
221 let mut leds = 0;
222 if self.modifiers.locked_with_type(NUM_LOCK, ModType::Num) {
223 leds |= 1;
224 }
225 if self.modifiers.locked_with_type(CAPS_LOCK, ModType::Caps) {
226 leds |= 2;
227 }
228 if self
229 .modifiers
230 .locked_with_type(SCROLL_LOCK, ModType::Scroll)
231 {
232 leds |= 4;
233 }
234 leds
235 }
236
237 pub fn update_modifiers(&mut self, depressed: u32, latched: u32, locked: u32, group: u32) {
239 if let Some(l) = self.layouts.get(group as usize) {
240 self.layout = l.clone();
241 }
242 for (code, bit) in MODIFIER_MAPPING {
243 let is_depressed = (depressed & bit) != 0;
244 let is_locked = (locked & bit) != 0;
245 let is_latched = (latched & bit) != 0;
246
247 if let Some(m) = self.modifiers.get_mut(code) {
248 if let Modifier::Single(mk) = m {
249 match mk {
250 ModKind::Pressed { pressed, .. } => *pressed = is_depressed,
251 ModKind::Lock {
252 pressed, locked, ..
253 } => {
254 *pressed = is_depressed;
255 *locked = if is_locked { 1 } else { 0 };
256 }
257 ModKind::Latch {
258 pressed, latched, ..
259 } => {
260 *pressed = is_depressed;
261 *latched = is_latched;
262 }
263 _ => {}
264 }
265 }
266 }
267 }
268 }
269
270 #[inline]
272 pub fn level_key(&self, evdev_code: u32, level_index: usize) -> Option<char> {
273 self.level_exceptions_keymap
274 .get(level_index, evdev_code)
275 .or_else(|| self.state_keymap.get(level_index, evdev_code))
276 }
277
278 #[inline]
280 pub fn num_levels(&self) -> usize {
281 self.state_keymap.num_levels()
282 }
283
284 pub fn key_repeats(&self, evdev_code: u32) -> bool {
286 self.repeat_keys.contains(evdev_code)
287 }
288
289 #[inline]
291 pub fn utf8(&mut self, evdev_code: u32) -> Option<char> {
292 let (none_active, level2, level3, level5) = self.modifiers.active_none_and_levels();
293 if none_active {
294 return None;
295 }
296 let nk = self.state_keymap.num_keys;
297 let level5 = level5 && self.state_keymap.data.len() > 4 * nk;
298 let level3 = level3 && self.state_keymap.data.len() > 2 * nk;
299 let level2 = level2 && self.state_keymap.data.len() > 1 * nk;
300 let base_level = level_index(level5, level3, level2);
301
302 if self.modifiers.locked(NUM_LOCK) {
303 if let Some(key) = self.num_lock_keys.get(base_level, evdev_code) {
304 return Some(key);
305 }
306 }
307
308 if self.modifiers.locked(CAPS_LOCK) {
309 if let Some(c) = self.caps_lock_keymap.get(base_level, evdev_code) {
310 return Some(c);
311 }
312 }
313
314 self.state_keymap.get(base_level, evdev_code)
315 }
316
317 pub(crate) fn update_key(&mut self, evdev_code: u32, key_direction: KeyDirection) -> bool {
319 let is_modifier = self.modifiers.set_state(evdev_code, key_direction);
320 if !is_modifier {
321 if key_direction == KeyDirection::Down {
322 self.modifiers.unlatch();
323 }
324 match key_direction {
325 KeyDirection::Up => {
326 self.pressed_keys.remove(evdev_code);
327 }
328 KeyDirection::Down => {
329 self.pressed_keys.insert(evdev_code);
330 }
331 };
332 }
333 is_modifier
334 }
335
336 pub fn key(&mut self, evdev_code: u32, key_direction: KeyDirection) -> (Option<char>, bool) {
338 let is_modifier = self.update_key(evdev_code, key_direction);
339 let utf8 = if key_direction == KeyDirection::Down && !is_modifier {
340 self.utf8(evdev_code)
341 } else {
342 None
343 };
344 (utf8, is_modifier)
345 }
346
347 #[cfg(feature = "compose")]
349 pub fn key_compose(
350 &mut self,
351 evdev_code: u32,
352 key_direction: KeyDirection,
353 ) -> (Option<ComposeState>, bool) {
354 let is_modifier = self.update_key(evdev_code, key_direction);
355 let compose_state = if key_direction == KeyDirection::Down
356 && is_modifier
357 && self.modifiers.active_mod_type(ModType::Compose)
358 {
359 Some(self.composer.feed(Token::Compose))
360 } else if key_direction == KeyDirection::Down && !is_modifier {
361 self.utf8(evdev_code)
362 .map(|c| self.composer.feed(Token::Char(c)))
363 } else {
364 None
365 };
366 (compose_state, is_modifier)
367 }
368
369 pub fn layouts(&self) -> Vec<String> {
371 self.layouts.clone()
372 }
373
374 pub fn current_layout(&self) -> String {
376 self.layout.clone()
377 }
378
379 #[cfg(feature = "xkb")]
383 pub fn as_xkb_string(&self) -> Option<String> {
384 self.xkb_keymap.as_ref().map(|km| km.as_xkb_string())
385 }
386}