1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
// the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/

//! This module contains functionality allowing to keep track of state of keyboard.

// -------------------------------------------------------------------------------------------------

use xkbcommon::xkb;

use qualia::{Illusion, KeyboardConfig, InputCode, InputValue};

use keymap::XkbKeymap;

// -------------------------------------------------------------------------------------------------

/// This struct represents state of keyboard modifiers (shift, ctrl, etc...).
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct KeyMods {
    pub depressed: u32,
    pub latched: u32,
    pub locked: u32,
    pub effective: u32,
}

// -------------------------------------------------------------------------------------------------

impl KeyMods {
    /// Constructs default `KeyMods`.
    pub fn default() -> Self {
        KeyMods {
            depressed: 0,
            latched: 0,
            locked: 0,
            effective: 0,
        }
    }

    /// Constructs `KeyMods` from given modifiers.
    pub fn new(depressed: u32, latched: u32, locked: u32, effective: u32) -> Self {
        KeyMods {
            depressed: depressed,
            latched: latched,
            locked: locked,
            effective: effective,
        }
    }
}

// -------------------------------------------------------------------------------------------------

/// Represents state of keyboard.
pub struct KeyboardState {
    xkb_state: xkb::State,
    mods: KeyMods,
}

// -------------------------------------------------------------------------------------------------

impl KeyboardState {
    /// Constructs new `KeyboardState`.
    pub fn new(config: &KeyboardConfig) -> Result<Self, Illusion> {
        let xkb_keymap = if let Some(xkb_keymap) = XkbKeymap::new(config) {
            xkb_keymap
        } else {
            return Err(Illusion::General(format!("Failed to create key map")));
        };

        Ok(KeyboardState {
               xkb_state: xkb::State::new(&xkb_keymap.keymap),
               mods: KeyMods::default(),
           })
    }

    /// Updates state with given key. Returns `true` when modifiers changed, false otherwise.
    pub fn update(&mut self, code: InputCode, value: InputValue) -> bool {
        let direction = if value == 0 {
            xkb::KeyDirection::Up
        } else {
            xkb::KeyDirection::Down
        };

        // Offset the key code by 8, as the evdev XKB rules reflect X's
        // broken key code system, which starts at 8.
        self.xkb_state.update_key(code as u32 + 8, direction);
        let mods = KeyMods::new(self.xkb_state.serialize_mods(xkb::STATE_MODS_DEPRESSED),
                                self.xkb_state.serialize_mods(xkb::STATE_MODS_LATCHED),
                                self.xkb_state.serialize_mods(xkb::STATE_MODS_LOCKED),
                                self.xkb_state.serialize_mods(xkb::STATE_MODS_EFFECTIVE));

        if mods != self.mods {
            self.mods = mods;
            true
        } else {
            false
        }
    }

    /// Returns state of modifiers.
    pub fn get_mods(&self) -> KeyMods {
        self.mods
    }
}

// -------------------------------------------------------------------------------------------------