Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combining mods with tap-hold-release-keys (i.e. Achordion-like tap-hold behaviour) #1006

Open
jurf opened this issue May 3, 2024 · 2 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@jurf
Copy link

jurf commented May 3, 2024

Is your feature request related to a problem? Please describe.

Homerow mods with Kanata are almost perfect thanks to tap-hold-release-keys that can much improve same-hand rolls, but unfortunately this prevents combing mods (e.g. Ctrl+Shift).

Describe the solution you'd like.

The solution I use in QMK is the Achordion library. In principle, it works similarly to tap-hold-release-keys, but it does not eagerly tap the keys on the down press. This unfortunately adds back the typical tap-hold delay, but allows to combine mods.

The implementation is a bit more nuanced (e.g. it employs a longer timeout but eagerly applies configured mods to improve usage when combined with a mouse), but the documentation is well-written.

Describe alternatives you've considered.

I currently simply hold the first modifier for the timeout duration, but honestly it's annoying and I'd rather revert back to the old behaviour.

Additional context

No response

@jurf jurf added the enhancement New feature or request label May 3, 2024
@jtroo
Copy link
Owner

jtroo commented May 3, 2024

Here's some random ideas I threw together ;)

@jtroo jtroo added the question Further information is requested label May 4, 2024
@jtroo
Copy link
Owner

jtroo commented May 4, 2024

With the random ideas thrown into the wind, perhaps one/some of them are sufficient to hit the use case.

If all are still insufficient, let's come up with what the minimal set of "missing" behaviours are. And achordion itself seems to be very similar to the internal Custom tap-hold variant which is used by tap-hold-release-keys.

Custom(&'a (dyn Fn(QueuedIter) -> (Option<WaitingAction>, bool) + Send + Sync)),

config: HoldTapConfig::Custom(custom_func(&tap_trigger_keys, &s.a)),

/// Returns a closure that can be used in `HoldTapConfig::Custom`, which will return early with a
/// Tap action in the case that any of `keys` are pressed. Otherwise it behaves as
/// `HoldTapConfig::PermissiveHold` would.
pub(crate) fn custom_tap_hold_release(
keys: &[OsCode],
a: &Allocations,
) -> &'static (dyn Fn(QueuedIter) -> (Option<WaitingAction>, bool) + Send + Sync) {
let keys = a.sref_vec(Vec::from_iter(keys.iter().copied()));
a.sref(
move |mut queued: QueuedIter| -> (Option<WaitingAction>, bool) {
while let Some(q) = queued.next() {
if q.event().is_press() {
let (i, j) = q.event().coord();
// If any key matches the input, do a tap right away.
if keys.iter().copied().map(u16::from).any(|j2| j2 == j) {
return (Some(WaitingAction::Tap), false);
}
// Otherwise do the PermissiveHold algorithm.
let target = Event::Release(i, j);
if queued.clone().copied().any(|q| q.event() == target) {
return (Some(WaitingAction::Hold), false);
}
}
}
(None, false)
},
)
}

One major difference I can think of from QMK is that multiple "eager mods" can't activate without terminating the antecedent tap-hold pending state; i.e. the decision of tap vs. hold must be chosen before activating the next eager mod. A way around this, if this is too restricting, is perhaps to forego tap-hold entirely and use:

  • multi
  • cancellable macro
  • virtual keys with switch logic tapped within the macro

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants