From 050472a4d07d07c1d9ae17d2fd26d44e9d95d950 Mon Sep 17 00:00:00 2001 From: Eric Gebhart Date: Sat, 12 Nov 2022 00:09:41 +0100 Subject: Eric Gebhart user space and keymaps (#17487) Co-authored-by: Drashna Jaelre --- users/ericgebhart/extensions/accented_keys.c | 50 +++ users/ericgebhart/extensions/accented_keys.h | 19 + users/ericgebhart/extensions/alt_shift.c | 99 ++++ users/ericgebhart/extensions/altlocal_keys.c | 82 ++++ users/ericgebhart/extensions/altlocal_keys.h | 56 +++ users/ericgebhart/extensions/console_key_logger.c | 38 ++ users/ericgebhart/extensions/console_key_logger.h | 19 + users/ericgebhart/extensions/encoders.c | 83 ++++ users/ericgebhart/extensions/encoders.h | 46 ++ users/ericgebhart/extensions/extensions.c | 91 ++++ users/ericgebhart/extensions/extensions.h | 22 + users/ericgebhart/extensions/key_overrides.h | 53 +++ users/ericgebhart/extensions/keycodes.h | 523 ++++++++++++++++++++++ users/ericgebhart/extensions/keymap_combo.h | 139 ++++++ users/ericgebhart/extensions/mod_lock.c | 81 ++++ users/ericgebhart/extensions/mod_lock.h | 39 ++ users/ericgebhart/extensions/not_dead.c | 36 ++ users/ericgebhart/extensions/nshot_mod.c | 154 +++++++ users/ericgebhart/extensions/nshot_mod.h | 45 ++ users/ericgebhart/extensions/oneshot.c | 217 +++++++++ users/ericgebhart/extensions/oneshot.h | 37 ++ users/ericgebhart/extensions/process_locales.h | 29 ++ users/ericgebhart/extensions/process_nshot.h | 21 + users/ericgebhart/extensions/process_smart_lock.h | 19 + users/ericgebhart/extensions/quick_tap.c | 37 ++ users/ericgebhart/extensions/send_string.c | 40 ++ users/ericgebhart/extensions/smart_lock.c | 117 +++++ users/ericgebhart/extensions/smart_lock.h | 103 +++++ users/ericgebhart/extensions/swapper.c | 58 +++ users/ericgebhart/extensions/swapper.h | 37 ++ users/ericgebhart/extensions/tap_dances.c | 277 ++++++++++++ users/ericgebhart/extensions/tap_dances.h | 19 + users/ericgebhart/extensions/tap_hold.c | 165 +++++++ users/ericgebhart/extensions/tap_hold.h | 20 + users/ericgebhart/extensions/unicode.c | 34 ++ users/ericgebhart/extensions/unicode.h | 24 + 36 files changed, 2929 insertions(+) create mode 100644 users/ericgebhart/extensions/accented_keys.c create mode 100644 users/ericgebhart/extensions/accented_keys.h create mode 100644 users/ericgebhart/extensions/alt_shift.c create mode 100644 users/ericgebhart/extensions/altlocal_keys.c create mode 100644 users/ericgebhart/extensions/altlocal_keys.h create mode 100644 users/ericgebhart/extensions/console_key_logger.c create mode 100644 users/ericgebhart/extensions/console_key_logger.h create mode 100644 users/ericgebhart/extensions/encoders.c create mode 100644 users/ericgebhart/extensions/encoders.h create mode 100644 users/ericgebhart/extensions/extensions.c create mode 100644 users/ericgebhart/extensions/extensions.h create mode 100644 users/ericgebhart/extensions/key_overrides.h create mode 100755 users/ericgebhart/extensions/keycodes.h create mode 100644 users/ericgebhart/extensions/keymap_combo.h create mode 100644 users/ericgebhart/extensions/mod_lock.c create mode 100644 users/ericgebhart/extensions/mod_lock.h create mode 100644 users/ericgebhart/extensions/not_dead.c create mode 100644 users/ericgebhart/extensions/nshot_mod.c create mode 100644 users/ericgebhart/extensions/nshot_mod.h create mode 100644 users/ericgebhart/extensions/oneshot.c create mode 100644 users/ericgebhart/extensions/oneshot.h create mode 100644 users/ericgebhart/extensions/process_locales.h create mode 100644 users/ericgebhart/extensions/process_nshot.h create mode 100644 users/ericgebhart/extensions/process_smart_lock.h create mode 100644 users/ericgebhart/extensions/quick_tap.c create mode 100644 users/ericgebhart/extensions/send_string.c create mode 100644 users/ericgebhart/extensions/smart_lock.c create mode 100644 users/ericgebhart/extensions/smart_lock.h create mode 100644 users/ericgebhart/extensions/swapper.c create mode 100644 users/ericgebhart/extensions/swapper.h create mode 100755 users/ericgebhart/extensions/tap_dances.c create mode 100755 users/ericgebhart/extensions/tap_dances.h create mode 100644 users/ericgebhart/extensions/tap_hold.c create mode 100644 users/ericgebhart/extensions/tap_hold.h create mode 100644 users/ericgebhart/extensions/unicode.c create mode 100644 users/ericgebhart/extensions/unicode.h (limited to 'users/ericgebhart/extensions') diff --git a/users/ericgebhart/extensions/accented_keys.c b/users/ericgebhart/extensions/accented_keys.c new file mode 100644 index 0000000000..2569bffea8 --- /dev/null +++ b/users/ericgebhart/extensions/accented_keys.c @@ -0,0 +1,50 @@ +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ + +#include USERSPACE_H +#include "accented_keys.h" +#include +#include + +static inline void tap_accented_letter(uint16_t letter, uint16_t dead_key) { + uint8_t mod_state = get_mods(); + uint8_t oneshot_mod_state = get_oneshot_mods(); + del_mods(MOD_MASK_SHIFT); + del_oneshot_mods(MOD_MASK_SHIFT); + tap_code16(dead_key); + set_mods(mod_state); + set_oneshot_mods(oneshot_mod_state); + tap_code(letter); +} + +#undef ACCENTED +#define ACCENTED(KC, K1, DEAD_KEY) \ + case KC: \ + if (record->event.pressed) { \ + tap_accented_letter(K1, DEAD_KEY); \ + } \ + return false; + + +bool process_accent_keys(uint16_t keycode, keyrecord_t* record) { + switch(keycode){ +#ifdef ACCENTED_KEYS_ENABLE +#include "accented_keys.def" +#endif + } + return true; +} diff --git a/users/ericgebhart/extensions/accented_keys.h b/users/ericgebhart/extensions/accented_keys.h new file mode 100644 index 0000000000..017c6fa312 --- /dev/null +++ b/users/ericgebhart/extensions/accented_keys.h @@ -0,0 +1,19 @@ +#pragma once +/* + Copyright 2018 Eric Gebhart + + 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 . +*/ + +bool process_accent_keys(uint16_t keycode, keyrecord_t* record); diff --git a/users/ericgebhart/extensions/alt_shift.c b/users/ericgebhart/extensions/alt_shift.c new file mode 100644 index 0000000000..002adec230 --- /dev/null +++ b/users/ericgebhart/extensions/alt_shift.c @@ -0,0 +1,99 @@ +#include USERSPACE_H +#include +#include + +bool shift_for_two(uint16_t keycode, keyrecord_t *record){ + uint16_t mod_state = get_mods(); + + bool is_shifted = (get_mods() & MOD_MASK_SHIFT) || + (get_oneshot_mods() & MOD_MASK_SHIFT); + + if(record ->event.pressed) { + // If shifted, double these common punctuation marks. + if(is_shifted){ + // clear shift temporarily + del_mods(MOD_MASK_SHIFT); + del_oneshot_mods(MOD_MASK_SHIFT); + + tap_code16(keycode); + tap_code16(keycode); + + // restore previous shift state + set_mods(mod_state); + return false; + } + } + return true; +} + +bool shift_for_three(uint16_t keycode, keyrecord_t *record){ + uint16_t mod_state = get_mods(); + + bool is_shifted = (get_mods() & MOD_MASK_SHIFT) || + (get_oneshot_mods() & MOD_MASK_SHIFT); + + if(record ->event.pressed) { + // If shifted, double these common punctuation marks. + if(is_shifted){ + // clear shift temporarily + del_mods(MOD_MASK_SHIFT); + del_oneshot_mods(MOD_MASK_SHIFT); + + tap_code16(keycode); + tap_code16(keycode); + tap_code16(keycode); + + // restore previous shift state + set_mods(mod_state); + return false; + } + } + return true; + } + +bool override_shift(uint16_t keycode, + uint16_t shift_keycode, + keyrecord_t *record + ) { + + bool is_shifted = (get_mods() & MOD_MASK_SHIFT) || + (get_oneshot_mods() & MOD_MASK_SHIFT); + + if (record->event.pressed) { + if (is_shifted) { + uint8_t mod_state = get_mods(); + del_mods(MOD_MASK_SHIFT); + del_oneshot_mods(MOD_MASK_SHIFT); + + tap_code16(shift_keycode); + + set_mods(mod_state); + } else { + //tap_code16(keycode); + } + } + return false; +} + +// macros for use in alt_shift.defs. +#define ALT_SHIFT(KCKEY, KC01) \ + case KCKEY: \ + return override_shift(KCKEY, KC01, record); \ + break; + +#define SHIFT_FOR_2(KCKEY) \ + case KCKEY: \ + return shift_for_two(KCKEY, record); \ + break; + +#define SHIFT_FOR_3(KCKEY) \ + case KCKEY: \ + return shift_for_three(KCKEY, record); \ + break; + +bool process_alt_shift_user(uint16_t keycode, keyrecord_t *record) { + switch(keycode){ +#include "alt_shift.def" + } + return true; +} diff --git a/users/ericgebhart/extensions/altlocal_keys.c b/users/ericgebhart/extensions/altlocal_keys.c new file mode 100644 index 0000000000..569a2076b5 --- /dev/null +++ b/users/ericgebhart/extensions/altlocal_keys.c @@ -0,0 +1,82 @@ +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +// Create custom keycodes with arbitrary shifted and unshifted keys. +// originally for dvorak on bepo. But used by beakl on qwerty now too. + +// Why?: Because the keycodes are actually defined on the computer. So +// if you are trying to have dvorak, or beakl on bepo-fr, the shifted keys +// are wrong. But, I want my dvorak, so this allows the pairing of keys into +// a keycode that has shifted and non shifted behavior, outside of what the +// locale map says on the computer. +// +// These are the keys for dvorak on bepo. column one is the keycode and mods for +// the unshifted key, the second column is the keycode and mods for the shifted key. +// GR is Good Range. It subtracts SAFE_RANGE from the keycode so we can make a +// reasonably sized array without difficulties. The macro is for the constant declarations +// the function is for when we use it. + +//make an alt_local_keys.def - see the example. +// Include this file where you have your process_record_user function, +// call process_alt_local_key inside your process_record_user. + +#include USERSPACE_H +#include "altlocal_keys.h" + +const uint16_t key_translations[][2][2] = { +#include "altlocal_keys.def" +}; + +uint8_t gr(uint16_t kc){ + return (kc - SAFE_RANGE); +} + +// send the right keycode for the right mod. +// remove the mods we are taking care of, +// send our keycodes then restore them. +// all so we can make dvorak keys from bepo keycodes. +void send_keycode(uint16_t kc){ + uint8_t tmp_mods = get_mods(); + bool is_shifted = ( tmp_mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) ); + + // need to turn of the shift if it is on. + unregister_mods((MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT))); + if(is_shifted){ + register_mods(SHIFTED_MODS(kc)); + register_code16(SHIFTED_KEY(kc)); + unregister_code16(SHIFTED_KEY(kc)); + unregister_mods(SHIFTED_MODS(kc)); + } else{ + register_mods(UNSHIFTED_MODS(kc)); + register_code16(UNSHIFTED_KEY(kc)); + unregister_code16(UNSHIFTED_KEY(kc)); + unregister_mods(UNSHIFTED_MODS(kc)); + } + clear_mods(); + register_mods(tmp_mods); +} + +bool process_alt_local_key(uint16_t keycode, keyrecord_t* record) { + switch(keycode){ + case ALT_LOCAL_KEYS_START ... ALT_LOCAL_KEYS_END: + if(record->event.pressed) + send_keycode(keycode); + unregister_code(keycode); + break; + } + return (true); +} diff --git a/users/ericgebhart/extensions/altlocal_keys.h b/users/ericgebhart/extensions/altlocal_keys.h new file mode 100644 index 0000000000..8e30472081 --- /dev/null +++ b/users/ericgebhart/extensions/altlocal_keys.h @@ -0,0 +1,56 @@ +#pragma once +/* + Copyright 2018 Eric Gebhart + + 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 . +*/ + +// Create custom keycodes with arbitrary shifted and unshifted keys. +// originally for dvorak on bepo. But used by beakl on qwerty now too. + +// Why?: Because the keycodes are actually defined on the computer. So +// if you are trying to have dvorak, or beakl on bepo-fr, the shifted keys +// are wrong. But, I want my dvorak, so this allows the pairing of keys into +// a keycode that has shifted and non shifted behavior, outside of what the +// locale map says on the computer. +// +// These are the keys for dvorak on bepo. column one is the keycode and mods for +// the unshifted key, the second column is the keycode and mods for the shifted key. +// GR is Good Range. It subtracts SAFE_RANGE from the keycode so we can make a +// reasonably sized array without difficulties. The macro is for the constant declarations +// the function is for when we use it. + +//make an alt_local_keys.def - see the example. +// Include this file where you have your process_record_user function, +// call process_alt_local_key inside your process_record_user. + +uint8_t gr(uint16_t); +void send_keycode(uint16_t); +bool process_alt_local_key(uint16_t keycode, keyrecord_t* record); + +#define MOD_NONE 0x00 + +#define GR(x) (x-SAFE_RANGE) +// indexs for the keycode translation table. + +#define MK_KEY(KCNAME, KC1, MOD1, KC2, MOD2) \ + [GR(KCNAME)] = {{KC1, MOD1}, {KC2, MOD2}}, + +#define MK_SKEY(KCNAME, KC1, KC2) \ + [GR(KCNAME)] = {{KC1, MOD_NONE}, {KC2, MOD_NONE}}, + +#define UNSHIFTED_KEY(key) key_translations[gr(key)][0][0] +#define UNSHIFTED_MODS(key) key_translations[gr(key)][0][1] +#define SHIFTED_KEY(key) key_translations[gr(key)][1][0] +#define SHIFTED_MODS(key) key_translations[gr(key)][1][1] diff --git a/users/ericgebhart/extensions/console_key_logger.c b/users/ericgebhart/extensions/console_key_logger.c new file mode 100644 index 0000000000..074673bd06 --- /dev/null +++ b/users/ericgebhart/extensions/console_key_logger.c @@ -0,0 +1,38 @@ +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#if defined( CONSOLE_ENABLE) && defined(CONSOLE_KEY_LOGGER_ENABLE) + +#include USERSPACE_H +#include "print.h" +#include "console_key_logger.h" + +void process_console_key_logger(uint16_t keycode, keyrecord_t *record) { + if (record->event.pressed) { + uprintf("0x%04X,%u,%u,%u,%b,0x%02X,0x%02X,%u\n", + keycode, + record->event.key.row, + record->event.key.col, + get_highest_layer(layer_state), + record->event.pressed, + get_mods(), + get_oneshot_mods(), + record->tap.count + ); + } +} +#endif diff --git a/users/ericgebhart/extensions/console_key_logger.h b/users/ericgebhart/extensions/console_key_logger.h new file mode 100644 index 0000000000..5e7e2d5bc0 --- /dev/null +++ b/users/ericgebhart/extensions/console_key_logger.h @@ -0,0 +1,19 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +void process_console_key_logger(uint16_t keycode, keyrecord_t *record); diff --git a/users/ericgebhart/extensions/encoders.c b/users/ericgebhart/extensions/encoders.c new file mode 100644 index 0000000000..9a3d90b82f --- /dev/null +++ b/users/ericgebhart/extensions/encoders.c @@ -0,0 +1,83 @@ +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ +#ifdef ENCODER_ENABLE +#include "encoders.h" +#include USERSPACE_H + +encoder_action_t encoder_actions[] = { +#include "encoders.def" +}; +uint8_t NUM_ENCODER_ACTIONS = sizeof(encoder_actions) / sizeof(encoder_action_t); + + +bool encoder_update_user(uint8_t index, bool clockwise) { + // do it twice, once for layer actions, once for non layer specific actions. + if (!do_encoder_action(index, clockwise, true)){ + do_encoder_action(index, clockwise, false); + } + return false; +} + +bool do_encoder_action(uint8_t index, bool clockwise, bool layer_actions) { + uint8_t mods = get_mods(); + encoder_action_t *action; + + // look for a match. + // on the layer, not on any layer. + // with the mods, or no mods. + for (int i = 0; i < NUM_ENCODER_ACTIONS; ++i) { + action = &encoder_actions[i]; + + // this encoder, or another. + if (action->index != index) + continue; + + // skip non layer specific actions and visa versa + // two pass system, once for layers, again for + // actions without layers. + if (layer_actions){ + if (action->layer == LAYER_NONE || + action->layer != biton32(layer_state)){ + continue; + } + }else if (action->layer != LAYER_NONE) + continue; + + // no mods, or these mods. + if ((mods && (action->mods == MOD_NONE)) || + (mods && (mods != action->mods))) + continue; + + // found one. + if (clockwise) { + if (action->clockwise != 0) { + tap_code16(action->clockwise); + } else if (action->cw_func != NULL) { + action->cw_func(); + } + } else { + if (action->counter_clockwise != 0) { + tap_code16(action->counter_clockwise); + } else if (action->ccw_func != NULL) { + action->ccw_func(); + } + } + } + return false; +} + +#endif diff --git a/users/ericgebhart/extensions/encoders.h b/users/ericgebhart/extensions/encoders.h new file mode 100644 index 0000000000..458c5c541d --- /dev/null +++ b/users/ericgebhart/extensions/encoders.h @@ -0,0 +1,46 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#include QMK_KEYBOARD_H + +typedef struct { + uint16_t layer; + uint16_t index; // 0 or 1, left/right. + uint16_t clockwise; + uint16_t counter_clockwise; + uint16_t mods; + void (*cw_func)(void); + void (*ccw_func)(void); +} encoder_action_t; +extern encoder_action_t encoder_actions[]; +extern uint8_t NUM_ENCODER_ACTIONS; + +// haven't looked at the real values for index, but I know +// 0 and 1 are left and right on my kyria. +#define LEFT 0 +#define RIGHT 1 +#define LAYER_NONE -1 +#define MOD_NONE 0x00 + +#define ENCODER_ACTION(LAYER, INDEX, CW_KC, CCW_KC, MOD) \ + {LAYER, INDEX, CW_KC, CCW_KC, MOD, NULL, NULL}, + +#define ENCODER_FUNCTION(LAYER, INDEX, CW_FUNC, CCW_FUNC, MOD) \ + {LAYER, INDEX, 0, 0, MOD, CW_FUNC, CCW_FUNC}, + +bool do_encoder_action(uint8_t index, bool clockwise, bool layer_actions); diff --git a/users/ericgebhart/extensions/extensions.c b/users/ericgebhart/extensions/extensions.c new file mode 100644 index 0000000000..f71e615a00 --- /dev/null +++ b/users/ericgebhart/extensions/extensions.c @@ -0,0 +1,91 @@ +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#include USERSPACE_H + +#include "extensions.h" +#include "keymap_combo.h" +#include "altlocal_keys.h" +#include "tap_hold.h" +#include "accented_keys.h" +#include "process_smart_lock.h" +#include "mod_lock.h" +#include "oneshot.h" +#include "process_nshot.h" +#include "process_locales.h" +#include "unicode.h" +#include "key_overrides.h" +#include "console_key_logger.h" + +// should make header files maybe. being lazy. +void process_not_dead(uint16_t keycode, keyrecord_t *record); +bool process_alt_shift_user(uint16_t keycode, keyrecord_t *record); +void process_send_strs(uint16_t keycode, keyrecord_t *record); +//bool process_alt_local_key(uint16_t keycode, keyrecord_t* record); +bool process_global_quick_tap(uint16_t keycode, keyrecord_t *record); + +// call this from the top of process records before the switch. + +bool process_extensions(uint16_t keycode, keyrecord_t *record){ + if (!process_locales(keycode, record)) { return false; } + +#ifdef GLOBAL_QUICK_TAP_ENABLE + if (!process_global_quick_tap(keycode, record)) {return false; } +#endif +#ifdef CAPS_WORD_ENABLE + if (!process_caps_word(keycode, record)) { return false; } +#endif +#ifdef ALT_LOCAL_ENABLE + if (!process_alt_local_key(keycode, record)) { return false; } +#endif +#ifdef ACCENTED_KEYS_ENABLE + if (!process_accent_keys(keycode, record)) { return false; } +#endif +#ifdef TAP_HOLD_ENABLE + process_tap_hold_user(keycode, record); +#endif +#ifdef SMART_LOCK_ENABLE + process_smart_lock(keycode, record); +#endif +#ifdef MOD_LOCK_ENABLE + process_mod_lock(keycode, record); +#endif +#ifdef NSHOT_ENABLE + if(!process_nshot_state(keycode, record)) {return false;} +#endif +#ifdef SEND_UNICODE_ENABLE + process_unicode_strs(keycode, record); +#endif +#ifdef SEND_STRING_ENABLE + process_send_strs(keycode, record); +#endif +#ifdef NOT_DEAD_ENABLE + process_not_dead(keycode, record); +#endif +#ifdef ALT_SHIFT_ENABLE + if(!process_alt_shift_user(keycode, record)) {return false;} +#endif +#if defined( CONSOLE_ENABLE) && defined(CONSOLE_KEY_LOGGER_ENABLE) + process_console_key_logger(keycode, record); +#endif +#ifdef ONESHOT_MOD_ENABLE + int8_t keycode_consumed = 0; + keycode_consumed += update_oneshot_modifiers(keycode, record, keycode_consumed); +#endif + return true; + +} diff --git a/users/ericgebhart/extensions/extensions.h b/users/ericgebhart/extensions/extensions.h new file mode 100644 index 0000000000..899dbdd3d6 --- /dev/null +++ b/users/ericgebhart/extensions/extensions.h @@ -0,0 +1,22 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +bool process_extensions(uint16_t keycode, keyrecord_t *record); + +#define PROCESS_EXTENSIONS \ + if (!process_extensions(keycode, record)) {return false;} diff --git a/users/ericgebhart/extensions/key_overrides.h b/users/ericgebhart/extensions/key_overrides.h new file mode 100644 index 0000000000..3fb0c9a5bb --- /dev/null +++ b/users/ericgebhart/extensions/key_overrides.h @@ -0,0 +1,53 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ +#ifdef KEY_OVERRIDE_ENABLE + +#define KO_NAME(name, ...) &name, +#define KO_T(name) const key_override_t name + +#undef KOL +#define KOL(name, mods, modded_key, replacement, layer) \ + KO_T(name) = ko_make_with_layers(mods, modded_key, replacement, (1 << layer)); + +#define KO(name, mods, key, replacement) \ + KO_T(name) = ko_make_basic(mods, key, replacement) + +#define KOLN(name, mods, key, replacement, layers, neg_mods) \ + KO_T(name) = ko_make_with_layers_and_negmods(mods, key, replacement, layers, neg_mods) + +#define KOLNO(name, mods, key, replacement, layers, neg_mods, options) \ + KO_T(name) = ko_make_with_layers_negmods_and_options \ + (mods, key, replacement, layers, neg_mods, options) + +#include "key_overrides.def" + +#undef KO +#undef KOL +#undef KOLN +#undef KOLNO +#define KO KO_NAME +#define KOL KO_NAME +#define KOLN KO_NAME +#define KOLNO KO_NAME + +// This globally defines all key overrides to be used +const key_override_t **key_overrides = (const key_override_t *[]){ +#include "key_overrides.def" + NULL // Null terminate the array of overrides! +}; +#endif diff --git a/users/ericgebhart/extensions/keycodes.h b/users/ericgebhart/extensions/keycodes.h new file mode 100755 index 0000000000..a3c5d72a09 --- /dev/null +++ b/users/ericgebhart/extensions/keycodes.h @@ -0,0 +1,523 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#include "quantum.h" +#include "process_keycode/process_tap_dance.h" +#include "eeconfig.h" +#include "keymap_bepo.h" +//#include "keymap_us_international.h" +#include "keymap_us_international_linux.h" +#include "lang.h" +#include "ericgebhart.h" + +//#define ONESHOT_TAP_TOGGLE 2 /* Tapping this number of times holds the key until tapped once again. */ + +// #define DEFAULT_LANG EN // US_INT // EN, BEPO, US_INT, EURkey + +#define KEY_NAME(NAME, ...) NAME, +#define BLANK(...) + +bool process_record_secrets(uint16_t keycode, keyrecord_t *record); + +enum userspace_custom_keycodes { + // Get all the custom keys from the defs if we can. + ALT_LOCAL_KEYS_START = SAFE_RANGE, +#ifdef ALT_LOCAL_ENABLE +#undef MK_KEY +#define MK_KEY KEY_NAME +#undef MK_SKEY +#define MK_SKEY KEY_NAME +#include "altlocal_keys.def" +#undef MK_KEY +#undef MK_SKEY +#endif + ALT_LOCAL_KEYS_END, + +#ifdef ACCENTED_KEYS_ENABLE +#undef ACCENTED +#define ACCENTED KEY_NAME +#include "accented_keys.def" +#undef ACCENTED +#endif + +#ifdef TAP_HOLD_ENABLE +#undef TP_TPL +#define TP_TPL KEY_NAME +#undef TP_SML +#define TP_SML KEY_NAME +#undef OPEN_OCL +#define OPEN_OCL KEY_NAME +#undef OPEN_OCL_ND +#define OPEN_OCL_ND KEY_NAME +#include "tap_hold.def" +#undef OPEN_OCL +#undef OPEN_OCL_ND +#undef TP_TPL +#undef TP_SML +#endif + +#ifdef UNICODE_ENABLE +#undef UC_STR +#define UC_STR KEY_NAME +#include "unicode.def" +#undef UC_STR +#endif + +#ifdef SEND_STRING_ENABLE +#undef SEND_STR +#define SEND_STR KEY_NAME +#undef SEND_STR_DELAY +#define SEND_STR_DELAY KEY_NAME +#include "send_string.def" +#undef SEND_STR +#undef SEND_STR_DELAY +#endif + +#ifdef SMART_LOCK_ENABLE +#undef SMLM +#define SMLM KEY_NAME +#undef SMLL +#define SMLL KEY_NAME +#include "smart_lock.def" +#undef SMLM +#undef SMLL +#endif + +#ifdef MOD_LOCK_ENABLE +#undef IGNORE_KC +#define IGNORE_KC BLANK +#undef MODL +#define MODL KEY_NAME +#include "mod_lock.def" +#undef IGNORE_KC +#undef MODL +#endif + + +#undef IGNORE_KEY +#define IGNORE_KEY BLANK +#undef CANCEL_KEY +#define CANCEL_KEY BLANK +#undef ONESHOT +#undef NSHOT +#define ONESHOT KEY_NAME +#define NSHOT KEY_NAME + +#ifdef NSHOT_ENABLE +#include "nshot.def" +#else + TS_RCTL, + TS_LCTL, +#endif + +#ifdef ONESHOT_MOD_ENABLE +#include "oneshot.def" +#endif + +#undef IGNORE_KEY +#undef CANCEL_KEY +#undef ONESHOT +#undef NSHOT + +#ifdef SWAPPER_ENABLE +#undef SWAPPER_KEY +#define SWAPPER_KEY KEY_NAME +#include "swapper.def" +#undef SWAPPER_KEY +#endif + +#ifdef NOT_DEAD_ENABLE +#undef NOT_DEAD +#define NOT_DEAD KEY_NAME +#include "not_dead.def" +#undef NOT_DEAD +#endif + +#include "custom_keys.def" + NEW_SAFE_RANGE +}; + +#define FIRST_LAYER (BEGINNING_OF_BASE_LAYERS + 1) + +#define TL_DQUO TLKC(_DQUO) +#define TL_QUOT TLKC(_QUOT) +#define TL_COMM TLKC(_COMM) +#define TL_DOT TLKC(_DOT) +#define TL_SCLN TLKC(_SCLN) +#define TL_SLSH TLKC(_SLSH) +#define TL_EXLM TLKC(_EXLM) +#define TL_MINS TLKC(_MINS) +#define TL_LPRN TLKC(_LPRN) +#define TL_LCBR TLKC(_LCBR) +#ifdef SYMBOL_LAYER_ENABLE +#define TL_DOT_SYMB LT(LN_SYMB, LANG_KC(TL_DOT)) +#endif + + +#define BP_LT BP_LABK +#define BP_GT BP_RABK +#define BP_TAB KC_TAB +#define US_GT US_RABK +#define US_LT US_LABK +#define US_TAB KC_TAB +#define US_DCMM KC_COMM // us doesn't have this dead key. + +// this is odd, there is interplay between this and +// the not-dead extension. - and tap-hold not-dead. +#undef US_TILD +#define US_TILD KC_TILD +// redefine us_circ so we actually get a circ. +#undef US_CIRC +#define US_CIRC KC_CIRC +#define US_EQUAL KC_EQUAL +// redefine us_quote so we actually get a quote. +#undef US_QUOT +#define US_QUOT KC_QUOT + +#define US_PRINT_SCREEN KC_PRINT_SCREEN +#define US_SCROLL_LOCK KC_SCROLL_LOCK +#define US_PAUSE KC_PAUSE +#define BP_PRINT_SCREEN KC_PRINT_SCREEN +#define BP_SCROLL_LOCK KC_SCROLL_LOCK +#define BP_PAUSE KC_PAUSE + +#define BP_F1 KC_F1 +#define BP_F2 KC_F2 +#define BP_F3 KC_F3 +#define BP_F4 KC_F4 +#define BP_F5 KC_F5 +#define BP_F6 KC_F6 +#define BP_F7 KC_F7 +#define BP_F8 KC_F8 +#define BP_F9 KC_F9 +#define BP_F10 KC_F10 +#define BP_F11 KC_F11 +#define BP_F12 KC_F12 +#define BP_TRNS KC_TRNS + +#define US_F1 KC_F1 +#define US_F2 KC_F2 +#define US_F3 KC_F3 +#define US_F4 KC_F4 +#define US_F5 KC_F5 +#define US_F6 KC_F6 +#define US_F7 KC_F7 +#define US_F8 KC_F8 +#define US_F9 KC_F9 +#define US_F10 KC_F10 +#define US_F11 KC_F11 +#define US_F12 KC_F12 +#define US_TRNS KC_TRNS + +#ifdef KEYPAD_LAYER_ENABLE +#define TT_KEYPAD TT(LANG_N(_KEYPAD)) +#define MO_KEYPAD MO(LANG_N(_KEYPAD)) +#else +#define TT_KEYPAD ___ +#define MO_KEYPAD ___ +#endif + +#ifdef SYMBOL_LAYER_ENABLE +#define TT_SYMB TT(LANG_N(_SYMB)) +#define MO_SYMB MO(LANG_N(_SYMB)) +#define OSL_SYMB OSL(LANG_N(_SYMB)) +#else +#define TT_SYMB ___ +#define MO_SYMB ___ +#define OSL_SYMB ___ +#endif + +#ifdef TOPROWS_LAYER_ENABLE +#define TT_TOPROWS TT(LANG_N(_TOPROWS)) +#define MO_TOPROWS MO(LANG_N(_TOPROWS)) +#else +#define TT_TOPROWS ___ +#define MO_TOPROWS ___ +#endif + +#ifdef RGB_LAYER_ENABLE +#define MO_RGB MO(_RGB) +#else +#define MO_RGB ___ +#endif + +#ifdef ADJUST_LAYER_ENABLE +#define MO_ADJUST MO(_ADJUST) +#else +#define MO_ADJUST ___ +#endif + +#ifdef ACCENTS_MORTE_LAYER_ENABLE +//#define LN_ACCENTS_MORTE LANG_N(_ACCENTS_MORTE) +#define OSL_ACCENTS_MORTE OSL(LANG_N(_ACCENTS_MORTE)) +#else +#define OSL_ACCENTS_MORTE ___ +#endif + +#ifdef ACCENTS_LAYER_ENABLE +#define LN_ACCENTS LANG_N(_ACCENTS) +#define OSL_ACCENTS OSL(LN_ACCENTS) +#else +#define OSL_ACCENTS ___ +#endif + +#ifdef MORTE_LAYER_ENABLE +#define LN_MORTE LANG_N(_MORTE) +#define OSL_MORTE OSL(LN_MORTE) +#else +#define OSL_MORTE ___ +#endif + +#define CTLGUI_T(kc) MT(MOD_LGUI | MOD_LCTL, kc) +#define SFTGUI_T(kc) MT(MOD_LGUI | MOD_LSFT, kc) +#define ALTGUI_T(kc) MT(MOD_LGUI | MOD_LALT, kc) + +#define ALT_ENT ALGR_T(KC_ENT) // Alt oor nter +#define CTL_ENT CTL_T(KC_ENT) // ctrl or space +#define CTL_SPC CTL_T(KC_SPC) // ctrl or space +#define CTL_BSPC CTL_T(KC_BSPC) // ctrl or backspace +#define ALT_DEL ALT_T(KC_DEL) // Alt or delete +#define GUI_ESC GUI_T(KC_ESC) // Gui or escape +#define ALGR_SYMB ALGR_T(TG(LANG_N(_SYMB))) // Alt gre or toggle symbol layer + +// one shot on tap, or hold like usual +#define OSLCTL_CTL CTL_T(OS_LCTL) +#define OSLSFT_SFT SFT_T(OS_LSFT) +#define OSLALT_ALT ALT_T(OS_LALT) +#define OSLGUI_GUI GUI_T(OS_LGUI) + +/* miryoku */ +/* esc_media, space_navnm, tab_navm, ENT_SYM, BSPC_TOPR, del_fun */ +/* hands down */ +/* TL_COMM, TL_DOT_SYMB, GUI_ESC, ALT_ENT, SPC_TOPR, BSPC */ + +// Lots of LT options. My thumb keys. +#ifdef TOPROWS_LAYER_ENABLE +#define LN_TOPROWS LANG_N(_TOPROWS) +#else +#define LN_TOPROWS KC_NO +#endif + +#ifdef SYMBOL_LAYER_ENABLE +# define LN_SYMB LANG_N(_SYMB) +# define TH_LTR_SYM LT(LN_SYMB, THUMB_LETTER) +#else +# define TH_LTR_SYM THUMB_LETTER +#endif + +#define TH_LTR_NAV LT(_NAV, THUMB_LETTER) + +#define LN_KEYPAD LANG_N(_KEYPAD) + +#define ACCENTS_RALT MT(MOD_RALT, OSL_ACCENTS) +#define ACCENTS_CTL MT(MOD_LCTL, OSL_ACCENTS) +#define ENT_SYM LT(LN_SYMB, KC_ENT) +#define ENT_NAV LT(_NAV, KC_ENT) +#define ENT_TOPR LT(LN_TOPROWS, KC_ENT) + +#define ESC_TOPR LT(LN_TOPROWS, KC_ESC) +#define ESC_SYMB LT(LN_SYMB, KC_ESC) +#define ESC_NUM LT(LN_KEYPAD, KC_ESC) +#define ESC_MEDIA LT(_MEDIA, KC_ESC) + +#define DEL_FUN LT(_FUN, KC_DEL) +#define TAB_NAVM LT(_NAVm, KC_TAB) +#define TAB_NUM LT(LN_KEYPAD, KC_TAB) +#define I_SYMB LT(LN_SYMB, KC_I) + +#define SPC_NAVm LT(_NAVm, KC_SPC) +#define SPC_NAVnm LT(_NAVnm, KC_SPC) +#define SPC_NAV LT(_NAV, KC_SPC) +#define SPC_SYMB LT(LN_SYMB, KC_SPC) +#define SPC_TOPR LT(LN_TOPROWS, KC_SPC) +#define SPC_LAYR LT(_LAYERS, KC_SPC) +#define SPC_ADJ LT(_ADJUST, KC_SPC) +#define SPC_NUM LT(LN_KEYPAD, KC_SPC) + +#define BSPC_NAVm LT(_NAVm, KC_BSPC) +#define BSPC_NAV LT(_NAV, KC_BSPC) +#ifdef SYMBOL_LAYER_ENABLE +#define BSPC_SYMB LT(LN_SYMB, KC_BSPC) +#else +#define BSPC_SYMB KC_BSPC +#endif +#define BSPC_TOPR LT(LN_TOPROWS, KC_BSPC) +#define BSPC_NUM LT(LN_KEYPAD, KC_BSPC) +#define BSPC_ALT MT(MOD_LALT, KC_BSPC) +#define BSPC_MEDIA LT(_MEDIA, KC_BSPC) + +#define KC_BKTAB LSFT(KC_TAB) + +// layer toggles +#define LAYER_OSL OSL(_LAYERS) +#define SYM_OSL OSL(LN_SYMB) +#define SYM_TG TG(LN_SYMB) +#define SYM_MO MO(LN_SYMB) +#define NAV_TG TG(_NAV) +#define COMBO_REF_TG_EN TG(_COMBO_REF) +#define NUM_OSL OSL(LN_KEYPAD) +#define NUM_TO TO(LN_KEYPAD) +#define FUN_OSL OSL(LN_FUNC) +#define SYS_OSL OSL(LN_SYSTEM) +#define SYS_TG TG(LN_SYSTEM) + +// Shortcuts +#define S_CUT S(KC_DEL) +#define S_COPY C(KC_INS) +#define S_PASTE S(KC_INS) +#define S_UNDO C(KC_Z) +#define S_REDO C(KC_Y) +#define S_SAVE C(KC_S) +#define S_ALL C(KC_A) +#define S_BACK A(KC_LEFT) +#define S_FWD A(KC_RIGHT) +#define C_BSPC C(KC_BSPC) +#define SCREEN S(C(KC_PSCR)) + +// One Shot Mods keycodes, +#define KC_MLSF OSM(MOD_LSFT) +#define KC_MRSF OSM(MOD_RSFT) +#define OS_LGUI OSM(MOD_LGUI) +#define OS_RGUI OSM(MOD_RGUI) +#define OS_LSFT OSM(MOD_LSFT) +#define OS_RSFT OSM(MOD_RSFT) +#define OS_LCTL OSM(MOD_LCTL) +#define OS_RCTL OSM(MOD_RCTL) +#define OS_LALT OSM(MOD_LALT) +#define OS_RALT OSM(MOD_RALT) +#define ALT_APP ALT_T(KC_APP) + +#define MG_NKRO MAGIC_TOGGLE_NKRO + +#define UC_IRNY UC(0x2E2E) +#define UC_CLUE UC(0x203D) + + +//// TAP DANCE + +typedef struct { + bool is_press_action; + int state; +} tdtap; + +enum { + SINGLE_TAP = 1, + SINGLE_HOLD = 2, + DOUBLE_TAP = 3, + DOUBLE_HOLD = 4, + DOUBLE_SINGLE_TAP = 5, //send two single taps + TRIPLE_TAP = 6, + TRIPLE_HOLD = 7 +}; + +//Tap Dance Declarations +enum { + TD_ESC_CAPS = 0, + TD_TAB_BKTAB = 1, + TD_MDIA_SYMB = 2, + TD_HOME_END = 3, + TD_XMONAD_ESC = 4, + TD_DEF_LAYER_SW = 5, + TD_DEF_OS_LAYER_SW = 6, + TD_MOUSE_BTNS = 7, + TD_DVORAK_BEPO = 8, + TD_UP_HOME = 9, + TD_DOWN_END = 10, + TD_RIGHT_TAB = 11, + TD_LEFT_BACKTAB = 12 +}; + + +// Tap dance +#define TAB_BKTAB TD(TD_TAB_BKTAB) // Tab or backtab tapdance. +#define MDIA_SYMB_KP_LAYERS TD(TD_MDIA_SYMB) // MDIA, symb, keypad, layouts layer tapdance toggle. +#define DEF_LAYER_SW TD(TD_DEF_LAYER_SW) // dvorak, dvorak_on_bepo, bepo default layer +#define DEF_OS_LAYER_SW TD(TD_DEF_OS_LAYER_SW) // dvorak, dvorak_on_bepo, bepo default layer +#define HOME_END TD(TD_HOME_END) // home or end tapdance. +#define XMONAD_ESC TD(TD_XMONAD_ESC) // Escape, dvorak, media or symb. - tap and hold tap dance. 1-4 +#define DVORAK_ET_BEPO TD(TD_DVORAK_BEPO) // Escape, dvorak, media or symb. - tap and hold tap dance. 1-4 +#define TDMOUSE_BTNS TD(TD_MOUSE_BTNS) // hmmm. 1-5 +#define RIGHT_TAB TD(TD_RIGHT_TAB) // Bad idea these 4. Maybe with good timing... +#define LEFT_BACKTAB TD(TD_LEFT_BACKTAB) +#define UP_HOME TD(TD_UP_HOME) +#define DOWN_END TD(TD_DOWN_END) // No! Down Down Not End.... + +// HOME ROW LAYER TOGGLE (LT) and Shift. +// both sides of the home row have "shift, ___, media , symb, ___" and "___, symb, media, ___, shift". +// so pinky fingers are shift when held and the index and second fingers are symbol and +// media layers when held. + +// The most portable copy/paste keys (windows (mostly), linux, and some terminal emulators). +// The KC_CCCV key takes care of the last two... +#define MK_CUT LSFT(KC_DEL) // shift + delete +#define MK_COPY LCTL(KC_INS) // ctrl + insert +#define MK_PASTE LSFT(KC_INS) // shift + insert +#define EOT LCTL(KC_D) +#define NAK LCTL(KC_U) +#define XPASTE LCTL(LSFT(KC_V)) +#define UNDO LCTL(KC_Z) +#define XCOPY LCTL(LSFT(KC_C)) + +#undef ___ //kint defines it as KC_NO +#define ___ KC_TRNS +#define XXX KC_NO +#define ____ _TRNS + +// Blocking keys +#define _X_ XXX +#define ___X___ XXX +#define ___X2___ XXX, XXX +#define ___X3___ ___X2___, XXX +#define ___X4___ ___X3___, XXX +#define ___X5___ ___X4___, XXX +#define ___X6___ ___X5___, XXX +#define ___X12___ ___X6___, ___X6___ +#define ___X15___ ___X5___, ___X5___, ___X5___ + +// Transparent keys +#define ___2___ ___, ___ +#define ___3___ ___2___, ___ +#define ___4___ ___3___, ___ +#define ___5___ ___4___, ___ +#define ___6___ ___5___, ___ +#define ___10___ ___6___, ___4___ +#define ___12___ ___6___, ___6___ +#define ___14___ ___5___, ___4___, ___5___ +#define ___15___ ___5___, ___5___, ___5___ +#define ___16___ ___15___, ___ + +#define ____2_ ____, ____ +#define ____3_ ____2_, ____ +#define ____4_ ____3_, ____ +#define ____5_ ____4_, ____ +#define ____6_ ____5_, ____ +#define ____10_ ____6_, ____4_ +#define ____12_ ____6_, ____6_ +#define ____14_ ____5_, ____4_, ____5_ +#define ____15_ ____5_, ____5_, ____5_ +#define ____16_ ____15_, ____ + +int on_qwerty(void); + +#ifdef TAP_DANCES_ENABLE +int cur_dance (qk_tap_dance_state_t *state); + +//for the x tap dance. Put it here so it can be used in any keymap +void x_finished (qk_tap_dance_state_t *state, void *user_data); +void x_reset (qk_tap_dance_state_t *state, void *user_data); +#endif diff --git a/users/ericgebhart/extensions/keymap_combo.h b/users/ericgebhart/extensions/keymap_combo.h new file mode 100644 index 0000000000..cd9684e601 --- /dev/null +++ b/users/ericgebhart/extensions/keymap_combo.h @@ -0,0 +1,139 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ +// Keymap helpers +void process_combo_event(uint16_t combo_index, bool pressed); + + +// define reference layers per layer. +#define REF_LAYER(LAYER, REF_LAYER) \ + case LAYER: return REF_LAYER; + +#define K_ENUM(name, key, ...) name, +#define K_DATA(name, key, ...) const uint16_t PROGMEM cmb_##name[] = {__VA_ARGS__, COMBO_END}; +#define K_COMB(name, key, ...) [name] = COMBO(cmb_##name, key), + +#define A_ENUM(name, string, ...) name, +#define A_DATA(name, string, ...) const uint16_t PROGMEM cmb_##name[] = {__VA_ARGS__, COMBO_END}; +#define A_COMB(name, string, ...) [name] = COMBO_ACTION(cmb_##name), +#define A_ACTI(name, string, ...) \ + case name: \ + if (pressed) SEND_STRING(string); \ + break; + +#define A_TOGG(name, layer, ...) \ + case name: \ + if (pressed) layer_invert(layer); \ + break; + +#define BLANK(...) +// Generate data needed for combos/actions +// Create Enum +#define COMBO_REF_LAYER BLANK +#undef COMB +#undef SUBS +#undef TOGG +#define COMB K_ENUM +#define SUBS A_ENUM +#define TOGG A_ENUM +enum combos { +#include "combos.def" + COMBO_LENGTH +}; +// Export length to combo module +uint16_t COMBO_LEN = COMBO_LENGTH; + +// Bake combos into mem +#undef COMB +#undef SUBS +#undef TOGG +#define COMB K_DATA +#define SUBS A_DATA +#define TOGG A_DATA +#include "combos.def" +#undef COMB +#undef SUBS +#undef TOGG + +// Fill combo array +#define COMB K_COMB +#define SUBS A_COMB +#define TOGG A_COMB +combo_t key_combos[] = { +#include "combos.def" +}; +#undef COMB +#undef SUBS +#undef TOGG + +// Fill QMK hook +#define COMB BLANK +#define SUBS A_ACTI +#define TOGG A_TOGG + +void process_combo_event(uint16_t combo_index, bool pressed) { +#if defined( CONSOLE_ENABLE) && defined(CONSOLE_KEY_LOGGER_ENABLE) + if (pressed) { + combo_t *combo = &key_combos[combo_index]; + uint8_t idx = 0; + uint16_t combo_keycode; + while ((combo_keycode = pgm_read_word(&combo->keys[idx])) != COMBO_END) { + uprintf("0x%04X,NA,NA,%u,%u,0x%02X,0x%02X,0\n", + combo_keycode, + /* */ + /* */ + get_highest_layer(layer_state), + pressed, + get_mods(), + get_oneshot_mods() + ); + idx++; + } + } +#endif + switch (combo_index) { +#include "combos.def" + } + + // Allow user overrides per keymap +#if __has_include("inject.h") +# include "inject.h" +#endif +} + +#undef COMB +#undef SUBS +#undef TOGG + +#define COMB BLANK +#define SUBS BLANK +#define TOGG BLANK + +#undef COMBO_REF_LAYER +#define COMBO_REF_LAYER REF_LAYER + +uint16_t combo_ref_from_layer(uint16_t layer){ + switch (biton32(layer_state)){ +#include "combos.def" + +#ifdef COMBO_REF_DEFAULT + default: return COMBO_REF_DEFAULT; +#else + default: return layer; +#endif + } +} diff --git a/users/ericgebhart/extensions/mod_lock.c b/users/ericgebhart/extensions/mod_lock.c new file mode 100644 index 0000000000..c78f7cdfe8 --- /dev/null +++ b/users/ericgebhart/extensions/mod_lock.c @@ -0,0 +1,81 @@ +/* + Copyright 2022 Eric Gebhart , @possumvibes + + 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 . +*/ +// Derived from mod_lock by @possumvibes. + +#include "mod_lock.h" + +#undef MODL +#define MODL(KEYCODE, MODKC) \ + {false, MODKC, KEYCODE}, + +#define A_KEY(KEYCODE) case KEYCODE: +#define BLANK(...) + +#undef IGNORE_KC +#define IGNORE_KC BLANK + +mod_lock_state_t modlock_states[] = { +#ifdef MOD_LOCK_ENABLE +#include "mod_lock.def" +#endif +}; +uint8_t NUM_MODLOCK_STATES = sizeof(modlock_states) / sizeof(mod_lock_state_t); + +void process_mod_lock(uint16_t keycode, keyrecord_t *record) { +#ifdef MOD_LOCK_ENABLE + mod_lock_state_t *curr_state = NULL; + + for (int i = 0; i < NUM_MODLOCK_STATES; ++i) { + curr_state = &modlock_states[i]; + + if (keycode == curr_state->trigger) { + if (record->event.pressed) { + if (curr_state->locking) { + unregister_code(curr_state->mod); + } else { + register_code(curr_state->mod); + } + + curr_state->locking = !curr_state->locking; + } + } else { + // check for cancel condition on keydown and keyup + if (curr_state->locking && is_mod_lock_cancel_key(keycode)) { + unregister_code(curr_state->mod); + curr_state->locking = false; + } + } + } +#endif +} + +#undef MODL +#undef IGNORE_KC +#define MODL BLANK +#define IGNORE_KC A_KEY +bool is_mod_lock_cancel_key(uint16_t keycode) { + // Mod locks are exclusively used on the nav layer. + // any key besides nav keys should cancel the lock. + switch (keycode) { +#ifdef MOD_LOCK_ENABLE +#include "mod_lock.def" +#endif + return false; + default: + return true; + } +} diff --git a/users/ericgebhart/extensions/mod_lock.h b/users/ericgebhart/extensions/mod_lock.h new file mode 100644 index 0000000000..d9e6106c4e --- /dev/null +++ b/users/ericgebhart/extensions/mod_lock.h @@ -0,0 +1,39 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#include USERSPACE_H + +typedef struct { + bool locking; + uint16_t mod; + uint16_t trigger; +} mod_lock_state_t; + +extern mod_lock_state_t mod_lock_states[]; +extern uint8_t NUM_MODLOCK_STATES; + +// Custom mod-locking functionality that registers the mod and +// keeps it registered until the trigger key is tapped again +// or until a specified cancel key is tapped. +void process_mod_lock(uint16_t keycode, keyrecord_t *record); + +bool is_mod_lock_cancel_key(uint16_t keycode); + +#undef IGNORE_KC +#define IGNORE_KC(KC) \ + case KC: diff --git a/users/ericgebhart/extensions/not_dead.c b/users/ericgebhart/extensions/not_dead.c new file mode 100644 index 0000000000..8369edd52d --- /dev/null +++ b/users/ericgebhart/extensions/not_dead.c @@ -0,0 +1,36 @@ +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ + +#include USERSPACE_H + +inline void not_dead(uint16_t kc1, keyrecord_t *record) { + if (record->event.pressed) { + tap_code16(kc1); + tap_code16(KC_SPACE); + } +} + +#define NOT_DEAD(KCKEY, KC01) \ + case KCKEY: \ + not_dead(KC01, record); \ + break; \ + +void process_not_dead(uint16_t keycode, keyrecord_t *record) { + switch(keycode){ +#include "not_dead.def" + } +} diff --git a/users/ericgebhart/extensions/nshot_mod.c b/users/ericgebhart/extensions/nshot_mod.c new file mode 100644 index 0000000000..1346f7eba6 --- /dev/null +++ b/users/ericgebhart/extensions/nshot_mod.c @@ -0,0 +1,154 @@ +/* + Copyright 2022 Eric Gebhart , @possumvibes + + 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 . +*/ +// Derived from nshot_mod by @possumvibes. +// Derived from one shot_mod by @Callum. + +#include "nshot_mod.h" +#include USERSPACE_H + +#undef NSHOT +#define NSHOT(KEYCODE, MOD, COUNT) \ + {KEYCODE, MOD, COUNT, os_up_unqueued, 0}, + +#undef ONESHOT +#define ONESHOT(KEYCODE, MOD) NSHOT(KEYCODE, MOD, 1) +#define A_KEY(KEYCODE) case KEYCODE: +#define BLANK(...) + +#define CANCEL_KEY BLANK +#define IGNORE_KEY BLANK +nshot_state_t nshot_states[] = { +#include "nshot.def" +}; +uint8_t NUM_NSHOT_STATES = sizeof(nshot_states) / sizeof(nshot_state_t); + +bool process_nshot_state(uint16_t keycode, keyrecord_t *record) { + nshot_state_t *curr_state = NULL; + + switch(keycode){ + case CLEAR: { + clear_oneshot_mods(); + clear_mods(); + return false; + } + case PANIC: { + clear_oneshot_mods(); + clear_mods(); + if (get_oneshot_layer() != 0) { + clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); + } + layer_move(0); + return false; + } + } + + for (int i = 0; i < NUM_NSHOT_STATES; ++i) { + curr_state = &nshot_states[i]; + + if (keycode == curr_state->trigger) { + if (record->event.pressed) { + // Trigger keydown + if (curr_state->state == os_up_unqueued) { + register_code(curr_state->mod); + } + curr_state->state = os_down_unused; + curr_state->count = 0; + } else { + // Trigger keyup + switch (curr_state->state) { + case os_down_unused: + // If we didn't use the mod while trigger was held, queue it. + curr_state->state = os_up_queued; + break; + case os_down_used: + // If we did use the mod while trigger was held, unregister it. + curr_state->state = os_up_unqueued; + unregister_code(curr_state->mod); + break; + default: + break; + } + } +} else { + if (record->event.pressed) { + if (is_nshot_cancel_key(keycode) && curr_state->state != os_up_unqueued) { + // Cancel oneshot on designated cancel keydown. + curr_state->state = os_up_unqueued; + curr_state->count = 0; + unregister_code(curr_state->mod); + } + } else { + if (!is_nshot_ignored_key(keycode)) { + // On non-ignored keyup, consider the oneshot used. + switch (curr_state->state) { + case os_down_unused: + // The mod key is being held as a normal mod. + curr_state->state = os_down_used; + break; + case os_up_queued: + // The mod key is being used as an n-shot. + // Increment the keys-used count. + curr_state->count = curr_state->count + 1; + + // If the n-shot max has been reached, complete the n-shot. + if (curr_state->count == curr_state->max_count) { + curr_state->state = os_up_unqueued; + curr_state->count = 0; + unregister_code(curr_state->mod); + } + break; + default: + break; + } + } + } + } + } + return true; +} + +// turn off the nshot/oneshot macros +#undef ONESHOT +#undef NSHOT +#define ONESHOT BLANK +#define NSHOT BLANK + +#undef CANCEL_KEY +#undef IGNORE_KEY +#define IGNORE_KEY BLANK +#define CANCEL_KEY A_KEY +bool is_nshot_cancel_key(uint16_t keycode) { + switch (keycode) { +#include "nshot.def" + return true; + default: + return false; + } +} + +#undef CANCEL_KEY +#undef IGNORE_KEY +#define CANCEL_KEY BLANK +#define IGNORE_KEY A_KEY +bool is_nshot_ignored_key(uint16_t keycode) { + switch (keycode) { +#include "nshot.def" + return true; + default: + return false; + } +} diff --git a/users/ericgebhart/extensions/nshot_mod.h b/users/ericgebhart/extensions/nshot_mod.h new file mode 100644 index 0000000000..c5840e6bef --- /dev/null +++ b/users/ericgebhart/extensions/nshot_mod.h @@ -0,0 +1,45 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#include QMK_KEYBOARD_H + +// Represents the four states an n-shot key can be in (from users/callum) +typedef enum { + os_up_unqueued, + os_up_queued, + os_down_unused, + os_down_used, +} oneshot_state; + +typedef struct { + uint16_t trigger; + uint16_t mod; + uint8_t max_count; + oneshot_state state; + uint8_t count; +} nshot_state_t; + +extern nshot_state_t nshot_states[]; +extern uint8_t NUM_NSHOT_STATES; + + +// Keys that should cancel the n-shot mod if tapped +bool is_nshot_cancel_key(uint16_t keycode); + +// Keys that should not count towards n-shot usage (e.g., layer toggles) +bool is_nshot_ignored_key(uint16_t keycode); diff --git a/users/ericgebhart/extensions/oneshot.c b/users/ericgebhart/extensions/oneshot.c new file mode 100644 index 0000000000..83c8a04363 --- /dev/null +++ b/users/ericgebhart/extensions/oneshot.c @@ -0,0 +1,217 @@ +#include QMK_KEYBOARD_H +#include USERSPACE_H +#include "oneshot.h" + +#ifdef ONESHOT_MOD_ENABLE + +/* -------------------------------------------- */ +// Add to process_record_user. +/* int8_t keycode_consumed = 0; */ + +/* #ifdef ONESHOT_ENABLE */ +/* keycode_consumed += update_oneshot_modifiers(keycode, record, keycode_consumed); */ +/* #endif */ +/* -------------------------------------------- */ + +#define ONESHOT(KEYCODE, MOD) case KEYCODE: return MOD; + +#define A_KEY(KEYCODE) case KEYCODE: +#define BLANK(...) + +#define CANCEL_KEY BLANK +#define IGNORE_KEY BLANK + +// the basic states a oneshot modifier can be in +typedef enum { + ONESHOT_STATE_OFF = 0, + ONESHOT_STATE_PRESSED = 1, + ONESHOT_STATE_QUEUED = 2, + ONESHOT_STATE_CAPSWORD = 3, + ONESHOT_STATE_LOCK = 4, + ONESHOT_STATE_END_PRESSED = 5, +} oneshot_state; + +oneshot_state modifiers_state_transitions_normal[5] = {ONESHOT_STATE_PRESSED, ONESHOT_STATE_QUEUED, ONESHOT_STATE_LOCK, ONESHOT_STATE_END_PRESSED, ONESHOT_STATE_END_PRESSED}; + +static oneshot_state modifiers_with_state[ONESHOT_MOD_COUNT] = { + ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, ONESHOT_STATE_OFF, +}; + +// oneshot mods always get registered immediately to the operating system, but we also +// need to keep track if the mod(s) got combined with a normal key (applied) +static bool unapplied_mods_present = false; + +// keycode of the last pressed 'normal' key which haven't been released yet +static uint16_t repeating_normal_key = 0; + +// utility functions (implemented at the bottom of this file) +static void set_modifier_state(oneshot_mod osmod, oneshot_state new_state); +static int8_t set_modifier_state_all(oneshot_state new_state); +static void set_modifier_state_all_from_to(oneshot_state oneshot_state_from, oneshot_state oneshot_state_to); +static bool all_modifiers_are_off(void); + +int8_t turnoff_oneshot_modifiers() { + return set_modifier_state_all(ONESHOT_STATE_OFF); +} + +// see comment in corresponding headerfile +int8_t update_oneshot_modifiers(uint16_t keycode, keyrecord_t *record, int8_t keycode_consumed) { + + // cancel keys + if (is_oneshot_modifier_cancel_key(keycode) && record->event.pressed) { + if (keycode_consumed == 0) { + unapplied_mods_present = false; + keycode_consumed += set_modifier_state_all(ONESHOT_STATE_OFF); + } else { + keycode_consumed = 0; + } + return keycode_consumed; + } + + // ignored keys + if (is_oneshot_modifier_ignored_key(keycode)) { + return keycode_consumed; + } + + oneshot_mod osmod = get_modifier_for_trigger_key(keycode); + + // trigger keys + if (osmod != ONESHOT_NONE) { + oneshot_state state = modifiers_with_state[osmod]; + if (record->event.pressed) { + if (state == ONESHOT_STATE_OFF) { + unapplied_mods_present = (repeating_normal_key == 0); + } + oneshot_state tostate = modifiers_state_transitions_normal[state]; + set_modifier_state(osmod, tostate); + } else { + if (state == ONESHOT_STATE_PRESSED) { + if (!unapplied_mods_present) { + set_modifier_state(osmod, ONESHOT_STATE_OFF); + } else { + set_modifier_state(osmod, ONESHOT_STATE_QUEUED); + } + } else if (state == ONESHOT_STATE_END_PRESSED) { + set_modifier_state(osmod, ONESHOT_STATE_OFF); + } + } + } + // normal keys + else { + if (record->event.pressed) { + if (!all_modifiers_are_off()) { + if (unapplied_mods_present) { + unapplied_mods_present = false; + } else { + unregister_code(repeating_normal_key); + set_modifier_state_all_from_to(ONESHOT_STATE_QUEUED, ONESHOT_STATE_OFF); + } + } + repeating_normal_key = keycode; + } else { + if (!all_modifiers_are_off()) { + unregister_code(keycode); + set_modifier_state_all_from_to(ONESHOT_STATE_QUEUED, ONESHOT_STATE_OFF); + } + repeating_normal_key = 0; + } + } + + return 0; +} + +// implementation of utility functions + +// registers/unregisters a mod to the operating system on state change if necessary +void update_modifier(oneshot_mod osmod, oneshot_state previous_state, oneshot_state current_state) { + if (previous_state == ONESHOT_STATE_OFF) { + register_code(KC_LCTRL + osmod); + } else { + if (current_state == ONESHOT_STATE_OFF) { + unregister_code(KC_LCTRL + osmod); + } + } +} + +void set_modifier_state(oneshot_mod osmod, oneshot_state new_state) { + oneshot_state previous_state = modifiers_with_state[osmod]; + if (previous_state != new_state) { + modifiers_with_state[osmod] = new_state; + update_modifier(osmod, previous_state, new_state); + } +} + +int8_t set_modifier_state_all(oneshot_state new_state) { + int8_t c = 0; + for (int8_t i = 0; i < ONESHOT_MOD_COUNT; i++) { + oneshot_state previous_state = modifiers_with_state[i]; + if (previous_state != new_state) { + modifiers_with_state[i] = new_state; + update_modifier(i, previous_state, new_state); + c += 1; + } + } + return c; +} + +void set_modifier_state_all_from_to(oneshot_state oneshot_state_from, oneshot_state oneshot_state_to) { + for (int8_t i = 0; i < ONESHOT_MOD_COUNT; i++) { + if (modifiers_with_state[i] == oneshot_state_from) { + modifiers_with_state[i] = oneshot_state_to; + update_modifier(i, oneshot_state_from, oneshot_state_to); + } + } +} + +bool all_modifiers_are_off() { + for (int8_t i = 0; i < ONESHOT_MOD_COUNT; i++) { + if (modifiers_with_state[i] != ONESHOT_STATE_OFF) { + return false; + } + } + return true; +} + +oneshot_mod get_modifier_for_trigger_key(uint16_t keycode) +{ + switch (keycode) + { +#include "oneshot.def" + return true; + default: + return ONESHOT_NONE; + } +} + +// turn off the oneshot macros +#undef ONESHOT +#define ONESHOT BLANK +#define NSHOT BLANK + +#undef CANCEL_KEY +#undef IGNORE_KEY +#define CANCEL_KEY A_KEY +#define IGNORE_KEY BLANK +bool is_oneshot_modifier_cancel_key(uint16_t keycode) { + switch (keycode) { +#include "oneshot.def" + return true; + default: + return false; + } +} + +#undef CANCEL_KEY +#undef IGNORE_KEY +#define CANCEL_KEY BLANK +#define IGNORE_KEY A_KEY +bool is_oneshot_modifier_ignored_key(uint16_t keycode) { + switch (keycode) { +#include "oneshot.def" + return true; + default: + return false; + } +} + +#endif diff --git a/users/ericgebhart/extensions/oneshot.h b/users/ericgebhart/extensions/oneshot.h new file mode 100644 index 0000000000..774dc4ab39 --- /dev/null +++ b/users/ericgebhart/extensions/oneshot.h @@ -0,0 +1,37 @@ +#define ENABLE_ONESHOT +#ifdef ENABLE_ONESHOT +#pragma once + +typedef enum { + ONESHOT_LCTL = 0, + ONESHOT_LSFT = 1, + ONESHOT_LALT = 2, + ONESHOT_LGUI = 3, + ONESHOT_RCTL = 4, + ONESHOT_RSFT = 5, + ONESHOT_RALT = 6, + ONESHOT_RGUI = 7, + ONESHOT_NONE = 8, + ONESHOT_MOD_COUNT = 8, +} oneshot_mod; + + +// This function should be called inside proces_record_user and does everything needed to get one shot modifiers working. +// Returns true if the keycode needs further handling, false otherwise. +int8_t update_oneshot_modifiers(uint16_t keycode, keyrecord_t *record, int8_t keycode_consumed); +int8_t turnoff_oneshot_modifiers(void); + +// TO BE IMPLEMENTED BY THE USER +// This function should return one of the oneshot_mod enumerations (see keymap.c implementation) +oneshot_mod get_modifier_for_trigger_key(uint16_t keycode); + +// TO BE IMPLEMENTED BY THE USER +// This function should return true for keycodes that must be ignored in the oneshot modifier behaviour. +// You probably want to ignore layer keys. Trigger keys don't need to be specified here. +bool is_oneshot_modifier_ignored_key(uint16_t keycode); + +// TO BE IMPLEMENTED BY THE USER +// This function should return true for keycodes that should reset all oneshot modifiers. +bool is_oneshot_modifier_cancel_key(uint16_t keycode); + +#endif diff --git a/users/ericgebhart/extensions/process_locales.h b/users/ericgebhart/extensions/process_locales.h new file mode 100644 index 0000000000..d0f7af53bf --- /dev/null +++ b/users/ericgebhart/extensions/process_locales.h @@ -0,0 +1,29 @@ +#pragma once +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ + +#include USERSPACE_H + +// Stuff we need for locale and layer switching +// there can be more but we need to know where they start and end. +// remember there's limitations on layers. +// Our locales. so it's easy to switch between them. + +bool process_locales(uint16_t keycode, keyrecord_t *record); + +#define PROCESS_LOCALES \ + if (!process_locales(keycode, record)) { return false; } diff --git a/users/ericgebhart/extensions/process_nshot.h b/users/ericgebhart/extensions/process_nshot.h new file mode 100644 index 0000000000..1ec42db478 --- /dev/null +++ b/users/ericgebhart/extensions/process_nshot.h @@ -0,0 +1,21 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ +// Custom one-or-more-shot implementation that does not rely on timers +// and persists across layer changes. Based on the users/callum implementation +// at https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum +bool process_nshot_state(uint16_t keycode, keyrecord_t *record); diff --git a/users/ericgebhart/extensions/process_smart_lock.h b/users/ericgebhart/extensions/process_smart_lock.h new file mode 100644 index 0000000000..b8e2fb2735 --- /dev/null +++ b/users/ericgebhart/extensions/process_smart_lock.h @@ -0,0 +1,19 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ +///* -------- Process Record -------- */ +void process_smart_lock(uint16_t keycode, keyrecord_t *record); diff --git a/users/ericgebhart/extensions/quick_tap.c b/users/ericgebhart/extensions/quick_tap.c new file mode 100644 index 0000000000..8c25f153bd --- /dev/null +++ b/users/ericgebhart/extensions/quick_tap.c @@ -0,0 +1,37 @@ +/* + Copyright 2022 Eric Gebhart , @possumvibes + + 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 . +*/ + +// written by @dnaq. +#if defined( global_quick_tap) && defined(CONSOLE_KEY_LOGGER_ENABLE) + bool process_global_quick_tap(uint16_t keycode, keyrecord_t *record) { + static uint16_t global_quick_tap_timer = 0; + if (keycode < QK_MOD_TAP || keycode > QK_MOD_TAP_MAX) { + global_quick_tap_timer = timer_read(); + return true; + } + if (timer_elapsed(global_quick_tap_timer) > TAPPING_TERM) { + return true; + } + if (record->event.pressed) { + keycode = keycode & 0xFF; + global_quick_tap_timer = timer_read(); + tap_code(keycode); + return false; + } + return true; + } +#endif diff --git a/users/ericgebhart/extensions/send_string.c b/users/ericgebhart/extensions/send_string.c new file mode 100644 index 0000000000..50237f5143 --- /dev/null +++ b/users/ericgebhart/extensions/send_string.c @@ -0,0 +1,40 @@ +/* + Copyright 2018 Eric Gebhart + + 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 . +*/ +#include USERSPACE_H +#include "version.h" + +#define SEND_STR(KEYC, STRING) \ + case KEYC: \ + if (record->event.pressed) { \ + SEND_STRING(STRING); \ + } \ + break; + +#define SEND_STR_DELAY(KEYC, STRING) \ + case KEYC: \ + if (record->event.pressed) { \ + SEND_STRING_DELAY(STRING, TAP_CODE_DELAY); \ + } \ + break; + +void process_send_strs(uint16_t keycode, keyrecord_t *record){ +#ifdef SEND_STRING_ENABLE + switch (keycode) { +#include "send_string.def" + } +#endif +} diff --git a/users/ericgebhart/extensions/smart_lock.c b/users/ericgebhart/extensions/smart_lock.c new file mode 100644 index 0000000000..5b3dc0ecb2 --- /dev/null +++ b/users/ericgebhart/extensions/smart_lock.c @@ -0,0 +1,117 @@ +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ +// Derived from smart_layers by @Possumvibes +// Derived from one shot_mod by @Callum. + +#include "smart_lock.h" +#include USERSPACE_H + +/* print("string"): Print a simple string. */ +/* uprintf("%s string", var) */ + +bool ignore_key(uint16_t keycode, + const uint16_t *cond_keys){ + + // look for non-cancel condition. + // look for keys to ignore, if we match, we do nothing. + for (; pgm_read_word(cond_keys) != COND_KEYS_END ; ++cond_keys){ + if (pgm_read_word(cond_keys) == keycode){ + return true; + } + } + return false; +} + +void deactivate_sml_layer(smart_lock_t *sml){ + layer_off(sml->thing); + sml->active = false; +} +void deactivate_sml_mod(smart_lock_t *sml){ + unregister_mods(sml->thing); + sml->active = false; +} + +void deactivate_sml(smart_lock_t *sml){ + switch(sml->type){ + case sml_layer: + deactivate_sml_layer(sml); + case sml_mod: + deactivate_sml_mod(sml); + } +} + + +void sml_activate_layer(smart_lock_t *sml){ + sml->active = true; + layer_on(sml->thing); +} + +void sml_maybe_activate_mod(smart_lock_t *sml ){ + if (sml->active) { + unregister_mods(sml->thing); + } else { + register_mods(sml->thing); + } + sml->active = !sml->active; +} + +void sml_activate(smart_lock_t *sml){ + switch(sml->type){ + case sml_layer: + sml_activate_layer(sml); + break; + case sml_mod: +sml_maybe_activate_mod(sml); + break; + } +} + + + +void update_smart_lock(uint16_t keycode) { + +#ifdef SMART_LOCK_ENABLE + bool deactivate = false; + smart_lock_t *sml; + + for (int i = 0; i < SML_LEN; ++i){ + sml = &smart_locks[i]; + + // if it's a match, + // maybe activate/deactivate it if we got it's keycode. + if (sml->keycode == keycode){ + sml_activate(sml); + return; + } + + // deactivate what we need to. + if(sml->active){ + deactivate = !ignore_key(keycode, &sml->keys[0]); + if (deactivate){ + deactivate_sml(sml); + } + } + } +#endif + return; +} + +void process_smart_lock(uint16_t keycode, keyrecord_t *record) { + if (record->event.pressed) { + update_smart_lock(keycode); + } +} diff --git a/users/ericgebhart/extensions/smart_lock.h b/users/ericgebhart/extensions/smart_lock.h new file mode 100644 index 0000000000..0102d611cd --- /dev/null +++ b/users/ericgebhart/extensions/smart_lock.h @@ -0,0 +1,103 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ +#include QMK_KEYBOARD_H +#include USERSPACE_H + +#ifdef SMART_LOCK_ENABLE +typedef enum { + sml_layer, + sml_mod +} smart_lock_type; + +typedef struct { + bool active; + const uint16_t *keys; + uint16_t keycode; + uint16_t thing; + smart_lock_type type; +} smart_lock_t; + + +// smart layer, smart mods +#undef SMLL +#undef SMLM +#define SMLL(key, layer, ...) +#define SMLM(key, mod, ...) // to replace mod_lock.. +#define COND_KEYS_END 0 + +#define CONCATENATE_SA(a, ...) a ## __VA_ARGS__ +#define CONCATENATE_S(a, ...) a ## __VA_ARGS__ +#define CAT_S(a, ...) CONCATENATE_S(a, __VA_ARGS__) +#define MK_SKEY(KC) CONCATENATE_S(sml_, KC) +#define MK_ARRAY(KC) \ + const uint16_t PROGMEM CONCATENATE_SA(sml_, KC)[] + +// to create an enum and find how many... +#define S_ENUM(kc, layer, ...) CAT_S(sml__, kc), +// create a const array of the condkeys for each SML +#define S_DATA(kc, thing, ...) MK_ARRAY(kc) = {__VA_ARGS__, COND_KEYS_END}; + +// create a list of smart_lock structs. Two names, one for mod one for layer to be concise. +#define S_SMART_LOCK(kc, layer, ...) {false, MK_SKEY(kc), kc, layer, sml_layer}, +#define M_SMART_LOCK(kc, mod, ...) {false, MK_SKEY(kc), kc, mod, sml_mod}, + +#define SML(sk, sa, st, stype) \ + { .keys = &(sk)[0], .keycode = (sa), .thing = (st), .smart_lock_type = stype} +#define K_SMLM(key, mod...) [MK_SKEY(key)] = SML(MK_SKEY(key), key, mod, sml_mod), +#define K_SMLL(key, layer...) [MK_SKEY(key)] = SML(MK_SKEY(key), key, layer, sml_layer), + +// Set everything up +// - Create enum of names, (sml_keycode). Used as indexes in the arrays. +// avoids using the keycodes which would create a sparse/large array. +// - Create array of conditional locks.. +// - Create array of the conditional keys for the locks, by name. + +// Create Enum +#undef SMLL +#undef SMLM +#define SMLL S_ENUM +#define SMLM S_ENUM + +// find how many +enum smart_locks { +#include "smart_lock.def" + SML_LENGTH +}; +uint16_t SML_LEN = SML_LENGTH; + +// Bake locks into mem, name, ignore/cancel keys +#undef SMLL +#undef SMLM +#undef TOGG +#define SMLL S_DATA +#define SMLM S_DATA +#include "smart_lock.def" +#undef SMLL +#undef SMLM + +// Fill array of locks by name, kc, layer/mod. +#define SMLL S_SMART_LOCK +#define SMLM M_SMART_LOCK + +smart_lock_t smart_locks[] = { +#include "smart_lock.def" +}; +#undef SMLL +#undef SMLM + +#endif diff --git a/users/ericgebhart/extensions/swapper.c b/users/ericgebhart/extensions/swapper.c new file mode 100644 index 0000000000..988a99e602 --- /dev/null +++ b/users/ericgebhart/extensions/swapper.c @@ -0,0 +1,58 @@ +/* + Copyright 2022 Eric Gebhart . +*/ +// Derived from swapper by @Possumvibes and @Callum + +#include "swapper.h" + +swapper_state_t swapper_states[] = { +#ifdef SWAPPER_ENABLE +#include "swapper.def" +#endif +}; +uint8_t NUM_SWAPPER_STATES = sizeof(swapper_states) / sizeof(swapper_state_t); + +// Based on https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum +void process_swappers(uint16_t keycode, keyrecord_t *record) { +#ifdef SWAPPER_ENABLE + swapper_state_t *curr_state = NULL; + for (int i = 0; i < NUM_SWAPPER_STATES; ++i) { + curr_state = &swapper_states[i]; + + if (keycode == curr_state->forward_trigger) { + if (record->event.pressed) { + if (!curr_state->active) { + curr_state->active = true; + register_code16(curr_state->mod); + } + register_code16(curr_state->forward); + } else { + unregister_code16(curr_state->forward); + // Don't unregister curr_state->mod until some other key is hit or released. + } + } else if (curr_state->active && keycode == curr_state->reverse_trigger) { + if (record->event.pressed) { + register_code16(curr_state->reverse); + } else { + unregister_code16(curr_state->reverse); + } + } else if (curr_state->active) { + unregister_code16(curr_state->mod); + curr_state->active = false; + } + } +#endif +} diff --git a/users/ericgebhart/extensions/swapper.h b/users/ericgebhart/extensions/swapper.h new file mode 100644 index 0000000000..fb7774f37a --- /dev/null +++ b/users/ericgebhart/extensions/swapper.h @@ -0,0 +1,37 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ + +#include QMK_KEYBOARD_H +#include USERSPACE_H + +typedef struct { + bool active; + uint16_t mod; + uint16_t forward; + uint16_t reverse; + uint16_t forward_trigger; + uint16_t reverse_trigger; +} swapper_state_t; +extern swapper_state_t swapper_states[]; +extern uint8_t NUM_SWAPPER_STATES; + +#undef SWAPPER_KEY +#define SWAPPER_KEY(KC, REVERSE_IT_KC, FWD_KC, REV_KC, MOD) \ + {false, MOD, FWD_KC, REV_KC, KC, REVERSE_IT_KC}, + +void process_swappers(uint16_t keycode, keyrecord_t *record); diff --git a/users/ericgebhart/extensions/tap_dances.c b/users/ericgebhart/extensions/tap_dances.c new file mode 100755 index 0000000000..b292dab678 --- /dev/null +++ b/users/ericgebhart/extensions/tap_dances.c @@ -0,0 +1,277 @@ +/* + Copyright 2018 Eric Gebhart + + 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 . +*/ +#ifdef TAP_DANCES_ENABLE + +#include "tap_dances.h" + +#include "action.h" +#include "action_layer.h" +#include "process_keycode/process_tap_dance.h" + +void tap_dance_mouse_btns (qk_tap_dance_state_t *state, void *user_data) { + switch(state->count){ + case 1: + register_code(KC_BTN1); + break; + case 2: + register_code(KC_BTN2); + break; + case 3: + register_code(KC_BTN3); + break; + case 4: + register_code(KC_BTN4); + break; + case 5: + register_code(KC_BTN5); + break; + default: + break; + } + reset_tap_dance(state); +} + +// counting on all the qwerty layers to be less than dvorak_on_bepo +int on_qwerty(){ + uint8_t deflayer = (biton32(default_layer_state)); + switch(deflayer){ + case _DVORAK_BP: + case _BEAKL_BP: + case _BEPO: + return (false); + default: + break; + } + return (true); +} + +static void switch_default_layer(uint8_t layer) { + default_layer_set(1UL<count){ + case 1: + switch_default_layer(_DVORAK_BP); + break; + case 2: + switch_default_layer(_BEPO); + break; + case 3: + layer_invert(_LAYERS); + break; + default: + break; + } + reset_tap_dance(state); +} + +void tap_dance_layer_switch (qk_tap_dance_state_t *state, void *user_data) { + switch(state->count){ + case 1: + if(on_qwerty()) + layer_invert(_SYMB); + else + layer_invert(_SYMB_BP); + break; + case 2: + layer_invert(_NAV); + break; + case 3: + layer_invert(_LAYERS); + break; + case 4: + if(on_qwerty()) + layer_invert(_KEYPAD); + else + layer_invert(_KEYPAD_BP); + break; + default: + break; + } + reset_tap_dance(state); +} + +void tap_dance_default_layer_switch (qk_tap_dance_state_t *state, void *user_data) { + switch(state->count){ + case 1: + switch_default_layer(_DVORAK); + break; + case 2: + switch_default_layer(_DVORAK_BP); + break; + case 3: + switch_default_layer(_BEPO); + break; + default: + break; + } + reset_tap_dance(state); +} + +// switch the default layer to another qwerty based layer. +void switch_default_layer_on_qwerty(int count) { + switch(count){ + case 1: + switch_default_layer(_DVORAK); + break; + case 2: + switch_default_layer(_QWERTY); + break; + case 3: + switch_default_layer(_COLEMAK); + break; + + /* case 4: */ + /* switch_default_layer(_WORKMAN); */ + /* break; */ + /* case 5: */ + /* switch_default_layer(_NORMAN); */ + /* break; */ + + default: + switch_default_layer(_DVORAK); + break; + } +} + +// switch the default layer to another bepo based layer. +void switch_default_layer_on_bepo(int count) { + switch(count){ + case 1: + switch_default_layer(_DVORAK_BP); + break; + case 2: + switch_default_layer(_BEPO); + break; + default: + switch_default_layer(_DVORAK_BP); + break; + } +} + + +// tap to change the default layer. Distinguishes between layers that are based on +// a qwerty software keyboard and a bepo software keyboard. +// if shifted, choose layers based on the other software keyboard, otherwise choose only +// layers that work on the current software keyboard. +void tap_dance_default_os_layer_switch (qk_tap_dance_state_t *state, void *user_data) { + //uint8_t shifted = (get_mods() & MOD_BIT(KC_LSFT|KC_RSFT)); + bool shifted = ( keyboard_report->mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) ); + int qwerty = on_qwerty(); + + + // shifted, choose between layers on the other software keyboard + if(shifted){ + if (qwerty) + switch_default_layer_on_bepo(state->count); + else + switch_default_layer_on_qwerty(state->count); + + // not shifted, choose between layers on the same software keyboard + } else { + if (qwerty) + switch_default_layer_on_qwerty(state->count); + else + switch_default_layer_on_bepo(state->count); + } + + reset_tap_dance(state); +} + + +/* Return an integer that corresponds to what kind of tap dance should be executed. + * + * How to figure out tap dance state: interrupted and pressed. + * + * Interrupted: If the state of a dance dance is "interrupted", that means that another key has been hit + * under the tapping term. This is typically indicitive that you are trying to "tap" the key. + * + * Pressed: Whether or not the key is still being pressed. If this value is true, that means the tapping term + * has ended, but the key is still being pressed down. This generally means the key is being "held". + * + * One thing that is currenlty not possible with qmk software in regards to tap dance is to mimic the "permissive hold" + * feature. In general, advanced tap dances do not work well if they are used with commonly typed letters. + * For example "A". Tap dances are best used on non-letter keys that are not hit while typing letters. + * + * Good places to put an advanced tap dance: + * z,q,x,j,k,v,b, any function key, home/end, comma, semi-colon + * + * Criteria for "good placement" of a tap dance key: + * Not a key that is hit frequently in a sentence + * Not a key that is used frequently to double tap, for example 'tab' is often double tapped in a terminal, or + * in a web form. So 'tab' would be a poor choice for a tap dance. + * Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the + * letter 'p', the word 'pepper' would be quite frustating to type. + * + * For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested + * + */ +int cur_dance (qk_tap_dance_state_t *state) { + if (state->count == 1) { + if (state->interrupted || !state->pressed) return SINGLE_TAP; + //key has not been interrupted, but they key is still held. Means you want to send a 'HOLD'. + else return SINGLE_HOLD; + } + else if (state->count == 2) { + /* + * DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap + * action when hitting 'pp'. Suggested use case for this return value is when you want to send two + * keystrokes of the key, and not the 'double tap' action/macro. + */ + if (state->interrupted) return DOUBLE_SINGLE_TAP; + else if (state->pressed) return DOUBLE_HOLD; + else return DOUBLE_TAP; + } + //Assumes no one is trying to type the same letter three times (at least not quickly). + //If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add + //an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP' + if (state->count == 3) { + if (state->interrupted || !state->pressed) return TRIPLE_TAP; + else return TRIPLE_HOLD; + } + else return 8; //magic number. At some point this method will expand to work for more presses +} + +//Tap Dance Definitions +qk_tap_dance_action_t tap_dance_actions[] = { + //Tap once for Esc, twice for Caps Lock + [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS), + [TD_TAB_BKTAB] = ACTION_TAP_DANCE_DOUBLE(KC_TAB, LSFT(KC_TAB)), + [TD_RIGHT_TAB] = ACTION_TAP_DANCE_DOUBLE(KC_RIGHT, KC_TAB), + [TD_LEFT_BACKTAB] = ACTION_TAP_DANCE_DOUBLE(KC_LEFT, LSFT(KC_TAB)), + [TD_UP_HOME] = ACTION_TAP_DANCE_DOUBLE(KC_UP, KC_HOME), + [TD_DOWN_END] = ACTION_TAP_DANCE_DOUBLE(KC_DOWN, KC_END), + [TD_MDIA_SYMB] = ACTION_TAP_DANCE_FN(tap_dance_layer_switch), + [TD_DVORAK_BEPO] = ACTION_TAP_DANCE_FN(tap_dance_df_bepo_layers_switch), + [TD_DEF_LAYER_SW] = ACTION_TAP_DANCE_FN(tap_dance_default_layer_switch), + [TD_DEF_OS_LAYER_SW] = ACTION_TAP_DANCE_FN(tap_dance_default_os_layer_switch), + [TD_HOME_END] = ACTION_TAP_DANCE_DOUBLE(KC_HOME, KC_END), + [TD_MOUSE_BTNS] = ACTION_TAP_DANCE_FN(tap_dance_mouse_btns) + +}; + +#endif diff --git a/users/ericgebhart/extensions/tap_dances.h b/users/ericgebhart/extensions/tap_dances.h new file mode 100755 index 0000000000..745446756e --- /dev/null +++ b/users/ericgebhart/extensions/tap_dances.h @@ -0,0 +1,19 @@ +#pragma once +/* + Copyright 2018 Eric Gebhart + + 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 . +*/ + +#include USERSPACE_H diff --git a/users/ericgebhart/extensions/tap_hold.c b/users/ericgebhart/extensions/tap_hold.c new file mode 100644 index 0000000000..041b961e11 --- /dev/null +++ b/users/ericgebhart/extensions/tap_hold.c @@ -0,0 +1,165 @@ +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ + +/* This is variations on custom tap hold functionality. It makes it easy */ +/* to maintain tap_hold keys and combinations. These combinations go into */ +/* the file "tap_hold.def". Here are two examples. */ +/* */ +/* This example is tap or tap for TAP_HOLD_TERM, It defines a key */ +/* KC_CCCV, which sends Control-c on tap, and Control-v on hold. */ +/* */ +/* TP_TPL(KC_CCCV, LCTL(KC_C), LCTL(KC_V)) */ +/* */ +/* This is an example of Open - Open and Close. */ +/* It defines a key, KC_OCPRN which when tapped gives an '(' and */ +/* when held gives '()' followed by a backarrow. */ +/* Which places the cursor between them.*/ +/* */ +/* OPEN_OCL(KC_OCPRN, KC_LPRN, KC_RPRN) */ +/* */ +/* To use this, add it to your src in rules.mk, and include */ +/* tap_hold.h in your code above process_record_user. */ +/* */ +/* Add a call like this to use it. */ +/* process_tap_hold_user(keycode, record); */ +/* */ +/* Note: You must add any custom keycodes to your keycodes enum */ +/* otherwise they will not exist. */ + + +#include USERSPACE_H +#include "stdint.h" +#include "tap_hold.h" +void update_smart_lock(uint16_t keycode); + + +void tap_taplong(uint16_t kc1, uint16_t kc2, keyrecord_t *record) { + if (record->event.pressed) { + tap_taplong_timer = timer_read(); + } else { + if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) { + tap_code16(kc2); + } else { + tap_code16(kc1); + } + } +} + +void tap_sml(uint16_t kc1, uint16_t kc2, keyrecord_t *record) { + if (record->event.pressed) { + tap_taplong_timer = timer_read(); + } else { + if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) { + update_smart_lock(kc2); + } else { + tap_code16(kc1); + } + } +} + +/* for (){}[]""''<>``. tap for open. Hold for open and close, ending inbetween. */ +/* Assumes a one character length. */ +void open_openclose(uint16_t kc1, uint16_t kc2, keyrecord_t *record) { + if (record->event.pressed) { + tap_taplong_timer = timer_read(); + }else{ + if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) { + tap_code16(kc1); + tap_code16(kc2); + tap_code16(KC_LEFT); + + } else { + // is shifted + uint16_t mod_state = get_mods(); + if ((mod_state & MOD_MASK_SHIFT) || + (get_oneshot_mods() & MOD_MASK_SHIFT)){ + del_mods(MOD_MASK_SHIFT); + del_oneshot_mods(MOD_MASK_SHIFT); + + tap_code16(kc1); + tap_code16(kc1); + tap_code16(kc1); + + set_mods(mod_state); + }else{ + tap_code16(kc1); + } + } + } +} + +// open and open close for dead keys. +void open_openclose_not_dead(uint16_t kc1, uint16_t kc2, keyrecord_t *record) { + if (record->event.pressed) { + tap_taplong_timer = timer_read(); + }else{ + if (timer_elapsed(tap_taplong_timer) > TAP_HOLD_TERM) { + tap_code16(kc1); + tap_code16(KC_SPACE); + tap_code16(kc2); + tap_code16(KC_SPACE); + tap_code16(KC_LEFT); + } else { + // is shifted - give a triple + uint16_t mod_state = get_mods(); + if ((mod_state & MOD_MASK_SHIFT) || + (get_oneshot_mods() & MOD_MASK_SHIFT)){ + del_mods(MOD_MASK_SHIFT); + del_oneshot_mods(MOD_MASK_SHIFT); + + tap_code16(kc1); + tap_code16(KC_SPACE); + tap_code16(kc1); + tap_code16(KC_SPACE); + tap_code16(kc1); + tap_code16(KC_SPACE); + + set_mods(mod_state); + }else{ + tap_code16(kc1); + tap_code16(KC_SPACE); + } + } + } +} + +// macros for use in tap_hold.defs. +#define TP_TPL(KCKEY, KC01, KC02) \ + case KCKEY: \ + tap_taplong(KC01, KC02, record); \ + break; + +#define TP_SML(KCKEY, KC01, KC02) \ + case KCKEY: \ + tap_sml(KC01, KC02, record); \ + break; + +#define OPEN_OCL(KCKEY, KC01, KC02) \ + case KCKEY: \ + open_openclose(KC01, KC02, record); \ + break; + +#define OPEN_OCL_ND(KCKEY, KC01, KC02) \ + case KCKEY: \ + open_openclose_not_dead(KC01, KC02, record); \ + break; + +void process_tap_hold_user(uint16_t keycode, keyrecord_t *record) { + switch(keycode){ +#include "tap_hold.def" + } +} diff --git a/users/ericgebhart/extensions/tap_hold.h b/users/ericgebhart/extensions/tap_hold.h new file mode 100644 index 0000000000..e5b3c42d8a --- /dev/null +++ b/users/ericgebhart/extensions/tap_hold.h @@ -0,0 +1,20 @@ +#pragma once +/* + Copyright 2022 Eric Gebhart + + 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 . +*/ + +void process_tap_hold_user(uint16_t keycode, keyrecord_t* record); +uint16_t tap_taplong_timer; diff --git a/users/ericgebhart/extensions/unicode.c b/users/ericgebhart/extensions/unicode.c new file mode 100644 index 0000000000..fe44c69b1c --- /dev/null +++ b/users/ericgebhart/extensions/unicode.c @@ -0,0 +1,34 @@ +/* + Copyright 2018 Eric Gebhart + + 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 . +*/ +#include USERSPACE_H +#include "process_unicode_common.h" + +#undef UC_STR +#define UC_STR(KEYC, STRING) \ + case KEYC: \ + if (record->event.pressed) { \ + send_unicode_string(STRING); \ + } \ + break; + +void process_unicode_strs(uint16_t keycode, keyrecord_t *record){ +#if defined(UNICODE_ENABLE) && defined(SEND_UNICODE_ENABLE) + switch (keycode) { +#include "unicode.def" + } +#endif +} diff --git a/users/ericgebhart/extensions/unicode.h b/users/ericgebhart/extensions/unicode.h new file mode 100644 index 0000000000..eecf05d1bc --- /dev/null +++ b/users/ericgebhart/extensions/unicode.h @@ -0,0 +1,24 @@ +#pragma once +/* + Copyright 2018-2022 Eric Gebhart + + 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 . +*/ +// Custom one-or-more-shot implementation that does not rely on timers +// and persists across layer changes. Based on the users/callum implementation +// at https://github.com/callum-oakley/qmk_firmware/tree/master/users/callum +// make it easy to put unicode keys into process_record + + +void process_unicode_strs(uint16_t keycode, keyrecord_t *record); -- cgit v1.2.3