logo

qmk_firmware

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

engine.c (12424B)


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