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.

194 lines
6.5 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.h"
  15. #include "report.h"
  16. #include "keycode.h"
  17. #include "action_layer.h"
  18. #include "action.h"
  19. #include "action_macro.h"
  20. #include "debug.h"
  21. #include "quantum.h"
  22. #ifdef BACKLIGHT_ENABLE
  23. # include "backlight.h"
  24. #endif
  25. #ifdef MIDI_ENABLE
  26. # include "process_midi.h"
  27. #endif
  28. extern keymap_config_t keymap_config;
  29. #include <inttypes.h>
  30. /* converts key to action */
  31. action_t action_for_key(uint8_t layer, keypos_t key) {
  32. // 16bit keycodes - important
  33. uint16_t keycode = keymap_key_to_keycode(layer, key);
  34. return action_for_keycode(keycode);
  35. };
  36. action_t action_for_keycode(uint16_t keycode) {
  37. // keycode remapping
  38. keycode = keycode_config(keycode);
  39. action_t action = {};
  40. uint8_t action_layer, when, mod;
  41. (void)action_layer;
  42. (void)when;
  43. (void)mod;
  44. switch (keycode) {
  45. case KC_A ... KC_EXSEL:
  46. case KC_LCTRL ... KC_RGUI:
  47. action.code = ACTION_KEY(keycode);
  48. break;
  49. #ifdef EXTRAKEY_ENABLE
  50. case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE:
  51. action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode));
  52. break;
  53. case KC_AUDIO_MUTE ... KC_BRIGHTNESS_DOWN:
  54. action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode));
  55. break;
  56. #endif
  57. #ifdef MOUSEKEY_ENABLE
  58. case KC_MS_UP ... KC_MS_ACCEL2:
  59. action.code = ACTION_MOUSEKEY(keycode);
  60. break;
  61. #endif
  62. case KC_TRNS:
  63. action.code = ACTION_TRANSPARENT;
  64. break;
  65. case QK_MODS ... QK_MODS_MAX:;
  66. // Has a modifier
  67. // Split it up
  68. action.code = ACTION_MODS_KEY(keycode >> 8, keycode & 0xFF); // adds modifier to key
  69. break;
  70. #ifndef NO_ACTION_FUNCTION
  71. case KC_FN0 ... KC_FN31:
  72. action.code = keymap_function_id_to_action(FN_INDEX(keycode));
  73. break;
  74. case QK_FUNCTION ... QK_FUNCTION_MAX:;
  75. // Is a shortcut for function action_layer, pull last 12bits
  76. // This means we have 4,096 FN macros at our disposal
  77. action.code = keymap_function_id_to_action((int)keycode & 0xFFF);
  78. break;
  79. #endif
  80. #ifndef NO_ACTION_MACRO
  81. case QK_MACRO ... QK_MACRO_MAX:
  82. if (keycode & 0x800) // tap macros have upper bit set
  83. action.code = ACTION_MACRO_TAP(keycode & 0xFF);
  84. else
  85. action.code = ACTION_MACRO(keycode & 0xFF);
  86. break;
  87. #endif
  88. #ifndef NO_ACTION_LAYER
  89. case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
  90. action.code = ACTION_LAYER_TAP_KEY((keycode >> 0x8) & 0xF, keycode & 0xFF);
  91. break;
  92. case QK_TO ... QK_TO_MAX:;
  93. // Layer set "GOTO"
  94. when = (keycode >> 0x4) & 0x3;
  95. action_layer = keycode & 0xF;
  96. action.code = ACTION_LAYER_SET(action_layer, when);
  97. break;
  98. case QK_MOMENTARY ... QK_MOMENTARY_MAX:;
  99. // Momentary action_layer
  100. action_layer = keycode & 0xFF;
  101. action.code = ACTION_LAYER_MOMENTARY(action_layer);
  102. break;
  103. case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:;
  104. // Set default action_layer
  105. action_layer = keycode & 0xFF;
  106. action.code = ACTION_DEFAULT_LAYER_SET(action_layer);
  107. break;
  108. case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:;
  109. // Set toggle
  110. action_layer = keycode & 0xFF;
  111. action.code = ACTION_LAYER_TOGGLE(action_layer);
  112. break;
  113. #endif
  114. #ifndef NO_ACTION_ONESHOT
  115. case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:;
  116. // OSL(action_layer) - One-shot action_layer
  117. action_layer = keycode & 0xFF;
  118. action.code = ACTION_LAYER_ONESHOT(action_layer);
  119. break;
  120. case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:;
  121. // OSM(mod) - One-shot mod
  122. mod = mod_config(keycode & 0xFF);
  123. action.code = ACTION_MODS_ONESHOT(mod);
  124. break;
  125. #endif
  126. #ifndef NO_ACTION_LAYER
  127. case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
  128. action.code = ACTION_LAYER_TAP_TOGGLE(keycode & 0xFF);
  129. break;
  130. case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
  131. mod = mod_config(keycode & 0xF);
  132. action_layer = (keycode >> 4) & 0xF;
  133. action.code = ACTION_LAYER_MODS(action_layer, mod);
  134. break;
  135. #endif
  136. #ifndef NO_ACTION_TAPPING
  137. case QK_MOD_TAP ... QK_MOD_TAP_MAX:
  138. mod = mod_config((keycode >> 0x8) & 0x1F);
  139. action.code = ACTION_MODS_TAP_KEY(mod, keycode & 0xFF);
  140. break;
  141. #endif
  142. #ifdef SWAP_HANDS_ENABLE
  143. case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
  144. action.code = ACTION(ACT_SWAP_HANDS, keycode & 0xff);
  145. break;
  146. #endif
  147. default:
  148. action.code = ACTION_NO;
  149. break;
  150. }
  151. return action;
  152. }
  153. __attribute__((weak)) const uint16_t PROGMEM fn_actions[] = {
  154. };
  155. /* Macro */
  156. __attribute__((weak)) const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { return MACRO_NONE; }
  157. /* Function */
  158. __attribute__((weak)) void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) {}
  159. // translates key to keycode
  160. __attribute__((weak)) uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
  161. // Read entire word (16bits)
  162. return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
  163. }
  164. // translates function id to action
  165. __attribute__((weak)) uint16_t keymap_function_id_to_action(uint16_t function_id) {
  166. // The compiler sees the empty (weak) fn_actions and generates a warning
  167. // This function should not be called in that case, so the warning is too strict
  168. // If this function is called however, the keymap should have overridden fn_actions, and then the compile
  169. // is comparing against the wrong array
  170. #pragma GCC diagnostic push
  171. #pragma GCC diagnostic ignored "-Warray-bounds"
  172. return pgm_read_word(&fn_actions[function_id]);
  173. #pragma GCC diagnostic pop
  174. }