process_key_lock.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* Copyright 2017 Fredric Silberberg
  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. #include "inttypes.h"
  17. #include "stdint.h"
  18. #include "process_key_lock.h"
  19. #define SHIFT(shift) (((uint64_t)1) << (shift))
  20. #define GET_KEY_ARRAY(code) (((code) < 0x40) ? key_state[0] : \
  21. ((code) < 0x80) ? key_state[1] : \
  22. ((code) < 0xC0) ? key_state[2] : key_state[3])
  23. #define GET_CODE_INDEX(code) (((code) < 0x40) ? (code) : \
  24. ((code) < 0x80) ? (code) - 0x40 : \
  25. ((code) < 0xC0) ? (code) - 0x80 : (code) - 0xC0)
  26. #define KEY_STATE(code) (GET_KEY_ARRAY(code) & SHIFT(GET_CODE_INDEX(code))) == SHIFT(GET_CODE_INDEX(code))
  27. #define SET_KEY_ARRAY_STATE(code, val) do { \
  28. switch (code) { \
  29. case 0x00 ... 0x3F: \
  30. key_state[0] = (val); \
  31. break; \
  32. case 0x40 ... 0x7F: \
  33. key_state[1] = (val); \
  34. break; \
  35. case 0x80 ... 0xBF: \
  36. key_state[2] = (val); \
  37. break; \
  38. case 0xC0 ... 0xFF: \
  39. key_state[3] = (val); \
  40. break; \
  41. } \
  42. } while(0)
  43. #define SET_KEY_STATE(code) SET_KEY_ARRAY_STATE(code, (GET_KEY_ARRAY(code) | SHIFT(GET_CODE_INDEX(code))))
  44. #define UNSET_KEY_STATE(code) SET_KEY_ARRAY_STATE(code, (GET_KEY_ARRAY(code)) & ~(SHIFT(GET_CODE_INDEX(code))))
  45. #define IS_STANDARD_KEYCODE(code) ((code) <= 0xFF)
  46. #define print_hex64(num) do { print_hex32((num & 0xFFFFFFFF00000000) >> 32); print_hex32(num & 0x00000000FFFFFFFF); } while (0)
  47. // Locked key state. This is an array of 256 bits, one for each of the standard keys supported qmk.
  48. uint64_t key_state[4] = { 0x0, 0x0, 0x0, 0x0 };
  49. bool watching = false;
  50. bool process_key_lock(uint16_t keycode, keyrecord_t *record) {
  51. // We start by categorizing the keypress event. In the event of a down
  52. // event, there are several possibilities:
  53. // 1. The key is not being locked, and we are not watching for new keys.
  54. // In this case, we bail immediately. This is the common case for down events.
  55. // 2. The key was locked, and we need to unlock it. In this case, we will
  56. // reset the state in our map and return false. When the user releases the
  57. // key, the up event will no longer be masked and the OS will observe the
  58. // released key.
  59. // 3. KC_LOCK was just pressed. In this case, we set up the state machine
  60. // to watch for the next key down event, and finish processing
  61. // 4. The keycode is below 0xFF, and we are watching for new keys. In this case,
  62. // we will send the key down event to the os, and set the key_state for that
  63. // key to mask the up event.
  64. // 5. The keycode is above 0xFF, and we're wathing for new keys. In this case,
  65. // the user pressed a key that we cannot "lock", as it's a series of keys,
  66. // or a macro invocation, or a layer transition, or a custom-defined key, or
  67. // or some other arbitrary code. In this case, we bail immediately, reset
  68. // our watch state, and return true.
  69. //
  70. // In the event of an up event, there are these possibilities:
  71. // 1. The key is not being locked. In this case, we return true and bail
  72. // immediately. This is the common case.
  73. // 2. The key is being locked. In this case, we will mask the up event
  74. // by returning false, so the OS never sees that the key was released
  75. // until the user pressed the key again.
  76. if (record->event.pressed) {
  77. // Non-standard keycode, reset and return
  78. if (!(IS_STANDARD_KEYCODE(keycode) || keycode == KC_LOCK)) {
  79. watching = false;
  80. return true;
  81. }
  82. // If we're already watching, turn off the watch.
  83. if (keycode == KC_LOCK) {
  84. watching = !watching;
  85. return false;
  86. }
  87. if (IS_STANDARD_KEYCODE(keycode)) {
  88. // We check watching first. This is so that in the following scenario, we continue to
  89. // hold the key: KC_LOCK, KC_F, KC_LOCK, KC_F
  90. // If we checked in reverse order, we'd end up holding the key pressed after the second
  91. // KC_F press is registered, when the user likely meant to hold F
  92. if (watching) {
  93. watching = false;
  94. SET_KEY_STATE(keycode);
  95. // Let the standard keymap send the keycode down event. The up event will be masked.
  96. return true;
  97. }
  98. if (KEY_STATE(keycode)) {
  99. UNSET_KEY_STATE(keycode);
  100. // The key is already held, stop this process. The up event will be sent when the user
  101. // releases the key.
  102. return false;
  103. }
  104. }
  105. // Either the key isn't a standard key, or we need to send the down event. Continue standard
  106. // processing
  107. return true;
  108. } else {
  109. // Stop processing if it's a standard key and we're masking up.
  110. return !(IS_STANDARD_KEYCODE(keycode) && KEY_STATE(keycode));
  111. }
  112. }