diff options
Diffstat (limited to 'tests/tap_dance/examples.c')
| -rw-r--r-- | tests/tap_dance/examples.c | 199 | 
1 files changed, 199 insertions, 0 deletions
| diff --git a/tests/tap_dance/examples.c b/tests/tap_dance/examples.c new file mode 100644 index 0000000000..4a5be41b08 --- /dev/null +++ b/tests/tap_dance/examples.c @@ -0,0 +1,199 @@ +/* Copyright 2022 Jouke Witteveen + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "quantum.h" +#include "examples.h" + +// Example code from the tap dance documentation, adapted for testing + +// clang-format off + +// Example 1 + +void dance_egg(qk_tap_dance_state_t *state, void *user_data) { +    if (state->count >= 100) { +        // SEND_STRING("Safety dance!"); +        tap_code(KC_C); +        reset_tap_dance(state); +    } +} + + +// Example 2 + +void dance_flsh_each(qk_tap_dance_state_t *state, void *user_data) { +    switch (state->count) { +        case 1: +            register_code(KC_3); +            break; +        case 2: +            register_code(KC_2); +            break; +        case 3: +            register_code(KC_1); +            break; +        case 4: +            unregister_code(KC_3); +            // wait_ms(50); +            unregister_code(KC_2); +            // wait_ms(50); +            unregister_code(KC_1); +    } +} + +void dance_flsh_finished(qk_tap_dance_state_t *state, void *user_data) { +    if (state->count >= 4) { +        // reset_keyboard(); +        tap_code(KC_R); +    } +} + +void dance_flsh_reset(qk_tap_dance_state_t *state, void *user_data) { +    unregister_code(KC_1); +    // wait_ms(50); +    unregister_code(KC_2); +    // wait_ms(50); +    unregister_code(KC_3); +} + + +// Example 3 + +typedef struct { +    uint16_t tap; +    uint16_t hold; +    uint16_t held; +} tap_dance_tap_hold_t; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { +    qk_tap_dance_action_t *action; + +    switch (keycode) { +        case TD(CT_CLN): +            action = &tap_dance_actions[TD_INDEX(keycode)]; +            if (!record->event.pressed && action->state.count && !action->state.finished) { +                tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data; +                tap_code16(tap_hold->tap); +            } +    } +    return true; +} + +void tap_dance_tap_hold_finished(qk_tap_dance_state_t *state, void *user_data) { +    tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; + +    if (state->pressed) { +        if (state->count == 1 +#ifndef PERMISSIVE_HOLD +            && !state->interrupted +#endif +        ) { +            register_code16(tap_hold->hold); +            tap_hold->held = tap_hold->hold; +        } else { +            register_code16(tap_hold->tap); +            tap_hold->held = tap_hold->tap; +        } +    } +} + +void tap_dance_tap_hold_reset(qk_tap_dance_state_t *state, void *user_data) { +    tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data; + +    if (tap_hold->held) { +        unregister_code16(tap_hold->held); +        tap_hold->held = 0; +    } +} + +#define ACTION_TAP_DANCE_TAP_HOLD(tap, hold) \ +    { .fn = {NULL, tap_dance_tap_hold_finished, tap_dance_tap_hold_reset}, .user_data = (void *)&((tap_dance_tap_hold_t){tap, hold, 0}), } + + +// Example 4 + +typedef enum { +    TD_NONE, +    TD_UNKNOWN, +    TD_SINGLE_TAP, +    TD_SINGLE_HOLD, +    TD_DOUBLE_TAP, +    TD_DOUBLE_HOLD, +    TD_DOUBLE_SINGLE_TAP, +    TD_TRIPLE_TAP, +    TD_TRIPLE_HOLD +} td_state_t; + +typedef struct { +    bool is_press_action; +    td_state_t state; +} td_tap_t; + +td_state_t cur_dance(qk_tap_dance_state_t *state) { +    if (state->count == 1) { +        if (state->interrupted || !state->pressed) return TD_SINGLE_TAP; +        else return TD_SINGLE_HOLD; +    } else if (state->count == 2) { +        if (state->interrupted) return TD_DOUBLE_SINGLE_TAP; +        else if (state->pressed) return TD_DOUBLE_HOLD; +        else return TD_DOUBLE_TAP; +    } + +    if (state->count == 3) { +        if (state->interrupted || !state->pressed) return TD_TRIPLE_TAP; +        else return TD_TRIPLE_HOLD; +    } else return TD_UNKNOWN; +} + +static td_tap_t xtap_state = { +    .is_press_action = true, +    .state = TD_NONE +}; + +void x_finished(qk_tap_dance_state_t *state, void *user_data) { +    xtap_state.state = cur_dance(state); +    switch (xtap_state.state) { +        case TD_SINGLE_TAP: register_code(KC_X); break; +        case TD_SINGLE_HOLD: register_code(KC_LCTL); break; +        case TD_DOUBLE_TAP: register_code(KC_ESC); break; +        case TD_DOUBLE_HOLD: register_code(KC_LALT); break; +        case TD_DOUBLE_SINGLE_TAP: tap_code(KC_X); register_code(KC_X); +        default: break;  // Not present in documentation +    } +} + +void x_reset(qk_tap_dance_state_t *state, void *user_data) { +    switch (xtap_state.state) { +        case TD_SINGLE_TAP: unregister_code(KC_X); break; +        case TD_SINGLE_HOLD: unregister_code(KC_LCTL); break; +        case TD_DOUBLE_TAP: unregister_code(KC_ESC); break; +        case TD_DOUBLE_HOLD: unregister_code(KC_LALT); +        case TD_DOUBLE_SINGLE_TAP: unregister_code(KC_X); +        default: break;  // Not present in documentation +    } +    xtap_state.state = TD_NONE; +} + + +qk_tap_dance_action_t tap_dance_actions[] = { +    [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS), +    [CT_EGG]      = ACTION_TAP_DANCE_FN(dance_egg), +    [CT_FLSH]     = ACTION_TAP_DANCE_FN_ADVANCED(dance_flsh_each, dance_flsh_finished, dance_flsh_reset), +    [CT_CLN]      = ACTION_TAP_DANCE_TAP_HOLD(KC_COLN, KC_SCLN), +    [X_CTL]       = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished, x_reset) +}; + +// clang-format on | 
