aboutsummaryrefslogtreecommitdiff
path: root/users/dennytom/chording_engine/engine.part.3
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 /users/dennytom/chording_engine/engine.part.3
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
Diffstat (limited to 'users/dennytom/chording_engine/engine.part.3')
-rw-r--r--users/dennytom/chording_engine/engine.part.3404
1 files changed, 404 insertions, 0 deletions
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