Skip to content

Commit

Permalink
WIP: vial combo support
Browse files Browse the repository at this point in the history
  • Loading branch information
pcasotti committed Nov 24, 2024
1 parent b914967 commit 46ca162
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 136 deletions.
66 changes: 9 additions & 57 deletions rmk/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
hid::{ConnectionType, HidWriterWrapper},
keyboard_macro::{MacroOperation, NUM_MACRO},
keycode::{KeyCode, ModifierCombination},
keymap::KeyMap,
keymap::{Combo, KeyMap, COMBO_MAX_LENGTH},
usb::descriptor::{CompositeReport, CompositeReportType, ViaReport},
KEYBOARD_STATE,
};
Expand All @@ -30,9 +30,6 @@ pub(crate) struct KeyEvent {
pub(crate) const EVENT_CHANNEL_SIZE: usize = 32;
pub(crate) const REPORT_CHANNEL_SIZE: usize = 32;

pub const COMBO_MAX_NUM: usize = 8;
pub const COMBO_MAX_LENGTH: usize = 8;

pub(crate) static key_event_channel: Channel<
CriticalSectionRawMutex,
KeyEvent,
Expand Down Expand Up @@ -68,49 +65,6 @@ impl<T> OneShotState<T> {
}
}

struct Combo {
pub actions: Vec<KeyAction, COMBO_MAX_LENGTH>,
pub result: KeyAction,
state: u8,
}

impl Combo {
pub fn new(actions: Vec<KeyAction, COMBO_MAX_LENGTH>, result: KeyAction) -> Self {
Self {
actions,
result,
state: 0,
}
}

pub fn update(&mut self, key_action: KeyAction) -> bool {
let action_idx = self.actions.iter().position(|&a| a == key_action);
if let Some(i) = action_idx {
self.state |= 1 << i;
true
} else {
self.reset();
false
}
}

pub fn done(&self) -> bool {
self.keys_pressed() == self.actions.len() as u32
}

pub fn started(&self) -> bool {
self.state != 0
}

pub fn keys_pressed(&self) -> u32 {
self.state.count_ones()
}

pub fn reset(&mut self) {
self.state = 0;
}
}

