pub use kanata_keyberon_macros::*;
use crate::action::{Action, HoldTapConfig, SequenceEvent};
use crate::key_code::KeyCode;
use arraydeque::ArrayDeque;
use heapless::Vec;
use State::*;
pub type Layers<const C: usize, const R: usize, const L: usize, T = core::convert::Infallible> =
[[[Action<T>; C]; R]; L];
type Stack = ArrayDeque<[Stacked; 16], arraydeque::behavior::Wrapping>;
pub struct Layout<const C: usize, const R: usize, const L: usize, T = core::convert::Infallible>
where
T: 'static,
{
layers: &'static [[[Action<T>; C]; R]; L],
default_layer: usize,
states: Vec<State<T>, 64>,
waiting: Option<WaitingState<T>>,
stacked: Stack,
tap_hold_tracker: TapHoldTracker,
active_sequences: ArrayDeque<[SequenceState; 4], arraydeque::behavior::Wrapping>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Event {
Press(u8, u8),
Release(u8, u8),
}
impl Event {
pub fn coord(self) -> (u8, u8) {
match self {
Event::Press(i, j) => (i, j),
Event::Release(i, j) => (i, j),
}
}
pub fn transform(self, f: impl FnOnce(u8, u8) -> (u8, u8)) -> Self {
match self {
Event::Press(i, j) => {
let (i, j) = f(i, j);
Event::Press(i, j)
}
Event::Release(i, j) => {
let (i, j) = f(i, j);
Event::Release(i, j)
}
}
}
pub fn is_press(self) -> bool {
match self {
Event::Press(..) => true,
Event::Release(..) => false,
}
}
pub fn is_release(self) -> bool {
match self {
Event::Release(..) => true,
Event::Press(..) => false,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum CustomEvent<T: 'static> {
NoEvent,
Press(&'static T),
Release(&'static T),
}
impl<T> CustomEvent<T> {
fn update(&mut self, e: Self) {
use CustomEvent::*;
match (&e, &self) {
(Release(_), NoEvent) | (Release(_), Press(_)) => *self = e,
(Press(_), NoEvent) => *self = e,
_ => (),
}
}
}
impl<T> Default for CustomEvent<T> {
fn default() -> Self {
CustomEvent::NoEvent
}
}
#[derive(Debug, Eq, PartialEq)]
enum State<T: 'static> {
NormalKey { keycode: KeyCode, coord: (u8, u8) },
LayerModifier { value: usize, coord: (u8, u8) },
Custom { value: &'static T, coord: (u8, u8) },
FakeKey { keycode: KeyCode }, }
impl<T> Copy for State<T> {}
impl<T> Clone for State<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: 'static> State<T> {
fn keycode(&self) -> Option<KeyCode> {
match self {
NormalKey { keycode, .. } => Some(*keycode),
FakeKey { keycode } => Some(*keycode),
_ => None,
}
}
fn tick(&self) -> Option<Self> {
Some(*self)
}
fn release(&self, c: (u8, u8), custom: &mut CustomEvent<T>) -> Option<Self> {
match *self {
NormalKey { coord, .. } | LayerModifier { coord, .. } if coord == c => None,
Custom { value, coord } if coord == c => {
custom.update(CustomEvent::Release(value));
None
}
_ => Some(*self),
}
}
fn seq_release(&self, kc: KeyCode) -> Option<Self> {
match *self {
FakeKey { keycode, .. } if keycode == kc => None,
_ => Some(*self),
}
}
fn get_layer(&self) -> Option<usize> {
match self {
LayerModifier { value, .. } => Some(*value),
_ => None,
}
}
}
#[derive(Debug)]
struct WaitingState<T: 'static> {
coord: (u8, u8),
timeout: u16,
delay: u16,
hold: &'static Action<T>,
tap: &'static Action<T>,
config: HoldTapConfig,
}
enum WaitingAction {
Hold,
Tap,
NoOp,
}
impl<T> WaitingState<T> {
fn tick(&mut self, stacked: &Stack) -> WaitingAction {
self.timeout = self.timeout.saturating_sub(1);
match self.config {
HoldTapConfig::Default => (),
HoldTapConfig::HoldOnOtherKeyPress => {
if stacked.iter().any(|s| s.event.is_press()) {
return WaitingAction::Hold;
}
}
HoldTapConfig::PermissiveHold => {
for (x, s) in stacked.iter().enumerate() {
if s.event.is_press() {
let (i, j) = s.event.coord();
let target = Event::Release(i, j);
if stacked.iter().skip(x + 1).any(|s| s.event == target) {
return WaitingAction::Hold;
}
}
}
}
}
if let Some(&Stacked { since, .. }) = stacked
.iter()
.find(|s| self.is_corresponding_release(&s.event))
{
if self.timeout >= self.delay - since {
WaitingAction::Tap
} else {
WaitingAction::Hold
}
} else if self.timeout == 0 {
WaitingAction::Hold
} else {
WaitingAction::NoOp
}
}
fn is_corresponding_release(&self, event: &Event) -> bool {
matches!(event, Event::Release(i, j) if (*i, *j) == self.coord)
}
}
#[derive(Debug, Copy, Clone)]
struct SequenceState {
cur_event: Option<SequenceEvent>,
delay: u32, tapped: Option<KeyCode>, remaining_events: &'static [SequenceEvent],
}
#[derive(Debug)]
struct Stacked {
event: Event,
since: u16,
}
impl From<Event> for Stacked {
fn from(event: Event) -> Self {
Stacked { event, since: 0 }
}
}
impl Stacked {
fn tick(&mut self) {
self.since = self.since.saturating_add(1);
}
}
#[derive(Default)]
struct TapHoldTracker {
coord: (u8, u8),
timeout: u16,
}
impl TapHoldTracker {
fn tick(&mut self) {
self.timeout = self.timeout.saturating_sub(1);
}
}
impl<const C: usize, const R: usize, const L: usize, T: 'static> Layout<C, R, L, T> {
pub fn new(layers: &'static [[[Action<T>; C]; R]; L]) -> Self {
Self {
layers,
default_layer: 0,
states: Vec::new(),
waiting: None,
stacked: ArrayDeque::new(),
tap_hold_tracker: Default::default(),
active_sequences: ArrayDeque::new(),
}
}
pub fn keycodes(&self) -> impl Iterator<Item = KeyCode> + '_ {
self.states.iter().filter_map(State::keycode)
}
fn waiting_into_hold(&mut self) -> CustomEvent<T> {
if let Some(w) = &self.waiting {
let hold = w.hold;
let coord = w.coord;
self.waiting = None;
if coord == self.tap_hold_tracker.coord {
self.tap_hold_tracker.timeout = 0;
}
self.do_action(hold, coord, 0)
} else {
CustomEvent::NoEvent
}
}
fn waiting_into_tap(&mut self) -> CustomEvent<T> {
if let Some(w) = &self.waiting {
let tap = w.tap;
let coord = w.coord;
self.waiting = None;
self.do_action(tap, coord, 0)
} else {
CustomEvent::NoEvent
}
}
pub fn tick(&mut self) -> CustomEvent<T> {
self.states = self.states.iter().filter_map(State::tick).collect();
self.stacked.iter_mut().for_each(Stacked::tick);
self.tap_hold_tracker.tick();
self.process_sequences();
match &mut self.waiting {
Some(w) => match w.tick(&self.stacked) {
WaitingAction::Hold => self.waiting_into_hold(),
WaitingAction::Tap => self.waiting_into_tap(),
WaitingAction::NoOp => CustomEvent::NoEvent,
},
None => match self.stacked.pop_front() {
Some(s) => self.unstack(s),
None => CustomEvent::NoEvent,
},
}
}
fn process_sequences(&mut self) {
for _ in 0..self.active_sequences.len() {
if let Some(mut seq) = self.active_sequences.pop_front() {
if seq.delay > 0 {
seq.delay = seq.delay.saturating_sub(1);
} else if let Some(keycode) = seq.tapped {
self.states = self
.states
.iter()
.filter_map(|s| s.seq_release(keycode))
.collect();
seq.tapped = None;
} else {
match seq.remaining_events {
[e, tail @ ..] => {
seq.cur_event = Some(*e);
seq.remaining_events = tail;
}
[] => (),
}
match seq.cur_event {
Some(SequenceEvent::Complete) => {
for fake_key in self.states.clone().iter() {
match *fake_key {
FakeKey { keycode } => {
self.states = self
.states
.iter()
.filter_map(|s| s.seq_release(keycode))
.collect();
}
_ => {}
}
}
seq.remaining_events = &[];
}
Some(SequenceEvent::Press(keycode)) => {
let _ = self.states.push(FakeKey { keycode });
}
Some(SequenceEvent::Tap(keycode)) => {
let _ = self.states.push(FakeKey { keycode });
seq.tapped = Some(keycode);
}
Some(SequenceEvent::Release(keycode)) => {
self.states = self
.states
.iter()
.filter_map(|s| s.seq_release(keycode))
.collect()
}
Some(SequenceEvent::Delay { duration }) => {
if duration > 0 {
seq.delay = duration - 1;
}
}
_ => {} }
}
if seq.remaining_events.len() > 0 {
self.active_sequences.push_back(seq);
}
}
}
}
fn unstack(&mut self, stacked: Stacked) -> CustomEvent<T> {
use Event::*;
match stacked.event {
Release(i, j) => {
let mut custom = CustomEvent::NoEvent;
self.states = self
.states
.iter()
.filter_map(|s| s.release((i, j), &mut custom))
.collect();
custom
}
Press(i, j) => {
let action = self.press_as_action((i, j), self.current_layer());
self.do_action(action, (i, j), stacked.since)
}
}
}
pub fn event(&mut self, event: Event) {
if let Some(stacked) = self.stacked.push_back(event.into()) {
self.waiting_into_hold();
self.unstack(stacked);
}
}
fn press_as_action(&self, coord: (u8, u8), layer: usize) -> &'static Action<T> {
use crate::action::Action::*;
let action = self
.layers
.get(layer)
.and_then(|l| l.get(coord.0 as usize))
.and_then(|l| l.get(coord.1 as usize));
match action {
None => &NoOp,
Some(Trans) => {
if layer != self.default_layer {
self.press_as_action(coord, self.default_layer)
} else {
&NoOp
}
}
Some(action) => action,
}
}
fn do_action(
&mut self,
action: &'static Action<T>,
coord: (u8, u8),
delay: u16,
) -> CustomEvent<T> {
assert!(self.waiting.is_none());
use Action::*;
match action {
NoOp | Trans => (),
HoldTap {
timeout,
hold,
tap,
config,
tap_hold_interval,
} => {
if *tap_hold_interval == 0
|| coord != self.tap_hold_tracker.coord
|| self.tap_hold_tracker.timeout == 0
{
let waiting: WaitingState<T> = WaitingState {
coord,
timeout: *timeout,
delay,
hold,
tap,
config: *config,
};
self.waiting = Some(waiting);
self.tap_hold_tracker.timeout = *tap_hold_interval;
} else {
self.tap_hold_tracker.timeout = 0;
self.do_action(tap, coord, delay);
}
self.tap_hold_tracker.coord = coord;
}
&KeyCode(keycode) => {
self.tap_hold_tracker.coord = coord;
let _ = self.states.push(NormalKey { coord, keycode });
}
&MultipleKeyCodes(v) => {
self.tap_hold_tracker.coord = coord;
for &keycode in v {
let _ = self.states.push(NormalKey { coord, keycode });
}
}
&MultipleActions(v) => {
self.tap_hold_tracker.coord = coord;
let mut custom = CustomEvent::NoEvent;
for action in v {
custom.update(self.do_action(action, coord, delay));
}
return custom;
}
Sequence { events } => {
self.active_sequences.push_back(SequenceState {
cur_event: None,
delay: 0,
tapped: None,
remaining_events: events,
});
}
CancelSequences => {
self.active_sequences.clear();
for fake_key in self.states.clone().iter() {
match *fake_key {
FakeKey { keycode } => {
self.states = self
.states
.iter()
.filter_map(|s| s.seq_release(keycode))
.collect();
}
_ => {}
}
}
}
&Layer(value) => {
self.tap_hold_tracker.coord = coord;
let _ = self.states.push(LayerModifier { value, coord });
}
DefaultLayer(value) => {
self.tap_hold_tracker.coord = coord;
self.set_default_layer(*value);
}
Custom(value) => {
self.tap_hold_tracker.coord = coord;
if self.states.push(State::Custom { value, coord }).is_ok() {
return CustomEvent::Press(value);
}
}
}
CustomEvent::NoEvent
}
pub fn current_layer(&self) -> usize {
self.states
.iter()
.rev()
.find_map(State::get_layer)
.unwrap_or(self.default_layer)
}
pub fn set_default_layer(&mut self, value: usize) {
if value < self.layers.len() {
self.default_layer = value
}
}
}
#[cfg(test)]
mod test {
extern crate std;
use super::{Event::*, Layout, *};
use crate::action::Action::*;
use crate::action::HoldTapConfig;
use crate::action::{k, l, m};
use crate::key_code::KeyCode;
use crate::key_code::KeyCode::*;
use std::collections::BTreeSet;
#[track_caller]
fn assert_keys(expected: &[KeyCode], iter: impl Iterator<Item = KeyCode>) {
let expected: BTreeSet<_> = expected.iter().copied().collect();
let tested = iter.collect();
assert_eq!(expected, tested);
}
#[test]
fn basic_hold_tap() {
static LAYERS: Layers<2, 1, 2> = [
[[
HoldTap {
timeout: 200,
hold: &l(1),
tap: &k(Space),
config: HoldTapConfig::Default,
tap_hold_interval: 0,
},
HoldTap {
timeout: 200,
hold: &k(LCtrl),
tap: &k(Enter),
config: HoldTapConfig::Default,
tap_hold_interval: 0,
},
]],
[[Trans, m(&[LCtrl, Enter])]],
];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
for _ in 0..197 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LCtrl], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LCtrl], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LCtrl, Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LCtrl], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn hold_tap_interleaved_timeout() {
static LAYERS: Layers<2, 1, 1> = [[[
HoldTap {
timeout: 200,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::Default,
tap_hold_interval: 0,
},
HoldTap {
timeout: 20,
hold: &k(LCtrl),
tap: &k(Enter),
config: HoldTapConfig::Default,
tap_hold_interval: 0,
},
]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
for _ in 0..15 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
for _ in 0..10 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
}
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space, LCtrl], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LCtrl], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn hold_on_press() {
static LAYERS: Layers<2, 1, 1> = [[[
HoldTap {
timeout: 200,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::HoldOnOtherKeyPress,
tap_hold_interval: 0,
},
k(Enter),
]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt, Enter], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..200 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt, Enter], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn permissive_hold() {
static LAYERS: Layers<2, 1, 1> = [[[
HoldTap {
timeout: 200,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::PermissiveHold,
tap_hold_interval: 0,
},
k(Enter),
]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt, Enter], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn multiple_actions() {
static LAYERS: Layers<2, 1, 2> = [
[[MultipleActions(&[l(1), k(LShift)]), k(F)]],
[[Trans, k(E)]],
];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LShift], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LShift, E], layout.keycodes());
layout.event(Release(0, 1));
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LShift], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn custom() {
static LAYERS: Layers<1, 1, 1, u8> = [[[Action::Custom(42)]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::Press(&42), layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::Release(&42), layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn multiple_layers() {
static LAYERS: Layers<2, 1, 4> = [
[[l(1), l(2)]],
[[k(A), l(3)]],
[[l(0), k(B)]],
[[k(C), k(D)]],
];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(0, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(1, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(3, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(3, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[C], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(0, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(2, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(0, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(2, layout.current_layer());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_eq!(0, layout.current_layer());
assert_keys(&[], layout.keycodes());
}
#[test]
fn tap_hold_interval() {
static LAYERS: Layers<2, 1, 1> = [[[
HoldTap {
timeout: 200,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::Default,
tap_hold_interval: 200,
},
k(Enter),
]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
for _ in 0..300 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
}
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..200 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn tap_hold_interval_interleave() {
static LAYERS: Layers<3, 1, 1> = [[[
HoldTap {
timeout: 200,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::Default,
tap_hold_interval: 200,
},
k(Enter),
HoldTap {
timeout: 200,
hold: &k(LAlt),
tap: &k(Enter),
config: HoldTapConfig::Default,
tap_hold_interval: 200,
},
]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..200 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter, Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..200 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 2));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 2));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter, Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Space], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..200 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
}
#[test]
fn tap_hold_interval_short_hold() {
static LAYERS: Layers<1, 1, 1> = [[[HoldTap {
timeout: 50,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::Default,
tap_hold_interval: 200,
}]]];
let mut layout = Layout::new(&LAYERS);
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..50 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
layout.event(Press(0, 0));
for _ in 0..50 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
#[test]
fn tap_hold_interval_different_hold() {
static LAYERS: Layers<2, 1, 1> = [[[
HoldTap {
timeout: 50,
hold: &k(LAlt),
tap: &k(Space),
config: HoldTapConfig::Default,
tap_hold_interval: 200,
},
HoldTap {
timeout: 200,
hold: &k(RAlt),
tap: &k(Enter),
config: HoldTapConfig::Default,
tap_hold_interval: 200,
},
]]];
let mut layout = Layout::new(&LAYERS);
layout.event(Press(0, 0));
layout.event(Press(0, 1));
for _ in 0..50 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
}
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 0));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt], layout.keycodes());
layout.event(Release(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[LAlt, Enter], layout.keycodes());
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter], layout.keycodes());
layout.event(Press(0, 1));
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[], layout.keycodes());
for _ in 0..300 {
assert_eq!(CustomEvent::NoEvent, layout.tick());
assert_keys(&[Enter], layout.keycodes());
}
}
}