Skip to content

Commit 5f94202

Browse files
committed
sequences: be able to filter/restore some key presses
1 parent 8deb7e6 commit 5f94202

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 heapless::Vec;
5354

5455
use State::*;
@@ -326,7 +327,38 @@ impl<'a> Iterator for StackedIter<'a> {
326327
}
327328

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

340374
impl<K: Copy> Default for SequenceState<K> {
@@ -344,6 +378,23 @@ impl<K: Copy> Default for SequenceState<K> {
344378
remaining_events: &[],
345379
delay: 0,
346380
tapped: None,
381+
to_restore: [None; 64],
382+
}
383+
}
384+
}
385+
impl<K: Copy> SequenceState<K> {
386+
fn add_to_restore<T>(&mut self, s: State<T, K>) {
387+
for e in self.to_restore.iter_mut() {
388+
if e.is_none() {
389+
match s {
390+
NormalKey { .. } | FakeKey { .. } => {
391+
let saved = SavedKeyCodeState::<K>::try_from(s);
392+
*e = Some(saved.unwrap());
393+
}
394+
_ => {}
395+
}
396+
return;
397+
}
347398
}
348399
}
349400
}
@@ -517,7 +568,36 @@ impl<const C: usize, const R: usize, const L: usize, T: 'static, K: 'static + Co
517568
seq.delay = duration - 1;
518569
}
519570
}
520-
_ => {} // We'll never get here
571+
Some(SequenceEvent::Filter(keys)) => {
572+
self.states = self
573+
.states
574+
.iter()
575+
.filter_map(|s| match s.keycode() {
576+
Some(k) => {
577+
if keys.contains(&k) {
578+
seq.add_to_restore(*s);
579+
None
580+
} else {
581+
Some(*s)
582+
}
583+
}
584+
_ => Some(*s),
585+
})
586+
.collect()
587+
}
588+
Some(SequenceEvent::Restore) => seq
589+
.to_restore
590+
.iter()
591+
.filter_map(|s| {
592+
if let Some(saved) = s {
593+
let _ = self.states.push((*saved).into());
594+
}
595+
None
596+
})
597+
.collect(),
598+
_ => {
599+
panic!("invalid sequence");
600+
}
521601
}
522602
}
523603
if !seq.remaining_events.is_empty() || seq.tapped.is_some() {
@@ -1645,4 +1725,189 @@ mod test {
16451725
// finished
16461726
assert_keys(&[], layout.keycodes());
16471727
}
1728+
1729+
#[test]
1730+
fn sequences_unshift() {
1731+
static LAYERS: Layers<8, 1, 1> = [[[
1732+
k(LShift),
1733+
k(RShift),
1734+
k(A),
1735+
k(B),
1736+
k(C),
1737+
Sequence(
1738+
&[
1739+
SequenceEvent::Press(A),
1740+
SequenceEvent::Release(A),
1741+
SequenceEvent::Press(RShift),
1742+
SequenceEvent::Press(B),
1743+
SequenceEvent::Release(B),
1744+
SequenceEvent::Release(RShift),
1745+
SequenceEvent::Press(C),
1746+
SequenceEvent::Release(C),
1747+
]
1748+
.as_slice(),
1749+
),
1750+
Sequence(
1751+
&[
1752+
SequenceEvent::Tap(A),
1753+
SequenceEvent::Press(RShift),
1754+
SequenceEvent::Tap(B),
1755+
SequenceEvent::Release(RShift),
1756+
SequenceEvent::Tap(C),
1757+
]
1758+
.as_slice(),
1759+
),
1760+
Sequence(
1761+
&[
1762+
SequenceEvent::Tap(A),
1763+
SequenceEvent::Filter(&[LShift, RShift].as_slice()),
1764+
SequenceEvent::Tap(B),
1765+
SequenceEvent::Restore,
1766+
SequenceEvent::Tap(C),
1767+
]
1768+
.as_slice(),
1769+
),
1770+
/* TODO: sequence with explicit Shift */
1771+
]]];
1772+
let mut layout = Layout::new(&LAYERS);
1773+
1774+
// Test a sequence that contains Shift
1775+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1776+
assert_keys(&[], layout.keycodes());
1777+
layout.event(Press(0, 2)); // A
1778+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1779+
assert_keys(&[A], layout.keycodes());
1780+
layout.event(Release(0, 2)); // A
1781+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1782+
assert_keys(&[], layout.keycodes());
1783+
layout.event(Press(0, 1)); // RShift
1784+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1785+
assert_keys(&[RShift], layout.keycodes());
1786+
layout.event(Press(0, 3)); // B
1787+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1788+
assert_keys(&[B, RShift], layout.keycodes());
1789+
layout.event(Release(0, 3)); // B
1790+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1791+
assert_keys(&[RShift], layout.keycodes());
1792+
layout.event(Release(0, 1)); // RShift
1793+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1794+
assert_keys(&[], layout.keycodes());
1795+
layout.event(Press(0, 4)); // C
1796+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1797+
assert_keys(&[C], layout.keycodes());
1798+
layout.event(Release(0, 4)); // C
1799+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1800+
assert_keys(&[], layout.keycodes());
1801+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1802+
assert_keys(&[], layout.keycodes());
1803+
1804+
// Test a sequence that contains Shift
1805+
layout.event(Press(0, 5));
1806+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1807+
assert_keys(&[], layout.keycodes());
1808+
layout.event(Release(0, 5));
1809+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Press(A)
1810+
assert_keys(&[A], layout.keycodes());
1811+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1812+
assert_keys(&[], layout.keycodes());
1813+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Press(RShift)
1814+
assert_keys(&[RShift], layout.keycodes());
1815+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Press(B)
1816+
assert_keys(&[RShift, B], layout.keycodes());
1817+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1818+
assert_keys(&[RShift], layout.keycodes());
1819+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(RShift)
1820+
assert_keys(&[], layout.keycodes());
1821+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1822+
assert_keys(&[C], layout.keycodes());
1823+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1824+
assert_keys(&[], layout.keycodes());
1825+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1826+
// finished
1827+
assert_keys(&[], layout.keycodes());
1828+
1829+
// Test a sequence that contains Shift with Tap
1830+
layout.event(Press(0, 6));
1831+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1832+
assert_keys(&[], layout.keycodes());
1833+
layout.event(Release(0, 6));
1834+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Tap(A)
1835+
assert_keys(&[A], layout.keycodes());
1836+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1837+
assert_keys(&[], layout.keycodes());
1838+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Press(RShift)
1839+
assert_keys(&[RShift], layout.keycodes());
1840+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(B)
1841+
assert_keys(&[RShift, B], layout.keycodes());
1842+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1843+
assert_keys(&[RShift], layout.keycodes());
1844+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(RShift)
1845+
assert_keys(&[], layout.keycodes());
1846+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1847+
assert_keys(&[C], layout.keycodes());
1848+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1849+
assert_keys(&[], layout.keycodes());
1850+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1851+
// finished
1852+
assert_keys(&[], layout.keycodes());
1853+
1854+
// Test a sequence with Unshift/Restore while Shift has not been
1855+
// pressed
1856+
layout.event(Press(0, 7));
1857+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1858+
assert_keys(&[], layout.keycodes());
1859+
layout.event(Release(0, 7));
1860+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Tap(A)
1861+
assert_keys(&[A], layout.keycodes());
1862+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1863+
assert_keys(&[], layout.keycodes());
1864+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Unshift
1865+
assert_keys(&[], layout.keycodes());
1866+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(B)
1867+
assert_keys(&[B], layout.keycodes());
1868+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1869+
assert_keys(&[], layout.keycodes());
1870+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // RestoreShift
1871+
assert_keys(&[], layout.keycodes());
1872+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1873+
assert_keys(&[C], layout.keycodes());
1874+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1875+
assert_keys(&[], layout.keycodes());
1876+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1877+
// finished
1878+
assert_keys(&[], layout.keycodes());
1879+
1880+
// Test a sequence with Unshift/Restore while RShift has been pressed
1881+
1882+
layout.event(Press(0, 1)); // RShift
1883+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1884+
assert_keys(&[RShift], layout.keycodes());
1885+
1886+
layout.event(Press(0, 7));
1887+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence detected & added
1888+
assert_keys(&[RShift], layout.keycodes());
1889+
layout.event(Release(0, 7));
1890+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // To Process Tap(A)
1891+
assert_keys(&[RShift, A], layout.keycodes());
1892+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(A)
1893+
assert_keys(&[RShift], layout.keycodes());
1894+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Unshift
1895+
assert_keys(&[], layout.keycodes());
1896+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(B)
1897+
assert_keys(&[B], layout.keycodes());
1898+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(B)
1899+
assert_keys(&[], layout.keycodes());
1900+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // RestoreShift
1901+
assert_keys(&[RShift], layout.keycodes());
1902+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Tap(C)
1903+
assert_keys(&[RShift, C], layout.keycodes());
1904+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Release(C)
1905+
assert_keys(&[RShift], layout.keycodes());
1906+
assert_eq!(CustomEvent::NoEvent, layout.tick()); // Sequence is
1907+
// finished
1908+
assert_keys(&[RShift], layout.keycodes());
1909+
layout.event(Release(0, 1)); // RShift
1910+
assert_eq!(CustomEvent::NoEvent, layout.tick());
1911+
assert_keys(&[], layout.keycodes());
1912+
}
16481913
}

0 commit comments

Comments
 (0)