This commit is contained in:
Michael Tyson 2025-12-01 09:19:50 +01:00 committed by GitHub
commit b51237eec1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 33 additions and 0 deletions

View File

@ -43,6 +43,8 @@ properties:
type: boolean
retro-tap:
type: boolean
fire-hold-as-tap:
type: boolean
hold-trigger-key-positions:
type: array
required: false

View File

@ -41,6 +41,7 @@ enum status {
STATUS_TAP,
STATUS_HOLD_INTERRUPT,
STATUS_HOLD_TIMER,
STATUS_HOLD_TAP_SENT,
};
enum decision_moment {
@ -62,6 +63,7 @@ struct behavior_hold_tap_config {
bool hold_while_undecided;
bool hold_while_undecided_linger;
bool retro_tap;
bool fire_hold_as_tap;
bool hold_trigger_on_release;
int32_t hold_trigger_key_positions_len;
int32_t hold_trigger_key_positions[];
@ -379,6 +381,8 @@ static inline const char *status_str(enum status status) {
return "hold-interrupt";
case STATUS_TAP:
return "tap";
case STATUS_HOLD_TAP_SENT:
return "hold-tap-sent";
default:
return "UNKNOWN STATUS";
}
@ -467,6 +471,12 @@ static int press_binding(struct active_hold_tap *hold_tap) {
if (hold_tap->config->hold_while_undecided) {
// the hold is already active, so we don't need to press it again
return 0;
} else if (hold_tap->config->fire_hold_as_tap) {
// send press followed immediately by release to simulate a tap
press_hold_binding(hold_tap);
release_hold_binding(hold_tap);
hold_tap->status = STATUS_HOLD_TAP_SENT;
return 0;
} else {
return press_hold_binding(hold_tap);
}
@ -485,6 +495,11 @@ static int release_binding(struct active_hold_tap *hold_tap) {
return 0;
}
if (hold_tap->config->fire_hold_as_tap && hold_tap->status == STATUS_HOLD_TAP_SENT) {
// Already sent tap/release for hold
return 0;
}
if (hold_tap->status == STATUS_HOLD_TIMER || hold_tap->status == STATUS_HOLD_INTERRUPT) {
return release_hold_binding(hold_tap);
} else {
@ -870,6 +885,7 @@ static int behavior_hold_tap_init(const struct device *dev) {
.hold_while_undecided = DT_INST_PROP(n, hold_while_undecided), \
.hold_while_undecided_linger = DT_INST_PROP(n, hold_while_undecided_linger), \
.retro_tap = DT_INST_PROP(n, retro_tap), \
.fire_hold_as_tap = DT_INST_PROP(n, fire_hold_as_tap), \
.hold_trigger_on_release = DT_INST_PROP(n, hold_trigger_on_release), \
.hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \
.hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions), \

View File

@ -460,3 +460,18 @@ For example, if you press `&mt LEFT_SHIFT A` and then release it without pressin
retro-tap;
};
```
### `fire-hold-as-tap`
If `fire-hold-as-tap` is enabled, the hold behavior will send both press and release immediately when the hold condition is met, instead of waiting for key release.
This prevents operating system key repeat behavior for hold actions that are intended to be momentary, such as triggering shortcut key combinations.
For example, if you press and hold `&mt KC_PGUP KC_PGDN` with `fire-hold-as-tap` enabled, it will send a single `KC_PGUP` event when the hold condition triggers, and will not repeat or send additional events on key release.
```dts
&mt {
fire-hold-as-tap;
};
```
**Note:** This option has no effect on the tap behavior. It only changes the way the hold action is sent.