aboutsummaryrefslogtreecommitdiff
path: root/quantum/process_keycode/process_combo.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/process_keycode/process_combo.c')
-rw-r--r--quantum/process_keycode/process_combo.c184
1 files changed, 95 insertions, 89 deletions
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
index e8661839c..a050161ed 100644
--- a/quantum/process_keycode/process_combo.c
+++ b/quantum/process_keycode/process_combo.c
@@ -18,10 +18,9 @@
18#include "process_combo.h" 18#include "process_combo.h"
19#include "action_tapping.h" 19#include "action_tapping.h"
20 20
21
22#ifdef COMBO_COUNT 21#ifdef COMBO_COUNT
23__attribute__((weak)) combo_t key_combos[COMBO_COUNT]; 22__attribute__((weak)) combo_t key_combos[COMBO_COUNT];
24uint16_t COMBO_LEN = COMBO_COUNT; 23uint16_t COMBO_LEN = COMBO_COUNT;
25#else 24#else
26extern combo_t key_combos[]; 25extern combo_t key_combos[];
27extern uint16_t COMBO_LEN; 26extern uint16_t COMBO_LEN;
@@ -46,64 +45,86 @@ __attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo
46#endif 45#endif
47 46
48#ifndef COMBO_NO_TIMER 47#ifndef COMBO_NO_TIMER
49static uint16_t timer = 0; 48static uint16_t timer = 0;
50#endif 49#endif
51static bool b_combo_enable = true; // defaults to enabled 50static bool b_combo_enable = true; // defaults to enabled
52static uint16_t longest_term = 0; 51static uint16_t longest_term = 0;
53 52
54typedef struct { 53typedef struct {
55 keyrecord_t record; 54 keyrecord_t record;
56 uint16_t combo_index; 55 uint16_t combo_index;
57 uint16_t keycode; 56 uint16_t keycode;
58} queued_record_t; 57} queued_record_t;
59static uint8_t key_buffer_size = 0; 58static uint8_t key_buffer_size = 0;
60static queued_record_t key_buffer[COMBO_KEY_BUFFER_LENGTH]; 59static queued_record_t key_buffer[COMBO_KEY_BUFFER_LENGTH];
61 60
62typedef struct { 61typedef struct {
63 uint16_t combo_index; 62 uint16_t combo_index;
64} queued_combo_t; 63} queued_combo_t;
65static uint8_t combo_buffer_write= 0; 64static uint8_t combo_buffer_write = 0;
66static uint8_t combo_buffer_read = 0; 65static uint8_t combo_buffer_read = 0;
67static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH]; 66static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH];
68 67
69#define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH 68#define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH
70 69
71#define COMBO_KEY_POS ((keypos_t){.col=254, .row=254}) 70#define COMBO_KEY_POS ((keypos_t){.col = 254, .row = 254})
72
73 71
74#ifndef EXTRA_SHORT_COMBOS 72#ifndef EXTRA_SHORT_COMBOS
75/* flags are their own elements in combo_t struct. */ 73/* flags are their own elements in combo_t struct. */
76# define COMBO_ACTIVE(combo) (combo->active) 74# define COMBO_ACTIVE(combo) (combo->active)
77# define COMBO_DISABLED(combo) (combo->disabled) 75# define COMBO_DISABLED(combo) (combo->disabled)
78# define COMBO_STATE(combo) (combo->state) 76# define COMBO_STATE(combo) (combo->state)
79 77
80# define ACTIVATE_COMBO(combo) do {combo->active = true;}while(0) 78# define ACTIVATE_COMBO(combo) \
81# define DEACTIVATE_COMBO(combo) do {combo->active = false;}while(0) 79 do { \
82# define DISABLE_COMBO(combo) do {combo->disabled = true;}while(0) 80 combo->active = true; \
83# define RESET_COMBO_STATE(combo) do { \ 81 } while (0)
84 combo->disabled = false; \ 82# define DEACTIVATE_COMBO(combo) \
85 combo->state = 0; \ 83 do { \
86}while(0) 84 combo->active = false; \
85 } while (0)
86# define DISABLE_COMBO(combo) \
87 do { \
88 combo->disabled = true; \
89 } while (0)
90# define RESET_COMBO_STATE(combo) \
91 do { \
92 combo->disabled = false; \
93 combo->state = 0; \
94 } while (0)
87#else 95#else
88/* flags are at the two high bits of state. */ 96/* flags are at the two high bits of state. */
89# define COMBO_ACTIVE(combo) (combo->state & 0x80) 97# define COMBO_ACTIVE(combo) (combo->state & 0x80)
90# define COMBO_DISABLED(combo) (combo->state & 0x40) 98# define COMBO_DISABLED(combo) (combo->state & 0x40)
91# define COMBO_STATE(combo) (combo->state & 0x3F) 99# define COMBO_STATE(combo) (combo->state & 0x3F)
92 100
93# define ACTIVATE_COMBO(combo) do {combo->state |= 0x80;}while(0) 101# define ACTIVATE_COMBO(combo) \
94# define DEACTIVATE_COMBO(combo) do {combo->state &= ~0x80;}while(0) 102 do { \
95# define DISABLE_COMBO(combo) do {combo->state |= 0x40;}while(0) 103 combo->state |= 0x80; \
96# define RESET_COMBO_STATE(combo) do {combo->state &= ~0x7F;}while(0) 104 } while (0)
105# define DEACTIVATE_COMBO(combo) \
106 do { \
107 combo->state &= ~0x80; \
108 } while (0)
109# define DISABLE_COMBO(combo) \
110 do { \
111 combo->state |= 0x40; \
112 } while (0)
113# define RESET_COMBO_STATE(combo) \
114 do { \
115 combo->state &= ~0x7F; \
116 } while (0)
97#endif 117#endif
98 118
99static inline void release_combo(uint16_t combo_index, combo_t *combo) { 119static inline void release_combo(uint16_t combo_index, combo_t *combo) {
100 if (combo->keycode) { 120 if (combo->keycode) {
101 keyrecord_t record = { 121 keyrecord_t record = {
102 .event = { 122 .event =
103 .key = COMBO_KEY_POS, 123 {
104 .time = timer_read()|1, 124 .key = COMBO_KEY_POS,
105 .pressed = false, 125 .time = timer_read() | 1,
106 }, 126 .pressed = false,
127 },
107 .keycode = combo->keycode, 128 .keycode = combo->keycode,
108 }; 129 };
109#ifndef NO_ACTION_TAPPING 130#ifndef NO_ACTION_TAPPING
@@ -123,18 +144,17 @@ static inline bool _get_combo_must_hold(uint16_t combo_index, combo_t *combo) {
123#elif defined(COMBO_MUST_HOLD_PER_COMBO) 144#elif defined(COMBO_MUST_HOLD_PER_COMBO)
124 return get_combo_must_hold(combo_index, combo); 145 return get_combo_must_hold(combo_index, combo);
125#elif defined(COMBO_MUST_HOLD_MODS) 146#elif defined(COMBO_MUST_HOLD_MODS)
126 return (KEYCODE_IS_MOD(combo->keycode) || 147 return (KEYCODE_IS_MOD(combo->keycode) || (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX));
127 (combo->keycode >= QK_MOMENTARY && combo->keycode <= QK_MOMENTARY_MAX));
128#endif 148#endif
129 return false; 149 return false;
130} 150}
131 151
132static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo ) { 152static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo) {
133 if (_get_combo_must_hold(combo_index, combo) 153 if (_get_combo_must_hold(combo_index, combo)
134#ifdef COMBO_MUST_TAP_PER_COMBO 154#ifdef COMBO_MUST_TAP_PER_COMBO
135 || get_combo_must_tap(combo_index, combo) 155 || get_combo_must_tap(combo_index, combo)
136#endif 156#endif
137 ) { 157 ) {
138 if (longest_term < COMBO_HOLD_TERM) { 158 if (longest_term < COMBO_HOLD_TERM) {
139 return COMBO_HOLD_TERM; 159 return COMBO_HOLD_TERM;
140 } 160 }
@@ -144,9 +164,8 @@ static inline uint16_t _get_wait_time(uint16_t combo_index, combo_t *combo ) {
144} 164}
145 165
146static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) { 166static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) {
147
148#if defined(COMBO_TERM_PER_COMBO) 167#if defined(COMBO_TERM_PER_COMBO)
149 return get_combo_term(combo_index, combo); 168 return get_combo_term(combo_index, combo);
150#endif 169#endif
151 170
152 return COMBO_TERM; 171 return COMBO_TERM;
@@ -154,7 +173,7 @@ static inline uint16_t _get_combo_term(uint16_t combo_index, combo_t *combo) {
154 173
155void clear_combos(void) { 174void clear_combos(void) {
156 uint16_t index = 0; 175 uint16_t index = 0;
157 longest_term = 0; 176 longest_term = 0;
158 for (index = 0; index < COMBO_LEN; ++index) { 177 for (index = 0; index < COMBO_LEN; ++index) {
159 combo_t *combo = &key_combos[index]; 178 combo_t *combo = &key_combos[index];
160 if (!COMBO_ACTIVE(combo)) { 179 if (!COMBO_ACTIVE(combo)) {
@@ -175,7 +194,7 @@ static inline void dump_key_buffer(void) {
175 key_buffer_next = key_buffer_i + 1; 194 key_buffer_next = key_buffer_i + 1;
176 195
177 queued_record_t *qrecord = &key_buffer[key_buffer_i]; 196 queued_record_t *qrecord = &key_buffer[key_buffer_i];
178 keyrecord_t *record = &qrecord->record; 197 keyrecord_t * record = &qrecord->record;
179 198
180 if (IS_NOEVENT(record->event)) { 199 if (IS_NOEVENT(record->event)) {
181 continue; 200 continue;
@@ -185,9 +204,9 @@ static inline void dump_key_buffer(void) {
185 process_combo_event(qrecord->combo_index, true); 204 process_combo_event(qrecord->combo_index, true);
186 } else { 205 } else {
187#ifndef NO_ACTION_TAPPING 206#ifndef NO_ACTION_TAPPING
188 action_tapping_process(*record); 207 action_tapping_process(*record);
189#else 208#else
190 process_record(record); 209 process_record(record);
191#endif 210#endif
192 } 211 }
193 record->event.time = 0; 212 record->event.time = 0;
@@ -242,7 +261,9 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
242 /* Apply combo's result keycode to the last chord key of the combo and 261 /* Apply combo's result keycode to the last chord key of the combo and
243 * disable the other keys. */ 262 * disable the other keys. */
244 263
245 if (COMBO_DISABLED(combo)) { return; } 264 if (COMBO_DISABLED(combo)) {
265 return;
266 }
246 267
247 // state to check against so we find the last key of the combo from the buffer 268 // state to check against so we find the last key of the combo from the buffer
248#if defined(EXTRA_EXTRA_LONG_COMBOS) 269#if defined(EXTRA_EXTRA_LONG_COMBOS)
@@ -254,12 +275,11 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
254#endif 275#endif
255 276
256 for (uint8_t key_buffer_i = 0; key_buffer_i < key_buffer_size; key_buffer_i++) { 277 for (uint8_t key_buffer_i = 0; key_buffer_i < key_buffer_size; key_buffer_i++) {
257
258 queued_record_t *qrecord = &key_buffer[key_buffer_i]; 278 queued_record_t *qrecord = &key_buffer[key_buffer_i];
259 keyrecord_t *record = &qrecord->record; 279 keyrecord_t * record = &qrecord->record;
260 uint16_t keycode = qrecord->keycode; 280 uint16_t keycode = qrecord->keycode;
261 281
262 uint8_t key_count = 0; 282 uint8_t key_count = 0;
263 uint16_t key_index = -1; 283 uint16_t key_index = -1;
264 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count); 284 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);
265 285
@@ -271,7 +291,7 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
271 KEY_STATE_DOWN(state, key_index); 291 KEY_STATE_DOWN(state, key_index);
272 if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) { 292 if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) {
273 // this in the end executes the combo when the key_buffer is dumped. 293 // this in the end executes the combo when the key_buffer is dumped.
274 record->keycode = combo->keycode; 294 record->keycode = combo->keycode;
275 record->event.key = COMBO_KEY_POS; 295 record->event.key = COMBO_KEY_POS;
276 296
277 qrecord->combo_index = combo_index; 297 qrecord->combo_index = combo_index;
@@ -283,19 +303,15 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
283 // by making it a TICK event. 303 // by making it a TICK event.
284 record->event.time = 0; 304 record->event.time = 0;
285 } 305 }
286
287 } 306 }
288 drop_combo_from_buffer(combo_index); 307 drop_combo_from_buffer(combo_index);
289} 308}
290 309
291static inline void apply_combos(void) { 310static inline void apply_combos(void) {
292 // Apply all buffered normal combos. 311 // Apply all buffered normal combos.
293 for (uint8_t i = combo_buffer_read; 312 for (uint8_t i = combo_buffer_read; i != combo_buffer_write; INCREMENT_MOD(i)) {
294 i != combo_buffer_write;
295 INCREMENT_MOD(i)) {
296
297 queued_combo_t *buffered_combo = &combo_buffer[i]; 313 queued_combo_t *buffered_combo = &combo_buffer[i];
298 combo_t *combo = &key_combos[buffered_combo->combo_index]; 314 combo_t * combo = &key_combos[buffered_combo->combo_index];
299 315
300#ifdef COMBO_MUST_TAP_PER_COMBO 316#ifdef COMBO_MUST_TAP_PER_COMBO
301 if (get_combo_must_tap(buffered_combo->combo_index, combo)) { 317 if (get_combo_must_tap(buffered_combo->combo_index, combo)) {
@@ -310,15 +326,15 @@ static inline void apply_combos(void) {
310 clear_combos(); 326 clear_combos();
311} 327}
312 328
313combo_t* overlaps(combo_t *combo1, combo_t *combo2) { 329combo_t *overlaps(combo_t *combo1, combo_t *combo2) {
314 /* Checks if the combos overlap and returns the combo that should be 330 /* Checks if the combos overlap and returns the combo that should be
315 * dropped from the combo buffer. 331 * dropped from the combo buffer.
316 * The combo that has less keys will be dropped. If they have the same 332 * The combo that has less keys will be dropped. If they have the same
317 * amount of keys, drop combo1. */ 333 * amount of keys, drop combo1. */
318 334
319 uint8_t idx1 = 0, idx2 = 0; 335 uint8_t idx1 = 0, idx2 = 0;
320 uint16_t key1, key2; 336 uint16_t key1, key2;
321 bool overlaps = false; 337 bool overlaps = false;
322 338
323 while ((key1 = pgm_read_word(&combo1->keys[idx1])) != COMBO_END) { 339 while ((key1 = pgm_read_word(&combo1->keys[idx1])) != COMBO_END) {
324 idx2 = 0; 340 idx2 = 0;
@@ -335,7 +351,7 @@ combo_t* overlaps(combo_t *combo1, combo_t *combo2) {
335} 351}
336 352
337static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) { 353static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) {
338 uint8_t key_count = 0; 354 uint8_t key_count = 0;
339 uint16_t key_index = -1; 355 uint16_t key_index = -1;
340 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count); 356 _find_key_index_and_count(combo->keys, keycode, &key_index, &key_count);
341 357
@@ -369,12 +385,9 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
369 385
370 // disable readied combos that overlap with this combo 386 // disable readied combos that overlap with this combo
371 combo_t *drop = NULL; 387 combo_t *drop = NULL;
372 for (uint8_t combo_buffer_i = combo_buffer_read; 388 for (uint8_t combo_buffer_i = combo_buffer_read; combo_buffer_i != combo_buffer_write; INCREMENT_MOD(combo_buffer_i)) {
373 combo_buffer_i != combo_buffer_write; 389 queued_combo_t *qcombo = &combo_buffer[combo_buffer_i];
374 INCREMENT_MOD(combo_buffer_i)) { 390 combo_t * buffered_combo = &key_combos[qcombo->combo_index];
375
376 queued_combo_t *qcombo = &combo_buffer[combo_buffer_i];
377 combo_t *buffered_combo = &key_combos[qcombo->combo_index];
378 391
379 if ((drop = overlaps(buffered_combo, combo))) { 392 if ((drop = overlaps(buffered_combo, combo))) {
380 DISABLE_COMBO(drop); 393 DISABLE_COMBO(drop);
@@ -387,21 +400,19 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
387 INCREMENT_MOD(combo_buffer_read); 400 INCREMENT_MOD(combo_buffer_read);
388 } 401 }
389 } 402 }
390
391 } 403 }
392 404
393 if (drop != combo) { 405 if (drop != combo) {
394 // save this combo to buffer 406 // save this combo to buffer
395 combo_buffer[combo_buffer_write] = (queued_combo_t){ 407 combo_buffer[combo_buffer_write] = (queued_combo_t){
396 .combo_index=combo_index, 408 .combo_index = combo_index,
397 }; 409 };
398 INCREMENT_MOD(combo_buffer_write); 410 INCREMENT_MOD(combo_buffer_write);
399 411
400 // get possible longer waiting time for tap-/hold-only combos. 412 // get possible longer waiting time for tap-/hold-only combos.
401 longest_term = _get_wait_time(combo_index, combo); 413 longest_term = _get_wait_time(combo_index, combo);
402 } 414 }
403 } // if timer elapsed end 415 } // if timer elapsed end
404
405 } 416 }
406 } else { 417 } else {
407 // chord releases 418 // chord releases
@@ -416,7 +427,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
416 else if (get_combo_must_tap(combo_index, combo)) { 427 else if (get_combo_must_tap(combo_index, combo)) {
417 // immediately apply tap-only combo 428 // immediately apply tap-only combo
418 apply_combo(combo_index, combo); 429 apply_combo(combo_index, combo);
419 apply_combos(); // also apply other prepared combos and dump key buffer 430 apply_combos(); // also apply other prepared combos and dump key buffer
420# ifdef COMBO_PROCESS_KEY_RELEASE 431# ifdef COMBO_PROCESS_KEY_RELEASE
421 if (process_combo_key_release(combo_index, combo, key_index, keycode)) { 432 if (process_combo_key_release(combo_index, combo, key_index, keycode)) {
422 release_combo(combo_index, combo); 433 release_combo(combo_index, combo);
@@ -424,10 +435,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
424# endif 435# endif
425 } 436 }
426#endif 437#endif
427 } else if (COMBO_ACTIVE(combo) 438 } else if (COMBO_ACTIVE(combo) && ONLY_ONE_KEY_IS_DOWN(COMBO_STATE(combo)) && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)) {
428 && ONLY_ONE_KEY_IS_DOWN(COMBO_STATE(combo))
429 && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)
430 ) {
431 /* last key released */ 439 /* last key released */
432 release_combo(combo_index, combo); 440 release_combo(combo_index, combo);
433 key_is_part_of_combo = true; 441 key_is_part_of_combo = true;
@@ -435,9 +443,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
435#ifdef COMBO_PROCESS_KEY_RELEASE 443#ifdef COMBO_PROCESS_KEY_RELEASE
436 process_combo_key_release(combo_index, combo, key_index, keycode); 444 process_combo_key_release(combo_index, combo, key_index, keycode);
437#endif 445#endif
438 } else if (COMBO_ACTIVE(combo) 446 } else if (COMBO_ACTIVE(combo) && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)) {
439 && KEY_NOT_YET_RELEASED(COMBO_STATE(combo), key_index)
440 ) {
441 /* first or middle key released */ 447 /* first or middle key released */
442 key_is_part_of_combo = true; 448 key_is_part_of_combo = true;
443 449
@@ -489,21 +495,21 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {
489 495
490 if (record->event.pressed && is_combo_key) { 496 if (record->event.pressed && is_combo_key) {
491#ifndef COMBO_NO_TIMER 497#ifndef COMBO_NO_TIMER
492# ifdef COMBO_STRICT_TIMER 498# ifdef COMBO_STRICT_TIMER
493 if (!timer) { 499 if (!timer) {
494 // timer is set only on the first key 500 // timer is set only on the first key
495 timer = timer_read(); 501 timer = timer_read();
496 } 502 }
497# else 503# else
498 timer = timer_read(); 504 timer = timer_read();
499# endif 505# endif
500#endif 506#endif
501 507
502 if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) { 508 if (key_buffer_size < COMBO_KEY_BUFFER_LENGTH) {
503 key_buffer[key_buffer_size++] = (queued_record_t){ 509 key_buffer[key_buffer_size++] = (queued_record_t){
504 .record = *record, 510 .record = *record,
505 .keycode = keycode, 511 .keycode = keycode,
506 .combo_index = -1, // this will be set when applying combos 512 .combo_index = -1, // this will be set when applying combos
507 }; 513 };
508 } 514 }
509 } else { 515 } else {
@@ -532,7 +538,7 @@ void combo_task(void) {
532 if (combo_buffer_read != combo_buffer_write) { 538 if (combo_buffer_read != combo_buffer_write) {
533 apply_combos(); 539 apply_combos();
534 longest_term = 0; 540 longest_term = 0;
535 timer = 0; 541 timer = 0;
536 } else { 542 } else {
537 dump_key_buffer(); 543 dump_key_buffer();
538 timer = 0; 544 timer = 0;
@@ -546,9 +552,9 @@ void combo_enable(void) { b_combo_enable = true; }
546 552
547void combo_disable(void) { 553void combo_disable(void) {
548#ifndef COMBO_NO_TIMER 554#ifndef COMBO_NO_TIMER
549 timer = 0; 555 timer = 0;
550#endif 556#endif
551 b_combo_enable = false; 557 b_combo_enable = false;
552 combo_buffer_read = combo_buffer_write; 558 combo_buffer_read = combo_buffer_write;
553 clear_combos(); 559 clear_combos();
554 dump_key_buffer(); 560 dump_key_buffer();