cognitive_inputs/
keyboard_state.rs

1// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
2// the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/
3
4//! This module contains functionality allowing to keep track of state of keyboard.
5
6// -------------------------------------------------------------------------------------------------
7
8use xkbcommon::xkb;
9
10use qualia::{Illusion, KeyboardConfig, InputCode, InputValue};
11
12use keymap::XkbKeymap;
13
14// -------------------------------------------------------------------------------------------------
15
16/// This struct represents state of keyboard modifiers (shift, ctrl, etc...).
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct KeyMods {
19    pub depressed: u32,
20    pub latched: u32,
21    pub locked: u32,
22    pub effective: u32,
23}
24
25// -------------------------------------------------------------------------------------------------
26
27impl KeyMods {
28    /// Constructs default `KeyMods`.
29    pub fn default() -> Self {
30        KeyMods {
31            depressed: 0,
32            latched: 0,
33            locked: 0,
34            effective: 0,
35        }
36    }
37
38    /// Constructs `KeyMods` from given modifiers.
39    pub fn new(depressed: u32, latched: u32, locked: u32, effective: u32) -> Self {
40        KeyMods {
41            depressed: depressed,
42            latched: latched,
43            locked: locked,
44            effective: effective,
45        }
46    }
47}
48
49// -------------------------------------------------------------------------------------------------
50
51/// Represents state of keyboard.
52pub struct KeyboardState {
53    xkb_state: xkb::State,
54    mods: KeyMods,
55}
56
57// -------------------------------------------------------------------------------------------------
58
59impl KeyboardState {
60    /// Constructs new `KeyboardState`.
61    pub fn new(config: &KeyboardConfig) -> Result<Self, Illusion> {
62        let xkb_keymap = if let Some(xkb_keymap) = XkbKeymap::new(config) {
63            xkb_keymap
64        } else {
65            return Err(Illusion::General(format!("Failed to create key map")));
66        };
67
68        Ok(KeyboardState {
69               xkb_state: xkb::State::new(&xkb_keymap.keymap),
70               mods: KeyMods::default(),
71           })
72    }
73
74    /// Updates state with given key. Returns `true` when modifiers changed, false otherwise.
75    pub fn update(&mut self, code: InputCode, value: InputValue) -> bool {
76        let direction = if value == 0 {
77            xkb::KeyDirection::Up
78        } else {
79            xkb::KeyDirection::Down
80        };
81
82        // Offset the key code by 8, as the evdev XKB rules reflect X's
83        // broken key code system, which starts at 8.
84        self.xkb_state.update_key(code as u32 + 8, direction);
85        let mods = KeyMods::new(self.xkb_state.serialize_mods(xkb::STATE_MODS_DEPRESSED),
86                                self.xkb_state.serialize_mods(xkb::STATE_MODS_LATCHED),
87                                self.xkb_state.serialize_mods(xkb::STATE_MODS_LOCKED),
88                                self.xkb_state.serialize_mods(xkb::STATE_MODS_EFFECTIVE));
89
90        if mods != self.mods {
91            self.mods = mods;
92            true
93        } else {
94            false
95        }
96    }
97
98    /// Returns state of modifiers.
99    pub fn get_mods(&self) -> KeyMods {
100        self.mods
101    }
102}
103
104// -------------------------------------------------------------------------------------------------