use heapless::Vec;
use postcard::experimental::max_size::MaxSize;
use rmk_types::action::KeyAction;
use serde::{Deserialize, Serialize};
use crate::COMBO_MAX_LENGTH;
use crate::event::KeyboardEvent;
#[derive(Clone, Copy, Debug, Serialize, Deserialize, MaxSize)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ComboConfig {
pub(crate) actions: [KeyAction; COMBO_MAX_LENGTH],
pub(crate) output: KeyAction,
pub(crate) layer: Option<u8>,
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Combo {
pub(crate) config: ComboConfig,
state: u8,
is_triggered: bool,
}
impl Default for Combo {
fn default() -> Self {
Self::empty()
}
}
impl ComboConfig {
pub fn new<I: IntoIterator<Item = KeyAction>>(actions: I, output: KeyAction, layer: Option<u8>) -> Self {
let mut combo_actions = [KeyAction::No; COMBO_MAX_LENGTH];
for (id, action) in actions.into_iter().enumerate() {
if id < COMBO_MAX_LENGTH {
combo_actions[id] = action;
}
}
Self {
actions: combo_actions,
output,
layer,
}
}
pub fn empty() -> Self {
Self::new(Vec::<KeyAction, COMBO_MAX_LENGTH>::new(), KeyAction::No, None)
}
pub fn size(&self) -> usize {
self.actions.iter().filter(|&&a| a != KeyAction::No).count()
}
pub fn find_key_action_index(&self, key_action: &KeyAction) -> Option<usize> {
self.actions.iter().position(|&a| a == *key_action)
}
}
impl Combo {
pub fn new(config: ComboConfig) -> Self {
Self {
config,
state: 0,
is_triggered: false,
}
}
pub fn empty() -> Self {
Self::new(ComboConfig::empty())
}
pub(crate) fn update(&mut self, key_action: &KeyAction, key_event: KeyboardEvent, active_layer: u8) -> bool {
if !key_event.pressed || self.config.actions.is_empty() || self.is_triggered {
return false;
}
if let Some(layer) = self.config.layer
&& layer != active_layer
{
return false;
}
let action_idx = self.config.find_key_action_index(key_action);
if let Some(i) = action_idx {
self.state |= 1 << i;
} else if !self.is_all_pressed() {
self.reset();
}
action_idx.is_some()
}
pub(crate) fn update_released(&mut self, key_action: &KeyAction) -> bool {
if let Some(i) = self.config.find_key_action_index(key_action) {
self.state &= !(1 << i);
}
if self.state == 0 {
if self.is_triggered {
self.reset();
return true;
}
self.reset();
}
false
}
pub(crate) fn trigger(&mut self) -> KeyAction {
if self.is_triggered() {
return self.config.output;
}
if self.config.output.is_empty() {
return self.config.output;
}
if self.is_all_pressed() {
self.is_triggered = true;
}
self.config.output
}
pub(crate) fn is_triggered(&self) -> bool {
self.is_triggered
}
pub(crate) fn is_all_pressed(&self) -> bool {
let cnt = self.config.size();
cnt > 0 && self.keys_pressed() == cnt as u32
}
pub(crate) fn size(&self) -> usize {
self.config.size()
}
pub(crate) fn started(&self) -> bool {
self.state != 0
}
pub(crate) fn keys_pressed(&self) -> u32 {
self.state.count_ones()
}
pub(crate) fn reset(&mut self) {
self.state = 0;
self.is_triggered = false;
}
}