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

[Core] Add TAPPING_RELEASE_HOLD_TERM option for Tapping Force Hold #15508

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/config_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ If you define these options you will enable the associated feature, which may in
* Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle)
* `#define TAPPING_FORCE_HOLD_PER_KEY`
* enables handling for per key `TAPPING_FORCE_HOLD` settings
* `#define TAPPING_RELEASE_HOLD_TERM 100`
* tap and hold timing to interrupt `TAPPING_FORCE_HOLD`
* `#define LEADER_TIMEOUT 300`
* how long before the leader key times out
* If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped.
Expand Down
10 changes: 10 additions & 0 deletions docs/tap_hold.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,16 @@ bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) {
}
```

For an option to interrupt force hold, add the following to `config.h`:

```c
#define TAPPING_RELEASE_HOLD_TERM 100
```

When a tap-hold key is held again after tapping within `TAPPING_RELEASE_HOLD_TERM` in milliseconds, force hold will be interrupted. This will provide user the ability to deliberately override force hold with quick tap and hold action to auto-repeat a key. `TAPPING_RELEASE_HOLD_TERM` must be less than `TAPPING_TERM` or tapping force hold will be disabled.

?> `TAPPING_RELEASE_HOLD_TERM` will only apply to `TAPPING_FORCE_HOLD_PER_KEY` when both are used together.

## Retro Tapping

To enable `retro tapping`, add the following to your `config.h`:
Expand Down
13 changes: 11 additions & 2 deletions quantum/action_tapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ __attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t
}
# endif

# ifdef TAPPING_RELEASE_HOLD_TERM
# define WITHIN_RELEASE_HOLD_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_RELEASE_HOLD_TERM)
# endif

# ifdef PERMISSIVE_HOLD_PER_KEY
__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
return false;
Expand Down Expand Up @@ -378,10 +382,15 @@ bool process_tapping(keyrecord_t *keyp) {
if (event.pressed) {
if (IS_TAPPING_RECORD(keyp)) {
//# ifndef TAPPING_FORCE_HOLD
# if !defined(TAPPING_FORCE_HOLD) || defined(TAPPING_FORCE_HOLD_PER_KEY)
# if !defined(TAPPING_FORCE_HOLD) || defined(TAPPING_FORCE_HOLD_PER_KEY) || defined(TAPPING_RELEASE_HOLD_TERM)
if (
# ifdef TAPPING_FORCE_HOLD_PER_KEY
# if defined(TAPPING_FORCE_HOLD_PER_KEY) && defined(TAPPING_RELEASE_HOLD_TERM)
// Apply force hold term only to per key
(!get_tapping_force_hold(tapping_keycode, &tapping_key) || WITHIN_RELEASE_HOLD_TERM(event)) &&
# elif defined(TAPPING_FORCE_HOLD_PER_KEY) && !defined(TAPPING_RELEASE_HOLD_TERM)
!get_tapping_force_hold(tapping_keycode, &tapping_key) &&
# elif !defined(TAPPING_FORCE_HOLD_PER_KEY) && defined(TAPPING_RELEASE_HOLD_TERM)
WITHIN_RELEASE_HOLD_TERM(event) &&
# endif
!tapping_key.tap.interrupted && tapping_key.tap.count > 0) {
// sequential tap.
Expand Down
3 changes: 2 additions & 1 deletion tests/tap_hold_configurations/tapping_force_hold/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@

#include "test_common.h"

#define TAPPING_FORCE_HOLD
#define TAPPING_FORCE_HOLD
#define TAPPING_RELEASE_HOLD_TERM 100
34 changes: 34 additions & 0 deletions tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,37 @@ TEST_F(TappingForceHold, tap_mod_tap_hold_key_twice_and_hold_on_second_time) {
run_one_scan_loop();
testing::Mock::VerifyAndClearExpectations(&driver);
}

TEST_F(TappingForceHold, tap_mod_tap_hold_key_twice_and_hold_within_release_hold_term) {
TestDriver driver;
InSequence s;
auto mod_tap_hold_key = KeymapKey(0, 1, 0, SFT_T(KC_T));

set_keymap({mod_tap_hold_key});

/* Press mod-tap-hold key. */
EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
mod_tap_hold_key.press();
run_one_scan_loop();
testing::Mock::VerifyAndClearExpectations(&driver);

/* Release mod-tap-hold key. */
EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_T)));
EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
mod_tap_hold_key.release();
run_one_scan_loop();
testing::Mock::VerifyAndClearExpectations(&driver);

/* Press mod-tap-hold key again within release hold term. */
EXPECT_CALL(driver, send_keyboard_mock(_)).Times(0);
mod_tap_hold_key.press();
idle_for(TAPPING_RELEASE_HOLD_TERM - 3);
testing::Mock::VerifyAndClearExpectations(&driver);

/* Release mod-tap-hold key. */
EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport(KC_T)));
EXPECT_CALL(driver, send_keyboard_mock(KeyboardReport()));
mod_tap_hold_key.release();
run_one_scan_loop();
testing::Mock::VerifyAndClearExpectations(&driver);
}