use crate::keycode::{KeyCode, ModifierCombination};
use defmt::{error, warn, Format};
use num_enum::FromPrimitive;
use packed_struct::PackedStructSlice;
#[derive(Format, Copy, Clone, PartialEq, Eq)]
pub enum KeyAction {
No,
Transparent,
Single(Action),
Tap(Action),
OneShot(Action),
LayerTapHold(Action, u8),
WithModifier(Action, ModifierCombination),
ModifierTapHold(Action, ModifierCombination),
TapHold(Action, Action),
}
impl KeyAction {
pub(crate) fn to_key_action_code(&self) -> u16 {
match self {
KeyAction::No => 0x0000,
KeyAction::Transparent => 0x0001,
KeyAction::Single(a) => a.to_action_code(),
KeyAction::Tap(a) => 0x0001 | a.to_action_code(),
KeyAction::OneShot(a) => 0x0010 | a.to_action_code(),
KeyAction::WithModifier(a, m) => {
let mut modifier_bits = [0];
ModifierCombination::pack_to_slice(m, &mut modifier_bits).unwrap_or_default();
0x4000 | ((modifier_bits[0] as u16) << 8) | a.to_basic_action_code()
}
KeyAction::ModifierTapHold(action, modifier) => {
let mut modifier_bits = [0];
ModifierCombination::pack_to_slice(modifier, &mut modifier_bits)
.unwrap_or_default();
0x6000 | ((modifier_bits[0] as u16) << 8) | action.to_basic_action_code()
}
KeyAction::LayerTapHold(action, layer) => {
if *layer < 16 {
0x3000 | ((*layer as u16) << 15) | action.to_basic_action_code()
} else {
error!("LayerTapHold supports only layer 0~15, got {}", layer);
0x0000
}
}
KeyAction::TapHold(tap, hold) => {
0x8000 | (hold.to_basic_action_code() << 15) | tap.to_basic_action_code()
}
}
}
pub(crate) fn from_key_action_code(code: u16) -> KeyAction {
match code {
0x0..=0xFFF => KeyAction::Single(Action::from_action_code(code)),
0x1000..=0x1FFF => KeyAction::Tap(Action::from_action_code(code & 0xFFF)),
0x2000..=0x2FFF => KeyAction::OneShot(Action::from_action_code(code & 0xFFF)),
0x3000..=0x3FFF => {
let layer = (code >> 8) & 0xF;
KeyAction::LayerTapHold(Action::from_action_code(code & 0xFF), layer as u8)
}
0x4000..=0x5FFF => {
let modifier_bits = (code >> 8) & 0x1F;
KeyAction::WithModifier(
Action::from_action_code(code & 0xFF),
ModifierCombination::from_bits(modifier_bits as u8),
)
}
0x6000..=0x7FFF => {
let modifier_bits = (code >> 8) & 0x1F;
KeyAction::ModifierTapHold(
Action::from_action_code(code & 0xFF),
ModifierCombination::from_bits(modifier_bits as u8),
)
}
0x8000..=0xFFFF => KeyAction::TapHold(
Action::from_action_code(code & 0xFF),
Action::from_action_code((code >> 8) & 0x7F),
),
}
}
}
#[derive(Debug, Format, Copy, Clone, PartialEq, Eq)]
pub enum Action {
Key(KeyCode),
Modifier(ModifierCombination),
LayerOn(u8),
LayerOff(u8),
LayerToggle(u8),
}
impl Action {
pub(crate) fn to_action_code(&self) -> u16 {
match self {
Action::Key(k) => *k as u16,
Action::Modifier(m) => 0xE00 | (m.to_bits() as u16),
Action::LayerOn(layer) => 0xE20 | (*layer as u16),
Action::LayerOff(layer) => 0xE40 | (*layer as u16),
Action::LayerToggle(layer) => 0xE60 | (*layer as u16),
}
}
pub(crate) fn from_action_code(action_code: u16) -> Action {
match action_code {
0x000..=0xCFF => Action::Key(KeyCode::from_primitive(action_code)),
0xE00..=0xE1F => {
let modifier_bits = (action_code & 0xFF) as u8;
Action::Modifier(ModifierCombination::from_bits(modifier_bits))
}
0xE20..=0xE3F => {
let layer = (action_code & 0xFF) as u8;
Action::LayerOn(layer)
}
0xE40..=0xE5F => {
let layer = (action_code & 0xFF) as u8;
Action::LayerOff(layer)
}
0xE60..=0xE7F => {
let layer = (action_code & 0xFF) as u8;
Action::LayerToggle(layer)
}
_ => {
warn!("Not a valid 12-bit action code: {:#X}", action_code);
Action::Key(KeyCode::No)
}
}
}
pub(crate) fn to_basic_action_code(&self) -> u16 {
match self {
Action::Key(kc) => {
if kc.is_basic() {
*kc as u16
} else {
0
}
}
_ => 0,
}
}
}