summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build_keyboard.mk5
-rw-r--r--quantum/process_keycode/process_combo.c66
-rw-r--r--quantum/process_keycode/process_combo.h25
-rw-r--r--quantum/quantum.c3
-rw-r--r--quantum/quantum.h4
5 files changed, 103 insertions, 0 deletions
diff --git a/build_keyboard.mk b/build_keyboard.mk
index ce505de126..14f4f36bc9 100644
--- a/build_keyboard.mk
+++ b/build_keyboard.mk
@@ -144,6 +144,11 @@ ifeq ($(strip $(MIDI_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/process_keycode/process_midi.c
endif
+ifeq ($(strip $(COMBO_ENABLE)), yes)
+ OPT_DEFS += -DCOMBO_ENABLE
+ SRC += $(QUANTUM_DIR)/process_keycode/process_combo.c
+endif
+
ifeq ($(strip $(VIRTSER_ENABLE)), yes)
OPT_DEFS += -DVIRTSER_ENABLE
endif
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
new file mode 100644
index 0000000000..a6cfed11aa
--- /dev/null
+++ b/quantum/process_keycode/process_combo.c
@@ -0,0 +1,66 @@
+#include "process_combo.h"
+#include "print.h"
+
+// __attribute__ ((weak))
+// combo_t key_combos[] = {
+
+// };
+
+#define SEND_KEY(key) \
+do { \
+ register_code16(key); \
+ send_keyboard_report(); \
+ unregister_code16(key); \
+} while(0)
+
+
+#define ALL_COMBO_KEYS_ARE_DOWN (((1<<count)-1) == combo->state)
+static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record)
+{
+ uint8_t count = 0;
+ bool is_combo_key = false;
+ // bool combo_key_released = false;
+
+ // Count the number of combo keys
+ for (const uint16_t *key = combo->keys; COMBO_END != pgm_read_word(key); ++key, ++count);
+
+ for (uint8_t i = 0; i < count; ++i) {
+ uint16_t key = pgm_read_word(&combo->keys[i]);
+
+ if (key == keycode) {
+ is_combo_key = true;
+
+ if (record->event.pressed) {
+ combo->state |= (1<<i);
+ } else { // Combo key released
+ if (!combo->state) {
+ // The combo was sent, no need to send released key
+ return true;
+ }
+
+ combo->state &= ~(1<<i);
+ SEND_KEY(key);
+ }
+ }
+ }
+
+ if (ALL_COMBO_KEYS_ARE_DOWN) {
+ SEND_KEY(combo->action);
+ combo->state = 0;
+ }
+
+ return is_combo_key;
+}
+
+
+bool process_combo(uint16_t keycode, keyrecord_t *record)
+{
+ bool is_combo_key = false;
+
+ for (int i = 0; i < NUM_ELEMS(key_combos); ++i) {
+ combo_t *combo = &key_combos[i];
+ is_combo_key |= process_single_combo(combo, keycode, record);
+ }
+
+ return !is_combo_key;
+} \ No newline at end of file
diff --git a/quantum/process_keycode/process_combo.h b/quantum/process_keycode/process_combo.h
new file mode 100644
index 0000000000..68786c0f19
--- /dev/null
+++ b/quantum/process_keycode/process_combo.h
@@ -0,0 +1,25 @@
+#ifndef PROCESS_COMBO_H
+#define PROCESS_COMBO_H
+
+#include <stdint.h>
+#include "progmem.h"
+#include "quantum.h"
+
+
+typedef struct
+{
+ const uint16_t *keys;
+ uint16_t action;
+ uint32_t state;
+} combo_t;
+
+
+#define COMBO_END 0
+#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
+
+
+extern combo_t key_combos[1];
+
+bool process_combo(uint16_t keycode, keyrecord_t *record);
+
+#endif \ No newline at end of file
diff --git a/quantum/quantum.c b/quantum/quantum.c
index f653564a67..eabeacff87 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -113,6 +113,9 @@ bool process_record_quantum(keyrecord_t *record) {
if (!(
process_record_kb(keycode, record) &&
+ #ifdef COMBO_ENABLE
+ process_combo(keycode, record) &&
+ #endif
#ifdef MIDI_ENABLE
process_midi(keycode, record) &&
#endif
diff --git a/quantum/quantum.h b/quantum/quantum.h
index e6adf974ab..8614c053ab 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -63,6 +63,10 @@ extern uint32_t default_layer_state;
#include "process_printer.h"
#endif
+#ifdef COMBO_ENABLE
+ #include "process_combo.h"
+#endif
+
#define SEND_STRING(str) send_string(PSTR(str))
void send_string(const char *str);