/// Matrix scanning task sends this [KeyboardReportMessage] to communication task.
pub(crate) enum KeyboardReportMessage {
/// Normal keyboard hid report
Expand Down Expand Up @@ -206,8 +160,6 @@ pub(crate) struct Keyboard<'a, const ROW: usize, const COL: usize, const NUM_LAY
mouse_key_move_delta: i8,
mouse_wheel_move_delta: i8,

/// Combos
combos: Vec<Combo, COMBO_MAX_NUM>,
/// Buffer for pressed `KeyAction` and `KeyEvents` in combos
combo_actions_buffer: Deque<(KeyAction, KeyEvent), COMBO_MAX_LENGTH>,
}
Expand Down Expand Up @@ -242,7 +194,6 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
last_mouse_tick: FnvIndexMap::new(),
mouse_key_move_delta: 8,
mouse_wheel_move_delta: 1,
combos: Vec::new(),
combo_actions_buffer: Deque::new(),
}
}
Expand Down Expand Up @@ -372,10 +323,10 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
key_action: KeyAction,
key_event: KeyEvent,
) -> Option<KeyAction> {
for combo in self.combos.iter_mut() {
for combo in self.keymap.borrow_mut().combos.iter_mut() {
if !key_event.pressed && combo.done() && combo.actions.contains(&key_action) {
combo.reset();
return Some(combo.result);
return Some(combo.output);
}
}

Expand All @@ -387,28 +338,29 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
error!("Combo actions buffer overflowed! This is a bug and should not happen!");
}

let is_combo_action = self.combos.iter_mut().fold(false, |is_combo, combo| {
let is_combo_action = self.keymap.borrow_mut().combos.iter_mut().fold(false, |is_combo, combo| {
is_combo || combo.update(key_action)
});

if is_combo_action && key_event.pressed {
if let Some(combo) = self
if let Some(combo) = self.keymap.borrow_mut()
.combos
.iter()
.filter(|c| c.actions.contains(&key_action))
.max_by_key(|c| c.keys_pressed())
{
// TODO: this is wrong
for _ in 0..(self.combo_actions_buffer.len() - combo.keys_pressed() as usize) {
if let Some((action, event)) = self.combo_actions_buffer.pop_front() {
self.process_key_action(action, event).await;
}
}
}

let next_action = self
let next_action = self.keymap.borrow_mut()
.combos
.iter()
.find_map(|combo| combo.done().then_some(combo.result));
.find_map(|combo| combo.done().then_some(combo.output));

if next_action.is_some() {
self.combo_actions_buffer.clear();
Expand All @@ -432,7 +384,7 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
while let Some((action, event)) = self.combo_actions_buffer.pop_front() {
self.process_key_action(action, event).await;
}
self.combos
self.keymap.borrow_mut().combos
.iter_mut()
.filter(|c| !c.done())
.for_each(Combo::reset);
Expand Down
91 changes: 90 additions & 1 deletion rmk/src/keymap.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,62 @@
use crate::{
action::KeyAction,
action::{Action, KeyAction},
keyboard::KeyEvent,
keyboard_macro::{MacroOperation, MACRO_SPACE_SIZE},
keycode::KeyCode,
reboot_keyboard,
storage::Storage,
};
use heapless::Vec;
use defmt::{error, warn};
use embedded_storage_async::nor_flash::NorFlash;
use num_enum::FromPrimitive;

pub(crate) const COMBO_MAX_NUM: usize = 8;
pub(crate) const COMBO_MAX_LENGTH: usize = 4;

pub(crate) struct Combo {
pub(crate) actions: Vec<KeyAction, COMBO_MAX_LENGTH>,
pub(crate) output: KeyAction,
state: u8,
}

impl Combo {
pub fn new(actions: Vec<KeyAction, COMBO_MAX_LENGTH>, output: KeyAction) -> Self {
Self {
actions,
output,
state: 0,
}
}

pub fn update(&mut self, key_action: KeyAction) -> bool {
let action_idx = self.actions.iter().position(|&a| a == key_action);
if let Some(i) = action_idx {
self.state |= 1 << i;
true
} else {
self.reset();
false
}
}

pub fn done(&self) -> bool {
self.keys_pressed() == self.actions.len() as u32
}

pub fn started(&self) -> bool {
self.state != 0
}

pub fn keys_pressed(&self) -> u32 {
self.state.count_ones()
}

pub fn reset(&mut self) {
self.state = 0;
}
}

/// Keymap represents the stack of layers.
///
/// The conception of Keymap in rmk is borrowed from qmk: <https://docs.qmk.fm/#/keymap>.
Expand All @@ -27,18 +74,40 @@ pub(crate) struct KeyMap<'a, const ROW: usize, const COL: usize, const NUM_LAYER
layer_cache: [[u8; COL]; ROW],
/// Macro cache
pub(crate) macro_cache: [u8; MACRO_SPACE_SIZE],
/// Combos
pub(crate) combos: Vec<Combo, COMBO_MAX_NUM>,
}

impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
KeyMap<'a, ROW, COL, NUM_LAYER>
{
pub(crate) async fn new(action_map: &'a mut [[[KeyAction; COL]; ROW]; NUM_LAYER]) -> Self {
let mut combos = Vec::new();
let mut actions = Vec::new();
let mut actions2 = Vec::new();
unsafe {
actions.push_unchecked(KeyAction::Single(Action::Key(KeyCode::O)));
actions.push_unchecked(KeyAction::Single(Action::Key(KeyCode::E)));
actions.push_unchecked(KeyAction::Single(Action::Key(KeyCode::U)));
combos.push_unchecked(Combo::new(
actions,
KeyAction::Single(Action::LayerToggle(6)),
));
actions2.push_unchecked(KeyAction::Single(Action::Key(KeyCode::A)));
actions2.push_unchecked(KeyAction::Single(Action::Key(KeyCode::S)));
actions2.push_unchecked(KeyAction::Single(Action::Key(KeyCode::D)));
combos.push_unchecked(Combo::new(
actions2,
KeyAction::Single(Action::LayerToggle(6)),
));
}
KeyMap {
layers: action_map,
layer_state: [false; NUM_LAYER],
default_layer: 0,
layer_cache: [[0; COL]; ROW],
macro_cache: [0; MACRO_SPACE_SIZE],
combos,
}
}

Expand Down Expand Up @@ -74,12 +143,32 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
}
}

let mut combos = Vec::new();
let mut actions = Vec::new();
let mut actions2 = Vec::new();
unsafe {
actions.push_unchecked(KeyAction::Single(Action::Key(KeyCode::O)));
actions.push_unchecked(KeyAction::Single(Action::Key(KeyCode::E)));
actions.push_unchecked(KeyAction::Single(Action::Key(KeyCode::U)));
combos.push_unchecked(Combo::new(
actions,
KeyAction::Single(Action::LayerToggle(6)),
));
actions2.push_unchecked(KeyAction::Single(Action::Key(KeyCode::A)));
actions2.push_unchecked(KeyAction::Single(Action::Key(KeyCode::S)));
actions2.push_unchecked(KeyAction::Single(Action::Key(KeyCode::D)));
combos.push_unchecked(Combo::new(
actions2,
KeyAction::Single(Action::LayerToggle(6)),
));
}
KeyMap {
layers: action_map,
layer_state: [false; NUM_LAYER],
default_layer: 0,
layer_cache: [[0; COL]; ROW],
macro_cache,
combos,
}
}

Expand Down
Loading

0 comments on commit 46ca162

Please sign in to comment.