From e3e82a1109cb1af97c073de310732db3dd444701 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 19 Dec 2023 08:34:06 -0800 Subject: [PATCH] Added short-circuit leader key --- .../features/leader/beta_leader.h | 39 +++++++ .../betalupi_ergodox/features/leader/leader.c | 103 ++++++++++++++++++ .../betalupi_ergodox/keymaps/default/config.h | 1 + .../betalupi_ergodox/keymaps/default/keymap.c | 18 ++- .../keymaps/default/parts/leader.c | 95 +++++++++------- .../betalupi_ergodox/keymaps/default/rules.mk | 1 - keyboards/betalupi_ergodox/rules.mk | 3 +- 7 files changed, 217 insertions(+), 43 deletions(-) create mode 100644 keyboards/betalupi_ergodox/features/leader/beta_leader.h create mode 100644 keyboards/betalupi_ergodox/features/leader/leader.c diff --git a/keyboards/betalupi_ergodox/features/leader/beta_leader.h b/keyboards/betalupi_ergodox/features/leader/beta_leader.h new file mode 100644 index 0000000..2528572 --- /dev/null +++ b/keyboards/betalupi_ergodox/features/leader/beta_leader.h @@ -0,0 +1,39 @@ +#pragma once +#ifdef ENABLE_BETA_LEADER + +#include "quantum.h" + +bool beta_process_leader(uint16_t keycode, keyrecord_t *record); + +void beta_leader_start(void); +void beta_leader_end(void); +bool beta_leader_check(void); +void beta_qk_leader_check(void); +void beta_qk_leader_start(void); + + +#define BETA_LEADER_EXTERNS() \ + extern bool beta_leading; \ + extern uint16_t beta_leader_time; \ + extern uint16_t beta_leader_sequence[5]; \ + extern uint8_t beta_leader_sequence_size + +// Normal sequence +// These do the same thing as SEQ_X_KEYS from qmk. +#define BETA_SEQ_1_LONG(key) if (beta_leader_sequence[0] == (key) && beta_leader_sequence[1] == 0 && beta_leader_sequence[2] == 0 && beta_leader_sequence[3] == 0 && beta_leader_sequence[4] == 0 && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT) +#define BETA_SEQ_2_LONG(key1, key2) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2) && beta_leader_sequence[2] == 0 && beta_leader_sequence[3] == 0 && beta_leader_sequence[4] == 0 && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT) +#define BETA_SEQ_3_LONG(key1, key2, key3) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2) && beta_leader_sequence[2] == (key3) && beta_leader_sequence[3] == 0 && beta_leader_sequence[4] == 0 && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT) +#define BETA_SEQ_4_LONG(key1, key2, key3, key4) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2) && beta_leader_sequence[2] == (key3) && beta_leader_sequence[3] == (key4) && beta_leader_sequence[4] == 0 && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT) +#define BETA_SEQ_5_LONG(key1, key2, key3, key4, key5) if (leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2) && beta_leader_sequence[2] == (key3) && beta_leader_sequence[3] == (key4) && beta_leader_sequence[4] == (key5) && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT) + +// Short-circuit sequence +// These match as soon as a matching sequence is seen, +// not waiting for the leader timeout. They thus register +// immediately, but cannot be used in longer sequences. +#define BETA_SEQ_1_SHORT(key) if (beta_leader_sequence[0] == (key)) +#define BETA_SEQ_2_SHORT(key1, key2) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2)) +#define BETA_SEQ_3_SHORT(key1, key2, key3) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2)) +#define BETA_SEQ_4_SHORT(key1, key2, key3, key4) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2)) +#define BETA_SEQ_5_SHORT(key1, key2, key3, key4, key5) if (beta_leader_sequence[0] == (key1) && beta_leader_sequence[1] == (key2)) + +#endif \ No newline at end of file diff --git a/keyboards/betalupi_ergodox/features/leader/leader.c b/keyboards/betalupi_ergodox/features/leader/leader.c new file mode 100644 index 0000000..e7dfe01 --- /dev/null +++ b/keyboards/betalupi_ergodox/features/leader/leader.c @@ -0,0 +1,103 @@ +#ifdef ENABLE_BETA_LEADER + +#include "beta_leader.h" +#include + +#ifndef LEADER_TIMEOUT +#define LEADER_TIMEOUT 300 +#endif + +__attribute__((weak)) void beta_leader_start(void) {} +__attribute__((weak)) void beta_leader_end(void) {} +__attribute__((weak)) bool beta_leader_check(void) { return true; } + +// Leader key stuff +bool beta_leading = false; +uint16_t beta_leader_time = 0; +bool beta_leader_change = false; + +uint16_t beta_leader_sequence[5] = {0, 0, 0, 0, 0}; +uint8_t beta_leader_sequence_size = 0; + +void beta_qk_leader_start(void) { + if (beta_leading) { + return; + } + beta_leader_start(); + beta_leading = true; + beta_leader_time = timer_read(); + beta_leader_sequence_size = 0; + beta_leader_change = false; // If true, run + memset(beta_leader_sequence, 0, sizeof(beta_leader_sequence)); +} + +void beta_qk_leader_check() { + + #ifdef LEADER_NO_TIMEOUT + bool timeout = (beta_leading && beta_leader_sequence_size > 0 && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT); + #else + bool timeout = (beta_leading && timer_elapsed(beta_leader_time) > LEADER_TIMEOUT); + #endif + + if (beta_leader_change || timeout) { + beta_leader_change = false; + + if ( + beta_leader_sequence[beta_leader_sequence_size - 1] == (KC_LEAD) + ) { + beta_leading = false; + beta_leader_end(); + return; + } + + if (timeout) { + beta_leading = false; + beta_leader_end(); + } + + if (!beta_leader_check()) { + beta_leading = false; + beta_leader_end(); + }; + } +} + +bool beta_process_leader(uint16_t keycode, keyrecord_t *record) { + // Leader key set-up + if (record->event.pressed) { + if (beta_leading) { +# ifndef LEADER_NO_TIMEOUT + if (timer_elapsed(beta_leader_time) < LEADER_TIMEOUT) +# endif // LEADER_NO_TIMEOUT + { +# ifndef LEADER_KEY_STRICT_KEY_PROCESSING + if (IS_QK_MOD_TAP(keycode)) { + keycode = QK_MOD_TAP_GET_TAP_KEYCODE(keycode); + } else if (IS_QK_LAYER_TAP(keycode)) { + keycode = QK_LAYER_TAP_GET_TAP_KEYCODE(keycode); + } +# endif // LEADER_KEY_STRICT_KEY_PROCESSING + if (beta_leader_sequence_size < ARRAY_SIZE(beta_leader_sequence)) { + beta_leader_sequence[beta_leader_sequence_size] = keycode; + beta_leader_sequence_size++; + beta_leader_change = true; + } else { + beta_leading = false; + beta_leader_end(); + return true; + } +# ifdef LEADER_PER_KEY_TIMING + beta_leader_time = timer_read(); +# endif + return false; + } + } else { + if (keycode == QK_LEADER) { + beta_qk_leader_start(); + } + } + } + return true; +} + +#endif \ No newline at end of file diff --git a/keyboards/betalupi_ergodox/keymaps/default/config.h b/keyboards/betalupi_ergodox/keymaps/default/config.h index b5552c7..1bd1fc2 100644 --- a/keyboards/betalupi_ergodox/keymaps/default/config.h +++ b/keyboards/betalupi_ergodox/keymaps/default/config.h @@ -1,3 +1,4 @@ +#define ENABLE_BETA_LEADER // No timeout after initial leader key press #define LEADER_NO_TIMEOUT diff --git a/keyboards/betalupi_ergodox/keymaps/default/keymap.c b/keyboards/betalupi_ergodox/keymaps/default/keymap.c index e42cdac..6a6f579 100644 --- a/keyboards/betalupi_ergodox/keymaps/default/keymap.c +++ b/keyboards/betalupi_ergodox/keymaps/default/keymap.c @@ -73,6 +73,10 @@ enum tap_dance_codes { #include "features/autocorrect/autocorrect.h" #endif +#ifdef ENABLE_BETA_LEADER +#include "features/leader/beta_leader.h" +#endif + #include "features/beta_rawhid.h" // Send a special character. @@ -86,6 +90,14 @@ bool send_special_character(uint16_t keycode) { } +void matrix_scan_user(void) { + #ifdef ENABLE_BETA_LEADER + beta_qk_leader_check(); + #endif +} + + + // Include all other parts of configuration #include "layers/layers.c" #include "parts/leader.c" @@ -96,6 +108,10 @@ bool send_special_character(uint16_t keycode) { // Return TRUE to allow QMK to handle keypress. bool process_record_user(uint16_t keycode, keyrecord_t *record) { + #ifdef ENABLE_BETA_LEADER + if (!beta_process_leader(keycode, record)) { return false; } + #endif + #ifdef ENABLE_HID_SPELLCHECK if (!process_spellcheck(keycode, record)) { return false; } #endif @@ -116,7 +132,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { SEND_STRING(SS_LCTL(SS_LGUI(SS_LSFT(SS_TAP(X_R))))); } return false; - + // Workaround for one-shot LGUI key. // Using just LGUI with LAYER_DESKTOP as OSL // does not allow you to hold lgui. This does. diff --git a/keyboards/betalupi_ergodox/keymaps/default/parts/leader.c b/keyboards/betalupi_ergodox/keymaps/default/parts/leader.c index bac1ee9..cb5dd10 100644 --- a/keyboards/betalupi_ergodox/keymaps/default/parts/leader.c +++ b/keyboards/betalupi_ergodox/keymaps/default/parts/leader.c @@ -1,49 +1,64 @@ -LEADER_EXTERNS(); +#include "features/leader/beta_leader.h" -void leader_start(void) { +BETA_LEADER_EXTERNS(); + +void beta_leader_start(void) { ergodox_right_led_3_on(); } -void leader_end(void) { +void beta_leader_end(void) { ergodox_right_led_3_off(); } -void matrix_scan_user(void) { - LEADER_DICTIONARY() { - leading = false; - leader_end(); - - SEQ_TWO_KEYS(KC_E, KC_M) { - SEND_STRING(SECRET_EMAIL); - } - - SEQ_TWO_KEYS(KC_G, KC_M) { - SEND_STRING(SECRET_GMAIL); - } - - SEQ_TWO_KEYS(KC_L, KC_I) { - SEND_STRING(SECRET_SCHOOL_EMAIL); - } - - SEQ_TWO_KEYS(KC_K, KC_B) { - layer_move(LAYER_KEYBOARD); - } - - //SEQ_ONE_KEY(KC_F) { - // doesn't work, no deactivate - // also, this is slow since laeder key uses dumb logic - // set_oneshot_layer(LAYER_FKEYS, ONESHOT_START); - //} - - SEQ_TWO_KEYS(KC_F, KC_1) { tap_code(KC_F1); } - SEQ_TWO_KEYS(KC_F, KC_2) { tap_code(KC_F2); } - SEQ_TWO_KEYS(KC_F, KC_3) { tap_code(KC_F3); } - SEQ_TWO_KEYS(KC_F, KC_4) { tap_code(KC_F4); } - SEQ_TWO_KEYS(KC_F, KC_5) { tap_code(KC_F5); } - SEQ_TWO_KEYS(KC_F, KC_Q) { tap_code(KC_F6); } - SEQ_TWO_KEYS(KC_F, KC_W) { tap_code(KC_F7); } - SEQ_TWO_KEYS(KC_F, KC_E) { tap_code(KC_F8); } - SEQ_TWO_KEYS(KC_F, KC_R) { tap_code(KC_F9); } - SEQ_TWO_KEYS(KC_F, KC_T) { tap_code(KC_F10); } +bool beta_leader_check(void) { + BETA_SEQ_1_SHORT(KC_E) { + SEND_STRING(SECRET_GMAIL); + return false; } + + BETA_SEQ_2_LONG(KC_E, KC_M) { + SEND_STRING(SECRET_EMAIL); + return false; + } + + BETA_SEQ_2_LONG(KC_G, KC_M) { + SEND_STRING(SECRET_GMAIL); + return false; + } + + BETA_SEQ_2_LONG(KC_L, KC_I) { + SEND_STRING(SECRET_SCHOOL_EMAIL); + return false; + } + + BETA_SEQ_2_LONG(KC_K, KC_B) { + layer_move(LAYER_KEYBOARD); + return false; + } + + BETA_SEQ_2_LONG(KC_K, KC_B) { + layer_move(LAYER_KEYBOARD); + return false; + } + + + BETA_SEQ_1_SHORT(KC_F) { + // doesn't work, no deactivate + // also, this is slow since laeder key uses dumb logic + set_oneshot_layer(LAYER_NUMBERS, ONESHOT_START); + return false; + } + + BETA_SEQ_2_LONG(KC_F, KC_1) { tap_code(KC_F1); return false; } + BETA_SEQ_2_LONG(KC_F, KC_2) { tap_code(KC_F2); return false; } + BETA_SEQ_2_LONG(KC_F, KC_3) { tap_code(KC_F3); return false; } + BETA_SEQ_2_LONG(KC_F, KC_4) { tap_code(KC_F4); return false; } + BETA_SEQ_2_LONG(KC_F, KC_5) { tap_code(KC_F5); return false; } + BETA_SEQ_2_LONG(KC_F, KC_Q) { tap_code(KC_F6); return false; } + BETA_SEQ_2_LONG(KC_F, KC_W) { tap_code(KC_F7); return false; } + BETA_SEQ_2_LONG(KC_F, KC_E) { tap_code(KC_F8); return false; } + BETA_SEQ_2_LONG(KC_F, KC_R) { tap_code(KC_F9); return false; } + BETA_SEQ_2_LONG(KC_F, KC_T) { tap_code(KC_F10); return false; } + + return true; } \ No newline at end of file diff --git a/keyboards/betalupi_ergodox/keymaps/default/rules.mk b/keyboards/betalupi_ergodox/keymaps/default/rules.mk index 1cb00f5..3e2f02c 100644 --- a/keyboards/betalupi_ergodox/keymaps/default/rules.mk +++ b/keyboards/betalupi_ergodox/keymaps/default/rules.mk @@ -1,4 +1,3 @@ # rules.mk overrides -LEADER_ENABLE = yes TAP_DANCE_ENABLE = yes diff --git a/keyboards/betalupi_ergodox/rules.mk b/keyboards/betalupi_ergodox/rules.mk index 423ff0c..08c169d 100644 --- a/keyboards/betalupi_ergodox/rules.mk +++ b/keyboards/betalupi_ergodox/rules.mk @@ -30,7 +30,7 @@ SLEEP_LED_ENABLE = no API_SYSEX_ENABLE = no MOUSE_SHARED_EP = no MAGIC_ENABLE = no -LEADER_ENABLE = yes +LEADER_ENABLE = no TAP_DANCE_ENABLE = yes AUDIO_SUPPORTED = no BACKLIGHT_SUPPORTED = no @@ -43,6 +43,7 @@ SRC += \ features/beta_rawhid.c \ features/hid_spellcheck.c \ features/autocorrect/autocorrect.c \ + features/leader/leader.c \ extra_mappings.c QUANTUM_LIB_SRC += i2c_master.c