Add fire-hold-as-tap option to behavior-hold-tap
Add fire-hold-as-tap option to behavior-hold-tap
This introduces a new optional setting for behavior-hold-tap called fire-hold-as-tap.
When enabled, the hold behavior will send both a press and immediate release immediately when the hold condition is met, instead of sending a press on hold and a release on key-up. This prevents operating system key repeat behavior for hold actions that are intended to be momentary.
This is especially useful for sending keyboard shortcuts on hold, when key repeats would be undesirable or harmful.
The option is fully backwards compatible and defaults to off.
Feature Added
- New boolean property:
fire-hold-as-tapforbehavior_hold_tap - Allows safe assignment of normal keys or simple behaviors to the hold side of hold-tap bindings
- Eliminates OS key repeats by sending both press + release immediately on hold condition
Testing Performed
Tested locally on:
- Wireless Corne using config repo with modified ZMK fork
- Multiple hold-tap keys with
fire-hold-as-tapset true and false - Long key holds confirmed: no OS-level repeat triggered
- Tap behavior unaffected
Example Usage
ht: hold_tap {
compatible = "zmk,behavior-hold-tap";
#binding-cells = <2>;
bindings = <&kp>, <&kp>;
tapping-term-ms = <300>;
quick-tap-ms = <150>;
flavor = "tap-preferred";
fire-hold-as-tap;
};
Additional Notes
This was implemented as an additional internal state (STATUS_HOLD_TAP_SENT) to avoid sending redundant key releases and keep the existing state machine clean.
If maintainers prefer, this could be split into a separate behavior (&tap-on-hold), but integrating it as an optional extension of hold-tap seems to align better with the extensibility approach of the current design.
Hey, thanks for the PR. I'm not sure I see the need for this, as this functionality should be accomplishable by putting a macro inside of a hold-tap. If it isn't, then I would consider that a bug in need of tackling. I would be supportive of a PR demonstrating putting a macro inside of a hold-tap in our docs, though.
Wow, super quick response!
Yeah, I can see that it could probably be achievable using macros – the problem that I had was that I just couldn’t figure it out on my own, and it seemed like a lot of finagling was required to get it working, especially within Nick Coutsos’ editor.
Setting it up with a macro seemed unnecessarily complex for what is a very simple requirement: send a single key/shortcut on hold without triggering OS repeats.
This PR offers a minimal, backwards-compatible option inside an existing core behavior. It makes this common case trivial to configure, without requiring extra behaviour definitions or macros.
What that said, I am not at all familiar with the ideology behind the current hold tap behaviour, so feel free to disregard if this is at odds with the intended use. But it did make my use case a lot simpler to achieve.
Thanks for your time!
Yeah, I can see that it could probably be achievable using macros – the problem that I had was that I just couldn’t figure it out on my own, and it seemed like a lot of finagling was required to get it working, especially within Nick Coutsos’ editor.
Yeah, this is what a note in the docs should have helped with. I don't really consider it unnecessarily complex to use a macro for this - I would consider it an elegant solution to make a &ktap behaviour using macro-one-param, and then simply use that in place of &kt in the hold-tap definition. This also allows to avoid issues that some OS may have where they expect a certain delay between taps and releases, something that macros can configure but is lacking here.
What that said, I am not at all familiar with the ideology behind the current hold tap behaviour, so feel free to disregard if this is at odds with the intended use. But it did make my use case a lot simpler to achieve.
Philosophically speaking, ignoring that this functionality already exists in ZMK, I consider hold-taps a "decision-maker" between different branches that the execution can take. Also allowing them to output more than one behaviour on a press or a release would confuse their purpose and I would fear the potential edge cases that can follow from that. Others may see the issue differently, though.
Practically speaking, I think that this PR would need approval from Pete, which considering his review backlog, pacing, and the higher priorities of other issues would mean it likely wouldn't get looked at for a very long time.
I think I would encourage you as an individual to take the macro solution to the problem, to avoid needing to maintain a branch. I do hope that my comments haven't discouraged you from making further contributions in the future. If you have further issues with setting up your keymap or missing functionality, perhaps it might be an idea to go to the ZMK discord and ask for advice there, and if your use case isn't solved then a PR or a module would certainly be welcomed.
Sure thing, no problem. I'll take a crack at it.
FWIW, I've been trying for an hour to get the macro behaviour to work with no luck—making this PR and updating my keymap to use it took 20 minutes. Just from a user's perspective, the macro equivalent is appallingly inaccessible. I'm giving up and using my own fork from here on out.
If this were my project, I'd be going with this PR, as it's drastically simpler.