Skip to content

Commit 1b0f074

Browse files
committed
sequences: be able to filter/restore some key presses
1 parent 5566dcf commit 1b0f074

File tree

2 files changed

+272
-3
lines changed

2 files changed

+272
-3
lines changed

src/action.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use core::fmt::Debug;
77
/// The different types of actions we support for key sequences/macros
88
#[non_exhaustive]
99
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
10-
pub enum SequenceEvent<K> {
10+
pub enum SequenceEvent<K: 'static> {
1111
/// No operation action: just do nothing (a placeholder).
1212
NoOp,
1313
/// A keypress/keydown
@@ -24,6 +24,10 @@ pub enum SequenceEvent<K> {
2424
/// Cancels the running sequence and can be used to mark the end of a sequence
2525
/// instead of using a number of Release() events
2626
Complete,
27+
/// If those keys are pressed, release them
28+
Filter(&'static &'static [K]),
29+
/// Restore keys if they were previously Filter-ed
30+
Restore,
2731
}
2832

2933
/// Behavior configuration of HoldTap.

src/layout.rs

+267-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub use keyberon_macros::*;
4949
use crate::action::{Action, HoldTapAction, HoldTapConfig, SequenceEvent};
5050
use crate::key_code::KeyCode;
5151
use arraydeque::ArrayDeque;
52+
use core::convert::TryFrom;
5253
use core::fmt::Debug;
5354
use heapless::Vec;
5455

@@ -331,7 +332,38 @@ impl<'a> Iterator for StackedIter<'a> {
331332
}
332333

333334
#[derive(Debug, Copy, Clone)]
334-
struct SequenceState<K: 'static> {
335+
/// Enum to save a state that represents a key pressed
336+
enum SavedKeyCodeState<K: 'static + Copy> {
337+
/// Key pressed
338+
NormalKey { keycode: K, coord: (u8, u8) },
339+
/// Fake key event for sequences
340+
FakeKey { keycode: K },
341+
}
342+
343+
impl<T: 'static, K: 'static + Copy + Eq> From<SavedKeyCodeState<K>> for State<T, K> {
344+
/// Convert a [`SavedKeyCodeState`] into a [`State`]
345+
fn from(saved: SavedKeyCodeState<K>) -> Self {
346+
match saved {
347+
SavedKeyCodeState::NormalKey { keycode, coord } => Self::NormalKey { keycode, coord },
348+
SavedKeyCodeState::FakeKey { keycode } => Self::FakeKey { keycode },
349+
}
350+
}
351+
}
352+
353+
impl<T: 'static, K: 'static + Copy> TryFrom<State<T, K>> for SavedKeyCodeState<K> {
354+
type Error = &'static str;
355+
/// Try to convert a [`State`] into a [`SavedKeyCodeState`]
356+
fn try_from(state: State<T, K>) -> Result<Self, Self::Error> {
357+
match state {
358+
NormalKey { keycode, coord } => Ok(Self::NormalKey { keycode, coord }),
359+
FakeKey { keycode } => Ok(Self::FakeKey { keycode }),
360+
_ => Err("Unsupported State conversion to SavedKeyCodeState"),
361+
}
362+
}
363+
}
364+
365+
#[derive(Debug, Copy, Clone)]
366+
struct SequenceState<K: 'static + Copy> {
335367
/// Current event being processed
336368
cur_event: Option<SequenceEvent<K>>,
337369
/// Remaining events to process
@@ -340,6 +372,8 @@ struct SequenceState<K: 'static> {
340372
delay: u32,
341373
/// Keycode of a key that should be released at the next tick
342374
tapped: Option<K>,
375+
/// Keys filtered that can be restored later
376+
to_restore: [Option<SavedKeyCodeState<K>>; 64],
343377
}
344378

345379
impl<K: Copy> Default for SequenceState<K> {
@@ -349,6 +383,23 @@ impl<K: Copy> Default for SequenceState<K> {
349383
remaining_events: &[],
350384
delay: 0,
351385
tapped: None,
386+
to_restore: [None; 64],
387+
}
388+
}
389+
}
390+
impl<K: Copy> SequenceState<K> {
391+
fn add_to_restore<T>(&mut self, s: State<T, K>) {
392+
for e in self.to_restore.iter_mut() {
393+
if e.is_none() {
394+
match s {
395+
NormalKey { .. } | FakeKey { .. } => {
396+
let saved = SavedKeyCodeState::<K>::try_from(s);
397+
*e = Some(saved.unwrap());
398+
}
399+
_ => {}
400+
}
401+
return;
402+
}
352403
}
353404
}
354405
}
@@ -527,7 +578,36 @@ impl<
527578
seq.delay = duration - 1;
528579
}
529580
}
530-
_ => {} // We'll never get here
581+
Some(SequenceEvent::Filter(keys)) => {
582+
self.states = self
583+
.states
584+
.iter()
585+
.filter_map(|s| match s.keycode() {
586+
Some(k) => {
587+
if keys.contains(&k) {
588+
seq.add_to_restore(*s);
589+
None
590+
} else {
591+
Some(*s)
592+
}
593+
}
594+
_ => Some(*s),
595+
})
596+
.collect()
597+
}
598+
Some(SequenceEvent::Restore) => seq
599+
.to_restore
600+
.iter()
601+
.filter_map(|s| {
602+
if let Some(saved) = s {
603+
let _ = self.states.push((*saved).into());
604+
}
605+
None
606+
})
607+
.collect(),
608+
_ => {
609+
panic!("invalid sequence");
610+
}
531611
}
532612
}
533613
if !seq.remaining_events.is_empty() || seq.tapped.is_some() {
@@ -1655,4 +1735,189 @@ mod test {
16551735
// finished
16561736
assert_keys(&[], layout.keycodes());
16571737
}
1738+
1739+
#[test]
1740+
fn sequences_unshift() {
1741+
static LAYERS: Layers<8, 1, 1> = [[[
1742+
k(LShift),
1743+
k(RShift),
1744+
k(A),
1745+
k(B),
1746+
k(C),
1747+
Sequence(
1748+
&[
1749+
SequenceEvent::Press(A),
1750+
SequenceEvent::Release(A),
1751+
SequenceEvent::Press(RShift),
1752+
SequenceEvent::Press(B),
1753+
SequenceEvent::Release(B),
1754+
SequenceEvent::Release(RShift),
1755+
SequenceEvent::Press(C),
1756+
SequenceEvent::Release(C),
1757+
]
1758+
.as_slice(),
1759+
),
1760+
Sequence(
1761+
&[
1762+
SequenceEvent::Tap(A),
1763+
SequenceEvent::Press(RShift),
1764+
SequenceEvent::Tap(B),
1765+
SequenceEvent::Release(RShift),
1766+
SequenceEvent::Tap(C),
1767+
]
1768+
.as_slice(),
1769+
),
1770+
Sequence(
1771+
&[
1772+
SequenceEvent::Tap(A),
1773+
SequenceEvent::Filter(&[LShift, RShift].as_slice()),
1774+
SequenceEvent::Tap(B),
1775+
SequenceEvent::Restore,
1776+
SequenceEvent::Tap(C),
1777+
]
1778+
.as_slice(),
1779+
),
1780+
/* TODO: sequence with explicit Shift */
1781+
]]];
1782+
let mut layout = Layout::new(&LAYERS);
1783+
1784+
// Test a sequence that contains Shift
1785+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1786+
assert_keys(&[], layout.keycodes());
1787+
layout.event(Press(0, 2)); // A
1788+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1789+
assert_keys(&[A], layout.keycodes());
1790+
layout.event(Release(0, 2)); // A
1791+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1792+
assert_keys(&[], layout.keycodes());
1793+
layout.event(Press(0, 1)); // RShift
1794+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1795+
assert_keys(&[RShift], layout.keycodes());
1796+
layout.event(Press(0, 3)); // B
1797+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1798+
assert_keys(&[B, RShift], layout.keycodes());
1799+
layout.event(Release(0, 3)); // B
1800+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1801+
assert_keys(&[RShift], layout.keycodes());
1802+
layout.event(Release(0, 1)); // RShift
1803+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1804+
assert_keys(&[], layout.keycodes());
1805+
layout.event(Press(0, 4)); // C
1806+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1807+
assert_keys(&[C], layout.keycodes());
1808+
layout.event(Release(0, 4)); // C
1809+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1810+
assert_keys(&[], layout.keycodes());
1811+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1812+
assert_keys(&[], layout.keycodes());
1813+
1814+
// Test a sequence that contains Shift
1815+
layout.event(Press(0, 5));
1816+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1817+
assert_keys(&[], layout.keycodes());
1818+
layout.event(Release(0, 5));
1819+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Press(A)
1820+
assert_keys(&[A], layout.keycodes());
1821+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1822+
assert_keys(&[], layout.keycodes());
1823+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Press(RShift)
1824+
assert_keys(&[RShift], layout.keycodes());
1825+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Press(B)
1826+
assert_keys(&[RShift, B], layout.keycodes());
1827+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1828+
assert_keys(&[RShift], layout.keycodes());
1829+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(RShift)
1830+
assert_keys(&[], layout.keycodes());
1831+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1832+
assert_keys(&[C], layout.keycodes());
1833+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1834+
assert_keys(&[], layout.keycodes());
1835+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1836+
// finished
1837+
assert_keys(&[], layout.keycodes());
1838+
1839+
// Test a sequence that contains Shift with Tap
1840+
layout.event(Press(0, 6));
1841+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1842+
assert_keys(&[], layout.keycodes());
1843+
layout.event(Release(0, 6));
1844+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Tap(A)
1845+
assert_keys(&[A], layout.keycodes());
1846+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1847+
assert_keys(&[], layout.keycodes());
1848+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Press(RShift)
1849+
assert_keys(&[RShift], layout.keycodes());
1850+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(B)
1851+
assert_keys(&[RShift, B], layout.keycodes());
1852+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1853+
assert_keys(&[RShift], layout.keycodes());
1854+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(RShift)
1855+
assert_keys(&[], layout.keycodes());
1856+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1857+
assert_keys(&[C], layout.keycodes());
1858+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1859+
assert_keys(&[], layout.keycodes());
1860+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1861+
// finished
1862+
assert_keys(&[], layout.keycodes());
1863+
1864+
// Test a sequence with Unshift/Restore while Shift has not been
1865+
// pressed
1866+
layout.event(Press(0, 7));
1867+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1868+
assert_keys(&[], layout.keycodes());
1869+
layout.event(Release(0, 7));
1870+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Tap(A)
1871+
assert_keys(&[A], layout.keycodes());
1872+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1873+
assert_keys(&[], layout.keycodes());
1874+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Unshift
1875+
assert_keys(&[], layout.keycodes());
1876+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(B)
1877+
assert_keys(&[B], layout.keycodes());
1878+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1879+
assert_keys(&[], layout.keycodes());
1880+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // RestoreShift
1881+
assert_keys(&[], layout.keycodes());
1882+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1883+
assert_keys(&[C], layout.keycodes());
1884+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1885+
assert_keys(&[], layout.keycodes());
1886+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1887+
// finished
1888+
assert_keys(&[], layout.keycodes());
1889+
1890+
// Test a sequence with Unshift/Restore while RShift has been pressed
1891+
1892+
layout.event(Press(0, 1)); // RShift
1893+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1894+
assert_keys(&[RShift], layout.keycodes());
1895+
1896+
layout.event(Press(0, 7));
1897+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1898+
assert_keys(&[RShift], layout.keycodes());
1899+
layout.event(Release(0, 7));
1900+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Tap(A)
1901+
assert_keys(&[RShift, A], layout.keycodes());
1902+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1903+
assert_keys(&[RShift], layout.keycodes());
1904+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Unshift
1905+
assert_keys(&[], layout.keycodes());
1906+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(B)
1907+
assert_keys(&[B], layout.keycodes());
1908+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1909+
assert_keys(&[], layout.keycodes());
1910+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // RestoreShift
1911+
assert_keys(&[RShift], layout.keycodes());
1912+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1913+
assert_keys(&[RShift, C], layout.keycodes());
1914+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1915+
assert_keys(&[RShift], layout.keycodes());
1916+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1917+
// finished
1918+
assert_keys(&[RShift], layout.keycodes());
1919+
layout.event(Release(0, 1)); // RShift
1920+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1921+
assert_keys(&[], layout.keycodes());
1922+
}
16581923
}

0 commit comments

Comments
 (0)