use rmk_types::keycode::{KeyCode, from_ascii, to_ascii};
use crate::MACRO_SPACE_SIZE;
use crate::keymap::fill_vec;
#[derive(Debug, Clone)]
pub enum MacroOperation {
End,
Tap(KeyCode),
Press(KeyCode),
Release(KeyCode),
Delay(u16),
Text(KeyCode, bool), }
impl MacroOperation {
pub(crate) fn get_next_macro_operation(
macro_sequences: &[u8],
macro_start_idx: usize,
offset: usize,
) -> (MacroOperation, usize) {
let idx = macro_start_idx + offset;
if idx >= macro_sequences.len() - 1 {
return (MacroOperation::End, offset);
}
match (macro_sequences[idx], macro_sequences[idx + 1]) {
(0, _) => (MacroOperation::End, offset),
(1, 1) => {
if idx + 2 < macro_sequences.len() {
let keycode = (macro_sequences[idx + 2] as u16).into();
(MacroOperation::Tap(keycode), offset + 3)
} else {
(MacroOperation::End, offset + 3)
}
}
(1, 2) => {
if idx + 2 < macro_sequences.len() {
let keycode = (macro_sequences[idx + 2] as u16).into();
(MacroOperation::Press(keycode), offset + 3)
} else {
(MacroOperation::End, offset + 3)
}
}
(1, 3) => {
if idx + 2 < macro_sequences.len() {
let keycode = (macro_sequences[idx + 2] as u16).into();
(MacroOperation::Release(keycode), offset + 3)
} else {
(MacroOperation::End, offset + 3)
}
}
(1, 4) => {
if idx + 3 < macro_sequences.len() {
let delay_ms = (macro_sequences[idx + 2].max(1) as u16 - 1)
+ (macro_sequences[idx + 3].max(1) as u16 - 1) * 255;
(MacroOperation::Delay(delay_ms), offset + 4)
} else {
(MacroOperation::End, offset + 4)
}
}
(1, 5) | (1, 6) | (1, 7) => {
warn!("VIAL_MACRO_EXT is not supported");
(MacroOperation::Delay(0), offset + 4)
}
_ => {
let (keycode, is_caps) = from_ascii(macro_sequences[idx]);
(MacroOperation::Text(keycode, is_caps), offset + 1)
}
}
}
pub(crate) fn get_macro_sequence_start(macro_sequences: &[u8], guessed_macro_start_idx: u8) -> Option<usize> {
let mut idx = 0;
let mut potential_start_idx = guessed_macro_start_idx;
loop {
if potential_start_idx == 0 || idx >= macro_sequences.len() {
break;
}
if macro_sequences[idx] == 0 {
potential_start_idx -= 1;
}
idx += 1;
}
if idx == macro_sequences.len() { None } else { Some(idx) }
}
}
pub fn define_macro_sequences(
macro_sequences: &[heapless::Vec<MacroOperation, MACRO_SPACE_SIZE>],
) -> [u8; MACRO_SPACE_SIZE] {
let mut macro_sequences_linear = fold_to_binary(macro_sequences);
fill_vec(&mut macro_sequences_linear);
macro_sequences_linear
.into_array()
.expect("as we resized the vector, this can't happen!")
}
impl IntoIterator for MacroOperation {
type Item = MacroOperation;
type IntoIter = <heapless::Vec<MacroOperation, MACRO_SPACE_SIZE> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
heapless::Vec::from_iter([self]).into_iter()
}
}
pub fn to_macro_sequence(text: &str) -> heapless::Vec<MacroOperation, MACRO_SPACE_SIZE> {
text.as_bytes()
.iter()
.map(|character| {
let (keycode, shifted) = from_ascii(*character);
MacroOperation::Text(keycode, shifted)
})
.collect()
}
fn fold_to_binary(
macro_sequences: &[heapless::Vec<MacroOperation, MACRO_SPACE_SIZE>],
) -> heapless::Vec<u8, MACRO_SPACE_SIZE> {
const TOO_MANY_ELEMENTS_ERROR_TEXT: &str = "Too many Macro Operations! The sum of all Macro Operations of all Macro Sequences cannot be more than MACRO_SPACE_SIZE";
macro_sequences
.iter()
.map(|macro_sequence| {
let mut vec_seq = macro_sequence
.into_iter()
.filter(|macro_operation| !matches!(macro_operation, MacroOperation::End))
.map(serialize)
.fold(heapless::Vec::<u8, MACRO_SPACE_SIZE>::new(), |mut acc, e| {
acc.extend_from_slice(&e).expect(TOO_MANY_ELEMENTS_ERROR_TEXT);
acc
});
vec_seq.push(0x00).expect(TOO_MANY_ELEMENTS_ERROR_TEXT); vec_seq
})
.fold(heapless::Vec::<u8, MACRO_SPACE_SIZE>::new(), |mut acc, e| {
acc.extend_from_slice(&e).expect(TOO_MANY_ELEMENTS_ERROR_TEXT);
acc
})
}
fn serialize(macro_operation: &MacroOperation) -> heapless::Vec<u8, 4> {
match macro_operation {
MacroOperation::End => heapless::Vec::from_slice(&[0x00]).unwrap(),
MacroOperation::Tap(key_code) => {
let mut result = heapless::Vec::from_slice(&[0x01, 0x01]).unwrap();
result
.extend_from_slice(&[(*key_code as u16).to_be_bytes()[1]])
.expect("impossible error");
result
}
MacroOperation::Press(key_code) => {
let mut result = heapless::Vec::from_slice(&[0x01, 0x02]).unwrap();
result
.extend_from_slice(&[(*key_code as u16).to_be_bytes()[1]])
.expect("impossible error");
result
}
MacroOperation::Release(key_code) => {
let mut result = heapless::Vec::from_slice(&[0x01, 0x03]).unwrap();
result
.extend_from_slice(&[(*key_code as u16).to_be_bytes()[1]])
.expect("impossible error");
result
}
MacroOperation::Delay(duration) => {
let mut result = heapless::Vec::from_slice(&[0x01, 0x04]).unwrap();
result
.extend_from_slice(&duration.to_be_bytes())
.expect("impossible error");
result
}
MacroOperation::Text(key_code, shifted) => heapless::Vec::from_slice(&[to_ascii(*key_code, *shifted)]).unwrap(),
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_define_one_macro_sequence_manual() {
let macro_sequences = &[heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::P),
MacroOperation::Release(KeyCode::LShift),
MacroOperation::Tap(KeyCode::A),
MacroOperation::Tap(KeyCode::T),
])
.expect("too many elements")];
let macro_sequences_binary = define_macro_sequences(macro_sequences);
let result: [u8; 16] = [
0x01, 0x02, 0xE1, 0x01, 0x01, 0x13, 0x01, 0x03, 0xE1, 0x01, 0x01, 0x4, 0x01, 0x01, 0x17, 0x00,
];
let mut result_filled = [0; MACRO_SPACE_SIZE];
for (i, element) in result.into_iter().enumerate() {
result_filled[i] = element
}
assert_eq!(macro_sequences_binary, result_filled);
}
#[test]
fn test_define_two_macro_sequence_manual() {
let macro_sequences_terminated_uneccessarily = [
heapless::Vec::from_slice(&[
MacroOperation::Text(KeyCode::H, true),
MacroOperation::Text(KeyCode::I, false),
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::P),
MacroOperation::Release(KeyCode::LShift),
MacroOperation::Tap(KeyCode::A),
MacroOperation::Tap(KeyCode::T),
])
.expect("too many elements"),
];
let macro_sequences_binary = define_macro_sequences(¯o_sequences_terminated_uneccessarily);
let result: [u8; 19] = [
0x48, 0x69, 0x00, 0x01, 0x02, 0xE1, 0x01, 0x01, 0x13, 0x01, 0x03, 0xE1, 0x01, 0x01, 0x4, 0x01, 0x01, 0x17,
0x00,
];
let mut result_filled = [0; MACRO_SPACE_SIZE];
for (i, element) in result.into_iter().enumerate() {
result_filled[i] = element
}
assert_eq!(macro_sequences_binary, result_filled);
}
#[test]
fn test_define_macro_sequences_clean() {
let macro_sequences_clean = [
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::H),
MacroOperation::Release(KeyCode::LShift),
MacroOperation::Tap(KeyCode::E),
MacroOperation::Tap(KeyCode::L),
MacroOperation::Tap(KeyCode::L),
MacroOperation::Tap(KeyCode::O),
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Tap(KeyCode::W),
MacroOperation::Tap(KeyCode::O),
MacroOperation::Tap(KeyCode::R),
MacroOperation::Tap(KeyCode::L),
MacroOperation::Tap(KeyCode::D),
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::Kc2),
MacroOperation::Release(KeyCode::LShift),
])
.expect("too many elements"),
];
let macro_sequences_binary = define_macro_sequences(¯o_sequences_clean);
let result: [u8; 48] = [
1, 2, 225, 1, 1, 11, 1, 3, 225, 1, 1, 8, 1, 1, 15, 1, 1, 15, 1, 1, 18, 0, 1, 1, 26, 1, 1, 18, 1, 1, 21, 1,
1, 15, 1, 1, 7, 0, 1, 2, 225, 1, 1, 31, 1, 3, 225, 0,
];
let mut result_filled = [0; MACRO_SPACE_SIZE];
for (i, element) in result.into_iter().enumerate() {
result_filled[i] = element
}
assert_eq!(macro_sequences_binary, result_filled);
}
#[test]
fn test_define_macro_sequences_uneccessarily_terminated() {
let macro_sequences_terminated_uneccessarily = [
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::H),
MacroOperation::Release(KeyCode::LShift),
MacroOperation::Tap(KeyCode::E),
MacroOperation::Tap(KeyCode::L),
MacroOperation::Tap(KeyCode::L),
MacroOperation::Tap(KeyCode::O),
MacroOperation::End,
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Tap(KeyCode::W),
MacroOperation::Tap(KeyCode::O),
MacroOperation::Tap(KeyCode::R),
MacroOperation::Tap(KeyCode::L),
MacroOperation::End,
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::Kc2),
MacroOperation::Release(KeyCode::LShift),
MacroOperation::End,
])
.expect("too many elements"),
];
let macro_sequences_binary = define_macro_sequences(¯o_sequences_terminated_uneccessarily);
let result: [u8; 45] = [
1, 2, 225, 1, 1, 11, 1, 3, 225, 1, 1, 8, 1, 1, 15, 1, 1, 15, 1, 1, 18, 0, 1, 1, 26, 1, 1, 18, 1, 1, 21, 1,
1, 15, 0, 1, 2, 225, 1, 1, 31, 1, 3, 225, 0,
];
let mut result_filled = [0; MACRO_SPACE_SIZE];
for (i, element) in result.into_iter().enumerate() {
result_filled[i] = element
}
assert_eq!(macro_sequences_binary, result_filled);
}
#[test]
fn test_define_macro_sequences_random_end_markers() {
let macro_sequences_random_end_markers = [
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::H),
MacroOperation::End,
MacroOperation::Release(KeyCode::LShift),
MacroOperation::Tap(KeyCode::E),
MacroOperation::End,
MacroOperation::End,
MacroOperation::Tap(KeyCode::L),
MacroOperation::End,
MacroOperation::Tap(KeyCode::L),
MacroOperation::Tap(KeyCode::O),
MacroOperation::End,
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Tap(KeyCode::W),
MacroOperation::Tap(KeyCode::O),
MacroOperation::End,
MacroOperation::End,
MacroOperation::End,
MacroOperation::End,
MacroOperation::Tap(KeyCode::R),
MacroOperation::Tap(KeyCode::L),
])
.expect("too many elements"),
heapless::Vec::from_slice(&[
MacroOperation::Press(KeyCode::LShift),
MacroOperation::Tap(KeyCode::Kc2),
MacroOperation::Release(KeyCode::LShift),
MacroOperation::End,
MacroOperation::End,
MacroOperation::End,
MacroOperation::End,
MacroOperation::End,
])
.expect("too many elements"),
];
let macro_sequences_binary = define_macro_sequences(¯o_sequences_random_end_markers);
let result: [u8; 45] = [
1, 2, 225, 1, 1, 11, 1, 3, 225, 1, 1, 8, 1, 1, 15, 1, 1, 15, 1, 1, 18, 0, 1, 1, 26, 1, 1, 18, 1, 1, 21, 1,
1, 15, 0, 1, 2, 225, 1, 1, 31, 1, 3, 225, 0,
];
let mut result_filled = [0; MACRO_SPACE_SIZE];
for (i, element) in result.into_iter().enumerate() {
result_filled[i] = element
}
assert_eq!(macro_sequences_binary, result_filled);
}
}