use alloc::collections::VecDeque;
use log::info;
use crate::{
key::{
KeyPos,
KeyState,
LogiKey,
ModuleKey,
PhysKey,
},
keycode::KeyCode,
vecmap::VecMap,
};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct MultiKey {
pub codes: &'static [KeyCode],
pub state: KeyState,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Translated {
Single(LogiKey),
Multi(MultiKey),
Broadcast(crate::serial::Msg),
Send(i8, crate::serial::Msg),
}
pub trait Translate {
fn translate(&mut self, key: Option<ModuleKey>) -> Option<Translated>;
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Action {
Nop,
Trans,
Key(KeyCode),
Seq(&'static [Action]),
Combo(&'static [KeyCode]),
Layer(usize),
BacklightSwitch,
Fn(fn()),
}
pub struct Map(pub &'static [&'static [Action]]);
pub struct Module {
pub ty: &'static str,
pub layers: &'static [Map],
pub orientation: Orientation,
}
pub enum Orientation {
RC,
CR,
}
pub struct Layout {
pub modules: &'static [Module],
}
pub struct Translator {
pub layout: Layout,
presses: VecMap<(u8, KeyPos), Action>,
layers: u32,
queue: VecDeque<Translated>,
full: usize,
bucket: usize,
}
impl Translator {
pub fn new(layout: Layout, poll_rate: u32) -> Self {
let full = (poll_rate / 1000) as usize * 10;
Self {
layout,
presses: Default::default(),
layers: 0x00_00_00_01,
queue: VecDeque::new(),
full,
bucket: full,
}
}
fn top_layer(&self) -> usize {
31 - self.layers.leading_zeros() as usize
}
fn is_active(&self, layer: usize) -> bool {
(self.layers & (0x01 << layer)) != 0
}
#[inline(never)]
fn get_action(&self, layer: usize, module: u8, pos: KeyPos) -> Option<Action> {
info!("layer: {}, module: {}, pos: {:?}", layer, module, pos);
let action = self
.layout
.modules
.get(module as usize)
.and_then(|module| {
let (outer, inner) = match module.orientation {
Orientation::RC => (pos.x, pos.y),
Orientation::CR => (pos.y, pos.x),
};
module
.layers
.get(layer)
.map(|matrix| ((outer as usize, inner as usize), matrix.0))
})
.and_then(|((outer, inner), matrix)| matrix.get(outer).and_then(|i| i.get(inner)));
dbg!(action.cloned())
}
#[inline(never)]
fn get_logical_action(&self, module: u8, pos: KeyPos) -> Option<Action> {
let mut layer = self.top_layer();
loop {
if self.is_active(layer) {
let action = self.get_action(layer, module, pos);
if let Some(action) = action {
info!("action: {:?}", action);
if action != Action::Trans {
return Some(action);
}
}
}
if layer == 0 {
return None;
}
layer -= 1;
}
}
fn enqueue(&mut self, key: Translated) {
self.queue.push_back(key)
}
fn dequeue(&mut self) -> Option<Translated> {
if self.bucket < self.full {
self.bucket += 1;
return None;
}
if !self.queue.is_empty() {
self.bucket = 0;
}
dbg!(self.queue.pop_front())
}
fn action_down(&mut self, action: Action) {
match action {
Action::Fn(_) => {}
Action::Nop => {}
Action::BacklightSwitch => {}
Action::Trans => unreachable!("should never return a transparent action"),
Action::Key(code) => self.enqueue(Translated::Single(LogiKey {
code,
state: true.into(),
})),
Action::Layer(layer) => {
self.layers ^= 0x1 << layer;
}
Action::Seq(_keys) => {}
Action::Combo(codes) => self.enqueue(Translated::Multi(MultiKey {
codes,
state: true.into(),
})),
}
}
fn action_up(&mut self, down_action: Action, module: u8, pos: KeyPos) {
match down_action {
Action::Fn(f) => f(),
Action::Trans => {}
Action::Nop => {}
Action::BacklightSwitch => {}
Action::Key(code) => self.enqueue(Translated::Single(LogiKey {
code,
state: false.into(),
})),
Action::Layer(layer) => {
let layer_action = self.get_action(layer, module, pos);
if layer_action.is_none() || layer_action == Some(Action::Trans) {
self.layers ^= 0x1 << layer;
}
}
Action::Seq(actions) => {
for action in actions {
self.action_down(*action);
self.action_up(*action, module, pos);
}
}
Action::Combo(codes) => self.enqueue(Translated::Multi(MultiKey {
codes,
state: false.into(),
})),
}
}
fn get_press(&mut self, module: u8, pos: KeyPos) -> Option<Action> {
self.presses.take(&(module, pos))
}
fn add_press(&mut self, module: u8, pos: KeyPos, action: Action) {
self.presses.insert((module, pos), action)
}
}
impl Translate for Translator {
fn translate(&mut self, key: Option<ModuleKey>) -> Option<Translated> {
let ModuleKey {
module,
key: PhysKey { pos, state },
} = if let Some(key) = key {
key
} else {
return self.dequeue();
};
if *state {
if let Some(action) = self.get_logical_action(module, pos) {
self.action_down(action);
self.add_press(module, pos, action);
}
self.dequeue()
} else {
if let Some(down_action) = self.get_press(module, pos) {
self.action_up(down_action, module, pos);
}
self.dequeue()
}
}
}
#[cfg(test)]
mod test {
use super::*;
use Action::*;
use KeyCode::*;
#[rustfmt::skip]
const TEST_LAYOUT: Layout = Layout {
modules: &[
Module {
ty: "",
orientation: Orientation::RC,
layers: &[
Map(&[
&[Key(Kb0), Seq(&[Combo(&[KbLShift, KbP]), Key(KbK), Key(KbB)])],
&[Key(KbA), Key(KbS)],
]),
Map(&[
&[Key(KbQ), Seq(&[Key(KbA), Key(KbB)])],
&[Key(KbE), Key(KbS)],
]),
],
},
Module {
ty: "",
orientation: Orientation::RC,
layers: &[
Map(&[
&[Key(KbLShift), Key(KbRCtrl)],
&[Layer(1), Layer(1)],
]),
Map(&[
&[Key(KbJ), Key(KbK)],
&[Layer(1), Trans],
]),
],
},
],
};
macro_rules! key_input {
($row:expr, $col:expr, $module:expr, nop) => {
Option::None
};
($row:expr, $col:expr, $module:expr, $press:expr) => {
Some(ModuleKey {
module: $module,
key: PhysKey {
pos: KeyPos { x: $row, y: $col },
state: $press.into(),
},
})
};
}
macro_rules! key_output {
($code:expr, $press:expr) => {
Translated::Single(LogiKey {
code: $code,
state: $press.into(),
})
};
}
macro_rules! multi_output {
($($code:expr),* ; $press:expr) => {
Translated::Multi(MultiKey {
codes: &[$($code),*],
state: $press.into(),
})
};
}
#[test]
fn test_layout() {
let mut translator = Translator::new(TEST_LAYOUT, 0);
let input = &[
key_input!(0, 0, 0, true), key_input!(0, 0, 0, false), key_input!(1, 0, 1, true), key_input!(0, 0, 0, true), key_input!(1, 0, 1, false), key_input!(0, 0, 0, false), key_input!(0, 0, 0, true), key_input!(0, 0, 0, false), key_input!(1, 0, 1, true), key_input!(1, 0, 1, false), key_input!(1, 1, 1, true), key_input!(0, 0, 0, true), key_input!(1, 1, 1, false), key_input!(0, 0, 0, false), key_input!(0, 0, 0, true), key_input!(0, 0, 0, false), key_input!(1, 0, 1, true), key_input!(1, 0, 1, false), key_input!(0, 1, 0, true), key_input!(0, 1, 0, false), key_input!(1, 0, 1, true), key_input!(1, 0, 1, false), key_input!(0, 1, 0, true),
key_input!(0, 1, 0, false),
key_input!(1, 1, 1, true),
key_input!(1, 1, 0, true),
key_input!(1, 1, 1, false),
key_input!(1, 1, 0, false),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
key_input!(0, 0, 0, nop),
];
let output: Vec<_> = input
.iter()
.filter_map(|e| translator.translate(*e))
.collect();
assert_eq!(
&output,
&[
key_output!(Kb0, true),
key_output!(Kb0, false),
key_output!(KbQ, true),
key_output!(KbQ, false),
key_output!(KbQ, true),
key_output!(KbQ, false),
key_output!(KbQ, true),
key_output!(KbQ, false),
key_output!(Kb0, true),
key_output!(Kb0, false),
key_output!(KbA, true),
key_output!(KbA, false),
key_output!(KbB, true),
key_output!(KbB, false),
multi_output!(KbLShift, KbP; true),
multi_output!(KbLShift, KbP; false),
key_output!(KbK, true),
key_output!(KbK, false),
key_output!(KbB, true),
key_output!(KbB, false),
key_output!(KbS, true),
key_output!(KbS, false),
]
);
assert!(translator.presses.inner().iter().all(|opt| opt.is_none()));
}
}