aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennyTom <denemark.tomas@gmail.com>2020-04-07 04:13:17 -0700
committerGitHub <noreply@github.com>2020-04-07 21:13:17 +1000
commite409fb47f27f9cf56479928ed86eb2eb346eec54 (patch)
treef7b27bec198b7bb6250fbcf73111c189bc22d107
parentae74922d1485e3c8e120dbc141d003ed7696b1f9 (diff)
downloadqmk_firmware-e409fb47f27f9cf56479928ed86eb2eb346eec54.tar.gz
qmk_firmware-e409fb47f27f9cf56479928ed86eb2eb346eec54.zip
DennyTom's buttery_engine (#8138)
* Selectively adding pieces * Adding georgi keymap * Adding more files, fixing make * Smaller makefiles * Fixing make rules * README more inline with QMK's guidelines * Turning off buggy assert * Improving documentation based on a user feedback. * Slightly better schema * Resurrected state machine diagram
-rw-r--r--keyboards/butterstick/keymaps/dennytom/README.md11
-rw-r--r--keyboards/butterstick/keymaps/dennytom/keymap.c1418
-rw-r--r--keyboards/butterstick/keymaps/dennytom/keymap_def.json309
-rw-r--r--keyboards/butterstick/keymaps/dennytom/rules.mk8
-rw-r--r--keyboards/georgi/keymaps/dennytom/README.md11
-rw-r--r--keyboards/georgi/keymaps/dennytom/keymap.c1208
-rw-r--r--keyboards/georgi/keymaps/dennytom/keymap_def.json153
-rw-r--r--keyboards/georgi/keymaps/dennytom/rules.mk8
-rw-r--r--users/dennytom/chording_engine/README.md376
-rw-r--r--users/dennytom/chording_engine/chord.py466
-rw-r--r--users/dennytom/chording_engine/engine.part.1163
-rw-r--r--users/dennytom/chording_engine/engine.part.2323
-rw-r--r--users/dennytom/chording_engine/engine.part.3404
-rw-r--r--users/dennytom/chording_engine/keymap_def.schema.json337
-rw-r--r--users/dennytom/chording_engine/parser.py231
-rw-r--r--users/dennytom/chording_engine/state_machine.dot49
-rw-r--r--users/dennytom/chording_engine/state_machine.svg235
-rw-r--r--users/dennytom/chording_engine/tests/minunit.h288
-rw-r--r--users/dennytom/chording_engine/tests/test.c1259
-rw-r--r--users/dennytom/chording_engine/tests/test_full.sh11
-rw-r--r--users/dennytom/chording_engine/tests/test_keymap_def.json145
-rw-r--r--users/dennytom/chording_engine/tests/test_quick.sh6
22 files changed, 7419 insertions, 0 deletions
diff --git a/keyboards/butterstick/keymaps/dennytom/README.md b/keyboards/butterstick/keymaps/dennytom/README.md
new file mode 100644
index 000000000..a75bcc750
--- /dev/null
+++ b/keyboards/butterstick/keymaps/dennytom/README.md
@@ -0,0 +1,11 @@
1# # Dennytom's Butterstick Layout
2
3This keymap is using a custom chording engine. Head out to my (DennyTom) user space to find the source files and details.
4
5To make a real keymap from the JSON file, run
6
7```sh
8python3 parser.py keymap_def.json keymap.c
9```
10
11Somehow it fits the whole keyboard on 20 keys. For longer typing sessions, use the ASET NIOP mode. \ No newline at end of file
diff --git a/keyboards/butterstick/keymaps/dennytom/keymap.c b/keyboards/butterstick/keymaps/dennytom/keymap.c
new file mode 100644
index 000000000..bfe0aa215
--- /dev/null
+++ b/keyboards/butterstick/keymaps/dennytom/keymap.c
@@ -0,0 +1,1418 @@
1#include QMK_KEYBOARD_H
2
3#define CHORD_TIMEOUT 100
4#define DANCE_TIMEOUT 200
5#define LEADER_TIMEOUT 750
6#define TAP_TIMEOUT 50
7#define LONG_PRESS_MULTIPLIER 3
8#define DYNAMIC_MACRO_MAX_LENGTH 20
9#define COMMAND_MAX_LENGTH 5
10#define LEADER_MAX_LENGTH 5
11#define HASH_TYPE uint32_t
12#define NUMBER_OF_KEYS 20
13#define DEFAULT_PSEUDOLAYER QWERTY
14
15#define H_TOP1 ((HASH_TYPE) 1 << 0)
16#define H_TOP2 ((HASH_TYPE) 1 << 1)
17#define H_TOP3 ((HASH_TYPE) 1 << 2)
18#define H_TOP4 ((HASH_TYPE) 1 << 3)
19#define H_TOP5 ((HASH_TYPE) 1 << 4)
20#define H_TOP6 ((HASH_TYPE) 1 << 5)
21#define H_TOP7 ((HASH_TYPE) 1 << 6)
22#define H_TOP8 ((HASH_TYPE) 1 << 7)
23#define H_TOP9 ((HASH_TYPE) 1 << 8)
24#define H_TOP0 ((HASH_TYPE) 1 << 9)
25#define H_BOT1 ((HASH_TYPE) 1 << 10)
26#define H_BOT2 ((HASH_TYPE) 1 << 11)
27#define H_BOT3 ((HASH_TYPE) 1 << 12)
28#define H_BOT4 ((HASH_TYPE) 1 << 13)
29#define H_BOT5 ((HASH_TYPE) 1 << 14)
30#define H_BOT6 ((HASH_TYPE) 1 << 15)
31#define H_BOT7 ((HASH_TYPE) 1 << 16)
32#define H_BOT8 ((HASH_TYPE) 1 << 17)
33#define H_BOT9 ((HASH_TYPE) 1 << 18)
34#define H_BOT0 ((HASH_TYPE) 1 << 19)
35
36enum internal_keycodes {
37 TOP1 = SAFE_RANGE,
38 TOP2, TOP3, TOP4, TOP5, TOP6, TOP7, TOP8, TOP9, TOP0, BOT1, BOT2, BOT3, BOT4, BOT5, BOT6, BOT7, BOT8, BOT9, BOT0,
39 FIRST_INTERNAL_KEYCODE = TOP1,
40 LAST_INTERNAL_KEYCODE = BOT0
41};
42
43enum pseudolayers {
44 ALWAYS_ON, QWERTY, NUM, MOV, MOUSE, ASETNIOP, ASETNIOP_123, ASETNIOP_FN
45};
46
47const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
48 [0] = LAYOUT_butter(TOP1, TOP2, TOP3, TOP4, TOP5, TOP6, TOP7, TOP8, TOP9, TOP0, BOT1, BOT2, BOT3, BOT4, BOT5, BOT6, BOT7, BOT8, BOT9, BOT0),
49};
50size_t keymapsCount = 1;
51
52uint8_t keycodes_buffer_array[] = {
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
54};
55
56uint8_t command_buffer[] = {
57 0, 0, 0, 0, 0
58};
59
60uint16_t leader_buffer[] = {
61 0, 0, 0, 0, 0
62};
63
64uint8_t dynamic_macro_buffer[] = {
65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
66};
67
68enum chord_states {
69 IDLE,
70 READY,
71 ACTIVATED,
72 DEACTIVATED,
73 PRESS_FROM_ACTIVE,
74 FINISHED_FROM_ACTIVE,
75 IDLE_IN_DANCE,
76 READY_IN_DANCE,
77 FINISHED,
78 LOCKED,
79 READY_LOCKED,
80 RESTART,
81 IN_ONE_SHOT
82};
83
84struct Chord {
85 uint32_t keycodes_hash;
86 uint8_t pseudolayer;
87 uint8_t* state;
88 uint8_t* counter;
89 uint16_t value1;
90 uint8_t value2;
91 void (*function) (const struct Chord*);
92};
93
94uint8_t current_pseudolayer = DEFAULT_PSEUDOLAYER;
95bool lock_next = false;
96uint16_t chord_timer = 0;
97uint16_t dance_timer = 0;
98bool autoshift_mode = true;
99uint8_t keycode_index = 0;
100uint8_t command_mode = 0;
101uint8_t command_ind = 0;
102bool in_leader_mode = false;
103uint8_t leader_ind = 0;
104uint16_t leader_timer = 0;
105uint8_t dynamic_macro_mode = false;
106uint8_t dynamic_macro_ind = 0;
107bool a_key_went_through = false;
108struct Chord* last_chord = NULL;
109
110bool handle_US_ANSI_shifted_keys(int16_t keycode, bool in) {
111 bool is_US_ANSI_shifted = true;
112
113 int16_t regular_keycode = KC_NO;
114 switch (keycode) {
115 case KC_TILDE:
116 regular_keycode = KC_GRAVE;
117 break;
118 case KC_EXCLAIM:
119 regular_keycode = KC_1;
120 break;
121 case KC_AT:
122 regular_keycode = KC_2;
123 break;
124 case KC_HASH:
125 regular_keycode = KC_3;
126 break;
127 case KC_DOLLAR:
128 regular_keycode = KC_4;
129 break;
130 case KC_PERCENT:
131 regular_keycode = KC_5;
132 break;
133 case KC_CIRCUMFLEX:
134 regular_keycode = KC_6;
135 break;
136 case KC_AMPERSAND:
137 regular_keycode = KC_7;
138 break;
139 case KC_ASTERISK:
140 regular_keycode = KC_8;
141 break;
142 case KC_LEFT_PAREN:
143 regular_keycode = KC_9;
144 break;
145 case KC_RIGHT_PAREN:
146 regular_keycode = KC_0;
147 break;
148 case KC_UNDERSCORE:
149 regular_keycode = KC_MINUS;
150 break;
151 case KC_PLUS:
152 regular_keycode = KC_EQUAL;
153 break;
154 case KC_LEFT_CURLY_BRACE:
155 regular_keycode = KC_LBRACKET;
156 break;
157 case KC_RIGHT_CURLY_BRACE:
158 regular_keycode = KC_RBRACKET;
159 break;
160 case KC_PIPE:
161 regular_keycode = KC_BSLASH;
162 break;
163 case KC_COLON:
164 regular_keycode = KC_SCOLON;
165 break;
166 case KC_DOUBLE_QUOTE:
167 regular_keycode = KC_QUOTE;
168 break;
169 case KC_LEFT_ANGLE_BRACKET:
170 regular_keycode = KC_COMMA;
171 break;
172 case KC_RIGHT_ANGLE_BRACKET:
173 regular_keycode = KC_DOT;
174 break;
175 case KC_QUESTION:
176 regular_keycode = KC_SLASH;
177 break;
178 default:
179 is_US_ANSI_shifted = false;
180 }
181 if (is_US_ANSI_shifted) {
182 if (in) {
183 register_code(KC_LSFT);
184 register_code(regular_keycode);
185 } else {
186 unregister_code(regular_keycode);
187 unregister_code(KC_LSFT);
188 }
189 }
190 return is_US_ANSI_shifted;
191}
192
193void key_in(int16_t keycode) {
194 if (command_mode == 1 && command_ind < COMMAND_MAX_LENGTH) {
195 command_buffer[command_ind] = keycode;
196 command_ind++;
197 a_key_went_through = true;
198 } else if (in_leader_mode && leader_ind < LEADER_MAX_LENGTH) {
199 leader_buffer[leader_ind] = keycode;
200 leader_ind++;
201 a_key_went_through = true;
202 } else if (dynamic_macro_mode && dynamic_macro_ind < DYNAMIC_MACRO_MAX_LENGTH) {
203 dynamic_macro_buffer[dynamic_macro_ind] = keycode;
204 dynamic_macro_ind++;
205 a_key_went_through = true;
206 } else {
207 if (!handle_US_ANSI_shifted_keys(keycode, true)) {
208 register_code(keycode);
209 }
210 send_keyboard_report();
211 a_key_went_through = true;
212 }
213}
214
215void key_out(int16_t keycode) {
216 if (command_mode == 0) {
217 if (!handle_US_ANSI_shifted_keys(keycode, false)) {
218 if (command_mode == 0 && in_leader_mode == false && dynamic_macro_mode == false) {
219 unregister_code(keycode);
220 }
221 }
222 send_keyboard_report();
223 }
224}
225
226void tap_key(int16_t keycode) {
227 key_in(keycode);
228 wait_ms(TAP_TIMEOUT);
229 key_out(keycode);
230}
231void single_dance(const struct Chord* self) {
232 switch (*self->state) {
233 case ACTIVATED:
234 key_in(self->value1);
235 break;
236 case DEACTIVATED:
237 key_out(self->value1);
238 *self->state = IDLE;
239 break;
240 case RESTART:
241 key_out(self->value1);
242 break;
243 default:
244 break;
245 }
246}
247
248void key_layer_dance(const struct Chord* self) {
249 switch (*self->state) {
250 case ACTIVATED:
251 current_pseudolayer = self->value2;
252 a_key_went_through = false;
253 break;
254 case DEACTIVATED:
255 case RESTART:
256 if (!a_key_went_through) {
257 tap_key(self->value1);
258 }
259 current_pseudolayer = self->pseudolayer;
260 *self->state = IDLE; // does not have effect if the state was RESTART
261 break;
262 default:
263 break;
264 }
265}
266
267void key_mod_dance(const struct Chord* self) {
268 switch (*self->state) {
269 case ACTIVATED:
270 key_in(self->value2);
271 a_key_went_through = false;
272 break;
273 case DEACTIVATED:
274 case RESTART:
275 key_out(self->value2);
276 if (!a_key_went_through) {
277 tap_key(self->value1);
278 }
279 *self->state = IDLE; // does not have effect if the state was RESTART
280 break;
281 default:
282 break;
283 }
284}
285
286void key_key_dance(const struct Chord* self) {
287 switch (*self->state) {
288 case ACTIVATED:
289 break;
290 case DEACTIVATED:
291 tap_key(self->value1);
292 *self->state = IDLE;
293 break;
294 case FINISHED:
295 case PRESS_FROM_ACTIVE:
296 key_in(self->value2);
297 break;
298 case RESTART:
299 key_out(self->value2);
300 break;
301 default:
302 break;
303 }
304}
305
306void autoshift_dance_impl(const struct Chord* self) {
307 switch (*self->state) {
308 case ACTIVATED:
309 *self->counter = 0;
310 break;
311 case DEACTIVATED:
312 case RESTART:
313 tap_key(self->value1);
314 *self->state = IDLE;
315 break;
316 case FINISHED_FROM_ACTIVE:
317 if (*self->counter == (LONG_PRESS_MULTIPLIER - 2)) {
318 key_in(KC_LSFT);
319 tap_key(self->value1);
320 key_out(KC_LSFT);
321 *self->state = IDLE;
322 // the skip to IDLE is usually just a lag optimization,
323 // in this case it has a logic function, on a short
324 // press (still longer than a tap) the key does not get shifted
325 } else {
326 *self->counter += 1;
327 *self->state = PRESS_FROM_ACTIVE;
328 dance_timer = timer_read();
329 }
330 break;
331 default:
332 break;
333 }
334}
335
336void autoshift_dance(const struct Chord* self) {
337 if (autoshift_mode) {
338 autoshift_dance_impl(self);
339 } else {
340 single_dance(self);
341 }
342}
343
344void autoshift_toggle(const struct Chord* self){
345 if (*self->state == ACTIVATED) {
346 autoshift_mode = !autoshift_mode;
347 *self->state = IDLE;
348 }
349}
350
351void temp_pseudolayer(const struct Chord* self) {
352 switch (*self->state) {
353 case ACTIVATED:
354 current_pseudolayer = self->value1;
355 break;
356 case DEACTIVATED:
357 current_pseudolayer = self->pseudolayer;
358 *self->state = IDLE;
359 break;
360 case RESTART:
361 current_pseudolayer = self->pseudolayer;
362 break;
363 default:
364 break;
365 }
366}
367
368void perm_pseudolayer(const struct Chord* self) {
369 if (*self->state == ACTIVATED) {
370 current_pseudolayer = self->value1;
371 *self->state = IDLE;
372 }
373}
374
375void switch_layer(const struct Chord* self) {
376 if (*self->state == ACTIVATED) {
377 layer_move(self->value1);
378 *self->state = IDLE;
379 }
380}
381
382void lock(const struct Chord* self) {
383 if (*self->state == ACTIVATED) {
384 lock_next = true;
385 *self->state = IDLE;
386 }
387}
388
389void one_shot_key(const struct Chord* self) {
390 switch (*self->state) {
391 case ACTIVATED:
392 break;
393 case DEACTIVATED:
394 key_in(self->value1);
395 *self->state = IN_ONE_SHOT;
396 break;
397 case FINISHED:
398 case PRESS_FROM_ACTIVE:
399 key_in(self->value1);
400 a_key_went_through = false;
401 break;
402 case RESTART:
403 if (a_key_went_through) {
404 key_out(self->value1);
405 } else {
406 *self->state = IN_ONE_SHOT;
407 }
408 default:
409 break;
410 }
411}
412
413void one_shot_layer(const struct Chord* self) {
414 switch (*self->state) {
415 case ACTIVATED:
416 break;
417 case DEACTIVATED:
418 current_pseudolayer = self->value1;
419 *self->state = IN_ONE_SHOT;
420 break;
421 case FINISHED:
422 case PRESS_FROM_ACTIVE:
423 current_pseudolayer = self->value1;
424 a_key_went_through = false;
425 break;
426 case RESTART:
427 if (a_key_went_through) {
428 current_pseudolayer = self->pseudolayer;
429 } else {
430 *self->state = IN_ONE_SHOT;
431 }
432 default:
433 break;
434 }
435}
436
437void command(const struct Chord* self) {
438 if (*self->state == ACTIVATED) {
439 command_mode++;
440 *self->state = IDLE;
441 }
442}
443
444bool identical(uint16_t* buffer1, uint16_t* buffer2) {
445 bool same = true;
446 for (int i = 0; i < LEADER_MAX_LENGTH; i++) {
447 same = same && (buffer1[i] == buffer2[i]);
448 }
449 return same;
450}
451
452void leader(const struct Chord* self) {
453 if (*self->state == ACTIVATED) {
454 in_leader_mode = true;
455 *self->state = IDLE;
456 }
457}
458
459void dynamic_macro_record(const struct Chord* self) {
460 if (*self->state == ACTIVATED) {
461 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
462 dynamic_macro_buffer[i] = 0;
463 }
464 dynamic_macro_mode = true;
465 *self->state = IDLE;
466 }
467}
468
469void dynamic_macro_next(const struct Chord* self) {
470 if (*self->state == ACTIVATED) {
471 if (dynamic_macro_mode && dynamic_macro_ind < DYNAMIC_MACRO_MAX_LENGTH) {
472 dynamic_macro_buffer[dynamic_macro_ind] = 0;
473 dynamic_macro_ind++;
474 }
475 *self->state = IDLE;
476 }
477}
478
479void dynamic_macro_end(const struct Chord* self) {
480 if (*self->state == ACTIVATED) {
481 if (dynamic_macro_mode) {
482 dynamic_macro_mode = false;
483 }
484 *self->state = IDLE;
485 }
486}
487
488void dynamic_macro_play(const struct Chord* self) {
489 if (*self->state == ACTIVATED) {
490 int ind_start = 0;
491 while (ind_start < DYNAMIC_MACRO_MAX_LENGTH) {
492 for (int i = ind_start; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
493 if (dynamic_macro_buffer[i] == 0) {
494 break;
495 }
496 register_code(dynamic_macro_buffer[i]);
497 }
498 send_keyboard_report();
499 wait_ms(TAP_TIMEOUT);
500 for (int i = ind_start; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
501 if (dynamic_macro_buffer[i] == 0) {
502 ind_start = i + 1;
503 break;
504 }
505 unregister_code(dynamic_macro_buffer[i]);
506 }
507 send_keyboard_report();
508 }
509 *self->state = IDLE;
510 }
511}
512
513void clear(const struct Chord* self);
514
515void reset_keyboard_kb(void){
516#ifdef WATCHDOG_ENABLE
517 MCUSR = 0;
518 wdt_disable();
519 wdt_reset();
520#endif
521 reset_keyboard();
522}
523
524void reset(const struct Chord* self) {
525 if (*self->state == ACTIVATED) {
526 reset_keyboard_kb();
527 }
528}
529
530uint8_t state_0 = IDLE;
531const struct Chord chord_0 PROGMEM = {H_TOP1 + H_TOP2 + H_BOT1 + H_BOT2, ALWAYS_ON, &state_0, NULL, 0, 0, lock};
532uint8_t state_1 = IDLE;
533const struct Chord chord_1 PROGMEM = {H_TOP2 + H_TOP3 + H_BOT2 + H_BOT3, ALWAYS_ON, &state_1, NULL, 0, 0, autoshift_toggle};
534uint8_t state_2 = IDLE;
535const struct Chord chord_2 PROGMEM = {H_TOP5 + H_TOP6 + H_BOT5 + H_BOT6, ALWAYS_ON, &state_2, NULL, 0, 0, command};
536uint8_t state_3 = IDLE;
537const struct Chord chord_3 PROGMEM = {H_TOP1 + H_TOP2 + H_TOP9 + H_TOP0 + H_BOT1 + H_BOT2 + H_BOT9 + H_BOT0, ALWAYS_ON, &state_3, NULL, 0, 0, clear};
538uint8_t state_4 = IDLE;
539uint8_t counter_4 = 0;
540const struct Chord chord_4 PROGMEM = {H_TOP1, QWERTY, &state_4, &counter_4, KC_Q, 0, autoshift_dance};
541uint8_t state_5 = IDLE;
542uint8_t counter_5 = 0;
543const struct Chord chord_5 PROGMEM = {H_TOP2, QWERTY, &state_5, &counter_5, KC_W, 0, autoshift_dance};
544uint8_t state_6 = IDLE;
545uint8_t counter_6 = 0;
546const struct Chord chord_6 PROGMEM = {H_TOP3, QWERTY, &state_6, &counter_6, KC_E, 0, autoshift_dance};
547uint8_t state_7 = IDLE;
548uint8_t counter_7 = 0;
549const struct Chord chord_7 PROGMEM = {H_TOP4, QWERTY, &state_7, &counter_7, KC_R, 0, autoshift_dance};
550uint8_t state_8 = IDLE;
551uint8_t counter_8 = 0;
552const struct Chord chord_8 PROGMEM = {H_TOP5, QWERTY, &state_8, &counter_8, KC_T, 0, autoshift_dance};
553uint8_t state_9 = IDLE;
554uint8_t counter_9 = 0;
555const struct Chord chord_9 PROGMEM = {H_TOP6, QWERTY, &state_9, &counter_9, KC_Y, 0, autoshift_dance};
556uint8_t state_10 = IDLE;
557uint8_t counter_10 = 0;
558const struct Chord chord_10 PROGMEM = {H_TOP7, QWERTY, &state_10, &counter_10, KC_U, 0, autoshift_dance};
559uint8_t state_11 = IDLE;
560uint8_t counter_11 = 0;
561const struct Chord chord_11 PROGMEM = {H_TOP8, QWERTY, &state_11, &counter_11, KC_I, 0, autoshift_dance};
562uint8_t state_12 = IDLE;
563uint8_t counter_12 = 0;
564const struct Chord chord_12 PROGMEM = {H_TOP9, QWERTY, &state_12, &counter_12, KC_O, 0, autoshift_dance};
565uint8_t state_13 = IDLE;
566uint8_t counter_13 = 0;
567const struct Chord chord_13 PROGMEM = {H_TOP0, QWERTY, &state_13, &counter_13, KC_P, 0, autoshift_dance};
568uint8_t state_14 = IDLE;
569uint8_t counter_14 = 0;
570const struct Chord chord_14 PROGMEM = {H_TOP1 + H_BOT1, QWERTY, &state_14, &counter_14, KC_A, 0, autoshift_dance};
571uint8_t state_15 = IDLE;
572uint8_t counter_15 = 0;
573const struct Chord chord_15 PROGMEM = {H_TOP2 + H_BOT2, QWERTY, &state_15, &counter_15, KC_S, 0, autoshift_dance};
574uint8_t state_16 = IDLE;
575uint8_t counter_16 = 0;
576const struct Chord chord_16 PROGMEM = {H_TOP3 + H_BOT3, QWERTY, &state_16, &counter_16, KC_D, 0, autoshift_dance};
577uint8_t state_17 = IDLE;
578uint8_t counter_17 = 0;
579const struct Chord chord_17 PROGMEM = {H_TOP4 + H_BOT4, QWERTY, &state_17, &counter_17, KC_F, 0, autoshift_dance};
580uint8_t state_18 = IDLE;
581uint8_t counter_18 = 0;
582const struct Chord chord_18 PROGMEM = {H_TOP5 + H_BOT5, QWERTY, &state_18, &counter_18, KC_G, 0, autoshift_dance};
583uint8_t state_19 = IDLE;
584uint8_t counter_19 = 0;
585const struct Chord chord_19 PROGMEM = {H_TOP6 + H_BOT6, QWERTY, &state_19, &counter_19, KC_H, 0, autoshift_dance};
586uint8_t state_20 = IDLE;
587uint8_t counter_20 = 0;
588const struct Chord chord_20 PROGMEM = {H_TOP7 + H_BOT7, QWERTY, &state_20, &counter_20, KC_J, 0, autoshift_dance};
589uint8_t state_21 = IDLE;
590uint8_t counter_21 = 0;
591const struct Chord chord_21 PROGMEM = {H_TOP8 + H_BOT8, QWERTY, &state_21, &counter_21, KC_K, 0, autoshift_dance};
592uint8_t state_22 = IDLE;
593uint8_t counter_22 = 0;
594const struct Chord chord_22 PROGMEM = {H_TOP9 + H_BOT9, QWERTY, &state_22, &counter_22, KC_L, 0, autoshift_dance};
595uint8_t state_23 = IDLE;
596uint8_t counter_23 = 0;
597const struct Chord chord_23 PROGMEM = {H_TOP0 + H_BOT0, QWERTY, &state_23, &counter_23, KC_SCOLON, 0, autoshift_dance};
598uint8_t state_24 = IDLE;
599uint8_t counter_24 = 0;
600const struct Chord chord_24 PROGMEM = {H_BOT1, QWERTY, &state_24, &counter_24, KC_Z, 0, autoshift_dance};
601uint8_t state_25 = IDLE;
602uint8_t counter_25 = 0;
603const struct Chord chord_25 PROGMEM = {H_BOT2, QWERTY, &state_25, &counter_25, KC_X, 0, autoshift_dance};
604uint8_t state_26 = IDLE;
605uint8_t counter_26 = 0;
606const struct Chord chord_26 PROGMEM = {H_BOT3, QWERTY, &state_26, &counter_26, KC_C, 0, autoshift_dance};
607uint8_t state_27 = IDLE;
608uint8_t counter_27 = 0;
609const struct Chord chord_27 PROGMEM = {H_BOT4, QWERTY, &state_27, &counter_27, KC_V, 0, autoshift_dance};
610uint8_t state_28 = IDLE;
611uint8_t counter_28 = 0;
612const struct Chord chord_28 PROGMEM = {H_BOT5, QWERTY, &state_28, &counter_28, KC_B, 0, autoshift_dance};
613uint8_t state_29 = IDLE;
614uint8_t counter_29 = 0;
615const struct Chord chord_29 PROGMEM = {H_BOT6, QWERTY, &state_29, &counter_29, KC_N, 0, autoshift_dance};
616uint8_t state_30 = IDLE;
617uint8_t counter_30 = 0;
618const struct Chord chord_30 PROGMEM = {H_BOT7, QWERTY, &state_30, &counter_30, KC_M, 0, autoshift_dance};
619uint8_t state_31 = IDLE;
620uint8_t counter_31 = 0;
621const struct Chord chord_31 PROGMEM = {H_BOT8, QWERTY, &state_31, &counter_31, KC_COMMA, 0, autoshift_dance};
622uint8_t state_32 = IDLE;
623uint8_t counter_32 = 0;
624const struct Chord chord_32 PROGMEM = {H_BOT9, QWERTY, &state_32, &counter_32, KC_DOT, 0, autoshift_dance};
625uint8_t state_33 = IDLE;
626uint8_t counter_33 = 0;
627const struct Chord chord_33 PROGMEM = {H_BOT0, QWERTY, &state_33, &counter_33, KC_SLASH, 0, autoshift_dance};
628uint8_t state_34 = IDLE;
629const struct Chord chord_34 PROGMEM = {H_TOP1 + H_TOP2, QWERTY, &state_34, NULL, KC_ESC, 0, single_dance};
630uint8_t state_35 = IDLE;
631const struct Chord chord_35 PROGMEM = {H_TOP2 + H_TOP3, QWERTY, &state_35, NULL, MOV, 0, temp_pseudolayer};
632uint8_t state_36 = IDLE;
633const struct Chord chord_36 PROGMEM = {H_TOP3 + H_TOP4, QWERTY, &state_36, NULL, KC_TAB, 0, single_dance};
634uint8_t state_37 = IDLE;
635const struct Chord chord_37 PROGMEM = {H_TOP5 + H_TOP6, QWERTY, &state_37, NULL, KC_RGUI, 0, one_shot_key};
636uint8_t state_38 = IDLE;
637const struct Chord chord_38 PROGMEM = {H_TOP7 + H_TOP8, QWERTY, &state_38, NULL, KC_INS, 0, single_dance};
638uint8_t state_39 = IDLE;
639const struct Chord chord_39 PROGMEM = {H_TOP8 + H_TOP9, QWERTY, &state_39, NULL, KC_DEL, 0, single_dance};
640uint8_t state_40 = IDLE;
641const struct Chord chord_40 PROGMEM = {H_TOP9 + H_TOP0, QWERTY, &state_40, NULL, KC_BSPC, 0, single_dance};
642uint8_t state_41 = IDLE;
643const struct Chord chord_41 PROGMEM = {H_TOP9 + H_TOP0 + H_BOT9 + H_BOT0, QWERTY, &state_41, NULL, KC_ENTER, 0, single_dance};
644uint8_t state_42 = IDLE;
645const struct Chord chord_42 PROGMEM = {H_BOT1 + H_BOT2, QWERTY, &state_42, NULL, KC_LSFT, 0, one_shot_key};
646uint8_t state_43 = IDLE;
647const struct Chord chord_43 PROGMEM = {H_BOT2 + H_BOT3, QWERTY, &state_43, NULL, KC_LCTL, 0, one_shot_key};
648uint8_t state_44 = IDLE;
649const struct Chord chord_44 PROGMEM = {H_BOT3 + H_BOT4, QWERTY, &state_44, NULL, KC_LALT, 0, one_shot_key};
650uint8_t state_45 = IDLE;
651const struct Chord chord_45 PROGMEM = {H_BOT4 + H_BOT5, QWERTY, &state_45, NULL, NUM, 0, one_shot_layer};
652uint8_t state_46 = IDLE;
653const struct Chord chord_46 PROGMEM = {H_BOT5 + H_BOT6, QWERTY, &state_46, NULL, KC_LGUI, 0, one_shot_key};
654uint8_t state_47 = IDLE;
655const struct Chord chord_47 PROGMEM = {H_BOT6 + H_BOT7, QWERTY, &state_47, NULL, NUM, 0, one_shot_layer};
656uint8_t state_48 = IDLE;
657const struct Chord chord_48 PROGMEM = {H_BOT7 + H_BOT8, QWERTY, &state_48, NULL, KC_RALT, 0, one_shot_key};
658uint8_t state_49 = IDLE;
659const struct Chord chord_49 PROGMEM = {H_BOT8 + H_BOT9, QWERTY, &state_49, NULL, KC_RCTL, 0, one_shot_key};
660uint8_t state_50 = IDLE;
661const struct Chord chord_50 PROGMEM = {H_BOT9 + H_BOT0, QWERTY, &state_50, NULL, KC_RSFT, 0, one_shot_key};
662uint8_t state_51 = IDLE;
663const struct Chord chord_51 PROGMEM = {H_BOT1 + H_BOT0, QWERTY, &state_51, NULL, KC_SPACE, 0, single_dance};
664uint8_t state_52 = IDLE;
665const struct Chord chord_52 PROGMEM = {H_TOP1 + H_TOP2 + H_TOP3 + H_TOP4, QWERTY, &state_52, NULL, MOUSE, 0, temp_pseudolayer};
666uint8_t state_53 = IDLE;
667const struct Chord chord_53 PROGMEM = {H_TOP1 + H_TOP2 + H_TOP3 + H_TOP4, QWERTY, &state_53, NULL, ASETNIOP, 0, perm_pseudolayer};
668uint8_t state_54 = IDLE;
669uint8_t counter_54 = 0;
670const struct Chord chord_54 PROGMEM = {H_TOP1, NUM, &state_54, &counter_54, KC_1, 0, autoshift_dance};
671uint8_t state_55 = IDLE;
672uint8_t counter_55 = 0;
673const struct Chord chord_55 PROGMEM = {H_TOP2, NUM, &state_55, &counter_55, KC_2, 0, autoshift_dance};
674uint8_t state_56 = IDLE;
675uint8_t counter_56 = 0;
676const struct Chord chord_56 PROGMEM = {H_TOP3, NUM, &state_56, &counter_56, KC_3, 0, autoshift_dance};
677uint8_t state_57 = IDLE;
678uint8_t counter_57 = 0;
679const struct Chord chord_57 PROGMEM = {H_TOP4, NUM, &state_57, &counter_57, KC_4, 0, autoshift_dance};
680uint8_t state_58 = IDLE;
681uint8_t counter_58 = 0;
682const struct Chord chord_58 PROGMEM = {H_TOP5, NUM, &state_58, &counter_58, KC_5, 0, autoshift_dance};
683uint8_t state_59 = IDLE;
684uint8_t counter_59 = 0;
685const struct Chord chord_59 PROGMEM = {H_TOP6, NUM, &state_59, &counter_59, KC_6, 0, autoshift_dance};
686uint8_t state_60 = IDLE;
687uint8_t counter_60 = 0;
688const struct Chord chord_60 PROGMEM = {H_TOP7, NUM, &state_60, &counter_60, KC_7, 0, autoshift_dance};
689uint8_t state_61 = IDLE;
690uint8_t counter_61 = 0;
691const struct Chord chord_61 PROGMEM = {H_TOP8, NUM, &state_61, &counter_61, KC_8, 0, autoshift_dance};
692uint8_t state_62 = IDLE;
693uint8_t counter_62 = 0;
694const struct Chord chord_62 PROGMEM = {H_TOP9, NUM, &state_62, &counter_62, KC_9, 0, autoshift_dance};
695uint8_t state_63 = IDLE;
696uint8_t counter_63 = 0;
697const struct Chord chord_63 PROGMEM = {H_TOP0, NUM, &state_63, &counter_63, KC_0, 0, autoshift_dance};
698uint8_t state_64 = IDLE;
699const struct Chord chord_64 PROGMEM = {H_TOP1 + H_BOT1, NUM, &state_64, NULL, KC_F1, 0, single_dance};
700uint8_t state_65 = IDLE;
701const struct Chord chord_65 PROGMEM = {H_TOP2 + H_BOT2, NUM, &state_65, NULL, KC_F2, 0, single_dance};
702uint8_t state_66 = IDLE;
703const struct Chord chord_66 PROGMEM = {H_TOP3 + H_BOT3, NUM, &state_66, NULL, KC_F3, 0, single_dance};
704uint8_t state_67 = IDLE;
705const struct Chord chord_67 PROGMEM = {H_TOP4 + H_BOT4, NUM, &state_67, NULL, KC_F4, 0, single_dance};
706uint8_t state_68 = IDLE;
707const struct Chord chord_68 PROGMEM = {H_TOP5 + H_BOT5, NUM, &state_68, NULL, KC_F5, 0, single_dance};
708uint8_t state_69 = IDLE;
709const struct Chord chord_69 PROGMEM = {H_TOP6 + H_BOT6, NUM, &state_69, NULL, KC_F6, 0, single_dance};
710uint8_t state_70 = IDLE;
711const struct Chord chord_70 PROGMEM = {H_TOP7 + H_BOT7, NUM, &state_70, NULL, KC_F7, 0, single_dance};
712uint8_t state_71 = IDLE;
713const struct Chord chord_71 PROGMEM = {H_TOP8 + H_BOT8, NUM, &state_71, NULL, KC_F8, 0, single_dance};
714uint8_t state_72 = IDLE;
715const struct Chord chord_72 PROGMEM = {H_TOP9 + H_BOT9, NUM, &state_72, NULL, KC_F9, 0, single_dance};
716uint8_t state_73 = IDLE;
717const struct Chord chord_73 PROGMEM = {H_TOP0 + H_BOT0, NUM, &state_73, NULL, KC_F10, 0, single_dance};
718uint8_t state_74 = IDLE;
719uint8_t counter_74 = 0;
720const struct Chord chord_74 PROGMEM = {H_BOT1, NUM, &state_74, &counter_74, KC_GRAVE, 0, autoshift_dance};
721uint8_t state_75 = IDLE;
722uint8_t counter_75 = 0;
723const struct Chord chord_75 PROGMEM = {H_BOT2, NUM, &state_75, &counter_75, KC_MINUS, 0, autoshift_dance};
724uint8_t state_76 = IDLE;
725uint8_t counter_76 = 0;
726const struct Chord chord_76 PROGMEM = {H_BOT3, NUM, &state_76, &counter_76, KC_EQUAL, 0, autoshift_dance};
727uint8_t state_77 = IDLE;
728uint8_t counter_77 = 0;
729const struct Chord chord_77 PROGMEM = {H_BOT4, NUM, &state_77, &counter_77, KC_LBRACKET, 0, autoshift_dance};
730uint8_t state_78 = IDLE;
731uint8_t counter_78 = 0;
732const struct Chord chord_78 PROGMEM = {H_BOT5, NUM, &state_78, &counter_78, KC_RBRACKET, 0, autoshift_dance};
733uint8_t state_79 = IDLE;
734uint8_t counter_79 = 0;
735const struct Chord chord_79 PROGMEM = {H_BOT6, NUM, &state_79, &counter_79, KC_BSLASH, 0, autoshift_dance};
736uint8_t state_80 = IDLE;
737uint8_t counter_80 = 0;
738const struct Chord chord_80 PROGMEM = {H_BOT7, NUM, &state_80, &counter_80, KC_QUOTE, 0, autoshift_dance};
739uint8_t state_81 = IDLE;
740const struct Chord chord_81 PROGMEM = {H_BOT9, NUM, &state_81, NULL, KC_F11, 0, single_dance};
741uint8_t state_82 = IDLE;
742const struct Chord chord_82 PROGMEM = {H_BOT0, NUM, &state_82, NULL, KC_F12, 0, single_dance};
743uint8_t state_83 = IDLE;
744const struct Chord chord_83 PROGMEM = {H_TOP1 + H_TOP2, NUM, &state_83, NULL, KC_ESC, 0, single_dance};
745uint8_t state_84 = IDLE;
746const struct Chord chord_84 PROGMEM = {H_TOP3 + H_TOP4, NUM, &state_84, NULL, KC_TAB, 0, single_dance};
747uint8_t state_85 = IDLE;
748const struct Chord chord_85 PROGMEM = {H_TOP5 + H_TOP6, NUM, &state_85, NULL, KC_RGUI, 0, one_shot_key};
749uint8_t state_86 = IDLE;
750const struct Chord chord_86 PROGMEM = {H_TOP7 + H_TOP8, NUM, &state_86, NULL, KC_INS, 0, single_dance};
751uint8_t state_87 = IDLE;
752const struct Chord chord_87 PROGMEM = {H_TOP8 + H_TOP9, NUM, &state_87, NULL, KC_DEL, 0, single_dance};
753uint8_t state_88 = IDLE;
754const struct Chord chord_88 PROGMEM = {H_TOP9 + H_TOP0, NUM, &state_88, NULL, KC_BSPC, 0, single_dance};
755uint8_t state_89 = IDLE;
756const struct Chord chord_89 PROGMEM = {H_TOP9 + H_TOP0 + H_BOT9 + H_BOT0, NUM, &state_89, NULL, KC_ENTER, 0, single_dance};
757uint8_t state_90 = IDLE;
758const struct Chord chord_90 PROGMEM = {H_BOT1 + H_BOT2, NUM, &state_90, NULL, KC_LSFT, 0, one_shot_key};
759uint8_t state_91 = IDLE;
760const struct Chord chord_91 PROGMEM = {H_BOT2 + H_BOT3, NUM, &state_91, NULL, KC_LCTL, 0, one_shot_key};
761uint8_t state_92 = IDLE;
762const struct Chord chord_92 PROGMEM = {H_BOT3 + H_BOT4, NUM, &state_92, NULL, KC_LALT, 0, one_shot_key};
763uint8_t state_93 = IDLE;
764const struct Chord chord_93 PROGMEM = {H_BOT5 + H_BOT6, NUM, &state_93, NULL, KC_LGUI, 0, one_shot_key};
765uint8_t state_94 = IDLE;
766const struct Chord chord_94 PROGMEM = {H_BOT7 + H_BOT8, NUM, &state_94, NULL, KC_RALT, 0, one_shot_key};
767uint8_t state_95 = IDLE;
768const struct Chord chord_95 PROGMEM = {H_BOT8 + H_BOT9, NUM, &state_95, NULL, KC_RCTL, 0, one_shot_key};
769uint8_t state_96 = IDLE;
770const struct Chord chord_96 PROGMEM = {H_BOT9 + H_BOT0, NUM, &state_96, NULL, KC_RSFT, 0, one_shot_key};
771uint8_t state_97 = IDLE;
772const struct Chord chord_97 PROGMEM = {H_BOT1 + H_BOT0, NUM, &state_97, NULL, KC_SPACE, 0, single_dance};
773uint8_t state_98 = IDLE;
774const struct Chord chord_98 PROGMEM = {H_TOP7, MOV, &state_98, NULL, KC_HOME, 0, single_dance};
775uint8_t state_99 = IDLE;
776const struct Chord chord_99 PROGMEM = {H_TOP8, MOV, &state_99, NULL, KC_UP, 0, single_dance};
777uint8_t state_100 = IDLE;
778const struct Chord chord_100 PROGMEM = {H_TOP9, MOV, &state_100, NULL, KC_END, 0, single_dance};
779uint8_t state_101 = IDLE;
780const struct Chord chord_101 PROGMEM = {H_TOP0, MOV, &state_101, NULL, KC_PGUP, 0, single_dance};
781uint8_t state_102 = IDLE;
782const struct Chord chord_102 PROGMEM = {H_BOT3, MOV, &state_102, NULL, KC_LSFT, 0, single_dance};
783uint8_t state_103 = IDLE;
784const struct Chord chord_103 PROGMEM = {H_BOT4, MOV, &state_103, NULL, KC_LCTL, 0, single_dance};
785uint8_t state_104 = IDLE;
786const struct Chord chord_104 PROGMEM = {H_BOT5, MOV, &state_104, NULL, KC_LALT, 0, single_dance};
787uint8_t state_105 = IDLE;
788const struct Chord chord_105 PROGMEM = {H_BOT6, MOV, &state_105, NULL, KC_LGUI, 0, single_dance};
789uint8_t state_106 = IDLE;
790const struct Chord chord_106 PROGMEM = {H_BOT7, MOV, &state_106, NULL, KC_LEFT, 0, single_dance};
791uint8_t state_107 = IDLE;
792const struct Chord chord_107 PROGMEM = {H_BOT8, MOV, &state_107, NULL, KC_DOWN, 0, single_dance};
793uint8_t state_108 = IDLE;
794const struct Chord chord_108 PROGMEM = {H_BOT9, MOV, &state_108, NULL, KC_RIGHT, 0, single_dance};
795uint8_t state_109 = IDLE;
796const struct Chord chord_109 PROGMEM = {H_BOT0, MOV, &state_109, NULL, KC_PGDN, 0, single_dance};
797uint8_t state_110 = IDLE;
798const struct Chord chord_110 PROGMEM = {H_TOP7, MOUSE, &state_110, NULL, KC_BTN1, 0, single_dance};
799uint8_t state_111 = IDLE;
800const struct Chord chord_111 PROGMEM = {H_TOP8, MOUSE, &state_111, NULL, KC_MS_U, 0, single_dance};
801uint8_t state_112 = IDLE;
802const struct Chord chord_112 PROGMEM = {H_TOP9, MOUSE, &state_112, NULL, KC_BTN2, 0, single_dance};
803uint8_t state_113 = IDLE;
804const struct Chord chord_113 PROGMEM = {H_TOP0, MOUSE, &state_113, NULL, KC_WH_U, 0, single_dance};
805uint8_t state_114 = IDLE;
806const struct Chord chord_114 PROGMEM = {H_BOT3, MOUSE, &state_114, NULL, KC_LSFT, 0, single_dance};
807uint8_t state_115 = IDLE;
808const struct Chord chord_115 PROGMEM = {H_BOT4, MOUSE, &state_115, NULL, KC_LCTL, 0, single_dance};
809uint8_t state_116 = IDLE;
810const struct Chord chord_116 PROGMEM = {H_BOT5, MOUSE, &state_116, NULL, KC_LALT, 0, single_dance};
811uint8_t state_117 = IDLE;
812const struct Chord chord_117 PROGMEM = {H_BOT6, MOUSE, &state_117, NULL, KC_LGUI, 0, single_dance};
813uint8_t state_118 = IDLE;
814const struct Chord chord_118 PROGMEM = {H_BOT7, MOUSE, &state_118, NULL, KC_MS_L, 0, single_dance};
815uint8_t state_119 = IDLE;
816const struct Chord chord_119 PROGMEM = {H_BOT8, MOUSE, &state_119, NULL, KC_MS_D, 0, single_dance};
817uint8_t state_120 = IDLE;
818const struct Chord chord_120 PROGMEM = {H_BOT9, MOUSE, &state_120, NULL, KC_MS_R, 0, single_dance};
819uint8_t state_121 = IDLE;
820const struct Chord chord_121 PROGMEM = {H_BOT0, MOUSE, &state_121, NULL, KC_WH_D, 0, single_dance};
821uint8_t state_122 = IDLE;
822const struct Chord chord_122 PROGMEM = {H_TOP1, ASETNIOP, &state_122, NULL, KC_A, 0, single_dance};
823uint8_t state_123 = IDLE;
824const struct Chord chord_123 PROGMEM = {H_TOP2, ASETNIOP, &state_123, NULL, KC_S, 0, single_dance};
825uint8_t state_124 = IDLE;
826const struct Chord chord_124 PROGMEM = {H_TOP3, ASETNIOP, &state_124, NULL, KC_E, 0, single_dance};
827uint8_t state_125 = IDLE;
828const struct Chord chord_125 PROGMEM = {H_TOP4, ASETNIOP, &state_125, NULL, KC_T, 0, single_dance};
829uint8_t state_126 = IDLE;
830const struct Chord chord_126 PROGMEM = {H_TOP7, ASETNIOP, &state_126, NULL, KC_N, 0, single_dance};
831uint8_t state_127 = IDLE;
832const struct Chord chord_127 PROGMEM = {H_TOP8, ASETNIOP, &state_127, NULL, KC_I, 0, single_dance};
833uint8_t state_128 = IDLE;
834const struct Chord chord_128 PROGMEM = {H_TOP9, ASETNIOP, &state_128, NULL, KC_O, 0, single_dance};
835uint8_t state_129 = IDLE;
836const struct Chord chord_129 PROGMEM = {H_TOP0, ASETNIOP, &state_129, NULL, KC_P, 0, single_dance};
837uint8_t state_130 = IDLE;
838const struct Chord chord_130 PROGMEM = {H_TOP1 + H_TOP2, ASETNIOP, &state_130, NULL, KC_W, 0, single_dance};
839uint8_t state_131 = IDLE;
840const struct Chord chord_131 PROGMEM = {H_TOP2 + H_TOP3, ASETNIOP, &state_131, NULL, KC_D, 0, single_dance};
841uint8_t state_132 = IDLE;
842const struct Chord chord_132 PROGMEM = {H_TOP3 + H_TOP4, ASETNIOP, &state_132, NULL, KC_R, 0, single_dance};
843uint8_t state_133 = IDLE;
844const struct Chord chord_133 PROGMEM = {H_TOP4 + H_TOP7, ASETNIOP, &state_133, NULL, KC_B, 0, single_dance};
845uint8_t state_134 = IDLE;
846const struct Chord chord_134 PROGMEM = {H_TOP7 + H_TOP8, ASETNIOP, &state_134, NULL, KC_H, 0, single_dance};
847uint8_t state_135 = IDLE;
848const struct Chord chord_135 PROGMEM = {H_TOP8 + H_TOP9, ASETNIOP, &state_135, NULL, KC_L, 0, single_dance};
849uint8_t state_136 = IDLE;
850const struct Chord chord_136 PROGMEM = {H_TOP9 + H_TOP0, ASETNIOP, &state_136, NULL, KC_SCOLON, 0, single_dance};
851uint8_t state_137 = IDLE;
852const struct Chord chord_137 PROGMEM = {H_TOP1 + H_TOP3, ASETNIOP, &state_137, NULL, KC_X, 0, single_dance};
853uint8_t state_138 = IDLE;
854const struct Chord chord_138 PROGMEM = {H_TOP2 + H_TOP4, ASETNIOP, &state_138, NULL, KC_C, 0, single_dance};
855uint8_t state_139 = IDLE;
856const struct Chord chord_139 PROGMEM = {H_TOP3 + H_TOP7, ASETNIOP, &state_139, NULL, KC_Y, 0, single_dance};
857uint8_t state_140 = IDLE;
858const struct Chord chord_140 PROGMEM = {H_TOP4 + H_TOP8, ASETNIOP, &state_140, NULL, KC_V, 0, single_dance};
859uint8_t state_141 = IDLE;
860const struct Chord chord_141 PROGMEM = {H_TOP7 + H_TOP9, ASETNIOP, &state_141, NULL, KC_U, 0, single_dance};
861uint8_t state_142 = IDLE;
862const struct Chord chord_142 PROGMEM = {H_TOP1 + H_TOP4, ASETNIOP, &state_142, NULL, KC_F, 0, single_dance};
863uint8_t state_143 = IDLE;
864const struct Chord chord_143 PROGMEM = {H_TOP2 + H_TOP7, ASETNIOP, &state_143, NULL, KC_J, 0, single_dance};
865uint8_t state_144 = IDLE;
866const struct Chord chord_144 PROGMEM = {H_TOP3 + H_TOP8, ASETNIOP, &state_144, NULL, KC_COMMA, 0, single_dance};
867uint8_t state_145 = IDLE;
868const struct Chord chord_145 PROGMEM = {H_TOP4 + H_TOP9, ASETNIOP, &state_145, NULL, KC_G, 0, single_dance};
869uint8_t state_146 = IDLE;
870const struct Chord chord_146 PROGMEM = {H_TOP7 + H_TOP0, ASETNIOP, &state_146, NULL, KC_M, 0, single_dance};
871uint8_t state_147 = IDLE;
872const struct Chord chord_147 PROGMEM = {H_TOP1 + H_TOP7, ASETNIOP, &state_147, NULL, KC_Q, 0, single_dance};
873uint8_t state_148 = IDLE;
874const struct Chord chord_148 PROGMEM = {H_TOP2 + H_TOP8, ASETNIOP, &state_148, NULL, KC_K, 0, single_dance};
875uint8_t state_149 = IDLE;
876const struct Chord chord_149 PROGMEM = {H_TOP3 + H_TOP9, ASETNIOP, &state_149, NULL, KC_MINUS, 0, single_dance};
877uint8_t state_150 = IDLE;
878const struct Chord chord_150 PROGMEM = {H_TOP4 + H_TOP0, ASETNIOP, &state_150, NULL, KC_BSPC, 0, single_dance};
879uint8_t state_151 = IDLE;
880const struct Chord chord_151 PROGMEM = {H_TOP1 + H_TOP8, ASETNIOP, &state_151, NULL, KC_Z, 0, single_dance};
881uint8_t state_152 = IDLE;
882const struct Chord chord_152 PROGMEM = {H_TOP2 + H_TOP9, ASETNIOP, &state_152, NULL, KC_DOT, 0, single_dance};
883uint8_t state_153 = IDLE;
884const struct Chord chord_153 PROGMEM = {H_TOP3 + H_TOP0, ASETNIOP, &state_153, NULL, KC_QUOTE, 0, single_dance};
885uint8_t state_154 = IDLE;
886const struct Chord chord_154 PROGMEM = {H_TOP1 + H_TOP9, ASETNIOP, &state_154, NULL, KC_LBRACKET, 0, single_dance};
887uint8_t state_155 = IDLE;
888const struct Chord chord_155 PROGMEM = {H_TOP2 + H_TOP0, ASETNIOP, &state_155, NULL, KC_RBRACKET, 0, single_dance};
889uint8_t state_156 = IDLE;
890const struct Chord chord_156 PROGMEM = {H_TOP1 + H_TOP0, ASETNIOP, &state_156, NULL, KC_SLASH, 0, single_dance};
891uint8_t state_157 = IDLE;
892const struct Chord chord_157 PROGMEM = {H_TOP5, ASETNIOP, &state_157, NULL, KC_ESC, 0, single_dance};
893uint8_t state_158 = IDLE;
894const struct Chord chord_158 PROGMEM = {H_TOP6, ASETNIOP, &state_158, NULL, KC_DEL, 0, single_dance};
895uint8_t state_159 = IDLE;
896const struct Chord chord_159 PROGMEM = {H_BOT4, ASETNIOP, &state_159, NULL, KC_LSFT, 0, single_dance};
897uint8_t state_160 = IDLE;
898const struct Chord chord_160 PROGMEM = {H_BOT5, ASETNIOP, &state_160, NULL, KC_LCTL, 0, single_dance};
899uint8_t state_161 = IDLE;
900const struct Chord chord_161 PROGMEM = {H_BOT6, ASETNIOP, &state_161, NULL, KC_LALT, 0, single_dance};
901uint8_t state_162 = IDLE;
902uint8_t counter_162 = 0;
903const struct Chord chord_162 PROGMEM = {H_BOT7, ASETNIOP, &state_162, &counter_162, KC_SPACE, ASETNIOP_123, key_layer_dance};
904uint8_t state_163 = IDLE;
905const struct Chord chord_163 PROGMEM = {H_TOP5 + H_TOP6, ASETNIOP, &state_163, NULL, KC_LGUI, 0, single_dance};
906uint8_t state_164 = IDLE;
907const struct Chord chord_164 PROGMEM = {H_TOP1 + H_TOP2 + H_TOP3 + H_TOP4, ASETNIOP, &state_164, NULL, QWERTY, 0, perm_pseudolayer};
908uint8_t state_165 = IDLE;
909const struct Chord chord_165 PROGMEM = {H_BOT4 + H_BOT7, ASETNIOP, &state_165, NULL, ASETNIOP_FN, 0, temp_pseudolayer};
910uint8_t state_166 = IDLE;
911const struct Chord chord_166 PROGMEM = {H_TOP1, ASETNIOP_123, &state_166, NULL, KC_1, 0, single_dance};
912uint8_t state_167 = IDLE;
913const struct Chord chord_167 PROGMEM = {H_TOP2, ASETNIOP_123, &state_167, NULL, KC_2, 0, single_dance};
914uint8_t state_168 = IDLE;
915const struct Chord chord_168 PROGMEM = {H_TOP3, ASETNIOP_123, &state_168, NULL, KC_3, 0, single_dance};
916uint8_t state_169 = IDLE;
917const struct Chord chord_169 PROGMEM = {H_TOP4, ASETNIOP_123, &state_169, NULL, KC_4, 0, single_dance};
918uint8_t state_170 = IDLE;
919const struct Chord chord_170 PROGMEM = {H_TOP7, ASETNIOP_123, &state_170, NULL, KC_7, 0, single_dance};
920uint8_t state_171 = IDLE;
921const struct Chord chord_171 PROGMEM = {H_TOP8, ASETNIOP_123, &state_171, NULL, KC_8, 0, single_dance};
922uint8_t state_172 = IDLE;
923const struct Chord chord_172 PROGMEM = {H_TOP9, ASETNIOP_123, &state_172, NULL, KC_9, 0, single_dance};
924uint8_t state_173 = IDLE;
925const struct Chord chord_173 PROGMEM = {H_TOP0, ASETNIOP_123, &state_173, NULL, KC_0, 0, single_dance};
926uint8_t state_174 = IDLE;
927const struct Chord chord_174 PROGMEM = {H_TOP3 + H_TOP4, ASETNIOP_123, &state_174, NULL, KC_5, 0, single_dance};
928uint8_t state_175 = IDLE;
929const struct Chord chord_175 PROGMEM = {H_TOP4 + H_TOP7, ASETNIOP_123, &state_175, NULL, KC_EQUAL, 0, single_dance};
930uint8_t state_176 = IDLE;
931const struct Chord chord_176 PROGMEM = {H_TOP7 + H_TOP8, ASETNIOP_123, &state_176, NULL, KC_6, 0, single_dance};
932uint8_t state_177 = IDLE;
933const struct Chord chord_177 PROGMEM = {H_TOP8 + H_TOP9, ASETNIOP_123, &state_177, NULL, KC_BSLASH, 0, single_dance};
934uint8_t state_178 = IDLE;
935const struct Chord chord_178 PROGMEM = {H_TOP9 + H_TOP0, ASETNIOP_123, &state_178, NULL, KC_SCOLON, 0, single_dance};
936uint8_t state_179 = IDLE;
937const struct Chord chord_179 PROGMEM = {H_TOP4 + H_TOP0, ASETNIOP_123, &state_179, NULL, KC_BSPC, 0, single_dance};
938uint8_t state_180 = IDLE;
939const struct Chord chord_180 PROGMEM = {H_TOP5, ASETNIOP_123, &state_180, NULL, KC_ESC, 0, single_dance};
940uint8_t state_181 = IDLE;
941const struct Chord chord_181 PROGMEM = {H_TOP6, ASETNIOP_123, &state_181, NULL, KC_DEL, 0, single_dance};
942uint8_t state_182 = IDLE;
943const struct Chord chord_182 PROGMEM = {H_BOT4, ASETNIOP_123, &state_182, NULL, KC_LSFT, 0, single_dance};
944uint8_t state_183 = IDLE;
945const struct Chord chord_183 PROGMEM = {H_BOT5, ASETNIOP_123, &state_183, NULL, KC_LCTL, 0, single_dance};
946uint8_t state_184 = IDLE;
947const struct Chord chord_184 PROGMEM = {H_BOT6, ASETNIOP_123, &state_184, NULL, KC_LALT, 0, single_dance};
948uint8_t state_185 = IDLE;
949const struct Chord chord_185 PROGMEM = {H_TOP5 + H_TOP6, ASETNIOP_123, &state_185, NULL, KC_LGUI, 0, single_dance};
950uint8_t state_186 = IDLE;
951const struct Chord chord_186 PROGMEM = {H_TOP1, ASETNIOP_FN, &state_186, NULL, KC_HOME, 0, single_dance};
952uint8_t state_187 = IDLE;
953const struct Chord chord_187 PROGMEM = {H_TOP2, ASETNIOP_FN, &state_187, NULL, KC_PGDN, 0, single_dance};
954uint8_t state_188 = IDLE;
955const struct Chord chord_188 PROGMEM = {H_TOP3, ASETNIOP_FN, &state_188, NULL, KC_PGUP, 0, single_dance};
956uint8_t state_189 = IDLE;
957const struct Chord chord_189 PROGMEM = {H_TOP4, ASETNIOP_FN, &state_189, NULL, KC_END, 0, single_dance};
958uint8_t state_190 = IDLE;
959const struct Chord chord_190 PROGMEM = {H_TOP7, ASETNIOP_FN, &state_190, NULL, KC_LEFT, 0, single_dance};
960uint8_t state_191 = IDLE;
961const struct Chord chord_191 PROGMEM = {H_TOP8, ASETNIOP_FN, &state_191, NULL, KC_DOWN, 0, single_dance};
962uint8_t state_192 = IDLE;
963const struct Chord chord_192 PROGMEM = {H_TOP9, ASETNIOP_FN, &state_192, NULL, KC_UP, 0, single_dance};
964uint8_t state_193 = IDLE;
965const struct Chord chord_193 PROGMEM = {H_TOP0, ASETNIOP_FN, &state_193, NULL, KC_RIGHT, 0, single_dance};
966uint8_t state_194 = IDLE;
967const struct Chord chord_194 PROGMEM = {H_TOP1 + H_TOP2, ASETNIOP_FN, &state_194, NULL, KC_F1, 0, single_dance};
968uint8_t state_195 = IDLE;
969const struct Chord chord_195 PROGMEM = {H_TOP2 + H_TOP3, ASETNIOP_FN, &state_195, NULL, KC_F2, 0, single_dance};
970uint8_t state_196 = IDLE;
971const struct Chord chord_196 PROGMEM = {H_TOP3 + H_TOP4, ASETNIOP_FN, &state_196, NULL, KC_F3, 0, single_dance};
972uint8_t state_197 = IDLE;
973const struct Chord chord_197 PROGMEM = {H_TOP4 + H_TOP7, ASETNIOP_FN, &state_197, NULL, KC_F4, 0, single_dance};
974uint8_t state_198 = IDLE;
975const struct Chord chord_198 PROGMEM = {H_TOP7 + H_TOP8, ASETNIOP_FN, &state_198, NULL, KC_F5, 0, single_dance};
976uint8_t state_199 = IDLE;
977const struct Chord chord_199 PROGMEM = {H_TOP8 + H_TOP9, ASETNIOP_FN, &state_199, NULL, KC_F6, 0, single_dance};
978uint8_t state_200 = IDLE;
979const struct Chord chord_200 PROGMEM = {H_TOP9 + H_TOP0, ASETNIOP_FN, &state_200, NULL, KC_F7, 0, single_dance};
980uint8_t state_201 = IDLE;
981const struct Chord chord_201 PROGMEM = {H_TOP1 + H_TOP3, ASETNIOP_FN, &state_201, NULL, KC_F10, 0, single_dance};
982uint8_t state_202 = IDLE;
983const struct Chord chord_202 PROGMEM = {H_TOP8 + H_TOP0, ASETNIOP_FN, &state_202, NULL, KC_F8, 0, single_dance};
984uint8_t state_203 = IDLE;
985const struct Chord chord_203 PROGMEM = {H_TOP1 + H_TOP4, ASETNIOP_FN, &state_203, NULL, KC_F11, 0, single_dance};
986uint8_t state_204 = IDLE;
987const struct Chord chord_204 PROGMEM = {H_TOP7 + H_TOP0, ASETNIOP_FN, &state_204, NULL, KC_F9, 0, single_dance};
988uint8_t state_205 = IDLE;
989const struct Chord chord_205 PROGMEM = {H_TOP1 + H_TOP7, ASETNIOP_FN, &state_205, NULL, KC_F12, 0, single_dance};
990uint8_t state_206 = IDLE;
991const struct Chord chord_206 PROGMEM = {H_TOP4 + H_TOP0, ASETNIOP_FN, &state_206, NULL, KC_BSPC, 0, single_dance};
992uint8_t state_207 = IDLE;
993const struct Chord chord_207 PROGMEM = {H_TOP5, ASETNIOP_FN, &state_207, NULL, KC_ESC, 0, single_dance};
994uint8_t state_208 = IDLE;
995const struct Chord chord_208 PROGMEM = {H_TOP6, ASETNIOP_FN, &state_208, NULL, KC_DEL, 0, single_dance};
996uint8_t state_209 = IDLE;
997const struct Chord chord_209 PROGMEM = {H_BOT4, ASETNIOP_FN, &state_209, NULL, KC_LSFT, 0, single_dance};
998uint8_t state_210 = IDLE;
999const struct Chord chord_210 PROGMEM = {H_BOT5, ASETNIOP_FN, &state_210, NULL, KC_LCTL, 0, single_dance};
1000uint8_t state_211 = IDLE;
1001const struct Chord chord_211 PROGMEM = {H_BOT6, ASETNIOP_FN, &state_211, NULL, KC_LALT, 0, single_dance};
1002uint8_t state_212 = IDLE;
1003const struct Chord chord_212 PROGMEM = {H_TOP5 + H_TOP6, ASETNIOP_FN, &state_212, NULL, KC_LGUI, 0, single_dance};
1004
1005const struct Chord* const list_of_chords[] PROGMEM = {
1006 &chord_0, &chord_1, &chord_2, &chord_3, &chord_4, &chord_5, &chord_6, &chord_7, &chord_8, &chord_9, &chord_10, &chord_11, &chord_12, &chord_13, &chord_14, &chord_15, &chord_16, &chord_17, &chord_18, &chord_19, &chord_20, &chord_21, &chord_22, &chord_23, &chord_24, &chord_25, &chord_26, &chord_27, &chord_28, &chord_29, &chord_30, &chord_31, &chord_32, &chord_33, &chord_34, &chord_35, &chord_36, &chord_37, &chord_38, &chord_39, &chord_40, &chord_41, &chord_42, &chord_43, &chord_44, &chord_45, &chord_46, &chord_47, &chord_48, &chord_49, &chord_50, &chord_51, &chord_52, &chord_53, &chord_54, &chord_55, &chord_56, &chord_57, &chord_58, &chord_59, &chord_60, &chord_61, &chord_62, &chord_63, &chord_64, &chord_65, &chord_66, &chord_67, &chord_68, &chord_69, &chord_70, &chord_71, &chord_72, &chord_73, &chord_74, &chord_75, &chord_76, &chord_77, &chord_78, &chord_79, &chord_80, &chord_81, &chord_82, &chord_83, &chord_84, &chord_85, &chord_86, &chord_87, &chord_88, &chord_89, &chord_90, &chord_91, &chord_92, &chord_93, &chord_94, &chord_95, &chord_96, &chord_97, &chord_98, &chord_99, &chord_100, &chord_101, &chord_102, &chord_103, &chord_104, &chord_105, &chord_106, &chord_107, &chord_108, &chord_109, &chord_110, &chord_111, &chord_112, &chord_113, &chord_114, &chord_115, &chord_116, &chord_117, &chord_118, &chord_119, &chord_120, &chord_121, &chord_122, &chord_123, &chord_124, &chord_125, &chord_126, &chord_127, &chord_128, &chord_129, &chord_130, &chord_131, &chord_132, &chord_133, &chord_134, &chord_135, &chord_136, &chord_137, &chord_138, &chord_139, &chord_140, &chord_141, &chord_142, &chord_143, &chord_144, &chord_145, &chord_146, &chord_147, &chord_148, &chord_149, &chord_150, &chord_151, &chord_152, &chord_153, &chord_154, &chord_155, &chord_156, &chord_157, &chord_158, &chord_159, &chord_160, &chord_161, &chord_162, &chord_163, &chord_164, &chord_165, &chord_166, &chord_167, &chord_168, &chord_169, &chord_170, &chord_171, &chord_172, &chord_173, &chord_174, &chord_175, &chord_176, &chord_177, &chord_178, &chord_179, &chord_180, &chord_181, &chord_182, &chord_183, &chord_184, &chord_185, &chord_186, &chord_187, &chord_188, &chord_189, &chord_190, &chord_191, &chord_192, &chord_193, &chord_194, &chord_195, &chord_196, &chord_197, &chord_198, &chord_199, &chord_200, &chord_201, &chord_202, &chord_203, &chord_204, &chord_205, &chord_206, &chord_207, &chord_208, &chord_209, &chord_210, &chord_211, &chord_212
1007};
1008
1009const uint16_t** const leader_triggers PROGMEM = NULL;
1010void (*leader_functions[]) (void) = {};
1011
1012#define NUMBER_OF_CHORDS 213
1013#define NUMBER_OF_LEADER_COMBOS 0
1014
1015bool are_hashed_keycodes_in_sound(HASH_TYPE keycodes_hash, HASH_TYPE sound) {
1016 return (keycodes_hash & sound) == keycodes_hash;
1017}
1018
1019uint8_t keycode_to_index(uint16_t keycode) {
1020 return keycode - FIRST_INTERNAL_KEYCODE;
1021}
1022
1023void sound_keycode_array(uint16_t keycode) {
1024 uint8_t index = keycode_to_index(keycode);
1025 keycode_index++;
1026 keycodes_buffer_array[index] = keycode_index;
1027}
1028
1029void silence_keycode_hash_array(HASH_TYPE keycode_hash) {
1030 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
1031 bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash;
1032 if (index_in_hash) {
1033 uint8_t current_val = keycodes_buffer_array[i];
1034 keycodes_buffer_array[i] = 0;
1035 for (int j = 0; j < NUMBER_OF_KEYS; j++) {
1036 if (keycodes_buffer_array[j] > current_val) {
1037 keycodes_buffer_array[j]--;
1038 }
1039 }
1040 keycode_index--;
1041 }
1042 }
1043}
1044
1045bool are_hashed_keycodes_in_array(HASH_TYPE keycode_hash) {
1046 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
1047 bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash;
1048 bool index_in_array = (bool) keycodes_buffer_array[i];
1049 if (index_in_hash && !index_in_array) {
1050 return false;
1051 }
1052 }
1053 return true;
1054}
1055
1056void kill_one_shots(void) {
1057 struct Chord chord_storage;
1058 struct Chord* chord_ptr;
1059 struct Chord* chord;
1060
1061 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1062 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1063 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1064 chord = &chord_storage;
1065
1066 if (*chord->state == IN_ONE_SHOT) {
1067 *chord->state = RESTART;
1068 chord->function(chord);
1069 if (*chord->state == RESTART) {
1070 *chord->state = IDLE;
1071 }
1072 }
1073 }
1074}
1075
1076void process_finished_dances(void) {
1077 struct Chord chord_storage;
1078 struct Chord* chord_ptr;
1079 struct Chord* chord;
1080
1081 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1082 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1083 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1084 chord = &chord_storage;
1085
1086 if (*chord->state == ACTIVATED) {
1087 *chord->state = PRESS_FROM_ACTIVE;
1088 chord->function(chord);
1089 if (a_key_went_through) {
1090 kill_one_shots();
1091 }
1092 dance_timer = timer_read();
1093 } else if (*chord->state == IDLE_IN_DANCE) {
1094 *chord->state = FINISHED;
1095 chord->function(chord);
1096 if (*chord->state == FINISHED) {
1097 *chord->state = RESTART;
1098 if (*chord->state == RESTART) {
1099 *chord->state = IDLE;
1100 }
1101 }
1102 } else if (*chord->state == PRESS_FROM_ACTIVE) {
1103 *chord->state = FINISHED_FROM_ACTIVE;
1104 chord->function(chord);
1105 if (a_key_went_through) {
1106 kill_one_shots();
1107 }
1108 dance_timer = timer_read();
1109 }
1110 }
1111}
1112
1113uint8_t keycodes_buffer_array_min(uint8_t* first_keycode_index) {
1114 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
1115 if (keycodes_buffer_array[i] == 1) {
1116 if (first_keycode_index != NULL) {
1117 *first_keycode_index = (uint8_t) i;
1118 }
1119 return 1;
1120 }
1121 }
1122 return 0;
1123}
1124
1125void remove_subchords(void) {
1126 struct Chord chord_storage;
1127 struct Chord* chord_ptr;
1128 struct Chord* chord;
1129
1130 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1131 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1132 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1133 chord = &chord_storage;
1134
1135 if (!(*chord->state == READY || *chord->state == READY_IN_DANCE || *chord->state == READY_LOCKED)) {
1136 continue;
1137 }
1138
1139 struct Chord chord_storage_2;
1140 struct Chord* chord_ptr_2;
1141 struct Chord* chord_2;
1142 for (int j = 0; j < NUMBER_OF_CHORDS; j++) {
1143 if (i == j) {continue;}
1144
1145 chord_ptr_2 = (struct Chord*) pgm_read_word (&list_of_chords[j]);
1146 memcpy_P(&chord_storage_2, chord_ptr_2, sizeof(struct Chord));
1147 chord_2 = &chord_storage_2;
1148
1149 if (are_hashed_keycodes_in_sound(chord_2->keycodes_hash, chord->keycodes_hash)) {
1150 if (*chord_2->state == READY) {
1151 *chord_2->state = IDLE;
1152 }
1153 if (*chord_2->state == READY_IN_DANCE) {
1154 *chord_2->state = IDLE_IN_DANCE;
1155 }
1156 if (*chord_2->state == READY_LOCKED) {
1157 *chord_2->state = LOCKED;
1158 }
1159 }
1160 }
1161 }
1162}
1163
1164void process_ready_chords(void) {
1165 uint8_t first_keycode_index = 0;
1166 while (keycodes_buffer_array_min(&first_keycode_index)) {
1167 // find ready chords
1168 struct Chord chord_storage;
1169 struct Chord* chord_ptr;
1170 struct Chord* chord;
1171
1172 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1173 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1174 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1175 chord = &chord_storage;
1176
1177 // if the chord does not contain the first keycode
1178 bool contains_first_keycode = ((uint32_t) 1 << first_keycode_index) & chord->keycodes_hash;
1179 if (!contains_first_keycode) {
1180 continue;
1181 }
1182
1183 if (!are_hashed_keycodes_in_array(chord->keycodes_hash)){
1184 continue;
1185 }
1186
1187 if (*chord->state == LOCKED) {
1188 *chord->state = READY_LOCKED;
1189 continue;
1190 }
1191
1192 if (!(chord->pseudolayer == current_pseudolayer || chord->pseudolayer == ALWAYS_ON)) {
1193 continue;
1194 }
1195
1196 if (*chord->state == IDLE) {
1197 *chord->state = READY;
1198 continue;
1199 }
1200
1201 if (*chord->state == IDLE_IN_DANCE) {
1202 *chord->state = READY_IN_DANCE;
1203 }
1204 }
1205
1206 // remove subchords
1207 remove_subchords();
1208
1209 // execute logic
1210 // this should be only one chord
1211 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1212 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1213 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1214 chord = &chord_storage;
1215
1216 if (*chord->state == READY_LOCKED) {
1217 *chord->state = RESTART;
1218 chord->function(chord);
1219 if (*chord->state == RESTART) {
1220 *chord->state = IDLE;
1221 }
1222 break;
1223 }
1224
1225 if (*chord->state == READY || *chord->state == READY_IN_DANCE) {
1226 if (last_chord && last_chord != chord) {
1227 process_finished_dances();
1228 }
1229
1230 bool lock_next_prev_state = lock_next;
1231
1232 *chord->state = ACTIVATED;
1233 chord->function(chord);
1234 dance_timer = timer_read();
1235
1236 if (lock_next && lock_next == lock_next_prev_state) {
1237 lock_next = false;
1238 *chord->state = PRESS_FROM_ACTIVE;
1239 chord->function(chord);
1240 if (*chord->state == PRESS_FROM_ACTIVE) {
1241 *chord->state = LOCKED;
1242 }
1243 if (a_key_went_through) {
1244 kill_one_shots();
1245 }
1246 }
1247 break;
1248 }
1249 }
1250
1251 // silence notes
1252 silence_keycode_hash_array(chord->keycodes_hash);
1253 }
1254}
1255
1256void deactivate_active_chords(uint16_t keycode) {
1257 HASH_TYPE hash = (HASH_TYPE)1 << (keycode - SAFE_RANGE);
1258 bool broken;
1259 struct Chord chord_storage;
1260 struct Chord* chord_ptr;
1261 struct Chord* chord;
1262
1263 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1264 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1265 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1266 chord = &chord_storage;
1267
1268 broken = are_hashed_keycodes_in_sound(hash, chord->keycodes_hash);
1269 if (!broken) {
1270 continue;
1271 }
1272
1273 switch (*chord->state) {
1274 case ACTIVATED:
1275 *chord->state = DEACTIVATED;
1276 chord->function(chord);
1277
1278 if (*chord->state == DEACTIVATED) {
1279 dance_timer = timer_read();
1280 *chord->state = IDLE_IN_DANCE;
1281 }
1282 if (*chord->state != IN_ONE_SHOT) {
1283 kill_one_shots();
1284 }
1285 break;
1286 case PRESS_FROM_ACTIVE:
1287 case FINISHED_FROM_ACTIVE:
1288 *chord->state = RESTART;
1289 chord->function(chord);
1290 if (*chord->state == RESTART) {
1291 *chord->state = IDLE;
1292 }
1293 kill_one_shots();
1294 break;
1295 default:
1296 break;
1297 }
1298 }
1299
1300}
1301
1302void process_command(void) {
1303 command_mode = 0;
1304 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
1305 if (command_buffer[i]) {
1306 register_code(command_buffer[i]);
1307 }
1308 send_keyboard_report();
1309 }
1310 wait_ms(TAP_TIMEOUT);
1311 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
1312 if (command_buffer[i]) {
1313 unregister_code(command_buffer[i]);
1314 }
1315 send_keyboard_report();
1316 }
1317 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
1318 command_buffer[i] = 0;
1319 }
1320 command_ind = 0;
1321}
1322
1323void process_leader(void) {
1324 in_leader_mode = false;
1325 for (int i = 0; i < NUMBER_OF_LEADER_COMBOS; i++) {
1326 uint16_t trigger[LEADER_MAX_LENGTH];
1327 memcpy_P(trigger, leader_triggers[i], LEADER_MAX_LENGTH * sizeof(uint16_t));
1328
1329 if (identical(leader_buffer, trigger)) {
1330 (*leader_functions[i])();
1331 break;
1332 }
1333 }
1334 for (int i = 0; i < LEADER_MAX_LENGTH; i++) {
1335 leader_buffer[i] = 0;
1336 }
1337}
1338
1339bool process_record_user(uint16_t keycode, keyrecord_t *record) {
1340 if (keycode < FIRST_INTERNAL_KEYCODE || keycode > LAST_INTERNAL_KEYCODE) {
1341 return true;
1342 }
1343
1344 if (record->event.pressed) {
1345 sound_keycode_array(keycode);
1346 } else {
1347 process_ready_chords();
1348 deactivate_active_chords(keycode);
1349 }
1350 chord_timer = timer_read();
1351 leader_timer = timer_read();
1352
1353 return false;
1354}
1355
1356void matrix_scan_user(void) {
1357 bool chord_timer_expired = timer_elapsed(chord_timer) > CHORD_TIMEOUT;
1358 if (chord_timer_expired && keycodes_buffer_array_min(NULL)) {
1359 process_ready_chords();
1360 }
1361
1362 bool dance_timer_expired = timer_elapsed(dance_timer) > DANCE_TIMEOUT;
1363 if (dance_timer_expired) { // would love to have && in_dance but not sure how
1364 process_finished_dances();
1365 }
1366
1367 bool in_command_mode = command_mode == 2;
1368 if (in_command_mode) {
1369 process_command();
1370 }
1371
1372 bool leader_timer_expired = timer_elapsed(leader_timer) > LEADER_TIMEOUT;
1373 if (leader_timer_expired && in_leader_mode) {
1374 process_leader();
1375 }
1376
1377}
1378
1379void clear(const struct Chord* self) {
1380 if (*self->state == ACTIVATED) {
1381 // kill all chords
1382 struct Chord chord_storage;
1383 struct Chord* chord_ptr;
1384 struct Chord* chord;
1385
1386 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1387 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1388 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1389 chord = &chord_storage;
1390
1391 *chord->state = IDLE;
1392
1393 if (chord->counter) {
1394 *chord->counter = 0;
1395 }
1396 }
1397
1398 // clear keyboard
1399 clear_keyboard();
1400 send_keyboard_report();
1401
1402 // switch to default pseudolayer
1403 current_pseudolayer = DEFAULT_PSEUDOLAYER;
1404
1405 // clear all keyboard states
1406 lock_next = false;
1407 autoshift_mode = true;
1408 command_mode = 0;
1409 in_leader_mode = false;
1410 leader_ind = 0;
1411 dynamic_macro_mode = false;
1412 a_key_went_through = false;
1413
1414 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
1415 dynamic_macro_buffer[i] = 0;
1416 }
1417 }
1418} \ No newline at end of file
diff --git a/keyboards/butterstick/keymaps/dennytom/keymap_def.json b/keyboards/butterstick/keymaps/dennytom/keymap_def.json
new file mode 100644
index 000000000..16f02ca52
--- /dev/null
+++ b/keyboards/butterstick/keymaps/dennytom/keymap_def.json
@@ -0,0 +1,309 @@
1{
2 "keys": [
3 "TOP1", "TOP2", "TOP3", "TOP4", "TOP5", "TOP6", "TOP7", "TOP8", "TOP9", "TOP0",
4 "BOT1", "BOT2", "BOT3", "BOT4", "BOT5", "BOT6", "BOT7", "BOT8", "BOT9", "BOT0"
5 ],
6 "parameters": {
7 "layout_function_name": "LAYOUT_butter",
8 "chord_timeout": 100,
9 "dance_timeout": 200,
10 "leader_timeout": 750,
11 "tap_timeout": 50,
12 "command_max_length": 5,
13 "leader_max_length": 5,
14 "dynamic_macro_max_length": 20,
15 "string_max_length": 16,
16 "long_press_multiplier": 3,
17 "default_pseudolayer": "QWERTY"
18 },
19 "layers": [
20 {
21 "type": "auto"
22 }
23 ],
24 "chord_sets": [
25 {
26 "name": "rows",
27 "chords": [
28 ["TOP1"], ["TOP2"], ["TOP3"], ["TOP4"], ["TOP5"], ["TOP6"], ["TOP7"], ["TOP8"], ["TOP9"], ["TOP0"],
29 ["TOP1", "BOT1"], ["TOP2", "BOT2"], ["TOP3", "BOT3"], ["TOP4", "BOT4"], ["TOP5", "BOT5"], ["TOP6", "BOT6"], ["TOP7", "BOT7"], ["TOP8", "BOT8"], ["TOP9", "BOT9"], ["TOP0", "BOT0"],
30 ["BOT1"], ["BOT2"], ["BOT3"], ["BOT4"], ["BOT5"], ["BOT6"], ["BOT7"], ["BOT8"], ["BOT9"], ["BOT0"]
31 ]
32 },
33 {
34 "name": "cols",
35 "chords": [
36 ["TOP1", "TOP2"], ["TOP2", "TOP3"], ["TOP3", "TOP4"], ["TOP4", "TOP5"], ["TOP5", "TOP6"], ["TOP6", "TOP7"], ["TOP7", "TOP8"], ["TOP8", "TOP9"], ["TOP9", "TOP0"],
37 ["TOP1", "TOP2", "BOT1", "BOT2"], ["TOP2", "TOP3", "BOT2", "BOT3"], ["TOP3", "TOP4", "BOT3", "BOT4"], ["TOP4", "TOP5", "BOT4", "BOT5"], ["TOP5", "TOP6", "BOT5", "BOT6"], ["TOP6", "TOP7", "BOT6", "BOT7"], ["TOP7", "TOP8", "BOT7", "BOT8"], ["TOP8", "TOP9", "BOT8", "BOT9"], ["TOP9", "TOP0", "BOT9", "BOT0"],
38 ["BOT1", "BOT2"], ["BOT2", "BOT3"], ["BOT3", "BOT4"], ["BOT4", "BOT5"], ["BOT5", "BOT6"], ["BOT6", "BOT7"], ["BOT7", "BOT8"], ["BOT8", "BOT9"], ["BOT9", "BOT0"]
39 ]
40 },
41 {
42 "name": "asetniop",
43 "chords": [
44 ["TOP1"], ["TOP2"], ["TOP3"], ["TOP4"], ["TOP7"], ["TOP8"], ["TOP9"], ["TOP0"],
45 ["TOP1", "TOP2"], ["TOP2", "TOP3"], ["TOP3", "TOP4"], ["TOP4", "TOP7"], ["TOP7", "TOP8"], ["TOP8", "TOP9"], ["TOP9", "TOP0"],
46 ["TOP1", "TOP3"], ["TOP2", "TOP4"], ["TOP3", "TOP7"], ["TOP4", "TOP8"], ["TOP7", "TOP9"], ["TOP8", "TOP0"],
47 ["TOP1", "TOP4"], ["TOP2", "TOP7"], ["TOP3", "TOP8"], ["TOP4", "TOP9"], ["TOP7", "TOP0"],
48 ["TOP1", "TOP7"], ["TOP2", "TOP8"], ["TOP3", "TOP9"], ["TOP4", "TOP0"],
49 ["TOP1", "TOP8"], ["TOP2", "TOP9"], ["TOP3", "TOP0"],
50 ["TOP1", "TOP9"], ["TOP2", "TOP0"],
51 ["TOP1", "TOP0"]
52 ]
53 }
54 ],
55 "pseudolayers": [
56 {
57 "name": "ALWAYS_ON",
58 "chords": [
59 {
60 "type": "chord_set",
61 "set": "cols",
62 "keycodes": [
63 " ", " ", " ", " ", " ", " ", " ", " ", " ",
64 "LOCK", " AT", " ", " ", " CMD", " ", " ", " ", " ",
65 " ", " ", " ", " ", " ", " ", " ", " ", " "
66 ]
67 },
68 {
69 "type": "visual",
70 "chord": [
71 "X", "X", " ", " ", " ", " ", " ", " ", "X", "X",
72 "X", "X", " ", " ", " ", " ", " ", " ", "X", "X"
73 ],
74 "keycode": "CLEAR_KB"
75 }
76 ]
77 },
78 {
79 "name": "QWERTY",
80 "chords": [
81 {
82 "type": "chord_set",
83 "set": "rows",
84 "keycodes": [
85 "AS(Q)", "AS(W)", "AS(E)", "AS(R)", "AS(T)", "AS(Y)", "AS(U)", "AS(I)", "AS(O)", "AS(P)",
86 "AS(A)", "AS(S)", "AS(D)", "AS(F)", "AS(G)", "AS(H)", "AS(J)", "AS(K)", "AS(L)", "AS(;)",
87 "AS(Z)", "AS(X)", "AS(C)", "AS(V)", "AS(B)", "AS(N)", "AS(M)", "AS(,)", "AS(.)", "AS(/)"
88 ]
89 },
90 {
91 "type": "chord_set",
92 "set": "cols",
93 "keycodes": [
94 " ESC", "MO(MOV)", " TAB", " ", "O(RGUI)", " ", " INS", " DEL", " BSPC",
95 " ", " ", " ", " ", " ", " ", " ", " ", " ENTER",
96 "O(LSFT)", "O(LCTL)", "O(LALT)", "O(NUM)", "O(LGUI)", "O(NUM)", "O(RALT)", "O(RCTL)", "O(RSFT)"
97 ]
98 },
99 {
100 "type": "simple",
101 "chord": ["BOT1", "BOT0"],
102 "keycode": "SPACE"
103 },
104 {
105 "type": "visual",
106 "chord": [
107 "X", "X", "X", "X", " ", " ", " ", " ", " ", " ",
108 " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
109 ],
110 "keycode": "MO(MOUSE)"
111 },
112 {
113 "type": "visual",
114 "chord": [
115 "X", "X", "X", "X", " ", " ", "X", "X", "X", "X",
116 " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
117 ],
118 "keycode": "DF(ASETNIOP)"
119 }
120 ]
121 },
122 {
123 "name": "NUM",
124 "chords": [
125 {
126 "type": "chord_set",
127 "set": "rows",
128 "keycodes": [
129 "AS(1)", "AS(2)", "AS(3)", "AS(4)", "AS(5)", "AS(6)", "AS(7)", "AS(8)", "AS(9)", "AS(0)",
130 " F1", " F2", " F3", " F4", " F5", " F6", " F7", " F8", " F9", " F10",
131 "AS(`)", "AS(-)", "AS(=)", "AS([)", "AS(])", "AS(\\)", "AS(')", " ", " F11", " F12"
132 ]
133 },
134 {
135 "type": "chord_set",
136 "set": "cols",
137 "keycodes": [
138 " ESC", " ", " TAB", " ", "O(RGUI)", " ", " INS", " DEL", " BSPC",
139 " ", " ", " ", " ", " ", " ", " ", " ", " ENTER",
140 "O(LSFT)", "O(LCTL)", "O(LALT)", " ", "O(LGUI)", " ", "O(RALT)", "O(RCTL)", " O(RSFT)"
141 ]
142 },
143 {
144 "type": "simple",
145 "chord": ["BOT1", "BOT0"],
146 "keycode": "SPACE"
147 }
148 ]
149 },
150 {
151 "name": "MOV",
152 "chords": [
153 {
154 "type": "chord_set",
155 "set": "rows",
156 "keycodes": [
157 " ", " ", " ", " ", " ", " ", " HOME", " UP", " END", " PGUP",
158 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
159 " ", " ", " LSFT", " LCTL", " LALT", " LGUI", " LEFT", " DOWN", "RIGHT", " PGDN"
160 ]
161 }
162 ]
163 },
164 {
165 "name": "MOUSE",
166 "chords": [
167 {
168 "type": "chord_set",
169 "set": "rows",
170 "keycodes": [
171 " ", " ", " ", " ", " ", " ", " BTN1", " MS_U", " BTN2", " WH_U",
172 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
173 " ", " ", " LSFT", " LCTL", " LALT", " LGUI", " MS_L", " MS_D", " MS_R", " WH_D"
174 ]
175 }
176 ]
177 },
178 {
179 "name": "ASETNIOP",
180 "chords": [
181 {
182 "type": "chord_set",
183 "set": "asetniop",
184 "keycodes": [
185 "A", "S", "E", "T", "N", "I", "O", "P",
186 "W", "D", "R", "B", "H", "L", ";",
187 "X", "C", "Y", "V", "U", "",
188 "F", "J", ",", "G", "M",
189 "Q", "K", "-", "BSPC",
190 "Z", ".", "'",
191 "[", "]",
192 "/"
193 ]
194 },
195 {
196 "type": "chord_set",
197 "set": "rows",
198 "keycodes": [
199 " ", " ", " ", " ", " ESC", " DEL", " ", " ", " ", " ",
200 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
201 " ", " ", " ", "LSFT", "LCTL", "LALT", "KL(SPACE, ASETNIOP_123)", "", "", ""
202 ]
203 },
204 {
205 "type": "chord_set",
206 "set": "cols",
207 "keycodes": [
208 " ", " ", " ", " ", "LGUI", " ", " ", " ", " ",
209 " ", " ", " ", " ", " ", " ", " ", " ", " ",
210 " ", " ", " ", " ", " ", " ", " ", " ", " "
211 ]
212 },
213 {
214 "type": "visual",
215 "chord": [
216 "X", "X", "X", "X", " ", " ", " ", " ", " ", " ",
217 " ", " ", " ", " ", " ", " ", " ", " ", " ", " "
218 ],
219 "keycode": "DF(QWERTY)"
220 },
221 {
222 "type": "visual",
223 "chord": [
224 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
225 " ", " ", " ", "X", " ", " ", "X", " ", " ", " "
226 ],
227 "keycode": "MO(ASETNIOP_FN)"
228 }
229 ]
230 },
231 {
232 "name": "ASETNIOP_123",
233 "chords": [
234 {
235 "type": "chord_set",
236 "set": "asetniop",
237 "keycodes": [
238 "1", "2", "3", "4", "7", "8", "9", "0",
239 " ", " ", "5", "=", "6", "\\", ";",
240 " ", " ", " ", " ", " ", " ",
241 " ", " ", " ", " ", " ",
242 " ", " ", " ", "BSPC",
243 " ", " ", " ",
244 " ", " ",
245 " "
246 ]
247 },
248 {
249 "type": "chord_set",
250 "set": "rows",
251 "keycodes": [
252 " ", " ", " ", " ", " ESC", " DEL", " ", " ", " ", " ",
253 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
254 " ", " ", " ", "LSFT", "LCTL", "LALT", " ", " ", " ", " "
255 ]
256 },
257 {
258 "type": "chord_set",
259 "set": "cols",
260 "keycodes": [
261 " ", " ", " ", " ", "LGUI", " ", " ", " ", " ",
262 " ", " ", " ", " ", " ", " ", " ", " ", " ",
263 " ", " ", " ", " ", " ", " ", " ", " ", " "
264 ]
265 }
266 ]
267 },
268 {
269 "name": "ASETNIOP_FN",
270 "chords": [
271 {
272 "type": "chord_set",
273 "set": "asetniop",
274 "keycodes": [
275 "HOME", "PGDN", "PGUP", " END", "LEFT", "DOWN", " UP", "RIGHT",
276 " F1", " F2", " F3", " F4", " F5", " F6", " F7",
277 " F10", " ", " ", " ", " ", " F8",
278 " F11", " ", " ", " ", " F9",
279 " F12", " ", " ", "BSPC",
280 " ", " ", " ",
281 " ", " ",
282 " "
283 ]
284 },
285 {
286 "type": "chord_set",
287 "set": "rows",
288 "keycodes": [
289 " ", " ", " ", " ", " ESC", " DEL", " ", " ", " ", " ",
290 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ",
291 " ", " ", " ", "LSFT", "LCTL", "LALT", " ", " ", " ", " "
292 ]
293 },
294 {
295 "type": "chord_set",
296 "set": "cols",
297 "keycodes": [
298 " ", " ", " ", " ", "LGUI", " ", " ", " ", " ",
299 " ", " ", " ", " ", " ", " ", " ", " ", " ",
300 " ", " ", " ", " ", " ", " ", " ", " ", " "
301 ]
302 }
303 ]
304 }
305 ],
306 "leader_sequences": [],
307 "extra_code": "",
308 "extra_dependencies": []
309} \ No newline at end of file
diff --git a/keyboards/butterstick/keymaps/dennytom/rules.mk b/keyboards/butterstick/keymaps/dennytom/rules.mk
new file mode 100644
index 000000000..1155f72c0
--- /dev/null
+++ b/keyboards/butterstick/keymaps/dennytom/rules.mk
@@ -0,0 +1,8 @@
1MOUSEKEY_ENABLE = yes
2EXTRAKEY_ENABLE = yes
3CONSOLE_ENABLE = no
4# COMMAND_ENABLE = no
5NKRO_ENABLE = yes
6
7TMPVAR := $(SRC)
8SRC = $(filter-out sten.c, $(TMPVAR)) \ No newline at end of file
diff --git a/keyboards/georgi/keymaps/dennytom/README.md b/keyboards/georgi/keymaps/dennytom/README.md
new file mode 100644
index 000000000..14bc1d204
--- /dev/null
+++ b/keyboards/georgi/keymaps/dennytom/README.md
@@ -0,0 +1,11 @@
1# # Dennytom's Georgi Layout
2
3This keymap is using a custom chording engine. Head out to my (DennyTom) user space to find the source files and details.
4
5To make a real keymap from the JSON file, run
6
7```sh
8python3 parser.py keymap_def.json keymap.c
9```
10
11Likely will change with use. I enjoy the modifiers on the "home row". \ No newline at end of file
diff --git a/keyboards/georgi/keymaps/dennytom/keymap.c b/keyboards/georgi/keymaps/dennytom/keymap.c
new file mode 100644
index 000000000..2e0191774
--- /dev/null
+++ b/keyboards/georgi/keymaps/dennytom/keymap.c
@@ -0,0 +1,1208 @@
1#include QMK_KEYBOARD_H
2
3#define H_TOP1 ((HASH_TYPE) 1 << 0)
4#define H_TOP2 ((HASH_TYPE) 1 << 1)
5#define H_TOP3 ((HASH_TYPE) 1 << 2)
6#define H_TOP4 ((HASH_TYPE) 1 << 3)
7#define H_TOP5 ((HASH_TYPE) 1 << 4)
8#define H_TOP6 ((HASH_TYPE) 1 << 5)
9#define H_TOP7 ((HASH_TYPE) 1 << 6)
10#define H_TOP8 ((HASH_TYPE) 1 << 7)
11#define H_TOP9 ((HASH_TYPE) 1 << 8)
12#define H_TOP10 ((HASH_TYPE) 1 << 9)
13#define H_TOP11 ((HASH_TYPE) 1 << 10)
14#define H_TOP12 ((HASH_TYPE) 1 << 11)
15#define H_BOT1 ((HASH_TYPE) 1 << 12)
16#define H_BOT2 ((HASH_TYPE) 1 << 13)
17#define H_BOT3 ((HASH_TYPE) 1 << 14)
18#define H_BOT4 ((HASH_TYPE) 1 << 15)
19#define H_BOT5 ((HASH_TYPE) 1 << 16)
20#define H_BOT6 ((HASH_TYPE) 1 << 17)
21#define H_BOT7 ((HASH_TYPE) 1 << 18)
22#define H_BOT8 ((HASH_TYPE) 1 << 19)
23#define H_BOT9 ((HASH_TYPE) 1 << 20)
24#define H_BOT10 ((HASH_TYPE) 1 << 21)
25#define H_BOT11 ((HASH_TYPE) 1 << 22)
26#define H_BOT12 ((HASH_TYPE) 1 << 23)
27#define H_THU1 ((HASH_TYPE) 1 << 24)
28#define H_THU2 ((HASH_TYPE) 1 << 25)
29#define H_THU3 ((HASH_TYPE) 1 << 26)
30#define H_THU4 ((HASH_TYPE) 1 << 27)
31#define H_THU5 ((HASH_TYPE) 1 << 28)
32#define H_THU6 ((HASH_TYPE) 1 << 29)
33
34enum internal_keycodes {
35 TOP1 = SAFE_RANGE,
36 TOP2, TOP3, TOP4, TOP5, TOP6, TOP7, TOP8, TOP9, TOP10, TOP11, TOP12, BOT1, BOT2, BOT3, BOT4, BOT5, BOT6, BOT7, BOT8, BOT9, BOT10, BOT11, BOT12, THU1, THU2, THU3, THU4, THU5, THU6,
37 FIRST_INTERNAL_KEYCODE = TOP1,
38 LAST_INTERNAL_KEYCODE = THU6
39};
40
41enum pseudolayers {
42 ALWAYS_ON, QWERTY, NUM, FNC, NAV, MOUSE
43};
44
45#define CHORD_TIMEOUT 100
46#define DANCE_TIMEOUT 200
47#define LEADER_TIMEOUT 750
48#define TAP_TIMEOUT 50
49#define LONG_PRESS_MULTIPLIER 3
50#define DYNAMIC_MACRO_MAX_LENGTH 20
51#define COMMAND_MAX_LENGTH 5
52#define STRING_MAX_LENGTH 16
53#define LEADER_MAX_LENGTH 5
54#define HASH_TYPE uint32_t
55#define NUMBER_OF_KEYS 30
56#define DEFAULT_PSEUDOLAYER QWERTY
57
58const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
59 [0] = LAYOUT_georgi(TOP1, TOP2, TOP3, TOP4, TOP5, TOP6, TOP7, TOP8, TOP9, TOP10, TOP11, TOP12, BOT1, BOT2, BOT3, BOT4, BOT5, BOT6, BOT7, BOT8, BOT9, BOT10, BOT11, BOT12, THU1, THU2, THU3, THU4, THU5, THU6),
60};
61size_t keymapsCount = 1;
62
63uint8_t keycodes_buffer_array[] = {
64 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
65};
66
67uint8_t command_buffer[] = {
68 0, 0, 0, 0, 0
69};
70
71uint16_t leader_buffer[] = {
72 0, 0, 0, 0, 0
73};
74
75uint8_t dynamic_macro_buffer[] = {
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
77};
78
79enum chord_states {
80 IDLE,
81 READY,
82 ACTIVATED,
83 DEACTIVATED,
84 PRESS_FROM_ACTIVE,
85 FINISHED_FROM_ACTIVE,
86 IDLE_IN_DANCE,
87 READY_IN_DANCE,
88 FINISHED,
89 LOCKED,
90 READY_LOCKED,
91 RESTART,
92 IN_ONE_SHOT
93};
94
95struct Chord {
96 uint32_t keycodes_hash;
97 uint8_t pseudolayer;
98 uint8_t* state;
99 uint8_t* counter;
100 uint16_t value1;
101 uint8_t value2;
102 void (*function) (const struct Chord*);
103};
104
105uint8_t current_pseudolayer = DEFAULT_PSEUDOLAYER;
106bool lock_next = false;
107uint16_t chord_timer = 0;
108uint16_t dance_timer = 0;
109bool autoshift_mode = true;
110uint8_t keycode_index = 0;
111uint8_t command_mode = 0;
112uint8_t command_ind = 0;
113bool in_leader_mode = false;
114uint8_t leader_ind = 0;
115uint16_t leader_timer = 0;
116uint8_t dynamic_macro_mode = false;
117uint8_t dynamic_macro_ind = 0;
118bool a_key_went_through = false;
119struct Chord* last_chord = NULL;
120
121bool handle_US_ANSI_shifted_keys(int16_t keycode, bool in) {
122 bool is_US_ANSI_shifted = true;
123
124 int16_t regular_keycode = KC_NO;
125 switch (keycode) {
126 case KC_TILDE:
127 regular_keycode = KC_GRAVE;
128 break;
129 case KC_EXCLAIM:
130 regular_keycode = KC_1;
131 break;
132 case KC_AT:
133 regular_keycode = KC_2;
134 break;
135 case KC_HASH:
136 regular_keycode = KC_3;
137 break;
138 case KC_DOLLAR:
139 regular_keycode = KC_4;
140 break;
141 case KC_PERCENT:
142 regular_keycode = KC_5;
143 break;
144 case KC_CIRCUMFLEX:
145 regular_keycode = KC_6;
146 break;
147 case KC_AMPERSAND:
148 regular_keycode = KC_7;
149 break;
150 case KC_ASTERISK:
151 regular_keycode = KC_8;
152 break;
153 case KC_LEFT_PAREN:
154 regular_keycode = KC_9;
155 break;
156 case KC_RIGHT_PAREN:
157 regular_keycode = KC_0;
158 break;
159 case KC_UNDERSCORE:
160 regular_keycode = KC_MINUS;
161 break;
162 case KC_PLUS:
163 regular_keycode = KC_EQUAL;
164 break;
165 case KC_LEFT_CURLY_BRACE:
166 regular_keycode = KC_LBRACKET;
167 break;
168 case KC_RIGHT_CURLY_BRACE:
169 regular_keycode = KC_RBRACKET;
170 break;
171 case KC_PIPE:
172 regular_keycode = KC_BSLASH;
173 break;
174 case KC_COLON:
175 regular_keycode = KC_SCOLON;
176 break;
177 case KC_DOUBLE_QUOTE:
178 regular_keycode = KC_QUOTE;
179 break;
180 case KC_LEFT_ANGLE_BRACKET:
181 regular_keycode = KC_COMMA;
182 break;
183 case KC_RIGHT_ANGLE_BRACKET:
184 regular_keycode = KC_DOT;
185 break;
186 case KC_QUESTION:
187 regular_keycode = KC_SLASH;
188 break;
189 default:
190 is_US_ANSI_shifted = false;
191 }
192 if (is_US_ANSI_shifted) {
193 if (in) {
194 register_code(KC_LSFT);
195 register_code(regular_keycode);
196 } else {
197 unregister_code(regular_keycode);
198 unregister_code(KC_LSFT);
199 }
200 }
201 return is_US_ANSI_shifted;
202}
203
204void key_in(int16_t keycode) {
205 if (command_mode == 1 && command_ind < COMMAND_MAX_LENGTH) {
206 command_buffer[command_ind] = keycode;
207 command_ind++;
208 a_key_went_through = true;
209 } else if (in_leader_mode && leader_ind < LEADER_MAX_LENGTH) {
210 leader_buffer[leader_ind] = keycode;
211 leader_ind++;
212 a_key_went_through = true;
213 } else if (dynamic_macro_mode && dynamic_macro_ind < DYNAMIC_MACRO_MAX_LENGTH) {
214 dynamic_macro_buffer[dynamic_macro_ind] = keycode;
215 dynamic_macro_ind++;
216 a_key_went_through = true;
217 } else {
218 if (!handle_US_ANSI_shifted_keys(keycode, true)) {
219 register_code(keycode);
220 }
221 send_keyboard_report();
222 a_key_went_through = true;
223 }
224}
225
226void key_out(int16_t keycode) {
227 if (command_mode == 0) {
228 if (!handle_US_ANSI_shifted_keys(keycode, false)) {
229 if (command_mode == 0 && in_leader_mode == false && dynamic_macro_mode == false) {
230 unregister_code(keycode);
231 }
232 }
233 send_keyboard_report();
234 }
235}
236
237void tap_key(int16_t keycode) {
238 key_in(keycode);
239 wait_ms(TAP_TIMEOUT);
240 key_out(keycode);
241}
242const char * const strings[] PROGMEM = {
243
244};
245void single_dance(const struct Chord* self) {
246 switch (*self->state) {
247 case ACTIVATED:
248 key_in(self->value1);
249 break;
250 case DEACTIVATED:
251 key_out(self->value1);
252 *self->state = IDLE;
253 break;
254 case RESTART:
255 key_out(self->value1);
256 break;
257 default:
258 break;
259 }
260}
261
262void key_layer_dance(const struct Chord* self) {
263 switch (*self->state) {
264 case ACTIVATED:
265 current_pseudolayer = self->value2;
266 a_key_went_through = false;
267 break;
268 case DEACTIVATED:
269 case RESTART:
270 if (!a_key_went_through) {
271 tap_key(self->value1);
272 }
273 current_pseudolayer = self->pseudolayer;
274 *self->state = IDLE; // does not have effect if the state was RESTART
275 break;
276 default:
277 break;
278 }
279}
280
281void key_mod_dance(const struct Chord* self) {
282 switch (*self->state) {
283 case ACTIVATED:
284 key_in(self->value2);
285 a_key_went_through = false;
286 break;
287 case DEACTIVATED:
288 case RESTART:
289 key_out(self->value2);
290 if (!a_key_went_through) {
291 tap_key(self->value1);
292 }
293 *self->state = IDLE; // does not have effect if the state was RESTART
294 break;
295 default:
296 break;
297 }
298}
299
300void key_key_dance(const struct Chord* self) {
301 switch (*self->state) {
302 case ACTIVATED:
303 break;
304 case DEACTIVATED:
305 tap_key(self->value1);
306 *self->state = IDLE;
307 break;
308 case FINISHED:
309 case PRESS_FROM_ACTIVE:
310 key_in(self->value2);
311 break;
312 case RESTART:
313 key_out(self->value2);
314 break;
315 default:
316 break;
317 }
318}
319
320void autoshift_dance_impl(const struct Chord* self) {
321 switch (*self->state) {
322 case ACTIVATED:
323 *self->counter = 0;
324 break;
325 case DEACTIVATED:
326 case RESTART:
327 tap_key(self->value1);
328 *self->state = IDLE;
329 break;
330 case FINISHED_FROM_ACTIVE:
331 if (*self->counter == (LONG_PRESS_MULTIPLIER - 2)) {
332 key_in(KC_LSFT);
333 tap_key(self->value1);
334 key_out(KC_LSFT);
335 *self->state = IDLE;
336 // the skip to IDLE is usually just a lag optimization,
337 // in this case it has a logic function, on a short
338 // press (still longer than a tap) the key does not get shifted
339 } else {
340 *self->counter += 1;
341 *self->state = PRESS_FROM_ACTIVE;
342 dance_timer = timer_read();
343 }
344 break;
345 default:
346 break;
347 }
348}
349
350void autoshift_dance(const struct Chord* self) {
351 if (autoshift_mode) {
352 autoshift_dance_impl(self);
353 } else {
354 single_dance(self);
355 }
356}
357
358void autoshift_toggle(const struct Chord* self){
359 if (*self->state == ACTIVATED) {
360 autoshift_mode = !autoshift_mode;
361 *self->state = IDLE;
362 }
363}
364
365void temp_pseudolayer(const struct Chord* self) {
366 switch (*self->state) {
367 case ACTIVATED:
368 current_pseudolayer = self->value1;
369 break;
370 case DEACTIVATED:
371 current_pseudolayer = self->pseudolayer;
372 *self->state = IDLE;
373 break;
374 case RESTART:
375 current_pseudolayer = self->pseudolayer;
376 break;
377 default:
378 break;
379 }
380}
381
382void temp_pseudolayer_alt(const struct Chord* self) {
383 switch (*self->state) {
384 case ACTIVATED:
385 current_pseudolayer = self->value1;
386 break;
387 case DEACTIVATED:
388 current_pseudolayer = self->value2;
389 *self->state = IDLE;
390 break;
391 case RESTART:
392 current_pseudolayer = self->value2;
393 break;
394 default:
395 break;
396 }
397}
398
399void perm_pseudolayer(const struct Chord* self) {
400 if (*self->state == ACTIVATED) {
401 current_pseudolayer = self->value1;
402 *self->state = IDLE;
403 }
404}
405
406void switch_layer(const struct Chord* self) {
407 if (*self->state == ACTIVATED) {
408 layer_move(self->value1);
409 *self->state = IDLE;
410 }
411}
412
413void lock(const struct Chord* self) {
414 if (*self->state == ACTIVATED) {
415 lock_next = true;
416 *self->state = IDLE;
417 }
418}
419
420void one_shot_key(const struct Chord* self) {
421 switch (*self->state) {
422 case ACTIVATED:
423 break;
424 case DEACTIVATED:
425 key_in(self->value1);
426 *self->state = IN_ONE_SHOT;
427 break;
428 case FINISHED:
429 case PRESS_FROM_ACTIVE:
430 key_in(self->value1);
431 a_key_went_through = false;
432 break;
433 case RESTART:
434 if (a_key_went_through) {
435 key_out(self->value1);
436 } else {
437 *self->state = IN_ONE_SHOT;
438 }
439 default:
440 break;
441 }
442}
443
444void one_shot_layer(const struct Chord* self) {
445 switch (*self->state) {
446 case ACTIVATED:
447 break;
448 case DEACTIVATED:
449 current_pseudolayer = self->value1;
450 *self->state = IN_ONE_SHOT;
451 break;
452 case FINISHED:
453 case PRESS_FROM_ACTIVE:
454 current_pseudolayer = self->value1;
455 a_key_went_through = false;
456 break;
457 case RESTART:
458 if (a_key_went_through) {
459 current_pseudolayer = self->pseudolayer;
460 } else {
461 *self->state = IN_ONE_SHOT;
462 }
463 default:
464 break;
465 }
466}
467
468void command(const struct Chord* self) {
469 if (*self->state == ACTIVATED) {
470 command_mode++;
471 *self->state = IDLE;
472 }
473}
474
475bool identical(uint16_t* buffer1, uint16_t* buffer2) {
476 bool same = true;
477 for (int i = 0; i < LEADER_MAX_LENGTH; i++) {
478 same = same && (buffer1[i] == buffer2[i]);
479 }
480 return same;
481}
482
483void leader(const struct Chord* self) {
484 if (*self->state == ACTIVATED) {
485 in_leader_mode = true;
486 *self->state = IDLE;
487 }
488}
489
490void dynamic_macro_record(const struct Chord* self) {
491 if (*self->state == ACTIVATED) {
492 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
493 dynamic_macro_buffer[i] = 0;
494 }
495 dynamic_macro_mode = true;
496 *self->state = IDLE;
497 }
498}
499
500void dynamic_macro_next(const struct Chord* self) {
501 if (*self->state == ACTIVATED) {
502 if (dynamic_macro_mode && dynamic_macro_ind < DYNAMIC_MACRO_MAX_LENGTH) {
503 dynamic_macro_buffer[dynamic_macro_ind] = 0;
504 dynamic_macro_ind++;
505 }
506 *self->state = IDLE;
507 }
508}
509
510void dynamic_macro_end(const struct Chord* self) {
511 if (*self->state == ACTIVATED) {
512 if (dynamic_macro_mode) {
513 dynamic_macro_mode = false;
514 }
515 *self->state = IDLE;
516 }
517}
518
519void dynamic_macro_play(const struct Chord* self) {
520 if (*self->state == ACTIVATED) {
521 int ind_start = 0;
522 while (ind_start < DYNAMIC_MACRO_MAX_LENGTH) {
523 for (int i = ind_start; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
524 if (dynamic_macro_buffer[i] == 0) {
525 break;
526 }
527 register_code(dynamic_macro_buffer[i]);
528 }
529 send_keyboard_report();
530 wait_ms(TAP_TIMEOUT);
531 for (int i = ind_start; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
532 if (dynamic_macro_buffer[i] == 0) {
533 ind_start = i + 1;
534 break;
535 }
536 unregister_code(dynamic_macro_buffer[i]);
537 }
538 send_keyboard_report();
539 }
540 *self->state = IDLE;
541 }
542}
543
544void string_in(const struct Chord* self) {
545 if (*self->state == ACTIVATED) {
546 char buffer[STRING_MAX_LENGTH];
547 strcpy_P(buffer, (char*)pgm_read_word(&(strings[self->value1])));
548 send_string(buffer);
549 }
550}
551
552void clear(const struct Chord* self);
553
554void reset_keyboard_kb(void){
555#ifdef WATCHDOG_ENABLE
556 MCUSR = 0;
557 wdt_disable();
558 wdt_reset();
559#endif
560 reset_keyboard();
561}
562
563void reset(const struct Chord* self) {
564 if (*self->state == ACTIVATED) {
565 reset_keyboard_kb();
566 }
567}
568
569uint8_t state_0 = IDLE;
570const struct Chord chord_0 PROGMEM = {H_TOP1 + H_TOP12 + H_BOT1 + H_BOT12, ALWAYS_ON, &state_0, NULL, 0, 0, clear};
571uint8_t state_1 = IDLE;
572const struct Chord chord_1 PROGMEM = {H_TOP6 + H_TOP7 + H_BOT6 + H_BOT7, ALWAYS_ON, &state_1, NULL, 0, 0, command};
573uint8_t state_2 = IDLE;
574const struct Chord chord_2 PROGMEM = {H_TOP1, QWERTY, &state_2, NULL, KC_ESC, 0, single_dance};
575uint8_t state_3 = IDLE;
576const struct Chord chord_3 PROGMEM = {H_TOP2, QWERTY, &state_3, NULL, KC_Q, 0, single_dance};
577uint8_t state_4 = IDLE;
578const struct Chord chord_4 PROGMEM = {H_TOP3, QWERTY, &state_4, NULL, KC_W, 0, single_dance};
579uint8_t state_5 = IDLE;
580const struct Chord chord_5 PROGMEM = {H_TOP4, QWERTY, &state_5, NULL, KC_E, 0, single_dance};
581uint8_t state_6 = IDLE;
582const struct Chord chord_6 PROGMEM = {H_TOP5, QWERTY, &state_6, NULL, KC_R, 0, single_dance};
583uint8_t state_7 = IDLE;
584const struct Chord chord_7 PROGMEM = {H_TOP6, QWERTY, &state_7, NULL, KC_T, 0, single_dance};
585uint8_t state_8 = IDLE;
586const struct Chord chord_8 PROGMEM = {H_TOP7, QWERTY, &state_8, NULL, KC_Y, 0, single_dance};
587uint8_t state_9 = IDLE;
588const struct Chord chord_9 PROGMEM = {H_TOP8, QWERTY, &state_9, NULL, KC_U, 0, single_dance};
589uint8_t state_10 = IDLE;
590const struct Chord chord_10 PROGMEM = {H_TOP9, QWERTY, &state_10, NULL, KC_I, 0, single_dance};
591uint8_t state_11 = IDLE;
592const struct Chord chord_11 PROGMEM = {H_TOP10, QWERTY, &state_11, NULL, KC_O, 0, single_dance};
593uint8_t state_12 = IDLE;
594const struct Chord chord_12 PROGMEM = {H_TOP11, QWERTY, &state_12, NULL, KC_P, 0, single_dance};
595uint8_t state_13 = IDLE;
596const struct Chord chord_13 PROGMEM = {H_TOP12, QWERTY, &state_13, NULL, KC_BSLASH, 0, single_dance};
597uint8_t state_14 = IDLE;
598const struct Chord chord_14 PROGMEM = {H_TOP1 + H_BOT1, QWERTY, &state_14, NULL, KC_INS, 0, single_dance};
599uint8_t state_15 = IDLE;
600const struct Chord chord_15 PROGMEM = {H_TOP2 + H_BOT2, QWERTY, &state_15, NULL, KC_A, 0, single_dance};
601uint8_t state_16 = IDLE;
602uint8_t counter_16 = 0;
603const struct Chord chord_16 PROGMEM = {H_TOP3 + H_BOT3, QWERTY, &state_16, &counter_16, KC_S, KC_LALT, key_key_dance};
604uint8_t state_17 = IDLE;
605const struct Chord chord_17 PROGMEM = {H_TOP4 + H_BOT4, QWERTY, &state_17, NULL, KC_D, KC_LCTL, key_mod_dance};
606uint8_t state_18 = IDLE;
607const struct Chord chord_18 PROGMEM = {H_TOP5 + H_BOT5, QWERTY, &state_18, NULL, KC_F, KC_LSFT, key_mod_dance};
608uint8_t state_19 = IDLE;
609uint8_t counter_19 = 0;
610const struct Chord chord_19 PROGMEM = {H_TOP6 + H_BOT6, QWERTY, &state_19, &counter_19, KC_G, KC_LGUI, key_key_dance};
611uint8_t state_20 = IDLE;
612uint8_t counter_20 = 0;
613const struct Chord chord_20 PROGMEM = {H_TOP7 + H_BOT7, QWERTY, &state_20, &counter_20, KC_H, KC_RGUI, key_key_dance};
614uint8_t state_21 = IDLE;
615const struct Chord chord_21 PROGMEM = {H_TOP8 + H_BOT8, QWERTY, &state_21, NULL, KC_J, KC_RSFT, key_mod_dance};
616uint8_t state_22 = IDLE;
617const struct Chord chord_22 PROGMEM = {H_TOP9 + H_BOT9, QWERTY, &state_22, NULL, KC_K, KC_RCTL, key_mod_dance};
618uint8_t state_23 = IDLE;
619uint8_t counter_23 = 0;
620const struct Chord chord_23 PROGMEM = {H_TOP10 + H_BOT10, QWERTY, &state_23, &counter_23, KC_L, KC_RALT, key_key_dance};
621uint8_t state_24 = IDLE;
622const struct Chord chord_24 PROGMEM = {H_TOP11 + H_BOT11, QWERTY, &state_24, NULL, KC_SCOLON, 0, single_dance};
623uint8_t state_25 = IDLE;
624const struct Chord chord_25 PROGMEM = {H_BOT1, QWERTY, &state_25, NULL, KC_TAB, 0, single_dance};
625uint8_t state_26 = IDLE;
626const struct Chord chord_26 PROGMEM = {H_BOT2, QWERTY, &state_26, NULL, KC_Z, 0, single_dance};
627uint8_t state_27 = IDLE;
628const struct Chord chord_27 PROGMEM = {H_BOT3, QWERTY, &state_27, NULL, KC_X, 0, single_dance};
629uint8_t state_28 = IDLE;
630const struct Chord chord_28 PROGMEM = {H_BOT4, QWERTY, &state_28, NULL, KC_C, 0, single_dance};
631uint8_t state_29 = IDLE;
632const struct Chord chord_29 PROGMEM = {H_BOT5, QWERTY, &state_29, NULL, KC_V, 0, single_dance};
633uint8_t state_30 = IDLE;
634const struct Chord chord_30 PROGMEM = {H_BOT6, QWERTY, &state_30, NULL, KC_B, 0, single_dance};
635uint8_t state_31 = IDLE;
636const struct Chord chord_31 PROGMEM = {H_BOT7, QWERTY, &state_31, NULL, KC_N, 0, single_dance};
637uint8_t state_32 = IDLE;
638const struct Chord chord_32 PROGMEM = {H_BOT8, QWERTY, &state_32, NULL, KC_M, 0, single_dance};
639uint8_t state_33 = IDLE;
640const struct Chord chord_33 PROGMEM = {H_BOT9, QWERTY, &state_33, NULL, KC_COMMA, 0, single_dance};
641uint8_t state_34 = IDLE;
642const struct Chord chord_34 PROGMEM = {H_BOT10, QWERTY, &state_34, NULL, KC_DOT, 0, single_dance};
643uint8_t state_35 = IDLE;
644const struct Chord chord_35 PROGMEM = {H_BOT11, QWERTY, &state_35, NULL, KC_SLASH, 0, single_dance};
645uint8_t state_36 = IDLE;
646const struct Chord chord_36 PROGMEM = {H_BOT12, QWERTY, &state_36, NULL, KC_QUOTE, 0, single_dance};
647uint8_t state_37 = IDLE;
648const struct Chord chord_37 PROGMEM = {H_THU1, QWERTY, &state_37, NULL, KC_ENTER, 0, single_dance};
649uint8_t state_38 = IDLE;
650uint8_t counter_38 = 0;
651const struct Chord chord_38 PROGMEM = {H_THU2, QWERTY, &state_38, &counter_38, KC_SPC, NUM, key_layer_dance};
652uint8_t state_39 = IDLE;
653uint8_t counter_39 = 0;
654const struct Chord chord_39 PROGMEM = {H_THU3, QWERTY, &state_39, &counter_39, KC_BSPC, NAV, key_layer_dance};
655uint8_t state_40 = IDLE;
656const struct Chord chord_40 PROGMEM = {H_THU4, QWERTY, &state_40, NULL, KC_DEL, 0, single_dance};
657uint8_t state_41 = IDLE;
658uint8_t counter_41 = 0;
659const struct Chord chord_41 PROGMEM = {H_THU5, QWERTY, &state_41, &counter_41, KC_SPC, FNC, key_layer_dance};
660uint8_t state_42 = IDLE;
661const struct Chord chord_42 PROGMEM = {H_THU6, QWERTY, &state_42, NULL, KC_ENTER, 0, single_dance};
662uint8_t state_43 = IDLE;
663const struct Chord chord_43 PROGMEM = {H_THU2 + H_THU3, QWERTY, &state_43, NULL, MOUSE, 0, temp_pseudolayer};
664uint8_t state_44 = IDLE;
665const struct Chord chord_44 PROGMEM = {H_TOP1, NUM, &state_44, NULL, KC_GRAVE, 0, single_dance};
666uint8_t state_45 = IDLE;
667const struct Chord chord_45 PROGMEM = {H_TOP2, NUM, &state_45, NULL, KC_1, 0, single_dance};
668uint8_t state_46 = IDLE;
669const struct Chord chord_46 PROGMEM = {H_TOP3, NUM, &state_46, NULL, KC_2, 0, single_dance};
670uint8_t state_47 = IDLE;
671const struct Chord chord_47 PROGMEM = {H_TOP4, NUM, &state_47, NULL, KC_3, 0, single_dance};
672uint8_t state_48 = IDLE;
673const struct Chord chord_48 PROGMEM = {H_TOP5, NUM, &state_48, NULL, KC_4, 0, single_dance};
674uint8_t state_49 = IDLE;
675const struct Chord chord_49 PROGMEM = {H_TOP6, NUM, &state_49, NULL, KC_5, 0, single_dance};
676uint8_t state_50 = IDLE;
677const struct Chord chord_50 PROGMEM = {H_TOP7, NUM, &state_50, NULL, KC_6, 0, single_dance};
678uint8_t state_51 = IDLE;
679const struct Chord chord_51 PROGMEM = {H_TOP8, NUM, &state_51, NULL, KC_7, 0, single_dance};
680uint8_t state_52 = IDLE;
681const struct Chord chord_52 PROGMEM = {H_TOP9, NUM, &state_52, NULL, KC_8, 0, single_dance};
682uint8_t state_53 = IDLE;
683const struct Chord chord_53 PROGMEM = {H_TOP10, NUM, &state_53, NULL, KC_9, 0, single_dance};
684uint8_t state_54 = IDLE;
685const struct Chord chord_54 PROGMEM = {H_TOP11, NUM, &state_54, NULL, KC_0, 0, single_dance};
686uint8_t state_55 = IDLE;
687const struct Chord chord_55 PROGMEM = {H_TOP12, NUM, &state_55, NULL, KC_MINUS, 0, single_dance};
688uint8_t state_56 = IDLE;
689const struct Chord chord_56 PROGMEM = {H_TOP3 + H_BOT3, NUM, &state_56, NULL, KC_LALT, 0, single_dance};
690uint8_t state_57 = IDLE;
691const struct Chord chord_57 PROGMEM = {H_TOP4 + H_BOT4, NUM, &state_57, NULL, KC_LCTL, 0, single_dance};
692uint8_t state_58 = IDLE;
693const struct Chord chord_58 PROGMEM = {H_TOP5 + H_BOT5, NUM, &state_58, NULL, KC_LSFT, 0, single_dance};
694uint8_t state_59 = IDLE;
695const struct Chord chord_59 PROGMEM = {H_TOP6 + H_BOT6, NUM, &state_59, NULL, KC_LGUI, 0, single_dance};
696uint8_t state_60 = IDLE;
697const struct Chord chord_60 PROGMEM = {H_TOP7 + H_BOT7, NUM, &state_60, NULL, KC_RGUI, 0, single_dance};
698uint8_t state_61 = IDLE;
699const struct Chord chord_61 PROGMEM = {H_TOP8 + H_BOT8, NUM, &state_61, NULL, KC_RSFT, 0, single_dance};
700uint8_t state_62 = IDLE;
701const struct Chord chord_62 PROGMEM = {H_TOP9 + H_BOT9, NUM, &state_62, NULL, KC_RCTL, 0, single_dance};
702uint8_t state_63 = IDLE;
703const struct Chord chord_63 PROGMEM = {H_TOP10 + H_BOT10, NUM, &state_63, NULL, KC_RALT, 0, single_dance};
704uint8_t state_64 = IDLE;
705const struct Chord chord_64 PROGMEM = {H_BOT12, NUM, &state_64, NULL, KC_EQUAL, 0, single_dance};
706uint8_t state_65 = IDLE;
707const struct Chord chord_65 PROGMEM = {H_TOP2, FNC, &state_65, NULL, KC_F1, 0, single_dance};
708uint8_t state_66 = IDLE;
709const struct Chord chord_66 PROGMEM = {H_TOP3, FNC, &state_66, NULL, KC_F2, 0, single_dance};
710uint8_t state_67 = IDLE;
711const struct Chord chord_67 PROGMEM = {H_TOP4, FNC, &state_67, NULL, KC_F3, 0, single_dance};
712uint8_t state_68 = IDLE;
713const struct Chord chord_68 PROGMEM = {H_TOP5, FNC, &state_68, NULL, KC_F4, 0, single_dance};
714uint8_t state_69 = IDLE;
715const struct Chord chord_69 PROGMEM = {H_TOP6, FNC, &state_69, NULL, KC_F5, 0, single_dance};
716uint8_t state_70 = IDLE;
717const struct Chord chord_70 PROGMEM = {H_TOP7, FNC, &state_70, NULL, KC_F6, 0, single_dance};
718uint8_t state_71 = IDLE;
719const struct Chord chord_71 PROGMEM = {H_TOP8, FNC, &state_71, NULL, KC_F7, 0, single_dance};
720uint8_t state_72 = IDLE;
721const struct Chord chord_72 PROGMEM = {H_TOP9, FNC, &state_72, NULL, KC_F8, 0, single_dance};
722uint8_t state_73 = IDLE;
723const struct Chord chord_73 PROGMEM = {H_TOP10, FNC, &state_73, NULL, KC_F9, 0, single_dance};
724uint8_t state_74 = IDLE;
725const struct Chord chord_74 PROGMEM = {H_TOP11, FNC, &state_74, NULL, KC_F10, 0, single_dance};
726uint8_t state_75 = IDLE;
727const struct Chord chord_75 PROGMEM = {H_TOP12, FNC, &state_75, NULL, KC_F11, 0, single_dance};
728uint8_t state_76 = IDLE;
729const struct Chord chord_76 PROGMEM = {H_TOP3 + H_BOT3, FNC, &state_76, NULL, KC_LALT, 0, single_dance};
730uint8_t state_77 = IDLE;
731const struct Chord chord_77 PROGMEM = {H_TOP4 + H_BOT4, FNC, &state_77, NULL, KC_LCTL, 0, single_dance};
732uint8_t state_78 = IDLE;
733const struct Chord chord_78 PROGMEM = {H_TOP5 + H_BOT5, FNC, &state_78, NULL, KC_LSFT, 0, single_dance};
734uint8_t state_79 = IDLE;
735const struct Chord chord_79 PROGMEM = {H_TOP6 + H_BOT6, FNC, &state_79, NULL, KC_LGUI, 0, single_dance};
736uint8_t state_80 = IDLE;
737const struct Chord chord_80 PROGMEM = {H_TOP7 + H_BOT7, FNC, &state_80, NULL, KC_RGUI, 0, single_dance};
738uint8_t state_81 = IDLE;
739const struct Chord chord_81 PROGMEM = {H_TOP8 + H_BOT8, FNC, &state_81, NULL, KC_RSFT, 0, single_dance};
740uint8_t state_82 = IDLE;
741const struct Chord chord_82 PROGMEM = {H_TOP9 + H_BOT9, FNC, &state_82, NULL, KC_RCTL, 0, single_dance};
742uint8_t state_83 = IDLE;
743const struct Chord chord_83 PROGMEM = {H_TOP10 + H_BOT10, FNC, &state_83, NULL, KC_RALT, 0, single_dance};
744uint8_t state_84 = IDLE;
745const struct Chord chord_84 PROGMEM = {H_BOT12, FNC, &state_84, NULL, KC_F12, 0, single_dance};
746uint8_t state_85 = IDLE;
747const struct Chord chord_85 PROGMEM = {H_TOP8, NAV, &state_85, NULL, KC_HOME, 0, single_dance};
748uint8_t state_86 = IDLE;
749const struct Chord chord_86 PROGMEM = {H_TOP9, NAV, &state_86, NULL, KC_UP, 0, single_dance};
750uint8_t state_87 = IDLE;
751const struct Chord chord_87 PROGMEM = {H_TOP10, NAV, &state_87, NULL, KC_END, 0, single_dance};
752uint8_t state_88 = IDLE;
753const struct Chord chord_88 PROGMEM = {H_TOP11, NAV, &state_88, NULL, KC_PGUP, 0, single_dance};
754uint8_t state_89 = IDLE;
755const struct Chord chord_89 PROGMEM = {H_TOP3 + H_BOT3, NAV, &state_89, NULL, KC_LALT, 0, single_dance};
756uint8_t state_90 = IDLE;
757const struct Chord chord_90 PROGMEM = {H_TOP4 + H_BOT4, NAV, &state_90, NULL, KC_LCTL, 0, single_dance};
758uint8_t state_91 = IDLE;
759const struct Chord chord_91 PROGMEM = {H_TOP5 + H_BOT5, NAV, &state_91, NULL, KC_LSFT, 0, single_dance};
760uint8_t state_92 = IDLE;
761const struct Chord chord_92 PROGMEM = {H_TOP6 + H_BOT6, NAV, &state_92, NULL, KC_LGUI, 0, single_dance};
762uint8_t state_93 = IDLE;
763const struct Chord chord_93 PROGMEM = {H_BOT8, NAV, &state_93, NULL, KC_LEFT, 0, single_dance};
764uint8_t state_94 = IDLE;
765const struct Chord chord_94 PROGMEM = {H_BOT9, NAV, &state_94, NULL, KC_DOWN, 0, single_dance};
766uint8_t state_95 = IDLE;
767const struct Chord chord_95 PROGMEM = {H_BOT10, NAV, &state_95, NULL, KC_RIGHT, 0, single_dance};
768uint8_t state_96 = IDLE;
769const struct Chord chord_96 PROGMEM = {H_BOT11, NAV, &state_96, NULL, KC_PGDN, 0, single_dance};
770uint8_t state_97 = IDLE;
771const struct Chord chord_97 PROGMEM = {H_TOP8, MOUSE, &state_97, NULL, KC_BTN1, 0, single_dance};
772uint8_t state_98 = IDLE;
773const struct Chord chord_98 PROGMEM = {H_TOP9, MOUSE, &state_98, NULL, KC_MS_U, 0, single_dance};
774uint8_t state_99 = IDLE;
775const struct Chord chord_99 PROGMEM = {H_TOP10, MOUSE, &state_99, NULL, KC_BTN2, 0, single_dance};
776uint8_t state_100 = IDLE;
777const struct Chord chord_100 PROGMEM = {H_TOP11, MOUSE, &state_100, NULL, KC_WH_U, 0, single_dance};
778uint8_t state_101 = IDLE;
779const struct Chord chord_101 PROGMEM = {H_TOP3 + H_BOT3, MOUSE, &state_101, NULL, KC_LALT, 0, single_dance};
780uint8_t state_102 = IDLE;
781const struct Chord chord_102 PROGMEM = {H_TOP4 + H_BOT4, MOUSE, &state_102, NULL, KC_LCTL, 0, single_dance};
782uint8_t state_103 = IDLE;
783const struct Chord chord_103 PROGMEM = {H_TOP5 + H_BOT5, MOUSE, &state_103, NULL, KC_LSFT, 0, single_dance};
784uint8_t state_104 = IDLE;
785const struct Chord chord_104 PROGMEM = {H_TOP6 + H_BOT6, MOUSE, &state_104, NULL, KC_LGUI, 0, single_dance};
786uint8_t state_105 = IDLE;
787const struct Chord chord_105 PROGMEM = {H_BOT8, MOUSE, &state_105, NULL, KC_MS_L, 0, single_dance};
788uint8_t state_106 = IDLE;
789const struct Chord chord_106 PROGMEM = {H_BOT9, MOUSE, &state_106, NULL, KC_MS_D, 0, single_dance};
790uint8_t state_107 = IDLE;
791const struct Chord chord_107 PROGMEM = {H_BOT10, MOUSE, &state_107, NULL, KC_MS_R, 0, single_dance};
792uint8_t state_108 = IDLE;
793const struct Chord chord_108 PROGMEM = {H_BOT11, MOUSE, &state_108, NULL, KC_WH_D, 0, single_dance};
794
795const struct Chord* const list_of_chords[] PROGMEM = {
796 &chord_0, &chord_1, &chord_2, &chord_3, &chord_4, &chord_5, &chord_6, &chord_7, &chord_8, &chord_9, &chord_10, &chord_11, &chord_12, &chord_13, &chord_14, &chord_15, &chord_16, &chord_17, &chord_18, &chord_19, &chord_20, &chord_21, &chord_22, &chord_23, &chord_24, &chord_25, &chord_26, &chord_27, &chord_28, &chord_29, &chord_30, &chord_31, &chord_32, &chord_33, &chord_34, &chord_35, &chord_36, &chord_37, &chord_38, &chord_39, &chord_40, &chord_41, &chord_42, &chord_43, &chord_44, &chord_45, &chord_46, &chord_47, &chord_48, &chord_49, &chord_50, &chord_51, &chord_52, &chord_53, &chord_54, &chord_55, &chord_56, &chord_57, &chord_58, &chord_59, &chord_60, &chord_61, &chord_62, &chord_63, &chord_64, &chord_65, &chord_66, &chord_67, &chord_68, &chord_69, &chord_70, &chord_71, &chord_72, &chord_73, &chord_74, &chord_75, &chord_76, &chord_77, &chord_78, &chord_79, &chord_80, &chord_81, &chord_82, &chord_83, &chord_84, &chord_85, &chord_86, &chord_87, &chord_88, &chord_89, &chord_90, &chord_91, &chord_92, &chord_93, &chord_94, &chord_95, &chord_96, &chord_97, &chord_98, &chord_99, &chord_100, &chord_101, &chord_102, &chord_103, &chord_104, &chord_105, &chord_106, &chord_107, &chord_108
797};
798
799const uint16_t** const leader_triggers PROGMEM = NULL;
800void (*leader_functions[]) (void) = {};
801
802#define NUMBER_OF_CHORDS 109
803#define NUMBER_OF_LEADER_COMBOS 0
804
805bool are_hashed_keycodes_in_sound(HASH_TYPE keycodes_hash, HASH_TYPE sound) {
806 return (keycodes_hash & sound) == keycodes_hash;
807}
808
809uint8_t keycode_to_index(uint16_t keycode) {
810 return keycode - FIRST_INTERNAL_KEYCODE;
811}
812
813void sound_keycode_array(uint16_t keycode) {
814 uint8_t index = keycode_to_index(keycode);
815 keycode_index++;
816 keycodes_buffer_array[index] = keycode_index;
817}
818
819void silence_keycode_hash_array(HASH_TYPE keycode_hash) {
820 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
821 bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash;
822 if (index_in_hash) {
823 uint8_t current_val = keycodes_buffer_array[i];
824 keycodes_buffer_array[i] = 0;
825 for (int j = 0; j < NUMBER_OF_KEYS; j++) {
826 if (keycodes_buffer_array[j] > current_val) {
827 keycodes_buffer_array[j]--;
828 }
829 }
830 keycode_index--;
831 }
832 }
833}
834
835bool are_hashed_keycodes_in_array(HASH_TYPE keycode_hash) {
836 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
837 bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash;
838 bool index_in_array = (bool) keycodes_buffer_array[i];
839 if (index_in_hash && !index_in_array) {
840 return false;
841 }
842 }
843 return true;
844}
845
846void kill_one_shots(void) {
847 struct Chord chord_storage;
848 struct Chord* chord_ptr;
849 struct Chord* chord;
850
851 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
852 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
853 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
854 chord = &chord_storage;
855
856 if (*chord->state == IN_ONE_SHOT) {
857 *chord->state = RESTART;
858 chord->function(chord);
859 if (*chord->state == RESTART) {
860 *chord->state = IDLE;
861 }
862 }
863 }
864}
865
866void process_finished_dances(void) {
867 struct Chord chord_storage;
868 struct Chord* chord_ptr;
869 struct Chord* chord;
870
871 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
872 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
873 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
874 chord = &chord_storage;
875
876 if (*chord->state == ACTIVATED) {
877 *chord->state = PRESS_FROM_ACTIVE;
878 chord->function(chord);
879 if (a_key_went_through) {
880 kill_one_shots();
881 }
882 dance_timer = timer_read();
883 } else if (*chord->state == IDLE_IN_DANCE) {
884 *chord->state = FINISHED;
885 chord->function(chord);
886 if (*chord->state == FINISHED) {
887 *chord->state = RESTART;
888 if (*chord->state == RESTART) {
889 *chord->state = IDLE;
890 }
891 }
892 } else if (*chord->state == PRESS_FROM_ACTIVE) {
893 *chord->state = FINISHED_FROM_ACTIVE;
894 chord->function(chord);
895 if (a_key_went_through) {
896 kill_one_shots();
897 }
898 dance_timer = timer_read();
899 }
900 }
901}
902
903uint8_t keycodes_buffer_array_min(uint8_t* first_keycode_index) {
904 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
905 if (keycodes_buffer_array[i] == 1) {
906 if (first_keycode_index != NULL) {
907 *first_keycode_index = (uint8_t) i;
908 }
909 return 1;
910 }
911 }
912 return 0;
913}
914
915void remove_subchords(void) {
916 struct Chord chord_storage;
917 struct Chord* chord_ptr;
918 struct Chord* chord;
919
920 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
921 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
922 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
923 chord = &chord_storage;
924
925 if (!(*chord->state == READY || *chord->state == READY_IN_DANCE || *chord->state == READY_LOCKED)) {
926 continue;
927 }
928
929 struct Chord chord_storage_2;
930 struct Chord* chord_ptr_2;
931 struct Chord* chord_2;
932 for (int j = 0; j < NUMBER_OF_CHORDS; j++) {
933 if (i == j) {continue;}
934
935 chord_ptr_2 = (struct Chord*) pgm_read_word (&list_of_chords[j]);
936 memcpy_P(&chord_storage_2, chord_ptr_2, sizeof(struct Chord));
937 chord_2 = &chord_storage_2;
938
939 if (are_hashed_keycodes_in_sound(chord_2->keycodes_hash, chord->keycodes_hash)) {
940 if (*chord_2->state == READY) {
941 *chord_2->state = IDLE;
942 }
943 if (*chord_2->state == READY_IN_DANCE) {
944 *chord_2->state = IDLE_IN_DANCE;
945 }
946 if (*chord_2->state == READY_LOCKED) {
947 *chord_2->state = LOCKED;
948 }
949 }
950 }
951 }
952}
953
954void process_ready_chords(void) {
955 uint8_t first_keycode_index = 0;
956 while (keycodes_buffer_array_min(&first_keycode_index)) {
957 // find ready chords
958 struct Chord chord_storage;
959 struct Chord* chord_ptr;
960 struct Chord* chord;
961
962 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
963 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
964 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
965 chord = &chord_storage;
966
967 // if the chord does not contain the first keycode
968 bool contains_first_keycode = ((uint32_t) 1 << first_keycode_index) & chord->keycodes_hash;
969 if (!contains_first_keycode) {
970 continue;
971 }
972
973 if (!are_hashed_keycodes_in_array(chord->keycodes_hash)){
974 continue;
975 }
976
977 if (*chord->state == LOCKED) {
978 *chord->state = READY_LOCKED;
979 continue;
980 }
981
982 if (!(chord->pseudolayer == current_pseudolayer || chord->pseudolayer == ALWAYS_ON)) {
983 continue;
984 }
985
986 if (*chord->state == IDLE) {
987 *chord->state = READY;
988 continue;
989 }
990
991 if (*chord->state == IDLE_IN_DANCE) {
992 *chord->state = READY_IN_DANCE;
993 }
994 }
995
996 // remove subchords
997 remove_subchords();
998
999 // execute logic
1000 // this should be only one chord
1001 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1002 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1003 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1004 chord = &chord_storage;
1005
1006 if (*chord->state == READY_LOCKED) {
1007 *chord->state = RESTART;
1008 chord->function(chord);
1009 if (*chord->state == RESTART) {
1010 *chord->state = IDLE;
1011 }
1012 break;
1013 }
1014
1015 if (*chord->state == READY || *chord->state == READY_IN_DANCE) {
1016 if (last_chord && last_chord != chord) {
1017 process_finished_dances();
1018 }
1019
1020 bool lock_next_prev_state = lock_next;
1021
1022 *chord->state = ACTIVATED;
1023 chord->function(chord);
1024 dance_timer = timer_read();
1025
1026 if (lock_next && lock_next == lock_next_prev_state) {
1027 lock_next = false;
1028 *chord->state = PRESS_FROM_ACTIVE;
1029 chord->function(chord);
1030 if (*chord->state == PRESS_FROM_ACTIVE) {
1031 *chord->state = LOCKED;
1032 }
1033 if (a_key_went_through) {
1034 kill_one_shots();
1035 }
1036 }
1037 break;
1038 }
1039 }
1040
1041 // silence notes
1042 silence_keycode_hash_array(chord->keycodes_hash);
1043 }
1044}
1045
1046void deactivate_active_chords(uint16_t keycode) {
1047 HASH_TYPE hash = (HASH_TYPE)1 << (keycode - SAFE_RANGE);
1048 bool broken;
1049 struct Chord chord_storage;
1050 struct Chord* chord_ptr;
1051 struct Chord* chord;
1052
1053 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1054 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1055 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1056 chord = &chord_storage;
1057
1058 broken = are_hashed_keycodes_in_sound(hash, chord->keycodes_hash);
1059 if (!broken) {
1060 continue;
1061 }
1062
1063 switch (*chord->state) {
1064 case ACTIVATED:
1065 *chord->state = DEACTIVATED;
1066 chord->function(chord);
1067
1068 if (*chord->state == DEACTIVATED) {
1069 dance_timer = timer_read();
1070 *chord->state = IDLE_IN_DANCE;
1071 }
1072 if (*chord->state != IN_ONE_SHOT) {
1073 kill_one_shots();
1074 }
1075 break;
1076 case PRESS_FROM_ACTIVE:
1077 case FINISHED_FROM_ACTIVE:
1078 *chord->state = RESTART;
1079 chord->function(chord);
1080 if (*chord->state == RESTART) {
1081 *chord->state = IDLE;
1082 }
1083 kill_one_shots();
1084 break;
1085 default:
1086 break;
1087 }
1088 }
1089
1090}
1091
1092void process_command(void) {
1093 command_mode = 0;
1094 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
1095 if (command_buffer[i]) {
1096 register_code(command_buffer[i]);
1097 }
1098 send_keyboard_report();
1099 }
1100 wait_ms(TAP_TIMEOUT);
1101 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
1102 if (command_buffer[i]) {
1103 unregister_code(command_buffer[i]);
1104 }
1105 send_keyboard_report();
1106 }
1107 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
1108 command_buffer[i] = 0;
1109 }
1110 command_ind = 0;
1111}
1112
1113void process_leader(void) {
1114 in_leader_mode = false;
1115 for (int i = 0; i < NUMBER_OF_LEADER_COMBOS; i++) {
1116 uint16_t trigger[LEADER_MAX_LENGTH];
1117 memcpy_P(trigger, leader_triggers[i], LEADER_MAX_LENGTH * sizeof(uint16_t));
1118
1119 if (identical(leader_buffer, trigger)) {
1120 (*leader_functions[i])();
1121 break;
1122 }
1123 }
1124 for (int i = 0; i < LEADER_MAX_LENGTH; i++) {
1125 leader_buffer[i] = 0;
1126 }
1127}
1128
1129bool process_record_user(uint16_t keycode, keyrecord_t *record) {
1130 if (keycode < FIRST_INTERNAL_KEYCODE || keycode > LAST_INTERNAL_KEYCODE) {
1131 return true;
1132 }
1133
1134 if (record->event.pressed) {
1135 sound_keycode_array(keycode);
1136 } else {
1137 process_ready_chords();
1138 deactivate_active_chords(keycode);
1139 }
1140 chord_timer = timer_read();
1141 leader_timer = timer_read();
1142
1143 return false;
1144}
1145
1146void matrix_scan_user(void) {
1147 bool chord_timer_expired = timer_elapsed(chord_timer) > CHORD_TIMEOUT;
1148 if (chord_timer_expired && keycodes_buffer_array_min(NULL)) {
1149 process_ready_chords();
1150 }
1151
1152 bool dance_timer_expired = timer_elapsed(dance_timer) > DANCE_TIMEOUT;
1153 if (dance_timer_expired) { // would love to have && in_dance but not sure how
1154 process_finished_dances();
1155 }
1156
1157 bool in_command_mode = command_mode == 2;
1158 if (in_command_mode) {
1159 process_command();
1160 }
1161
1162 bool leader_timer_expired = timer_elapsed(leader_timer) > LEADER_TIMEOUT;
1163 if (leader_timer_expired && in_leader_mode) {
1164 process_leader();
1165 }
1166
1167}
1168
1169void clear(const struct Chord* self) {
1170 if (*self->state == ACTIVATED) {
1171 // kill all chords
1172 struct Chord chord_storage;
1173 struct Chord* chord_ptr;
1174 struct Chord* chord;
1175
1176 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
1177 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
1178 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
1179 chord = &chord_storage;
1180
1181 *chord->state = IDLE;
1182
1183 if (chord->counter) {
1184 *chord->counter = 0;
1185 }
1186 }
1187
1188 // clear keyboard
1189 clear_keyboard();
1190 send_keyboard_report();
1191
1192 // switch to default pseudolayer
1193 current_pseudolayer = DEFAULT_PSEUDOLAYER;
1194
1195 // clear all keyboard states
1196 lock_next = false;
1197 autoshift_mode = true;
1198 command_mode = 0;
1199 in_leader_mode = false;
1200 leader_ind = 0;
1201 dynamic_macro_mode = false;
1202 a_key_went_through = false;
1203
1204 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
1205 dynamic_macro_buffer[i] = 0;
1206 }
1207 }
1208} \ No newline at end of file
diff --git a/keyboards/georgi/keymaps/dennytom/keymap_def.json b/keyboards/georgi/keymaps/dennytom/keymap_def.json
new file mode 100644
index 000000000..232ccafad
--- /dev/null
+++ b/keyboards/georgi/keymaps/dennytom/keymap_def.json
@@ -0,0 +1,153 @@
1{
2 "keys": [
3 "TOP1", "TOP2", "TOP3", "TOP4", "TOP5", "TOP6", "TOP7", "TOP8", "TOP9", "TOP10", "TOP11", "TOP12",
4 "BOT1", "BOT2", "BOT3", "BOT4", "BOT5", "BOT6", "BOT7", "BOT8", "BOT9", "BOT10", "BOT11", "BOT12",
5 "THU1", "THU2", "THU3", "THU4", "THU5", "THU6"
6 ],
7 "parameters": {
8 "layout_function_name": "LAYOUT_georgi",
9 "chord_timeout": 100,
10 "dance_timeout": 200,
11 "leader_timeout": 750,
12 "tap_timeout": 50,
13 "command_max_length": 5,
14 "leader_max_length": 5,
15 "dynamic_macro_max_length": 20,
16 "string_max_length": 16,
17 "long_press_multiplier": 3,
18 "default_pseudolayer": "QWERTY"
19 },
20 "layers": [
21 {
22 "type": "auto"
23 }
24 ],
25 "chord_sets": [
26 {
27 "name": "rows",
28 "chords":
29 [
30 ["TOP1"], ["TOP2"], ["TOP3"], ["TOP4"], ["TOP5"], ["TOP6"], ["TOP7"], ["TOP8"], ["TOP9"], ["TOP10"], ["TOP11"], ["TOP12"],
31 ["TOP1", "BOT1"], ["TOP2", "BOT2"], ["TOP3", "BOT3"], ["TOP4", "BOT4"], ["TOP5", "BOT5"], ["TOP6", "BOT6"], ["TOP7", "BOT7"], ["TOP8", "BOT8"], ["TOP9", "BOT9"], ["TOP10", "BOT10"], ["TOP11", "BOT11"], ["TOP12", "BOT12"],
32 ["BOT1"], ["BOT2"], ["BOT3"], ["BOT4"], ["BOT5"], ["BOT6"], ["BOT7"], ["BOT8"], ["BOT9"], ["BOT10"], ["BOT11"], ["BOT12"],
33 ["THU1"], ["THU2"], ["THU3"], ["THU4"], ["THU5"], ["THU6"]
34 ]
35 }
36 ],
37 "pseudolayers": [
38 {
39 "name": "ALWAYS_ON",
40 "chords": [
41 {
42 "type": "visual",
43 "chord": [
44 "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X",
45 "X", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "X",
46 " ", " ", " ", " ", " ", " "
47 ],
48 "keycode": "CLEAR_KB"
49 },
50 {
51 "type": "visual",
52 "chord": [
53 " ", " ", " ", " ", " ", "X", "X", " ", " ", " ", " ", " ",
54 " ", " ", " ", " ", " ", "X", "X", " ", " ", " ", " ", " ",
55 " ", " ", " ", " ", " ", " "
56 ],
57 "keycode": "CMD"
58 }
59 ]
60 },
61 {
62 "name": "QWERTY",
63 "chords": [
64 {
65 "type": "chord_set",
66 "set": "rows",
67 "keycodes": [
68 "ESC", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "\\",
69 "INS", "A", "KK(S, LALT)", "KM(D, LCTL)", "KM(F, LSFT)", "KK(G, LGUI)", "KK(H, RGUI)", "KM(J, RSFT)", "KM(K, RCTL)", "KK(L, RALT)", ";", " ",
70 "TAB", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "'",
71 "","","","","",""
72 ]
73 },
74 {
75 "type": "visual_array",
76 "keys": ["THU1", "THU2", "THU3", "THU4", "THU5", "THU6"],
77 "dictionary": [
78 ["X", " ", " ", " ", " ", " ", "ENTER"],
79 [" ", "X", " ", " ", " ", " ", "KL(SPC, NUM)"],
80 [" ", " ", "X", " ", " ", " ", "KL(BSPC, NAV)"],
81 [" ", " ", " ", "X", " ", " ", "DEL"],
82 [" ", " ", " ", " ", "X", " ", "KL(SPC, FNC)"],
83 [" ", " ", " ", " ", " ", "X", "ENTER"],
84 [" ", "X", "X", " ", " ", " ", "MO(MOUSE)"]
85 ]
86 }
87 ]
88 },
89 {
90 "name": "NUM",
91 "chords": [
92 {
93 "type": "chord_set",
94 "set": "rows",
95 "keycodes": [
96 "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-",
97 " ", " ", "LALT", "LCTL", "LSFT", "LGUI", "RGUI", "RSFT", "RCTL", "RALT", " ", " ",
98 " ", " ", " ", " ", " ", " ", " ", " ", " ", "[", "]", "=",
99 " ", " ", " ", " ", " ", " "
100 ]
101 }
102 ]
103 },
104 {
105 "name": "FNC",
106 "chords": [
107 {
108 "type": "chord_set",
109 "set": "rows",
110 "keycodes": [
111 " ", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11",
112 " ", " ", "LALT", "LCTL", "LSFT", "LGUI", "RGUI", "RSFT", "RCTL", "RALT", " ", " ",
113 " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "F12",
114 " ", " ", " ", " ", " ", " "
115 ]
116 }
117 ]
118 },
119 {
120 "name": "NAV",
121 "chords": [
122 {
123 "type": "chord_set",
124 "set": "rows",
125 "keycodes": [
126 " ", " ", " ", " ", " ", " ", " ", "HOME", "UP", "END", "PGUP", " ",
127 " ", " ", "LALT", "LCTL", "LSFT", "LGUI", " ", " ", " ", " ", " ", " ",
128 " ", " ", " ", " ", " ", " ", " ", "LEFT", "DOWN", "RIGHT", "PGDN", " ",
129 " ", " ", " ", " ", " ", " "
130 ]
131 }
132 ]
133 },
134 {
135 "name": "MOUSE",
136 "chords": [
137 {
138 "type": "chord_set",
139 "set": "rows",
140 "keycodes": [
141 " ", " ", " ", " ", " ", " ", " ", "BTN1", "MS_U", "BTN2", "WH_U", " ",
142 " ", " ", "LALT", "LCTL", "LSFT", "LGUI", " ", " ", " ", " ", " ", " ",
143 " ", " ", " ", " ", " ", " ", " ", "MS_L", "MS_D", "MS_R", "WH_D", " ",
144 " ", " ", " ", " ", " ", " "
145 ]
146 }
147 ]
148 }
149 ],
150 "leader_sequences": [],
151 "extra_code": "",
152 "extra_dependencies": []
153} \ No newline at end of file
diff --git a/keyboards/georgi/keymaps/dennytom/rules.mk b/keyboards/georgi/keymaps/dennytom/rules.mk
new file mode 100644
index 000000000..1155f72c0
--- /dev/null
+++ b/keyboards/georgi/keymaps/dennytom/rules.mk
@@ -0,0 +1,8 @@
1MOUSEKEY_ENABLE = yes
2EXTRAKEY_ENABLE = yes
3CONSOLE_ENABLE = no
4# COMMAND_ENABLE = no
5NKRO_ENABLE = yes
6
7TMPVAR := $(SRC)
8SRC = $(filter-out sten.c, $(TMPVAR)) \ No newline at end of file
diff --git a/users/dennytom/chording_engine/README.md b/users/dennytom/chording_engine/README.md
new file mode 100644
index 000000000..3610b190b
--- /dev/null
+++ b/users/dennytom/chording_engine/README.md
@@ -0,0 +1,376 @@
1# README
2
3## About
4
5This is a custom combo engine. I call it chording engine mostly to differentiate it from QMK's combos. It is useful even if you are not using chording as a main input method to replace combos.
6
7Why does this exist? Typing on tiny keyboards can be challenging and you will end up relying on dances and / or combos. Pure QMK combos can be insufficient as they do not really support overlapping combos. For example, if you define 3 combos `(KC_Q, KC_W)`, `(KC_Z, KC_X)` and `(KC_Q, KC_W, KC_Z, KC_X)` and press Q, W, Z and X at the same time, all three combos will activate. Steno engines (and g Board Industries' custom steno inspired engine) solve this, however, they don't allow for comfortable typing in the traditional way. The steno chord activates only when *all* keys are lifted and makes it difficult to implement some advanced features. This engine treats each chord independently to allow for more comfortable typing experience.
8
9## TOC
10
11- [README](#readme)
12 - [About](#about)
13 - [TOC](#toc)
14 - [Start here](#start-here)
15 - [Steps](#steps)
16 - [Features](#features)
17 - [Chords](#chords)
18 - [Tap-Dance](#tap-dance)
19 - [Pseudolayers](#pseudolayers)
20 - [Control chords](#control-chords)
21 - [Settings up JSON definition](#settings-up-json-definition)
22 - [Keyboard and engine parameters](#keyboard-and-engine-parameters)
23 - [Pseudolayers](#pseudolayers-1)
24 - [Supported keycodes](#supported-keycodes)
25 - [Leader Key](#leader-key)
26 - [Extra code](#extra-code)
27 - [Further details](#further-details)
28 - [Implementation](#implementation)
29 - [Internal keycodes](#internal-keycodes)
30 - [Chords](#chords-1)
31 - [Caveats](#caveats)
32
33## Start here
34
35This engine therefore uses python parser that translates a JSON definition of keyboard specific information and keymap definition and produces `keymap.c`. Every function on this keymap is a chord (combo). The resulting keymap file is long and I do not encourage you to edit it. All you should have to edit is the JSON file. To produce the keymap file, run
36
37```sh
38./parser.py keymap_def.json keymap.c
39```
40
41To prepare the keymap JSON definition, you can use on of my keymaps as a starting point. I have on for butterstick and for georgi. There is also a JSON schema that has some examples and sane defaults. All details are explained in the next section. The parser tries to validate some of the things that the JSON schema can not. Finally there is a JSON in the tests folder that has at least one example of every feature.
42
43Watch out, you can not name your JSON file `keymap.json` if you place in the keymap folder. QMK creates `keymap.json` as a part of compilation process and if you already have one, it gets confused.
44
45## Steps
46
47When setting up a new keyboard, follow the steps:
48
491. Make a new directory for your keymap as QMK's documentation describes.
502. Write your JSON. Name it anything but `keymap.json`.
513. Depending on the keyboard / keymap, create `rules.mk` (follow QMK's documentation and note that if the keyboard's `rules.mk` include custom source files, this is the place you can remove them).
524. Use my python parser to generate the `keymap.c`. Run it from the `/users/dennytom/chording_engine` directory as it is using relative paths to some extra files.
535. Follow QMK's documentation to compile and flash your firmware.
54
55## Features
56
57### Chords
58
59Once again, *everything* on this keymap is a chord. Even sending `KC_Q` is done by pressing a single key chord. Chord gets activated after all it's keys get pressed. Only the longest chord gets activated. The order of the pressed keys *does not matter*, only the fact they have been pressed within the same time frame. An active chord gets deactivated if *any* of it's keys gets depressed. To activate the same single chord again, *all* it's keys have to be depressed and pressed again. With a few exceptions chords are independent of each other. No matter if some chords are currently active and some not, others can be activated or deactivated without affecting each other's state. *If you press keys to belonging to multiple different, non-overlapping chords, all get activated in the order they are defined in the keymap.*
60
61### Tap-Dance
62
63To make it even stranger, all chords are technically tap-dance chords. They are relatively simple state machines that execute a specific function every time they change state. For simplicity and optimization purposes, there are a few prewritten functions that implement common features like "send a single key" or "lock". Any number of chords can be "in dance" at any given moment without affecting each other's state. Custom dances can be easily added. Check out the `state_machine.png` to see all the states any chord can be in.
64
65### Pseudolayers
66
67Only one QMK layer is used. Following the butterstick's default keymap's example, the chording engine is using pseudolayers. The main difference to QMK's layers is that only one pseudolayer can be active at each time (meaning you can not use `KC_TRANS`, I actually don't know what will happen if you do). Chords can be activated only if they are on the currently active pseudolayer. Chords that are currently active do not get deactivated if the pseudolayer changes and will deactivate if any of their keys gets depressed even no matter the current pseudolayer. Locked chords (see below) and chords on the `ALWAYS_ON` pseudolayer can be activated anytime.
68
69### Control chords
70
71The engine implements a number of ways of changing how chords behave:
72
73* **Lock**: Similarly to QMK's lock, the next chord activated after the Lock chord will not deactivate on release of any of its keys, it will deactivate when all its keys get pressed again. Any number of chords can be locked at the same time. To make sure a locked chord can be unlocked, it can activate no matter the current pseudolayer. A chord can be locked mid dance.
74* **One shots**: Chords that send keycodes and chords that turn on pseudolayers can be one shots. If tapped, they will lock (stay active) until the next keycode gets sent, *not necessarily when the next chord gets activated*. If held, they will deactivate on release *even if no keycode got sent*.
75* **Tap-Hold**: Also called key-layer dance and key-key dance. Either sends a defined keycode on tap and temporarily switches pseudolayer on hold *or* sends two different keycodes on tap and hold.
76* **Command mode**: After getting activated for the first time, the keyboard switches to command mode. All *keycodes* that would get registered get buffered instead. After activating the Command mode chord for the second time, all buffered keycodes get released at the same time allowing for key combination that would be hard or impossible to press. The Command mode only affects keycodes. It is therefore possible to change pseudolayers or activate / deactivate other chords while in Command mode. While multiple Command mode chords can be defined, they would not be independent. The keyboard either is or is not in command mode and there is only one buffer.
77* **Leader key**: Just like pure QMK's Leader key, this allows you to add functions that get executed if the Leader key and a specific sequence of keycodes gets registered in a predefined order in a short timeframe. For example `:wq` can send `Ctrl+S` and `Ctrl+W` in a quick succession. While multiple Leader keys can be defined, they all would access the same list of sequences.
78* **Dynamic macro**: A sequence of keycodes can be recorded and stored in the RAM of the keyboard and replayed.
79
80## Settings up JSON definition
81
82The JSON definition has 3 main sections. The elements `keys`, `parameters` and `layers` teach the engine about the details of your keyboard and set its parameters. The elements `pseudolayers`, `leader_sequences` and `chord_sets` define your keymap. Finally, the elements `extra_code` and `extra_dependencies` allow you to include more code to extend the capabilities of the engine.
83
84### Keyboard and engine parameters
85
86I do not have experience with stenography, so the the steno keycodes are hard for me to remember. That is why the keymap is using new keycodes TOP1, TOP2, ... .
87
88```c
89 "keys": ["TOP1", "TOP2", "TOP3", ...]
90```
91
92You can name these however you like as long as they do not crash with QMK's keycodes.
93
94*The chording engine in it's current implementation can handle up to 64 keys. If you need to support more, contact me (email or u/DennyTom at Reddit).*
95
96All timings, maximum lengths for macros, command mode and leader function are defined in `keyboard_parameters` field. Almost all should be pretty self-explanatory.
97
98My keyboards are small, so I only use the engine, but you might want to use layers that combine chord-able keys and traditional QMK keys or layers with advanced keycodes, for example for stenography. The array `layers` defines all the parser needs to know:
99
100```json
101"layers": [
102 {
103 "type": "auto"
104 },
105 {
106 "type": "manual",
107 "keycodes": ["KC_1", "KC_2", "KC_3", "KC_4", "KC_5", "KC_6", "KC_7", "KC_8", "KC_9", "KC_0",
108 "KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P"
109 ]
110 },
111 {
112 "type": "manual",
113 "keycodes": ["KC_1", "KC_2", "KC_3", "KC_4", "KC_5", "KC_6", "KC_7", "KC_8", "KC_9", "KC_0",
114 "BOT1", "BOT2", "BOT3", "BOT4", "BOT5", "BOT6", "BOT7", "BOT8", "BOT9", "BOT0"]
115 }
116 ]
117```
118
119This example defines 3 layers, one that is automatically populated with chording engine's internal keycodes, second that is populated with QMK's keycodes and third that uses both internal and QMK's keycodes. The layers do not have names, you have to access them with `TO(1)` and `TO(0)`.
120
121Some keyboards mangle the order of keycodes when registering them in the layers. For that fill up the `layout_function_name` with the name of function / macro. If your keyboard does not do it, leave that string empty.
122
123### Pseudolayers
124
125Array `pseudolayers` defines the keymap per pseudolayer. Each field has to contain the name for the layer and the list of chords.
126
127```JSON
128"pseudolayers": [
129 {
130 "name": "QWERTY",
131 "chords": [
132 {
133 "type": "simple",
134 "keycode": "SPACE",
135 "chord": ["BOT1", "BOT0"]
136 },
137 {
138 "type": "visual",
139 "keycode": "CLEAR_KB",
140 "chord": [
141 "X", "", "", "", "", "", "", "", "", "X",
142 "X", "", "", "", "", "", "", "", "", "X",
143 ]
144 },
145 {
146 "type": "visual_array",
147 "keys": ["TOP1", "TOP2", "TOP3"],
148 "dictionary": [
149 ["X", "X", " ", "ESC"],
150 [" ", "X", "X", "TAB"],
151 ["X", "X", "X", "ENTER"]
152 ]
153 },
154 {
155 "type": "chord_set",
156 "set": "rows",
157 "keycodes": [
158 "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
159 "A", "S", "D", "F", "G", "H", "J", "K", "L", ";",
160 "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/"
161 ]
162 }
163 ]
164 }
165]
166```
167
168The array `chord` defines chords. You can either use simple chord and list all the keys that have to pressed at the same time, or use the visual chord and place `"X"` over keys that will be part of the chord. You can also use `visual_array` to define a number of chords in a visual way on a subset of keys defined in the `keys` array. Finally, you can use `chord_set` to define a number of chords following a pattern that was set in the `chord_sets` array in the root object like this:
169
170```json
171"chord_sets": [
172 {
173 "name": "rows",
174 "chords": [
175 ["TOP1"], ["TOP2"], ["TOP3"], ["TOP4"], ["TOP5"], ["TOP6"], ["TOP7"], ["TOP8"], ["TOP9"], ["TOP0"]
176 ["TOP1", "BOT1"], ["TOP2", "BOT2"], ["TOP3", "BOT3"], ["TOP4", "BOT4"], ["TOP5", "BOT5"], ["TOP6", "BOT6"], ["TOP7", "BOT7"], ["TOP8", "BOT8"], ["TOP9", "BOT9"], ["TOP0", "BOT0"],
177 ["BOT1"], ["BOT2"], ["BOT3"], ["BOT4"], ["BOT5"], ["BOT6"], ["BOT7"], ["BOT8"], ["BOT9"], ["BOT0"]
178 ]
179 },
180 {
181 "name": "cols",
182 "chords": [
183 ["TOP1", "TOP2"], ["TOP2", "TOP3"], ["TOP3", "TOP4"], ["TOP4", "TOP5"], ["TOP5", "TOP6"], ["TOP6", "TOP7"], ["TOP7", "TOP8"], ["TOP8", "TOP9"], ["TOP9", "TOP0"],
184 ["TOP1", "TOP2", "BOT1", "BOT2"], ["TOP2", "TOP3", "BOT2", "BOT3"], ["TOP3", "TOP4", "BOT3", "BOT4"], ["TOP4", "TOP5", "BOT4", "BOT5"], ["TOP5", "TOP6", "BOT5", "BOT6"], ["TOP6", "TOP7", "BOT6", "BOT7"], ["TOP7", "TOP8", "BOT7", "BOT8"], ["TOP8", "TOP9", "BOT8", "BOT9"], ["TOP9", "TOP0", "BOT9", "BOT0"],
185 ["BOT1", "BOT2"], ["BOT2", "BOT3"], ["BOT3", "BOT4"], ["BOT4", "BOT5"], ["BOT5", "BOT6"], ["BOT6", "BOT7"], ["BOT7", "BOT8"], ["BOT8", "BOT9"], ["BOT9", "BOT00"],
186 ]
187 }
188]
189```
190
191
192
193You might notice that the code tries to do a few clever things when parsing keycodes:
194
195* If the keycode would be just a character basic keycode, it tries to allow the use of shortcuts. `Q` will get replaced with `KC_Q`, `,` becomes `KC_COMMA`. This *should* work for all KC_ keycodes unless I missed some.
196* `MO()` and `DF()` macros work the same way for pseudolayers as they would for layers in pure QMK.
197* `O()` is a shortcut for `OSK()` or `OSL()`.
198* `STR('...')` sends a string. Careful with quoting.
199* Special chords like Command mode have their own codes like `CMD`.
200* The empty strings get ignored.
201
202### Supported keycodes
203
204* **`X`** or **`KC_X`**: Send code `KC_X` just like a normal keyboard.
205
206* **`STR("X")`**: Send string "x" on each activation of the chord. Once again, watch out for quoting and escaping characters. If you want special characters (especially quotes) in your string, look up Python reference for string literals and experiment. Also, because of how the string gets parsed, it is not possible to use `(` in the string.
207
208* **`MO(X)`**: Temporary switch to pseudolayer `X`. Because only one pseudolayer can be active at any moment, this works by switching back to the pseudolayer the chord lives on on deactivation. If you chain `MO()`s on multiple pseudolayers and deactivate them in a random order, you might end up stranded on a pseudolayer. I recommend adding `CLEAR` somewhere on `ALWAYS_ON` pseudolayer just in case.
209
210* **`MO(X,Y)`**: Temporary switch to pseudolayer `Y`. Switches to pseudolayer `X` on deactivation. Especially useful when you want to put the `MO()` chord on `ALWAYS_ON`.
211
212* **`DF(X)`**: Permanent switch to pseudolayer `X`.
213
214* **`TO(X)`**: Switches the QMK layer to `X`.
215
216* **`O(X)`**: One-shot key `X` (if `X` starts with `"KC_"`) or one-shot layer `X` (otherwise) . Both have retro tapping enabled.
217
218* **Tap-holds**
219
220 * **`KK(X, Y)`**: Pulses code `X` on tap and code `Y` on hold.
221 * **`KL(X, Y)`**: Pulses code `X` on tap and switches to pseudolayer `Y` on hold. If during the hold no key gets registered, the code `X` will get sent instead (similar to QMK's retro tapping).
222 * **`KM(X, Y)`**: Same as `KK()` but meant for modifiers on hold. Instead of a timer to figure out tap-hold, uses retro tapping like behavior just like `KL()`. This has issues with GUI and ALT as they often have a meaning.
223 * The chording engine determines if you are holding a chord based on a *global* timer. If you start holding a tap-hold chord and very quickly start tapping other chords, the hold might not activate until a short moment *after the last* chord when the timer expires. If you are running into this, adjust timeouts or wait a brief moment after pressing the chord to make sure it switches into the hold state before pressing other chords.
224
225* **Autoshift**
226
227 * **`AS(X)`**: Pulses code `X` on tap and Pulses left shift + `X` on hold.
228 * **`AT`** : Toggles autoshift for all autoshift chords. If off, all `AS` chords act like `KC` chords.
229
230* **`LOCK`**: The lock key. Since tap-dances of chords are independent, it is possible to lock a chord *anywhere in it's dance if you time it right!*. If that happens, use the `CLEAR` chord or restart your keeb.
231
232* **`CMD`**: The command mode. The number of keycodes that can be buffered is defined in in `command_max_length`.
233
234* **`LEAD`**: The leader key. The maximum length of the sequences needs to be defined in `keyboard_params`. You can use `leader_sequences` array to add sequences:
235
236 ```json
237 "leader_sequences": [
238 {
239 "name": "fn_L1",
240 "function": "void fn_L1(void) { SEND(KC_LCTL); SEND(KC_LALT); SEND(KC_DEL); }",
241 "sequence": ["KC_Q", "KC_Z"]
242 }
243 ]
244 ```
245
246 When the engine notices the sequence, it will call the function defined in the field `name`. You can either define it in the `function` field, in the field `extra_code` or in an external file that you then have to insert manually or using the `extra_dependencies` array. The parser copy-pastes the contents `extra_code` of all files specified in the `extra_dependencies` array in the `keymap.c`.
247
248* **`M(X, VALUE1, VALUE2)`**: A custom macro. Adds a chord that will use function `X` and with `chord.value1 = VALUE1; chord.value2 = VALUE2;`. The function `X` can be arbitrary C function, go crazy. Just like with the leader sequences, you have to insert the code into the generated `keymap.c` manually or through `extra_code` or `extra_dependencies`. The following example defines a macro that acts exactly like `KC_MEH` (the chording engine *should* support `KC_MEH`, this is just an example):
249
250 ```c
251 void fn_M1(const struct Chord* self) {
252 switch (*self->state) {
253 case ACTIVATED:
254 key_in(KC_LCTL);
255 key_in(KC_LSFT);
256 key_in(KC_LALT);
257 break;
258 case DEACTIVATED:
259 key_out(KC_LCTL);
260 key_out(KC_LSFT);
261 key_out(KC_LALT);
262 break;
263 case FINISHED:
264 case FINISHED_FROM_ACTIVE:
265 break;
266 case RESTART:
267 key_out(KC_LCTL);
268 key_out(KC_LSFT);
269 key_out(KC_LALT);
270 break;
271 default:
272 break;
273 }
274 }
275 ```
276
277 Since this feels like it would be the most common way to use this feature, I wrote a macro for this:
278
279* **`MK(X1, X2, ...)`**: Acts like `KC()` except it registers / unregisters all `X1`, `X2`, ... codes at the same time.
280
281* **`D(X1, X2, ...)`**: A basic keycode dance. If tapped (or held), registers `X1`. If tapped and then tapped again (or held), registers `X2`, ... It *cannot* be combined with tap-hold, however holding will result in repeat. You can put in as many basic keycodes as you want, but the macro will break if you go beyond 256. It will try to expand shortened keycodes. Advanced keycodes are not supported.
282
283* **`DM_RECORD`, `DM_NEXT`, `DM_END`, `DM_PLAY`**: Start recording a dynamic macro. Once you start recording, basic keycodes will get stored. When replaying the macro, all keys you press before `DM_NEXT` or `DM_END` will get pressed at the same time. For example the sequence `DM_RECORD`, `KC_CTRL`, `KC_A`, `DM_NEXT`, `KC_BSPC`, `DM_END` will record a macro that when played will execute the sequence Ctrl+a, Backspace. `dynamic_macro_max_length` defines the maximum length of the macro to be recorded. You can increase it for the price of RAM. The example above requires 4 units of length to be saved (Ctrl, A, next, Backspace).
284
285* **`CLEAR_KB`**: clears keyboard, sets all chords to the default state and switches the pseudolayer to the default one. Basically the emergency stop button.
286
287* **`RESET`**: Go to the DFU flashing mode.
288
289**Caveat** of the current implementation is that the tap-hold, `MK` and `D` keycodes can not accept any of the keycodes that have some sort a function like dynamic macro specific chords, `CLEAR_KB`, `RESET`, `LOCK`, `AT`, ...
290
291### Leader Key
292
293The sequences are not defined by the *keys* you press but by the *keycodes* that get intercepted. The length of the sequence must be equal or shorter than the maximum (defined in `keyboard.inc`). Currently, the timeout for the leader sequence refreshes after each key pressed. If the sequence is not in the database, nothing will happen.
294
295### Extra code
296
297Extra C code needed to define custom chords can be added by quoting in in the `extra_code` element or by saving it in another header file and including it using the `extra_dependencies` element:
298
299```json
300{
301 "extra_code": "void double_dance(const struct Chord* self) { ... }\n",
302 "extra_dependencies": ["my_header.h"]
303}
304```
305
306
307
308## Further details
309
310### Implementation
311
312The source files are split into several files. `engine.part.1`, `engine.part.2` and `engine.part.3` contain C code that defines the Chord structure, implementations for all provided functions and the engine itself. `parser.py` generates keyboard and keymap dependent code. The file `chord.py` contains most of the logic required to properly translate chords from the JSON to the C code. I rarely write in python, if you have improvements, let me know, *please*.
313
314### Internal keycodes
315
316When `process_record_user()` gets one of the internal keycodes, it returns `true`, completely bypassing keyboard's and QMK's `process_record` functions. *All other* keycodes get passed down to QMK's standard processing.
317
318### Chords
319
320Each chord is defined by a constant structure, a function and two non-constant `int` variables keeping the track of the chord's state:
321
322```c
323struct Chord {
324 uint32_t keycodes_hash;
325 uint8_t pseudolayer;
326 uint8_t* state;
327 uint8_t* counter;
328 uint16_t value1;
329 uint8_t value2;
330 void (*function) (const struct Chord*);
331};
332
333uint8_t state_0 = IDLE;
334uint8_t counter_0 = 0;
335void function_0(struct Chord* self) {
336 switch (*self->state) {
337 case ACTIVATED:
338 register_code(self->value1);
339 break;
340 case DEACTIVATED:
341 unregister_code(self->value1);
342 break;
343 case FINISHED:
344 case PRESS_FROM_ACTIVE:
345 break;
346 case RESTART:
347 unregister_code(self->value1);
348 break;
349 default:
350 break;
351 }
352}
353const struct Chord chord_0 PROGMEM = {H_TOP1, QWERTY, &state_0, &counter_0, KC_Q, 0, function_0};
354```
355
356All chords have to be added to `list_of_chord` array that gets regularly scanned and processed. The function doesn't actually activate on all state changes, there are a few more like `IDLE` (nothing is currently happening to the chord) or `IN_ONE_SHOT` (the chord is one shot and is currently locked). Those are all necessary for internal use only. The ones you have to worry about are
357
358* `ACTIVATED`: Analogous to a key being pressed (this includes repeated presses for tap-dance)
359* `DEACTIVATED`: Analogous to a key being depressed (also can be repeated)
360* `FINISHED`: Happens if the chord got deactivated and then the dance timer expired.
361* `PRESS_FROM_ACTIVE`: Happens if the chord was active when the dance timer expired. Meaning you at least once activated the chord and then kept holding it down. Useful to recognize taps and holds.
362* `FINISHED_FROM_ACTIVE`: Happens *after* `PRESS_FROM_HOLD` if the chord is still active when the dance timer expires for the second time. Can be combined with the `counter` to recognize even longer presses. Useful if you want to recognize long presses, for example for autoshift functionality. In `keyboard.inc` you can set `LONG_PRESS_MULTIPLIER` to set how many times does dance timer have to expire for the autoshift to trigger.
363* `RESTART`: The dance is done. Happens immediately after `FINISHED` or on chord deactivation from `FINISHED_FROM_ACTIVE`. Anything you have to do to get the chord into `IDLE` mode happens here.
364
365The chords change states based on external and internal events. Anytime a chord's function is activated, it may change it's own state. Also, on certain events, the chording engine will trigger the functions of all chords in a specific state and *if the chords' state hasn't changed* it will then change it appropriately. The default behavior when a chord changes state is described by the following diagram:
366
367![state machine diagram](state_machine.png)
368The colors differentiate in which function the change happens, see `state_machine.dot` for a bit more detail. Black arrows happen in more than one function. Arrows without a label happen immediately.
369
370You can see that the diagram is not exhaustive. For example nothing leads into `IN_ONE_SHOT`. That is because the chord's function can change the chord's state. This is useful for some advanced chords that break the default behavir (one-shots) and for optimization (chords that just send `KC_X` do not need to ever go into dance).
371
372## Caveats
373
374Each chord stores as much as possible in `PROGMEM` and unless it needs it, doesn't allocate `counter`. However it still has to store it's `state` and sometimes the `counter` in RAM. If you keep adding more chords, at one point you will run out. If your firmware fits in the memory and your keyboard crashes, try optimizing your RAM usage.
375
376Also, the code is not perfect. I keep testing it, but can not guarantee that it is stable. Some functions take (very short but still) time and if you happen to create keypress event when the keyboard can not see it, a chord can get stuck in a funny state. That is especially fun if the pseudolayer changes and you can not immediately press it again. Just restart the keyboard or push the key a few times.
diff --git a/users/dennytom/chording_engine/chord.py b/users/dennytom/chording_engine/chord.py
new file mode 100644
index 000000000..707f36b82
--- /dev/null
+++ b/users/dennytom/chording_engine/chord.py
@@ -0,0 +1,466 @@
1from functools import reduce
2import re
3
4strings = []
5number_of_strings = -1
6
7def top_level_split(s):
8 """
9 Split `s` by top-level commas only. Commas within parentheses are ignored.
10 """
11
12 # Parse the string tracking whether the current character is within
13 # parentheses.
14 balance = 0
15 parts = []
16 part = ""
17
18 for i in range(len(s)):
19 c = s[i]
20 part += c
21 if c == '(':
22 balance += 1
23 elif c == ')':
24 balance -= 1
25 elif c == ',' and balance == 0 and not s[i+1] == ',':
26 part = part[:-1].strip()
27 parts.append(part)
28 part = ""
29
30 # Capture last part
31 if len(part):
32 parts.append(part.strip())
33
34 return parts
35
36def new_chord(on_pseudolayer, keycodes_hash, has_counter, value1, value2, function, output_buffer, index):
37 counter_link = "NULL"
38 output_buffer += "uint8_t state_" + str(index) + " = IDLE;\n"
39 if has_counter:
40 output_buffer += "uint8_t counter_" + str(index) + " = 0;\n"
41 counter_link = "&counter_" + str(index)
42 output_buffer += "const struct Chord chord_" + str(index) + " PROGMEM = {" + keycodes_hash + ", " + on_pseudolayer + ", &state_" + str(index) + ", " + counter_link + ", " + str(value1) + ", " + str(value2) + ", " + function + "};\n"
43 index += 1
44 return [output_buffer, index]
45
46def KC(on_pseudolayer, keycodes_hash, keycode, output_buffer, index):
47 return new_chord(on_pseudolayer, keycodes_hash, False, keycode, 0, "single_dance", output_buffer, index)
48
49def AS(on_pseudolayer, keycodes_hash, keycode, output_buffer, index):
50 return new_chord(on_pseudolayer, keycodes_hash, True, keycode, 0, "autoshift_dance", output_buffer, index)
51
52def AT(on_pseudolayer, keycodes_hash, output_buffer, index):
53 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "autoshift_toggle", output_buffer, index)
54
55def KL(on_pseudolayer, keycodes_hash, keycode, to_pseudolayer, output_buffer, index):
56 return new_chord(on_pseudolayer, keycodes_hash, True, keycode, to_pseudolayer, "key_layer_dance", output_buffer, index)
57
58def KK(on_pseudolayer, keycodes_hash, keycode1, keycode2, output_buffer, index):
59 return new_chord(on_pseudolayer, keycodes_hash, True, keycode1, keycode2, "key_key_dance", output_buffer, index)
60
61def KM(on_pseudolayer, keycodes_hash, keycode, to_pseudolayer, output_buffer, index):
62 return new_chord(on_pseudolayer, keycodes_hash, False, keycode, to_pseudolayer, "key_mod_dance", output_buffer, index)
63
64def MO(on_pseudolayer, keycodes_hash, to_pseudolayer, output_buffer, index):
65 return new_chord(on_pseudolayer, keycodes_hash, False, to_pseudolayer, 0, "temp_pseudolayer", output_buffer, index)
66
67def MO_alt(on_pseudolayer, keycodes_hash, from_pseudolayer, to_pseudolayer, output_buffer, index):
68 return new_chord(on_pseudolayer, keycodes_hash, False, to_pseudolayer, from_pseudolayer, "temp_pseudolayer_alt", output_buffer, index)
69
70def LOCK(on_pseudolayer, keycodes_hash, output_buffer, index):
71 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "lock", output_buffer, index)
72
73def DF(on_pseudolayer, keycodes_hash, to_pseudolayer, output_buffer, index):
74 return new_chord(on_pseudolayer, keycodes_hash, False, to_pseudolayer, 0, "perm_pseudolayer", output_buffer, index)
75
76def TO(on_pseudolayer, keycodes_hash, to_pseudolayer, output_buffer, index):
77 return new_chord(on_pseudolayer, keycodes_hash, False, to_pseudolayer, 0, "switch_layer", output_buffer, index)
78
79def OSK(on_pseudolayer, keycodes_hash, keycode, output_buffer, index):
80 return new_chord(on_pseudolayer, keycodes_hash, False, keycode, 0, "one_shot_key", output_buffer, index)
81
82def OSL(on_pseudolayer, keycodes_hash, to_pseudolayer, output_buffer, index):
83 return new_chord(on_pseudolayer, keycodes_hash, False, to_pseudolayer, 0, "one_shot_layer", output_buffer, index)
84
85def CMD(on_pseudolayer, keycodes_hash, output_buffer, index):
86 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "command", output_buffer, index)
87
88def DM_RECORD(on_pseudolayer, keycodes_hash, output_buffer, index):
89 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "dynamic_macro_record", output_buffer, index)
90
91def DM_NEXT(on_pseudolayer, keycodes_hash, output_buffer, index):
92 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "dynamic_macro_next", output_buffer, index)
93
94def DM_END(on_pseudolayer, keycodes_hash, output_buffer, index):
95 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "dynamic_macro_end", output_buffer, index)
96
97def DM_PLAY(on_pseudolayer, keycodes_hash, output_buffer, index):
98 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "dynamic_macro_play", output_buffer, index)
99
100def LEAD(on_pseudolayer, keycodes_hash, output_buffer, index):
101 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "leader", output_buffer, index)
102
103def CLEAR(on_pseudolayer, keycodes_hash, output_buffer, index):
104 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "clear", output_buffer, index)
105
106def RESET(on_pseudolayer, keycodes_hash, output_buffer, index):
107 return new_chord(on_pseudolayer, keycodes_hash, False, 0, 0, "reset", output_buffer, index)
108
109def STR(on_pseudolayer, keycodes_hash, string_input, output_buffer, index, number_of_strings, strings):
110 [a, b] = new_chord(on_pseudolayer, keycodes_hash, False, number_of_strings, 0, "string_in", output_buffer, index)
111 return [a, b, number_of_strings + 1, strings + [string_input]]
112
113def M(on_pseudolayer, keycodes_hash, value1, value2, fnc, output_buffer, index):
114 return new_chord(on_pseudolayer, keycodes_hash, True, value1, value2, fnc, output_buffer, index)
115
116def expand_keycode_fnc(DEFINITION):
117 if DEFINITION == "`":
118 DEFINITION = "GRAVE"
119 elif DEFINITION == "-":
120 DEFINITION = "MINUS"
121 elif DEFINITION == "=":
122 DEFINITION = "EQUAL"
123 elif DEFINITION == "[":
124 DEFINITION = "LBRACKET"
125 elif DEFINITION == "]":
126 DEFINITION = "RBRACKET"
127 elif DEFINITION == "\\":
128 DEFINITION = "BSLASH"
129 elif DEFINITION == ";":
130 DEFINITION = "SCOLON"
131 elif DEFINITION == "'":
132 DEFINITION = "QUOTE"
133 elif DEFINITION == ",":
134 DEFINITION = "COMMA"
135 elif DEFINITION == ".":
136 DEFINITION = "DOT"
137 elif DEFINITION == "/":
138 DEFINITION = "SLASH"
139 elif DEFINITION == "~":
140 DEFINITION = "TILDE"
141 elif DEFINITION == "*":
142 DEFINITION = "ASTERISK"
143 elif DEFINITION == "+":
144 DEFINITION = "PLUS"
145 elif DEFINITION == "(":
146 DEFINITION = "LEFT_PAREN"
147 elif DEFINITION == ")":
148 DEFINITION = "RIGHT_PAREN"
149 elif DEFINITION == "<":
150 DEFINITION = "LEFT_ANGLE_BRACKET"
151 elif DEFINITION == ">":
152 DEFINITION = "RIGHT_ANGLE_BRACKET"
153 elif DEFINITION == "{":
154 DEFINITION = "LEFT_CURLY_BRACE"
155 elif DEFINITION == "}":
156 DEFINITION = "RIGHT_CURLY_BRACE"
157 elif DEFINITION == "?":
158 DEFINITION = "QUESTION"
159 elif DEFINITION == "~":
160 DEFINITION = "TILDE"
161 elif DEFINITION == ":":
162 DEFINITION = "COLON"
163 elif DEFINITION == "_":
164 DEFINITION = "UNDERSCORE"
165 elif DEFINITION == '"':
166 DEFINITION = "DOUBLE_QUOTE"
167 elif DEFINITION == "@":
168 DEFINITION = "AT"
169 elif DEFINITION == "#":
170 DEFINITION = "HASH"
171 elif DEFINITION == "$":
172 DEFINITION = "DOLLAR"
173 elif DEFINITION == "!":
174 DEFINITION = "EXCLAIM"
175 elif DEFINITION == "%":
176 DEFINITION = "PERCENT"
177 elif DEFINITION == "^":
178 DEFINITION = "CIRCUMFLEX"
179 elif DEFINITION == "&":
180 DEFINITION = "AMPERSAND"
181 elif DEFINITION == "|":
182 DEFINITION = "PIPE"
183
184 if DEFINITION in [
185 "A", "a", "B", "b", "C", "c", "D", "d", "E", "e",
186 "F", "f", "G", "g", "H", "h", "I", "i", "J", "j",
187 "K", "k", "L", "l", "M", "m", "N", "n", "O", "o",
188 "P", "p", "Q", "q", "R", "r", "S", "s", "T", "t",
189 "U", "u", "V", "v", "W", "w", "X", "x", "Y", "y",
190 "Z", "z", "1", "2", "3", "4", "5", "6", "7", "8",
191 "9", "0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
192 "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
193 "F16", "F17", "F18", "F19", "F20", "F21", "F22",
194 "F23", "F24", "ENTER", "ENT", "ESCAPE", "ESC",
195 "BSPACE", "BSPC", "TAB", "SPACE", "SPC", "NONUS_HASH",
196 "NUHS", "NONUS_BSLASH", "NUBS", "COMMA", "COMM",
197 "DOT", "SLASH", "SLSH", "TILDE", "TILD", "EXCLAIM",
198 "EXLM", "AT", "HASH", "DOLLAR", "DLR", "PERCENT",
199 "PERC", "CIRCUMFLEX", "CIRC", "AMPERSAND", "AMPR",
200 "ASTERISK", "ASTR", "LEFT_PAREN", "LPRN", "RIGHT_PAREN",
201 "RPRN", "UNDERSCORE", "UNDS", "PLUS", "LEFT_CURLY_BRACE",
202 "LCBR", "RIGHT_CURLY_BRACE", "RCBR", "PIPE", "COLON",
203 "COLN", "DOUBLE_QUOTE", "DQUO", "DQT",
204 "LEFT_ANGLE_BRACKET", "LABK", "LT", "RIGHT_ANGLE_BRACKET",
205 "RABK", "GT", "QUESTION", "QUES", "SCOLON", "SCLN",
206 "QUOTE", "QUOT", "LBRACKET", "LBRC", "RBRACKET", "RBRC",
207 "BSLASH", "BSLS", "MINUS", "MINS", "EQUAL", "EQL",
208 "GRAVE", "GRV", "ZKHK", "CAPSLOCK", "CLCK", "CAPS",
209 "SCROLLOCK", "SLCK", "BRMD", "NUMLOCK", "NLCK",
210 "LOCKING_CAPS", "LCAP", "LOCKING_NUM", "LNUM",
211 "LOCKING_SCROLL", "LSCR", "LCTRL", "LCTL", "LSHIFT",
212 "LSFT", "LALT", "LGUI", "LCMD", "LWIN", "RCTRL",
213 "RCTL", "RSHIFT", "RSFT", "RALT", "RGUI", "RCMD",
214 "RWIN", "INT1", "RO", "INT2", "KANA", "INT3", "JYEN",
215 "INT4", "HENK", "INT5", "MHEN", "INT6", "INT7",
216 "INT8", "INT9", "LANG1", "HAEN", "LANG2", "HANJ",
217 "LANG3", "LANG4", "LANG5", "LANG6", "LANG7", "LANG8",
218 "LANG9", "PSCREEN", "PSCR", "PAUSE", "PAUS", "BRK",
219 "BRMU", "INSERT", "INS", "HOME", "PGUP", "DELETE",
220 "DEL", "END", "PGDOWN", "PGDN", "RIGHT", "RGHT",
221 "LEFT", "DOWN", "UP", "APPLICATION", "APP", "POWER",
222 "EXECUTE", "EXEC", "HELP", "MENU", "SELECT", "SLCT",
223 "STOP", "AGAIN", "AGIN", "UNDO", "CUT", "COPY",
224 "PASTE", "PSTE", "FIND", "MUTE", "VOLUP", "VOLDOWN",
225 "ALT_ERASE", "ERAS", "SYSREQ", "CANCEL", "CLEAR",
226 "CLR", "PRIOR", "RETURN", "SEPARATOR", "OUT", "OPER",
227 "CLEAR_AGAIN", "CRSEL", "EXSEL", "SYSTEM_POWER",
228 "PWR", "SYSTEM_SLEEP", "SLEP", "SYSTEM_WAKE", "WAKE",
229 "AUDIO_MUTE", "MUTE", "AUDIO_VOL_UP", "VOLU",
230 "AUDIO_VOL_DOWN", "VOLD", "MEDIA_NEXT_TRACK", "MNXT",
231 "MEDIA_PREV_TRACK", "MPRV", "CPRV", "MEDIA_STOP", "MSTP",
232 "MEDIA_PLAY_PAUSE", "MPLY", "MEDIA_SELECT", "MSEL",
233 "MEDIA_EJECT", "EJCT", "MAIL", "CALCULATOR", "CALC",
234 "MY_COMPUTER", "MYCM", "WWW_SEARCH", "WSCH", "WWW_HOME",
235 "WHOM", "WWW_BACK", "WBAK", "WWW_FORWARD", "WFWD",
236 "WWW_STOP", "WSTP", "WWW_REFRESH", "WREF",
237 "WWW_FAVORITES", "WFAV", "MEDIA_FAST_FORWARD", "MFFD",
238 "MEDIA_REWIND", "MRWD", "BRIGHTNESS_UP", "BRIU",
239 "BRIGHTNESS_DOWN", "BRID", "KP_SLASH", "PSLS",
240 "KP_ASTERISK", "PAST", "KP_MINUS", "PMNS", "KP_PLUS",
241 "PPLS", "KP_ENTER", "PENT", "KP_1", "P1", "KP_2", "P2",
242 "KP_3", "P3", "KP_4", "P4", "KP_5", "P5", "KP_6", "P6",
243 "KP_7", "P7", "KP_8", "P8", "KP_9", "P9", "KP_0", "P0",
244 "KP_DOT", "PDOT", "KP_EQUAL", "PEQL", "KP_COMMA", "PCMM",
245 "MS_BTN1", "BTN1", "MS_BTN2", "BTN2", "MS_BTN3", "BTN3",
246 "MS_BTN4", "BTN4", "MS_BTN5", "BTN5", "MS_BTN6", "BTN6",
247 "MS_LEFT", "MS_L", "MS_DOWN", "MS_D", "MS_UP", "MS_U",
248 "MS_RIGHT", "MS_R", "MS_WH_UP", "WH_U", "MS_WH_DOWN",
249 "WH_D", "MS_WH_LEFT", "MS_WH_L", "MS_WH_RIGHT", "MS_WH_R",
250 "KC_MS_ACCEL0", "ACL0", "KC_MS_ACCEL1", "ACL1",
251 "KC_MS_ACCEL2", "ACL2"
252 ]:
253 return "KC_" + DEFINITION
254 else:
255 return DEFINITION
256
257def MK(on_pseudolayer, keycodes_hash, definition, output_buffer, index):
258 l = len(definition.split(', '))
259 output_buffer += "void function_" + str(index) + "(const struct Chord* self) {\n"
260 output_buffer += " switch (*self->state) {\n"
261 output_buffer += " case ACTIVATED:\n"
262 for i in range(0, l):
263 val = definition.split(',')[i].strip()
264 code = expand_keycode_fnc(val)
265 output_buffer += " key_in(" + code + ");\n"
266 output_buffer += " break;\n"
267 output_buffer += " case DEACTIVATED:\n"
268 for i in range(0, l):
269 val = definition.split(',')[i].strip()
270 code = expand_keycode_fnc(val)
271 output_buffer += " key_out(" + code + ");\n"
272 output_buffer += " *self->state = IDLE;\n"
273 output_buffer += " break;\n"
274 output_buffer += " case RESTART:\n"
275 for i in range(0, l):
276 val = definition.split(',')[i].strip()
277 code = expand_keycode_fnc(val)
278 output_buffer += " key_out(" + code + ");\n"
279 output_buffer += " break;\n"
280 output_buffer += " default:\n"
281 output_buffer += " break;\n"
282 output_buffer += " };\n"
283 output_buffer += "}\n"
284 return new_chord(on_pseudolayer, keycodes_hash, True, 0, 0, "function_" + str(index), output_buffer, index)
285
286def D(on_pseudolayer, keycodes_hash, DEFINITION, output_buffer, index):
287 l = len(DEFINITION.split(','))
288 output_buffer += "void function_" + str(index) + "(const struct Chord* self) {\n"
289 output_buffer += " switch (*self->state) {\n"
290 output_buffer += " case ACTIVATED:\n"
291 output_buffer += " *self->counter = *self->counter + 1;\n"
292 output_buffer += " break;\n"
293 output_buffer += " case PRESS_FROM_ACTIVE:\n"
294 output_buffer += " switch (*self->counter) {\n"
295 for i in range(0, l):
296 val = DEFINITION.split(',')[i].strip()
297 code = expand_keycode_fnc(val)
298 output_buffer += " case " + str(i + 1) + ":\n"
299 output_buffer += " key_in( " + code + ");\n"
300 output_buffer += " break;\n"
301 output_buffer += " default:\n"
302 output_buffer += " break;\n"
303 output_buffer += " }\n"
304 output_buffer += " *self->state = FINISHED_FROM_ACTIVE;\n"
305 output_buffer += " break;\n"
306 output_buffer += " case FINISHED:\n"
307 output_buffer += " switch (*self->counter) {\n"
308 for i in range(0, l):
309 val = DEFINITION.split(',')[i].strip()
310 code = expand_keycode_fnc(val)
311 output_buffer += " case " + str(i + 1) + ":\n"
312 output_buffer += " tap_key( " + code + ");\n"
313 output_buffer += " break;\n"
314 output_buffer += " default:\n"
315 output_buffer += " break;\n"
316 output_buffer += " }\n"
317 output_buffer += " *self->counter = 0;\n"
318 output_buffer += " *self->state = IDLE;\n"
319 output_buffer += " break;\n"
320 output_buffer += " case RESTART:\n"
321 output_buffer += " switch (*self->counter) {\n"
322 for i in range(0, l):
323 val = DEFINITION.split(',')[i].strip()
324 code = expand_keycode_fnc(val)
325 output_buffer += " case " + str(i + 1) + ":\n"
326 output_buffer += " key_out( " + code + ");\n"
327 output_buffer += " break;\n"
328 output_buffer += " default:\n"
329 output_buffer += " break;\n"
330 output_buffer += " }\n"
331 output_buffer += " *self->counter = 0;\n"
332 output_buffer += " break;\n"
333 output_buffer += " default:\n"
334 output_buffer += " break;\n"
335 output_buffer += " }\n"
336 output_buffer += "}\n"
337 return new_chord(on_pseudolayer, keycodes_hash, True, 0, 0, "function_" + str(index), output_buffer, index)
338
339def O(on_pseudolayer, keycodes_hash, DEFINITION, output_buffer, index):
340 if DEFINITION[0:3] == "KC_":
341 return OSK(on_pseudolayer, keycodes_hash, DEFINITION, output_buffer, index)
342 else:
343 return OSL(on_pseudolayer, keycodes_hash, DEFINITION, output_buffer, index)
344
345def add_key(PSEUDOLAYER, KEYCODES_HASH, DEFINITION, output_buffer, index, number_of_strings, strings):
346 # if "= {" + KEYCODES_HASH + ", " + PSEUDOLAYER in output_buffer:
347 # KEYCODES_HASH = re.sub('H_', '', KEYCODES_HASH)
348 # raise Exception("You are trying to register a chord that you already registered (" + KEYCODES_HASH + ", " + PSEUDOLAYER + ")")
349
350 if DEFINITION == "":
351 return [output_buffer, index, number_of_strings, strings]
352 else:
353 split = DEFINITION.split("(")
354 type = split[0].strip()
355 if len(split) == 1:
356 if type == "LOCK":
357 [output_buffer, index] = LOCK(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
358 elif type == "AT":
359 [output_buffer, index] = AT(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
360 elif type == "CMD":
361 [output_buffer, index] = CMD(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
362 elif type == "LEAD":
363 [output_buffer, index] = LEAD(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
364 elif type == "DM_RECORD":
365 [output_buffer, index] = DM_RECORD(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
366 elif type == "DM_NEXT":
367 [output_buffer, index] = DM_NEXT(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
368 elif type == "DM_END":
369 [output_buffer, index] = DM_END(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
370 elif type == "DM_PLAY":
371 [output_buffer, index] = DM_PLAY(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
372 elif type == "CLEAR_KB":
373 [output_buffer, index] = CLEAR(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
374 elif type == "RESET":
375 [output_buffer, index] = RESET(PSEUDOLAYER, KEYCODES_HASH, output_buffer, index)
376 else:
377 code = expand_keycode_fnc(type)
378 [output_buffer, index] = KC(PSEUDOLAYER, KEYCODES_HASH, code, output_buffer, index)
379 else:
380 val = split[1][:-1].strip()
381 if type == "O":
382 code = expand_keycode_fnc(val)
383 [output_buffer, index] = O(PSEUDOLAYER, KEYCODES_HASH, code, output_buffer, index)
384 elif type == "D":
385 [output_buffer, index] = D(PSEUDOLAYER, KEYCODES_HASH, val, output_buffer, index)
386 elif type == "MK":
387 [output_buffer, index] = MK(PSEUDOLAYER, KEYCODES_HASH, val, output_buffer, index)
388 elif type == "M":
389 fnc = val.split(',')[0].strip()
390 val1 = val.split(',')[1].strip()
391 val2 = val.split(',')[2].strip()
392 [output_buffer, index] = M(PSEUDOLAYER, KEYCODES_HASH, val1, val2, fnc, output_buffer, index)
393 elif type == "KK":
394 val1 = val.split(',')[0].strip()
395 code1 = expand_keycode_fnc(val1)
396 val2 = val.split(',')[1].strip()
397 code2 = expand_keycode_fnc(val2)
398 [output_buffer, index] = KK(PSEUDOLAYER, KEYCODES_HASH, code1, code2, output_buffer, index)
399 elif type == "KL":
400 val1 = val.split(',')[0].strip()
401 code1 = expand_keycode_fnc(val1)
402 val2 = val.split(',')[1].strip()
403 [output_buffer, index] = KL(PSEUDOLAYER, KEYCODES_HASH, code1, val2, output_buffer, index)
404 elif type == "KM":
405 val1 = val.split(',')[0].strip()
406 code1 = expand_keycode_fnc(val1)
407 val2 = val.split(',')[1].strip()
408 code2 = expand_keycode_fnc(val2)
409 [output_buffer, index] = KM(PSEUDOLAYER, KEYCODES_HASH, code1, code2, output_buffer, index)
410 elif type == "AS":
411 code = expand_keycode_fnc(val)
412 [output_buffer, index] = AS(PSEUDOLAYER, KEYCODES_HASH, code, output_buffer, index)
413 elif type == "MO":
414 if not ',' in val:
415 [output_buffer, index] = MO(PSEUDOLAYER, KEYCODES_HASH, val, output_buffer, index)
416 else:
417 val1 = val.split(',')[0].strip()
418 val2 = val.split(',')[1].strip()
419 [output_buffer, index] = MO_alt(PSEUDOLAYER, KEYCODES_HASH, val1, val2, output_buffer, index)
420 elif type == "DF":
421 [output_buffer, index] = DF(PSEUDOLAYER, KEYCODES_HASH, val, output_buffer, index)
422 elif type == "TO":
423 [output_buffer, index] = TO(PSEUDOLAYER, KEYCODES_HASH, val, output_buffer, index)
424 elif type == "STR":
425 [output_buffer, index, number_of_strings, strings] = STR(PSEUDOLAYER, KEYCODES_HASH, val, output_buffer, index, number_of_strings, strings)
426 return [output_buffer, index, number_of_strings, strings]
427
428def add_leader_combo(DEFINITION, FUNCTION):
429 return list_of_leader_combos.append([DEFINITION, FUNCTION])
430
431def add_chord_set(PSEUDOLAYER, INPUT_STRING, TYPE, data, output_buffer, index, number_of_strings, strings):
432 chord_set = {}
433 for set in data["chord_sets"]:
434 if set["name"] == TYPE:
435 chord_set = set["chords"]
436 break
437
438 separated_string = top_level_split(INPUT_STRING)
439 for word, chord in zip(separated_string, chord_set):
440 chord_hash = reduce((lambda x, y: str(x) + " + " + str(y)), ["H_" + key for key in chord])
441 [output_buffer, index, number_of_strings, strings] = add_key(PSEUDOLAYER, chord_hash, word, output_buffer, index, number_of_strings, strings)
442
443 return [output_buffer, index, number_of_strings, strings]
444
445def add_dictionary(PSEUDOLAYER, keycodes, array, output_buffer, index, number_of_strings, strings):
446 for chord in array:
447 hash = ""
448 for word, key in zip(chord[:-1], keycodes):
449 if word == "X":
450 hash = hash + " + H_" + key
451 hash = hash[3:]
452 if hash != "":
453 [output_buffer, index, number_of_strings, strings] = add_key(PSEUDOLAYER, hash, chord[-1], output_buffer, index, number_of_strings, strings)
454
455 return [output_buffer, index, number_of_strings, strings]
456
457def secret_chord(PSEUDOLAYER, ACTION, INPUT_STRING, data, output_buffer, index, number_of_strings, strings):
458 separated_string = top_level_split(INPUT_STRING)
459 hash = ""
460 for word, key in zip(separated_string, data["keys"]):
461 if word == "X":
462 hash = hash + " + H_" + key
463
464 hash = hash[3:]
465 if hash != "":
466 return add_key(PSEUDOLAYER, hash, ACTION, output_buffer, index, number_of_strings, strings) \ No newline at end of file
diff --git a/users/dennytom/chording_engine/engine.part.1 b/users/dennytom/chording_engine/engine.part.1
new file mode 100644
index 000000000..73df4cdea
--- /dev/null
+++ b/users/dennytom/chording_engine/engine.part.1
@@ -0,0 +1,163 @@
1enum chord_states {
2 IDLE,
3 READY,
4 ACTIVATED,
5 DEACTIVATED,
6 PRESS_FROM_ACTIVE,
7 FINISHED_FROM_ACTIVE,
8 IDLE_IN_DANCE,
9 READY_IN_DANCE,
10 FINISHED,
11 LOCKED,
12 READY_LOCKED,
13 RESTART,
14 IN_ONE_SHOT
15};
16
17struct Chord {
18 uint32_t keycodes_hash;
19 uint8_t pseudolayer;
20 uint8_t* state;
21 uint8_t* counter;
22 uint16_t value1;
23 uint8_t value2;
24 void (*function) (const struct Chord*);
25};
26
27uint8_t current_pseudolayer = DEFAULT_PSEUDOLAYER;
28bool lock_next = false;
29uint16_t chord_timer = 0;
30uint16_t dance_timer = 0;
31bool autoshift_mode = true;
32uint8_t keycode_index = 0;
33uint8_t command_mode = 0;
34uint8_t command_ind = 0;
35bool in_leader_mode = false;
36uint8_t leader_ind = 0;
37uint16_t leader_timer = 0;
38uint8_t dynamic_macro_mode = false;
39uint8_t dynamic_macro_ind = 0;
40bool a_key_went_through = false;
41struct Chord* last_chord = NULL;
42
43bool handle_US_ANSI_shifted_keys(int16_t keycode, bool in) {
44 bool is_US_ANSI_shifted = true;
45
46 int16_t regular_keycode = KC_NO;
47 switch (keycode) {
48 case KC_TILDE:
49 regular_keycode = KC_GRAVE;
50 break;
51 case KC_EXCLAIM:
52 regular_keycode = KC_1;
53 break;
54 case KC_AT:
55 regular_keycode = KC_2;
56 break;
57 case KC_HASH:
58 regular_keycode = KC_3;
59 break;
60 case KC_DOLLAR:
61 regular_keycode = KC_4;
62 break;
63 case KC_PERCENT:
64 regular_keycode = KC_5;
65 break;
66 case KC_CIRCUMFLEX:
67 regular_keycode = KC_6;
68 break;
69 case KC_AMPERSAND:
70 regular_keycode = KC_7;
71 break;
72 case KC_ASTERISK:
73 regular_keycode = KC_8;
74 break;
75 case KC_LEFT_PAREN:
76 regular_keycode = KC_9;
77 break;
78 case KC_RIGHT_PAREN:
79 regular_keycode = KC_0;
80 break;
81 case KC_UNDERSCORE:
82 regular_keycode = KC_MINUS;
83 break;
84 case KC_PLUS:
85 regular_keycode = KC_EQUAL;
86 break;
87 case KC_LEFT_CURLY_BRACE:
88 regular_keycode = KC_LBRACKET;
89 break;
90 case KC_RIGHT_CURLY_BRACE:
91 regular_keycode = KC_RBRACKET;
92 break;
93 case KC_PIPE:
94 regular_keycode = KC_BSLASH;
95 break;
96 case KC_COLON:
97 regular_keycode = KC_SCOLON;
98 break;
99 case KC_DOUBLE_QUOTE:
100 regular_keycode = KC_QUOTE;
101 break;
102 case KC_LEFT_ANGLE_BRACKET:
103 regular_keycode = KC_COMMA;
104 break;
105 case KC_RIGHT_ANGLE_BRACKET:
106 regular_keycode = KC_DOT;
107 break;
108 case KC_QUESTION:
109 regular_keycode = KC_SLASH;
110 break;
111 default:
112 is_US_ANSI_shifted = false;
113 }
114 if (is_US_ANSI_shifted) {
115 if (in) {
116 register_code(KC_LSFT);
117 register_code(regular_keycode);
118 } else {
119 unregister_code(regular_keycode);
120 unregister_code(KC_LSFT);
121 }
122 }
123 return is_US_ANSI_shifted;
124}
125
126void key_in(int16_t keycode) {
127 if (command_mode == 1 && command_ind < COMMAND_MAX_LENGTH) {
128 command_buffer[command_ind] = keycode;
129 command_ind++;
130 a_key_went_through = true;
131 } else if (in_leader_mode && leader_ind < LEADER_MAX_LENGTH) {
132 leader_buffer[leader_ind] = keycode;
133 leader_ind++;
134 a_key_went_through = true;
135 } else if (dynamic_macro_mode && dynamic_macro_ind < DYNAMIC_MACRO_MAX_LENGTH) {
136 dynamic_macro_buffer[dynamic_macro_ind] = keycode;
137 dynamic_macro_ind++;
138 a_key_went_through = true;
139 } else {
140 if (!handle_US_ANSI_shifted_keys(keycode, true)) {
141 register_code(keycode);
142 }
143 send_keyboard_report();
144 a_key_went_through = true;
145 }
146}
147
148void key_out(int16_t keycode) {
149 if (command_mode == 0) {
150 if (!handle_US_ANSI_shifted_keys(keycode, false)) {
151 if (command_mode == 0 && in_leader_mode == false && dynamic_macro_mode == false) {
152 unregister_code(keycode);
153 }
154 }
155 send_keyboard_report();
156 }
157}
158
159void tap_key(int16_t keycode) {
160 key_in(keycode);
161 wait_ms(TAP_TIMEOUT);
162 key_out(keycode);
163} \ No newline at end of file
diff --git a/users/dennytom/chording_engine/engine.part.2 b/users/dennytom/chording_engine/engine.part.2
new file mode 100644
index 000000000..91dcbb750
--- /dev/null
+++ b/users/dennytom/chording_engine/engine.part.2
@@ -0,0 +1,323 @@
1void single_dance(const struct Chord* self) {
2 switch (*self->state) {
3 case ACTIVATED:
4 key_in(self->value1);
5 break;
6 case DEACTIVATED:
7 key_out(self->value1);
8 *self->state = IDLE;
9 break;
10 case RESTART:
11 key_out(self->value1);
12 break;
13 default:
14 break;
15 }
16}
17
18void key_layer_dance(const struct Chord* self) {
19 switch (*self->state) {
20 case ACTIVATED:
21 current_pseudolayer = self->value2;
22 a_key_went_through = false;
23 break;
24 case DEACTIVATED:
25 case RESTART:
26 if (!a_key_went_through) {
27 tap_key(self->value1);
28 }
29 current_pseudolayer = self->pseudolayer;
30 *self->state = IDLE; // does not have effect if the state was RESTART
31 break;
32 default:
33 break;
34 }
35}
36
37void key_mod_dance(const struct Chord* self) {
38 switch (*self->state) {
39 case ACTIVATED:
40 key_in(self->value2);
41 a_key_went_through = false;
42 break;
43 case DEACTIVATED:
44 case RESTART:
45 key_out(self->value2);
46 if (!a_key_went_through) {
47 tap_key(self->value1);
48 }
49 *self->state = IDLE; // does not have effect if the state was RESTART
50 break;
51 default:
52 break;
53 }
54}
55
56void key_key_dance(const struct Chord* self) {
57 switch (*self->state) {
58 case ACTIVATED:
59 break;
60 case DEACTIVATED:
61 tap_key(self->value1);
62 *self->state = IDLE;
63 break;
64 case FINISHED:
65 case PRESS_FROM_ACTIVE:
66 key_in(self->value2);
67 break;
68 case RESTART:
69 key_out(self->value2);
70 break;
71 default:
72 break;
73 }
74}
75
76void autoshift_dance_impl(const struct Chord* self) {
77 switch (*self->state) {
78 case ACTIVATED:
79 *self->counter = 0;
80 break;
81 case DEACTIVATED:
82 case RESTART:
83 tap_key(self->value1);
84 *self->state = IDLE;
85 break;
86 case FINISHED_FROM_ACTIVE:
87 if (*self->counter == (LONG_PRESS_MULTIPLIER - 2)) {
88 key_in(KC_LSFT);
89 tap_key(self->value1);
90 key_out(KC_LSFT);
91 *self->state = IDLE;
92 // the skip to IDLE is usually just a lag optimization,
93 // in this case it has a logic function, on a short
94 // press (still longer than a tap) the key does not get shifted
95 } else {
96 *self->counter += 1;
97 *self->state = PRESS_FROM_ACTIVE;
98 dance_timer = timer_read();
99 }
100 break;
101 default:
102 break;
103 }
104}
105
106void autoshift_dance(const struct Chord* self) {
107 if (autoshift_mode) {
108 autoshift_dance_impl(self);
109 } else {
110 single_dance(self);
111 }
112}
113
114void autoshift_toggle(const struct Chord* self){
115 if (*self->state == ACTIVATED) {
116 autoshift_mode = !autoshift_mode;
117 *self->state = IDLE;
118 }
119}
120
121void temp_pseudolayer(const struct Chord* self) {
122 switch (*self->state) {
123 case ACTIVATED:
124 current_pseudolayer = self->value1;
125 break;
126 case DEACTIVATED:
127 current_pseudolayer = self->pseudolayer;
128 *self->state = IDLE;
129 break;
130 case RESTART:
131 current_pseudolayer = self->pseudolayer;
132 break;
133 default:
134 break;
135 }
136}
137
138void temp_pseudolayer_alt(const struct Chord* self) {
139 switch (*self->state) {
140 case ACTIVATED:
141 current_pseudolayer = self->value1;
142 break;
143 case DEACTIVATED:
144 current_pseudolayer = self->value2;
145 *self->state = IDLE;
146 break;
147 case RESTART:
148 current_pseudolayer = self->value2;
149 break;
150 default:
151 break;
152 }
153}
154
155void perm_pseudolayer(const struct Chord* self) {
156 if (*self->state == ACTIVATED) {
157 current_pseudolayer = self->value1;
158 *self->state = IDLE;
159 }
160}
161
162void switch_layer(const struct Chord* self) {
163 if (*self->state == ACTIVATED) {
164 layer_move(self->value1);
165 *self->state = IDLE;
166 }
167}
168
169void lock(const struct Chord* self) {
170 if (*self->state == ACTIVATED) {
171 lock_next = true;
172 *self->state = IDLE;
173 }
174}
175
176void one_shot_key(const struct Chord* self) {
177 switch (*self->state) {
178 case ACTIVATED:
179 break;
180 case DEACTIVATED:
181 key_in(self->value1);
182 *self->state = IN_ONE_SHOT;
183 break;
184 case FINISHED:
185 case PRESS_FROM_ACTIVE:
186 key_in(self->value1);
187 a_key_went_through = false;
188 break;
189 case RESTART:
190 if (a_key_went_through) {
191 key_out(self->value1);
192 } else {
193 *self->state = IN_ONE_SHOT;
194 }
195 default:
196 break;
197 }
198}
199
200void one_shot_layer(const struct Chord* self) {
201 switch (*self->state) {
202 case ACTIVATED:
203 break;
204 case DEACTIVATED:
205 current_pseudolayer = self->value1;
206 *self->state = IN_ONE_SHOT;
207 break;
208 case FINISHED:
209 case PRESS_FROM_ACTIVE:
210 current_pseudolayer = self->value1;
211 a_key_went_through = false;
212 break;
213 case RESTART:
214 if (a_key_went_through) {
215 current_pseudolayer = self->pseudolayer;
216 } else {
217 *self->state = IN_ONE_SHOT;
218 }
219 default:
220 break;
221 }
222}
223
224void command(const struct Chord* self) {
225 if (*self->state == ACTIVATED) {
226 command_mode++;
227 *self->state = IDLE;
228 }
229}
230
231bool identical(uint16_t* buffer1, uint16_t* buffer2) {
232 bool same = true;
233 for (int i = 0; i < LEADER_MAX_LENGTH; i++) {
234 same = same && (buffer1[i] == buffer2[i]);
235 }
236 return same;
237}
238
239void leader(const struct Chord* self) {
240 if (*self->state == ACTIVATED) {
241 in_leader_mode = true;
242 *self->state = IDLE;
243 }
244}
245
246void dynamic_macro_record(const struct Chord* self) {
247 if (*self->state == ACTIVATED) {
248 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
249 dynamic_macro_buffer[i] = 0;
250 }
251 dynamic_macro_mode = true;
252 *self->state = IDLE;
253 }
254}
255
256void dynamic_macro_next(const struct Chord* self) {
257 if (*self->state == ACTIVATED) {
258 if (dynamic_macro_mode && dynamic_macro_ind < DYNAMIC_MACRO_MAX_LENGTH) {
259 dynamic_macro_buffer[dynamic_macro_ind] = 0;
260 dynamic_macro_ind++;
261 }
262 *self->state = IDLE;
263 }
264}
265
266void dynamic_macro_end(const struct Chord* self) {
267 if (*self->state == ACTIVATED) {
268 if (dynamic_macro_mode) {
269 dynamic_macro_mode = false;
270 }
271 *self->state = IDLE;
272 }
273}
274
275void dynamic_macro_play(const struct Chord* self) {
276 if (*self->state == ACTIVATED) {
277 int ind_start = 0;
278 while (ind_start < DYNAMIC_MACRO_MAX_LENGTH) {
279 for (int i = ind_start; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
280 if (dynamic_macro_buffer[i] == 0) {
281 break;
282 }
283 register_code(dynamic_macro_buffer[i]);
284 }
285 send_keyboard_report();
286 wait_ms(TAP_TIMEOUT);
287 for (int i = ind_start; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
288 if (dynamic_macro_buffer[i] == 0) {
289 ind_start = i + 1;
290 break;
291 }
292 unregister_code(dynamic_macro_buffer[i]);
293 }
294 send_keyboard_report();
295 }
296 *self->state = IDLE;
297 }
298}
299
300void string_in(const struct Chord* self) {
301 if (*self->state == ACTIVATED) {
302 char buffer[STRING_MAX_LENGTH];
303 strcpy_P(buffer, (char*)pgm_read_word(&(strings[self->value1])));
304 send_string(buffer);
305 }
306}
307
308void clear(const struct Chord* self);
309
310void reset_keyboard_kb(void){
311#ifdef WATCHDOG_ENABLE
312 MCUSR = 0;
313 wdt_disable();
314 wdt_reset();
315#endif
316 reset_keyboard();
317}
318
319void reset(const struct Chord* self) {
320 if (*self->state == ACTIVATED) {
321 reset_keyboard_kb();
322 }
323}
diff --git a/users/dennytom/chording_engine/engine.part.3 b/users/dennytom/chording_engine/engine.part.3
new file mode 100644
index 000000000..cf19008ab
--- /dev/null
+++ b/users/dennytom/chording_engine/engine.part.3
@@ -0,0 +1,404 @@
1bool are_hashed_keycodes_in_sound(HASH_TYPE keycodes_hash, HASH_TYPE sound) {
2 return (keycodes_hash & sound) == keycodes_hash;
3}
4
5uint8_t keycode_to_index(uint16_t keycode) {
6 return keycode - FIRST_INTERNAL_KEYCODE;
7}
8
9void sound_keycode_array(uint16_t keycode) {
10 uint8_t index = keycode_to_index(keycode);
11 keycode_index++;
12 keycodes_buffer_array[index] = keycode_index;
13}
14
15void silence_keycode_hash_array(HASH_TYPE keycode_hash) {
16 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
17 bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash;
18 if (index_in_hash) {
19 uint8_t current_val = keycodes_buffer_array[i];
20 keycodes_buffer_array[i] = 0;
21 for (int j = 0; j < NUMBER_OF_KEYS; j++) {
22 if (keycodes_buffer_array[j] > current_val) {
23 keycodes_buffer_array[j]--;
24 }
25 }
26 keycode_index--;
27 }
28 }
29}
30
31bool are_hashed_keycodes_in_array(HASH_TYPE keycode_hash) {
32 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
33 bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash;
34 bool index_in_array = (bool) keycodes_buffer_array[i];
35 if (index_in_hash && !index_in_array) {
36 return false;
37 }
38 }
39 return true;
40}
41
42void kill_one_shots(void) {
43 struct Chord chord_storage;
44 struct Chord* chord_ptr;
45 struct Chord* chord;
46
47 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
48 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
49 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
50 chord = &chord_storage;
51
52 if (*chord->state == IN_ONE_SHOT) {
53 *chord->state = RESTART;
54 chord->function(chord);
55 if (*chord->state == RESTART) {
56 *chord->state = IDLE;
57 }
58 }
59 }
60}
61
62void process_finished_dances(void) {
63 struct Chord chord_storage;
64 struct Chord* chord_ptr;
65 struct Chord* chord;
66
67 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
68 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
69 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
70 chord = &chord_storage;
71
72 if (*chord->state == ACTIVATED) {
73 *chord->state = PRESS_FROM_ACTIVE;
74 chord->function(chord);
75 if (a_key_went_through) {
76 kill_one_shots();
77 }
78 dance_timer = timer_read();
79 } else if (*chord->state == IDLE_IN_DANCE) {
80 *chord->state = FINISHED;
81 chord->function(chord);
82 if (*chord->state == FINISHED) {
83 *chord->state = RESTART;
84 if (*chord->state == RESTART) {
85 *chord->state = IDLE;
86 }
87 }
88 } else if (*chord->state == PRESS_FROM_ACTIVE) {
89 *chord->state = FINISHED_FROM_ACTIVE;
90 chord->function(chord);
91 if (a_key_went_through) {
92 kill_one_shots();
93 }
94 dance_timer = timer_read();
95 }
96 }
97}
98
99uint8_t keycodes_buffer_array_min(uint8_t* first_keycode_index) {
100 for (int i = 0; i < NUMBER_OF_KEYS; i++) {
101 if (keycodes_buffer_array[i] == 1) {
102 if (first_keycode_index != NULL) {
103 *first_keycode_index = (uint8_t) i;
104 }
105 return 1;
106 }
107 }
108 return 0;
109}
110
111void remove_subchords(void) {
112 struct Chord chord_storage;
113 struct Chord* chord_ptr;
114 struct Chord* chord;
115
116 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
117 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
118 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
119 chord = &chord_storage;
120
121 if (!(*chord->state == READY || *chord->state == READY_IN_DANCE || *chord->state == READY_LOCKED)) {
122 continue;
123 }
124
125 struct Chord chord_storage_2;
126 struct Chord* chord_ptr_2;
127 struct Chord* chord_2;
128 for (int j = 0; j < NUMBER_OF_CHORDS; j++) {
129 if (i == j) {continue;}
130
131 chord_ptr_2 = (struct Chord*) pgm_read_word (&list_of_chords[j]);
132 memcpy_P(&chord_storage_2, chord_ptr_2, sizeof(struct Chord));
133 chord_2 = &chord_storage_2;
134
135 if (are_hashed_keycodes_in_sound(chord_2->keycodes_hash, chord->keycodes_hash)) {
136 if (*chord_2->state == READY) {
137 *chord_2->state = IDLE;
138 }
139 if (*chord_2->state == READY_IN_DANCE) {
140 *chord_2->state = IDLE_IN_DANCE;
141 }
142 if (*chord_2->state == READY_LOCKED) {
143 *chord_2->state = LOCKED;
144 }
145 }
146 }
147 }
148}
149
150void process_ready_chords(void) {
151 uint8_t first_keycode_index = 0;
152 while (keycodes_buffer_array_min(&first_keycode_index)) {
153 // find ready chords
154 struct Chord chord_storage;
155 struct Chord* chord_ptr;
156 struct Chord* chord;
157
158 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
159 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
160 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
161 chord = &chord_storage;
162
163 // if the chord does not contain the first keycode
164 bool contains_first_keycode = ((uint32_t) 1 << first_keycode_index) & chord->keycodes_hash;
165 if (!contains_first_keycode) {
166 continue;
167 }
168
169 if (!are_hashed_keycodes_in_array(chord->keycodes_hash)){
170 continue;
171 }
172
173 if (*chord->state == LOCKED) {
174 *chord->state = READY_LOCKED;
175 continue;
176 }
177
178 if (!(chord->pseudolayer == current_pseudolayer || chord->pseudolayer == ALWAYS_ON)) {
179 continue;
180 }
181
182 if (*chord->state == IDLE) {
183 *chord->state = READY;
184 continue;
185 }
186
187 if (*chord->state == IDLE_IN_DANCE) {
188 *chord->state = READY_IN_DANCE;
189 }
190 }
191
192 // remove subchords
193 remove_subchords();
194
195 // execute logic
196 // this should be only one chord
197 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
198 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
199 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
200 chord = &chord_storage;
201
202 if (*chord->state == READY_LOCKED) {
203 *chord->state = RESTART;
204 chord->function(chord);
205 if (*chord->state == RESTART) {
206 *chord->state = IDLE;
207 }
208 break;
209 }
210
211 if (*chord->state == READY || *chord->state == READY_IN_DANCE) {
212 if (last_chord && last_chord != chord) {
213 process_finished_dances();
214 }
215
216 bool lock_next_prev_state = lock_next;
217
218 *chord->state = ACTIVATED;
219 chord->function(chord);
220 dance_timer = timer_read();
221
222 if (lock_next && lock_next == lock_next_prev_state) {
223 lock_next = false;
224 *chord->state = PRESS_FROM_ACTIVE;
225 chord->function(chord);
226 if (*chord->state == PRESS_FROM_ACTIVE) {
227 *chord->state = LOCKED;
228 }
229 if (a_key_went_through) {
230 kill_one_shots();
231 }
232 }
233 break;
234 }
235 }
236
237 // silence notes
238 silence_keycode_hash_array(chord->keycodes_hash);
239 }
240}
241
242void deactivate_active_chords(uint16_t keycode) {
243 HASH_TYPE hash = (HASH_TYPE)1 << (keycode - SAFE_RANGE);
244 bool broken;
245 struct Chord chord_storage;
246 struct Chord* chord_ptr;
247 struct Chord* chord;
248
249 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
250 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
251 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
252 chord = &chord_storage;
253
254 broken = are_hashed_keycodes_in_sound(hash, chord->keycodes_hash);
255 if (!broken) {
256 continue;
257 }
258
259 switch (*chord->state) {
260 case ACTIVATED:
261 *chord->state = DEACTIVATED;
262 chord->function(chord);
263
264 if (*chord->state == DEACTIVATED) {
265 dance_timer = timer_read();
266 *chord->state = IDLE_IN_DANCE;
267 }
268 if (*chord->state != IN_ONE_SHOT) {
269 kill_one_shots();
270 }
271 break;
272 case PRESS_FROM_ACTIVE:
273 case FINISHED_FROM_ACTIVE:
274 *chord->state = RESTART;
275 chord->function(chord);
276 if (*chord->state == RESTART) {
277 *chord->state = IDLE;
278 }
279 kill_one_shots();
280 break;
281 default:
282 break;
283 }
284 }
285
286}
287
288void process_command(void) {
289 command_mode = 0;
290 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
291 if (command_buffer[i]) {
292 register_code(command_buffer[i]);
293 }
294 send_keyboard_report();
295 }
296 wait_ms(TAP_TIMEOUT);
297 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
298 if (command_buffer[i]) {
299 unregister_code(command_buffer[i]);
300 }
301 send_keyboard_report();
302 }
303 for (int i = 0; i < COMMAND_MAX_LENGTH; i++) {
304 command_buffer[i] = 0;
305 }
306 command_ind = 0;
307}
308
309void process_leader(void) {
310 in_leader_mode = false;
311 for (int i = 0; i < NUMBER_OF_LEADER_COMBOS; i++) {
312 uint16_t trigger[LEADER_MAX_LENGTH];
313 memcpy_P(trigger, leader_triggers[i], LEADER_MAX_LENGTH * sizeof(uint16_t));
314
315 if (identical(leader_buffer, trigger)) {
316 (*leader_functions[i])();
317 break;
318 }
319 }
320 for (int i = 0; i < LEADER_MAX_LENGTH; i++) {
321 leader_buffer[i] = 0;
322 }
323}
324
325bool process_record_user(uint16_t keycode, keyrecord_t *record) {
326 if (keycode < FIRST_INTERNAL_KEYCODE || keycode > LAST_INTERNAL_KEYCODE) {
327 return true;
328 }
329
330 if (record->event.pressed) {
331 sound_keycode_array(keycode);
332 } else {
333 process_ready_chords();
334 deactivate_active_chords(keycode);
335 }
336 chord_timer = timer_read();
337 leader_timer = timer_read();
338
339 return false;
340}
341
342void matrix_scan_user(void) {
343 bool chord_timer_expired = timer_elapsed(chord_timer) > CHORD_TIMEOUT;
344 if (chord_timer_expired && keycodes_buffer_array_min(NULL)) {
345 process_ready_chords();
346 }
347
348 bool dance_timer_expired = timer_elapsed(dance_timer) > DANCE_TIMEOUT;
349 if (dance_timer_expired) { // would love to have && in_dance but not sure how
350 process_finished_dances();
351 }
352
353 bool in_command_mode = command_mode == 2;
354 if (in_command_mode) {
355 process_command();
356 }
357
358 bool leader_timer_expired = timer_elapsed(leader_timer) > LEADER_TIMEOUT;
359 if (leader_timer_expired && in_leader_mode) {
360 process_leader();
361 }
362
363}
364
365void clear(const struct Chord* self) {
366 if (*self->state == ACTIVATED) {
367 // kill all chords
368 struct Chord chord_storage;
369 struct Chord* chord_ptr;
370 struct Chord* chord;
371
372 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
373 chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
374 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
375 chord = &chord_storage;
376
377 *chord->state = IDLE;
378
379 if (chord->counter) {
380 *chord->counter = 0;
381 }
382 }
383
384 // clear keyboard
385 clear_keyboard();
386 send_keyboard_report();
387
388 // switch to default pseudolayer
389 current_pseudolayer = DEFAULT_PSEUDOLAYER;
390
391 // clear all keyboard states
392 lock_next = false;
393 autoshift_mode = true;
394 command_mode = 0;
395 in_leader_mode = false;
396 leader_ind = 0;
397 dynamic_macro_mode = false;
398 a_key_went_through = false;
399
400 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
401 dynamic_macro_buffer[i] = 0;
402 }
403 }
404} \ No newline at end of file
diff --git a/users/dennytom/chording_engine/keymap_def.schema.json b/users/dennytom/chording_engine/keymap_def.schema.json
new file mode 100644
index 000000000..9f9a8c5cb
--- /dev/null
+++ b/users/dennytom/chording_engine/keymap_def.schema.json
@@ -0,0 +1,337 @@
1{
2 "definitions": {},
3 "$schema": "http://json-schema.org/draft-07/schema#",
4 "type": "object",
5 "title": "The Keymap definition",
6 "required": [
7 "keys",
8 "parameters",
9 "layers",
10 "chord_sets",
11 "pseudolayers",
12 "leader_sequences",
13 "extra_code",
14 "extra_dependencies"
15 ],
16 "properties": {
17 "keys": {
18 "type": "array",
19 "title": "The Internal Keycodes",
20 "description": "Name Keycodes for the Chording Engine. These can be any string except already valid QMK keycodes.",
21 "items": {
22 "type": "string",
23 "title": "Individual Keycode",
24 "examples": [
25 "L1",
26 "R1",
27 "TOP1",
28 "THUMB_3",
29 "Bottom_6"
30 ]
31 }
32 },
33 "parameters": {
34 "type": "object",
35 "title": "Keyboard Parameters",
36 "description": "Keyboard, user and layout specific parameters like timers, max length for buffers and default pseudolayer.",
37 "required": [
38 "layout_function_name",
39 "chord_timeout",
40 "dance_timeout",
41 "leader_timeout",
42 "tap_timeout",
43 "command_max_length",
44 "leader_max_length",
45 "dynamic_macro_max_length",
46 "string_max_length",
47 "long_press_multiplier",
48 "default_pseudolayer"
49 ],
50 "properties": {
51 "layout_function_name": {
52 "type": "string",
53 "examples": [
54 "LAYOUT_ginny",
55 ""
56 ]
57 },
58 "chord_timeout": {
59 "type": "integer",
60 "title": "The Chord Timeout",
61 "description": "The time in ms you have to press additional keys before the engine assumes you finished pressing keys that are part of a chord.",
62 "default": 100
63 },
64 "dance_timeout": {
65 "type": "integer",
66 "title": "The Dance Timeout",
67 "description": "The time in ms you have to repeatedly activate a chord before the engine assumes you finished a dance.",
68 "default": 200
69 },
70 "leader_timeout": {
71 "type": "integer",
72 "title": "The Leader Timeout",
73 "description": "The time in ms you have to activate additional chords before the engine assumes you finished adding chords to a leader sequence.",
74 "default": 750
75 },
76 "tap_timeout": {
77 "type": "integer",
78 "title": "The Tap Timeout",
79 "description": "The time in ms you have to finish pressing a chord before the engine assumes that you didn't just tap it but are holding it down.",
80 "default": 50
81 },
82 "command_max_length": {
83 "type": "integer",
84 "title": "Command Max Length",
85 "description": "The maximum length for chords buffered in command mode.",
86 "default": 5
87 },
88 "leader_max_length": {
89 "type": "integer",
90 "title": "Leader Max Length",
91 "description": "The maximum length of leader sequences you can define in your keymap",
92 "default": 5
93 },
94 "dynamic_macro_max_length": {
95 "type": "integer",
96 "title": "Dynamic Macro Max Length",
97 "description": "The maximum number of chords (including Dynamic Macro Next) you can record to a Dynamic Macro",
98 "default": 20
99 },
100 "string_max_length": {
101 "type": "integer",
102 "title": "String Max Length",
103 "description": "The maximum length of a string that the STR() chord can accept.",
104 "default": 16
105 },
106 "long_press_multiplier": {
107 "type": "integer",
108 "title": "Long Press Multiplier",
109 "description": "How many times does the chord timer have expire before a chord is registered as not only held but in a long press (for example for Autoshift). Has to be integer.",
110 "default": 3
111 },
112 "default_pseudolayer": {
113 "type": "string",
114 "title": "Default Pseudolayer",
115 "description": "Which pseudolayer should be active when the keyboard starts / restarts.",
116 "examples": [
117 "BASE",
118 "QWERTY"
119 ]
120 }
121 }
122 },
123 "layers": {
124 "type": "array",
125 "title": "QMK Layers",
126 "description": "The layers QMK needs to know about. Can contain chording engine's internal keycodes or QMK's keycodes. Do not define chords here, those belong in pseudolayers.",
127 "minItems": 1,
128 "uniqueItems": false,
129 "items": {
130 "type": "object",
131 "title": "Individual Layers",
132 "required": [
133 "type"
134 ],
135 "properties": {
136 "type": {
137 "type": "string",
138 "title": "Type of Individual Layers",
139 "description": "Auto layer fills all keycodes to be chording engine's internal keycodes, manual let's you place internal and QMK's keycodes however you wish.",
140 "examples": [
141 "auto",
142 "manual"
143 ]
144 },
145 "keycodes": {
146 "type": "array",
147 "title": "Individual Chord",
148 "description": "A list of of keys that need to be pressed to activate this chord",
149 "items": {
150 "type": "string",
151 "title": "Individual Keycodes",
152 "description": "A keycode that is a part of the individual chord. Has to be an internal keycode."
153 }
154 }
155 }
156 }
157 },
158 "chord_sets": {
159 "type": "array",
160 "title": "Chord Sets Definitions",
161 "description": "Describes predefined sets of chords to ease defining a number of chords in a pseudolayer.",
162 "items": {
163 "type": "object",
164 "required": [
165 "name",
166 "chords"
167 ],
168 "properties": {
169 "name": {
170 "type": "string",
171 "title": "Name of the Set",
172 "examples": [
173 "rows",
174 "asetniop"
175 ]
176 },
177 "chords": {
178 "type": "array",
179 "title": "Chords",
180 "description": "List of all chords in this set",
181 "minItems": 1,
182 "uniqueItems": true,
183 "items": {
184 "type": "array",
185 "title": "Individual Chord",
186 "description": "A list of of keys that need to be pressed to activate this chord",
187 "items": {
188 "type": "string",
189 "title": "Individual Keycodes",
190 "description": "A keycode that is a part of the individual chord. Has to be an internal keycode."
191 }
192 }
193 }
194 }
195 }
196 },
197 "pseudolayers": {
198 "type": "array",
199 "title": "Pseudolayers",
200 "description": "The pseudolayers holding the chords to be processed by the chording engine.",
201 "minItems": 1,
202 "uniqueItems": true,
203 "items": {
204 "type": "object",
205 "required": [
206 "name"
207 ],
208 "properties": {
209 "name": {
210 "type": "string",
211 "title": "Name of the Pseudolayer",
212 "default": null,
213 "examples": [
214 "ALWAYS_ON",
215 "QWERTY"
216 ]
217 },
218 "chords": {
219 "type": "array",
220 "title": "Chords",
221 "description": "List of chords belonging on the pseudolayer.",
222 "items": {
223 "type": "object",
224 "required": [
225 "type"
226 ],
227 "properties": {
228 "type": {
229 "type": "string",
230 "title": "Type of the chord array",
231 "description": "Defines how this objects describes one or more chords.",
232 "examples": [
233 "visual_array",
234 "visual",
235 "simple",
236 "chord_set"
237 ]
238 },
239 "keys": {
240 "type": "array",
241 "title": "Subset of keys",
242 "description": "Subset of internal keycodes that will be used when defining the chords. For visual_array type only.",
243 "examples": [
244 "[\"L1\", \"L2\", \"L3\", \"L4\", \"R1\", \"R2\", \"R3\", \"R4\"]"
245 ],
246 "items": {
247 "type": "string"
248 }
249 },
250 "dictionary": {
251 "type": "array",
252 "title": "Dictionary",
253 "description": "A table. Each row defines in a visual way which keys have to be pressed and what is the desired outcome. For visual_array type only.",
254 "items": {
255 "type": "array",
256 "items": {
257 "type": "string",
258 "examples": [
259 "[\"X"\, \" "\, \" "\, \"X"\, \"X"\, \" "\, \" "\, \"X"\, \"MO(BASE, NUM)\"]
260 ]
261 }
262 }
263 },
264 "keycode": {
265 "type": "string",
266 "title": "Keycode",
267 "description": "A keycode to be assigned to the chord when it is registered. For simple and visual types only."
268 },
269 "set": {
270 "type": "string",
271 "title": "Chord set",
272 "description": "Name of the chord set to be used. Has to be one already defined in the chord_sets array. For chord_set type only."
273 },
274 "keycodes": {
275 "type": "array",
276 "title": "Keycodes",
277 "description": "List of keycodes to be assigned to each chord when it is registered. For set type only.",
278 "items": {
279 "type": "string"
280 }
281 },
282 "chord": {
283 "type": "array",
284 "title": "Chord",
285 "description": "Array of \"X\"'s and \" \"'s that shows which keys have to be pressed to activate the chord. For visual type only ",
286 "items": {
287 "type": "string"
288 }
289 }
290 }
291 }
292 }
293 }
294 }
295 },
296 "leader_sequences": {
297 "type": "array",
298 "items": {
299 "type": "object",
300 "properties": {
301 "name": {
302 "type": "string",
303 "examples": ["fn_L1"]
304 },
305 "function": {
306 "type": "string",
307 "description": "C code the sequence should run. Instead of here, can be defined in extra_dependencies or extra_code",
308 "examples": ["void fn_L1(void) { SEND(KC_LCTL); SEND(KC_LALT); SEND(KC_DEL); }"]
309 },
310 "sequence": {
311 "type": "array",
312 "items": {
313 "type": "string"
314 },
315 "examples": [["KC_Q", "KC_Z"]]
316 }
317 }
318 }
319 },
320 "extra_code": {
321 "type": "string",
322 "label": "Extra Code",
323 "description": "C code to be inserted into the generated keymap",
324 "examples": ["void fn_L1(void) {\n SEND(KC_LCTL);\n SEND(KC_LALT);\n SEND(KC_DEL);\n}\n"],
325 "default": ""
326 },
327 "extra_dependencies": {
328 "type": "array",
329 "label": "Extra Dependencies",
330 "description": "List of files to be #include'd in the generated keymap",
331 "examples": [
332 "[\"user_functions.c\"]"
333 ],
334 "default": ""
335 }
336 }
337} \ No newline at end of file
diff --git a/users/dennytom/chording_engine/parser.py b/users/dennytom/chording_engine/parser.py
new file mode 100644
index 000000000..b62cf007e
--- /dev/null
+++ b/users/dennytom/chording_engine/parser.py
@@ -0,0 +1,231 @@
1#!/usr/bin/env python3
2
3import json
4from functools import reduce
5from chord import *
6import sys
7
8comma_separator = (lambda x, y: str(x) + ", " + str(y))
9string_sum = (lambda x, y: str(x) + " + " + str(y))
10newline_separator = (lambda x, y: str(x) + "\n" + str(y))
11
12def add_includes(data):
13 output_buffer = ""
14 if not ("do_not_include_QMK" in data["parameters"] and data["parameters"]["do_not_include_QMK"] == True):
15 output_buffer += "#include QMK_KEYBOARD_H\n"
16 if len(data["extra_dependencies"]) > 0:
17 for dependecy in data["extra_dependencies"]:
18 output_buffer += '#include "' + dependecy + '"\n'
19
20 return output_buffer + "\n"
21
22def add_parameters(data):
23 output_buffer = ""
24
25 number_of_keys = len(data["keys"])
26 if number_of_keys <= 8:
27 hash_type = "uint8_t"
28 elif number_of_keys <= 16:
29 hash_type = "uint16_t"
30 elif number_of_keys <= 32:
31 hash_type = "uint32_t"
32 elif number_of_keys <= 64:
33 hash_type = "uint64_t"
34 else:
35 raise Exception("The engine currently supports only up to 64 keys.")
36
37 output_buffer += "#define CHORD_TIMEOUT " + str(data["parameters"]["chord_timeout"]) + "\n"
38 output_buffer += "#define DANCE_TIMEOUT " + str(data["parameters"]["dance_timeout"]) + "\n"
39 output_buffer += "#define LEADER_TIMEOUT " + str(data["parameters"]["leader_timeout"]) + "\n"
40 output_buffer += "#define TAP_TIMEOUT " + str(data["parameters"]["tap_timeout"]) + "\n"
41 output_buffer += "#define LONG_PRESS_MULTIPLIER " + str(data["parameters"]["long_press_multiplier"]) + "\n"
42 output_buffer += "#define DYNAMIC_MACRO_MAX_LENGTH " + str(data["parameters"]["dynamic_macro_max_length"]) + "\n"
43 output_buffer += "#define COMMAND_MAX_LENGTH " + str(data["parameters"]["command_max_length"]) + "\n"
44 output_buffer += "#define STRING_MAX_LENGTH " + str(data["parameters"]["string_max_length"]) + "\n"
45 output_buffer += "#define LEADER_MAX_LENGTH " + str(data["parameters"]["leader_max_length"]) + "\n"
46 output_buffer += "#define HASH_TYPE " + hash_type + "\n"
47 output_buffer += "#define NUMBER_OF_KEYS " + str(len(data["keys"])) + "\n"
48 output_buffer += "#define DEFAULT_PSEUDOLAYER " + data["parameters"]["default_pseudolayer"] + "\n"
49
50 return output_buffer + "\n"
51
52def add_keycodes(data):
53 output_buffer = ""
54
55 if not len(data["keys"]) == len(set(data["keys"])):
56 raise Exception("The keys must have unique names")
57
58 for key, counter in zip(data["keys"], range(0, len(data["keys"]))):
59 output_buffer += "#define H_" + key + " ((HASH_TYPE) 1 << " + str(counter) + ")\n"
60 output_buffer += "\n"
61
62 output_buffer += "enum internal_keycodes {\n"
63 output_buffer += " " + data["keys"][0] + " = SAFE_RANGE,\n"
64 output_buffer += " " + reduce(comma_separator, [key for key in data["keys"][1:]]) + ",\n"
65 output_buffer += " FIRST_INTERNAL_KEYCODE = " + data["keys"][0] + ",\n"
66 output_buffer += " LAST_INTERNAL_KEYCODE = " + data["keys"][-1] + "\n"
67 output_buffer += "};\n"
68
69 return output_buffer + "\n"
70
71def add_pseudolayers(data):
72 output_buffer = ""
73
74 if len(data["pseudolayers"]) == 0:
75 raise Exception("You didn't define any pseudolayers")
76
77 if not len([pseudolayer["name"] for pseudolayer in data["pseudolayers"]]) == len(set([pseudolayer["name"] for pseudolayer in data["pseudolayers"]])):
78 raise Exception("The pseudolayers must have unique names")
79
80 pseudolayers = data["pseudolayers"]
81 if not "ALWAYS_ON" in [layer["name"] for layer in pseudolayers]:
82 pseudolayers += [{"name": "ALWAYS_ON", "chords": []}] # the engine expects ALWAYS_ON to exist
83
84 output_buffer += "enum pseudolayers {\n"
85 output_buffer += " " + reduce(comma_separator, [layer["name"] for layer in pseudolayers]) + "\n"
86 output_buffer += "};\n"
87
88 return output_buffer + "\n"
89
90def add_layers(data):
91 output_buffer = ""
92
93 output_buffer += "const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {\n"
94 for layer, counter in zip(data["layers"], range(0,len(data["layers"]))):
95 if layer["type"] == "auto":
96 output_buffer += " [" + str(counter) + "] = " + data["parameters"]["layout_function_name"] + "(" + reduce(comma_separator, [key for key in data["keys"]]) + "),\n"
97 else:
98 output_buffer += " [" + str(counter) + "] = " + data["parameters"]["layout_function_name"] + "(" + reduce(comma_separator, [key for key in layer["keycodes"]]) + "),\n"
99 output_buffer += "};\n"
100 output_buffer += "size_t keymapsCount = " + str(len(data["layers"])) + ";\n"
101
102 return output_buffer + "\n"
103
104def prep_buffers(data):
105 output_buffer = ""
106
107 output_buffer += "uint8_t keycodes_buffer_array[] = {\n"
108 output_buffer += " " + reduce(comma_separator, ["0"] * len(data["keys"])) + "\n"
109 output_buffer += "};\n"
110 output_buffer += "\n"
111
112 output_buffer += "uint8_t command_buffer[] = {\n"
113 output_buffer += " " + reduce(comma_separator, ["0"] * data["parameters"]["command_max_length"]) + "\n"
114 output_buffer += "};\n"
115 output_buffer += "\n"
116
117 output_buffer += "uint16_t leader_buffer[] = {\n"
118 output_buffer += " " + reduce(comma_separator, ["0"] * data["parameters"]["leader_max_length"]) + "\n"
119 output_buffer += "};\n"
120 output_buffer += "\n"
121
122 output_buffer += "uint8_t dynamic_macro_buffer[] = {\n"
123 output_buffer += " " + reduce(comma_separator, ["0"] * data["parameters"]["dynamic_macro_max_length"]) + "\n"
124 output_buffer += "};"
125
126 return output_buffer + "\n"
127
128def parse_keyboard_specifics(data):
129 keyboard_part_0 = add_includes(data)
130 keyboard_part_0 += add_keycodes(data)
131 keyboard_part_0 += add_pseudolayers(data)
132 keyboard_part_0 += add_parameters(data)
133 keyboard_part_0 += add_layers(data)
134 keyboard_part_0 += prep_buffers(data)
135
136 return keyboard_part_0 + '\n'
137
138def parse_chords(data):
139 keyboard_part_2 = ""
140 strings = []
141 number_of_strings = 0
142 number_of_chords = 0
143
144 for pseudolayer in data["pseudolayers"]:
145 name = pseudolayer["name"]
146 for chord in pseudolayer["chords"]:
147 if chord["type"] == "chord_set":
148 keycodes = reduce(comma_separator, [word for word in chord["keycodes"]])
149 [keyboard_part_2, number_of_chords, number_of_strings, strings] = add_chord_set(name, keycodes, chord["set"], data, keyboard_part_2, number_of_chords, number_of_strings, strings)
150 if chord["type"] == "visual_array":
151 [keyboard_part_2, number_of_chords, number_of_strings, strings] = add_dictionary(name, chord["keys"], chord["dictionary"], keyboard_part_2, number_of_chords, number_of_strings, strings)
152 if chord["type"] == "visual":
153 keycodes = reduce(comma_separator, [word for word in chord["chord"]])
154 [keyboard_part_2, number_of_chords, number_of_strings, strings] = secret_chord(name, chord["keycode"], keycodes, data, keyboard_part_2, number_of_chords, number_of_strings, strings)
155 elif chord["type"] == "simple":
156 keycodes = reduce(string_sum, ["H_" + word for word in chord["chord"]])
157 [keyboard_part_2, number_of_chords, number_of_strings, strings] = add_key(name, keycodes, chord["keycode"], keyboard_part_2, number_of_chords, number_of_strings, strings)
158 keyboard_part_2 += "\n"
159
160 keyboard_part_2 += "const struct Chord* const list_of_chords[] PROGMEM = {\n"
161 keyboard_part_2 += " " + reduce(comma_separator, ["&chord_" + str(i) for i in range(0, number_of_chords)]) + "\n"
162 keyboard_part_2 += "};\n"
163 keyboard_part_2 += "\n"
164
165 if len(data["leader_sequences"]) > 0:
166 keyboard_part_2 += reduce(newline_separator, [sequence["function"] for sequence in data["leader_sequences"]]) + "\n\n"
167 keyboard_part_2 += "const uint16_t leader_triggers[][LEADER_MAX_LENGTH] PROGMEM = {\n"
168 for sequence in data["leader_sequences"]:
169 keyboard_part_2 += " {" + reduce(comma_separator, sequence["sequence"] + ["0"] * (data["parameters"]["leader_max_length"] - len(sequence["sequence"]))) + "},\n"
170 keyboard_part_2 += "};\n\n"
171 keyboard_part_2 += "void (*leader_functions[]) (void) = {\n"
172 keyboard_part_2 += " " + reduce(comma_separator, ["&" + sequence["name"] for sequence in data["leader_sequences"]]) + "\n"
173 keyboard_part_2 += "};\n"
174 else:
175 keyboard_part_2 += "const uint16_t** const leader_triggers PROGMEM = NULL;\n"
176 keyboard_part_2 += "void (*leader_functions[]) (void) = {};\n"
177 keyboard_part_2 += "\n"
178
179 keyboard_part_2 += "#define NUMBER_OF_CHORDS " + str(number_of_chords) + "\n"
180 keyboard_part_2 += "#define NUMBER_OF_LEADER_COMBOS " + str(len(data["leader_sequences"]))
181
182 return keyboard_part_2 + "\n\n"
183
184def parse_strings_for_chords(data):
185 keyboard_part_1 = ""
186
187 for string, i in zip(strings, range(0, len(strings))):
188 keyboard_part_1 += "const char string_" + str(i) + " [] PROGMEM = \"" + string + "\";\n"
189
190 keyboard_part_1 += "\n"
191 keyboard_part_1 += "const char * const strings[] PROGMEM = {\n"
192 if len(strings) > 0:
193 keyboard_part_1 += " " + reduce(comma_separator, ["string_" + str(i) for i in range(0, len(strings))])
194 keyboard_part_1 += "\n};\n"
195
196 return keyboard_part_1
197
198def main():
199 if len(sys.argv) != 3:
200 raise Exception("Wrong number of arguments.\n\nUsage: python parser.py keymap.json keymap.c")
201
202 input_filepath = sys.argv[1]
203 output_filepath = sys.argv[2]
204
205 with open(input_filepath, "r") as read_file:
206 data = json.load(read_file)
207
208 keyboard_part_0 = parse_keyboard_specifics(data)
209 keyboard_part_1 = parse_strings_for_chords(data)
210 keyboard_part_2 = parse_chords(data)
211
212 engine_part_1 = open("engine.part.1", "r").read()
213 engine_part_2 = open("engine.part.2", "r").read() + "\n"
214 engine_part_3 = open("engine.part.3", "r").read()
215
216 output_buffer = keyboard_part_0
217 output_buffer += engine_part_1
218
219 if len(data["extra_code"]) > 0:
220 output_buffer += data["extra_code"] + "\n"
221
222 output_buffer += keyboard_part_1
223 output_buffer += engine_part_2
224 output_buffer += keyboard_part_2
225 output_buffer += engine_part_3
226
227 with open(output_filepath, "w") as write_file:
228 write_file.write(output_buffer)
229
230if __name__ == "__main__":
231 main() \ No newline at end of file
diff --git a/users/dennytom/chording_engine/state_machine.dot b/users/dennytom/chording_engine/state_machine.dot
new file mode 100644
index 000000000..431e6f69b
--- /dev/null
+++ b/users/dennytom/chording_engine/state_machine.dot
@@ -0,0 +1,49 @@
1digraph {
2 IDLE
3 READY
4 ACTIVATED
5 DEACTIVATED
6 PRESS_FROM_ACTIVE
7 FINISHED_FROM_ACTIVE
8 IDLE_IN_DANCE
9 READY_IN_DANCE
10 FINISHED
11 LOCKED
12 READY_LOCKED
13 RESTART
14 IN_ONE_SHOT
15
16 // common
17 FINISHED -> RESTART;
18 RESTART -> IDLE;
19 DEACTIVATED -> IDLE_IN_DANCE;
20
21 // kill_one_shots()
22 IN_ONE_SHOT -> RESTART [label="non-one-shot key went through", color="blue"];
23
24 // process_finished_dances()
25 ACTIVATED -> PRESS_FROM_ACTIVE [label="dance timer", color="green"];
26 IDLE_IN_DANCE -> FINISHED [label="dance timer", color="green"];
27 PRESS_FROM_ACTIVE -> FINISHED_FROM_ACTIVE [label="dance timer", color="green"];
28
29 // remove_subchords()
30 READY -> IDLE [label="superchord active", color="red"];
31 READY_IN_DANCE -> IDLE_IN_DANCE [label="superchord active", color="red"];
32 READY_LOCKED -> LOCKED [label="superchord active", color="red"];
33
34 // process_ready_chords()
35 LOCKED -> READY_LOCKED [label="all keys pressed", color="orange"];
36 IDLE -> READY [label="all keys pressed", color="orange"];
37 IDLE_IN_DANCE -> READY_IN_DANCE [label="all keys pressed", color="orange"];
38
39 READY_LOCKED -> RESTART [label="chord timer", color="orange"];
40 READY -> ACTIVATED [label="chord timer", color="orange"];
41 READY_IN_DANCE -> ACTIVATED [label="chord timer", color="orange"];
42 ACTIVATED -> PRESS_FROM_ACTIVE [label="lock next", color="orange"];
43 PRESS_FROM_ACTIVE -> LOCKED [label="lock next", color="orange"];
44
45 // deactivate_active_chords()
46 ACTIVATED -> DEACTIVATED [label="a key lifted", color="purple"];
47 PRESS_FROM_ACTIVE -> RESTART [label="a key lifted", color="orange"];
48 FINISHED_FROM_ACTIVE -> DEACTIVATED [label="a key lifted", color="orange"];
49} \ No newline at end of file
diff --git a/users/dennytom/chording_engine/state_machine.svg b/users/dennytom/chording_engine/state_machine.svg
new file mode 100644
index 000000000..773168988
--- /dev/null
+++ b/users/dennytom/chording_engine/state_machine.svg
@@ -0,0 +1,235 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<!-- Generated by graphviz version 2.40.1 (20161225.0304)
5 -->
6<!-- Title: %0 Pages: 1 -->
7<svg width="829pt" height="754pt"
8 viewBox="0.00 0.00 829.35 754.40" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 750.4)">
10<title>%0</title>
11<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-750.4 825.3486,-750.4 825.3486,4 -4,4"/>
12<!-- IDLE -->
13<g id="node1" class="node">
14<title>IDLE</title>
15<ellipse fill="none" stroke="#000000" cx="492" cy="-728.4" rx="33.043" ry="18"/>
16<text text-anchor="middle" x="492" y="-724.2" font-family="Times,serif" font-size="14.00" fill="#000000">IDLE</text>
17</g>
18<!-- READY -->
19<g id="node2" class="node">
20<title>READY</title>
21<ellipse fill="none" stroke="#000000" cx="404" cy="-639.6" rx="44.0814" ry="18"/>
22<text text-anchor="middle" x="404" y="-635.4" font-family="Times,serif" font-size="14.00" fill="#000000">READY</text>
23</g>
24<!-- IDLE&#45;&gt;READY -->
25<g id="edge12" class="edge">
26<title>IDLE&#45;&gt;READY</title>
27<path fill="none" stroke="#ffa500" d="M487.6897,-710.0931C484.347,-699.0742 478.772,-685.3407 470,-675.6 463.1872,-668.0349 454.3989,-661.7377 445.4714,-656.6382"/>
28<polygon fill="#ffa500" stroke="#ffa500" points="447.0426,-653.5099 436.5654,-651.9352 443.7738,-659.6998 447.0426,-653.5099"/>
29<text text-anchor="middle" x="524.317" y="-679.8" font-family="Times,serif" font-size="14.00" fill="#000000">all keys pressed</text>
30</g>
31<!-- READY&#45;&gt;IDLE -->
32<g id="edge8" class="edge">
33<title>READY&#45;&gt;IDLE</title>
34<path fill="none" stroke="#ff0000" d="M383.1899,-655.7528C371.9777,-666.4401 362.0803,-680.6044 370.88,-692.4 380.5143,-705.3144 418.9714,-715.2612 450.0017,-721.3939"/>
35<polygon fill="#ff0000" stroke="#ff0000" points="449.7109,-724.9011 460.188,-723.3263 451.0156,-718.0238 449.7109,-724.9011"/>
36<text text-anchor="middle" x="420.56" y="-679.8" font-family="Times,serif" font-size="14.00" fill="#000000">superchord active</text>
37</g>
38<!-- ACTIVATED -->
39<g id="node3" class="node">
40<title>ACTIVATED</title>
41<ellipse fill="none" stroke="#000000" cx="404" cy="-550.8" rx="66.0512" ry="18"/>
42<text text-anchor="middle" x="404" y="-546.6" font-family="Times,serif" font-size="14.00" fill="#000000">ACTIVATED</text>
43</g>
44<!-- READY&#45;&gt;ACTIVATED -->
45<g id="edge15" class="edge">
46<title>READY&#45;&gt;ACTIVATED</title>
47<path fill="none" stroke="#ffa500" d="M404,-621.2006C404,-609.0949 404,-593.0076 404,-579.2674"/>
48<polygon fill="#ffa500" stroke="#ffa500" points="407.5001,-578.872 404,-568.872 400.5001,-578.8721 407.5001,-578.872"/>
49<text text-anchor="middle" x="436.4611" y="-591" font-family="Times,serif" font-size="14.00" fill="#000000">chord timer</text>
50</g>
51<!-- DEACTIVATED -->
52<g id="node4" class="node">
53<title>DEACTIVATED</title>
54<ellipse fill="none" stroke="#000000" cx="301" cy="-284.4" rx="79.2922" ry="18"/>
55<text text-anchor="middle" x="301" y="-280.2" font-family="Times,serif" font-size="14.00" fill="#000000">DEACTIVATED</text>
56</g>
57<!-- ACTIVATED&#45;&gt;DEACTIVATED -->
58<g id="edge19" class="edge">
59<title>ACTIVATED&#45;&gt;DEACTIVATED</title>
60<path fill="none" stroke="#a020f0" d="M414.457,-532.6765C417.1337,-527.1214 419.6389,-520.8699 421,-514.8 426.1765,-491.7151 456.5634,-425.2497 416,-355.2 402.3607,-331.646 377.4429,-314.8951 354.2805,-303.6207"/>
61<polygon fill="#a020f0" stroke="#a020f0" points="355.7259,-300.433 345.1798,-299.4173 352.7907,-306.7879 355.7259,-300.433"/>
62<text text-anchor="middle" x="468.4881" y="-413.4" font-family="Times,serif" font-size="14.00" fill="#000000">a key lifted</text>
63</g>
64<!-- PRESS_FROM_ACTIVE -->
65<g id="node5" class="node">
66<title>PRESS_FROM_ACTIVE</title>
67<ellipse fill="none" stroke="#000000" cx="279" cy="-462" rx="111.797" ry="18"/>
68<text text-anchor="middle" x="279" y="-457.8" font-family="Times,serif" font-size="14.00" fill="#000000">PRESS_FROM_ACTIVE</text>
69</g>
70<!-- ACTIVATED&#45;&gt;PRESS_FROM_ACTIVE -->
71<g id="edge5" class="edge">
72<title>ACTIVATED&#45;&gt;PRESS_FROM_ACTIVE</title>
73<path fill="none" stroke="#00ff00" d="M381.0189,-533.8085C363.6663,-521.0049 341.3076,-504.5706 332,-498 326.1999,-493.9054 319.9973,-489.6147 313.9535,-485.4802"/>
74<polygon fill="#00ff00" stroke="#00ff00" points="315.5139,-482.3085 305.2776,-479.5755 311.5753,-488.0954 315.5139,-482.3085"/>
75<text text-anchor="middle" x="387.8454" y="-502.2" font-family="Times,serif" font-size="14.00" fill="#000000">dance timer</text>
76</g>
77<!-- ACTIVATED&#45;&gt;PRESS_FROM_ACTIVE -->
78<g id="edge17" class="edge">
79<title>ACTIVATED&#45;&gt;PRESS_FROM_ACTIVE</title>
80<path fill="none" stroke="#ffa500" d="M346.8191,-541.6158C317.1162,-535.5544 285.1886,-526.5544 276.2896,-514.8 271.0903,-507.9325 270.0671,-499.0047 270.857,-490.45"/>
81<polygon fill="#ffa500" stroke="#ffa500" points="274.3462,-490.8071 272.5608,-480.3638 267.444,-489.6411 274.3462,-490.8071"/>
82<text text-anchor="middle" x="302.8552" y="-502.2" font-family="Times,serif" font-size="14.00" fill="#000000">lock next</text>
83</g>
84<!-- IDLE_IN_DANCE -->
85<g id="node7" class="node">
86<title>IDLE_IN_DANCE</title>
87<ellipse fill="none" stroke="#000000" cx="293" cy="-195.6" rx="86.2367" ry="18"/>
88<text text-anchor="middle" x="293" y="-191.4" font-family="Times,serif" font-size="14.00" fill="#000000">IDLE_IN_DANCE</text>
89</g>
90<!-- DEACTIVATED&#45;&gt;IDLE_IN_DANCE -->
91<g id="edge3" class="edge">
92<title>DEACTIVATED&#45;&gt;IDLE_IN_DANCE</title>
93<path fill="none" stroke="#000000" d="M299.3424,-266.0006C298.241,-253.775 296.7738,-237.4887 295.5279,-223.6599"/>
94<polygon fill="#000000" stroke="#000000" points="299.0114,-223.3176 294.6281,-213.672 292.0396,-223.9458 299.0114,-223.3176"/>
95</g>
96<!-- FINISHED_FROM_ACTIVE -->
97<g id="node6" class="node">
98<title>FINISHED_FROM_ACTIVE</title>
99<ellipse fill="none" stroke="#000000" cx="280" cy="-373.2" rx="127.3672" ry="18"/>
100<text text-anchor="middle" x="280" y="-369" font-family="Times,serif" font-size="14.00" fill="#000000">FINISHED_FROM_ACTIVE</text>
101</g>
102<!-- PRESS_FROM_ACTIVE&#45;&gt;FINISHED_FROM_ACTIVE -->
103<g id="edge7" class="edge">
104<title>PRESS_FROM_ACTIVE&#45;&gt;FINISHED_FROM_ACTIVE</title>
105<path fill="none" stroke="#00ff00" d="M279.2072,-443.6006C279.3435,-431.4949 279.5247,-415.4076 279.6794,-401.6674"/>
106<polygon fill="#00ff00" stroke="#00ff00" points="283.1836,-401.3108 279.7965,-391.272 276.184,-401.2319 283.1836,-401.3108"/>
107<text text-anchor="middle" x="312.8454" y="-413.4" font-family="Times,serif" font-size="14.00" fill="#000000">dance timer</text>
108</g>
109<!-- LOCKED -->
110<g id="node10" class="node">
111<title>LOCKED</title>
112<ellipse fill="none" stroke="#000000" cx="84" cy="-373.2" rx="50.38" ry="18"/>
113<text text-anchor="middle" x="84" y="-369" font-family="Times,serif" font-size="14.00" fill="#000000">LOCKED</text>
114</g>
115<!-- PRESS_FROM_ACTIVE&#45;&gt;LOCKED -->
116<g id="edge18" class="edge">
117<title>PRESS_FROM_ACTIVE&#45;&gt;LOCKED</title>
118<path fill="none" stroke="#ffa500" d="M241.402,-444.8785C207.8161,-429.584 158.7472,-407.2387 124.3482,-391.574"/>
119<polygon fill="#ffa500" stroke="#ffa500" points="125.6113,-388.3034 115.06,-387.3442 122.7102,-394.6739 125.6113,-388.3034"/>
120<text text-anchor="middle" x="224.8552" y="-413.4" font-family="Times,serif" font-size="14.00" fill="#000000">lock next</text>
121</g>
122<!-- RESTART -->
123<g id="node12" class="node">
124<title>RESTART</title>
125<ellipse fill="none" stroke="#000000" cx="201" cy="-18" rx="53.9098" ry="18"/>
126<text text-anchor="middle" x="201" y="-13.8" font-family="Times,serif" font-size="14.00" fill="#000000">RESTART</text>
127</g>
128<!-- PRESS_FROM_ACTIVE&#45;&gt;RESTART -->
129<g id="edge20" class="edge">
130<title>PRESS_FROM_ACTIVE&#45;&gt;RESTART</title>
131<path fill="none" stroke="#ffa500" d="M190.3393,-450.9993C108.6441,-438.3099 0,-413.8018 0,-373.2 0,-373.2 0,-373.2 0,-106.8 0,-74.7037 86.8374,-46.4364 146.3579,-30.8311"/>
132<polygon fill="#ffa500" stroke="#ffa500" points="147.578,-34.1313 156.3916,-28.2515 145.835,-27.3517 147.578,-34.1313"/>
133<text text-anchor="middle" x="31.4881" y="-235.8" font-family="Times,serif" font-size="14.00" fill="#000000">a key lifted</text>
134</g>
135<!-- FINISHED_FROM_ACTIVE&#45;&gt;DEACTIVATED -->
136<g id="edge21" class="edge">
137<title>FINISHED_FROM_ACTIVE&#45;&gt;DEACTIVATED</title>
138<path fill="none" stroke="#ffa500" d="M284.3512,-354.8006C287.2424,-342.575 291.0939,-326.2887 294.3642,-312.4599"/>
139<polygon fill="#ffa500" stroke="#ffa500" points="297.8308,-313.0091 296.7262,-302.472 291.0187,-311.3981 297.8308,-313.0091"/>
140<text text-anchor="middle" x="324.4881" y="-324.6" font-family="Times,serif" font-size="14.00" fill="#000000">a key lifted</text>
141</g>
142<!-- READY_IN_DANCE -->
143<g id="node8" class="node">
144<title>READY_IN_DANCE</title>
145<ellipse fill="none" stroke="#000000" cx="402" cy="-106.8" rx="97.2741" ry="18"/>
146<text text-anchor="middle" x="402" y="-102.6" font-family="Times,serif" font-size="14.00" fill="#000000">READY_IN_DANCE</text>
147</g>
148<!-- IDLE_IN_DANCE&#45;&gt;READY_IN_DANCE -->
149<g id="edge13" class="edge">
150<title>IDLE_IN_DANCE&#45;&gt;READY_IN_DANCE</title>
151<path fill="none" stroke="#ffa500" d="M285.2465,-177.3414C281.8879,-166.3406 280.1649,-152.6093 287.366,-142.8 292.9374,-135.2107 308.8319,-128.4976 327.077,-122.9864"/>
152<polygon fill="#ffa500" stroke="#ffa500" points="328.1338,-126.3246 336.79,-120.2157 326.2135,-119.5932 328.1338,-126.3246"/>
153<text text-anchor="middle" x="332.317" y="-147" font-family="Times,serif" font-size="14.00" fill="#000000">all keys pressed</text>
154</g>
155<!-- FINISHED -->
156<g id="node9" class="node">
157<title>FINISHED</title>
158<ellipse fill="none" stroke="#000000" cx="201" cy="-106.8" rx="55.0323" ry="18"/>
159<text text-anchor="middle" x="201" y="-102.6" font-family="Times,serif" font-size="14.00" fill="#000000">FINISHED</text>
160</g>
161<!-- IDLE_IN_DANCE&#45;&gt;FINISHED -->
162<g id="edge6" class="edge">
163<title>IDLE_IN_DANCE&#45;&gt;FINISHED</title>
164<path fill="none" stroke="#00ff00" d="M231.9976,-182.6889C220.3684,-177.4272 209.5756,-170.022 202.3092,-159.6 197.3878,-152.5413 195.8986,-143.5625 195.9866,-135.0199"/>
165<polygon fill="#00ff00" stroke="#00ff00" points="199.4821,-135.2114 196.7515,-124.9745 192.5023,-134.6799 199.4821,-135.2114"/>
166<text text-anchor="middle" x="235.8454" y="-147" font-family="Times,serif" font-size="14.00" fill="#000000">dance timer</text>
167</g>
168<!-- READY_IN_DANCE&#45;&gt;ACTIVATED -->
169<g id="edge16" class="edge">
170<title>READY_IN_DANCE&#45;&gt;ACTIVATED</title>
171<path fill="none" stroke="#ffa500" d="M460.9306,-121.2262C473.3432,-126.4214 485.5301,-133.4169 495,-142.8 512.9398,-160.5753 516,-170.3454 516,-195.6 516,-462 516,-462 516,-462 516,-495.4749 484.8997,-518.3284 455.476,-532.4591"/>
172<polygon fill="#ffa500" stroke="#ffa500" points="453.6869,-529.4272 446.0233,-536.7429 456.5764,-535.803 453.6869,-529.4272"/>
173<text text-anchor="middle" x="548.4611" y="-324.6" font-family="Times,serif" font-size="14.00" fill="#000000">chord timer</text>
174</g>
175<!-- READY_IN_DANCE&#45;&gt;IDLE_IN_DANCE -->
176<g id="edge9" class="edge">
177<title>READY_IN_DANCE&#45;&gt;IDLE_IN_DANCE</title>
178<path fill="none" stroke="#ff0000" d="M398.1917,-124.942C395.0071,-136.1761 389.421,-150.2021 380,-159.6 372.9696,-166.6132 364.3766,-172.3251 355.3586,-176.9585"/>
179<polygon fill="#ff0000" stroke="#ff0000" points="353.8046,-173.8215 346.241,-181.2406 356.7803,-180.1575 353.8046,-173.8215"/>
180<text text-anchor="middle" x="441.56" y="-147" font-family="Times,serif" font-size="14.00" fill="#000000">superchord active</text>
181</g>
182<!-- FINISHED&#45;&gt;RESTART -->
183<g id="edge1" class="edge">
184<title>FINISHED&#45;&gt;RESTART</title>
185<path fill="none" stroke="#000000" d="M201,-88.4006C201,-76.2949 201,-60.2076 201,-46.4674"/>
186<polygon fill="#000000" stroke="#000000" points="204.5001,-46.072 201,-36.072 197.5001,-46.0721 204.5001,-46.072"/>
187</g>
188<!-- READY_LOCKED -->
189<g id="node11" class="node">
190<title>READY_LOCKED</title>
191<ellipse fill="none" stroke="#000000" cx="116" cy="-284.4" rx="88.0442" ry="18"/>
192<text text-anchor="middle" x="116" y="-280.2" font-family="Times,serif" font-size="14.00" fill="#000000">READY_LOCKED</text>
193</g>
194<!-- LOCKED&#45;&gt;READY_LOCKED -->
195<g id="edge11" class="edge">
196<title>LOCKED&#45;&gt;READY_LOCKED</title>
197<path fill="none" stroke="#ffa500" d="M62.8266,-356.7262C52.2277,-346.3972 43.0571,-332.745 50.366,-320.4 53.6683,-314.8223 58.175,-310.0516 63.2916,-305.985"/>
198<polygon fill="#ffa500" stroke="#ffa500" points="65.4987,-308.7148 71.7485,-300.1596 61.5278,-302.9501 65.4987,-308.7148"/>
199<text text-anchor="middle" x="95.317" y="-324.6" font-family="Times,serif" font-size="14.00" fill="#000000">all keys pressed</text>
200</g>
201<!-- READY_LOCKED&#45;&gt;LOCKED -->
202<g id="edge10" class="edge">
203<title>READY_LOCKED&#45;&gt;LOCKED</title>
204<path fill="none" stroke="#ff0000" d="M134.3377,-302.181C142.7003,-312.508 149.4503,-325.708 143,-337.2 139.1182,-344.1159 133.3081,-349.8603 126.8241,-354.5772"/>
205<polygon fill="#ff0000" stroke="#ff0000" points="124.8745,-351.6695 118.3451,-360.0132 128.6526,-357.5624 124.8745,-351.6695"/>
206<text text-anchor="middle" x="195.56" y="-324.6" font-family="Times,serif" font-size="14.00" fill="#000000">superchord active</text>
207</g>
208<!-- READY_LOCKED&#45;&gt;RESTART -->
209<g id="edge14" class="edge">
210<title>READY_LOCKED&#45;&gt;RESTART</title>
211<path fill="none" stroke="#ffa500" d="M114.0574,-266.3175C111.0132,-230.457 108.1435,-148.6335 137,-88.8 145.6041,-70.9596 160.1275,-54.343 173.1661,-41.6972"/>
212<polygon fill="#ffa500" stroke="#ffa500" points="175.702,-44.1178 180.6155,-34.7312 170.9209,-39.0049 175.702,-44.1178"/>
213<text text-anchor="middle" x="152.4611" y="-147" font-family="Times,serif" font-size="14.00" fill="#000000">chord timer</text>
214</g>
215<!-- RESTART&#45;&gt;IDLE -->
216<g id="edge2" class="edge">
217<title>RESTART&#45;&gt;IDLE</title>
218<path fill="none" stroke="#000000" d="M251.8307,-24.1482C358.5139,-37.7418 596,-71.9196 596,-106.8 596,-639.6 596,-639.6 596,-639.6 596,-665.1965 591.0323,-674.2337 573,-692.4 561.7252,-703.7586 546.243,-711.8298 531.8327,-717.4099"/>
219<polygon fill="#000000" stroke="#000000" points="530.3349,-714.2281 522.0925,-720.8849 532.6871,-720.8211 530.3349,-714.2281"/>
220</g>
221<!-- IN_ONE_SHOT -->
222<g id="node13" class="node">
223<title>IN_ONE_SHOT</title>
224<ellipse fill="none" stroke="#000000" cx="700" cy="-106.8" rx="75.8643" ry="18"/>
225<text text-anchor="middle" x="700" y="-102.6" font-family="Times,serif" font-size="14.00" fill="#000000">IN_ONE_SHOT</text>
226</g>
227<!-- IN_ONE_SHOT&#45;&gt;RESTART -->
228<g id="edge4" class="edge">
229<title>IN_ONE_SHOT&#45;&gt;RESTART</title>
230<path fill="none" stroke="#0000ff" d="M676.9312,-89.3704C659.5151,-77.2164 634.5042,-61.8271 610,-54 547.5343,-34.0473 363.5933,-24.1795 265.053,-20.2067"/>
231<polygon fill="#0000ff" stroke="#0000ff" points="265.0515,-16.704 254.9213,-19.8069 264.7755,-23.6986 265.0515,-16.704"/>
232<text text-anchor="middle" x="733.6743" y="-58.2" font-family="Times,serif" font-size="14.00" fill="#000000">non&#45;one&#45;shot key went through</text>
233</g>
234</g>
235</svg>
diff --git a/users/dennytom/chording_engine/tests/minunit.h b/users/dennytom/chording_engine/tests/minunit.h
new file mode 100644
index 000000000..ed71b6253
--- /dev/null
+++ b/users/dennytom/chording_engine/tests/minunit.h
@@ -0,0 +1,288 @@
1#define mu_assert(message, test) \
2 do { \
3 if (!(test)) { \
4 return message; \
5 } \
6 } while (0)
7
8#define RED "\033[0;31m"
9#define GREEN "\033[0;32m"
10#define NC "\033[0m"
11
12enum ASSERT_TYPES {
13 UINT,
14 INT
15};
16
17#define BUFF_SIZE 1024
18char buffer[BUFF_SIZE];
19
20#define ASSERT_EQ(type, actual, expected) \
21 do { \
22 if (actual != expected) { \
23 switch (type) { \
24 case UINT: \
25 snprintf(buffer, BUFF_SIZE, "\nline %d\nvar %s\nactual = %u\nexpected = %u\n", __LINE__, #actual, actual, expected); \
26 break; \
27 case INT: \
28 snprintf(buffer, BUFF_SIZE, "\nline %d\nvar %s\nactual = %d\nexpected = %d\n", __LINE__, #actual, actual, expected); \
29 break; \
30 default: \
31 snprintf(buffer, BUFF_SIZE, "\nline %d\nunsupported ASSERT_EQ type\n", __LINE__); \
32 break; \
33 } \
34 printf("%s\n", buffer); \
35 passed = false; \
36 all_passed = false; \
37 } \
38 } while (0)
39
40#include <stdio.h>
41#include <stdint.h>
42#include <stddef.h>
43#include <stdbool.h>
44#include <string.h>
45
46#define MATRIX_ROWS 2
47#define MATRIX_COLS 10
48#define LAYOUT_test( \
49 k09, k08, k07, k06, k05, k04, k03, k02, k01, k00, \
50 k19, k18, k17, k16, k15, k14, k13, k12, k11, k10 \
51) { \
52 { k00, k01, k02, k03, k04, k05, k06, k07, k08, k09}, \
53 { k10, k11, k12, k13, k14, k15, k16, k17, k18, k19}, \
54}
55
56#define PROGMEM
57#define memcpy_P memcpy
58const struct Chord* pgm_read_word(const struct Chord* const* chord) {return *chord;}
59
60typedef struct {
61 uint8_t col;
62 uint8_t row;
63} keypos_t;
64
65typedef struct {
66 keypos_t key;
67 bool pressed;
68 uint16_t time;
69} keyevent_t;
70
71typedef struct {
72 bool interrupted :1;
73 bool reserved2 :1;
74 bool reserved1 :1;
75 bool reserved0 :1;
76 uint8_t count :4;
77} tap_t;
78
79typedef struct {
80 keyevent_t event;
81 tap_t tap;
82} keyrecord_t;
83
84keyrecord_t pressed = {{{0,0},true,0}, {0,0,0,0,0}};
85keyrecord_t depressed = {{{0,0},false,0}, {0,0,0,0,0}};
86
87enum keycodes {
88 KC_NO,
89 KC_TILDE,
90 KC_GRAVE,
91 KC_EXCLAIM,
92 KC_1,
93 KC_AT,
94 KC_2,
95 KC_HASH,
96 KC_3,
97 KC_DOLLAR,
98 KC_4,
99 KC_PERCENT,
100 KC_5,
101 KC_CIRCUMFLEX,
102 KC_6,
103 KC_AMPERSAND,
104 KC_7,
105 KC_ASTERISK,
106 KC_8,
107 KC_LEFT_PAREN,
108 KC_9,
109 KC_RIGHT_PAREN,
110 KC_0,
111 KC_UNDERSCORE,
112 KC_MINUS,
113 KC_PLUS,
114 KC_EQUAL,
115 KC_LEFT_CURLY_BRACE,
116 KC_LBRACKET,
117 KC_RIGHT_CURLY_BRACE,
118 KC_RBRACKET,
119 KC_PIPE,
120 KC_BSLASH,
121 KC_COLON,
122 KC_SCOLON,
123 KC_DOUBLE_QUOTE,
124 KC_QUOTE,
125 KC_LEFT_ANGLE_BRACKET,
126 KC_COMMA,
127 KC_RIGHT_ANGLE_BRACKET,
128 KC_DOT,
129 KC_QUESTION,
130 KC_SLASH,
131 KC_Q,
132 KC_W,
133 KC_E,
134 KC_R,
135 KC_T,
136 KC_Y,
137 KC_U,
138 KC_I,
139 KC_O,
140 KC_P,
141 KC_A,
142 KC_S,
143 KC_D,
144 KC_F,
145 KC_G,
146 KC_H,
147 KC_J,
148 KC_K,
149 KC_L,
150 KC_Z,
151 KC_X,
152 KC_C,
153 KC_V,
154 KC_B,
155 KC_N,
156 KC_M,
157 KC_ESC,
158 KC_LSFT,
159 KC_LCTL,
160 KC_LGUI,
161 KC_LALT,
162 KC_RALT,
163 KC_RCTL,
164 KC_RGUI,
165 KC_RSFT,
166 KC_TAB,
167 KC_DEL,
168 KC_INS,
169 KC_BSPC,
170 KC_ENTER,
171 KC_SPACE,
172 KC_F1,
173 KC_F2,
174 KC_F3,
175 KC_F4,
176 KC_F5,
177 KC_F6,
178 KC_F7,
179 KC_F8,
180 KC_F9,
181 KC_F10,
182 KC_F11,
183 KC_F12,
184 KC_LEFT,
185 KC_DOWN,
186 KC_UP,
187 KC_RIGHT,
188
189 SAFE_RANGE
190};
191
192#define HISTORY 20
193
194int16_t current_time;
195uint8_t keyboard_history[HISTORY][SAFE_RANGE-1];
196int16_t time_history[HISTORY];
197uint8_t history_index;
198
199void register_code(int16_t keycode) {
200 history_index++;
201 for (int j = 0; j < SAFE_RANGE-1; j++) {
202 keyboard_history[history_index][j] = keyboard_history[history_index-1][j];
203 }
204 keyboard_history[history_index][keycode] = 1;
205 time_history[history_index] = current_time;
206};
207void unregister_code(int16_t keycode) {
208 history_index++;
209 for (int j = 0; j < SAFE_RANGE-1; j++) {
210 keyboard_history[history_index][j] = keyboard_history[history_index-1][j];
211 }
212 keyboard_history[history_index][keycode] = 0;
213 time_history[history_index] = current_time;
214};
215void send_keyboard_report(void) { /*still don't know what this does*/ };
216void matrix_scan_user (void);
217void wait_ms(uint16_t ms) {
218 current_time += ms;
219};
220uint16_t timer_read(void) {
221 uint16_t result = current_time;
222 return result;
223};
224uint16_t timer_elapsed(uint16_t timer) {
225 uint16_t result = current_time - timer;
226 return result;
227};
228void layer_move(int16_t layer) { /*ignoring for now*/ };
229void clear_keyboard(void) {
230 history_index++;
231 for (int j = 0; j < SAFE_RANGE-1; j++) {
232 keyboard_history[history_index][j] = 0;
233 }
234 time_history[history_index] = current_time;
235};
236void reset_keyboard(void) { /*ignoring for now*/ };
237
238void pause_ms(uint16_t ms) {
239 for (int i = 0; i < ms; i++) {
240 current_time++;
241 matrix_scan_user();
242 }
243};
244
245#define TEST(name) \
246 do { \
247 printf("%s\n", name); \
248 passed = true; \
249 do { \
250 uint8_t clear_state = ACTIVATED; \
251 struct Chord clear_chord PROGMEM = {0, QWERTY, &clear_state, NULL, 0, 0, clear}; \
252 clear_chord.function(&clear_chord); \
253 } while (0); \
254 current_time = 0; \
255 history_index = 0; \
256 for (int j = 0; j < SAFE_RANGE-1; j++) { \
257 keyboard_history[0][j] = 0; \
258 } \
259 time_history[0] = 0; \
260 for (int i = 1; i < HISTORY; i++) { \
261 for (int j = 0; j < SAFE_RANGE-1; j++) { \
262 keyboard_history[i][j] = -1; \
263 } \
264 time_history[i] = -1; \
265 }
266
267#define END_TEST \
268 if (passed) { \
269 printf(GREEN"PASSED"NC"\n"); \
270 } else { \
271 printf(RED"FAILED"NC"\n"); \
272 } \
273 } while(0);
274
275#define MAIN \
276int main(int argc, char **argv) { \
277 bool passed = true; \
278 bool all_passed = true;
279
280#define END \
281 printf("\n"); \
282 if (all_passed) { \
283 printf(GREEN"ALL TESTS PASSED"NC"\n"); \
284 } else { \
285 printf(RED"TESTS FAILED"NC"\n"); \
286 } \
287 return 1 - all_passed; \
288} \ No newline at end of file
diff --git a/users/dennytom/chording_engine/tests/test.c b/users/dennytom/chording_engine/tests/test.c
new file mode 100644
index 000000000..0cc172f0a
--- /dev/null
+++ b/users/dennytom/chording_engine/tests/test.c
@@ -0,0 +1,1259 @@
1#include "minunit.h"
2#include "test_keymap.c"
3
4MAIN
5
6// CLEAR_KB
7TEST("clear")
8 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
9 struct Chord* chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
10 struct Chord chord_storage;
11 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
12 struct Chord* chord = &chord_storage;
13
14 *chord->state = READY;
15
16 if (chord->counter) {
17 *chord->counter = 1;
18 }
19 }
20
21 history_index++;
22 for (int j = 0; j < SAFE_RANGE-1; j++) {
23 keyboard_history[history_index][j] = 1;
24 }
25
26 current_pseudolayer = 5;
27 lock_next = true;
28 autoshift_mode = false;
29 command_mode = 1;
30 in_leader_mode = true;
31 dynamic_macro_mode = true;
32 a_key_went_through = true;
33
34 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
35 dynamic_macro_buffer[i] = 1;
36 }
37
38 uint8_t clear_state = ACTIVATED;
39 struct Chord clear_chord PROGMEM = {0, QWERTY, &clear_state, NULL, 0, 0, clear};
40 clear_chord.function(&clear_chord);
41
42 for (int i = 0; i < NUMBER_OF_CHORDS; i++) {
43 struct Chord* chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]);
44 struct Chord chord_storage;
45 memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord));
46 struct Chord* chord = &chord_storage;
47
48 ASSERT_EQ(UINT, *chord->state, IDLE);
49
50 if (chord->counter) {
51 ASSERT_EQ(UINT, *chord->counter, 0);
52 }
53 }
54
55 for (int j = 0; j < SAFE_RANGE-1; j++) {
56 ASSERT_EQ(UINT, keyboard_history[history_index][j], 0);
57 }
58
59 ASSERT_EQ(UINT, current_pseudolayer, 1);
60 ASSERT_EQ(UINT, lock_next, false);
61 ASSERT_EQ(UINT, autoshift_mode, true);
62 ASSERT_EQ(UINT, command_mode, 0);
63 ASSERT_EQ(UINT, in_leader_mode, false);
64 ASSERT_EQ(UINT, leader_ind, 0);
65 ASSERT_EQ(UINT, dynamic_macro_mode, false);
66 ASSERT_EQ(UINT, a_key_went_through, false);
67
68 for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) {
69 ASSERT_EQ(UINT, dynamic_macro_buffer[i], 0);
70 }
71END_TEST
72
73TEST("pause_ms")
74 pause_ms(500);
75 ASSERT_EQ(UINT, current_time, 500);
76END_TEST
77
78// KC
79TEST("single_dance_held_states")
80 ASSERT_EQ(UINT, state_1, IDLE);
81 process_record_user(TOP1, &pressed);
82 pause_ms(CHORD_TIMEOUT);
83 ASSERT_EQ(UINT, state_1, IDLE);
84 pause_ms(1);
85 ASSERT_EQ(UINT, state_1, ACTIVATED);
86 pause_ms(DANCE_TIMEOUT);
87 ASSERT_EQ(UINT, state_1, ACTIVATED);
88 pause_ms(1);
89 ASSERT_EQ(UINT, state_1, PRESS_FROM_ACTIVE);
90 pause_ms(DANCE_TIMEOUT);
91 ASSERT_EQ(UINT, state_1, PRESS_FROM_ACTIVE);
92 pause_ms(1);
93 ASSERT_EQ(UINT, state_1, FINISHED_FROM_ACTIVE);
94 process_record_user(TOP1, &depressed);
95 ASSERT_EQ(UINT, state_1, IDLE);
96END_TEST
97
98TEST("single_dance_held_codes")
99 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
100 process_record_user(TOP1, &pressed);
101 pause_ms(CHORD_TIMEOUT);
102 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
103 pause_ms(1);
104 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
105 pause_ms(DANCE_TIMEOUT);
106 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
107 pause_ms(1);
108 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
109 pause_ms(DANCE_TIMEOUT);
110 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
111 pause_ms(1);
112 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
113 process_record_user(TOP1, &depressed);
114 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
115END_TEST
116
117TEST("single_dance_tapped_states")
118 ASSERT_EQ(UINT, state_1, IDLE);
119 process_record_user(TOP1, &pressed);
120 pause_ms(CHORD_TIMEOUT);
121 ASSERT_EQ(UINT, state_1, IDLE);
122 pause_ms(1);
123 ASSERT_EQ(UINT, state_1, ACTIVATED);
124 process_record_user(TOP1, &depressed);
125 ASSERT_EQ(UINT, state_1, IDLE);
126END_TEST
127
128TEST("single_dance_tapped_codes")
129 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
130 process_record_user(TOP1, &pressed);
131 pause_ms(CHORD_TIMEOUT);
132 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
133 pause_ms(1);
134 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
135 process_record_user(TOP1, &depressed);
136 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
137END_TEST
138
139// I can not actually track the states if the tap is faster than chord timeout
140
141TEST("single_dance_tapped_fast_codes")
142 ASSERT_EQ(UINT, state_0, IDLE);
143 process_record_user(TOP1, &pressed);
144 pause_ms(1);
145 process_record_user(TOP1, &depressed);
146 ASSERT_EQ(UINT, keyboard_history[0][KC_Q], 0);
147 ASSERT_EQ(UINT, keyboard_history[1][KC_Q], 1);
148 ASSERT_EQ(UINT, keyboard_history[2][KC_Q], 0);
149END_TEST
150
151TEST("subchords_are_ignored")
152 ASSERT_EQ(UINT, state_0, IDLE);
153 process_record_user(TOP1, &pressed);
154 pause_ms(1);
155 process_record_user(TOP2, &pressed);
156 pause_ms(CHORD_TIMEOUT + 1);
157 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
158 ASSERT_EQ(UINT, keyboard_history[history_index][KC_W], 0);
159 ASSERT_EQ(UINT, keyboard_history[history_index][KC_ESC], 1);
160END_TEST
161
162TEST("multiple_chords_at_once")
163 ASSERT_EQ(UINT, state_0, IDLE);
164 process_record_user(TOP1, &pressed);
165 pause_ms(1);
166 process_record_user(TOP3, &pressed);
167 pause_ms(CHORD_TIMEOUT + 1);
168 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 1);
169 ASSERT_EQ(UINT, keyboard_history[history_index][KC_E], 1);
170END_TEST
171
172// MO
173TEST("momentary_layer")
174 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
175 process_record_user(BOT7, &pressed);
176 pause_ms(1);
177 process_record_user(BOT8, &pressed);
178 pause_ms(CHORD_TIMEOUT + 1);
179 ASSERT_EQ(UINT, current_pseudolayer, NUM);
180 process_record_user(BOT7, &depressed);
181 pause_ms(1);
182 process_record_user(BOT8, &depressed);
183 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
184END_TEST
185
186TEST("momentary_layer_reset")
187 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
188 process_record_user(BOT7, &pressed);
189 pause_ms(1);
190 process_record_user(BOT8, &pressed);
191 pause_ms(CHORD_TIMEOUT + 1);
192 ASSERT_EQ(UINT, current_pseudolayer, NUM);
193 pause_ms(DANCE_TIMEOUT + 1);
194 ASSERT_EQ(UINT, current_pseudolayer, NUM);
195 process_record_user(BOT7, &depressed);
196 pause_ms(1);
197 process_record_user(BOT8, &depressed);
198 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
199END_TEST
200
201TEST("momentary_layer_alt")
202 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
203
204 process_record_user(TOP8, &pressed);
205 pause_ms(1);
206 process_record_user(TOP9, &pressed);
207 pause_ms(1);
208 process_record_user(TOP0, &pressed);
209 pause_ms(1);
210 process_record_user(BOT8, &pressed);
211 pause_ms(1);
212 process_record_user(BOT9, &pressed);
213 pause_ms(1);
214 process_record_user(BOT0, &pressed);
215 pause_ms(CHORD_TIMEOUT + 1);
216
217 ASSERT_EQ(UINT, current_pseudolayer, NUM);
218
219 process_record_user(TOP8, &depressed);
220 pause_ms(1);
221 process_record_user(TOP9, &depressed);
222 pause_ms(1);
223 process_record_user(TOP0, &depressed);
224 pause_ms(1);
225 process_record_user(BOT8, &depressed);
226 pause_ms(1);
227 process_record_user(BOT9, &depressed);
228 pause_ms(1);
229 process_record_user(BOT0, &depressed);
230
231 ASSERT_EQ(UINT, current_pseudolayer, FNC);
232END_TEST
233
234// DF
235TEST("permanent_layer")
236 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
237 process_record_user(BOT9, &pressed);
238 pause_ms(1);
239 process_record_user(BOT0, &pressed);
240 pause_ms(CHORD_TIMEOUT + 1);
241 ASSERT_EQ(UINT, current_pseudolayer, NUM);
242 process_record_user(BOT9, &depressed);
243 pause_ms(1);
244 process_record_user(BOT0, &depressed);
245 ASSERT_EQ(UINT, current_pseudolayer, NUM);
246 pause_ms(1000);
247 ASSERT_EQ(UINT, current_pseudolayer, NUM);
248END_TEST
249
250// AT
251TEST("autoshift_toggle")
252 ASSERT_EQ(UINT, autoshift_mode, 1);
253 uint8_t state = ACTIVATED;
254 struct Chord chord PROGMEM = {0, QWERTY, &state, NULL, 0, 0, autoshift_toggle};
255 chord.function(&chord);
256 ASSERT_EQ(UINT, autoshift_mode, 0);
257 state = ACTIVATED;
258 chord.function(&chord);
259 ASSERT_EQ(UINT, autoshift_mode, 1);
260END_TEST
261
262// AS
263TEST("autoshift_tap")
264 process_record_user(BOT1, &pressed);
265 pause_ms(CHORD_TIMEOUT + 1);
266 process_record_user(BOT1, &depressed);
267
268 ASSERT_EQ(UINT, keyboard_history[0][KC_Z], 0);
269 ASSERT_EQ(UINT, keyboard_history[0][KC_LSFT], 0);
270
271 ASSERT_EQ(UINT, keyboard_history[1][KC_Z], 1);
272 ASSERT_EQ(UINT, keyboard_history[1][KC_LSFT], 0);
273
274 ASSERT_EQ(UINT, keyboard_history[2][KC_Z], 0);
275 ASSERT_EQ(UINT, keyboard_history[2][KC_LSFT], 0);
276END_TEST
277
278TEST("autoshift_hold")
279 process_record_user(BOT1, &pressed);
280 pause_ms(CHORD_TIMEOUT + 1);
281 pause_ms(LONG_PRESS_MULTIPLIER * (DANCE_TIMEOUT + 1));
282 process_record_user(BOT1, &depressed);
283
284 ASSERT_EQ(UINT, keyboard_history[0][KC_Z], 0);
285 ASSERT_EQ(UINT, keyboard_history[0][KC_LSFT], 0);
286
287 ASSERT_EQ(UINT, keyboard_history[1][KC_Z], 0);
288 ASSERT_EQ(UINT, keyboard_history[1][KC_LSFT], 1);
289
290 ASSERT_EQ(UINT, keyboard_history[2][KC_Z], 1);
291 ASSERT_EQ(UINT, keyboard_history[2][KC_LSFT], 1);
292
293 ASSERT_EQ(UINT, keyboard_history[3][KC_Z], 0);
294 ASSERT_EQ(UINT, keyboard_history[3][KC_LSFT], 1);
295
296 ASSERT_EQ(UINT, keyboard_history[4][KC_Z], 0);
297 ASSERT_EQ(UINT, keyboard_history[4][KC_LSFT], 0);
298END_TEST
299
300TEST("autoshift_hold_off")
301 autoshift_mode = 0;
302 process_record_user(BOT1, &pressed);
303 pause_ms(CHORD_TIMEOUT + 1);
304 pause_ms(LONG_PRESS_MULTIPLIER * (DANCE_TIMEOUT + 1));
305 process_record_user(BOT1, &depressed);
306
307 ASSERT_EQ(UINT, keyboard_history[0][KC_Z], 0);
308 ASSERT_EQ(UINT, keyboard_history[0][KC_LSFT], 0);
309
310 ASSERT_EQ(UINT, keyboard_history[1][KC_Z], 1);
311 ASSERT_EQ(UINT, keyboard_history[1][KC_LSFT], 0);
312
313 ASSERT_EQ(UINT, keyboard_history[2][KC_Z], 0);
314 ASSERT_EQ(UINT, keyboard_history[2][KC_LSFT], 0);
315END_TEST
316
317// LOCK
318TEST("lock")
319 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
320 process_record_user(BOT1, &pressed);
321 process_record_user(BOT2, &pressed);
322 pause_ms(CHORD_TIMEOUT + 1);
323 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
324 process_record_user(BOT1, &depressed);
325 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
326 pause_ms(1);
327 process_record_user(BOT2, &depressed);
328 pause_ms(1);
329 process_record_user(TOP1, &pressed);
330 process_record_user(TOP2, &pressed);
331 process_record_user(BOT1, &pressed);
332 process_record_user(BOT2, &pressed);
333 pause_ms(CHORD_TIMEOUT + 1);
334 process_record_user(TOP1, &depressed);
335 pause_ms(1);
336 process_record_user(TOP2, &depressed);
337 process_record_user(BOT1, &depressed);
338 process_record_user(BOT2, &depressed);
339 pause_ms(1);
340 process_record_user(BOT1, &pressed);
341 process_record_user(BOT2, &pressed);
342 pause_ms(CHORD_TIMEOUT + 1);
343 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
344 process_record_user(BOT1, &depressed);
345 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
346 pause_ms(1);
347 process_record_user(BOT2, &depressed);
348 pause_ms(1000);
349 process_record_user(BOT1, &pressed);
350 process_record_user(BOT2, &pressed);
351 pause_ms(CHORD_TIMEOUT + 1);
352 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
353 process_record_user(BOT1, &depressed);
354 pause_ms(1);
355 process_record_user(BOT2, &depressed);
356 pause_ms(1000);
357 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
358END_TEST
359
360// OSK
361TEST("one_shot_key_tap")
362 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
363 process_record_user(BOT2, &pressed);
364 process_record_user(BOT3, &pressed);
365 pause_ms(CHORD_TIMEOUT + 1);
366 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
367 process_record_user(BOT2, &depressed);
368 pause_ms(1);
369 process_record_user(BOT3, &depressed);
370 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
371 pause_ms(1000);
372 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
373
374 process_record_user(TOP1, &pressed);
375 pause_ms(CHORD_TIMEOUT + 1);
376 process_record_user(TOP1, &depressed);
377 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
378END_TEST
379
380TEST("one_shot_key_hold")
381 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
382 process_record_user(BOT2, &pressed);
383 process_record_user(BOT3, &pressed);
384 pause_ms(CHORD_TIMEOUT + 1);
385 pause_ms(DANCE_TIMEOUT + 1);
386 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
387
388 process_record_user(TOP1, &pressed);
389 pause_ms(CHORD_TIMEOUT + 1);
390 process_record_user(TOP1, &depressed);
391 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
392
393 process_record_user(BOT2, &depressed);
394 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
395END_TEST
396
397TEST("one_shot_key_retrotapping")
398 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
399 process_record_user(BOT2, &pressed);
400 process_record_user(BOT3, &pressed);
401 pause_ms(CHORD_TIMEOUT + 1);
402 pause_ms(DANCE_TIMEOUT + 1);
403 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
404
405 pause_ms(1000);
406
407 process_record_user(BOT2, &depressed);
408 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 1);
409END_TEST
410
411// OSL
412TEST("one_shot_layer_tap")
413 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
414 process_record_user(BOT6, &pressed);
415 process_record_user(BOT7, &pressed);
416 pause_ms(CHORD_TIMEOUT + 1);
417 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
418 process_record_user(BOT6, &depressed);
419 pause_ms(1);
420 process_record_user(BOT7, &depressed);
421 ASSERT_EQ(UINT, current_pseudolayer, NUM);
422 pause_ms(1000);
423 ASSERT_EQ(UINT, current_pseudolayer, NUM);
424
425 process_record_user(TOP1, &pressed);
426 pause_ms(CHORD_TIMEOUT + 1);
427 process_record_user(TOP1, &depressed);
428 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
429END_TEST
430
431TEST("one_shot_layer_hold")
432 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
433 process_record_user(BOT6, &pressed);
434 process_record_user(BOT7, &pressed);
435 pause_ms(CHORD_TIMEOUT + 1);
436 pause_ms(DANCE_TIMEOUT + 1);
437 ASSERT_EQ(UINT, current_pseudolayer, NUM);
438
439 process_record_user(TOP1, &pressed);
440 pause_ms(CHORD_TIMEOUT + 1);
441 process_record_user(TOP1, &depressed);
442 ASSERT_EQ(UINT, current_pseudolayer, NUM);
443
444 process_record_user(BOT6, &depressed);
445 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
446END_TEST
447
448TEST("one_shot_layer_retrotapping")
449 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
450 process_record_user(BOT6, &pressed);
451 process_record_user(BOT7, &pressed);
452 pause_ms(CHORD_TIMEOUT + 1);
453 pause_ms(DANCE_TIMEOUT + 1);
454 ASSERT_EQ(UINT, current_pseudolayer, NUM);
455
456 pause_ms(1000);
457
458 process_record_user(BOT6, &depressed);
459 ASSERT_EQ(UINT, current_pseudolayer, NUM);
460END_TEST
461
462// CMD
463TEST("command_mode")
464 // start recording
465 process_record_user(TOP5, &pressed);
466 process_record_user(TOP6, &pressed);
467 process_record_user(BOT5, &pressed);
468 process_record_user(BOT6, &pressed);
469 pause_ms(1);
470 process_record_user(TOP5, &depressed);
471 process_record_user(TOP6, &depressed);
472 process_record_user(BOT5, &depressed);
473 process_record_user(BOT6, &depressed);
474
475 ASSERT_EQ(UINT, command_mode, 1);
476
477 // record shift+q
478 process_record_user(BOT1, &pressed);
479 process_record_user(BOT2, &pressed);
480 pause_ms(CHORD_TIMEOUT + 1);
481 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
482 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
483 process_record_user(BOT1, &depressed);
484 process_record_user(BOT2, &depressed);
485 pause_ms(1000);
486
487 process_record_user(TOP1, &pressed);
488 pause_ms(CHORD_TIMEOUT + 1);
489 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
490 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
491 process_record_user(TOP1, &depressed);
492 pause_ms(1000);
493
494
495 ASSERT_EQ(UINT, keyboard_history[history_index][KC_Q], 0);
496 ASSERT_EQ(UINT, keyboard_history[history_index][KC_LSFT], 0);
497 // execute
498 process_record_user(TOP5, &pressed);
499 process_record_user(TOP6, &pressed);
500 process_record_user(BOT5, &pressed);
501 process_record_user(BOT6, &pressed);
502 pause_ms(CHORD_TIMEOUT + 1);
503
504 ASSERT_EQ(UINT, command_mode, 0);
505
506 // test history
507 ASSERT_EQ(UINT, keyboard_history[0][KC_Q], 0);
508 ASSERT_EQ(UINT, keyboard_history[0][KC_LSFT], 0);
509
510 ASSERT_EQ(UINT, keyboard_history[1][KC_Q], 0);
511 ASSERT_EQ(UINT, keyboard_history[1][KC_LSFT], 1);
512
513 ASSERT_EQ(UINT, keyboard_history[2][KC_Q], 1);
514 ASSERT_EQ(UINT, keyboard_history[2][KC_LSFT], 1);
515
516 ASSERT_EQ(UINT, keyboard_history[3][KC_Q], 1);
517 ASSERT_EQ(UINT, keyboard_history[3][KC_LSFT], 0);
518
519 ASSERT_EQ(UINT, keyboard_history[4][KC_Q], 0);
520 ASSERT_EQ(UINT, keyboard_history[4][KC_LSFT], 0);
521
522 ASSERT_EQ(UINT, keyboard_history[5][KC_Q], 255);
523 ASSERT_EQ(UINT, keyboard_history[5][KC_LSFT], 255);
524END_TEST
525
526// KK
527TEST("key_key_dance_tap")
528 process_record_user(BOT2, &pressed);
529 pause_ms(CHORD_TIMEOUT + 1);
530 process_record_user(BOT2, &depressed);
531
532 ASSERT_EQ(UINT, keyboard_history[0][KC_X], 0);
533 ASSERT_EQ(UINT, keyboard_history[0][KC_LCTL], 0);
534
535 ASSERT_EQ(UINT, keyboard_history[1][KC_X], 1);
536 ASSERT_EQ(UINT, keyboard_history[1][KC_LCTL], 0);
537
538 ASSERT_EQ(UINT, keyboard_history[2][KC_X], 0);
539 ASSERT_EQ(UINT, keyboard_history[2][KC_LCTL], 0);
540END_TEST
541
542TEST("key_key_dance_hold")
543 process_record_user(BOT2, &pressed);
544 pause_ms(CHORD_TIMEOUT + 1);
545 pause_ms(DANCE_TIMEOUT + 1);
546 process_record_user(BOT2, &depressed);
547
548 ASSERT_EQ(UINT, keyboard_history[0][KC_X], 0);
549 ASSERT_EQ(UINT, keyboard_history[0][KC_LCTL], 0);
550
551 ASSERT_EQ(UINT, keyboard_history[1][KC_X], 0);
552 ASSERT_EQ(UINT, keyboard_history[1][KC_LCTL], 1);
553
554 ASSERT_EQ(UINT, keyboard_history[2][KC_X], 0);
555 ASSERT_EQ(UINT, keyboard_history[2][KC_LCTL], 0);
556END_TEST
557
558// KL
559TEST("key_layer_tap")
560 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
561 process_record_user(BOT3, &pressed);
562 pause_ms(CHORD_TIMEOUT + 1);
563 ASSERT_EQ(UINT, current_pseudolayer, NUM);
564 process_record_user(BOT3, &depressed);
565 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
566 pause_ms(1000);
567
568 ASSERT_EQ(UINT, keyboard_history[0][KC_C], 0);
569 ASSERT_EQ(UINT, keyboard_history[1][KC_C], 1);
570 ASSERT_EQ(UINT, keyboard_history[2][KC_C], 0);
571 ASSERT_EQ(UINT, keyboard_history[3][KC_C], 255);
572END_TEST
573
574TEST("key_layer_retrotapping")
575 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
576 process_record_user(BOT3, &pressed);
577 pause_ms(1000);
578 ASSERT_EQ(UINT, current_pseudolayer, NUM);
579 process_record_user(BOT3, &depressed);
580 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
581 pause_ms(1000);
582
583 ASSERT_EQ(UINT, keyboard_history[0][KC_C], 0);
584 ASSERT_EQ(UINT, keyboard_history[1][KC_C], 1);
585 ASSERT_EQ(UINT, keyboard_history[2][KC_C], 0);
586 ASSERT_EQ(UINT, keyboard_history[3][KC_C], 255);
587END_TEST
588
589TEST("key_layer_hold_quick_typist")
590 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
591 process_record_user(BOT3, &pressed);
592 pause_ms(CHORD_TIMEOUT + 1);
593 ASSERT_EQ(UINT, current_pseudolayer, NUM);
594
595 pause_ms(1);
596 process_record_user(TOP1, &pressed);
597 pause_ms(1);
598 process_record_user(TOP1, &depressed);
599 pause_ms(1);
600 process_record_user(TOP1, &pressed);
601 pause_ms(1);
602 process_record_user(TOP1, &depressed);
603 pause_ms(1);
604 process_record_user(TOP1, &pressed);
605 pause_ms(1);
606 process_record_user(TOP1, &depressed);
607 ASSERT_EQ(UINT, current_pseudolayer, NUM);
608 pause_ms(1);
609
610 process_record_user(BOT3, &depressed);
611 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
612
613 ASSERT_EQ(UINT, keyboard_history[0][KC_1], 0);
614 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
615 ASSERT_EQ(UINT, keyboard_history[2][KC_1], 0);
616 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 1);
617 ASSERT_EQ(UINT, keyboard_history[4][KC_1], 0);
618 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 1);
619 ASSERT_EQ(UINT, keyboard_history[6][KC_1], 0);
620 ASSERT_EQ(UINT, keyboard_history[7][KC_1], 255);
621END_TEST
622
623TEST("key_layer_hold_slow_typist")
624 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
625 process_record_user(BOT3, &pressed);
626 pause_ms(CHORD_TIMEOUT + 1);
627 ASSERT_EQ(UINT, current_pseudolayer, NUM);
628
629 pause_ms(1000);
630 process_record_user(TOP1, &pressed);
631 pause_ms(1000);
632 process_record_user(TOP1, &depressed);
633 pause_ms(1000);
634 process_record_user(TOP1, &pressed);
635 pause_ms(1000);
636 process_record_user(TOP1, &depressed);
637 pause_ms(1000);
638 process_record_user(TOP1, &pressed);
639 pause_ms(1000);
640 process_record_user(TOP1, &depressed);
641 ASSERT_EQ(UINT, current_pseudolayer, NUM);
642 pause_ms(1);
643
644 process_record_user(BOT3, &depressed);
645 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
646
647 ASSERT_EQ(UINT, keyboard_history[0][KC_1], 0);
648 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
649 ASSERT_EQ(UINT, keyboard_history[2][KC_1], 0);
650 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 1);
651 ASSERT_EQ(UINT, keyboard_history[4][KC_1], 0);
652 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 1);
653 ASSERT_EQ(UINT, keyboard_history[6][KC_1], 0);
654 ASSERT_EQ(UINT, keyboard_history[7][KC_1], 255);
655END_TEST
656
657// KM
658TEST("key_mod_tap")
659 ASSERT_EQ(UINT, keyboard_history[0][KC_LALT], 0);
660 ASSERT_EQ(UINT, keyboard_history[0][KC_V], 0);
661 process_record_user(BOT4, &pressed);
662 pause_ms(CHORD_TIMEOUT + 1);
663 ASSERT_EQ(UINT, keyboard_history[1][KC_LALT], 1);
664 ASSERT_EQ(UINT, keyboard_history[1][KC_V], 0);
665 process_record_user(BOT4, &depressed);
666 ASSERT_EQ(UINT, keyboard_history[2][KC_LALT], 0);
667 ASSERT_EQ(UINT, keyboard_history[2][KC_V], 0);
668 pause_ms(1000);
669
670 ASSERT_EQ(UINT, keyboard_history[3][KC_LALT], 0);
671 ASSERT_EQ(UINT, keyboard_history[3][KC_V], 1);
672 ASSERT_EQ(UINT, keyboard_history[4][KC_LALT], 0);
673 ASSERT_EQ(UINT, keyboard_history[4][KC_V], 0);
674 ASSERT_EQ(UINT, keyboard_history[5][KC_LALT], 255);
675 ASSERT_EQ(UINT, keyboard_history[5][KC_V], 255);
676END_TEST
677
678TEST("key_mod_retrotapping")
679 ASSERT_EQ(UINT, keyboard_history[0][KC_LALT], 0);
680 ASSERT_EQ(UINT, keyboard_history[0][KC_V], 0);
681 process_record_user(BOT4, &pressed);
682 pause_ms(1000);
683 ASSERT_EQ(UINT, keyboard_history[1][KC_LALT], 1);
684 ASSERT_EQ(UINT, keyboard_history[1][KC_V], 0);
685 process_record_user(BOT4, &depressed);
686 ASSERT_EQ(UINT, keyboard_history[2][KC_LALT], 0);
687 ASSERT_EQ(UINT, keyboard_history[2][KC_V], 0);
688 pause_ms(1000);
689
690 ASSERT_EQ(UINT, keyboard_history[3][KC_LALT], 0);
691 ASSERT_EQ(UINT, keyboard_history[3][KC_V], 1);
692 ASSERT_EQ(UINT, keyboard_history[4][KC_LALT], 0);
693 ASSERT_EQ(UINT, keyboard_history[4][KC_V], 0);
694 ASSERT_EQ(UINT, keyboard_history[5][KC_LALT], 255);
695 ASSERT_EQ(UINT, keyboard_history[5][KC_V], 255);
696END_TEST
697
698TEST("key_mod_hold_quick_typist")
699 process_record_user(BOT4, &pressed);
700 pause_ms(CHORD_TIMEOUT + 1);
701
702 pause_ms(1);
703 process_record_user(TOP1, &pressed);
704 pause_ms(1);
705 process_record_user(TOP1, &depressed);
706 pause_ms(1);
707 process_record_user(TOP1, &pressed);
708 pause_ms(1);
709 process_record_user(TOP1, &depressed);
710 pause_ms(1);
711 process_record_user(TOP1, &pressed);
712 pause_ms(1);
713 process_record_user(TOP1, &depressed);
714 pause_ms(1);
715
716 process_record_user(BOT4, &depressed);
717 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
718
719 ASSERT_EQ(UINT, keyboard_history[0][KC_LALT], 0);
720 ASSERT_EQ(UINT, keyboard_history[0][KC_V], 0);
721 ASSERT_EQ(UINT, keyboard_history[1][KC_LALT], 1);
722 ASSERT_EQ(UINT, keyboard_history[1][KC_V], 0);
723 ASSERT_EQ(UINT, keyboard_history[2][KC_LALT], 1);
724 ASSERT_EQ(UINT, keyboard_history[2][KC_V], 0);
725 ASSERT_EQ(UINT, keyboard_history[3][KC_LALT], 1);
726 ASSERT_EQ(UINT, keyboard_history[3][KC_V], 0);
727 ASSERT_EQ(UINT, keyboard_history[4][KC_LALT], 1);
728 ASSERT_EQ(UINT, keyboard_history[4][KC_V], 0);
729 ASSERT_EQ(UINT, keyboard_history[5][KC_LALT], 1);
730 ASSERT_EQ(UINT, keyboard_history[5][KC_V], 0);
731 ASSERT_EQ(UINT, keyboard_history[6][KC_LALT], 1);
732 ASSERT_EQ(UINT, keyboard_history[6][KC_V], 0);
733 ASSERT_EQ(UINT, keyboard_history[7][KC_LALT], 1);
734 ASSERT_EQ(UINT, keyboard_history[7][KC_V], 0);
735 ASSERT_EQ(UINT, keyboard_history[8][KC_LALT], 0);
736 ASSERT_EQ(UINT, keyboard_history[8][KC_V], 0);
737 ASSERT_EQ(UINT, keyboard_history[9][KC_LALT], 255);
738 ASSERT_EQ(UINT, keyboard_history[9][KC_V], 255);
739END_TEST
740
741TEST("key_mod_hold_slow_typist")
742 process_record_user(BOT4, &pressed);
743 pause_ms(CHORD_TIMEOUT + 1);
744
745 pause_ms(1000);
746 process_record_user(TOP1, &pressed);
747 pause_ms(1000);
748 process_record_user(TOP1, &depressed);
749 pause_ms(1000);
750 process_record_user(TOP1, &pressed);
751 pause_ms(1000);
752 process_record_user(TOP1, &depressed);
753 pause_ms(1000);
754 process_record_user(TOP1, &pressed);
755 pause_ms(1000);
756 process_record_user(TOP1, &depressed);
757 pause_ms(1000);
758
759 process_record_user(BOT4, &depressed);
760 ASSERT_EQ(UINT, current_pseudolayer, QWERTY);
761
762 ASSERT_EQ(UINT, keyboard_history[0][KC_LALT], 0);
763 ASSERT_EQ(UINT, keyboard_history[0][KC_V], 0);
764 ASSERT_EQ(UINT, keyboard_history[0][KC_Q], 0);
765 ASSERT_EQ(UINT, keyboard_history[1][KC_LALT], 1);
766 ASSERT_EQ(UINT, keyboard_history[1][KC_V], 0);
767 ASSERT_EQ(UINT, keyboard_history[1][KC_Q], 0);
768 ASSERT_EQ(UINT, keyboard_history[2][KC_LALT], 1);
769 ASSERT_EQ(UINT, keyboard_history[2][KC_V], 0);
770 ASSERT_EQ(UINT, keyboard_history[2][KC_Q], 1);
771 ASSERT_EQ(UINT, keyboard_history[3][KC_LALT], 1);
772 ASSERT_EQ(UINT, keyboard_history[3][KC_V], 0);
773 ASSERT_EQ(UINT, keyboard_history[3][KC_Q], 0);
774 ASSERT_EQ(UINT, keyboard_history[4][KC_LALT], 1);
775 ASSERT_EQ(UINT, keyboard_history[4][KC_V], 0);
776 ASSERT_EQ(UINT, keyboard_history[4][KC_Q], 1);
777 ASSERT_EQ(UINT, keyboard_history[5][KC_LALT], 1);
778 ASSERT_EQ(UINT, keyboard_history[5][KC_V], 0);
779 ASSERT_EQ(UINT, keyboard_history[5][KC_Q], 0);
780 ASSERT_EQ(UINT, keyboard_history[6][KC_LALT], 1);
781 ASSERT_EQ(UINT, keyboard_history[6][KC_V], 0);
782 ASSERT_EQ(UINT, keyboard_history[6][KC_Q], 1);
783 ASSERT_EQ(UINT, keyboard_history[7][KC_LALT], 1);
784 ASSERT_EQ(UINT, keyboard_history[7][KC_V], 0);
785 ASSERT_EQ(UINT, keyboard_history[7][KC_Q], 0);
786 ASSERT_EQ(UINT, keyboard_history[8][KC_LALT], 0);
787 ASSERT_EQ(UINT, keyboard_history[8][KC_V], 0);
788 ASSERT_EQ(UINT, keyboard_history[8][KC_Q], 0);
789 ASSERT_EQ(UINT, keyboard_history[9][KC_LALT], 255);
790 ASSERT_EQ(UINT, keyboard_history[9][KC_V], 255);
791 ASSERT_EQ(UINT, keyboard_history[9][KC_Q], 255);
792END_TEST
793
794// LEADER
795TEST("leader_triggers_global")
796 uint8_t state = ACTIVATED;
797 struct Chord chord PROGMEM = {0, QWERTY, &state, NULL, 0, 0, leader};
798 chord.function(&chord);
799
800 ASSERT_EQ(UINT, in_leader_mode, 1);
801END_TEST
802
803TEST("leader_no_follow")
804 uint8_t state = ACTIVATED;
805 struct Chord chord PROGMEM = {0, QWERTY, &state, NULL, 0, 0, leader};
806 chord.function(&chord);
807
808 ASSERT_EQ(UINT, in_leader_mode, 1);
809
810 pause_ms(1000);
811
812 ASSERT_EQ(UINT, in_leader_mode, 0);
813 ASSERT_EQ(UINT, keyboard_history[1][KC_O], 255);
814END_TEST
815
816TEST("leader_wrong_follow")
817 process_record_user(TOP2, &pressed);
818 process_record_user(TOP3, &pressed);
819 process_record_user(BOT2, &pressed);
820 process_record_user(BOT3, &pressed);
821 pause_ms(1);
822 process_record_user(TOP2, &depressed);
823 process_record_user(TOP3, &depressed);
824 process_record_user(BOT2, &depressed);
825 process_record_user(BOT3, &depressed);
826
827 ASSERT_EQ(UINT, in_leader_mode, 1);
828
829 pause_ms(1);
830 process_record_user(TOP1, &pressed);
831 pause_ms(1);
832 process_record_user(TOP1, &depressed);
833 pause_ms(1);
834 process_record_user(TOP2, &pressed);
835 pause_ms(1);
836 process_record_user(TOP2, &depressed);
837
838 pause_ms(LEADER_TIMEOUT);
839 pause_ms(1);
840
841 ASSERT_EQ(UINT, in_leader_mode, 0);
842 ASSERT_EQ(UINT, keyboard_history[1][KC_Q], 255);
843END_TEST
844
845TEST("leader_correct_follow")
846 process_record_user(TOP2, &pressed);
847 process_record_user(TOP3, &pressed);
848 process_record_user(BOT2, &pressed);
849 process_record_user(BOT3, &pressed);
850 pause_ms(1);
851 process_record_user(TOP2, &depressed);
852 process_record_user(TOP3, &depressed);
853 process_record_user(BOT2, &depressed);
854 process_record_user(BOT3, &depressed);
855
856 ASSERT_EQ(UINT, in_leader_mode, 1);
857
858 pause_ms(1);
859 process_record_user(TOP0, &pressed);
860 pause_ms(1);
861 process_record_user(TOP0, &depressed);
862 pause_ms(1);
863 process_record_user(TOP9, &pressed);
864 pause_ms(1);
865 process_record_user(TOP9, &depressed);
866
867 pause_ms(LEADER_TIMEOUT);
868 ASSERT_EQ(UINT, in_leader_mode, 1);
869
870 pause_ms(1);
871 ASSERT_EQ(UINT, in_leader_mode, 0);
872
873 ASSERT_EQ(UINT, keyboard_history[1][KC_O], 0);
874 ASSERT_EQ(UINT, keyboard_history[1][KC_P], 0);
875 ASSERT_EQ(UINT, keyboard_history[1][KC_A], 0);
876 ASSERT_EQ(UINT, keyboard_history[1][KC_S], 1);
877
878 ASSERT_EQ(UINT, keyboard_history[2][KC_O], 0);
879 ASSERT_EQ(UINT, keyboard_history[2][KC_P], 0);
880 ASSERT_EQ(UINT, keyboard_history[2][KC_A], 0);
881 ASSERT_EQ(UINT, keyboard_history[2][KC_S], 0);
882
883 ASSERT_EQ(UINT, keyboard_history[3][KC_O], 255);
884 ASSERT_EQ(UINT, keyboard_history[3][KC_P], 255);
885 ASSERT_EQ(UINT, keyboard_history[3][KC_A], 255);
886 ASSERT_EQ(UINT, keyboard_history[3][KC_S], 255);
887
888 ASSERT_EQ(UINT, keyboard_history[4][KC_O], 255);
889 ASSERT_EQ(UINT, keyboard_history[4][KC_P], 255);
890 ASSERT_EQ(UINT, keyboard_history[4][KC_A], 255);
891 ASSERT_EQ(UINT, keyboard_history[4][KC_S], 255);
892
893 ASSERT_EQ(UINT, keyboard_history[5][KC_Q], 255);
894END_TEST
895
896// DYNAMIC MACRO
897TEST("dynamic_macro_record_mode")
898 current_pseudolayer = NUM;
899
900 // record
901 ASSERT_EQ(UINT, dynamic_macro_mode, 0);
902 process_record_user(BOT7, &pressed);
903 process_record_user(BOT7, &depressed);
904 ASSERT_EQ(UINT, dynamic_macro_mode, 1);
905 pause_ms(1000);
906 ASSERT_EQ(UINT, dynamic_macro_mode, 1);
907END_TEST
908
909TEST("dynamic_macro_record_mode_off")
910 current_pseudolayer = NUM;
911
912 process_record_user(BOT7, &pressed);
913 process_record_user(BOT7, &depressed);
914 ASSERT_EQ(UINT, dynamic_macro_mode, 1);
915
916 process_record_user(BOT9, &pressed);
917 process_record_user(BOT9, &depressed);
918 ASSERT_EQ(UINT, dynamic_macro_mode, 0);
919END_TEST
920
921TEST("dynamic_macro_record_one")
922 current_pseudolayer = NUM;
923
924 process_record_user(BOT7, &pressed);
925 process_record_user(BOT7, &depressed);
926 ASSERT_EQ(UINT, dynamic_macro_mode, 1);
927
928 process_record_user(TOP1, &pressed);
929 process_record_user(TOP1, &depressed);
930
931 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 255);
932
933 process_record_user(BOT9, &pressed);
934 process_record_user(BOT9, &depressed);
935
936 pause_ms(1000);
937
938 process_record_user(BOT0, &pressed);
939 process_record_user(BOT0, &depressed);
940
941 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
942 ASSERT_EQ(UINT, keyboard_history[2][KC_1], 0);
943 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 255);
944
945 pause_ms(1000);
946
947 process_record_user(BOT0, &pressed);
948 process_record_user(BOT0, &depressed);
949
950 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 1);
951 ASSERT_EQ(UINT, keyboard_history[4][KC_1], 0);
952 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 255);
953END_TEST
954
955TEST("dynamic_macro_record_two")
956 current_pseudolayer = NUM;
957
958 process_record_user(BOT7, &pressed);
959 process_record_user(BOT7, &depressed);
960 ASSERT_EQ(UINT, dynamic_macro_mode, 1);
961
962 process_record_user(TOP1, &pressed);
963 process_record_user(TOP1, &depressed);
964
965 process_record_user(TOP2, &pressed);
966 process_record_user(TOP2, &depressed);
967
968 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 255);
969
970 process_record_user(BOT9, &pressed);
971 process_record_user(BOT9, &depressed);
972
973 pause_ms(1000);
974
975 process_record_user(BOT0, &pressed);
976 process_record_user(BOT0, &depressed);
977
978 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
979 ASSERT_EQ(UINT, keyboard_history[2][KC_2], 1);
980 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 0);
981 ASSERT_EQ(UINT, keyboard_history[4][KC_2], 0);
982 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 255);
983END_TEST
984
985TEST("dynamic_macro_record_two_parts")
986 current_pseudolayer = NUM;
987
988 process_record_user(BOT7, &pressed);
989 process_record_user(BOT7, &depressed);
990 ASSERT_EQ(UINT, dynamic_macro_mode, 1);
991
992 process_record_user(TOP1, &pressed);
993 process_record_user(TOP1, &depressed);
994
995 process_record_user(TOP2, &pressed);
996 process_record_user(TOP2, &depressed);
997
998 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 255);
999
1000 process_record_user(BOT8, &pressed);
1001 process_record_user(BOT8, &depressed);
1002
1003 process_record_user(TOP3, &pressed);
1004 process_record_user(TOP3, &depressed);
1005
1006 process_record_user(BOT9, &pressed);
1007 process_record_user(BOT9, &depressed);
1008
1009 pause_ms(1000);
1010
1011 process_record_user(BOT0, &pressed);
1012 process_record_user(BOT0, &depressed);
1013
1014 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
1015 ASSERT_EQ(UINT, keyboard_history[1][KC_2], 0);
1016 ASSERT_EQ(UINT, keyboard_history[1][KC_3], 0);
1017
1018 ASSERT_EQ(UINT, keyboard_history[2][KC_1], 1);
1019 ASSERT_EQ(UINT, keyboard_history[2][KC_2], 1);
1020 ASSERT_EQ(UINT, keyboard_history[2][KC_3], 0);
1021
1022 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 0);
1023 ASSERT_EQ(UINT, keyboard_history[3][KC_2], 1);
1024 ASSERT_EQ(UINT, keyboard_history[3][KC_3], 0);
1025
1026 ASSERT_EQ(UINT, keyboard_history[4][KC_1], 0);
1027 ASSERT_EQ(UINT, keyboard_history[4][KC_2], 0);
1028 ASSERT_EQ(UINT, keyboard_history[4][KC_3], 0);
1029
1030 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 0);
1031 ASSERT_EQ(UINT, keyboard_history[5][KC_2], 0);
1032 ASSERT_EQ(UINT, keyboard_history[5][KC_3], 1);
1033
1034 ASSERT_EQ(UINT, keyboard_history[6][KC_1], 0);
1035 ASSERT_EQ(UINT, keyboard_history[6][KC_2], 0);
1036 ASSERT_EQ(UINT, keyboard_history[6][KC_3], 0);
1037
1038 ASSERT_EQ(UINT, keyboard_history[7][KC_1], 255);
1039END_TEST
1040
1041// dance + M()
1042
1043TEST("dance_tap")
1044 process_record_user(BOT0, &pressed);
1045 process_record_user(BOT0, &depressed);
1046
1047 pause_ms(1000);
1048
1049 ASSERT_EQ(UINT, keyboard_history[1][KC_9], 1);
1050 ASSERT_EQ(UINT, keyboard_history[1][KC_0], 0);
1051 ASSERT_EQ(UINT, keyboard_history[2][KC_9], 0);
1052 ASSERT_EQ(UINT, keyboard_history[2][KC_0], 0);
1053 ASSERT_EQ(UINT, keyboard_history[3][KC_9], 255);
1054END_TEST
1055
1056TEST("dance_hold")
1057 process_record_user(BOT0, &pressed);
1058 pause_ms(1000);
1059
1060 ASSERT_EQ(UINT, keyboard_history[1][KC_9], 1);
1061
1062 process_record_user(BOT0, &depressed);
1063 ASSERT_EQ(UINT, keyboard_history[2][KC_9], 0);
1064END_TEST
1065
1066TEST("dance_tap_tap")
1067 process_record_user(BOT0, &pressed);
1068 process_record_user(BOT0, &depressed);
1069 process_record_user(BOT0, &pressed);
1070 process_record_user(BOT0, &depressed);
1071
1072 pause_ms(1000);
1073
1074 ASSERT_EQ(UINT, keyboard_history[1][KC_9], 0);
1075 ASSERT_EQ(UINT, keyboard_history[1][KC_0], 1);
1076 ASSERT_EQ(UINT, keyboard_history[2][KC_9], 0);
1077 ASSERT_EQ(UINT, keyboard_history[2][KC_0], 0);
1078 ASSERT_EQ(UINT, keyboard_history[3][KC_9], 255);
1079END_TEST
1080
1081TEST("dance_tap_hold")
1082 process_record_user(BOT0, &pressed);
1083 process_record_user(BOT0, &depressed);
1084 pause_ms(1);
1085 process_record_user(BOT0, &pressed);
1086 pause_ms(1000);
1087
1088 ASSERT_EQ(UINT, keyboard_history[1][KC_0], 1);
1089
1090 process_record_user(BOT0, &depressed);
1091 ASSERT_EQ(UINT, keyboard_history[2][KC_0], 0);
1092END_TEST
1093
1094// MK
1095TEST("multiple_keys")
1096 current_pseudolayer = NUM;
1097
1098 process_record_user(BOT1, &pressed);
1099 process_record_user(BOT1, &depressed);
1100
1101 ASSERT_EQ(UINT, keyboard_history[1][KC_LCTL], 1);
1102 ASSERT_EQ(UINT, keyboard_history[1][KC_LSFT], 0);
1103
1104 ASSERT_EQ(UINT, keyboard_history[2][KC_LCTL], 1);
1105 ASSERT_EQ(UINT, keyboard_history[2][KC_LSFT], 1);
1106
1107 ASSERT_EQ(UINT, keyboard_history[3][KC_LCTL], 0);
1108 ASSERT_EQ(UINT, keyboard_history[3][KC_LSFT], 1);
1109
1110 ASSERT_EQ(UINT, keyboard_history[4][KC_LCTL], 0);
1111 ASSERT_EQ(UINT, keyboard_history[4][KC_LSFT], 0);
1112
1113 ASSERT_EQ(UINT, keyboard_history[5][KC_LCTL], 255);
1114END_TEST
1115
1116TEST("multiple_keys_interleaved")
1117 current_pseudolayer = NUM;
1118
1119 process_record_user(BOT1, &pressed);
1120 pause_ms(CHORD_TIMEOUT+1);
1121
1122 process_record_user(TOP1, &pressed);
1123 process_record_user(TOP1, &depressed);
1124 process_record_user(TOP1, &pressed);
1125 process_record_user(TOP1, &depressed);
1126 process_record_user(TOP1, &pressed);
1127 process_record_user(TOP1, &depressed);
1128
1129 process_record_user(BOT1, &depressed);
1130
1131 ASSERT_EQ(UINT, keyboard_history[1][KC_LCTL], 1);
1132 ASSERT_EQ(UINT, keyboard_history[1][KC_LSFT], 0);
1133
1134 ASSERT_EQ(UINT, keyboard_history[2][KC_LCTL], 1);
1135 ASSERT_EQ(UINT, keyboard_history[2][KC_LSFT], 1);
1136
1137 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 1);
1138 ASSERT_EQ(UINT, keyboard_history[4][KC_1], 0);
1139 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 1);
1140 ASSERT_EQ(UINT, keyboard_history[6][KC_1], 0);
1141 ASSERT_EQ(UINT, keyboard_history[7][KC_1], 1);
1142 ASSERT_EQ(UINT, keyboard_history[8][KC_1], 0);
1143
1144 ASSERT_EQ(UINT, keyboard_history[9][KC_LCTL], 0);
1145 ASSERT_EQ(UINT, keyboard_history[9][KC_LSFT], 1);
1146
1147 ASSERT_EQ(UINT, keyboard_history[10][KC_LCTL], 0);
1148 ASSERT_EQ(UINT, keyboard_history[10][KC_LSFT], 0);
1149
1150 ASSERT_EQ(UINT, keyboard_history[11][KC_LCTL], 255);
1151END_TEST
1152
1153// D
1154TEST("dance_one")
1155 current_pseudolayer = NUM;
1156
1157 process_record_user(BOT3, &pressed);
1158 process_record_user(BOT3, &depressed);
1159
1160 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1161
1162 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
1163 ASSERT_EQ(UINT, keyboard_history[2][KC_1], 0);
1164 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 255);
1165
1166 process_record_user(BOT3, &pressed);
1167 process_record_user(BOT3, &depressed);
1168
1169 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1170
1171 ASSERT_EQ(UINT, keyboard_history[1][KC_1], 1);
1172 ASSERT_EQ(UINT, keyboard_history[2][KC_1], 0);
1173 ASSERT_EQ(UINT, keyboard_history[3][KC_1], 1);
1174 ASSERT_EQ(UINT, keyboard_history[4][KC_1], 0);
1175 ASSERT_EQ(UINT, keyboard_history[5][KC_1], 255);
1176END_TEST
1177
1178TEST("dance_two")
1179 current_pseudolayer = NUM;
1180
1181 process_record_user(BOT3, &pressed);
1182 process_record_user(BOT3, &depressed);
1183 process_record_user(BOT3, &pressed);
1184 process_record_user(BOT3, &depressed);
1185
1186 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1187
1188 ASSERT_EQ(UINT, keyboard_history[1][KC_2], 1);
1189 ASSERT_EQ(UINT, keyboard_history[2][KC_2], 0);
1190 ASSERT_EQ(UINT, keyboard_history[3][KC_2], 255);
1191
1192 process_record_user(BOT3, &pressed);
1193 process_record_user(BOT3, &depressed);
1194 process_record_user(BOT3, &pressed);
1195 process_record_user(BOT3, &depressed);
1196
1197 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1198
1199 ASSERT_EQ(UINT, keyboard_history[1][KC_2], 1);
1200 ASSERT_EQ(UINT, keyboard_history[2][KC_2], 0);
1201 ASSERT_EQ(UINT, keyboard_history[3][KC_2], 1);
1202 ASSERT_EQ(UINT, keyboard_history[4][KC_2], 0);
1203 ASSERT_EQ(UINT, keyboard_history[5][KC_2], 255);
1204END_TEST
1205
1206TEST("dance_three")
1207 current_pseudolayer = NUM;
1208
1209 process_record_user(BOT3, &pressed);
1210 process_record_user(BOT3, &depressed);
1211 process_record_user(BOT3, &pressed);
1212 process_record_user(BOT3, &depressed);
1213 process_record_user(BOT3, &pressed);
1214 process_record_user(BOT3, &depressed);
1215
1216 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1217
1218 ASSERT_EQ(UINT, keyboard_history[1][KC_3], 1);
1219 ASSERT_EQ(UINT, keyboard_history[2][KC_3], 0);
1220 ASSERT_EQ(UINT, keyboard_history[3][KC_3], 255);
1221
1222 process_record_user(BOT3, &pressed);
1223 process_record_user(BOT3, &depressed);
1224 process_record_user(BOT3, &pressed);
1225 process_record_user(BOT3, &depressed);
1226 process_record_user(BOT3, &pressed);
1227 process_record_user(BOT3, &depressed);
1228
1229 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1230
1231 ASSERT_EQ(UINT, keyboard_history[1][KC_3], 1);
1232 ASSERT_EQ(UINT, keyboard_history[2][KC_3], 0);
1233 ASSERT_EQ(UINT, keyboard_history[3][KC_3], 1);
1234 ASSERT_EQ(UINT, keyboard_history[4][KC_3], 0);
1235 ASSERT_EQ(UINT, keyboard_history[5][KC_3], 255);
1236END_TEST
1237
1238TEST("dance_two_held")
1239 current_pseudolayer = NUM;
1240
1241 process_record_user(BOT3, &pressed);
1242 process_record_user(BOT3, &depressed);
1243 process_record_user(BOT3, &pressed);
1244
1245 pause_ms(CHORD_TIMEOUT+DANCE_TIMEOUT+2);
1246
1247 ASSERT_EQ(UINT, keyboard_history[1][KC_2], 1);
1248 ASSERT_EQ(UINT, keyboard_history[2][KC_2], 255);
1249
1250 process_record_user(BOT3, &depressed);
1251 ASSERT_EQ(UINT, keyboard_history[2][KC_2], 0);
1252 ASSERT_EQ(UINT, keyboard_history[3][KC_2], 255);
1253END_TEST
1254
1255// These two are leaving the chording engine, they kinda have to be tested manually
1256// TO
1257// RESET
1258
1259END
diff --git a/users/dennytom/chording_engine/tests/test_full.sh b/users/dennytom/chording_engine/tests/test_full.sh
new file mode 100644
index 000000000..ea93aec8f
--- /dev/null
+++ b/users/dennytom/chording_engine/tests/test_full.sh
@@ -0,0 +1,11 @@
1#!/bin/sh
2cd ..
3python3 parser.py tests/test_keymap_def.json tests/test_keymap.c && \
4gcc -g tests/test.c -o tests/test && \
5tests/test && \
6python3 parser.py ../../../keyboards/butterstick/keymaps/tomas/keymap_def.json ../../../keyboards/butterstick/keymaps/tomas/keymap.c && \
7python3 parser.py ../../../keyboards/georgi/keymaps/tomas/keymap_def.json ../../../keyboards/georgi/keymaps/tomas/keymap.c && \
8python3 parser.py ../../../keyboards/georgi/keymaps/buttery/keymap_def.json ../../../keyboards/georgi/keymaps/buttery/keymap.c && \
9cd ../../../ && \
10make butterstick && \
11make georgi \ No newline at end of file
diff --git a/users/dennytom/chording_engine/tests/test_keymap_def.json b/users/dennytom/chording_engine/tests/test_keymap_def.json
new file mode 100644
index 000000000..eae2ed37c
--- /dev/null
+++ b/users/dennytom/chording_engine/tests/test_keymap_def.json
@@ -0,0 +1,145 @@
1{
2 "keys": [
3 "TOP1", "TOP2", "TOP3", "TOP4", "TOP5", "TOP6", "TOP7", "TOP8", "TOP9", "TOP0",
4 "BOT1", "BOT2", "BOT3", "BOT4", "BOT5", "BOT6", "BOT7", "BOT8", "BOT9", "BOT0"
5 ],
6 "parameters": {
7 "do_not_include_QMK": true,
8 "layout_function_name": "LAYOUT_test",
9 "chord_timeout": 100,
10 "dance_timeout": 200,
11 "leader_timeout": 750,
12 "tap_timeout": 50,
13 "command_max_length": 5,
14 "leader_max_length": 5,
15 "dynamic_macro_max_length": 20,
16 "string_max_length": 16,
17 "long_press_multiplier": 3,
18 "default_pseudolayer": "QWERTY"
19 },
20 "layers": [
21 {
22 "type": "auto"
23 },
24 {
25 "type": "manual",
26 "keycodes": ["KC_1", "KC_2", "KC_3", "KC_4", "KC_5", "KC_6", "KC_7", "KC_8", "KC_9", "KC_0",
27 "KC_Q", "KC_W", "KC_E", "KC_R", "KC_T", "KC_Y", "KC_U", "KC_I", "KC_O", "KC_P"
28 ]
29 }
30 ],
31 "chord_sets": [
32 {
33 "name": "rows",
34 "chords": [
35 ["TOP1"], ["TOP2"], ["TOP3"], ["TOP4"], ["TOP5"], ["TOP6"], ["TOP7"], ["TOP8"], ["TOP9"], ["TOP0"],
36 ["TOP1", "BOT1"], ["TOP2", "BOT2"], ["TOP3", "BOT3"], ["TOP4", "BOT4"], ["TOP5", "BOT5"], ["TOP6", "BOT6"], ["TOP7", "BOT7"], ["TOP8", "BOT8"], ["TOP9", "BOT9"], ["TOP0", "BOT0"],
37 ["BOT1"], ["BOT2"], ["BOT3"], ["BOT4"], ["BOT5"], ["BOT6"], ["BOT7"], ["BOT8"], ["BOT9"], ["BOT0"]
38 ]
39 },
40 {
41 "name": "cols",
42 "chords": [
43 ["TOP1", "TOP2"], ["TOP2", "TOP3"], ["TOP3", "TOP4"], ["TOP4", "TOP5"], ["TOP5", "TOP6"], ["TOP6", "TOP7"], ["TOP7", "TOP8"], ["TOP8", "TOP9"], ["TOP9", "TOP0"],
44 ["TOP1", "TOP2", "BOT1", "BOT2"], ["TOP2", "TOP3", "BOT2", "BOT3"], ["TOP3", "TOP4", "BOT3", "BOT4"], ["TOP4", "TOP5", "BOT4", "BOT5"], ["TOP5", "TOP6", "BOT5", "BOT6"], ["TOP6", "TOP7", "BOT6", "BOT7"], ["TOP7", "TOP8", "BOT7", "BOT8"], ["TOP8", "TOP9", "BOT8", "BOT9"], ["TOP9", "TOP0", "BOT9", "BOT0"],
45 ["BOT1", "BOT2"], ["BOT2", "BOT3"], ["BOT3", "BOT4"], ["BOT4", "BOT5"], ["BOT5", "BOT6"], ["BOT6", "BOT7"], ["BOT7", "BOT8"], ["BOT8", "BOT9"], ["BOT9", "BOT0"]
46 ]
47 },
48 {
49 "name": "asetniop",
50 "chords": [
51 ["TOP1"], ["TOP2"], ["TOP3"], ["TOP4"], ["TOP7"], ["TOP8"], ["TOP9"], ["TOP0"],
52 ["TOP1", "TOP2"], ["TOP2", "TOP3"], ["TOP3", "TOP4"], ["TOP4", "TOP7"], ["TOP7", "TOP8"], ["TOP8", "TOP9"], ["TOP9", "TOP0"],
53 ["TOP1", "TOP3"], ["TOP2", "TOP4"], ["TOP3", "TOP7"], ["TOP4", "TOP8"], ["TOP7", "TOP9"], ["TOP8", "TOP0"],
54 ["TOP1", "TOP4"], ["TOP2", "TOP7"], ["TOP3", "TOP8"], ["TOP4", "TOP9"], ["TOP7", "TOP0"],
55 ["TOP1", "TOP7"], ["TOP2", "TOP8"], ["TOP3", "TOP9"], ["TOP4", "TOP0"],
56 ["TOP1", "TOP8"], ["TOP2", "TOP9"], ["TOP3", "TOP0"],
57 ["TOP1", "TOP9"], ["TOP2", "TOP0"],
58 ["TOP1", "TOP0"]
59 ]
60 }
61 ],
62 "pseudolayers": [
63 {
64 "name": "ALWAYS_ON",
65 "chords": [
66 {
67 "type": "visual",
68 "chord": [
69 " ", " ", " ", " ", " ", " ", " ", "X", "X", "X",
70 " ", " ", " ", " ", " ", " ", " ", "X", "X", "X"
71 ],
72 "keycode": "MO(FNC, NUM)"
73 }
74 ]
75 },
76 {
77 "name": "QWERTY",
78 "chords": [
79 {
80 "type": "chord_set",
81 "set": "rows",
82 "keycodes": [
83 "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
84 "A", "S", "D", "F", "G", "H", "J", "K", "L", ";",
85 "AS(Z)", "KK(X, LCTL)", "KL(C, NUM)", "KM(V, LALT)", "B", "N", "M", "COMMA", ".", "M(double_dance, KC_9, KC_0)"
86 ]
87 },
88 {
89 "type": "chord_set",
90 "set": "cols",
91 "keycodes": [
92 "ESC", "", "", "", "", "", "", "", "",
93 "", "LEAD", "", "", "CMD", "", "", "", "",
94 "LSFT", "O(LSFT)", "", "", "", "O(NUM)", "MO(NUM)", "", "DF(NUM)"
95 ]
96 },
97 {
98 "type": "visual",
99 "chord": [
100 "X", "X", " ", " ", " ", " ", " ", " ", " ", " ",
101 "X", "X", " ", " ", " ", " ", " ", " ", " ", " "
102 ],
103 "keycode": "LOCK"
104 }
105 ]
106 },
107 {
108 "name": "NUM",
109 "chords": [
110 {
111 "type": "chord_set",
112 "set": "rows",
113 "keycodes": [
114 "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
115 "", "", "", "", "", "", "", "", "", "",
116 "", "KC_LEFT", "D(KC_1, KC_2, KC_3)", "", "", "", "DM_RECORD", "DM_NEXT", "DM_END", "DM_PLAY"
117 ]
118 },
119 {
120 "type": "simple",
121 "chord": ["BOT1"],
122 "keycode": "MK(KC_LCTL, KC_LSFT)"
123 }
124 ]
125 },
126 {
127 "name": "FNC",
128 "chords": []
129 }
130 ],
131 "leader_sequences": [
132 {
133 "name": "fnc_L1",
134 "function": "void fnc_L1(void) { key_in(KC_A); clear_keyboard(); }",
135 "sequence": ["KC_O", "KC_P"]
136 },
137 {
138 "name": "fnc_L2",
139 "function": "void fnc_L2(void) { key_in(KC_S); clear_keyboard(); }",
140 "sequence": ["KC_P", "KC_O"]
141 }
142 ],
143 "extra_code": "void double_dance(const struct Chord* self) {\n switch (*self->state) {\n case ACTIVATED:\n *self->counter = (*self->counter + 1) % 2;\n break;\n case PRESS_FROM_ACTIVE:\n if (*self->counter == 1) {\n key_in(self->value1);\n } else {\n key_in(self->value2);\n }\n *self->state = FINISHED_FROM_ACTIVE;\n break;\n case FINISHED:\n if (*self->counter == 1) {\n tap_key(self->value1);\n } else {\n tap_key(self->value2);\n }\n *self->counter = 0;\n *self->state = IDLE;\n break;\n case RESTART:\n if (*self->counter == 1) {\n key_out(self->value1);\n } else {\n key_out(self->value2);\n }\n *self->counter = 0;\n break;\n default:\n break;\n }\n}\n",
144 "extra_dependencies": []
145} \ No newline at end of file
diff --git a/users/dennytom/chording_engine/tests/test_quick.sh b/users/dennytom/chording_engine/tests/test_quick.sh
new file mode 100644
index 000000000..3740122e2
--- /dev/null
+++ b/users/dennytom/chording_engine/tests/test_quick.sh
@@ -0,0 +1,6 @@
1#!/bin/sh
2
3cd ..
4python3 parser.py tests/test_keymap_def.json tests/test_keymap.c && \
5gcc -g tests/test.c -o tests/test && \
6tests/test \ No newline at end of file