mirror of https://github.com/qmk/qmk_firmware
657 lines
15 KiB
C
657 lines
15 KiB
C
|
|
// .......................................................... Keycode Primitives
|
|
|
|
// register simple key press
|
|
void tap_key(uint16_t keycode)
|
|
{
|
|
register_code (keycode);
|
|
unregister_code(keycode);
|
|
}
|
|
|
|
void shift_key(uint16_t keycode)
|
|
{
|
|
register_code (KC_LSFT);
|
|
tap_key (keycode);
|
|
unregister_code(KC_LSFT);
|
|
}
|
|
|
|
#define SHIFT 1
|
|
#define NOSHIFT 0
|
|
|
|
static uint16_t key_timer = 0;
|
|
|
|
// key press for thumb_layer() and lt_shift() macros
|
|
bool key_press(uint8_t shift, uint16_t keycode)
|
|
{
|
|
if (keycode) {
|
|
if (timer_elapsed(key_timer) < TAPPING_TERM) {
|
|
if (shift) {
|
|
shift_key(keycode);
|
|
}
|
|
else {
|
|
tap_key(keycode);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ALT_T, CTL_T, GUI_T, SFT_T for shifted keycodes
|
|
void mt_shift(keyrecord_t *record, uint16_t modifier, uint16_t modifier2, uint16_t keycode)
|
|
{
|
|
if (record->event.pressed) {
|
|
key_timer = timer_read();
|
|
register_code(modifier);
|
|
if (modifier2) {
|
|
register_code(modifier2);
|
|
}
|
|
}
|
|
else {
|
|
unregister_code(modifier);
|
|
if (modifier2) {
|
|
unregister_code(modifier2);
|
|
}
|
|
if (timer_elapsed(key_timer) < TAPPING_TERM) {
|
|
shift_key(keycode);
|
|
}
|
|
key_timer = 0;
|
|
}
|
|
}
|
|
|
|
// ................................................................... Mod Masks
|
|
|
|
// tap dance persistant mods, see process_record_user()
|
|
// keyboard_report->mods (?) appears to be cleared by tap dance
|
|
static uint8_t mods = 0;
|
|
|
|
void tap_mods(keyrecord_t *record, uint16_t keycode)
|
|
{
|
|
if (record->event.pressed) {
|
|
mods |= MOD_BIT(keycode);
|
|
}
|
|
else {
|
|
mods &= ~(MOD_BIT(keycode));
|
|
}
|
|
}
|
|
|
|
// (un)register modifiers
|
|
void modifier(void (*f)(uint8_t))
|
|
{
|
|
if (mods & MOD_BIT(KC_LCTL)) {
|
|
(*f)(KC_LCTL);
|
|
}
|
|
if (mods & MOD_BIT(KC_LGUI)) {
|
|
(*f)(KC_LGUI);
|
|
}
|
|
if (mods & MOD_BIT(KC_LALT)) {
|
|
(*f)(KC_LALT);
|
|
}
|
|
}
|
|
|
|
// .................................................... Triple Dance Shift/Layer
|
|
|
|
static uint8_t dt_shift = 0;
|
|
|
|
void double_shift(uint16_t keycode, uint8_t layer)
|
|
{
|
|
tap_key (keycode);
|
|
if (DT_SHIFT) {
|
|
// set_oneshot_mods(MOD_LSFT);
|
|
// layer_on(layer);
|
|
layer_on (_SHIFT);
|
|
set_oneshot_layer(_SHIFT, ONESHOT_START);
|
|
dt_shift = 1;
|
|
}
|
|
else {
|
|
layer_on(layer);
|
|
}
|
|
}
|
|
|
|
// tap dance LT (LAYER, KEY) emulation with <KEY><DOWN> -> <KEY><SHIFT> and auto-repeat extensions!
|
|
void tap_shift(qk_tap_dance_state_t *state, uint16_t keycode, uint8_t layer)
|
|
{
|
|
// double tap plus down
|
|
if (state->count > 2) {
|
|
// double enter shift
|
|
if (keycode == KC_ENT) {
|
|
tap_key (keycode);
|
|
double_shift(keycode, layer);
|
|
}
|
|
// repeating keycode
|
|
else {
|
|
register_code(keycode);
|
|
}
|
|
}
|
|
// tap plus down (or double tap): keycode (one shot) shift
|
|
else if (state->count > 1) {
|
|
double_shift(keycode, layer);
|
|
}
|
|
// down: shift
|
|
else if (state->pressed) {
|
|
layer_on(layer);
|
|
}
|
|
// tap: keycode
|
|
else {
|
|
modifier(register_code);
|
|
tap_key (keycode);
|
|
modifier(unregister_code);
|
|
}
|
|
}
|
|
|
|
void tap_reset(uint16_t keycode, uint8_t layer)
|
|
{
|
|
unregister_code(keycode);
|
|
if (DT_SHIFT && dt_shift) {
|
|
clear_oneshot_layer_state(ONESHOT_PRESSED);
|
|
dt_shift = 0;
|
|
}
|
|
else {
|
|
layer_off(layer);
|
|
}
|
|
}
|
|
|
|
// augment pseudo LT (_RSHIFT, KC_ENT) handling below for rapid <ENTER><SHIFT> sequences
|
|
void enter(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_shift(state, KC_ENT, _RSHIFT);
|
|
}
|
|
|
|
void enter_reset(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_reset(KC_ENT, _RSHIFT);
|
|
}
|
|
|
|
// augment pseudo LT (_LSHIFT, KC_SPC) handling below for rapid <SPACE><SHIFT> sequences
|
|
void space(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_shift(state, KC_SPC, _LSHIFT);
|
|
}
|
|
|
|
void space_reset(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_reset(KC_SPC, _LSHIFT);
|
|
}
|
|
|
|
// ......................................................... Triple Dance Insert
|
|
|
|
void double_max(uint8_t count, uint8_t shift, uint16_t keycode)
|
|
{
|
|
if (shift) {
|
|
shift_key(keycode);
|
|
if (count > 1) {
|
|
shift_key(keycode);
|
|
}
|
|
}
|
|
else {
|
|
tap_key(keycode);
|
|
if (count > 1) {
|
|
tap_key(keycode);
|
|
}
|
|
}
|
|
}
|
|
|
|
void colon(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 2) {
|
|
tap_key (KC_SPC);
|
|
shift_key(KC_SCLN);
|
|
shift_key(KC_SCLN);
|
|
tap_key (KC_SPC);
|
|
}
|
|
else {
|
|
double_max(state->count, SHIFT, KC_SCLN);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
void eql(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 2) {
|
|
tap_key(KC_SPC);
|
|
tap_key(KC_SLSH);
|
|
tap_key(KC_EQL);
|
|
tap_key(KC_SPC);
|
|
}
|
|
else {
|
|
double_max(state->count, NOSHIFT, KC_EQL);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
void greater(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 2) {
|
|
tap_key (KC_SPC);
|
|
tap_key (KC_MINS);
|
|
shift_key(KC_DOT);
|
|
tap_key (KC_SPC);
|
|
}
|
|
else {
|
|
double_max(state->count, SHIFT, KC_DOT);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
void lesser(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 2) {
|
|
tap_key (KC_SPC);
|
|
shift_key(KC_COMM);
|
|
tap_key (KC_MINS);
|
|
tap_key (KC_SPC);
|
|
}
|
|
else {
|
|
double_max(state->count, SHIFT, KC_COMM);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
void tilde(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
// double tap plus down: repeating keycode
|
|
if (state->count > 2) {
|
|
register_code(KC_LSFT);
|
|
register_code(KC_GRV);
|
|
}
|
|
// tap: keycode
|
|
else {
|
|
shift_key(KC_GRV);
|
|
// double tap: unix home directory
|
|
if (state->count > 1) {
|
|
tap_key(KC_SLSH);
|
|
}
|
|
}
|
|
}
|
|
|
|
void tilde_reset(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
unregister_code(KC_GRV);
|
|
unregister_code(KC_LSFT);
|
|
}
|
|
|
|
// ............................................................. Tap Dance Pairs
|
|
|
|
// tap dance shift rules
|
|
#define S_NEVER 0
|
|
#define S_SINGLE 1
|
|
#define S_DOUBLE 2
|
|
#define S_ALWAYS S_SINGLE | S_DOUBLE
|
|
|
|
void symbol_pair(uint8_t shift, uint16_t left, uint16_t right)
|
|
{
|
|
if (shift & S_DOUBLE) {
|
|
shift_key(left);
|
|
shift_key(right);
|
|
}
|
|
else {
|
|
tap_key(left);
|
|
tap_key(right);
|
|
}
|
|
}
|
|
|
|
#define CLOSE 1
|
|
|
|
// tap dance symbol pairs
|
|
void tap_pair(qk_tap_dance_state_t *state, uint8_t shift, uint16_t left, uint16_t right, uint16_t modifier, uint8_t close)
|
|
{
|
|
// triple tap: left right with cursor between symbol pair a la vim :-)
|
|
if (state->count > 2) {
|
|
symbol_pair(shift, left, right);
|
|
tap_key (KC_LEFT);
|
|
}
|
|
// double tap: left right
|
|
else if (state->count > 1) {
|
|
symbol_pair(shift, left, right);
|
|
}
|
|
// down: modifier
|
|
else if (state->pressed) {
|
|
if (modifier) {
|
|
register_code(modifier);
|
|
}
|
|
}
|
|
// tap: left (close: right)
|
|
else {
|
|
if (shift & S_SINGLE) {
|
|
shift_key(close ? right : left);
|
|
}
|
|
else {
|
|
tap_key(close ? right : left);
|
|
}
|
|
}
|
|
if (!modifier) {
|
|
reset_tap_dance(state);
|
|
}
|
|
}
|
|
|
|
void doublequote(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_ALWAYS, KC_QUOT, KC_QUOT, 0, 0);
|
|
}
|
|
|
|
void grave(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_NEVER, KC_GRV, KC_GRV, 0, 0);
|
|
}
|
|
|
|
void lbrace(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_NEVER, KC_LBRC, KC_RBRC, 0, 0);
|
|
}
|
|
|
|
void lcurly(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_ALWAYS, KC_LBRC, KC_RBRC, 0, 0);
|
|
}
|
|
|
|
void lparen(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_ALWAYS, KC_9, KC_0, KC_LCTL, 0);
|
|
}
|
|
|
|
void lparen_reset(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
unregister_code(KC_LCTL);
|
|
}
|
|
|
|
void quote(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_NEVER, KC_QUOT, KC_QUOT, 0, 0);
|
|
}
|
|
|
|
void rangle(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_ALWAYS, KC_COMM, KC_DOT, 0, CLOSE);
|
|
}
|
|
|
|
void rbrace(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_NEVER, KC_LBRC, KC_RBRC, 0, CLOSE);
|
|
}
|
|
|
|
void rcurly(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_ALWAYS, KC_LBRC, KC_RBRC, 0, CLOSE);
|
|
}
|
|
|
|
void rparen(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_pair(state, S_ALWAYS, KC_9, KC_0, 0, CLOSE);
|
|
}
|
|
|
|
void rparen_reset(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
unregister_code(KC_LCTL);
|
|
}
|
|
|
|
// ............................................................ Tap Dance Insert
|
|
|
|
void comma(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
tap_key(KC_COMM);
|
|
if (state->count > 1) {
|
|
tap_key(KC_SPC);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
void dot(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 1) {
|
|
shift_key(KC_COLN);
|
|
}
|
|
else {
|
|
tap_key(KC_DOT);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
// compile time macro string, see functions/hardware planck script
|
|
void private(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 1) {
|
|
#ifdef PRIVATE_STRING
|
|
#include "private_string.h"
|
|
#endif
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
// config.h defined string
|
|
void send(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 1) {
|
|
SEND_STRING(PUBLIC_STRING);
|
|
}
|
|
reset_tap_dance(state);
|
|
}
|
|
|
|
// .......................................................... Tap Dance One Shot
|
|
|
|
void caps(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
if (state->count > 1) {
|
|
tap_key(KC_CAPS);
|
|
}
|
|
else {
|
|
set_oneshot_mods(MOD_LSFT);
|
|
register_code (KC_LSFT); // on hold down
|
|
}
|
|
}
|
|
|
|
void caps_reset(qk_tap_dance_state_t *state, void *user_data)
|
|
{
|
|
unregister_code(KC_LSFT);
|
|
}
|
|
|
|
// ................................................................... Tap Dance
|
|
|
|
qk_tap_dance_action_t tap_dance_actions[] = {
|
|
[_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, caps, caps_reset)
|
|
,[_COLN] = ACTION_TAP_DANCE_FN (colon)
|
|
,[_COMM] = ACTION_TAP_DANCE_FN (comma)
|
|
,[_DOT] = ACTION_TAP_DANCE_FN (dot)
|
|
,[_DQOT] = ACTION_TAP_DANCE_FN (doublequote)
|
|
,[_ENT] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, enter, enter_reset)
|
|
,[_EQL] = ACTION_TAP_DANCE_FN (eql)
|
|
,[_GRV] = ACTION_TAP_DANCE_FN (grave)
|
|
,[_GT] = ACTION_TAP_DANCE_FN (greater)
|
|
,[_LBRC] = ACTION_TAP_DANCE_FN (lbrace)
|
|
,[_LCBR] = ACTION_TAP_DANCE_FN (lcurly)
|
|
,[_LPRN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lparen, lparen_reset)
|
|
,[_LT] = ACTION_TAP_DANCE_FN (lesser)
|
|
,[_PRIV] = ACTION_TAP_DANCE_FN (private)
|
|
,[_QUOT] = ACTION_TAP_DANCE_FN (quote)
|
|
,[_RBRC] = ACTION_TAP_DANCE_FN (rbrace)
|
|
,[_RCBR] = ACTION_TAP_DANCE_FN (rcurly)
|
|
,[_RNGL] = ACTION_TAP_DANCE_FN (rangle)
|
|
,[_RPRN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, rparen, rparen_reset)
|
|
,[_SEND] = ACTION_TAP_DANCE_FN (send)
|
|
,[_SPC] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, space, space_reset)
|
|
,[_TILD] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, tilde, tilde_reset)
|
|
};
|
|
|
|
// .............................................................. Dynamic Layers
|
|
|
|
#define LEFT 1
|
|
#define RIGHT 2
|
|
static uint8_t thumb = 0;
|
|
|
|
// LEFT (KC_SPC, S(KC_BSLS)), RIGHT (KC_LEFT, S(KC_LEFT)) opposite thumb combinations, see process_record_user()
|
|
// up, up -> _BASE
|
|
// up, down -> _SYMBOL
|
|
// down, up -> _NUMBER
|
|
// down, down -> _MOUSE // see layer keycodes that raise mouse layer
|
|
#define THUMBS_DOWN _MOUSE // layer
|
|
|
|
static uint8_t overlayer = 0;
|
|
|
|
// left right thumb layer combinations
|
|
void thumb_layer(keyrecord_t *record, uint8_t side, uint8_t shift, uint16_t keycode, uint8_t thumb_dn_layer, uint8_t thumb_up_layer)
|
|
{
|
|
if (record->event.pressed) {
|
|
// layer_on via tap_layer(), see process_record_user()
|
|
key_timer = timer_read();
|
|
thumb = thumb | side;
|
|
}
|
|
else {
|
|
layer_off(thumb_dn_layer);
|
|
// opposite thumb_layer() thumb may have switched effective layer!
|
|
if (overlayer) {
|
|
layer_off(overlayer);
|
|
overlayer = 0;
|
|
}
|
|
if (!key_press(shift, keycode)) {
|
|
layer_off(THUMBS_DOWN); // both thumbs needed
|
|
// opposite thumb down? see left right combination layer table above
|
|
if (thumb & (side == LEFT ? RIGHT : LEFT)) {
|
|
layer_on(thumb_up_layer);
|
|
overlayer = thumb_up_layer;
|
|
}
|
|
}
|
|
clear_mods();
|
|
thumb = thumb & ~side;
|
|
key_timer = 0;
|
|
}
|
|
}
|
|
|
|
// #ifdef STENO_ENABLE
|
|
// // LT for steno keycode
|
|
// void stn_layer(keyrecord_t *record, uint16_t keycode, uint8_t layer)
|
|
// {
|
|
// if (record->event.pressed) {
|
|
// key_timer = timer_read();
|
|
// if (keycode) {
|
|
// process_steno(keycode, record);
|
|
// }
|
|
// layer_on(layer);
|
|
// }
|
|
// else {
|
|
// layer_off(layer);
|
|
// if (keycode) {
|
|
// if (timer_elapsed(key_timer) < TAPPING_TERM) {
|
|
// process_steno(keycode, record);
|
|
// }
|
|
// else {
|
|
// // clear pressed state (request push of updated) process_steno.c and .h
|
|
// // steno_clear_state();
|
|
// }
|
|
// }
|
|
// key_timer = 0;
|
|
// }
|
|
// }
|
|
// #endif
|
|
|
|
// LT for S(keycode)
|
|
void lt_shift(keyrecord_t *record, uint16_t keycode, uint8_t layer)
|
|
{
|
|
if (record->event.pressed) {
|
|
key_timer = timer_read();
|
|
layer_on(layer);
|
|
}
|
|
else {
|
|
layer_off(layer);
|
|
// for shifted keycodes, hence, LT_SHIFT
|
|
key_press(SHIFT, keycode);
|
|
clear_mods();
|
|
key_timer = 0;
|
|
}
|
|
}
|
|
|
|
// set layer asap to overcome macro latency errors, notably tap dance and LT usage
|
|
// this routine inexplicably (?) sets layer_on() faster than can be done in thumb_layer()
|
|
void tap_layer(keyrecord_t *record, uint8_t layer)
|
|
{
|
|
if (record->event.pressed) {
|
|
layer_on(layer);
|
|
}
|
|
else {
|
|
layer_off(layer);
|
|
}
|
|
}
|
|
|
|
// ..................................................................... Keymaps
|
|
|
|
// void persistant_default_layer_set(uint16_t default_layer)
|
|
// {
|
|
// eeconfig_update_default_layer(default_layer);
|
|
// default_layer_set (default_layer);
|
|
// }
|
|
|
|
void clear_layers(void)
|
|
{
|
|
uint8_t layer;
|
|
for (layer = 0; layer < _END_LAYERS; layer++) {
|
|
layer_off(layer);
|
|
}
|
|
}
|
|
|
|
#ifdef CENTER_TT
|
|
static uint16_t tt_keycode = 0; // current TT keycode
|
|
|
|
void clear_tt(void)
|
|
{
|
|
if (tt_keycode == KC_CAPS) {
|
|
tap_key(KC_CAPS); // clear capslock
|
|
}
|
|
tt_keycode = 0;
|
|
clear_layers();
|
|
set_single_persistent_default_layer(_BASE);
|
|
}
|
|
#endif
|
|
|
|
// txbolt plover run state
|
|
static uint8_t plover = 0;
|
|
|
|
void base_layer(void)
|
|
{
|
|
#ifdef AUDIO_ENABLE
|
|
if (plover) {
|
|
PLAY_SONG(song_plover_gb);
|
|
}
|
|
else {
|
|
PLAY_SONG(song_qwerty);
|
|
}
|
|
#endif
|
|
clear_layers();
|
|
set_single_persistent_default_layer(_BASE);
|
|
}
|
|
|
|
void toggle_plover(uint8_t state)
|
|
{
|
|
if (plover != state) {
|
|
#ifdef PLOVER_KEYBIND
|
|
#include "plover_keybind.h"
|
|
#endif
|
|
plover = state;
|
|
}
|
|
}
|
|
|
|
void steno(keyrecord_t *record)
|
|
{
|
|
if (record->event.pressed) {
|
|
#ifdef AUDIO_ENABLE
|
|
PLAY_SONG(song_plover);
|
|
#endif
|
|
clear_layers();
|
|
layer_on(_PLOVER);
|
|
if (!eeconfig_is_enabled()) {
|
|
eeconfig_init();
|
|
}
|
|
keymap_config.raw = eeconfig_read_keymap();
|
|
keymap_config.nkro = 1;
|
|
eeconfig_update_keymap(keymap_config.raw);
|
|
if (!plover) {
|
|
toggle_plover(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void steno_exit(keyrecord_t *record)
|
|
{
|
|
if (record->event.pressed) {
|
|
base_layer();
|
|
toggle_plover(0);
|
|
}
|
|
}
|