diff options
author | James Young <18669334+noroadsleft@users.noreply.github.com> | 2020-11-28 12:02:18 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-28 12:02:18 -0800 |
commit | c66df1664497546f32662409778731143e45a552 (patch) | |
tree | da73a2d532a27685a31d932b3a44a707d4a3af81 /quantum/process_keycode/process_auto_shift.c | |
parent | 15385d4113414d42bd062c60c9de5df797d3157f (diff) | |
download | qmk_firmware-c66df1664497546f32662409778731143e45a552.tar.gz qmk_firmware-c66df1664497546f32662409778731143e45a552.zip |
2020 November 28 Breaking Changes Update (#11053)
* Branch point for 2020 November 28 Breaking Change
* Remove matrix_col_t to allow MATRIX_ROWS > 32 (#10183)
* Add support for soft serial to ATmega32U2 (#10204)
* Change MIDI velocity implementation to allow direct control of velocity value (#9940)
* Add ability to build a subset of all keyboards based on platform.
* Actually use eeprom_driver_init().
* Make bootloader_jump weak for ChibiOS. (#10417)
* Joystick 16-bit support (#10439)
* Per-encoder resolutions (#10259)
* Share button state from mousekey to pointing_device (#10179)
* Add hotfix for chibios keyboards not wake (#10088)
* Add advanced/efficient RGB Matrix Indicators (#8564)
* Naming change.
* Support for STM32 GPIOF,G,H,I,J,K (#10206)
* Add milc as a dependency and remove the installed milc (#10563)
* ChibiOS upgrade: early init conversions (#10214)
* ChibiOS upgrade: configuration file migrator (#9952)
* Haptic and solenoid cleanup (#9700)
* XD75 cleanup (#10524)
* OLED display update interval support (#10388)
* Add definition based on currently-selected serial driver. (#10716)
* New feature: Retro Tapping per key (#10622)
* Allow for modification of output RGB values when using rgblight/rgb_matrix. (#10638)
* Add housekeeping task callbacks so that keyboards/keymaps are capable of executing code for each main loop iteration. (#10530)
* Rescale both ChibiOS and AVR backlighting.
* Reduce Helix keyboard build variation (#8669)
* Minor change to behavior allowing display updates to continue between task ticks (#10750)
* Some GPIO manipulations in matrix.c change to atomic. (#10491)
* qmk cformat (#10767)
* [Keyboard] Update the Speedo firmware for v3.0 (#10657)
* Maartenwut/Maarten namechange to evyd13/Evy (#10274)
* [quantum] combine repeated lines of code (#10837)
* Add step sequencer feature (#9703)
* aeboards/ext65 refactor (#10820)
* Refactor xelus/dawn60 for Rev2 later (#10584)
* add DEBUG_MATRIX_SCAN_RATE_ENABLE to common_features.mk (#10824)
* [Core] Added `add_oneshot_mods` & `del_oneshot_mods` (#10549)
* update chibios os usb for the otg driver (#8893)
* Remove HD44780 References, Part 4 (#10735)
* [Keyboard] Add Valor FRL TKL (+refactor) (#10512)
* Fix cursor position bug in oled_write_raw functions (#10800)
* Fixup version.h writing when using SKIP_VERSION=yes (#10972)
* Allow for certain code in the codebase assuming length of string. (#10974)
* Add AT90USB support for serial.c (#10706)
* Auto shift: support repeats and early registration (#9826)
* Rename ledmatrix.h to match .c file (#7949)
* Split RGB_MATRIX_ENABLE into _ENABLE and _DRIVER (#10231)
* Split LED_MATRIX_ENABLE into _ENABLE and _DRIVER (#10840)
* Merge point for 2020 Nov 28 Breaking Change
Diffstat (limited to 'quantum/process_keycode/process_auto_shift.c')
-rw-r--r-- | quantum/process_keycode/process_auto_shift.c | 199 |
1 files changed, 149 insertions, 50 deletions
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index b1267922c..a2d315408 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c | |||
@@ -16,48 +16,149 @@ | |||
16 | 16 | ||
17 | #ifdef AUTO_SHIFT_ENABLE | 17 | #ifdef AUTO_SHIFT_ENABLE |
18 | 18 | ||
19 | # include <stdbool.h> | ||
19 | # include <stdio.h> | 20 | # include <stdio.h> |
20 | 21 | ||
21 | # include "process_auto_shift.h" | 22 | # include "process_auto_shift.h" |
22 | 23 | ||
23 | static bool autoshift_enabled = true; | ||
24 | static uint16_t autoshift_time = 0; | 24 | static uint16_t autoshift_time = 0; |
25 | static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; | 25 | static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; |
26 | static uint16_t autoshift_lastkey = KC_NO; | 26 | static uint16_t autoshift_lastkey = KC_NO; |
27 | static struct { | ||
28 | // Whether autoshift is enabled. | ||
29 | bool enabled : 1; | ||
30 | // Whether the last auto-shifted key was released after the timeout. This | ||
31 | // is used to replicate the last key for a tap-then-hold. | ||
32 | bool lastshifted : 1; | ||
33 | // Whether an auto-shiftable key has been pressed but not processed. | ||
34 | bool in_progress : 1; | ||
35 | // Whether the auto-shifted keypress has been registered. | ||
36 | bool holding_shift : 1; | ||
37 | } autoshift_flags = {true, false, false, false}; | ||
38 | |||
39 | /** \brief Record the press of an autoshiftable key | ||
40 | * | ||
41 | * \return Whether the record should be further processed. | ||
42 | */ | ||
43 | static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) { | ||
44 | if (!autoshift_flags.enabled) { | ||
45 | return true; | ||
46 | } | ||
47 | |||
48 | # ifndef AUTO_SHIFT_MODIFIERS | ||
49 | if (get_mods() & (~MOD_BIT(KC_LSFT))) { | ||
50 | return true; | ||
51 | } | ||
52 | # endif | ||
53 | # ifdef AUTO_SHIFT_REPEAT | ||
54 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
55 | # ifndef AUTO_SHIFT_NO_AUTO_REPEAT | ||
56 | if (!autoshift_flags.lastshifted) { | ||
57 | # endif | ||
58 | if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) { | ||
59 | // Allow a tap-then-hold for keyrepeat. | ||
60 | if (!autoshift_flags.lastshifted) { | ||
61 | register_code(autoshift_lastkey); | ||
62 | } else { | ||
63 | // Simulate pressing the shift key. | ||
64 | add_weak_mods(MOD_BIT(KC_LSFT)); | ||
65 | register_code(autoshift_lastkey); | ||
66 | } | ||
67 | return false; | ||
68 | } | ||
69 | # ifndef AUTO_SHIFT_NO_AUTO_REPEAT | ||
70 | } | ||
71 | # endif | ||
72 | # endif | ||
27 | 73 | ||
28 | void autoshift_flush(void) { | 74 | // Record the keycode so we can simulate it later. |
29 | if (autoshift_lastkey != KC_NO) { | 75 | autoshift_lastkey = keycode; |
30 | uint16_t elapsed = timer_elapsed(autoshift_time); | 76 | autoshift_time = now; |
77 | autoshift_flags.in_progress = true; | ||
31 | 78 | ||
32 | if (elapsed > autoshift_timeout) { | 79 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) |
33 | tap_code16(LSFT(autoshift_lastkey)); | 80 | clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); |
81 | # endif | ||
82 | return false; | ||
83 | } | ||
84 | |||
85 | /** \brief Registers an autoshiftable key under the right conditions | ||
86 | * | ||
87 | * If the autoshift delay has elapsed, register a shift and the key. | ||
88 | * | ||
89 | * If the autoshift key is released before the delay has elapsed, register the | ||
90 | * key without a shift. | ||
91 | */ | ||
92 | static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { | ||
93 | // Called on key down with KC_NO, auto-shifted key up, and timeout. | ||
94 | if (autoshift_flags.in_progress) { | ||
95 | // Process the auto-shiftable key. | ||
96 | autoshift_flags.in_progress = false; | ||
97 | |||
98 | // Time since the initial press was recorded. | ||
99 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
100 | if (elapsed < autoshift_timeout) { | ||
101 | register_code(autoshift_lastkey); | ||
102 | autoshift_flags.lastshifted = false; | ||
34 | } else { | 103 | } else { |
35 | tap_code(autoshift_lastkey); | 104 | // Simulate pressing the shift key. |
105 | add_weak_mods(MOD_BIT(KC_LSFT)); | ||
106 | register_code(autoshift_lastkey); | ||
107 | autoshift_flags.lastshifted = true; | ||
108 | # if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) | ||
109 | if (matrix_trigger) { | ||
110 | // Prevents release. | ||
111 | return; | ||
112 | } | ||
113 | # endif | ||
36 | } | 114 | } |
37 | 115 | ||
38 | autoshift_time = 0; | 116 | # if TAP_CODE_DELAY > 0 |
39 | autoshift_lastkey = KC_NO; | 117 | wait_ms(TAP_CODE_DELAY); |
118 | # endif | ||
119 | unregister_code(autoshift_lastkey); | ||
120 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
121 | } else { | ||
122 | // Release after keyrepeat. | ||
123 | unregister_code(keycode); | ||
124 | if (keycode == autoshift_lastkey) { | ||
125 | // This will only fire when the key was the last auto-shiftable | ||
126 | // pressed. That prevents aaaaBBBB then releasing a from unshifting | ||
127 | // later Bs (if B wasn't auto-shiftable). | ||
128 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
129 | } | ||
40 | } | 130 | } |
131 | send_keyboard_report(); // del_weak_mods doesn't send one. | ||
132 | // Roll the autoshift_time forward for detecting tap-and-hold. | ||
133 | autoshift_time = now; | ||
41 | } | 134 | } |
42 | 135 | ||
43 | void autoshift_on(uint16_t keycode) { | 136 | /** \brief Simulates auto-shifted key releases when timeout is hit |
44 | autoshift_time = timer_read(); | 137 | * |
45 | autoshift_lastkey = keycode; | 138 | * Can be called from \c matrix_scan_user so that auto-shifted keys are sent |
139 | * immediately after the timeout has expired, rather than waiting for the key | ||
140 | * to be released. | ||
141 | */ | ||
142 | void autoshift_matrix_scan(void) { | ||
143 | if (autoshift_flags.in_progress) { | ||
144 | const uint16_t now = timer_read(); | ||
145 | const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
146 | if (elapsed >= autoshift_timeout) { | ||
147 | autoshift_end(autoshift_lastkey, now, true); | ||
148 | } | ||
149 | } | ||
46 | } | 150 | } |
47 | 151 | ||
48 | void autoshift_toggle(void) { | 152 | void autoshift_toggle(void) { |
49 | if (autoshift_enabled) { | 153 | autoshift_flags.enabled = !autoshift_flags.enabled; |
50 | autoshift_enabled = false; | 154 | del_weak_mods(MOD_BIT(KC_LSFT)); |
51 | autoshift_flush(); | ||
52 | } else { | ||
53 | autoshift_enabled = true; | ||
54 | } | ||
55 | } | 155 | } |
56 | 156 | ||
57 | void autoshift_enable(void) { autoshift_enabled = true; } | 157 | void autoshift_enable(void) { autoshift_flags.enabled = true; } |
158 | |||
58 | void autoshift_disable(void) { | 159 | void autoshift_disable(void) { |
59 | autoshift_enabled = false; | 160 | autoshift_flags.enabled = false; |
60 | autoshift_flush(); | 161 | del_weak_mods(MOD_BIT(KC_LSFT)); |
61 | } | 162 | } |
62 | 163 | ||
63 | # ifndef AUTO_SHIFT_NO_SETUP | 164 | # ifndef AUTO_SHIFT_NO_SETUP |
@@ -70,19 +171,30 @@ void autoshift_timer_report(void) { | |||
70 | } | 171 | } |
71 | # endif | 172 | # endif |
72 | 173 | ||
73 | bool get_autoshift_state(void) { return autoshift_enabled; } | 174 | bool get_autoshift_state(void) { return autoshift_flags.enabled; } |
74 | 175 | ||
75 | uint16_t get_autoshift_timeout(void) { return autoshift_timeout; } | 176 | uint16_t get_autoshift_timeout(void) { return autoshift_timeout; } |
76 | 177 | ||
77 | void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } | 178 | void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } |
78 | 179 | ||
79 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | 180 | bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { |
181 | // Note that record->event.time isn't reliable, see: | ||
182 | // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550 | ||
183 | const uint16_t now = timer_read(); | ||
184 | |||
80 | if (record->event.pressed) { | 185 | if (record->event.pressed) { |
186 | if (autoshift_flags.in_progress) { | ||
187 | // Evaluate previous key if there is one. Doing this elsewhere is | ||
188 | // more complicated and easier to break. | ||
189 | autoshift_end(KC_NO, now, false); | ||
190 | } | ||
191 | // For pressing another key while keyrepeating shifted autoshift. | ||
192 | del_weak_mods(MOD_BIT(KC_LSFT)); | ||
193 | |||
81 | switch (keycode) { | 194 | switch (keycode) { |
82 | case KC_ASTG: | 195 | case KC_ASTG: |
83 | autoshift_toggle(); | 196 | autoshift_toggle(); |
84 | return true; | 197 | return true; |
85 | |||
86 | case KC_ASON: | 198 | case KC_ASON: |
87 | autoshift_enable(); | 199 | autoshift_enable(); |
88 | return true; | 200 | return true; |
@@ -102,41 +214,28 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | |||
102 | autoshift_timer_report(); | 214 | autoshift_timer_report(); |
103 | return true; | 215 | return true; |
104 | # endif | 216 | # endif |
217 | } | ||
218 | } | ||
219 | |||
220 | switch (keycode) { | ||
105 | # ifndef NO_AUTO_SHIFT_ALPHA | 221 | # ifndef NO_AUTO_SHIFT_ALPHA |
106 | case KC_A ... KC_Z: | 222 | case KC_A ... KC_Z: |
107 | # endif | 223 | # endif |
108 | # ifndef NO_AUTO_SHIFT_NUMERIC | 224 | # ifndef NO_AUTO_SHIFT_NUMERIC |
109 | case KC_1 ... KC_0: | 225 | case KC_1 ... KC_0: |
110 | # endif | 226 | # endif |
111 | # ifndef NO_AUTO_SHIFT_SPECIAL | 227 | # ifndef NO_AUTO_SHIFT_SPECIAL |
112 | case KC_TAB: | 228 | case KC_TAB: |
113 | case KC_MINUS ... KC_SLASH: | 229 | case KC_MINUS ... KC_SLASH: |
114 | case KC_NONUS_BSLASH: | 230 | case KC_NONUS_BSLASH: |
115 | # endif | ||
116 | autoshift_flush(); | ||
117 | if (!autoshift_enabled) return true; | ||
118 | |||
119 | # ifndef AUTO_SHIFT_MODIFIERS | ||
120 | if (get_mods()) { | ||
121 | return true; | ||
122 | } | ||
123 | # endif | ||
124 | autoshift_on(keycode); | ||
125 | |||
126 | // We need some extra handling here for OSL edge cases | ||
127 | # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) | ||
128 | clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); | ||
129 | # endif | 231 | # endif |
232 | if (record->event.pressed) { | ||
233 | return autoshift_press(keycode, now, record); | ||
234 | } else { | ||
235 | autoshift_end(keycode, now, false); | ||
130 | return false; | 236 | return false; |
131 | 237 | } | |
132 | default: | ||
133 | autoshift_flush(); | ||
134 | return true; | ||
135 | } | ||
136 | } else { | ||
137 | autoshift_flush(); | ||
138 | } | 238 | } |
139 | |||
140 | return true; | 239 | return true; |
141 | } | 240 | } |
142 | 241 | ||