process_key_lock.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. // Locked key state. This is an array of 256 bits, one for each of the standard keys supported qmk.
  47. uint64_t key_state[4] = { 0x0, 0x0, 0x0, 0x0 };
  48. bool watching = false;
  49. bool process_key_lock(uint16_t keycode, keyrecord_t *record) {
  50. // We start by categorizing the keypress event. In the event of a down
  51. // event, there are several possibilities:
  52. // 1. The key is not being locked, and we are not watching for new keys.
  53. // In this case, we bail immediately. This is the common case for down events.
  54. // 2. The key was locked, and we need to unlock it. In this case, we will
  55. // reset the state in our map and return false. When the user releases the
  56. // key, the up event will no longer be masked and the OS will observe the
  57. // released key.
  58. // 3. KC_LOCK was just pressed. In this case, we set up the state machine
  59. // to watch for the next key down event, and finish processing
  60. // 4. The keycode is below 0xFF, and we are watching for new keys. In this case,
  61. // we will send the key down event to the os, and set the key_state for that
  62. // key to mask the up event.
  63. // 5. The keycode is above 0xFF, and we're wathing for new keys. In this case,
  64. // the user pressed a key that we cannot "lock", as it's a series of keys,
  65. // or a macro invocation, or a layer transition, or a custom-defined key, or
  66. // or some other arbitrary code. In this case, we bail immediately, reset
  67. // our watch state, and return true.
  68. //
  69. // In the event of an up event, there are these possibilities:
  70. // 1. The key is not being locked. In this case, we return true and bail
  71. // immediately. This is the common case.
  72. // 2. The key is being locked. In this case, we will mask the up event
  73. // by returning false, so the OS never sees that the key was released
  74. // until the user pressed the key again.
  75. if (record->event.pressed) {
  76. // Non-standard keycode, reset and return
  77. if (!(IS_STANDARD_KEYCODE(keycode) || keycode == KC_LOCK)) {
  78. watching = false;
  79. return true;
  80. }
  81. // If we're already watching, turn off the watch.
  82. if (keycode == KC_LOCK) {
  83. watching = !watching;
  84. return false;
  85. }
  86. if (IS_STANDARD_KEYCODE(keycode)) {
  87. // We check watching first. This is so that in the following scenario, we continue to
  88. // hold the key: KC_LOCK, KC_F, KC_LOCK, KC_F
  89. // If we checked in reverse order, we'd end up holding the key pressed after the second
  90. // KC_F press is registered, when the user likely meant to hold F
  91. if (watching) {
  92. watching = false;
  93. SET_KEY_STATE(keycode);
  94. // Let the standard keymap send the keycode down event. The up event will be masked.
  95. return true;
  96. }
  97. if (KEY_STATE(keycode)) {
  98. UNSET_KEY_STATE(keycode);
  99. // The key is already held, stop this process. The up event will be sent when the user
  100. // releases the key.
  101. return false;
  102. }
  103. }
  104. // Either the key isn't a standard key, or we need to send the down event. Continue standard
  105. // processing
  106. return true;
  107. } else {
  108. // Stop processing if it's a standard key and we're masking up.
  109. return !(IS_STANDARD_KEYCODE(keycode) && KEY_STATE(keycode));
  110. }
  111. }