diff options
| author | Isaac Elenbaas <isaacelenbaas@gmail.com> | 2021-11-25 07:12:14 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-25 23:12:14 +1100 |
| commit | d9393b86842b7ef143259b5f771ae7969f98cbb4 (patch) | |
| tree | e0760c20f65c4cac7b6ffb3fedf3f36c6f7c13a2 /quantum/process_keycode | |
| parent | 282e916d86a5d353b7cbdfef3afad3c7b011eb14 (diff) | |
| download | qmk_firmware-d9393b86842b7ef143259b5f771ae7969f98cbb4.tar.gz qmk_firmware-d9393b86842b7ef143259b5f771ae7969f98cbb4.zip | |
Add Retro Shift (Auto Shift for Tap Hold via Retro Tapping) and Custom Auto Shifts (#11059)
* Add Retro Shift and Custom Auto Shifts
* Fix compilation errors with no RETRO_SHIFT value
Diffstat (limited to 'quantum/process_keycode')
| -rw-r--r-- | quantum/process_keycode/process_auto_shift.c | 419 | ||||
| -rw-r--r-- | quantum/process_keycode/process_auto_shift.h | 22 |
2 files changed, 346 insertions, 95 deletions
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 4d928edb5..bbc6367ff 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | # include <stdbool.h> | 19 | # include <stdbool.h> |
| 20 | # include <stdio.h> | 20 | # include <stdio.h> |
| 21 | |||
| 22 | # include "process_auto_shift.h" | 21 | # include "process_auto_shift.h" |
| 23 | 22 | ||
| 24 | # ifndef AUTO_SHIFT_DISABLED_AT_STARTUP | 23 | # ifndef AUTO_SHIFT_DISABLED_AT_STARTUP |
| @@ -27,11 +26,25 @@ | |||
| 27 | # define AUTO_SHIFT_STARTUP_STATE false /* disabled */ | 26 | # define AUTO_SHIFT_STARTUP_STATE false /* disabled */ |
| 28 | # endif | 27 | # endif |
| 29 | 28 | ||
| 30 | static uint16_t autoshift_time = 0; | 29 | // Stores the last Auto Shift key's up or down time, for evaluation or keyrepeat. |
| 31 | static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; | 30 | static uint16_t autoshift_time = 0; |
| 32 | static uint16_t autoshift_lastkey = KC_NO; | 31 | # if defined(RETRO_SHIFT) && !defined(NO_ACTION_TAPPING) |
| 32 | // Stores the last key's up or down time, to replace autoshift_time so that Tap Hold times are accurate. | ||
| 33 | static uint16_t retroshift_time = 0; | ||
| 34 | // Stores a possibly Retro Shift key's up or down time, as retroshift_time needs | ||
| 35 | // to be set before the Retro Shift key is evaluated if it is interrupted by an | ||
| 36 | // Auto Shifted key. | ||
| 37 | static uint16_t last_retroshift_time; | ||
| 38 | # endif | ||
| 39 | static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; | ||
| 40 | static uint16_t autoshift_lastkey = KC_NO; | ||
| 41 | static keyrecord_t autoshift_lastrecord; | ||
| 42 | // Keys take 8 bits if modifiers are excluded. This records the shift state | ||
| 43 | // when pressed for each key, so that can be passed to the release function | ||
| 44 | // and it knows which key needs to be released (if shifted is different base). | ||
| 45 | static uint16_t autoshift_shift_states[((1 << 8) + 15) / 16]; | ||
| 33 | static struct { | 46 | static struct { |
| 34 | // Whether autoshift is enabled. | 47 | // Whether Auto Shift is enabled. |
| 35 | bool enabled : 1; | 48 | bool enabled : 1; |
| 36 | // Whether the last auto-shifted key was released after the timeout. This | 49 | // Whether the last auto-shifted key was released after the timeout. This |
| 37 | // is used to replicate the last key for a tap-then-hold. | 50 | // is used to replicate the last key for a tap-then-hold. |
| @@ -40,43 +53,157 @@ static struct { | |||
| 40 | bool in_progress : 1; | 53 | bool in_progress : 1; |
| 41 | // Whether the auto-shifted keypress has been registered. | 54 | // Whether the auto-shifted keypress has been registered. |
| 42 | bool holding_shift : 1; | 55 | bool holding_shift : 1; |
| 43 | } autoshift_flags = {AUTO_SHIFT_STARTUP_STATE, false, false, false}; | 56 | // Whether the user is holding a shift and we removed it. |
| 57 | bool cancelling_lshift : 1; | ||
| 58 | bool cancelling_rshift : 1; | ||
| 59 | // clang-format wants to remove the true for some reason. | ||
| 60 | // clang-format off | ||
| 61 | } autoshift_flags = {AUTO_SHIFT_STARTUP_STATE, false, false, false, false, false}; | ||
| 62 | // clang-format on | ||
| 63 | |||
| 64 | /** \brief Called on physical press, returns whether key should be added to Auto Shift */ | ||
| 65 | __attribute__((weak)) bool get_custom_auto_shifted_key(uint16_t keycode, keyrecord_t *record) { return false; } | ||
| 66 | |||
| 67 | /** \brief Called on physical press, returns whether is Auto Shift key */ | ||
| 68 | __attribute__((weak)) bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *record) { | ||
| 69 | switch (keycode) { | ||
| 70 | # ifndef NO_AUTO_SHIFT_ALPHA | ||
| 71 | case AUTO_SHIFT_ALPHA: | ||
| 72 | # endif | ||
| 73 | # ifndef NO_AUTO_SHIFT_NUMERIC | ||
| 74 | case AUTO_SHIFT_NUMERIC: | ||
| 75 | # endif | ||
| 76 | # ifndef NO_AUTO_SHIFT_SPECIAL | ||
| 77 | case AUTO_SHIFT_SPECIAL: | ||
| 78 | # endif | ||
| 79 | return true; | ||
| 80 | } | ||
| 81 | return get_custom_auto_shifted_key(keycode, record); | ||
| 82 | } | ||
| 83 | |||
| 84 | /** \brief Called to check whether defines should apply if PER_KEY is set for it */ | ||
| 85 | __attribute__((weak)) bool get_auto_shift_repeat(uint16_t keycode, keyrecord_t *record) { return true; } | ||
| 86 | __attribute__((weak)) bool get_auto_shift_no_auto_repeat(uint16_t keycode, keyrecord_t *record) { return true; } | ||
| 87 | |||
| 88 | /** \brief Called when an Auto Shift key needs to be pressed */ | ||
| 89 | __attribute__((weak)) void autoshift_press_user(uint16_t keycode, bool shifted, keyrecord_t *record) { | ||
| 90 | if (shifted) { | ||
| 91 | add_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 92 | } | ||
| 93 | register_code16((IS_RETRO(keycode)) ? keycode & 0xFF : keycode); | ||
| 94 | } | ||
| 95 | |||
| 96 | /** \brief Called when an Auto Shift key needs to be released */ | ||
| 97 | __attribute__((weak)) void autoshift_release_user(uint16_t keycode, bool shifted, keyrecord_t *record) { unregister_code16((IS_RETRO(keycode)) ? keycode & 0xFF : keycode); } | ||
| 98 | |||
| 99 | /** \brief Sets the shift state to use when keyrepeating, required by custom shifts */ | ||
| 100 | void set_autoshift_shift_state(uint16_t keycode, bool shifted) { | ||
| 101 | keycode = keycode & 0xFF; | ||
| 102 | if (shifted) { | ||
| 103 | autoshift_shift_states[keycode / 16] |= (uint16_t)1 << keycode % 16; | ||
| 104 | } else { | ||
| 105 | autoshift_shift_states[keycode / 16] &= ~((uint16_t)1 << keycode % 16); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | /** \brief Gets the shift state to use when keyrepeating, required by custom shifts */ | ||
| 110 | bool get_autoshift_shift_state(uint16_t keycode) { | ||
| 111 | keycode = keycode & 0xFF; | ||
| 112 | return (autoshift_shift_states[keycode / 16] & (uint16_t)1 << keycode % 16) != (uint16_t)0; | ||
| 113 | } | ||
| 114 | |||
| 115 | /** \brief Restores the shift key if it was cancelled by Auto Shift */ | ||
| 116 | static void autoshift_flush_shift(void) { | ||
| 117 | autoshift_flags.holding_shift = false; | ||
| 118 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
| 119 | if (autoshift_flags.cancelling_lshift) { | ||
| 120 | autoshift_flags.cancelling_lshift = false; | ||
| 121 | add_mods(MOD_BIT(KC_LSFT)); | ||
| 122 | } | ||
| 123 | if (autoshift_flags.cancelling_rshift) { | ||
| 124 | autoshift_flags.cancelling_rshift = false; | ||
| 125 | add_mods(MOD_BIT(KC_RSFT)); | ||
| 126 | } | ||
| 127 | send_keyboard_report(); | ||
| 128 | } | ||
| 44 | 129 | ||
| 45 | /** \brief Record the press of an autoshiftable key | 130 | /** \brief Record the press of an autoshiftable key |
| 46 | * | 131 | * |
| 47 | * \return Whether the record should be further processed. | 132 | * \return Whether the record should be further processed. |
| 48 | */ | 133 | */ |
| 49 | static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) { | 134 | static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) { |
| 50 | if (!autoshift_flags.enabled) { | 135 | // clang-format off |
| 51 | return true; | 136 | if ((get_mods() |
| 52 | } | 137 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) |
| 53 | 138 | | get_oneshot_mods() | |
| 139 | # endif | ||
| 140 | ) & (~MOD_BIT(KC_LSFT)) | ||
| 141 | ) { | ||
| 142 | // clang-format on | ||
| 143 | // Prevents keyrepeating unshifted value of key after using it in a key combo. | ||
| 144 | autoshift_lastkey = KC_NO; | ||
| 54 | # ifndef AUTO_SHIFT_MODIFIERS | 145 | # ifndef AUTO_SHIFT_MODIFIERS |
| 55 | if (get_mods()) { | 146 | // We can't return true here anymore because custom unshifted values are |
| 56 | return true; | 147 | // possible and there's no good way to tell whether the press returned |
| 57 | } | 148 | // true upon release. |
| 149 | set_autoshift_shift_state(keycode, false); | ||
| 150 | autoshift_press_user(keycode, false, record); | ||
| 151 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) | ||
| 152 | set_oneshot_mods(get_oneshot_mods() & (~MOD_BIT(KC_LSFT))); | ||
| 153 | clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); | ||
| 154 | # endif | ||
| 155 | return false; | ||
| 58 | # endif | 156 | # endif |
| 59 | # ifdef AUTO_SHIFT_REPEAT | 157 | } |
| 60 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | 158 | |
| 61 | # ifndef AUTO_SHIFT_NO_AUTO_REPEAT | 159 | // Store record to be sent to user functions if there's no release record then. |
| 62 | if (!autoshift_flags.lastshifted) { | 160 | autoshift_lastrecord = *record; |
| 161 | autoshift_lastrecord.event.pressed = false; | ||
| 162 | autoshift_lastrecord.event.time = 0; | ||
| 163 | // clang-format off | ||
| 164 | # if defined(AUTO_SHIFT_REPEAT) || defined(AUTO_SHIFT_REPEAT_PER_KEY) | ||
| 165 | if (keycode == autoshift_lastkey && | ||
| 166 | # ifdef AUTO_SHIFT_REPEAT_PER_KEY | ||
| 167 | get_auto_shift_repeat(autoshift_lastkey, record) && | ||
| 63 | # endif | 168 | # endif |
| 64 | if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) { | 169 | # if !defined(AUTO_SHIFT_NO_AUTO_REPEAT) || defined(AUTO_SHIFT_NO_AUTO_REPEAT_PER_KEY) |
| 65 | // Allow a tap-then-hold for keyrepeat. | 170 | ( |
| 66 | if (!autoshift_flags.lastshifted) { | 171 | !autoshift_flags.lastshifted |
| 67 | register_code(autoshift_lastkey); | 172 | # ifdef AUTO_SHIFT_NO_AUTO_REPEAT_PER_KEY |
| 68 | } else { | 173 | || get_auto_shift_no_auto_repeat(autoshift_lastkey, record) |
| 69 | // Simulate pressing the shift key. | 174 | # endif |
| 70 | add_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | 175 | ) && |
| 71 | register_code(autoshift_lastkey); | 176 | # endif |
| 72 | } | 177 | TIMER_DIFF_16(now, autoshift_time) < |
| 73 | return false; | 178 | # ifdef TAPPING_TERM_PER_KEY |
| 179 | get_tapping_term(autoshift_lastkey, record) | ||
| 180 | # else | ||
| 181 | TAPPING_TERM | ||
| 182 | # endif | ||
| 183 | ) { | ||
| 184 | // clang-format on | ||
| 185 | // Allow a tap-then-hold for keyrepeat. | ||
| 186 | if (get_mods() & MOD_BIT(KC_LSFT)) { | ||
| 187 | autoshift_flags.cancelling_lshift = true; | ||
| 188 | del_mods(MOD_BIT(KC_LSFT)); | ||
| 74 | } | 189 | } |
| 75 | # ifndef AUTO_SHIFT_NO_AUTO_REPEAT | 190 | if (get_mods() & MOD_BIT(KC_RSFT)) { |
| 191 | autoshift_flags.cancelling_rshift = true; | ||
| 192 | del_mods(MOD_BIT(KC_RSFT)); | ||
| 193 | } | ||
| 194 | // autoshift_shift_state doesn't need to be changed. | ||
| 195 | autoshift_press_user(autoshift_lastkey, autoshift_flags.lastshifted, record); | ||
| 196 | return false; | ||
| 76 | } | 197 | } |
| 77 | # endif | ||
| 78 | # endif | 198 | # endif |
| 79 | 199 | ||
| 200 | // Use physical shift state of press event to be more like normal typing. | ||
| 201 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) | ||
| 202 | autoshift_flags.lastshifted = (get_mods() | get_oneshot_mods()) & MOD_BIT(KC_LSFT); | ||
| 203 | set_oneshot_mods(get_oneshot_mods() & (~MOD_BIT(KC_LSFT))); | ||
| 204 | # else | ||
| 205 | autoshift_flags.lastshifted = get_mods() & MOD_BIT(KC_LSFT); | ||
| 206 | # endif | ||
| 80 | // Record the keycode so we can simulate it later. | 207 | // Record the keycode so we can simulate it later. |
| 81 | autoshift_lastkey = keycode; | 208 | autoshift_lastkey = keycode; |
| 82 | autoshift_time = now; | 209 | autoshift_time = now; |
| @@ -90,51 +217,70 @@ static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) | |||
| 90 | 217 | ||
| 91 | /** \brief Registers an autoshiftable key under the right conditions | 218 | /** \brief Registers an autoshiftable key under the right conditions |
| 92 | * | 219 | * |
| 93 | * If the autoshift delay has elapsed, register a shift and the key. | 220 | * If autoshift_timeout has elapsed, register a shift and the key. |
| 94 | * | 221 | * |
| 95 | * If the autoshift key is released before the delay has elapsed, register the | 222 | * If the Auto Shift key is released before the delay has elapsed, register the |
| 96 | * key without a shift. | 223 | * key without a shift. |
| 224 | * | ||
| 225 | * Called on key down with keycode=KC_NO, auto-shifted key up, and timeout. | ||
| 97 | */ | 226 | */ |
| 98 | static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { | 227 | static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger, keyrecord_t *record) { |
| 99 | // Called on key down with KC_NO, auto-shifted key up, and timeout. | 228 | if (autoshift_flags.in_progress && (keycode == autoshift_lastkey || keycode == KC_NO)) { |
| 100 | if (autoshift_flags.in_progress) { | ||
| 101 | // Process the auto-shiftable key. | 229 | // Process the auto-shiftable key. |
| 102 | autoshift_flags.in_progress = false; | 230 | autoshift_flags.in_progress = false; |
| 103 | 231 | // clang-format off | |
| 104 | // Time since the initial press was recorded. | 232 | autoshift_flags.lastshifted = |
| 105 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | 233 | autoshift_flags.lastshifted |
| 106 | if (elapsed < autoshift_timeout) { | 234 | || TIMER_DIFF_16(now, autoshift_time) >= |
| 107 | register_code(autoshift_lastkey); | 235 | # ifdef AUTO_SHIFT_TIMEOUT_PER_KEY |
| 108 | autoshift_flags.lastshifted = false; | 236 | get_autoshift_timeout(autoshift_lastkey, record) |
| 109 | } else { | 237 | # else |
| 110 | // Simulate pressing the shift key. | 238 | autoshift_timeout |
| 111 | add_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | ||
| 112 | register_code(autoshift_lastkey); | ||
| 113 | autoshift_flags.lastshifted = true; | ||
| 114 | # if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) | ||
| 115 | if (matrix_trigger) { | ||
| 116 | // Prevents release. | ||
| 117 | return; | ||
| 118 | } | ||
| 119 | # endif | 239 | # endif |
| 240 | ; | ||
| 241 | // clang-format on | ||
| 242 | set_autoshift_shift_state(autoshift_lastkey, autoshift_flags.lastshifted); | ||
| 243 | if (get_mods() & MOD_BIT(KC_LSFT)) { | ||
| 244 | autoshift_flags.cancelling_lshift = true; | ||
| 245 | del_mods(MOD_BIT(KC_LSFT)); | ||
| 246 | } | ||
| 247 | if (get_mods() & MOD_BIT(KC_RSFT)) { | ||
| 248 | autoshift_flags.cancelling_rshift = true; | ||
| 249 | del_mods(MOD_BIT(KC_RSFT)); | ||
| 120 | } | 250 | } |
| 251 | autoshift_press_user(autoshift_lastkey, autoshift_flags.lastshifted, record); | ||
| 121 | 252 | ||
| 253 | // clang-format off | ||
| 254 | # if (defined(AUTO_SHIFT_REPEAT) || defined(AUTO_SHIFT_REPEAT_PER_KEY)) && (!defined(AUTO_SHIFT_NO_AUTO_REPEAT) || defined(AUTO_SHIFT_NO_AUTO_REPEAT_PER_KEY)) | ||
| 255 | if (matrix_trigger | ||
| 256 | # ifdef AUTO_SHIFT_REPEAT_PER_KEY | ||
| 257 | && get_auto_shift_repeat(autoshift_lastkey, record) | ||
| 258 | # endif | ||
| 259 | # ifdef AUTO_SHIFT_NO_AUTO_REPEAT_PER_KEY | ||
| 260 | && !get_auto_shift_no_auto_repeat(autoshift_lastkey, record) | ||
| 261 | # endif | ||
| 262 | ) { | ||
| 263 | // Prevents release. | ||
| 264 | return; | ||
| 265 | } | ||
| 266 | # endif | ||
| 267 | // clang-format on | ||
| 122 | # if TAP_CODE_DELAY > 0 | 268 | # if TAP_CODE_DELAY > 0 |
| 123 | wait_ms(TAP_CODE_DELAY); | 269 | wait_ms(TAP_CODE_DELAY); |
| 124 | # endif | 270 | # endif |
| 125 | unregister_code(autoshift_lastkey); | 271 | |
| 126 | del_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | 272 | autoshift_release_user(autoshift_lastkey, autoshift_flags.lastshifted, record); |
| 273 | autoshift_flush_shift(); | ||
| 127 | } else { | 274 | } else { |
| 128 | // Release after keyrepeat. | 275 | // Release after keyrepeat. |
| 129 | unregister_code(keycode); | 276 | autoshift_release_user(keycode, get_autoshift_shift_state(keycode), record); |
| 130 | if (keycode == autoshift_lastkey) { | 277 | if (keycode == autoshift_lastkey) { |
| 131 | // This will only fire when the key was the last auto-shiftable | 278 | // This will only fire when the key was the last auto-shiftable |
| 132 | // pressed. That prevents aaaaBBBB then releasing a from unshifting | 279 | // pressed. That prevents 'aaaaBBBB' then releasing a from unshifting |
| 133 | // later Bs (if B wasn't auto-shiftable). | 280 | // later 'B's (if 'B' wasn't auto-shiftable). |
| 134 | del_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | 281 | autoshift_flush_shift(); |
| 135 | } | 282 | } |
| 136 | } | 283 | } |
| 137 | send_keyboard_report(); // del_weak_mods doesn't send one. | ||
| 138 | // Roll the autoshift_time forward for detecting tap-and-hold. | 284 | // Roll the autoshift_time forward for detecting tap-and-hold. |
| 139 | autoshift_time = now; | 285 | autoshift_time = now; |
| 140 | } | 286 | } |
| @@ -147,24 +293,29 @@ static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { | |||
| 147 | */ | 293 | */ |
| 148 | void autoshift_matrix_scan(void) { | 294 | void autoshift_matrix_scan(void) { |
| 149 | if (autoshift_flags.in_progress) { | 295 | if (autoshift_flags.in_progress) { |
| 150 | const uint16_t now = timer_read(); | 296 | const uint16_t now = timer_read(); |
| 151 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | 297 | if (TIMER_DIFF_16(now, autoshift_time) >= |
| 152 | if (elapsed >= autoshift_timeout) { | 298 | # ifdef AUTO_SHIFT_TIMEOUT_PER_KEY |
| 153 | autoshift_end(autoshift_lastkey, now, true); | 299 | get_autoshift_timeout(autoshift_lastkey, &autoshift_lastrecord) |
| 300 | # else | ||
| 301 | autoshift_timeout | ||
| 302 | # endif | ||
| 303 | ) { | ||
| 304 | autoshift_end(autoshift_lastkey, now, true, &autoshift_lastrecord); | ||
| 154 | } | 305 | } |
| 155 | } | 306 | } |
| 156 | } | 307 | } |
| 157 | 308 | ||
| 158 | void autoshift_toggle(void) { | 309 | void autoshift_toggle(void) { |
| 159 | autoshift_flags.enabled = !autoshift_flags.enabled; | 310 | autoshift_flags.enabled = !autoshift_flags.enabled; |
| 160 | del_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | 311 | autoshift_flush_shift(); |
| 161 | } | 312 | } |
| 162 | 313 | ||
| 163 | void autoshift_enable(void) { autoshift_flags.enabled = true; } | 314 | void autoshift_enable(void) { autoshift_flags.enabled = true; } |
| 164 | 315 | ||
| 165 | void autoshift_disable(void) { | 316 | void autoshift_disable(void) { |
| 166 | autoshift_flags.enabled = false; | 317 | autoshift_flags.enabled = false; |
| 167 | del_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | 318 | autoshift_flush_shift(); |
| 168 | } | 319 | } |
| 169 | 320 | ||
| 170 | # ifndef AUTO_SHIFT_NO_SETUP | 321 | # ifndef AUTO_SHIFT_NO_SETUP |
| @@ -179,76 +330,158 @@ void autoshift_timer_report(void) { | |||
| 179 | 330 | ||
| 180 | bool get_autoshift_state(void) { return autoshift_flags.enabled; } | 331 | bool get_autoshift_state(void) { return autoshift_flags.enabled; } |
| 181 | 332 | ||
| 182 | uint16_t get_autoshift_timeout(void) { return autoshift_timeout; } | 333 | uint16_t get_generic_autoshift_timeout() { return autoshift_timeout; } |
| 334 | __attribute__((weak)) uint16_t get_autoshift_timeout(uint16_t keycode, keyrecord_t *record) { return autoshift_timeout; } | ||
| 183 | 335 | ||
| 184 | void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } | 336 | void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } |
| 185 | 337 | ||
| 186 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | 338 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { |
| 187 | // Note that record->event.time isn't reliable, see: | 339 | // Note that record->event.time isn't reliable, see: |
| 188 | // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550 | 340 | // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550 |
| 189 | const uint16_t now = timer_read(); | 341 | // clang-format off |
| 342 | const uint16_t now = | ||
| 343 | # if !defined(RETRO_SHIFT) || defined(NO_ACTION_TAPPING) | ||
| 344 | timer_read() | ||
| 345 | # else | ||
| 346 | (record->event.pressed) ? retroshift_time : timer_read() | ||
| 347 | # endif | ||
| 348 | ; | ||
| 349 | // clang-format on | ||
| 190 | 350 | ||
| 191 | if (record->event.pressed) { | 351 | if (record->event.pressed) { |
| 192 | if (autoshift_flags.in_progress) { | 352 | if (autoshift_flags.in_progress) { |
| 193 | // Evaluate previous key if there is one. Doing this elsewhere is | 353 | // Evaluate previous key if there is one. |
| 194 | // more complicated and easier to break. | 354 | autoshift_end(KC_NO, now, false, &autoshift_lastrecord); |
| 195 | autoshift_end(KC_NO, now, false); | ||
| 196 | } | 355 | } |
| 197 | // For pressing another key while keyrepeating shifted autoshift. | ||
| 198 | del_weak_mods(MOD_BIT(KC_LEFT_SHIFT)); | ||
| 199 | 356 | ||
| 200 | switch (keycode) { | 357 | switch (keycode) { |
| 201 | case KC_ASTG: | 358 | case KC_ASTG: |
| 202 | autoshift_toggle(); | 359 | autoshift_toggle(); |
| 203 | return true; | 360 | break; |
| 204 | case KC_ASON: | 361 | case KC_ASON: |
| 205 | autoshift_enable(); | 362 | autoshift_enable(); |
| 206 | return true; | 363 | break; |
| 207 | case KC_ASOFF: | 364 | case KC_ASOFF: |
| 208 | autoshift_disable(); | 365 | autoshift_disable(); |
| 209 | return true; | 366 | break; |
| 210 | 367 | ||
| 211 | # ifndef AUTO_SHIFT_NO_SETUP | 368 | # ifndef AUTO_SHIFT_NO_SETUP |
| 212 | case KC_ASUP: | 369 | case KC_ASUP: |
| 213 | autoshift_timeout += 5; | 370 | autoshift_timeout += 5; |
| 214 | return true; | 371 | break; |
| 215 | case KC_ASDN: | 372 | case KC_ASDN: |
| 216 | autoshift_timeout -= 5; | 373 | autoshift_timeout -= 5; |
| 217 | return true; | 374 | break; |
| 218 | |||
| 219 | case KC_ASRP: | 375 | case KC_ASRP: |
| 220 | autoshift_timer_report(); | 376 | autoshift_timer_report(); |
| 221 | return true; | 377 | break; |
| 378 | # endif | ||
| 379 | } | ||
| 380 | // If Retro Shift is disabled, possible custom actions shouldn't happen. | ||
| 381 | // clang-format off | ||
| 382 | if (IS_RETRO(keycode) | ||
| 383 | # if defined(RETRO_SHIFT) && !defined(NO_ACTION_TAPPING) | ||
| 384 | // Not tapped or #defines mean that rolls should use hold action. | ||
| 385 | && ( | ||
| 386 | record->tap.count == 0 | ||
| 387 | # ifdef RETRO_TAPPING_PER_KEY | ||
| 388 | || !get_retro_tapping(keycode, record) | ||
| 389 | # endif | ||
| 390 | || (record->tap.interrupted && (IS_LT(keycode) | ||
| 391 | # if defined(HOLD_ON_OTHER_KEY_PRESS) || defined(HOLD_ON_OTHER_KEY_PRESS_PER_KEY) | ||
| 392 | # ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY | ||
| 393 | ? get_hold_on_other_key_press(keycode, record) | ||
| 394 | # else | ||
| 395 | ? true | ||
| 396 | # endif | ||
| 397 | # else | ||
| 398 | ? false | ||
| 399 | # endif | ||
| 400 | # if defined(IGNORE_MOD_TAP_INTERRUPT) || defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY) | ||
| 401 | # ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY | ||
| 402 | : !get_ignore_mod_tap_interrupt(keycode, record) | ||
| 403 | # else | ||
| 404 | : false | ||
| 405 | # endif | ||
| 406 | # else | ||
| 407 | : true | ||
| 408 | # endif | ||
| 409 | )) | ||
| 410 | ) | ||
| 411 | # endif | ||
| 412 | ) { | ||
| 413 | // clang-format on | ||
| 414 | autoshift_lastkey = KC_NO; | ||
| 415 | return true; | ||
| 416 | } | ||
| 417 | } else { | ||
| 418 | if (keycode == KC_LSFT) { | ||
| 419 | autoshift_flags.cancelling_lshift = false; | ||
| 420 | } else if (keycode == KC_RSFT) { | ||
| 421 | autoshift_flags.cancelling_rshift = false; | ||
| 422 | } | ||
| 423 | // Same as above (for pressed), additional checks are not needed because | ||
| 424 | // tap.count gets set to 0 in process_action | ||
| 425 | // clang-format off | ||
| 426 | else if (IS_RETRO(keycode) | ||
| 427 | # if defined(RETRO_SHIFT) && !defined(NO_ACTION_TAPPING) | ||
| 428 | && ( | ||
| 429 | record->tap.count == 0 | ||
| 430 | # ifdef RETRO_TAPPING_PER_KEY | ||
| 431 | || !get_retro_tapping(keycode, record) | ||
| 432 | # endif | ||
| 433 | ) | ||
| 222 | # endif | 434 | # endif |
| 435 | ) { | ||
| 436 | // Fixes modifiers not being applied to rolls with AUTO_SHIFT_MODIFIERS set. | ||
| 437 | # if !defined(IGNORE_MOD_TAP_INTERRUPT) || defined(IGNORE_MOD_TAP_INTERRUPT_PER_KEY) | ||
| 438 | if (autoshift_flags.in_progress | ||
| 439 | # ifdef IGNORE_MOD_TAP_INTERRUPT_PER_KEY | ||
| 440 | && !get_ignore_mod_tap_interrupt(keycode, record) | ||
| 441 | # endif | ||
| 442 | ) { | ||
| 443 | autoshift_end(KC_NO, now, false, &autoshift_lastrecord); | ||
| 444 | } | ||
| 445 | # endif | ||
| 446 | // clang-format on | ||
| 447 | return true; | ||
| 223 | } | 448 | } |
| 224 | } | 449 | } |
| 450 | |||
| 451 | if (!autoshift_flags.enabled) { | ||
| 452 | return true; | ||
| 453 | } | ||
| 225 | if (get_auto_shifted_key(keycode, record)) { | 454 | if (get_auto_shifted_key(keycode, record)) { |
| 226 | if (record->event.pressed) { | 455 | if (record->event.pressed) { |
| 227 | return autoshift_press(keycode, now, record); | 456 | return autoshift_press(keycode, now, record); |
| 228 | } else { | 457 | } else { |
| 229 | autoshift_end(keycode, now, false); | 458 | autoshift_end(keycode, now, false, record); |
| 230 | return false; | 459 | return false; |
| 231 | } | 460 | } |
| 232 | } | 461 | } |
| 462 | |||
| 463 | // Prevent keyrepeating of older keys upon non-AS key event. | ||
| 464 | // Not commented at above returns but they serve the same function. | ||
| 465 | if (record->event.pressed) { | ||
| 466 | autoshift_lastkey = KC_NO; | ||
| 467 | } | ||
| 233 | return true; | 468 | return true; |
| 234 | } | 469 | } |
| 235 | 470 | ||
| 236 | __attribute__((weak)) bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *record) { | 471 | # if defined(RETRO_SHIFT) && !defined(NO_ACTION_TAPPING) |
| 237 | switch (keycode) { | 472 | // Called to record time before possible delays by action_tapping_process. |
| 238 | # ifndef NO_AUTO_SHIFT_ALPHA | 473 | void retroshift_poll_time(keyevent_t *event) { |
| 239 | case KC_A ... KC_Z: | 474 | last_retroshift_time = retroshift_time; |
| 240 | # endif | 475 | retroshift_time = timer_read(); |
| 241 | # ifndef NO_AUTO_SHIFT_NUMERIC | 476 | } |
| 242 | case KC_1 ... KC_0: | 477 | // Used to swap the times of Retro Shifted key and Auto Shift key that interrupted it. |
| 243 | # endif | 478 | void retroshift_swap_times() { |
| 244 | # ifndef NO_AUTO_SHIFT_SPECIAL | 479 | if (last_retroshift_time != 0 && autoshift_flags.in_progress) { |
| 245 | case KC_TAB: | 480 | uint16_t temp = retroshift_time; |
| 246 | case KC_MINUS ... KC_SLASH: | 481 | retroshift_time = last_retroshift_time; |
| 247 | case KC_NONUS_BACKSLASH: | 482 | last_retroshift_time = temp; |
| 248 | # endif | ||
| 249 | return true; | ||
| 250 | } | 483 | } |
| 251 | return false; | ||
| 252 | } | 484 | } |
| 485 | # endif | ||
| 253 | 486 | ||
| 254 | #endif | 487 | #endif |
diff --git a/quantum/process_keycode/process_auto_shift.h b/quantum/process_keycode/process_auto_shift.h index 00a9ab036..ac6a14374 100644 --- a/quantum/process_keycode/process_auto_shift.h +++ b/quantum/process_keycode/process_auto_shift.h | |||
| @@ -22,13 +22,31 @@ | |||
| 22 | # define AUTO_SHIFT_TIMEOUT 175 | 22 | # define AUTO_SHIFT_TIMEOUT 175 |
| 23 | #endif | 23 | #endif |
| 24 | 24 | ||
| 25 | #define IS_LT(kc) ((kc) >= QK_LAYER_TAP && (kc) <= QK_LAYER_TAP_MAX) | ||
| 26 | #define IS_MT(kc) ((kc) >= QK_MOD_TAP && (kc) <= QK_MOD_TAP_MAX) | ||
| 27 | #define IS_RETRO(kc) (IS_MT(kc) || IS_LT(kc)) | ||
| 28 | #define DO_GET_AUTOSHIFT_TIMEOUT(keycode, record, ...) record | ||
| 29 | // clang-format off | ||
| 30 | #define AUTO_SHIFT_ALPHA KC_A ... KC_Z | ||
| 31 | #define AUTO_SHIFT_NUMERIC KC_1 ... KC_0 | ||
| 32 | #define AUTO_SHIFT_SPECIAL \ | ||
| 33 | KC_TAB: \ | ||
| 34 | case KC_MINUS ... KC_SLASH: \ | ||
| 35 | case KC_NONUS_BSLASH | ||
| 36 | // clang-format on | ||
| 37 | |||
| 25 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record); | 38 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record); |
| 39 | void retroshift_poll_time(keyevent_t *event); | ||
| 40 | void retroshift_swap_times(void); | ||
| 26 | 41 | ||
| 27 | void autoshift_enable(void); | 42 | void autoshift_enable(void); |
| 28 | void autoshift_disable(void); | 43 | void autoshift_disable(void); |
| 29 | void autoshift_toggle(void); | 44 | void autoshift_toggle(void); |
| 30 | bool get_autoshift_state(void); | 45 | bool get_autoshift_state(void); |
| 31 | uint16_t get_autoshift_timeout(void); | 46 | uint16_t get_generic_autoshift_timeout(void); |
| 47 | // clang-format off | ||
| 48 | uint16_t (get_autoshift_timeout)(uint16_t keycode, keyrecord_t *record); | ||
| 32 | void set_autoshift_timeout(uint16_t timeout); | 49 | void set_autoshift_timeout(uint16_t timeout); |
| 33 | void autoshift_matrix_scan(void); | 50 | void autoshift_matrix_scan(void); |
| 34 | bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *record); | 51 | bool get_custom_auto_shifted_key(uint16_t keycode, keyrecord_t *record); |
| 52 | // clang-format on | ||
