process_auto_shift.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /* Copyright 2017 Jeremy Cowgar
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #ifdef AUTO_SHIFT_ENABLE
  17. # include <stdbool.h>
  18. # include <stdio.h>
  19. # include "process_auto_shift.h"
  20. static uint16_t autoshift_time = 0;
  21. static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
  22. static uint16_t autoshift_lastkey = KC_NO;
  23. static struct {
  24. // Whether autoshift is enabled.
  25. bool enabled : 1;
  26. // Whether the last auto-shifted key was released after the timeout. This
  27. // is used to replicate the last key for a tap-then-hold.
  28. bool lastshifted : 1;
  29. // Whether an auto-shiftable key has been pressed but not processed.
  30. bool in_progress : 1;
  31. // Whether the auto-shifted keypress has been registered.
  32. bool holding_shift : 1;
  33. } autoshift_flags = {true, false, false, false};
  34. /** \brief Record the press of an autoshiftable key
  35. *
  36. * \return Whether the record should be further processed.
  37. */
  38. static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) {
  39. if (!autoshift_flags.enabled) {
  40. return true;
  41. }
  42. # ifndef AUTO_SHIFT_MODIFIERS
  43. if (get_mods() & (~MOD_BIT(KC_LSFT))) {
  44. return true;
  45. }
  46. # endif
  47. # ifdef AUTO_SHIFT_REPEAT
  48. const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
  49. # ifndef AUTO_SHIFT_NO_AUTO_REPEAT
  50. if (!autoshift_flags.lastshifted) {
  51. # endif
  52. if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) {
  53. // Allow a tap-then-hold for keyrepeat.
  54. if (!autoshift_flags.lastshifted) {
  55. register_code(autoshift_lastkey);
  56. } else {
  57. // Simulate pressing the shift key.
  58. add_weak_mods(MOD_BIT(KC_LSFT));
  59. register_code(autoshift_lastkey);
  60. }
  61. return false;
  62. }
  63. # ifndef AUTO_SHIFT_NO_AUTO_REPEAT
  64. }
  65. # endif
  66. # endif
  67. // Record the keycode so we can simulate it later.
  68. autoshift_lastkey = keycode;
  69. autoshift_time = now;
  70. autoshift_flags.in_progress = true;
  71. # if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
  72. clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
  73. # endif
  74. return false;
  75. }
  76. /** \brief Registers an autoshiftable key under the right conditions
  77. *
  78. * If the autoshift delay has elapsed, register a shift and the key.
  79. *
  80. * If the autoshift key is released before the delay has elapsed, register the
  81. * key without a shift.
  82. */
  83. static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) {
  84. // Called on key down with KC_NO, auto-shifted key up, and timeout.
  85. if (autoshift_flags.in_progress) {
  86. // Process the auto-shiftable key.
  87. autoshift_flags.in_progress = false;
  88. // Time since the initial press was recorded.
  89. const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
  90. if (elapsed < autoshift_timeout) {
  91. register_code(autoshift_lastkey);
  92. autoshift_flags.lastshifted = false;
  93. } else {
  94. // Simulate pressing the shift key.
  95. add_weak_mods(MOD_BIT(KC_LSFT));
  96. register_code(autoshift_lastkey);
  97. autoshift_flags.lastshifted = true;
  98. # if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT)
  99. if (matrix_trigger) {
  100. // Prevents release.
  101. return;
  102. }
  103. # endif
  104. }
  105. # if TAP_CODE_DELAY > 0
  106. wait_ms(TAP_CODE_DELAY);
  107. # endif
  108. unregister_code(autoshift_lastkey);
  109. del_weak_mods(MOD_BIT(KC_LSFT));
  110. } else {
  111. // Release after keyrepeat.
  112. unregister_code(keycode);
  113. if (keycode == autoshift_lastkey) {
  114. // This will only fire when the key was the last auto-shiftable
  115. // pressed. That prevents aaaaBBBB then releasing a from unshifting
  116. // later Bs (if B wasn't auto-shiftable).
  117. del_weak_mods(MOD_BIT(KC_LSFT));
  118. }
  119. }
  120. send_keyboard_report(); // del_weak_mods doesn't send one.
  121. // Roll the autoshift_time forward for detecting tap-and-hold.
  122. autoshift_time = now;
  123. }
  124. /** \brief Simulates auto-shifted key releases when timeout is hit
  125. *
  126. * Can be called from \c matrix_scan_user so that auto-shifted keys are sent
  127. * immediately after the timeout has expired, rather than waiting for the key
  128. * to be released.
  129. */
  130. void autoshift_matrix_scan(void) {
  131. if (autoshift_flags.in_progress) {
  132. const uint16_t now = timer_read();
  133. const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
  134. if (elapsed >= autoshift_timeout) {
  135. autoshift_end(autoshift_lastkey, now, true);
  136. }
  137. }
  138. }
  139. void autoshift_toggle(void) {
  140. autoshift_flags.enabled = !autoshift_flags.enabled;
  141. del_weak_mods(MOD_BIT(KC_LSFT));
  142. }
  143. void autoshift_enable(void) { autoshift_flags.enabled = true; }
  144. void autoshift_disable(void) {
  145. autoshift_flags.enabled = false;
  146. del_weak_mods(MOD_BIT(KC_LSFT));
  147. }
  148. # ifndef AUTO_SHIFT_NO_SETUP
  149. void autoshift_timer_report(void) {
  150. char display[8];
  151. snprintf(display, 8, "\n%d\n", autoshift_timeout);
  152. send_string((const char *)display);
  153. }
  154. # endif
  155. bool get_autoshift_state(void) { return autoshift_flags.enabled; }
  156. uint16_t get_autoshift_timeout(void) { return autoshift_timeout; }
  157. void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; }
  158. bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
  159. // Note that record->event.time isn't reliable, see:
  160. // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550
  161. const uint16_t now = timer_read();
  162. if (record->event.pressed) {
  163. if (autoshift_flags.in_progress) {
  164. // Evaluate previous key if there is one. Doing this elsewhere is
  165. // more complicated and easier to break.
  166. autoshift_end(KC_NO, now, false);
  167. }
  168. // For pressing another key while keyrepeating shifted autoshift.
  169. del_weak_mods(MOD_BIT(KC_LSFT));
  170. switch (keycode) {
  171. case KC_ASTG:
  172. autoshift_toggle();
  173. return true;
  174. case KC_ASON:
  175. autoshift_enable();
  176. return true;
  177. case KC_ASOFF:
  178. autoshift_disable();
  179. return true;
  180. # ifndef AUTO_SHIFT_NO_SETUP
  181. case KC_ASUP:
  182. autoshift_timeout += 5;
  183. return true;
  184. case KC_ASDN:
  185. autoshift_timeout -= 5;
  186. return true;
  187. case KC_ASRP:
  188. autoshift_timer_report();
  189. return true;
  190. # endif
  191. }
  192. }
  193. switch (keycode) {
  194. # ifndef NO_AUTO_SHIFT_ALPHA
  195. case KC_A ... KC_Z:
  196. # endif
  197. # ifndef NO_AUTO_SHIFT_NUMERIC
  198. case KC_1 ... KC_0:
  199. # endif
  200. # ifndef NO_AUTO_SHIFT_SPECIAL
  201. case KC_TAB:
  202. case KC_MINUS ... KC_SLASH:
  203. case KC_NONUS_BSLASH:
  204. # endif
  205. if (record->event.pressed) {
  206. return autoshift_press(keycode, now, record);
  207. } else {
  208. autoshift_end(keycode, now, false);
  209. return false;
  210. }
  211. }
  212. return true;
  213. }
  214. #endif