Skip to content

Commit

Permalink
fix(chordsv2): preserve oneshot activations
Browse files Browse the repository at this point in the history
  • Loading branch information
jtroo committed Oct 6, 2024
1 parent 4967bce commit d54257a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 3 deletions.
12 changes: 10 additions & 2 deletions keyberon/src/chord.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ macro_rules! no_chord_activations {
}};
}

pub(crate) const TRIGGER_TAPHOLD_COORD: (u8, u16) = (0, 0);

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ReleaseBehaviour {
OnFirstRelease,
Expand Down Expand Up @@ -207,7 +209,10 @@ impl<'a, T> ChordsV2<'a, T> {
// HoldOnOtherKeyPress or PermissiveHold.
// FLAW: this does not associate with the actual input keys and thus cannot correctly
// trigger the early tap for *-keys variants of kanata tap-hold.
q.push_back(Queued::new_press(0, 0));
q.push_back(Queued::new_press(
TRIGGER_TAPHOLD_COORD.0,
TRIGGER_TAPHOLD_COORD.1,
));
}
if self
.active_chords
Expand All @@ -217,7 +222,10 @@ impl<'a, T> ChordsV2<'a, T> {
// A chord was released. Forward a no-op release event to potentially trigger
// PermissiveHold.
// FLAW: see above
q.push_back(Queued::new_release(0, 0));
q.push_back(Queued::new_release(
TRIGGER_TAPHOLD_COORD.0,
TRIGGER_TAPHOLD_COORD.1,
));
}
self.clear_released_chords(&mut q);
self.ticks_to_ignore_chord = self.ticks_to_ignore_chord.saturating_sub(1);
Expand Down
8 changes: 7 additions & 1 deletion keyberon/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,13 @@ impl<'a, const C: usize, const R: usize, T: 'a + Copy + std::fmt::Debug> Layout<
});
match action {
NoOp => {
if !is_oneshot {
// There is an interaction between oneshot and chordsv2 here.
// chordsv2 sends fake queued press/release events at the coordinate level in order
// to trigger other "waiting" style actions, namely tap-hold. However, these can
// potentially interfere with oneshot by triggering early oneshot activation. This
// is resolved by ignoring actions at the coordinate at which the fake events are
// sent.
if !is_oneshot && coord != TRIGGER_TAPHOLD_COORD {
self.oneshot
.handle_press(OneShotHandlePressKey::Other(coord));
}
Expand Down
21 changes: 21 additions & 0 deletions src/tests/sim_tests/chord_sim_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,24 @@ fn sim_chord_error_on_duplicate_keyset() {
"",
);
}

#[test]
fn sim_chord_oneshot() {
let result = simulate(
"
(defcfg concurrent-tap-hold yes)
(defsrc)(deflayer base)
(defchordsv2-experimental
(a b) (one-shot 2500 rsft) 35 first-release ()
)
",
"d:a t:10 d:b t:10 u:a t:10 u:b t:3000 \
d:a t:10 d:b t:10 u:a t:10 u:b t:500 d:c u:c t:3000",
)
.to_ascii();
assert_eq!(
"t:10ms dn:RShift t:2500ms up:RShift t:530ms \
dn:RShift t:521ms dn:C t:5ms up:RShift up:C",
result
);
}

0 comments on commit d54257a

Please sign in to comment.