aboutsummaryrefslogtreecommitdiff
path: root/quantum/process_keycode/process_auto_shift.c
diff options
context:
space:
mode:
authorJames Young <18669334+noroadsleft@users.noreply.github.com>2020-11-28 12:02:18 -0800
committerGitHub <noreply@github.com>2020-11-28 12:02:18 -0800
commitc66df1664497546f32662409778731143e45a552 (patch)
treeda73a2d532a27685a31d932b3a44a707d4a3af81 /quantum/process_keycode/process_auto_shift.c
parent15385d4113414d42bd062c60c9de5df797d3157f (diff)
downloadqmk_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.c199
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
23static bool autoshift_enabled = true;
24static uint16_t autoshift_time = 0; 24static uint16_t autoshift_time = 0;
25static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT; 25static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
26static uint16_t autoshift_lastkey = KC_NO; 26static uint16_t autoshift_lastkey = KC_NO;
27static 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 */
43static 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
28void 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 */
92static 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
43void 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 */
142void 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
48void autoshift_toggle(void) { 152void 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
57void autoshift_enable(void) { autoshift_enabled = true; } 157void autoshift_enable(void) { autoshift_flags.enabled = true; }
158
58void autoshift_disable(void) { 159void 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
73bool get_autoshift_state(void) { return autoshift_enabled; } 174bool get_autoshift_state(void) { return autoshift_flags.enabled; }
74 175
75uint16_t get_autoshift_timeout(void) { return autoshift_timeout; } 176uint16_t get_autoshift_timeout(void) { return autoshift_timeout; }
76 177
77void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } 178void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; }
78 179
79bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { 180bool 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