#![allow(unused)]
#[cfg(feature = "hardware")]
mod hardware;
#[cfg(feature = "hardware")]
pub use hardware::{LK201Hardware, ScanCell};
mod keys;
pub use keys::{ALL_KEYS, Key, SpecialKey};
use std::{collections::VecDeque, fmt, sync::mpsc};
use tracing::trace;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Led(u8);
impl Led {
pub fn new(byte: u8) -> Self {
Led(byte)
}
pub fn is_wait(&self) -> bool {
self.0 & 0x01 == 0x01
}
pub fn is_compose(&self) -> bool {
self.0 & 0x02 == 0x02
}
pub fn is_lock(&self) -> bool {
self.0 & 0x04 == 0x04
}
pub fn is_hold(&self) -> bool {
self.0 & 0x08 == 0x08
}
pub fn is_all(&self) -> bool {
self.0 & 0x0F == 0x0F
}
}
impl fmt::Debug for Led {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Led({:02X}=", self.0)?;
let mut first = true;
for led in [
("Wait", self.is_wait()),
("Compose", self.is_compose()),
("Lock", self.is_lock()),
("Hold", self.is_hold()),
] {
if led.1 {
if first {
first = false;
} else {
write!(f, "+")?;
}
write!(f, "{}", led.0)?;
}
}
write!(f, ")")?;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyMode {
Down = 0x80,
AutoDown = 0x82,
UpDown = 0x86,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Division(pub u8);
impl Division {
pub fn new(div: u8) -> Option<Self> {
if div <= 14 { Some(Division(div)) } else { None }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AutoRepeatRegister(pub u8);
impl AutoRepeatRegister {
pub fn new(reg: u8) -> Option<Self> {
if reg <= 3 {
Some(AutoRepeatRegister(reg))
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Volume(pub u8);
impl Volume {
pub fn new(level: u8) -> Option<Self> {
if level <= 7 {
Some(Volume(level))
} else {
None
}
}
pub fn as_param_byte(self) -> u8 {
0x80 | (self.0 & 0x7)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LK201Command {
LedEnable(Led),
LedDisable(Led),
KeyClickEnable(Volume),
CtrlKeyClickEnable,
KeyClickDisable,
CtrlKeyClickDisable,
SoundClick,
BellEnable(Volume),
BellDisable,
RingBell,
SetMode { mode: KeyMode, division: Division },
SetModeWithAutoRepeat {
mode: KeyMode,
division: Division,
register: AutoRepeatRegister,
},
RepeatToDown,
EnableRepeat { division: Division },
DisableRepeat { division: Division },
TempNoRepeat,
SetAutoRepeat {
register: AutoRepeatRegister,
timeout: u8,
rate: u8,
},
PowerUp,
RequestId,
SetDefaults,
TestMode,
TestExit,
Inhibit,
Resume,
Unknown(u8),
Unknown2(u8, u8),
Unknown3(u8, u8, u8),
}
impl LK201Command {
pub fn len(&self) -> usize {
match self {
LK201Command::LedEnable(_) => 2,
LK201Command::LedDisable(_) => 2,
LK201Command::KeyClickEnable(_) => 2,
LK201Command::CtrlKeyClickEnable => 1,
LK201Command::KeyClickDisable => 1,
LK201Command::CtrlKeyClickDisable => 1,
LK201Command::SoundClick => 1,
LK201Command::BellEnable(_) => 2,
LK201Command::BellDisable => 1,
LK201Command::RingBell => 1,
LK201Command::SetMode { .. } => 1,
LK201Command::SetModeWithAutoRepeat { .. } => 2,
LK201Command::RepeatToDown => 1,
LK201Command::EnableRepeat { .. } => 1,
LK201Command::DisableRepeat { .. } => 1,
LK201Command::TempNoRepeat => 1,
LK201Command::SetAutoRepeat { .. } => 3,
LK201Command::PowerUp => 1,
LK201Command::RequestId => 1,
LK201Command::SetDefaults => 1,
LK201Command::TestMode => 1,
LK201Command::TestExit => 1,
LK201Command::Inhibit => 1,
LK201Command::Resume => 1,
LK201Command::Unknown(_) => 1,
LK201Command::Unknown2(_, _) => 2,
LK201Command::Unknown3(_, _, _) => 3,
}
}
pub fn response(&self) -> Option<LK201Response> {
Some(match self {
LK201Command::PowerUp => LK201Response::PowerUpSelfTest {
keyboard_id_firmware: 0x01, keyboard_id_hardware: 0x00, error: PowerUpError::NoError,
keycode: 0,
},
LK201Command::RequestId => LK201Response::KeyboardId {
firmware_id: 0x01, hardware_id: 0x01, },
LK201Command::SetMode { .. } => LK201Response::ModeChangeAck,
LK201Command::SetModeWithAutoRepeat { .. } => LK201Response::ModeChangeAck,
LK201Command::SetAutoRepeat { .. } => LK201Response::ModeChangeAck,
LK201Command::RepeatToDown => LK201Response::ModeChangeAck,
LK201Command::TempNoRepeat => LK201Response::ModeChangeAck,
LK201Command::EnableRepeat { .. } => LK201Response::ModeChangeAck,
LK201Command::DisableRepeat { .. } => LK201Response::ModeChangeAck,
LK201Command::TestMode => LK201Response::TestModeAck,
LK201Command::Inhibit => LK201Response::KeyboardLockAck,
LK201Command::Unknown(_) => LK201Response::InputError,
_ => return None,
})
}
}
impl TryFrom<&VecDeque<u8>> for LK201Command {
type Error = ();
fn try_from(value: &VecDeque<u8>) -> Result<Self, Self::Error> {
let Some(&byte0) = value.get(0) else {
return Err(());
};
match byte0 {
0x13 => {
let Some(&led_byte) = value.get(1) else {
return Err(());
};
let led = Led::new(led_byte);
Ok(LK201Command::LedEnable(led))
}
0x11 => {
let Some(&led_byte) = value.get(1) else {
return Err(());
};
let led = Led::new(led_byte);
Ok(LK201Command::LedDisable(led))
}
0x1B => {
let Some(&vol_byte) = value.get(1) else {
return Err(());
};
let Some(volume) = Volume::new((vol_byte & 0x7) as u8) else {
return Ok(LK201Command::Unknown2(0x1B, vol_byte));
};
Ok(LK201Command::KeyClickEnable(volume))
}
0xBB => Ok(LK201Command::CtrlKeyClickEnable),
0x99 => Ok(LK201Command::KeyClickDisable),
0xB9 => Ok(LK201Command::CtrlKeyClickDisable),
0x9F => Ok(LK201Command::SoundClick),
0x23 => {
let Some(&vol_byte) = value.get(1) else {
return Err(());
};
let Some(volume) = Volume::new((vol_byte & 0x7) as u8) else {
return Ok(LK201Command::Unknown2(0x23, vol_byte));
};
Ok(LK201Command::BellEnable(volume))
}
0xA1 => Ok(LK201Command::BellDisable),
0xA7 => Ok(LK201Command::RingBell),
0x78..=0x7F if (byte0 >> 3) & 0xF == 0xF => {
let Some(&timeout) = value.get(1) else {
return Err(());
};
let Some(&rate) = value.get(2) else {
return Err(());
};
let Some(register) = AutoRepeatRegister::new((byte0 >> 1) & 0x3) else {
return Ok(LK201Command::Unknown2(0x78, byte0));
};
Ok(LK201Command::SetAutoRepeat {
register,
timeout: timeout & 0x7F,
rate: rate & 0x7F,
})
}
b if (b & 0x01) == 0 => {
let division_bits = (b >> 3) & 0xF;
let mode_bits = (b >> 1) & 0x3;
let has_param = (b & 0x80) == 0;
if division_bits <= 14 {
let Some(division) = Division::new(division_bits) else {
return Ok(LK201Command::Unknown(b));
};
let mode = match mode_bits {
0b00 => KeyMode::Down,
0b01 => KeyMode::AutoDown,
0b11 => KeyMode::UpDown,
_ => return Ok(LK201Command::Unknown(b)),
};
if has_param {
let Some(¶m_byte) = value.get(1) else {
return Err(());
};
let Some(register) = AutoRepeatRegister::new(param_byte & 0x3) else {
return Ok(LK201Command::Unknown2(b, param_byte));
};
return Ok(LK201Command::SetModeWithAutoRepeat {
mode,
division,
register,
});
} else {
return Ok(LK201Command::SetMode { mode, division });
}
}
Ok(LK201Command::Unknown(byte0))
}
0xD9 => Ok(LK201Command::RepeatToDown),
0xD1 => Ok(LK201Command::TempNoRepeat),
0xE1..0xEF => {
let division_bits = (byte0 >> 3) & 0b111;
let Some(division) = Division::new(division_bits) else {
return Ok(LK201Command::Unknown(byte0));
};
if byte0 & 0x02 == 0 {
Ok(LK201Command::DisableRepeat { division })
} else {
Ok(LK201Command::EnableRepeat { division })
}
}
0xFD => Ok(LK201Command::PowerUp),
0xAB => Ok(LK201Command::RequestId),
0xD3 => Ok(LK201Command::SetDefaults),
0xCB => Ok(LK201Command::TestMode),
0x8B => Ok(LK201Command::Resume),
0x89 => Ok(LK201Command::Inhibit),
_ => Ok(LK201Command::Unknown(byte0)),
}
}
}
pub mod keycodes {
pub const KEY_LOCK: u8 = 0xB0;
pub const KEY_SHIFT: u8 = 0xAE;
pub const KEY_CTRL: u8 = 0xAF;
pub const KEY_COMP: u8 = 0xB1;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LK201Response {
PowerUpSelfTest {
keyboard_id_firmware: u8,
keyboard_id_hardware: u8,
error: PowerUpError,
keycode: u8,
},
KeyboardId { firmware_id: u8, hardware_id: u8 },
ModeChangeAck,
KeyboardLockAck,
TestModeAck,
InputError,
OutputError,
KeyDown(u8),
Repeat,
AllUp,
PrefixKeyDown(u8),
}
impl LK201Response {
pub fn to_bytes(&self) -> Vec<u8> {
match self {
LK201Response::PowerUpSelfTest {
keyboard_id_firmware,
keyboard_id_hardware,
error,
keycode,
} => {
vec![
*keyboard_id_firmware,
*keyboard_id_hardware,
(*error).into(),
*keycode,
]
}
LK201Response::KeyboardId {
firmware_id,
hardware_id,
} => {
vec![*firmware_id, *hardware_id]
}
LK201Response::ModeChangeAck => vec![0xBA],
LK201Response::KeyboardLockAck => vec![0xB7],
LK201Response::TestModeAck => vec![0xB8],
LK201Response::InputError => vec![0xB6],
LK201Response::OutputError => vec![0xB5],
LK201Response::KeyDown(keycode) => vec![*keycode],
LK201Response::Repeat => vec![0xB4],
LK201Response::AllUp => vec![0xB3],
LK201Response::PrefixKeyDown(keycode) => vec![0xB9, *keycode],
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyboardType {
LK201 = 1,
LK401 = 2,
LK443 = 3,
LK421 = 4,
}
impl KeyboardType {
pub fn from_id(id: u8) -> Option<Self> {
match id {
1 => Some(KeyboardType::LK201),
2 => Some(KeyboardType::LK401),
3 => Some(KeyboardType::LK443),
4 => Some(KeyboardType::LK421),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PowerUpError {
NoError,
KeyDownError,
PowerError,
Unknown(u8),
}
impl From<u8> for PowerUpError {
fn from(byte: u8) -> Self {
match byte {
0x00 => PowerUpError::NoError,
0x3D => PowerUpError::KeyDownError,
0x3E => PowerUpError::PowerError,
other => PowerUpError::Unknown(other),
}
}
}
impl From<PowerUpError> for u8 {
fn from(error: PowerUpError) -> u8 {
match error {
PowerUpError::NoError => 0x00,
PowerUpError::KeyDownError => 0x3D,
PowerUpError::PowerError => 0x3E,
PowerUpError::Unknown(byte) => byte,
}
}
}
pub struct LK201Sender {
send: mpsc::Sender<u8>,
}
impl LK201Sender {
fn new(send: mpsc::Sender<u8>) -> Self {
Self { send }
}
pub fn send_special_key(&self, key: SpecialKey) {
_ = self.send.send(key as u8);
}
pub fn send_char(&self, c: char) {
if let Some((key, shift)) = Key::char_to_keycode(c) {
if shift {
_ = self.send.send(0xae); }
_ = self.send.send(key as u8);
if shift {
_ = self.send.send(0xb3); }
}
}
pub fn send_ctrl_char(&self, c: char) {
if let Some((keycode, shift)) = Key::char_to_keycode(c) {
_ = self.send.send(0xaf); if shift {
_ = self.send.send(0xae); }
_ = self.send.send(keycode as u8);
_ = self.send.send(0xb3); }
}
pub fn send_ctrl_special_key(&self, key: SpecialKey) {
_ = self.send.send(0xaf); _ = self.send.send(key as u8);
_ = self.send.send(0xb3); }
pub fn send_shift_special_key(&self, key: SpecialKey) {
_ = self.send.send(0xae); _ = self.send.send(key as u8);
_ = self.send.send(0xb3); }
pub fn send_shift_ctrl_special_key(&self, key: SpecialKey) {
_ = self.send.send(0xaf); _ = self.send.send(0xae); _ = self.send.send(key as u8);
_ = self.send.send(0xb3); }
pub fn send_escape(&self) {
_ = self.send.send(0xaf); _ = self.send.send(0xcb); _ = self.send.send(0xb3); }
}
pub struct LK201 {
recv: mpsc::Receiver<u8>,
send: mpsc::Sender<u8>,
kbd_queue: VecDeque<u8>,
collect_commands: bool,
collected_bytes: Vec<u8>,
collected_commands: Vec<LK201Command>,
}
impl LK201 {
pub fn new(send: mpsc::Sender<u8>, recv: mpsc::Receiver<u8>) -> Self {
Self {
send,
recv,
kbd_queue: VecDeque::new(),
collect_commands: false,
collected_bytes: Vec::new(),
collected_commands: Vec::new(),
}
}
pub fn start_collecting_commands(&mut self) {
self.collect_commands = true;
}
pub fn stop_collecting_commands(&mut self) -> (Vec<u8>, Vec<LK201Command>) {
self.collect_commands = false;
(
std::mem::take(&mut self.collected_bytes),
std::mem::take(&mut self.collected_commands),
)
}
pub fn sender(&self) -> LK201Sender {
LK201Sender::new(self.send.clone())
}
pub fn tick(&mut self) {
let mut received = false;
while let Ok(byte) = self.recv.try_recv() {
if self.collect_commands {
self.collected_bytes.push(byte);
}
self.kbd_queue.push_back(byte);
received = true;
}
if self.kbd_queue.is_empty() || !received {
return;
}
let Ok(command) = LK201Command::try_from(&self.kbd_queue) else {
return;
};
if self.collect_commands {
self.collected_commands.push(command.clone());
}
let cmd_len = command.len();
trace!("KBD: Command {:?}", command);
for _ in 0..cmd_len {
self.kbd_queue.pop_front();
}
if let Some(response) = command.response() {
trace!(
"KBD: Sending response {:?} = {:02X?}",
response,
response.to_bytes()
);
for byte in response.to_bytes() {
_ = self.send.send(byte);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_parse(input: &[u8], expected: LK201Command) {
let queue = VecDeque::from_iter(input.iter().copied());
let command = LK201Command::try_from(&queue).unwrap();
assert_eq!(
command, expected,
"input: {:02X?}, expected: {:?}",
input, expected
);
assert_eq!(
input.len(),
command.len(),
"input: {:02X?}, expected: {:?}",
input,
expected
);
}
#[test]
fn test_mode_commands() {
test_parse(
&[0x0A, 0x80],
LK201Command::SetModeWithAutoRepeat {
division: Division(1),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(0),
},
);
test_parse(
&[0x12, 0x81],
LK201Command::SetModeWithAutoRepeat {
division: Division(2),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(1),
},
);
test_parse(
&[0x72, 0x82],
LK201Command::SetModeWithAutoRepeat {
division: Division(14),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(2),
},
);
test_parse(
&[0xA2],
LK201Command::SetMode {
mode: KeyMode::AutoDown,
division: Division(4),
},
);
}
#[test]
fn test_autorepeat_commands() {
test_parse(
&[0x78, 0x64, 0x9E],
LK201Command::SetAutoRepeat {
register: AutoRepeatRegister(0),
timeout: 0x64,
rate: 0x1E,
},
);
test_parse(
&[0x7A, 0x64, 0x9E],
LK201Command::SetAutoRepeat {
register: AutoRepeatRegister(1),
timeout: 0x64,
rate: 0x1E,
},
);
test_parse(
&[0x7C, 0x64, 0x9E],
LK201Command::SetAutoRepeat {
register: AutoRepeatRegister(2),
timeout: 0x64,
rate: 0x1E,
},
);
}
#[test]
fn test_led_commands() {
test_parse(&[0x13, 0x84], LK201Command::LedEnable(Led::new(0x84)));
test_parse(&[0x11, 0x88], LK201Command::LedDisable(Led::new(0x88)));
test_parse(&[0x13, 0x8F], LK201Command::LedEnable(Led::new(0x8F)));
test_parse(&[0x13, 0x81], LK201Command::LedEnable(Led::new(0x81)));
test_parse(&[0x13, 0x80], LK201Command::LedEnable(Led::new(0x80))); test_parse(&[0x13, 0x83], LK201Command::LedEnable(Led::new(0x83))); test_parse(&[0x13, 0x85], LK201Command::LedEnable(Led::new(0x85))); test_parse(&[0x13, 0x86], LK201Command::LedEnable(Led::new(0x86))); test_parse(&[0x13, 0x8C], LK201Command::LedEnable(Led::new(0x8C))); test_parse(&[0x11, 0x8D], LK201Command::LedDisable(Led::new(0x8D))); }
#[test]
fn test_bell_and_click_commands() {
test_parse(&[0x23, 0x80], LK201Command::BellEnable(Volume(0)));
test_parse(&[0xA1], LK201Command::BellDisable);
test_parse(&[0xA7], LK201Command::RingBell);
test_parse(&[0x1B, 0x80], LK201Command::KeyClickEnable(Volume(0)));
test_parse(&[0x99], LK201Command::KeyClickDisable);
test_parse(&[0xBB], LK201Command::CtrlKeyClickEnable);
test_parse(&[0xB9], LK201Command::CtrlKeyClickDisable);
}
#[test]
fn test_control_commands() {
test_parse(&[0xFD], LK201Command::PowerUp);
test_parse(&[0xAB], LK201Command::RequestId);
test_parse(
&[0xE3],
LK201Command::EnableRepeat {
division: Division(4),
},
);
test_parse(
&[0xE1],
LK201Command::DisableRepeat {
division: Division(4),
},
);
test_parse(&[0xD9], LK201Command::RepeatToDown);
test_parse(&[0xD1], LK201Command::TempNoRepeat);
test_parse(&[0xD3], LK201Command::SetDefaults);
test_parse(&[0xCB], LK201Command::TestMode);
test_parse(&[0x8B], LK201Command::Resume);
test_parse(&[0x89], LK201Command::Inhibit);
test_parse(
&[0x80],
LK201Command::SetMode {
mode: KeyMode::Down,
division: Division(0),
},
);
}
#[test]
fn test_unknown_commands() {
test_parse(&[0x0D], LK201Command::Unknown(0x0D));
test_parse(&[0xFF], LK201Command::Unknown(0xFF));
test_parse(&[0x01], LK201Command::Unknown(0x01));
test_parse(&[0x55], LK201Command::Unknown(0x55));
let cmd = LK201Command::Unknown(0x0D);
let resp = cmd.response().unwrap();
assert_eq!(resp, LK201Response::InputError);
assert_eq!(resp.to_bytes(), vec![0xB6]);
}
#[test]
fn test_command_responses() {
let cmd = LK201Command::PowerUp;
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0x01, 0x00, 0x00, 0x00]);
let cmd = LK201Command::RequestId;
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0x01, 0x01]);
let cmd = LK201Command::SetMode {
mode: KeyMode::AutoDown,
division: Division(1),
};
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xBA]);
let cmd = LK201Command::SetModeWithAutoRepeat {
mode: KeyMode::AutoDown,
division: Division(1),
register: AutoRepeatRegister(0),
};
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xBA]);
let cmd = LK201Command::EnableRepeat {
division: Division(13),
};
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xBA]);
let cmd = LK201Command::DisableRepeat {
division: Division(13),
};
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xBA]);
let cmd = LK201Command::RepeatToDown;
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xBA]);
let cmd = LK201Command::TestMode;
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xB8]);
let cmd = LK201Command::Inhibit;
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xB7]);
let cmd = LK201Command::Unknown(0xFF);
let resp = cmd.response().unwrap();
assert_eq!(resp.to_bytes(), vec![0xB6]);
assert!(LK201Command::LedEnable(Led::new(0x84)).response().is_none());
assert!(LK201Command::BellEnable(Volume(4)).response().is_none());
assert!(LK201Command::KeyClickDisable.response().is_none());
assert!(LK201Command::SetDefaults.response().is_none());
assert!(LK201Command::Resume.response().is_none());
}
#[test]
fn test_response_serialization() {
let resp = LK201Response::ModeChangeAck;
assert_eq!(resp.to_bytes(), vec![0xBA]);
let resp = LK201Response::KeyboardLockAck;
assert_eq!(resp.to_bytes(), vec![0xB7]);
let resp = LK201Response::TestModeAck;
assert_eq!(resp.to_bytes(), vec![0xB8]);
let resp = LK201Response::InputError;
assert_eq!(resp.to_bytes(), vec![0xB6]);
let resp = LK201Response::OutputError;
assert_eq!(resp.to_bytes(), vec![0xB5]);
let resp = LK201Response::Repeat;
assert_eq!(resp.to_bytes(), vec![0xB4]);
let resp = LK201Response::AllUp;
assert_eq!(resp.to_bytes(), vec![0xB3]);
let resp = LK201Response::KeyDown(0x42);
assert_eq!(resp.to_bytes(), vec![0x42]);
let resp = LK201Response::PrefixKeyDown(0x42);
assert_eq!(resp.to_bytes(), vec![0xB9, 0x42]);
}
#[test]
fn test_full_sequence() {
test_parse(
&[0x0A, 0x80],
LK201Command::SetModeWithAutoRepeat {
division: Division(1),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(0),
},
);
test_parse(
&[0x1A, 0x80],
LK201Command::SetModeWithAutoRepeat {
division: Division(3),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(0),
},
);
test_parse(
&[0x3A, 0x80],
LK201Command::SetModeWithAutoRepeat {
division: Division(7),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(0),
},
);
test_parse(
&[0x42, 0x81],
LK201Command::SetModeWithAutoRepeat {
division: Division(8),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(1),
},
);
test_parse(
&[0x4A, 0x82],
LK201Command::SetModeWithAutoRepeat {
division: Division(9),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(2),
},
);
test_parse(
&[0x5A, 0x82],
LK201Command::SetModeWithAutoRepeat {
division: Division(11),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(2),
},
);
test_parse(
&[0x62, 0x82],
LK201Command::SetModeWithAutoRepeat {
division: Division(12),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(2),
},
);
test_parse(
&[0x6A, 0x82],
LK201Command::SetModeWithAutoRepeat {
division: Division(13),
mode: KeyMode::AutoDown,
register: AutoRepeatRegister(2),
},
);
}
}