You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
8.8 KiB

Process combos earlier & overlapping combos (#8591) * Combo processing improvements. Now it is possible to use ModTap and LayerTap keys as part of combos. Overlapping combos also don't trigger all the combos, just exactly the one that you press. New settings: - COMBO_MUST_HOLD_MODS - COMBO_MOD_TERM - COMBO_TERM_PER_COMBO - COMBO_MUST_HOLD_PER_COMBO - COMBO_STRICT_TIMER - COMBO_NO_TIMER * Remove the size flags from combo_t struct boolean members. This in the end actually saves space as the members are accessed so many times. The amount of operations needed to access the bits uses more memory than setting the size saves. * Fix `process_combo_key_release` not called correctly with tap-only combos * Fix not passing a pointer when NO_ACTION_TAPPING is defined. * Docs for `COMBO_ONLY_FROM_LAYER` * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update quantum/process_keycode/process_combo.c Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Add `EXTRA_SHORT_COMBOS` option. Stuff combo's `disabled` and `active` flags into `state`. Possibly can save some space. * Add more examples and clarify things with dict management system. - Simple examples now has a combo that has modifiers included. - The slightly more advanced examples now are actually more advanced instead of just `tap_code16(<modded-keycode>)`. - Added a note that `COMBO_ACTION`s are not needed anymore as you can just use custom keycodes. - Added a note that the `g/keymap_combo.h` macros use the `process_combo_event` function and that it is not usable in one's keymap afterwards. * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Change "the" combo action example to "email" example. * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Fix sneaky infinite loop with `combo_disable()` No need to call `dump_key_buffer` when disabling combos because the buffer is either being dumped if a combo-key was pressed, or the buffer is empty if a non-combo-key is pressed. * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> Co-authored-by: Drashna Jaelre <drashna@live.com>
2 years ago
Process combos earlier & overlapping combos (#8591) * Combo processing improvements. Now it is possible to use ModTap and LayerTap keys as part of combos. Overlapping combos also don't trigger all the combos, just exactly the one that you press. New settings: - COMBO_MUST_HOLD_MODS - COMBO_MOD_TERM - COMBO_TERM_PER_COMBO - COMBO_MUST_HOLD_PER_COMBO - COMBO_STRICT_TIMER - COMBO_NO_TIMER * Remove the size flags from combo_t struct boolean members. This in the end actually saves space as the members are accessed so many times. The amount of operations needed to access the bits uses more memory than setting the size saves. * Fix `process_combo_key_release` not called correctly with tap-only combos * Fix not passing a pointer when NO_ACTION_TAPPING is defined. * Docs for `COMBO_ONLY_FROM_LAYER` * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update quantum/process_keycode/process_combo.c Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Add `EXTRA_SHORT_COMBOS` option. Stuff combo's `disabled` and `active` flags into `state`. Possibly can save some space. * Add more examples and clarify things with dict management system. - Simple examples now has a combo that has modifiers included. - The slightly more advanced examples now are actually more advanced instead of just `tap_code16(<modded-keycode>)`. - Added a note that `COMBO_ACTION`s are not needed anymore as you can just use custom keycodes. - Added a note that the `g/keymap_combo.h` macros use the `process_combo_event` function and that it is not usable in one's keymap afterwards. * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Change "the" combo action example to "email" example. * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Fix sneaky infinite loop with `combo_disable()` No need to call `dump_key_buffer` when disabling combos because the buffer is either being dumped if a combo-key was pressed, or the buffer is empty if a non-combo-key is pressed. * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> * Update docs/feature_combo.md Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> Co-authored-by: precondition <57645186+precondition@users.noreply.github.com> Co-authored-by: Drashna Jaelre <drashna@live.com>
2 years ago
  1. /*
  2. Copyright 2012-2017 Jun Wako <wakojun@gmail.com>
  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. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include "keymap_common.h"
  15. #include "keymap_introspection.h"
  16. #include "report.h"
  17. #include "keycode.h"
  18. #include "action_layer.h"
  19. #include "action.h"
  20. #include "debug.h"
  21. #include "keycode_config.h"
  22. #include "quantum_keycodes.h"
  23. #ifdef ENCODER_MAP_ENABLE
  24. # include "encoder.h"
  25. #endif
  26. #ifdef DIP_SWITCH_MAP_ENABLE
  27. # include "dip_switch.h"
  28. #endif
  29. #ifdef BACKLIGHT_ENABLE
  30. # include "backlight.h"
  31. #endif
  32. #ifdef MIDI_ENABLE
  33. # include "process_midi.h"
  34. #endif
  35. extern keymap_config_t keymap_config;
  36. #include <inttypes.h>
  37. /* converts key to action */
  38. action_t action_for_key(uint8_t layer, keypos_t key) {
  39. // 16bit keycodes - important
  40. uint16_t keycode = keymap_key_to_keycode(layer, key);
  41. return action_for_keycode(keycode);
  42. };
  43. action_t action_for_keycode(uint16_t keycode) {
  44. // keycode remapping
  45. keycode = keycode_config(keycode);
  46. action_t action = {};
  47. uint8_t action_layer, mod;
  48. (void)action_layer;
  49. (void)mod;
  50. switch (keycode) {
  51. case BASIC_KEYCODE_RANGE:
  52. case MODIFIER_KEYCODE_RANGE:
  53. action.code = ACTION_KEY(keycode);
  54. break;
  55. #ifdef EXTRAKEY_ENABLE
  56. case SYSTEM_KEYCODE_RANGE:
  57. action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
  58. break;
  59. case CONSUMER_KEYCODE_RANGE:
  60. action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
  61. break;
  62. #endif
  63. case MOUSE_KEYCODE_RANGE:
  64. action.code = ACTION_MOUSEKEY(keycode);
  65. break;
  66. case KC_TRANSPARENT:
  67. action.code = ACTION_TRANSPARENT;
  68. break;
  69. case QK_MODS ... QK_MODS_MAX:;
  70. // Has a modifier
  71. // Split it up
  72. #ifdef LEGACY_MAGIC_HANDLING
  73. action.code = ACTION_MODS_KEY(QK_MODS_GET_MODS(keycode), QK_MODS_GET_BASIC_KEYCODE(keycode)); // adds modifier to key
  74. #else // LEGACY_MAGIC_HANDLING
  75. action.code = ACTION_MODS_KEY(mod_config(QK_MODS_GET_MODS(keycode)), keycode_config(QK_MODS_GET_BASIC_KEYCODE(keycode))); // adds modifier to key
  76. #endif // LEGACY_MAGIC_HANDLING
  77. break;
  78. case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
  79. #if !defined(NO_ACTION_LAYER) && !defined(NO_ACTION_TAPPING)
  80. # ifdef LEGACY_MAGIC_HANDLING
  81. action.code = ACTION_LAYER_TAP_KEY(QK_LAYER_TAP_GET_LAYER(keycode), QK_LAYER_TAP_GET_TAP_KEYCODE(keycode));
  82. # else // LEGACY_MAGIC_HANDLING
  83. action.code = ACTION_LAYER_TAP_KEY(QK_LAYER_TAP_GET_LAYER(keycode), keycode_config(QK_LAYER_TAP_GET_TAP_KEYCODE(keycode)));
  84. # endif // LEGACY_MAGIC_HANDLING
  85. #else
  86. // pass through keycode_config again, since it previously missed it
  87. // and then only send as ACTION_KEY to bypass most of action.c handling
  88. action.code = ACTION_KEY(keycode_config(QK_LAYER_TAP_GET_TAP_KEYCODE(keycode)));
  89. #endif
  90. break;
  91. #ifndef NO_ACTION_LAYER
  92. case QK_TO ... QK_TO_MAX:;
  93. // Layer set "GOTO"
  94. action_layer = QK_TO_GET_LAYER(keycode);
  95. action.code = ACTION_LAYER_GOTO(action_layer);
  96. break;
  97. case QK_MOMENTARY ... QK_MOMENTARY_MAX:;
  98. // Momentary action_layer
  99. action_layer = QK_MOMENTARY_GET_LAYER(keycode);
  100. action.code = ACTION_LAYER_MOMENTARY(action_layer);
  101. break;
  102. case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:;
  103. // Set default action_layer
  104. action_layer = QK_DEF_LAYER_GET_LAYER(keycode);
  105. action.code = ACTION_DEFAULT_LAYER_SET(action_layer);
  106. break;
  107. case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:;
  108. // Set toggle
  109. action_layer = QK_TOGGLE_LAYER_GET_LAYER(keycode);
  110. action.code = ACTION_LAYER_TOGGLE(action_layer);
  111. break;
  112. #endif
  113. #ifndef NO_ACTION_ONESHOT
  114. case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:;
  115. // OSL(action_layer) - One-shot action_layer
  116. action_layer = QK_ONE_SHOT_LAYER_GET_LAYER(keycode);
  117. action.code = ACTION_LAYER_ONESHOT(action_layer);
  118. break;
  119. #endif // NO_ACTION_ONESHOT
  120. case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:;
  121. // OSM(mod) - One-shot mod
  122. mod = mod_config(QK_ONE_SHOT_MOD_GET_MODS(keycode));
  123. #if defined(NO_ACTION_TAPPING) || defined(NO_ACTION_ONESHOT)
  124. action.code = ACTION_MODS(mod);
  125. #else // defined(NO_ACTION_TAPPING) || defined(NO_ACTION_ONESHOT)
  126. action.code = ACTION_MODS_ONESHOT(mod);
  127. #endif // defined(NO_ACTION_TAPPING) || defined(NO_ACTION_ONESHOT)
  128. break;
  129. #ifndef NO_ACTION_LAYER
  130. case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
  131. # ifndef NO_ACTION_TAPPING
  132. action.code = ACTION_LAYER_TAP_TOGGLE(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode));
  133. # else // NO_ACTION_TAPPING
  134. # ifdef NO_ACTION_TAPPING_TAP_TOGGLE_MO
  135. action.code = ACTION_LAYER_MOMENTARY(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode));
  136. # else // NO_ACTION_TAPPING_TAP_TOGGLE_MO
  137. action.code = ACTION_LAYER_TOGGLE(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode));
  138. # endif // NO_ACTION_TAPPING_TAP_TOGGLE_MO
  139. # endif // NO_ACTION_TAPPING
  140. break;
  141. case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
  142. mod = mod_config(QK_LAYER_MOD_GET_MODS(keycode));
  143. action_layer = QK_LAYER_MOD_GET_LAYER(keycode);
  144. action.code = ACTION_LAYER_MODS(action_layer, (mod & 0x10) ? mod << 4 : mod);
  145. break;
  146. #endif // NO_ACTION_LAYER
  147. case QK_MOD_TAP ... QK_MOD_TAP_MAX:
  148. #ifndef NO_ACTION_TAPPING
  149. mod = mod_config(QK_MOD_TAP_GET_MODS(keycode));
  150. # ifdef LEGACY_MAGIC_HANDLING
  151. action.code = ACTION_MODS_TAP_KEY(mod, QK_MOD_TAP_GET_TAP_KEYCODE(keycode));
  152. # else // LEGACY_MAGIC_HANDLING
  153. action.code = ACTION_MODS_TAP_KEY(mod, keycode_config(QK_MOD_TAP_GET_TAP_KEYCODE(keycode)));
  154. # endif // LEGACY_MAGIC_HANDLING
  155. #else // NO_ACTION_TAPPING
  156. # ifdef NO_ACTION_TAPPING_MODTAP_MODS
  157. // pass through mod_config again, since it previously missed it
  158. // and then only send as ACTION_KEY to bypass most of action.c handling
  159. action.code = ACTION_MODS(mod_config(QK_MOD_TAP_GET_MODS(keycode)));
  160. # else // NO_ACTION_TAPPING_MODTAP_MODS
  161. // pass through keycode_config again, since it previously missed it
  162. // and then only send as ACTION_KEY to bypass most of action.c handling
  163. action.code = ACTION_KEY(keycode_config(QK_MOD_TAP_GET_TAP_KEYCODE(keycode)));
  164. # endif // NO_ACTION_TAPPING_MODTAP_MODS
  165. #endif // NO_ACTION_TAPPING
  166. break;
  167. #ifdef SWAP_HANDS_ENABLE
  168. case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
  169. # ifdef LEGACY_MAGIC_HANDLING
  170. action.code = ACTION(ACT_SWAP_HANDS, QK_SWAP_HANDS_GET_TAP_KEYCODE(keycode));
  171. # else // LEGACY_MAGIC_HANDLING
  172. action.code = ACTION(ACT_SWAP_HANDS, keycode_config(QK_SWAP_HANDS_GET_TAP_KEYCODE(keycode)));
  173. # endif // LEGACY_MAGIC_HANDLING
  174. break;
  175. #endif
  176. default:
  177. action.code = ACTION_NO;
  178. break;
  179. }
  180. return action;
  181. }
  182. // translates key to keycode
  183. __attribute__((weak)) uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
  184. if (key.row < MATRIX_ROWS && key.col < MATRIX_COLS) {
  185. return keycode_at_keymap_location(layer, key.row, key.col);
  186. }
  187. #ifdef ENCODER_MAP_ENABLE
  188. else if (key.row == KEYLOC_ENCODER_CW && key.col < NUM_ENCODERS) {
  189. return keycode_at_encodermap_location(layer, key.col, true);
  190. } else if (key.row == KEYLOC_ENCODER_CCW && key.col < NUM_ENCODERS) {
  191. return keycode_at_encodermap_location(layer, key.col, false);
  192. }
  193. #endif // ENCODER_MAP_ENABLE
  194. #ifdef DIP_SWITCH_MAP_ENABLE
  195. else if (key.row == KEYLOC_DIP_SWITCH_ON && key.col < NUM_DIP_SWITCHES) {
  196. return keycode_at_dip_switch_map_location(key.col, true);
  197. } else if (key.row == KEYLOC_DIP_SWITCH_OFF && key.col < NUM_DIP_SWITCHES) {
  198. return keycode_at_dip_switch_map_location(key.col, false);
  199. }
  200. #endif // DIP_SWITCH_MAP_ENABLE
  201. return KC_NO;
  202. }