forked from koniifer/ableos
291 lines
8.6 KiB
Rust
291 lines
8.6 KiB
Rust
#![allow(dead_code)]
|
|
|
|
mod abstractions;
|
|
mod small_types;
|
|
mod traits;
|
|
|
|
pub use abstractions::*;
|
|
pub use small_types::*;
|
|
pub use traits::*;
|
|
|
|
const EXTENDED_KEY_CODE: u8 = 0xE0;
|
|
const KEYCODE_BITS: u8 = 11;
|
|
const KEY_RELEASE_CODE: u8 = 0xF0;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Keyboard<T, S>
|
|
where
|
|
T: KeyboardLayout,
|
|
S: ScancodeSet,
|
|
{
|
|
register: u16,
|
|
num_bits: u8,
|
|
decode_state: DecodeState,
|
|
handle_ctrl: HandleControl,
|
|
modifiers: Modifiers,
|
|
layout: T,
|
|
set: S,
|
|
}
|
|
|
|
impl<T, S> Keyboard<T, S>
|
|
where
|
|
T: KeyboardLayout + Default,
|
|
S: ScancodeSet + Default,
|
|
{
|
|
/// Make a new Keyboard object with the given layout.
|
|
pub fn new(_layout: T, _set: S, handle_ctrl: HandleControl) -> Keyboard<T, S> {
|
|
Keyboard {
|
|
register: 0,
|
|
num_bits: 0,
|
|
decode_state: DecodeState::Start,
|
|
handle_ctrl,
|
|
modifiers: Modifiers {
|
|
lshift: false,
|
|
rshift: false,
|
|
lctrl: false,
|
|
rctrl: false,
|
|
numlock: true,
|
|
capslock: false,
|
|
alt_gr: false,
|
|
},
|
|
layout: T::default(),
|
|
set: S::default(),
|
|
}
|
|
}
|
|
|
|
/// Change the Ctrl key mapping.
|
|
pub fn set_ctrl_handling(&mut self, new_value: HandleControl) {
|
|
self.handle_ctrl = new_value;
|
|
}
|
|
|
|
/// Get the current Ctrl key mapping.
|
|
pub fn get_ctrl_handling(&self) -> HandleControl {
|
|
self.handle_ctrl
|
|
}
|
|
|
|
/// Clears the bit register.
|
|
///
|
|
/// Call this when there is a timeout reading data from the keyboard.
|
|
pub fn clear(&mut self) {
|
|
self.register = 0;
|
|
self.num_bits = 0;
|
|
self.decode_state = DecodeState::Start;
|
|
}
|
|
|
|
/// Processes a 16-bit word from the keyboard.
|
|
///
|
|
/// * The start bit (0) must be in bit 0.
|
|
/// * The data octet must be in bits 1..8, with the LSB in bit 1 and the
|
|
/// MSB in bit 8.
|
|
/// * The parity bit must be in bit 9.
|
|
/// * The stop bit (1) must be in bit 10.
|
|
pub fn add_word(&mut self, word: u16) -> Result<Option<KeyEvent>, Error> {
|
|
let byte = self.check_word(word)?;
|
|
self.add_byte(byte)
|
|
}
|
|
|
|
/// Processes an 8-bit byte from the keyboard.
|
|
///
|
|
/// We assume the start, stop and parity bits have been processed and
|
|
/// verified.
|
|
pub fn add_byte(&mut self, byte: u8) -> Result<Option<KeyEvent>, Error> {
|
|
self.set.advance_state(&mut self.decode_state, byte)
|
|
}
|
|
|
|
/// Shift a bit into the register.
|
|
///
|
|
/// Call this /or/ call `add_word` - don't call both.
|
|
/// Until the last bit is added you get Ok(None) returned.
|
|
pub fn add_bit(&mut self, bit: bool) -> Result<Option<KeyEvent>, Error> {
|
|
self.register |= (bit as u16) << self.num_bits;
|
|
self.num_bits += 1;
|
|
if self.num_bits == KEYCODE_BITS {
|
|
let word = self.register;
|
|
self.register = 0;
|
|
self.num_bits = 0;
|
|
self.add_word(word)
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
/// Processes a `KeyEvent` returned from `add_bit`, `add_byte` or `add_word`
|
|
/// and produces a decoded key.
|
|
///
|
|
/// For example, the KeyEvent for pressing the '5' key on your keyboard
|
|
/// gives a DecodedKey of unicode character '5', unless the shift key is
|
|
/// held in which case you get the unicode character '%'.
|
|
pub fn process_keyevent(&mut self, ev: KeyEvent) -> Option<DecodedKey> {
|
|
match ev {
|
|
KeyEvent {
|
|
code: KeyCode::ShiftLeft,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.lshift = true;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ShiftRight,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.rshift = true;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ShiftLeft,
|
|
state: KeyState::Up,
|
|
} => {
|
|
self.modifiers.lshift = false;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ShiftRight,
|
|
state: KeyState::Up,
|
|
} => {
|
|
self.modifiers.rshift = false;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::CapsLock,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.capslock = !self.modifiers.capslock;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::NumpadLock,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.numlock = !self.modifiers.numlock;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ControlLeft,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.lctrl = true;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ControlLeft,
|
|
state: KeyState::Up,
|
|
} => {
|
|
self.modifiers.lctrl = false;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ControlRight,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.rctrl = true;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::ControlRight,
|
|
state: KeyState::Up,
|
|
} => {
|
|
self.modifiers.rctrl = false;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::AltRight,
|
|
state: KeyState::Down,
|
|
} => {
|
|
self.modifiers.alt_gr = true;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: KeyCode::AltRight,
|
|
state: KeyState::Up,
|
|
} => {
|
|
self.modifiers.alt_gr = false;
|
|
None
|
|
}
|
|
KeyEvent {
|
|
code: c,
|
|
state: KeyState::Down,
|
|
} => Some(
|
|
self.layout
|
|
.map_keycode(c, &self.modifiers, self.handle_ctrl),
|
|
),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn get_bit(&self, word: u16, offset: usize) -> bool {
|
|
((word >> offset) & 0x0001) != 0
|
|
}
|
|
|
|
fn has_even_number_bits(&self, data: u8) -> bool {
|
|
(data.count_ones() % 2) == 0
|
|
}
|
|
|
|
/// Check 11-bit word has 1 start bit, 1 stop bit and an odd parity bit.
|
|
fn check_word(&self, word: u16) -> Result<u8, Error> {
|
|
let start_bit = self.get_bit(word, 0);
|
|
let parity_bit = self.get_bit(word, 9);
|
|
let stop_bit = self.get_bit(word, 10);
|
|
let data = ((word >> 1) & 0xFF) as u8;
|
|
if start_bit {
|
|
return Err(Error::BadStartBit);
|
|
}
|
|
if !stop_bit {
|
|
return Err(Error::BadStopBit);
|
|
}
|
|
let need_parity = self.has_even_number_bits(data);
|
|
// Odd parity, so these must not match
|
|
if need_parity != parity_bit {
|
|
return Err(Error::ParityError);
|
|
}
|
|
|
|
Ok(data)
|
|
}
|
|
}
|
|
|
|
pub fn parse_format() {
|
|
let test = include_str!("../../keymaps/qwerty.keymap").lines();
|
|
// r#"0-NONE\n1-HI#Says HI"#
|
|
for x in test {
|
|
for y in x.split('-') {
|
|
if y.parse::<u64>().is_ok() {
|
|
todo![];
|
|
// NOTE: this unwrap is ok bcause of the above check
|
|
// println!("NUM: {:?}", y.parse::<u64>().unwrap());
|
|
// serial_println!("NUM: {:?}", y.parse::<u64>().unwrap());
|
|
} else if y.starts_with('#') {
|
|
// ignore all # delimeted lines
|
|
} else {
|
|
// println!("STR: {:?}", y);
|
|
// serial_println!("STR: {:?}", y);
|
|
match y.trim() {
|
|
"NONE" => {}
|
|
"TAB" => {}
|
|
"SHIFT" => {}
|
|
"SCROLL_LOCK" => {}
|
|
"FUNCTION_1" => {}
|
|
"FUNCTION_2" => {}
|
|
"FUNCTION_3" => {}
|
|
"FUNCTION_4" => {}
|
|
"FUNCTION_5" => {}
|
|
"FUNCTION_6" => {}
|
|
"FUNCTION_7" => {}
|
|
"FUNCTION_8" => {}
|
|
"FUNCTION_9" => {}
|
|
"FUNCTION_10" => {}
|
|
"FUNCTION_11" => {}
|
|
"FUNCTION_12" => {}
|
|
"COMMA" => {}
|
|
"PERIOD" => {}
|
|
"FORWARDSLASH" => {}
|
|
"GRAVE" => {}
|
|
"BRACKET_LEFT" => {}
|
|
"BACK_SLASH" => {}
|
|
"BRACKET_RIGHT" => {}
|
|
"QUOTE" => {}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|