From d3b9131cf333a38e1d602ee312ed541372a29fc6 Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Sat, 18 Dec 2021 13:44:34 +0800 Subject: [PATCH 1/3] Add tapping force hold term function --- docs/config_options.md | 2 ++ docs/tap_hold.md | 10 ++++++++++ quantum/action_tapping.c | 13 +++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/config_options.md b/docs/config_options.md index 838c4d86fdb0..46d9ee009045 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -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. diff --git a/docs/tap_hold.md b/docs/tap_hold.md index d206c10cc583..a221844c64b0 100644 --- a/docs/tap_hold.md +++ b/docs/tap_hold.md @@ -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 TAPPING_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`: diff --git a/quantum/action_tapping.c b/quantum/action_tapping.c index 6f8b4f8c56ae..e7214a81fde4 100644 --- a/quantum/action_tapping.c +++ b/quantum/action_tapping.c @@ -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; @@ -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. From b890773650a64007dedde6c526f7cd01dfbf99a7 Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Mon, 18 Apr 2022 17:17:26 +0800 Subject: [PATCH 2/3] Use static value for TAPPING_RELEASE_HOLD_TERM Co-authored-by: Drashna Jaelre --- docs/tap_hold.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tap_hold.md b/docs/tap_hold.md index a221844c64b0..dcc74ca84f0f 100644 --- a/docs/tap_hold.md +++ b/docs/tap_hold.md @@ -318,7 +318,7 @@ 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 TAPPING_TERM - 100 +#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. From db8443ae18f5bdbe623902527cd032dd7735ee7c Mon Sep 17 00:00:00 2001 From: Albert Y <76888457+filterpaper@users.noreply.github.com> Date: Tue, 3 May 2022 15:07:00 +0800 Subject: [PATCH 3/3] Add release_hold_term test suite --- .../tapping_force_hold/config.h | 3 +- .../tapping_force_hold/test_tap_hold.cpp | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/tap_hold_configurations/tapping_force_hold/config.h b/tests/tap_hold_configurations/tapping_force_hold/config.h index 3b4646338a30..84495e168808 100644 --- a/tests/tap_hold_configurations/tapping_force_hold/config.h +++ b/tests/tap_hold_configurations/tapping_force_hold/config.h @@ -18,4 +18,5 @@ #include "test_common.h" -#define TAPPING_FORCE_HOLD \ No newline at end of file +#define TAPPING_FORCE_HOLD +#define TAPPING_RELEASE_HOLD_TERM 100 diff --git a/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp b/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp index 3ae7c4ccfdfd..a96c5c03c580 100644 --- a/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp +++ b/tests/tap_hold_configurations/tapping_force_hold/test_tap_hold.cpp @@ -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); +}