logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

engine.c (11991B)


  1. /* This is a stripped down version of the Georgi engine meant for use with
  2. * Ginni. As such serial-Steno features are disabled, chords are 16bits and
  3. * crap is removed where possible
  4. *
  5. * Do not use this on anything other then Ginny if you want to be sane
  6. */
  7. #include "engine.h"
  8. // Chord state
  9. C_SIZE cChord = 0; // Current Chord
  10. int chordIndex = 0; // Keys in previousachord
  11. C_SIZE pressed = 0; // number of held keys
  12. C_SIZE chordState[32]; // Full Chord history
  13. #define QWERBUF 24 // Size of chords to buffer for output
  14. bool repeatFlag = false; // Should we repeat?
  15. C_SIZE pChord = 0; // Previous Chord
  16. C_SIZE stickyBits = 0; // Or'd with every incoming press
  17. int pChordIndex = 0; // Keys in previousachord
  18. C_SIZE pChordState[32]; // Previous chord sate
  19. // Key Dicts
  20. extern const struct keyEntry keyDict[];
  21. extern const struct comboEntry cmbDict[];
  22. extern const struct funcEntry funDict[];
  23. extern const struct stringEntry strDict[];
  24. extern const struct specialEntry spcDict[];
  25. extern size_t specialLen;
  26. extern size_t stringLen;
  27. extern size_t funcsLen;
  28. extern size_t keyLen;
  29. extern size_t comboLen;
  30. // Mode state
  31. enum MODE { STENO = 0, QWERTY, COMMAND };
  32. enum MODE pMode;
  33. enum MODE cMode = QWERTY;
  34. // Command State
  35. #define MAX_CMD_BUF 20
  36. uint8_t CMDLEN = 0;
  37. uint8_t CMDBUF[MAX_CMD_BUF];
  38. // Key Repeat state
  39. bool inChord = false;
  40. bool repEngaged = false;
  41. uint16_t repTimer = 0;
  42. #define REP_INIT_DELAY 750
  43. #define REP_DELAY 25
  44. // Mousekeys state
  45. bool inMouse = false;
  46. int8_t mousePress;
  47. // All processing done at chordUp goes through here
  48. void processKeysUp(void) {
  49. // Check for mousekeys, this is release
  50. #ifdef MOUSEKEY_ENABLE
  51. if (inMouse) {
  52. inMouse = false;
  53. mousekey_off(mousePress);
  54. mousekey_send();
  55. }
  56. #endif
  57. // handle command mode
  58. if (cChord == COMMAND_MODE) {
  59. #ifndef NO_DEBUG
  60. uprintf("COMMAND Toggle\n");
  61. #endif
  62. if (cMode != COMMAND) { // Entering Command Mode
  63. CMDLEN = 0;
  64. pMode = cMode;
  65. cMode = COMMAND;
  66. } else { // Exiting Command Mode
  67. cMode = pMode;
  68. // Press all and release all
  69. for (int i = 0; i < CMDLEN; i++) {
  70. register_code(CMDBUF[i]);
  71. }
  72. clear_keyboard();
  73. }
  74. }
  75. // Process and reset state
  76. processChord();
  77. cChord = pressed;
  78. inChord = false;
  79. chordIndex = 0;
  80. clear_keyboard();
  81. repEngaged = false;
  82. for (int i = 0; i < 32; i++) chordState[i] = 0xFFFF;
  83. }
  84. // Update Chord State
  85. bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
  86. // Everything happens in here when steno keys come in.
  87. // Bail on keyup
  88. // Update key repeat timers
  89. repTimer = timer_read();
  90. bool pr = record->event.pressed;
  91. // Switch on the press adding to chord
  92. switch (keycode) {
  93. ENGINE_CONFIG
  94. default:
  95. return true;
  96. }
  97. // Handle any postprocessing
  98. // All keys up, send it!
  99. if (inChord && !pr && (pressed & IN_CHORD_MASK) == 0) {
  100. processKeysUp();
  101. return false;
  102. }
  103. if (pressed == 0 && !pr) {
  104. processKeysUp();
  105. return false;
  106. }
  107. cChord |= pressed;
  108. cChord = process_engine_post(cChord, keycode, record);
  109. inChord = (cChord & IN_CHORD_MASK) != 0;
  110. // Store previous state for fastQWER
  111. if (pr) {
  112. chordState[chordIndex] = cChord;
  113. chordIndex++;
  114. }
  115. #ifndef NO_DEBUG
  116. uprintf("Chord: %u\n", cChord);
  117. #endif
  118. return false;
  119. }
  120. void matrix_scan_user(void) {
  121. // We abuse this for early sending of key
  122. // Key repeat only on QWER/SYMB layers
  123. if (cMode != QWERTY || !inChord) return;
  124. // Check timers
  125. #ifndef NO_HOLD
  126. if (!repEngaged && timer_elapsed(repTimer) > REP_INIT_DELAY) {
  127. // Process Key for report
  128. processChord();
  129. // Send report to host
  130. send_keyboard_report();
  131. repEngaged = true;
  132. }
  133. #endif
  134. };
  135. // Try and match cChord
  136. C_SIZE mapKeys(C_SIZE chord, bool lookup) {
  137. lookup = lookup || repEngaged;
  138. #ifndef NO_DEBUG
  139. if (!lookup) uprint("SENT!\n");
  140. #endif
  141. // Single key chords
  142. for (int i = 0; i < keyLen; i++) {
  143. if (keyDict[i].chord == chord) {
  144. if (!lookup) SEND(keyDict[i].key);
  145. return chord;
  146. }
  147. }
  148. // strings
  149. for (int i = 0; i < stringLen; i++) {
  150. struct stringEntry fromPgm;
  151. memcpy_P(&fromPgm, &strDict[i], sizeof(stringEntry_t));
  152. if (fromPgm.chord == chord) {
  153. if (!lookup) {
  154. if (get_mods() & (MOD_LSFT | MOD_RSFT)) {
  155. set_mods(get_mods() & ~(MOD_LSFT | MOD_RSFT));
  156. set_oneshot_mods(MOD_LSFT);
  157. }
  158. send_string_P((PGM_P)(fromPgm.str));
  159. }
  160. return chord;
  161. }
  162. }
  163. // combos
  164. for (int i = 0; i < comboLen; i++) {
  165. struct comboEntry fromPgm;
  166. memcpy_P(&fromPgm, &cmbDict[i], sizeof(comboEntry_t));
  167. if (fromPgm.chord == chord) {
  168. #ifndef NO_DEBUG
  169. uprintf("%d found combo\n", i);
  170. #endif
  171. if (!lookup) {
  172. uint8_t comboKeys[COMBO_MAX];
  173. memcpy_P(&comboKeys, fromPgm.keys, sizeof(uint8_t) * COMBO_MAX);
  174. for (int j = 0; j < COMBO_MAX; j++)
  175. #ifndef NO_DEBUG
  176. uprintf("Combo [%u]: %u\n", j, comboKeys[j]);
  177. #endif
  178. for (int j = 0; (j < COMBO_MAX) && (comboKeys[j] != COMBO_END); j++) {
  179. #ifndef NO_DEBUG
  180. uprintf("Combo [%u]: %u\n", j, comboKeys[j]);
  181. #endif
  182. SEND(comboKeys[j]);
  183. }
  184. }
  185. return chord;
  186. }
  187. }
  188. // functions
  189. for (int i = 0; i < funcsLen; i++) {
  190. if (funDict[i].chord == chord) {
  191. if (!lookup) funDict[i].act();
  192. return chord;
  193. }
  194. }
  195. // Special handling
  196. for (int i = 0; i < specialLen; i++) {
  197. if (spcDict[i].chord == chord) {
  198. if (!lookup) {
  199. uint16_t arg = spcDict[i].arg;
  200. switch (spcDict[i].action) {
  201. case SPEC_STICKY:
  202. SET_STICKY(arg);
  203. break;
  204. case SPEC_REPEAT:
  205. REPEAT();
  206. break;
  207. case SPEC_CLICK:
  208. CLICK_MOUSE((uint8_t)arg);
  209. break;
  210. case SPEC_SWITCH:
  211. SWITCH_LAYER(arg);
  212. break;
  213. default:
  214. SEND_STRING("Invalid Special in Keymap");
  215. }
  216. }
  217. return chord;
  218. }
  219. }
  220. if ((chord & IN_CHORD_MASK) && (chord & IN_CHORD_MASK) != chord && mapKeys((chord & IN_CHORD_MASK), true) == (chord & IN_CHORD_MASK)) {
  221. #ifndef NO_DEBUG
  222. uprintf("Try with ignore mask:%u\n", (chord & IN_CHORD_MASK));
  223. #endif
  224. mapKeys((chord & ~IN_CHORD_MASK), lookup);
  225. mapKeys((chord & IN_CHORD_MASK), lookup);
  226. return chord;
  227. }
  228. #ifndef NO_DEBUG
  229. uprintf("Reached end\n");
  230. #endif
  231. return 0;
  232. }
  233. // Traverse the chord history to a given point
  234. // Returns the mask to use
  235. void processChord(void) {
  236. // Save the clean chord state
  237. C_SIZE savedChord = cChord;
  238. // Apply Stick Bits if needed
  239. if (stickyBits != 0) {
  240. cChord |= stickyBits;
  241. for (int i = 0; i <= chordIndex; i++) chordState[i] |= stickyBits;
  242. }
  243. // First we test if a whole chord was passsed
  244. // If so we just run it handling repeat logic
  245. if (mapKeys(cChord, true) == cChord) {
  246. mapKeys(cChord, false);
  247. // Repeat logic
  248. if (repeatFlag) {
  249. #ifndef NO_DEBUG
  250. uprintf("repeating?\n");
  251. #endif
  252. restoreState();
  253. repeatFlag = false;
  254. processChord();
  255. } else {
  256. saveState(cChord);
  257. }
  258. return;
  259. }
  260. C_SIZE next = process_chord_getnext(cChord);
  261. if (next && next != cChord) {
  262. #ifndef NO_DEBUG
  263. uprintf("Trying next candidate: %u\n", next);
  264. #endif
  265. if (mapKeys(next, true) == next) {
  266. mapKeys(next, false);
  267. // Repeat logic
  268. if (repeatFlag) {
  269. #ifndef NO_DEBUG
  270. uprintf("repeating?\n");
  271. #endif
  272. restoreState();
  273. repeatFlag = false;
  274. processChord();
  275. } else {
  276. saveState(cChord);
  277. }
  278. return;
  279. }
  280. }
  281. #ifndef NO_DEBUG
  282. uprintf("made it past the maw\n");
  283. #endif
  284. // Iterate through chord picking out the individual
  285. // and longest chords
  286. C_SIZE bufChords[QWERBUF];
  287. int bufLen = 0;
  288. C_SIZE mask = 0;
  289. // We iterate over it multiple times to catch the longest
  290. // chord. Then that gets addded to the mask and re run.
  291. while (savedChord != mask) {
  292. C_SIZE test = 0;
  293. C_SIZE longestChord = 0;
  294. for (int i = 0; i <= chordIndex; i++) {
  295. cChord = chordState[i] & ~mask;
  296. if (cChord == 0) continue;
  297. test = mapKeys(cChord, true);
  298. if (test != 0) {
  299. longestChord = test;
  300. }
  301. }
  302. mask |= longestChord;
  303. bufChords[bufLen] = longestChord;
  304. bufLen++;
  305. // That's a loop of sorts, halt processing
  306. if (bufLen >= QWERBUF) {
  307. #ifndef NO_DEBUG
  308. uprintf("looped. exiting");
  309. #endif
  310. return;
  311. }
  312. }
  313. // Now that the buffer is populated, we run it
  314. for (int i = 0; i < bufLen; i++) {
  315. cChord = bufChords[i];
  316. #ifndef NO_DEBUG
  317. uprintf("sending: %u\n", cChord);
  318. #endif
  319. mapKeys(cChord, false);
  320. }
  321. // Save state in case of repeat
  322. if (!repeatFlag) {
  323. saveState(savedChord);
  324. }
  325. // Restore cChord for held repeat
  326. cChord = savedChord;
  327. return;
  328. }
  329. void saveState(C_SIZE cleanChord) {
  330. pChord = cleanChord;
  331. pChordIndex = chordIndex;
  332. for (int i = 0; i < 32; i++) pChordState[i] = chordState[i];
  333. }
  334. void restoreState(void) {
  335. cChord = pChord;
  336. chordIndex = pChordIndex;
  337. for (int i = 0; i < 32; i++) chordState[i] = pChordState[i];
  338. }
  339. // Macros for calling from keymap.c
  340. void SEND(uint8_t kc) {
  341. // Send Keycode, Does not work for Quantum Codes
  342. if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
  343. #ifndef NO_DEBUG
  344. uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
  345. #endif
  346. CMDBUF[CMDLEN] = kc;
  347. CMDLEN++;
  348. }
  349. if (cMode != COMMAND) register_code(kc);
  350. return;
  351. }
  352. void REPEAT(void) {
  353. if (cMode != QWERTY) return;
  354. repeatFlag = true;
  355. return;
  356. }
  357. void SET_STICKY(C_SIZE stick) {
  358. stickyBits ^= stick;
  359. return;
  360. }
  361. void CLICK_MOUSE(uint8_t kc) {
  362. #ifdef MOUSEKEY_ENABLE
  363. mousekey_on(kc);
  364. mousekey_send();
  365. // Store state for later use
  366. inMouse = true;
  367. mousePress = kc;
  368. #endif
  369. }
  370. void SWITCH_LAYER(int layer) {
  371. #ifndef NO_ACTION_LAYER
  372. if (keymapsCount >= layer) layer_on(layer);
  373. #endif
  374. }
  375. uint8_t bitpop_v(C_SIZE val) {
  376. #if C_SIZE == uint8_t
  377. return bitpop(val);
  378. #elif C_SIZE == uint16_t
  379. return bitpop16(val);
  380. #elif C_SIZE == uint32_t
  381. return bitpop32(val);
  382. #elif C_SIZE == uint64_t
  383. uint8_t n = 0;
  384. if (bits >> 32) {
  385. bits >>= 32;
  386. n += 32;
  387. }
  388. if (bits >> 16) {
  389. bits >>= 16;
  390. n += 16;
  391. }
  392. if (bits >> 8) {
  393. bits >>= 8;
  394. n += 8;
  395. }
  396. if (bits >> 4) {
  397. bits >>= 4;
  398. n += 4;
  399. }
  400. if (bits >> 2) {
  401. bits >>= 2;
  402. n += 2;
  403. }
  404. if (bits >> 1) {
  405. bits >>= 1;
  406. n += 1;
  407. }
  408. return n;
  409. #else
  410. # error unsupported C_SIZE
  411. #endif
  412. }
  413. __attribute__((weak)) C_SIZE process_engine_post(C_SIZE cur_chord, uint16_t keycode, keyrecord_t *record) { return cur_chord; }