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