diff --git a/Makefile b/Makefile index 5abb4d651990..17ebec4343d9 100644 --- a/Makefile +++ b/Makefile @@ -170,6 +170,11 @@ ifeq ($(strip $(RGBLIGHT_ENABLE)), yes) SRC += $(QUANTUM_DIR)/rgblight.c endif +ifeq ($(strip $(TAP_DANCE_ENABLE)), yes) + OPT_DEFS += -DTAP_DANCE_ENABLE + SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c +endif + # Optimize size but this may cause error "relocation truncated to fit" #EXTRALDFLAGS = -Wl,--relax diff --git a/keyboards/alps64/matrix.c b/keyboards/alps64/matrix.c index 805999d4a1a7..b3508850dec3 100644 --- a/keyboards/alps64/matrix.c +++ b/keyboards/alps64/matrix.c @@ -100,6 +100,8 @@ uint8_t matrix_scan(void) } } + matrix_scan_quantum(); + return 1; } diff --git a/keyboards/ergodox_ez/matrix.c b/keyboards/ergodox_ez/matrix.c index e0de06c3492d..b87fddbad7ed 100644 --- a/keyboards/ergodox_ez/matrix.c +++ b/keyboards/ergodox_ez/matrix.c @@ -187,8 +187,7 @@ uint8_t matrix_scan(void) } } - - matrix_scan_kb(); + matrix_scan_quantum(); return 1; } diff --git a/keyboards/hhkb/matrix.c b/keyboards/hhkb/matrix.c index 2dfb2f5e1f45..666b6f595f17 100644 --- a/keyboards/hhkb/matrix.c +++ b/keyboards/hhkb/matrix.c @@ -71,6 +71,14 @@ void matrix_init(void) matrix_prev = _matrix1; } +__attribute__ ((weak)) +void matrix_scan_user(void) { +} + +void matrix_scan_kb(void) { + matrix_scan_user(); +} + uint8_t matrix_scan(void) { uint8_t *tmp; @@ -150,6 +158,9 @@ uint8_t matrix_scan(void) KEY_POWER_OFF(); suspend_power_down(); } + + matrix_scan_quantum(); + return 1; } diff --git a/keyboards/sixkeyboard/matrix.c b/keyboards/sixkeyboard/matrix.c index c279986487e8..ed1b70e286f5 100644 --- a/keyboards/sixkeyboard/matrix.c +++ b/keyboards/sixkeyboard/matrix.c @@ -87,7 +87,7 @@ uint8_t matrix_scan(void) matrix[0] = (PINC&(1<<7) ? 0 : (1<<0)) | (PINB&(1<<7) ? 0 : (1<<1)) | (PINB&(1<<5) ? 0 : (1<<2)); matrix[1] = (PIND&(1<<6) ? 0 : (1<<0)) | (PIND&(1<<1) ? 0 : (1<<1)) | (PIND&(1<<4) ? 0 : (1<<2)); - matrix_scan_kb(); + matrix_scan_quantum(); return 1; } diff --git a/quantum/keymap.h b/quantum/keymap.h index 41fa394ab697..a994f4f2e559 100644 --- a/quantum/keymap.h +++ b/quantum/keymap.h @@ -77,6 +77,8 @@ enum quantum_keycodes { #endif QK_MOD_TAP = 0x6000, QK_MOD_TAP_MAX = 0x6FFF, + QK_TAP_DANCE = 0x7100, + QK_TAP_DANCE_MAX = 0x71FF, #ifdef UNICODE_ENABLE QK_UNICODE = 0x8000, QK_UNICODE_MAX = 0xFFFF, diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c new file mode 100644 index 000000000000..9b172e1b6c92 --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.c @@ -0,0 +1,90 @@ +#include "quantum.h" + +static qk_tap_dance_state_t qk_tap_dance_state; + +static void _process_tap_dance_action_pair (qk_tap_dance_state_t *state, + uint16_t kc1, uint16_t kc2) { + uint16_t kc; + + if (state->count == 0) + return; + + kc = (state->count == 1) ? kc1 : kc2; + + register_code (kc); + unregister_code (kc); + + if (state->count >= 2) { + reset_tap_dance (state); + } +} + +static void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, + qk_tap_dance_user_fn_t fn) +{ + fn(state); +} + +void process_tap_dance_action (uint16_t keycode) +{ + uint16_t idx = keycode - QK_TAP_DANCE; + qk_tap_dance_action_t action; + + action = tap_dance_actions[idx]; + + switch (action.type) { + case QK_TAP_DANCE_TYPE_PAIR: + _process_tap_dance_action_pair (&qk_tap_dance_state, + action.pair.kc1, action.pair.kc2); + break; + case QK_TAP_DANCE_TYPE_FN: + _process_tap_dance_action_fn (&qk_tap_dance_state, action.fn); + break; + + default: + break; + } +} + +bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { + bool r = true; + + switch(keycode) { + case QK_TAP_DANCE ... QK_TAP_DANCE_MAX: + if (qk_tap_dance_state.keycode && qk_tap_dance_state.keycode != keycode) { + process_tap_dance_action (qk_tap_dance_state.keycode); + } else { + r = false; + } + + if (record->event.pressed) { + qk_tap_dance_state.keycode = keycode; + qk_tap_dance_state.timer = timer_read (); + qk_tap_dance_state.count++; + } + break; + + default: + if (qk_tap_dance_state.keycode) { + process_tap_dance_action (qk_tap_dance_state.keycode); + + reset_tap_dance (&qk_tap_dance_state); + } + break; + } + + return r; +} + +void matrix_scan_tap_dance () { + if (qk_tap_dance_state.keycode && timer_elapsed (qk_tap_dance_state.timer) > TAPPING_TERM) { + process_tap_dance_action (qk_tap_dance_state.keycode); + + reset_tap_dance (&qk_tap_dance_state); + } +} + +void reset_tap_dance (qk_tap_dance_state_t *state) { + state->keycode = 0; + state->count = 0; +} diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h new file mode 100644 index 000000000000..b9d7c7fcf452 --- /dev/null +++ b/quantum/process_keycode/process_tap_dance.h @@ -0,0 +1,62 @@ +#ifndef PROCESS_TAP_DANCE_H +#define PROCESS_TAP_DANCE_H + +#ifdef TAP_DANCE_ENABLE + +#include +#include + +typedef struct +{ + uint8_t count; + uint16_t keycode; + uint16_t timer; +} qk_tap_dance_state_t; + +#define TD(n) (QK_TAP_DANCE + n) + +typedef enum +{ + QK_TAP_DANCE_TYPE_PAIR, + QK_TAP_DANCE_TYPE_FN, +} qk_tap_dance_type_t; + +typedef void (*qk_tap_dance_user_fn_t) (qk_tap_dance_state_t *state); + +typedef struct +{ + qk_tap_dance_type_t type; + union { + struct { + uint16_t kc1; + uint16_t kc2; + } pair; + qk_tap_dance_user_fn_t fn; + }; +} qk_tap_dance_action_t; + +#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \ + .type = QK_TAP_DANCE_TYPE_PAIR, \ + .pair = { kc1, kc2 } \ + } + +#define ACTION_TAP_DANCE_FN(user_fn) { \ + .type = QK_TAP_DANCE_TYPE_FN, \ + .fn = user_fn \ + } + +extern const qk_tap_dance_action_t tap_dance_actions[]; + +/* To be used internally */ + +bool process_tap_dance(uint16_t keycode, keyrecord_t *record); +void matrix_scan_tap_dance (void); +void reset_tap_dance (qk_tap_dance_state_t *state); + +#else + +#define TD(n) KC_NO + +#endif + +#endif diff --git a/quantum/quantum.c b/quantum/quantum.c index 2a83890cbeb9..c0580e0aa5f2 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -46,7 +46,6 @@ bool process_record_quantum(keyrecord_t *record) { keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key); #endif - // This is how you use actions here // if (keycode == KC_LEAD) { // action_t action; @@ -63,6 +62,9 @@ bool process_record_quantum(keyrecord_t *record) { #ifdef AUDIO_ENABLE process_music(keycode, record) && #endif + #ifdef TAP_DANCE_ENABLE + process_tap_dance(keycode, record) && + #endif #ifndef DISABLE_LEADER process_leader(keycode, record) && #endif @@ -317,6 +319,9 @@ void matrix_scan_quantum() { matrix_scan_music(); #endif + #ifdef TAP_DANCE_ENABLE + matrix_scan_tap_dance(); + #endif matrix_scan_kb(); } diff --git a/quantum/quantum.h b/quantum/quantum.h index a84b5a1b0e44..ad180c71f82a 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -53,6 +53,8 @@ extern uint32_t default_layer_state; #include "process_unicode.h" #endif +#include "process_tap_dance.h" + #define SEND_STRING(str) send_string(PSTR(str)) void send_string(const char *str);