summaryrefslogtreecommitdiff
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.c88
1 files changed, 77 insertions, 11 deletions
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
index a050161edf..efaf8fe0e9 100644
--- a/quantum/process_keycode/process_combo.c
+++ b/quantum/process_keycode/process_combo.c
@@ -17,6 +17,7 @@
#include "print.h"
#include "process_combo.h"
#include "action_tapping.h"
+#include "action.h"
#ifdef COMBO_COUNT
__attribute__((weak)) combo_t key_combos[COMBO_COUNT];
@@ -29,25 +30,45 @@ extern uint16_t COMBO_LEN;
__attribute__((weak)) void process_combo_event(uint16_t combo_index, bool pressed) {}
#ifdef COMBO_MUST_HOLD_PER_COMBO
-__attribute__((weak)) bool get_combo_must_hold(uint16_t index, combo_t *combo) { return false; }
+__attribute__((weak)) bool get_combo_must_hold(uint16_t index, combo_t *combo) {
+ return false;
+}
#endif
#ifdef COMBO_MUST_TAP_PER_COMBO
-__attribute__((weak)) bool get_combo_must_tap(uint16_t index, combo_t *combo) { return false; }
+__attribute__((weak)) bool get_combo_must_tap(uint16_t index, combo_t *combo) {
+ return false;
+}
#endif
#ifdef COMBO_TERM_PER_COMBO
-__attribute__((weak)) uint16_t get_combo_term(uint16_t index, combo_t *combo) { return COMBO_TERM; }
+__attribute__((weak)) uint16_t get_combo_term(uint16_t index, combo_t *combo) {
+ return COMBO_TERM;
+}
+#endif
+
+#ifdef COMBO_MUST_PRESS_IN_ORDER_PER_COMBO
+__attribute__((weak)) bool get_combo_must_press_in_order(uint16_t combo_index, combo_t *combo) {
+ return true;
+}
#endif
#ifdef COMBO_PROCESS_KEY_RELEASE
-__attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) { return false; }
+__attribute__((weak)) bool process_combo_key_release(uint16_t combo_index, combo_t *combo, uint8_t key_index, uint16_t keycode) {
+ return false;
+}
+#endif
+
+#ifdef COMBO_SHOULD_TRIGGER
+__attribute__((weak)) bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) {
+ return true;
+}
#endif
#ifndef COMBO_NO_TIMER
static uint16_t timer = 0;
#endif
-static bool b_combo_enable = true; // defaults to enabled
+static bool b_combo_enable = true; // defaults to enabled
static uint16_t longest_term = 0;
typedef struct {
@@ -185,6 +206,9 @@ void clear_combos(void) {
static inline void dump_key_buffer(void) {
/* First call start from 0 index; recursive calls need to start from i+1 index */
static uint8_t key_buffer_next = 0;
+#if TAP_CODE_DELAY > 0
+ bool delay_done = false;
+#endif
if (key_buffer_size == 0) {
return;
@@ -210,6 +234,15 @@ static inline void dump_key_buffer(void) {
#endif
}
record->event.time = 0;
+ clear_weak_mods();
+
+#if TAP_CODE_DELAY > 0
+ // only delay once and for a non-tapping key
+ if (!delay_done && !is_tap_record(record)) {
+ delay_done = true;
+ wait_ms(TAP_CODE_DELAY);
+ }
+#endif
}
key_buffer_next = key_buffer_size = 0;
@@ -350,6 +383,28 @@ combo_t *overlaps(combo_t *combo1, combo_t *combo2) {
return combo1;
}
+#if defined(COMBO_MUST_PRESS_IN_ORDER) || defined(COMBO_MUST_PRESS_IN_ORDER_PER_COMBO)
+static bool keys_pressed_in_order(uint16_t combo_index, combo_t *combo, uint16_t key_index, uint16_t keycode, keyrecord_t *record) {
+# ifdef COMBO_MUST_PRESS_IN_ORDER_PER_COMBO
+ if (!get_combo_must_press_in_order(combo_index, combo)) {
+ return true;
+ }
+# endif
+ if (
+ // The `state` bit for the key being pressed.
+ (1 << key_index) ==
+ // The *next* combo key's bit.
+ (COMBO_STATE(combo) + 1)
+ // E.g. two keys already pressed: `state == 11`.
+ // Next possible `state` is `111`.
+ // So the needed bit is `100` which we get with `11 + 1`.
+ ) {
+ return true;
+ }
+ return false;
+}
+#endif
+
static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record, uint16_t combo_index) {
uint8_t key_count = 0;
uint16_t key_index = -1;
@@ -360,7 +415,14 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
return false;
}
- bool key_is_part_of_combo = !COMBO_DISABLED(combo) && is_combo_enabled();
+ bool key_is_part_of_combo = (!COMBO_DISABLED(combo) && is_combo_enabled()
+#if defined(COMBO_MUST_PRESS_IN_ORDER) || defined(COMBO_MUST_PRESS_IN_ORDER_PER_COMBO)
+ && keys_pressed_in_order(combo_index, combo, key_index, keycode, record)
+#endif
+#ifdef COMBO_SHOULD_TRIGGER
+ && combo_should_trigger(combo_index, combo, keycode, record)
+#endif
+ );
if (record->event.pressed && key_is_part_of_combo) {
uint16_t time = _get_combo_term(combo_index, combo);
@@ -412,7 +474,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
// get possible longer waiting time for tap-/hold-only combos.
longest_term = _get_wait_time(combo_index, combo);
}
- } // if timer elapsed end
+ } // if timer elapsed end
}
} else {
// chord releases
@@ -427,7 +489,7 @@ static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *
else if (get_combo_must_tap(combo_index, combo)) {
// immediately apply tap-only combo
apply_combo(combo_index, combo);
- apply_combos(); // also apply other prepared combos and dump key buffer
+ apply_combos(); // also apply other prepared combos and dump key buffer
# ifdef COMBO_PROCESS_KEY_RELEASE
if (process_combo_key_release(combo_index, combo, key_index, keycode)) {
release_combo(combo_index, combo);
@@ -509,7 +571,7 @@ bool process_combo(uint16_t keycode, keyrecord_t *record) {
key_buffer[key_buffer_size++] = (queued_record_t){
.record = *record,
.keycode = keycode,
- .combo_index = -1, // this will be set when applying combos
+ .combo_index = -1, // this will be set when applying combos
};
}
} else {
@@ -548,7 +610,9 @@ void combo_task(void) {
#endif
}
-void combo_enable(void) { b_combo_enable = true; }
+void combo_enable(void) {
+ b_combo_enable = true;
+}
void combo_disable(void) {
#ifndef COMBO_NO_TIMER
@@ -568,4 +632,6 @@ void combo_toggle(void) {
}
}
-bool is_combo_enabled(void) { return b_combo_enable; }
+bool is_combo_enabled(void) {
+ return b_combo_enable;
+}