nshot_mod.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. Copyright 2022 Eric Gebhart <e.a.gebhart@gmail.com>, @possumvibes
  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. // Derived from nshot_mod by @possumvibes.
  15. // Derived from one shot_mod by @Callum.
  16. #include "nshot_mod.h"
  17. #include USERSPACE_H
  18. #undef NSHOT
  19. #define NSHOT(KEYCODE, MOD, COUNT) \
  20. {KEYCODE, MOD, COUNT, os_up_unqueued, 0},
  21. #undef ONESHOT
  22. #define ONESHOT(KEYCODE, MOD) NSHOT(KEYCODE, MOD, 1)
  23. #define A_KEY(KEYCODE) case KEYCODE:
  24. #define BLANK(...)
  25. #define CANCEL_KEY BLANK
  26. #define IGNORE_KEY BLANK
  27. nshot_state_t nshot_states[] = {
  28. #include "nshot.def"
  29. };
  30. uint8_t NUM_NSHOT_STATES = sizeof(nshot_states) / sizeof(nshot_state_t);
  31. bool process_nshot_state(uint16_t keycode, keyrecord_t *record) {
  32. nshot_state_t *curr_state = NULL;
  33. switch(keycode){
  34. case CLEAR: {
  35. clear_oneshot_mods();
  36. clear_mods();
  37. return false;
  38. }
  39. case PANIC: {
  40. clear_oneshot_mods();
  41. clear_mods();
  42. if (get_oneshot_layer() != 0) {
  43. clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
  44. }
  45. layer_move(0);
  46. return false;
  47. }
  48. }
  49. for (int i = 0; i < NUM_NSHOT_STATES; ++i) {
  50. curr_state = &nshot_states[i];
  51. if (keycode == curr_state->trigger) {
  52. if (record->event.pressed) {
  53. // Trigger keydown
  54. if (curr_state->state == os_up_unqueued) {
  55. register_code(curr_state->mod);
  56. }
  57. curr_state->state = os_down_unused;
  58. curr_state->count = 0;
  59. } else {
  60. // Trigger keyup
  61. switch (curr_state->state) {
  62. case os_down_unused:
  63. // If we didn't use the mod while trigger was held, queue it.
  64. curr_state->state = os_up_queued;
  65. break;
  66. case os_down_used:
  67. // If we did use the mod while trigger was held, unregister it.
  68. curr_state->state = os_up_unqueued;
  69. unregister_code(curr_state->mod);
  70. break;
  71. default:
  72. break;
  73. }
  74. }
  75. } else {
  76. if (record->event.pressed) {
  77. if (is_nshot_cancel_key(keycode) && curr_state->state != os_up_unqueued) {
  78. // Cancel oneshot on designated cancel keydown.
  79. curr_state->state = os_up_unqueued;
  80. curr_state->count = 0;
  81. unregister_code(curr_state->mod);
  82. }
  83. } else {
  84. if (!is_nshot_ignored_key(keycode)) {
  85. // On non-ignored keyup, consider the oneshot used.
  86. switch (curr_state->state) {
  87. case os_down_unused:
  88. // The mod key is being held as a normal mod.
  89. curr_state->state = os_down_used;
  90. break;
  91. case os_up_queued:
  92. // The mod key is being used as an n-shot.
  93. // Increment the keys-used count.
  94. curr_state->count = curr_state->count + 1;
  95. // If the n-shot max has been reached, complete the n-shot.
  96. if (curr_state->count == curr_state->max_count) {
  97. curr_state->state = os_up_unqueued;
  98. curr_state->count = 0;
  99. unregister_code(curr_state->mod);
  100. }
  101. break;
  102. default:
  103. break;
  104. }
  105. }
  106. }
  107. }
  108. }
  109. return true;
  110. }
  111. // turn off the nshot/oneshot macros
  112. #undef ONESHOT
  113. #undef NSHOT
  114. #define ONESHOT BLANK
  115. #define NSHOT BLANK
  116. #undef CANCEL_KEY
  117. #undef IGNORE_KEY
  118. #define IGNORE_KEY BLANK
  119. #define CANCEL_KEY A_KEY
  120. bool is_nshot_cancel_key(uint16_t keycode) {
  121. switch (keycode) {
  122. #include "nshot.def"
  123. return true;
  124. default:
  125. return false;
  126. }
  127. }
  128. #undef CANCEL_KEY
  129. #undef IGNORE_KEY
  130. #define CANCEL_KEY BLANK
  131. #define IGNORE_KEY A_KEY
  132. bool is_nshot_ignored_key(uint16_t keycode) {
  133. switch (keycode) {
  134. #include "nshot.def"
  135. return true;
  136. default:
  137. return false;
  138. }
  139. }