use crate::key_code::KeyCode;
use crate::layout::{StackedIter, WaitingAction};
use core::fmt::Debug;
#[non_exhaustive]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum SequenceEvent<'a, T: 'a> {
NoOp,
Press(KeyCode),
Release(KeyCode),
Tap(KeyCode),
Delay {
duration: u32, },
Continue {
index: usize,
events: &'a [SequenceEvent<'a, T>],
},
Custom(&'a T),
Complete,
}
impl<'a, T> Debug for SequenceEvent<'a, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NoOp => write!(f, "NoOp"),
Self::Press(arg0) => f.debug_tuple("Press").field(arg0).finish(),
Self::Release(arg0) => f.debug_tuple("Release").field(arg0).finish(),
Self::Tap(arg0) => f.debug_tuple("Tap").field(arg0).finish(),
Self::Delay { duration } => {
f.debug_struct("Delay").field("duration", duration).finish()
}
Self::Continue { index, events } => f
.debug_struct("Continue")
.field("index", index)
.field("events", events)
.finish(),
Self::Custom(_) => write!(f, "Custom"),
Self::Complete => write!(f, "Complete"),
}
}
}
#[non_exhaustive]
#[derive(Clone, Copy)]
pub enum HoldTapConfig {
Default,
HoldOnOtherKeyPress,
PermissiveHold,
Custom(fn(StackedIter) -> Option<WaitingAction>),
}
impl Debug for HoldTapConfig {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
HoldTapConfig::Default => f.write_str("Default"),
HoldTapConfig::HoldOnOtherKeyPress => f.write_str("HoldOnOtherKeyPress"),
HoldTapConfig::PermissiveHold => f.write_str("PermissiveHold"),
HoldTapConfig::Custom(func) => f
.debug_tuple("Custom")
.field(&(*func as fn(StackedIter<'static>) -> Option<WaitingAction>) as &dyn Debug)
.finish(),
}
}
}
impl PartialEq for HoldTapConfig {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(HoldTapConfig::Default, HoldTapConfig::Default)
| (HoldTapConfig::HoldOnOtherKeyPress, HoldTapConfig::HoldOnOtherKeyPress)
| (HoldTapConfig::PermissiveHold, HoldTapConfig::PermissiveHold) => true,
(HoldTapConfig::Custom(self_func), HoldTapConfig::Custom(other_func)) => {
*self_func as fn(StackedIter<'static>) -> Option<WaitingAction> == *other_func
}
_ => false,
}
}
}
impl Eq for HoldTapConfig {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ReleasableState {
KeyCode(KeyCode),
Layer(usize),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct HoldTapAction<'a, T>
where
T: 'a,
{
pub timeout: u16,
pub hold: Action<'a, T>,
pub tap: Action<'a, T>,
pub timeout_action: Action<'a, T>,
pub config: HoldTapConfig,
pub tap_hold_interval: u16,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct OneShot<'a, T = core::convert::Infallible>
where
T: 'a,
{
pub action: &'a Action<'a, T>,
pub timeout: u16,
pub end_config: OneShotEndConfig,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum OneShotEndConfig {
EndOnFirstPress,
EndOnFirstRelease,
}
pub const ONE_SHOT_MAX_ACTIVE: usize = 8;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct TapDance<'a, T = core::convert::Infallible>
where
T: 'a,
{
pub actions: &'a [&'a Action<'a, T>],
pub timeout: u16,
pub config: TapDanceConfig,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TapDanceConfig {
Lazy,
Eager,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ChordsGroup<'a, T = core::convert::Infallible>
where
T: 'a,
{
pub coords: &'a [((u8, u16), ChordKeys)],
pub chords: &'a [(ChordKeys, &'a Action<'a, T>)],
pub timeout: u16,
}
impl<'a, T> ChordsGroup<'a, T> {
pub fn get_keys(&self, coord: (u8, u16)) -> Option<ChordKeys> {
self.coords.iter().find(|c| c.0 == coord).map(|c| c.1)
}
pub fn get_chord(&self, keys: ChordKeys) -> Option<&'a Action<'a, T>> {
self.chords
.iter()
.find(|(chord_keys, _)| *chord_keys == keys)
.map(|(_, action)| *action)
}
pub fn get_chord_if_unambiguous(&self, keys: ChordKeys) -> Option<&'a Action<'a, T>> {
self.chords
.iter()
.try_fold(None, |res, &(chord_keys, action)| {
if chord_keys == keys {
Ok(Some(action))
} else if chord_keys | keys == chord_keys {
Err(())
} else {
Ok(res)
}
})
.unwrap_or_default()
}
}
pub type ChordKeys = u32;
pub const MAX_CHORD_KEYS: usize = ChordKeys::BITS as usize;
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum Action<'a, T = core::convert::Infallible>
where
T: 'a,
{
NoOp,
Trans,
KeyCode(KeyCode),
MultipleKeyCodes(&'a &'a [KeyCode]),
MultipleActions(&'a &'a [Action<'a, T>]),
Layer(usize),
DefaultLayer(usize),
Sequence {
events: &'a &'a [SequenceEvent<'a, T>],
},
CancelSequences,
ReleaseState(ReleasableState),
HoldTap(&'a HoldTapAction<'a, T>),
Custom(T),
OneShot(&'a OneShot<'a, T>),
TapDance(&'a TapDance<'a, T>),
Chords(&'a ChordsGroup<'a, T>),
}
impl<'a, T> Action<'a, T> {
pub fn layer(self) -> Option<usize> {
match self {
Action::Layer(l) => Some(l),
_ => None,
}
}
pub fn key_codes(&self) -> impl Iterator<Item = KeyCode> + '_ {
match self {
Action::KeyCode(kc) => core::slice::from_ref(kc).iter().cloned(),
Action::MultipleKeyCodes(kcs) => kcs.iter().cloned(),
_ => [].iter().cloned(),
}
}
}
pub const fn k<T>(kc: KeyCode) -> Action<'static, T> {
Action::KeyCode(kc)
}
pub const fn l<T>(layer: usize) -> Action<'static, T> {
Action::Layer(layer)
}
pub const fn d<T>(layer: usize) -> Action<'static, T> {
Action::DefaultLayer(layer)
}