tap_hold.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. Copyright 2022 Eric Gebhart <e.a.gebhart@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. /* This is variations on custom tap hold functionality. It makes it easy */
  15. /* to maintain tap_hold keys and combinations. These combinations go into */
  16. /* the file "tap_hold.def". Here are two examples. */
  17. /* */
  18. /* This example is tap or tap for TAP_HOLD_TERM, It defines a key */
  19. /* KC_CCCV, which sends Control-c on tap, and Control-v on hold. */
  20. /* */
  21. /* TP_TPL(KC_CCCV, LCTL(KC_C), LCTL(KC_V)) */
  22. /* */
  23. /* This is an example of Open - Open and Close. */
  24. /* It defines a key, KC_OCPRN which when tapped gives an '(' and */
  25. /* when held gives '()' followed by a backarrow. */
  26. /* Which places the cursor between them.*/
  27. /* */
  28. /* OPEN_OCL(KC_OCPRN, KC_LPRN, KC_RPRN) */
  29. /* */
  30. /* To use this, add it to your src in rules.mk, and include */
  31. /* tap_hold.h in your code above process_record_user. */
  32. /* */
  33. /* Add a call like this to use it. */
  34. /* process_tap_hold_user(keycode, record); */
  35. /* */
  36. /* Note: You must add any custom keycodes to your keycodes enum */
  37. /* otherwise they will not exist. */
  38. #include USERSPACE_H
  39. #include "stdint.h"
  40. #include "tap_hold.h"
  41. void update_smart_lock(uint16_t keycode);
  42. void tap_taplong(uint16_t kc1, uint16_t kc2, keyrecord_t *record) {
  43. if (record->event.pressed) {
  44. tap_taplong_timer = timer_read();
  45. } else {
  46. if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) {
  47. tap_code16(kc2);
  48. } else {
  49. tap_code16(kc1);
  50. }
  51. }
  52. }
  53. void tap_sml(uint16_t kc1, uint16_t kc2, keyrecord_t *record) {
  54. if (record->event.pressed) {
  55. tap_taplong_timer = timer_read();
  56. } else {
  57. if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) {
  58. update_smart_lock(kc2);
  59. } else {
  60. tap_code16(kc1);
  61. }
  62. }
  63. }
  64. /* for (){}[]""''<>``. tap for open. Hold for open and close, ending inbetween. */
  65. /* Assumes a one character length. */
  66. void open_openclose(uint16_t kc1, uint16_t kc2, keyrecord_t *record) {
  67. if (record->event.pressed) {
  68. tap_taplong_timer = timer_read();
  69. }else{
  70. if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) {
  71. tap_code16(kc1);
  72. tap_code16(kc2);
  73. tap_code16(KC_LEFT);
  74. } else {
  75. // is shifted
  76. uint16_t mod_state = get_mods();
  77. if ((mod_state & MOD_MASK_SHIFT) ||
  78. (get_oneshot_mods() & MOD_MASK_SHIFT)){
  79. del_mods(MOD_MASK_SHIFT);
  80. del_oneshot_mods(MOD_MASK_SHIFT);
  81. tap_code16(kc1);
  82. tap_code16(kc1);
  83. tap_code16(kc1);
  84. set_mods(mod_state);
  85. }else{
  86. tap_code16(kc1);
  87. }
  88. }
  89. }
  90. }
  91. // open and open close for dead keys.
  92. void open_openclose_not_dead(uint16_t kc1, uint16_t kc2, keyrecord_t *record) {
  93. if (record->event.pressed) {
  94. tap_taplong_timer = timer_read();
  95. }else{
  96. if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) {
  97. tap_code16(kc1);
  98. tap_code16(KC_SPACE);
  99. tap_code16(kc2);
  100. tap_code16(KC_SPACE);
  101. tap_code16(KC_LEFT);
  102. } else {
  103. // is shifted - give a triple
  104. uint16_t mod_state = get_mods();
  105. if ((mod_state & MOD_MASK_SHIFT) ||
  106. (get_oneshot_mods() & MOD_MASK_SHIFT)){
  107. del_mods(MOD_MASK_SHIFT);
  108. del_oneshot_mods(MOD_MASK_SHIFT);
  109. tap_code16(kc1);
  110. tap_code16(KC_SPACE);
  111. tap_code16(kc1);
  112. tap_code16(KC_SPACE);
  113. tap_code16(kc1);
  114. tap_code16(KC_SPACE);
  115. set_mods(mod_state);
  116. }else{
  117. tap_code16(kc1);
  118. tap_code16(KC_SPACE);
  119. }
  120. }
  121. }
  122. }
  123. // macros for use in tap_hold.defs.
  124. #define TP_TPL(KCKEY, KC01, KC02) \
  125. case KCKEY: \
  126. tap_taplong(KC01, KC02, record); \
  127. break;
  128. #define TP_SML(KCKEY, KC01, KC02) \
  129. case KCKEY: \
  130. tap_sml(KC01, KC02, record); \
  131. break;
  132. #define OPEN_OCL(KCKEY, KC01, KC02) \
  133. case KCKEY: \
  134. open_openclose(KC01, KC02, record); \
  135. break;
  136. #define OPEN_OCL_ND(KCKEY, KC01, KC02) \
  137. case KCKEY: \
  138. open_openclose_not_dead(KC01, KC02, record); \
  139. break;
  140. void process_tap_hold_user(uint16_t keycode, keyrecord_t *record) {
  141. switch(keycode){
  142. #include "tap_hold.def"
  143. }
  144. }