From 046bd609cea437b5911d852907650a0a8b3cfdcc Mon Sep 17 00:00:00 2001 From: IsaacElenbaas Date: Mon, 27 Jul 2020 20:47:23 -0400 Subject: [PATCH 1/5] Cleanup and refactoring, mostly prepared for custom values --- quantum/process_keycode/process_auto_shift.c | 205 ++++++++----------- 1 file changed, 88 insertions(+), 117 deletions(-) diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 373e087cf1d8..b1b523cbf79d 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -27,16 +27,14 @@ static uint16_t autoshift_lastkey = KC_NO; static struct { // Whether autoshift is enabled. bool enabled : 1; - // Whether the last autoshifted key was released after the timeout. This + // Whether the last auto-shifted key was released after the timeout. This // is used to replicate the last key for a tap-then-hold. bool lastshifted : 1; - // Whether an auto-shiftable key is currently being pressed. + // Whether an auto-shiftable key has been pressed but not processed. bool in_progress : 1; // Whether the auto-shifted keypress has been registered. - bool registered : 1; - // Whether autoshift is currently "holding" the shift key. bool holding_shift : 1; -} autoshift_flags = {true, false, false, false, false}; +} autoshift_flags = {true, false, false, false}; void autoshift_timer_report(void) { char display[8]; @@ -46,27 +44,9 @@ void autoshift_timer_report(void) { send_string((const char *)display); } -/** \brief Resets the autoshift state */ -static void autoshift_flush(uint16_t now) { - if (autoshift_flags.in_progress && !autoshift_flags.registered) { - // Register the key. - register_code(autoshift_lastkey); -# if TAP_CODE_DELAY > 0 - wait_ms(TAP_CODE_DELAY); -# endif - } - // Roll the autoshift_time forward for detecting tap-and-hold. - autoshift_time = now; - autoshift_flags.in_progress = false; - autoshift_flags.registered = false; -} - -/** \brief Releases the shift key if it was held by auto-shift */ +/** \brief Releases the shift key if it was held by autoshift */ static void autoshift_flush_shift(void) { - if (autoshift_flags.holding_shift) { - // Release the shift key if it was simulated. - unregister_code(KC_LSFT); - } + del_weak_mods(MOD_BIT(KC_LSFT)); autoshift_flags.holding_shift = false; } @@ -79,24 +59,37 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { return true; } - const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); - autoshift_flush(record->event.time); # ifndef AUTO_SHIFT_MODIFIERS - if (get_mods() ^ (autoshift_flags.holding_shift ? MOD_BIT(KC_LSFT) : 0)) { + if (get_mods() & (~MOD_BIT(KC_LSFT))) { return true; } # endif -# ifndef TAPPING_FORCE_HOLD - if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey && !autoshift_flags.lastshifted) { - // Allow a tap-then-hold to hold the unshifted key. - autoshift_lastkey = KC_NO; - return true; +# ifndef AUTO_SHIFT_NO_REPEAT + const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); +# ifndef AUTO_SHIFT_NO_AUTO_REPEAT + if (!autoshift_flags.lastshifted) { +# endif + if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) { + // Allow a tap-then-hold for keyrepeat. + if (!autoshift_flags.lastshifted) { + // Change this and below to 16 if custom keys are added. + register_code(autoshift_lastkey); + } else { + // Simulate pressing the shift key. + add_weak_mods(MOD_BIT(KC_LSFT)); + register_code(autoshift_lastkey); + } + return false; + } +# ifndef AUTO_SHIFT_NO_AUTO_REPEAT } +# endif # endif // Record the keycode so we can simulate it later. autoshift_lastkey = keycode; + autoshift_time = record->event.time; autoshift_flags.in_progress = true; # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) @@ -107,113 +100,83 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { /** \brief Registers an autoshiftable key under the right conditions * - * If the autoshift delay has elapsed and no shift has already been registered, - * register a shift and the key. - * - * \return True if the timeout had elapsed. - */ -void autoshift_check_timeout(uint16_t now) { - const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); - if (elapsed >= autoshift_timeout) { - // The timeout has expired, so simulate the keypress. - if (!(get_mods() & (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)))) { - // Simulate pressing the shift key. - register_code(KC_LSFT); - autoshift_flags.lastshifted = true; - autoshift_flags.holding_shift = true; - } - register_code(autoshift_lastkey); - autoshift_flags.registered = true; - -# if TAP_CODE_DELAY > 0 - wait_ms(TAP_CODE_DELAY); -# endif - } -} - -/** \brief Registers an autoshiftable key under the right conditions - * - * If the autoshift delay has elapsed and no shift has already been registered, - * register a shift and the key. + * If the autoshift delay has elapsed, register a shift and the key. * * If the autoshift key is released before the delay has elapsed, register the * key without a shift. - * - * If another key is pressed, register the key. */ -static void autoshift_check_record(uint16_t keycode, keyrecord_t *record) { - if (!autoshift_flags.in_progress) { - return; - } +static void autoshift_end(uint16_t keycode, uint16_t now, bool matrixTrigger) { + // Called on key down with KC_NO, auto-shifted key up, and timeout. + if (autoshift_flags.in_progress) { + // Process the auto-shiftable key. + autoshift_flags.in_progress = false; - // Process the release of the autoshiftable key. - if (keycode == autoshift_lastkey && !record->event.pressed) { - autoshift_flush_shift(); // Time since the initial press was recorded. - const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); - if (!autoshift_flags.registered && elapsed < autoshift_timeout) { - // Auto-shiftable key is being released before the shift timeout; - // simulate the original press then let the usual processing take - // care of the release. - register_code(keycode); + const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); + if (elapsed < autoshift_timeout) { + // Change this and below to 16 if custom keys are added. + register_code(autoshift_lastkey); autoshift_flags.lastshifted = false; - autoshift_flags.registered = true; -# if TAP_CODE_DELAY > 0 - wait_ms(TAP_CODE_DELAY); + } else { + // Simulate pressing the shift key. + add_weak_mods(MOD_BIT(KC_LSFT)); + register_code(autoshift_lastkey); + autoshift_flags.lastshifted = true; +# if !defined(AUTO_SHIFT_NO_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) + if (matrixTrigger) { + // Prevents release. + return; + } # endif } - autoshift_flush(record->event.time); - } else if (record->event.pressed) { - if (keycode == KC_LSFT) { - // If the user presses shift, auto-shift will not hold shift for - // them. - autoshift_flags.holding_shift = false; - } else if (!autoshift_flags.registered) { - // If the key isn't registered yet, it means the timeout hasn't - // elapsed, so register the key without additional shifting. - autoshift_flush(0); - autoshift_lastkey = KC_NO; - } else { - // The key is registered; flush any shift state for the - // non-autoshiftable key. + +# if TAP_CODE_DELAY > 0 + wait_ms(TAP_CODE_DELAY); +# endif + unregister_code(autoshift_lastkey); + autoshift_flush_shift(); + } + else { + // Release after keyrepeat. + unregister_code(keycode); + if (keycode == autoshift_lastkey) { + // This will only fire when the key was the last auto-shiftable + // pressed. That prevents aaaaBBBB then releasing a from unshifting + // later Bs (if B wasn't auto-shiftable). autoshift_flush_shift(); } } + // Roll the autoshift_time forward for detecting tap-and-hold. + autoshift_time = now; } -/** \brief Simulates auto-shifted key presses +/** \brief Simulates auto-shifted key releases when timeout is hit * * Can be called from \c matrix_scan_user so that auto-shifted keys are sent * immediately after the timeout has expired, rather than waiting for the key * to be released. */ void autoshift_matrix_scan(void) { - if (!autoshift_flags.in_progress || autoshift_flags.registered) { - return; + const uint16_t now = timer_read(); + const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); + if (autoshift_flags.in_progress && elapsed >= autoshift_timeout) { + autoshift_end(autoshift_lastkey, now, true); } - - autoshift_check_timeout(timer_read()); } void autoshift_enable(void) { autoshift_flags.enabled = true; - autoshift_flush_shift(); - autoshift_flush(0); } void autoshift_disable(void) { autoshift_flags.enabled = false; autoshift_flush_shift(); - autoshift_flush(0); } void autoshift_toggle(void) { - if (autoshift_flags.enabled) { - autoshift_flags.enabled = false; + autoshift_flags.enabled = !autoshift_flags.enabled; + if (!autoshift_flags.enabled) { autoshift_flush_shift(); - autoshift_flush(0); - } else { - autoshift_flags.enabled = true; } } @@ -225,6 +188,12 @@ void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { + if (autoshift_flags.in_progress) { + autoshift_end(KC_NO, record->event.time, false); + } + // For pressing another key while keyrepeating shifted autoshift + autoshift_flush_shift(); + switch (keycode) { case KC_ASUP: autoshift_timeout += 5; @@ -247,26 +216,28 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { case KC_ASOFF: autoshift_disable(); return true; + } + } + switch (keycode) { # ifndef NO_AUTO_SHIFT_ALPHA - case KC_A ... KC_Z: + case KC_A ... KC_Z: # endif # ifndef NO_AUTO_SHIFT_NUMERIC - case KC_1 ... KC_0: + case KC_1 ... KC_0: # endif # ifndef NO_AUTO_SHIFT_SPECIAL - case KC_TAB: - case KC_MINUS ... KC_SLASH: - case KC_NONUS_BSLASH: + case KC_TAB: + case KC_MINUS ... KC_SLASH: + case KC_NONUS_BSLASH: # endif + if (record->event.pressed) { return autoshift_press(keycode, record); - - default: - break; - } + } else { + autoshift_end(keycode, record->event.time, false); + return false; + } } - - autoshift_check_record(keycode, record); return true; } From 3c1dc57b0505fc0439943f7af07571738de12b45 Mon Sep 17 00:00:00 2001 From: IsaacElenbaas Date: Tue, 28 Jul 2020 07:52:05 -0400 Subject: [PATCH 2/5] snake_case --- quantum/process_keycode/process_auto_shift.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index b1b523cbf79d..49b1c912fb21 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -105,7 +105,7 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { * If the autoshift key is released before the delay has elapsed, register the * key without a shift. */ -static void autoshift_end(uint16_t keycode, uint16_t now, bool matrixTrigger) { +static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { // Called on key down with KC_NO, auto-shifted key up, and timeout. if (autoshift_flags.in_progress) { // Process the auto-shiftable key. @@ -123,7 +123,7 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrixTrigger) { register_code(autoshift_lastkey); autoshift_flags.lastshifted = true; # if !defined(AUTO_SHIFT_NO_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) - if (matrixTrigger) { + if (matrix_trigger) { // Prevents release. return; } From 54ea2264caa8b106f2fd27dfb52d68fa6e9223c6 Mon Sep 17 00:00:00 2001 From: IsaacElenbaas Date: Tue, 28 Jul 2020 08:25:49 -0400 Subject: [PATCH 3/5] cformat, requested changes --- quantum/process_keycode/process_auto_shift.c | 28 +++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 49b1c912fb21..d8388978baa3 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -59,7 +59,6 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { return true; } - # ifndef AUTO_SHIFT_MODIFIERS if (get_mods() & (~MOD_BIT(KC_LSFT))) { return true; @@ -73,7 +72,6 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) { // Allow a tap-then-hold for keyrepeat. if (!autoshift_flags.lastshifted) { - // Change this and below to 16 if custom keys are added. register_code(autoshift_lastkey); } else { // Simulate pressing the shift key. @@ -89,7 +87,7 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { // Record the keycode so we can simulate it later. autoshift_lastkey = keycode; - autoshift_time = record->event.time; + autoshift_time = record->event.time; autoshift_flags.in_progress = true; # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) @@ -114,7 +112,6 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { // Time since the initial press was recorded. const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); if (elapsed < autoshift_timeout) { - // Change this and below to 16 if custom keys are added. register_code(autoshift_lastkey); autoshift_flags.lastshifted = false; } else { @@ -131,12 +128,11 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { } # if TAP_CODE_DELAY > 0 - wait_ms(TAP_CODE_DELAY); + wait_ms(TAP_CODE_DELAY); # endif unregister_code(autoshift_lastkey); autoshift_flush_shift(); - } - else { + } else { // Release after keyrepeat. unregister_code(keycode); if (keycode == autoshift_lastkey) { @@ -157,16 +153,16 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { * to be released. */ void autoshift_matrix_scan(void) { - const uint16_t now = timer_read(); - const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); - if (autoshift_flags.in_progress && elapsed >= autoshift_timeout) { - autoshift_end(autoshift_lastkey, now, true); + if (autoshift_flags.in_progress) { + const uint16_t now = timer_read(); + const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); + if (elapsed >= autoshift_timeout) { + autoshift_end(autoshift_lastkey, now, true); + } } } -void autoshift_enable(void) { - autoshift_flags.enabled = true; -} +void autoshift_enable(void) { autoshift_flags.enabled = true; } void autoshift_disable(void) { autoshift_flags.enabled = false; @@ -189,9 +185,11 @@ void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { if (autoshift_flags.in_progress) { + // Evaluate previous key if there is one. Doing this elsewhere is + // more complicated and easier to break. autoshift_end(KC_NO, record->event.time, false); } - // For pressing another key while keyrepeating shifted autoshift + // For pressing another key while keyrepeating shifted autoshift. autoshift_flush_shift(); switch (keycode) { From e65a3770b8da2e3eb77f8a728383d6cd455aa400 Mon Sep 17 00:00:00 2001 From: IsaacElenbaas Date: Thu, 30 Jul 2020 10:45:28 -0400 Subject: [PATCH 4/5] Docs and changed defines to not be breaking change --- docs/feature_auto_shift.md | 22 ++++++++++++++++---- quantum/process_keycode/process_auto_shift.c | 4 ++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/docs/feature_auto_shift.md b/docs/feature_auto_shift.md index ff52852ae3a9..6166b9a271b6 100644 --- a/docs/feature_auto_shift.md +++ b/docs/feature_auto_shift.md @@ -20,10 +20,11 @@ have not released the key after the `AUTO_SHIFT_TIMEOUT` period, then a shifted version of the key is emitted. If the time is less than the `AUTO_SHIFT_TIMEOUT` time, or you press another key, then the normal state is emitted. -If you hold the key down, it will repeat the shifted key. If you want to repeat -the normal key, then tap it once then immediately (within `TAPPING_TERM`) hold -it down again. The ability to repeat the normal key like this will be disabled -if `TAPPING_FORCE_HOLD` is set. +If `AUTO_SHIFT_REPEAT` is defined, there is keyrepeat support. Holding the key +down will repeat the shifted key, though this can be disabled with +`AUTO_SHIFT_NO_AUTO_REPEAT`. If you want to repeat the normal key, then tap it +once then immediately (within `TAPPING_TERM`) hold it down again (this works +with the shifted value as well if auto-repeat is disabled). ## Are There Limitations to Auto Shift? @@ -35,6 +36,11 @@ practice. As we get in a hurry, we think we have hit the key long enough for a shifted version, but we did not. On the other hand, we may think we are tapping the keys, but really we have held it for a little longer than anticipated. +Additionally, with keyrepeat the desired shift state can get mixed up. It will +always 'belong' to the last key pressed. For example, keyrepeating a capital +and then tapping something lowercase (whether or not it's an Auto Shift key) +will result in the capital's *key* still being held, but shift not. + ## How Do I Enable Auto Shift? Add to your `rules.mk` in the keymap folder: @@ -103,6 +109,14 @@ Do not Auto Shift numeric keys, zero through nine. Do not Auto Shift alpha characters, which include A through Z. +### AUTO_SHIFT_REPEAT (simple define) + +Enables keyrepeat. + +### AUTO_SHIFT_NO_AUTO_REPEAT (simple define) + +Disables automatically keyrepeating when `AUTO_SHIFT_TIMEOUT` is exceeded. + ## Using Auto Shift Setup This will enable you to define three keys temporarily to increase, decrease and report your `AUTO_SHIFT_TIMEOUT`. diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index d8388978baa3..44f8f44ca685 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -64,7 +64,7 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { return true; } # endif -# ifndef AUTO_SHIFT_NO_REPEAT +# ifdef AUTO_SHIFT_REPEAT const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); # ifndef AUTO_SHIFT_NO_AUTO_REPEAT if (!autoshift_flags.lastshifted) { @@ -119,7 +119,7 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { add_weak_mods(MOD_BIT(KC_LSFT)); register_code(autoshift_lastkey); autoshift_flags.lastshifted = true; -# if !defined(AUTO_SHIFT_NO_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) +# if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) if (matrix_trigger) { // Prevents release. return; From 3491f8618cfffe3bebad28c222a035a049a58a63 Mon Sep 17 00:00:00 2001 From: IsaacElenbaas Date: Thu, 30 Jul 2020 22:22:51 -0400 Subject: [PATCH 5/5] Fixed shift not being released and removed unnecessary flush_shift. --- quantum/process_keycode/process_auto_shift.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 44f8f44ca685..27f0b2c4e71e 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -44,12 +44,6 @@ void autoshift_timer_report(void) { send_string((const char *)display); } -/** \brief Releases the shift key if it was held by autoshift */ -static void autoshift_flush_shift(void) { - del_weak_mods(MOD_BIT(KC_LSFT)); - autoshift_flags.holding_shift = false; -} - /** \brief Record the press of an autoshiftable key * * \return Whether the record should be further processed. @@ -131,7 +125,7 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { wait_ms(TAP_CODE_DELAY); # endif unregister_code(autoshift_lastkey); - autoshift_flush_shift(); + del_weak_mods(MOD_BIT(KC_LSFT)); } else { // Release after keyrepeat. unregister_code(keycode); @@ -139,9 +133,10 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { // This will only fire when the key was the last auto-shiftable // pressed. That prevents aaaaBBBB then releasing a from unshifting // later Bs (if B wasn't auto-shiftable). - autoshift_flush_shift(); + del_weak_mods(MOD_BIT(KC_LSFT)); } } + send_keyboard_report(); // del_weak_mods doesn't send one. // Roll the autoshift_time forward for detecting tap-and-hold. autoshift_time = now; } @@ -166,14 +161,12 @@ void autoshift_enable(void) { autoshift_flags.enabled = true; } void autoshift_disable(void) { autoshift_flags.enabled = false; - autoshift_flush_shift(); + del_weak_mods(MOD_BIT(KC_LSFT)); } void autoshift_toggle(void) { autoshift_flags.enabled = !autoshift_flags.enabled; - if (!autoshift_flags.enabled) { - autoshift_flush_shift(); - } + del_weak_mods(MOD_BIT(KC_LSFT)); } bool get_autoshift_state(void) { return autoshift_flags.enabled; } @@ -190,7 +183,7 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { autoshift_end(KC_NO, record->event.time, false); } // For pressing another key while keyrepeating shifted autoshift. - autoshift_flush_shift(); + del_weak_mods(MOD_BIT(KC_LSFT)); switch (keycode) { case KC_ASUP: