sten.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. // 2019, g Heavy Industries
  2. #include QMK_KEYBOARD_H
  3. #include "mousekey.h"
  4. #include "keymap.h"
  5. #include "keymap_steno.h"
  6. // Bitfield representing the current chord
  7. uint32_t cChord = 0;
  8. // See if a given chord is pressed.
  9. // P will return
  10. // PJ will continue processing, removing the found chord
  11. #define P(chord, act) if (cChord == (chord)) { act; return true; }
  12. #define PJ(chord, act) if ((cChord & (chord)) == (chord)) { cChord ^= chord; act; }
  13. // All Steno Codes
  14. // Shift to internal representation
  15. #define STN(n) (1L<<n)
  16. //i.e) S(teno)R(ight)F
  17. enum ORDER {
  18. SFN = 0, SPWR, SST1, SST2, SST3, SST4, SNUM,
  19. SLSU, SLSD, SLT, SLK, SLP, SLW, SLH, SLR, SLA, SLO,
  20. SRE, SRU, SRF, SRR, SRP, SRB, SRL, SRG, SRT, SRS, SRD, SRZ
  21. };
  22. // Break it all out
  23. #define FN STN(SFN)
  24. #define PWR STN(SPWR)
  25. #define ST1 STN(SST1)
  26. #define ST2 STN(SST2)
  27. #define ST3 STN(SST3)
  28. #define ST4 STN(SST4)
  29. #define NUM STN(SNUM) // No distinction between left and right
  30. #define LSU STN(SLSU)
  31. #define LSD STN(SLSD)
  32. #define LFT STN(SLT) // (L)e(F)t (T), preprocessor conflict
  33. #define LK STN(SLK)
  34. #define LP STN(SLP)
  35. #define LW STN(SLW)
  36. #define LH STN(SLH)
  37. #define LR STN(SLR)
  38. #define LA STN(SLA)
  39. #define LO STN(SLO)
  40. #define RE STN(SRE)
  41. #define RU STN(SRU)
  42. #define RF STN(SRF)
  43. #define RR STN(SRR)
  44. #define RP STN(SRP)
  45. #define RB STN(SRB)
  46. #define RL STN(SRL)
  47. #define RG STN(SRG)
  48. #define RT STN(SRT)
  49. #define RS STN(SRS)
  50. #define RD STN(SRD)
  51. #define RZ STN(SRZ)
  52. bool processQwerty(void);
  53. bool processFakeSteno(void);
  54. void clickMouse(uint8_t kc);
  55. void SEND(uint8_t kc);
  56. extern int getKeymapCount(void);
  57. // Mode state
  58. enum MODE { STENO = 0, QWERTY, COMMAND };
  59. enum MODE cMode = STENO;
  60. enum MODE pMode;
  61. bool QWERSTENO = false;
  62. // Command State
  63. #define MAX_CMD_BUF 20
  64. uint8_t CMDBUF[MAX_CMD_BUF];
  65. uint8_t CMDLEN = 0;
  66. // Key Repeat state
  67. bool inChord = false;
  68. uint16_t repTimer = 0;
  69. #define REP_DELAY 300
  70. // Mousekeys state
  71. bool inMouse = false;
  72. int8_t mousePress;
  73. // All processing done at chordUp goes through here
  74. bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) {
  75. // Check for mousekeys, this is release
  76. #ifdef MOUSEKEY_ENABLE
  77. if (inMouse) {
  78. inMouse = false;
  79. mousekey_off(mousePress);
  80. mousekey_send();
  81. }
  82. #endif
  83. // Toggle Serial/QWERTY steno
  84. if (cChord == (PWR | FN | ST1 | ST2)) {
  85. uprintf("Fallback Toggle\n");
  86. QWERSTENO = !QWERSTENO;
  87. goto out;
  88. }
  89. // handle command mode
  90. if (cChord == (PWR | FN | RD | RZ)) {
  91. uprintf("COMMAND Toggle\n");
  92. if (cMode != COMMAND) { // Entering Command Mode
  93. CMDLEN = 0;
  94. pMode = cMode;
  95. cMode = COMMAND;
  96. } else { // Exiting Command Mode
  97. cMode = pMode;
  98. // Press all and release all
  99. for (int i = 0; i < CMDLEN; i++) {
  100. register_code(CMDBUF[i]);
  101. }
  102. clear_keyboard();
  103. }
  104. goto out;
  105. }
  106. // Handle Gaming Toggle,
  107. if (cChord == (PWR | FN | ST2 | ST3) && getKeymapCount() > 1) {
  108. uprintf("Switching to QMK\n");
  109. layer_on(1);
  110. goto out;
  111. }
  112. // Lone FN press, toggle QWERTY
  113. if (cChord == FN) {
  114. (cMode == STENO) ? (cMode = QWERTY) : (cMode = STENO);
  115. goto out;
  116. }
  117. // Check for Plover momentary
  118. if (cMode == QWERTY && (cChord & FN)) {
  119. cChord ^= FN;
  120. goto steno;
  121. }
  122. // Do QWERTY and Momentary QWERTY
  123. if (cMode == QWERTY || (cMode == COMMAND) || (cChord & (FN | PWR))) {
  124. if (cChord & FN) cChord ^= FN;
  125. processQwerty();
  126. goto out;
  127. }
  128. // Fallback NKRO Steno
  129. if (cMode == STENO && QWERSTENO) {
  130. processFakeSteno();
  131. goto out;
  132. }
  133. steno:
  134. // Hey that's a steno chord!
  135. inChord = false;
  136. cChord = 0;
  137. return true;
  138. out:
  139. inChord = false;
  140. clear_keyboard();
  141. cChord = 0;
  142. return false;
  143. }
  144. // Update Chord State
  145. bool process_steno_user(uint16_t keycode, keyrecord_t *record) {
  146. // Everything happens in here when steno keys come in.
  147. // Bail on keyup
  148. if (!record->event.pressed) return true;
  149. // Update key repeat timers
  150. repTimer = timer_read();
  151. inChord = true;
  152. // Switch on the press adding to chord
  153. bool pr = record->event.pressed;
  154. switch (keycode) {
  155. // Mods and stuff
  156. case STN_ST1: pr ? (cChord |= (ST1)): (cChord &= ~(ST1)); break;
  157. case STN_ST2: pr ? (cChord |= (ST2)): (cChord &= ~(ST2)); break;
  158. case STN_ST3: pr ? (cChord |= (ST3)): (cChord &= ~(ST3)); break;
  159. case STN_ST4: pr ? (cChord |= (ST4)): (cChord &= ~(ST4)); break;
  160. case STN_FN: pr ? (cChord |= (FN)) : (cChord &= ~(FN)); break;
  161. case STN_PWR: pr ? (cChord |= (PWR)): (cChord &= ~(PWR)); break;
  162. case STN_N1...STN_N6:
  163. case STN_N7...STN_NC: pr ? (cChord |= (NUM)): (cChord &= ~(NUM)); break;
  164. // All the letter keys
  165. case STN_S1: pr ? (cChord |= (LSU)) : (cChord &= ~(LSU)); break;
  166. case STN_S2: pr ? (cChord |= (LSD)) : (cChord &= ~(LSD)); break;
  167. case STN_TL: pr ? (cChord |= (LFT)) : (cChord &= ~(LFT)); break;
  168. case STN_KL: pr ? (cChord |= (LK)) : (cChord &= ~(LK)); break;
  169. case STN_PL: pr ? (cChord |= (LP)) : (cChord &= ~(LP)); break;
  170. case STN_WL: pr ? (cChord |= (LW)) : (cChord &= ~(LW)); break;
  171. case STN_HL: pr ? (cChord |= (LH)) : (cChord &= ~(LH)); break;
  172. case STN_RL: pr ? (cChord |= (LR)) : (cChord &= ~(LR)); break;
  173. case STN_A: pr ? (cChord |= (LA)) : (cChord &= ~(LA)); break;
  174. case STN_O: pr ? (cChord |= (LO)) : (cChord &= ~(LO)); break;
  175. case STN_E: pr ? (cChord |= (RE)) : (cChord &= ~(RE)); break;
  176. case STN_U: pr ? (cChord |= (RU)) : (cChord &= ~(RU)); break;
  177. case STN_FR: pr ? (cChord |= (RF)) : (cChord &= ~(RF)); break;
  178. case STN_RR: pr ? (cChord |= (RR)) : (cChord &= ~(RR)); break;
  179. case STN_PR: pr ? (cChord |= (RP)) : (cChord &= ~(RP)); break;
  180. case STN_BR: pr ? (cChord |= (RB)) : (cChord &= ~(RB)); break;
  181. case STN_LR: pr ? (cChord |= (RL)) : (cChord &= ~(RL)); break;
  182. case STN_GR: pr ? (cChord |= (RG)) : (cChord &= ~(RG)); break;
  183. case STN_TR: pr ? (cChord |= (RT)) : (cChord &= ~(RT)); break;
  184. case STN_SR: pr ? (cChord |= (RS)) : (cChord &= ~(RS)); break;
  185. case STN_DR: pr ? (cChord |= (RD)) : (cChord &= ~(RD)); break;
  186. case STN_ZR: pr ? (cChord |= (RZ)) : (cChord &= ~(RZ)); break;
  187. }
  188. // Check for key repeat in QWERTY mode
  189. return true;
  190. }
  191. void matrix_scan_user(void) {
  192. // We abuse this for early sending of key
  193. // Key repeat only on QWER/SYMB layers
  194. if (cMode != QWERTY) return;
  195. // Check timers
  196. if (timer_elapsed(repTimer) > REP_DELAY) {
  197. // Process Key for report
  198. processQwerty();
  199. // Send report to host
  200. send_keyboard_report();
  201. repTimer = timer_read();
  202. }
  203. };
  204. // Helpers
  205. bool processFakeSteno(void) {
  206. PJ( LSU, SEND(KC_Q););
  207. PJ( LSD, SEND(KC_A););
  208. PJ( LFT, SEND(KC_W););
  209. PJ( LP, SEND(KC_E););
  210. PJ( LH, SEND(KC_R););
  211. PJ( LK, SEND(KC_S););
  212. PJ( LW, SEND(KC_D););
  213. PJ( LR, SEND(KC_F););
  214. PJ( ST1, SEND(KC_T););
  215. PJ( ST2, SEND(KC_G););
  216. PJ( LA, SEND(KC_C););
  217. PJ( LO, SEND(KC_V););
  218. PJ( RE, SEND(KC_N););
  219. PJ( RU, SEND(KC_M););
  220. PJ( ST3, SEND(KC_Y););
  221. PJ( ST4, SEND(KC_H););
  222. PJ( RF, SEND(KC_U););
  223. PJ( RP, SEND(KC_I););
  224. PJ( RL, SEND(KC_O););
  225. PJ( RT, SEND(KC_P););
  226. PJ( RD, SEND(KC_LBRC););
  227. PJ( RR, SEND(KC_J););
  228. PJ( RB, SEND(KC_K););
  229. PJ( RG, SEND(KC_L););
  230. PJ( RS, SEND(KC_SCLN););
  231. PJ( RZ, SEND(KC_COMM););
  232. PJ( NUM, SEND(KC_1););
  233. return false;
  234. }
  235. void clickMouse(uint8_t kc) {
  236. #ifdef MOUSEKEY_ENABLE
  237. mousekey_on(kc);
  238. mousekey_send();
  239. // Store state for later use
  240. inMouse = true;
  241. mousePress = kc;
  242. #endif
  243. }
  244. void SEND(uint8_t kc) {
  245. // Send Keycode, Does not work for Quantum Codes
  246. if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
  247. uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
  248. CMDBUF[CMDLEN] = kc;
  249. CMDLEN++;
  250. }
  251. if (cMode != COMMAND) register_code(kc);
  252. return;
  253. }