]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/georgi/sten.c
[Keyboard] Georgi FW updates (#5609)
[qmk_firmware.git] / keyboards / georgi / sten.c
1 #include "sten.h"
2
3 // Chord state
4 uint32_t cChord                 = 0;            // Current Chord
5 int              chordIndex     = 0;            // Keys in previousachord
6 int32_t  chordState[32];                        // Full Chord history
7 #define  QWERBUF                24                      // Size of chords to buffer for output
8
9 bool     repeatFlag     = false;        // Should we repeat?
10 uint32_t pChord                 = 0;            // Previous Chord
11 int              pChordIndex    = 0;            // Keys in previousachord
12 uint32_t pChordState[32];                       // Previous chord sate 
13 uint32_t stickyBits = 0;                        // Or'd with every incoming press
14
15 // Mode state
16 enum MODE { STENO = 0, QWERTY, COMMAND };
17 enum MODE pMode;
18 bool QWERSTENO = false;
19 #ifdef ONLYQWERTY
20 enum MODE cMode = QWERTY;
21 #else
22 enum MODE cMode = STENO;
23 #endif
24
25 // Command State
26 #define MAX_CMD_BUF   20
27 uint8_t  CMDLEN         = 0;
28 uint8_t  CMDBUF[MAX_CMD_BUF];
29
30 // Key Repeat state
31 bool     inChord                = false;
32 bool     repEngaged     = false;
33 uint16_t repTimer               = 0;
34 #define  REP_INIT_DELAY 750
35 #define  REP_DELAY              25
36
37 // Mousekeys state
38 bool    inMouse                 = false;
39 int8_t  mousePress;
40
41 // All processing done at chordUp goes through here
42 bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { 
43         // Check for mousekeys, this is release
44 #ifdef MOUSEKEY_ENABLE
45         if (inMouse) {
46                 inMouse = false;
47                 mousekey_off(mousePress);
48                 mousekey_send();
49         }
50 #endif
51
52         // Toggle Serial/QWERTY steno
53         if (cChord == (PWR | FN | ST1 | ST2)) {
54 #ifndef NO_DEBUG
55                 uprintf("Fallback Toggle\n");
56 #endif
57                 QWERSTENO = !QWERSTENO;
58                 
59                 goto out;
60         }
61
62         // handle command mode
63         if (cChord == (PWR | FN | RD | RZ)) {
64 #ifndef NO_DEBUG
65                 uprintf("COMMAND Toggle\n");
66 #endif
67                 if (cMode != COMMAND) {   // Entering Command Mode
68                         CMDLEN = 0;
69                         pMode = cMode;
70                         cMode = COMMAND;
71                 } else {                  // Exiting Command Mode
72                         cMode = pMode;
73
74                         // Press all and release all
75                         for (int i = 0; i < CMDLEN; i++) {
76                                 register_code(CMDBUF[i]);
77                         }
78                         clear_keyboard();
79                 }
80
81                 goto out;
82         }
83
84         // Handle Gaming Toggle,
85         if (cChord == (PWR | FN | ST4 | ST3) && keymapsCount > 1) {
86 #ifndef NO_DEBUG
87                 uprintf("Switching to QMK\n");
88 #endif
89                 layer_on(1);
90                 goto out;
91         }
92
93         // Lone FN press, toggle QWERTY
94 #ifndef ONLYQWERTY
95         if (cChord == FN) {
96                 (cMode == STENO) ? (cMode = QWERTY) : (cMode = STENO);
97                 goto out;
98         }
99 #endif
100
101         // Check for Plover momentary
102         if (cMode == QWERTY && (cChord & FN)) {
103                 cChord ^= FN;
104                 goto steno;
105         }
106
107         // Do QWERTY and Momentary QWERTY
108         if (cMode == QWERTY || (cMode == COMMAND) || (cChord & (FN | PWR))) {
109                 processChord(false);
110                 goto out;
111         }
112
113         // Fallback NKRO Steno
114         if (cMode == STENO && QWERSTENO) {
115                 processChord(true);
116                 goto out;
117         }
118
119 steno:
120         // Hey that's a steno chord!
121         inChord = false;
122         chordIndex = 0;
123         cChord = 0;
124         return true; 
125
126 out:
127         cChord = 0;
128         inChord = false;
129         chordIndex = 0;
130         clear_keyboard();
131         repEngaged  = false;
132         for (int i = 0; i < 32; i++)
133                 chordState[i] = 0xFFFF;
134
135         return false;
136 }
137
138 // Update Chord State 
139 bool process_steno_user(uint16_t keycode, keyrecord_t *record) { 
140         // Everything happens in here when steno keys come in.
141         // Bail on keyup
142         if (!record->event.pressed) return true;
143
144         // Update key repeat timers
145         repTimer = timer_read();
146         inChord  = true;
147
148         // Switch on the press adding to chord
149         bool pr = record->event.pressed;
150         switch (keycode) {
151                         // Mods and stuff
152                         case STN_ST1:                   pr ? (cChord |= (ST1)): (cChord &= ~(ST1)); break;
153                         case STN_ST2:                   pr ? (cChord |= (ST2)): (cChord &= ~(ST2)); break;
154                         case STN_ST3:                   pr ? (cChord |= (ST3)): (cChord &= ~(ST3)); break;
155                         case STN_ST4:                   pr ? (cChord |= (ST4)): (cChord &= ~(ST4)); break;
156                         case STN_FN:                    pr ? (cChord |= (FN)) : (cChord &= ~(FN)); break;
157                         case STN_PWR:                   pr ? (cChord |= (PWR)): (cChord &= ~(PWR)); break;
158                         case STN_N1...STN_N6:   pr ? (cChord |= (LNO)): (cChord &= ~(LNO)); break;
159                         case STN_N7...STN_NC:   pr ? (cChord |= (RNO)): (cChord &= ~(RNO)); break;
160
161                         // All the letter keys
162                         case STN_S1:                    pr ? (cChord |= (LSU)) : (cChord &= ~(LSU));  break;
163                         case STN_S2:                    pr ? (cChord |= (LSD)) : (cChord &= ~(LSD));  break;
164                         case STN_TL:                    pr ? (cChord |= (LFT)) : (cChord &= ~(LFT)); break;
165                         case STN_KL:                    pr ? (cChord |= (LK)) : (cChord &= ~(LK)); break;
166                         case STN_PL:                    pr ? (cChord |= (LP)) : (cChord &= ~(LP)); break;
167                         case STN_WL:                    pr ? (cChord |= (LW)) : (cChord &= ~(LW)); break;
168                         case STN_HL:                    pr ? (cChord |= (LH)) : (cChord &= ~(LH)); break;
169                         case STN_RL:                    pr ? (cChord |= (LR)) : (cChord &= ~(LR)); break;
170                         case STN_A:                             pr ? (cChord |= (LA)) : (cChord &= ~(LA)); break;
171                         case STN_O:                             pr ? (cChord |= (LO)) : (cChord &= ~(LO)); break;
172                         case STN_E:                             pr ? (cChord |= (RE)) : (cChord &= ~(RE)); break;
173                         case STN_U:                             pr ? (cChord |= (RU)) : (cChord &= ~(RU)); break;
174                         case STN_FR:                    pr ? (cChord |= (RF)) : (cChord &= ~(RF)); break;
175                         case STN_RR:                    pr ? (cChord |= (RR)) : (cChord &= ~(RR)); break;
176                         case STN_PR:                    pr ? (cChord |= (RP)) : (cChord &= ~(RP)); break;
177                         case STN_BR:                    pr ? (cChord |= (RB)) : (cChord &= ~(RB)); break;
178                         case STN_LR:                    pr ? (cChord |= (RL)) : (cChord &= ~(RL)); break;
179                         case STN_GR:                    pr ? (cChord |= (RG)) : (cChord &= ~(RG)); break;
180                         case STN_TR:                    pr ? (cChord |= (RT)) : (cChord &= ~(RT)); break;
181                         case STN_SR:                    pr ? (cChord |= (RS)) : (cChord &= ~(RS)); break;
182                         case STN_DR:                    pr ? (cChord |= (RD)) : (cChord &= ~(RD)); break;
183                         case STN_ZR:                    pr ? (cChord |= (RZ)) : (cChord &= ~(RZ)); break;
184         }
185
186         // Store previous state for fastQWER
187         if (pr) {
188                 chordState[chordIndex] = cChord; 
189                 chordIndex++;
190         }
191
192         return true; 
193 }
194 void matrix_scan_user(void) {
195         // We abuse this for early sending of key
196         // Key repeat only on QWER/SYMB layers
197         if (cMode != QWERTY || !inChord) return;
198
199         // Check timers
200 #ifndef NO_REPEAT
201         if (repEngaged && timer_elapsed(repTimer) > REP_DELAY) {
202                 // Process Key for report
203                 processChord(false);
204
205                 // Send report to host
206                 send_keyboard_report();
207                 clear_keyboard();
208                 repTimer = timer_read();
209         }
210
211         if (!repEngaged && timer_elapsed(repTimer) > REP_INIT_DELAY) {
212                 repEngaged = true;
213         }
214 #endif
215 };
216
217 // For Plover NKRO
218 uint32_t processFakeSteno(bool lookup) { 
219         P( LSU,                         SEND(KC_Q););
220         P( LSD,                         SEND(KC_A););
221         P( LFT,                         SEND(KC_W););
222         P( LP,                          SEND(KC_E););
223         P( LH,                          SEND(KC_R););
224         P( LK,                          SEND(KC_S););
225         P( LW,                          SEND(KC_D););
226         P( LR,                          SEND(KC_F););
227         P( ST1,                         SEND(KC_T););
228         P( ST2,                         SEND(KC_G););
229         P( LA,                          SEND(KC_C););
230         P( LO,                          SEND(KC_V););
231         P( RE,                          SEND(KC_N););
232         P( RU,                          SEND(KC_M););
233         P( ST3,                         SEND(KC_Y););
234         P( ST4,                         SEND(KC_H););
235         P( RF,                          SEND(KC_U););
236         P( RP,                          SEND(KC_I););
237         P( RL,                          SEND(KC_O););
238         P( RT,                          SEND(KC_P););
239         P( RD,                          SEND(KC_LBRC););
240         P( RR,                          SEND(KC_J););
241         P( RB,                          SEND(KC_K););
242         P( RG,                          SEND(KC_L););
243         P( RS,                          SEND(KC_SCLN););
244         P( RZ,                          SEND(KC_COMM););
245         P( LNO,                         SEND(KC_1););
246         P( RNO,                         SEND(KC_1););
247
248         return 0;
249 }
250
251 // Traverse the chord history to a given point
252 // Returns the mask to use
253 void processChord(bool useFakeSteno) {
254         // Save the clean chord state
255         uint32_t savedChord = cChord;
256
257         // Apply Stick Bits if needed
258         if (stickyBits != 0) {
259                 cChord |= stickyBits;
260                 for (int i = 0; i <= chordIndex; i++)
261                         chordState[i] |= stickyBits;
262         }
263
264         // Strip FN
265         if (cChord & FN) cChord ^= FN;
266
267         // First we test if a whole chord was passsed
268         // If so we just run it handling repeat logic
269         if (useFakeSteno && processFakeSteno(true) == cChord) {
270                 processFakeSteno(false);
271                 return;
272         } else if (processQwerty(true) == cChord) {
273                 processQwerty(false);
274                 // Repeat logic
275                 if (repeatFlag) {
276                         restoreState();
277                         repeatFlag = false;
278                         processChord(false);
279                 } else {
280                         saveState(cChord);
281                 }
282                 return;
283         }
284
285         // Iterate through chord picking out the individual 
286         // and longest chords
287         uint32_t bufChords[QWERBUF];
288         int      bufLen         = 0;
289         uint32_t mask           = 0;
290
291         // We iterate over it multiple times to catch the longest
292         // chord. Then that gets addded to the mask and re run.
293         while (savedChord != mask) {
294                 uint32_t test                   = 0;
295                 uint32_t longestChord   = 0;
296
297                 for (int i = 0; i <= chordIndex; i++) {
298                         cChord = chordState[i] & ~mask;
299                         if (cChord == 0)
300                                 continue;
301
302                         // Assume mid parse Sym is new chord
303                         if (i != 0 && test != 0 && (cChord ^ test) == PWR) {
304                                 longestChord = test;
305                                 break;
306                         }
307
308                         // Lock SYM layer in once detected
309                         if (mask & PWR)
310                                 cChord |= PWR;
311
312
313                         // Testing for keycodes
314                         if (useFakeSteno) {
315                                 test = processFakeSteno(true);
316                         } else {
317                                 test = processQwerty(true);
318                         }
319                  
320                         if (test != 0) {
321                                 longestChord = test;
322                         }
323                 }
324                 
325                 mask |= longestChord;
326                 bufChords[bufLen] = longestChord;
327                 bufLen++;
328
329                 // That's a loop of sorts, halt processing
330                 if (bufLen >= QWERBUF) {
331                         return;
332                 }
333         }
334         
335         // Now that the buffer is populated, we run it
336         for (int i = 0; i < bufLen ; i++) {
337                 cChord = bufChords[i];
338                 if (useFakeSteno) {
339                         processFakeSteno(false);
340                 } else {
341                         processQwerty(false);
342                 }
343         }
344
345         // Save state in case of repeat
346         if (!repeatFlag) {                      
347                 saveState(savedChord);
348         }
349
350         // Restore cChord for held repeat
351         cChord = savedChord;
352
353         return;
354 }
355 void saveState(uint32_t cleanChord) {
356         pChord = cleanChord;
357         pChordIndex = chordIndex;
358         for (int i = 0; i < 32; i++) 
359                 pChordState[i] = chordState[i];
360 }
361 void restoreState() {
362         cChord = pChord;
363         chordIndex = pChordIndex;
364         for (int i = 0; i < 32; i++) 
365                 chordState[i] = pChordState[i];
366 }
367
368 // Macros for calling from keymap.c
369 void SEND(uint8_t kc) {
370         // Send Keycode, Does not work for Quantum Codes
371         if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
372 #ifndef NO_DEBUG
373                 uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
374 #endif
375                 CMDBUF[CMDLEN] = kc;
376                 CMDLEN++;
377         } 
378
379         if (cMode != COMMAND) register_code(kc);
380         return;
381 }
382 void REPEAT(void) {
383         if (cMode != QWERTY)
384                 return;
385
386         repeatFlag = true;
387         return;
388 }
389 void SET_STICKY(uint32_t stick) {
390         stickyBits = stick;
391         return;
392 }
393 void SWITCH_LAYER(int layer) {
394         if (keymapsCount >= layer) 
395                 layer_on(layer);
396 }
397 void CLICK_MOUSE(uint8_t kc) {
398 #ifdef MOUSEKEY_ENABLE
399         mousekey_on(kc);
400         mousekey_send();
401
402         // Store state for later use
403         inMouse = true;
404         mousePress = kc;
405 #endif
406 }