summaryrefslogtreecommitdiff
path: root/users/ericgebhart/extensions
diff options
context:
space:
mode:
authorDrashna Jael're <drashna@live.com>2022-11-12 17:10:04 -0800
committerDrashna Jael're <drashna@live.com>2022-11-12 17:10:04 -0800
commit731633e133de428408cd313fbd65fb0a36145672 (patch)
treeb788a9fe150a353ce20d338848d3dab2bbc42879 /users/ericgebhart/extensions
parent6cc9513ab0cd5e21354c51ab83a89af9f2eb517e (diff)
parent2e39647618295e4a2ba685cfb8e3ab36622e92ee (diff)
Merge remote-tracking branch 'origin/master' into develop
Diffstat (limited to 'users/ericgebhart/extensions')
-rw-r--r--users/ericgebhart/extensions/accented_keys.c50
-rw-r--r--users/ericgebhart/extensions/accented_keys.h19
-rw-r--r--users/ericgebhart/extensions/alt_shift.c99
-rw-r--r--users/ericgebhart/extensions/altlocal_keys.c82
-rw-r--r--users/ericgebhart/extensions/altlocal_keys.h56
-rw-r--r--users/ericgebhart/extensions/console_key_logger.c38
-rw-r--r--users/ericgebhart/extensions/console_key_logger.h19
-rw-r--r--users/ericgebhart/extensions/encoders.c83
-rw-r--r--users/ericgebhart/extensions/encoders.h46
-rw-r--r--users/ericgebhart/extensions/extensions.c91
-rw-r--r--users/ericgebhart/extensions/extensions.h22
-rw-r--r--users/ericgebhart/extensions/key_overrides.h53
-rwxr-xr-xusers/ericgebhart/extensions/keycodes.h523
-rw-r--r--users/ericgebhart/extensions/keymap_combo.h139
-rw-r--r--users/ericgebhart/extensions/mod_lock.c81
-rw-r--r--users/ericgebhart/extensions/mod_lock.h39
-rw-r--r--users/ericgebhart/extensions/not_dead.c36
-rw-r--r--users/ericgebhart/extensions/nshot_mod.c154
-rw-r--r--users/ericgebhart/extensions/nshot_mod.h45
-rw-r--r--users/ericgebhart/extensions/oneshot.c217
-rw-r--r--users/ericgebhart/extensions/oneshot.h37
-rw-r--r--users/ericgebhart/extensions/process_locales.h29
-rw-r--r--users/ericgebhart/extensions/process_nshot.h21
-rw-r--r--users/ericgebhart/extensions/process_smart_lock.h19
-rw-r--r--users/ericgebhart/extensions/quick_tap.c37
-rw-r--r--users/ericgebhart/extensions/send_string.c40
-rw-r--r--users/ericgebhart/extensions/smart_lock.c117
-rw-r--r--users/ericgebhart/extensions/smart_lock.h103
-rw-r--r--users/ericgebhart/extensions/swapper.c58
-rw-r--r--users/ericgebhart/extensions/swapper.h37
-rwxr-xr-xusers/ericgebhart/extensions/tap_dances.c277
-rwxr-xr-xusers/ericgebhart/extensions/tap_dances.h19
-rw-r--r--users/ericgebhart/extensions/tap_hold.c165
-rw-r--r--users/ericgebhart/extensions/tap_hold.h20
-rw-r--r--users/ericgebhart/extensions/unicode.c34
-rw-r--r--users/ericgebhart/extensions/unicode.h24
36 files changed, 2929 insertions, 0 deletions
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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include USERSPACE_H
+#include "accented_keys.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+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 <stdbool.h>
+#include <stdint.h>
+
+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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "quantum.h"
+#include "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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+// 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,
+ /* <missing row information> */
+ /* <missing column information> */
+ 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 <e.a.gebhart@gmail.com>, @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 <http://www.gnu.org/licenses/>.
+*/
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>, @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 <http://www.gnu.org/licenses/>.
+*/
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+///* -------- 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 <e.a.gebhart@gmail.com>, @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 <http://www.gnu.org/licenses/>.
+*/
+
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include 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 <e.a.gebhart@gmail.com, @possumvibes,@Callum.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+// 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#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<<layer);
+ clear_keyboard();
+}
+
+// so the keyboard remembers which layer it's in after power disconnect.
+/*
+ uint32_t default_layer_state_set_kb(uint32_t state) {
+ eeconfig_update_default_layer(state);
+ return state;
+ }
+*/
+
+void tap_dance_df_bepo_layers_switch (qk_tap_dance_state_t *state, void *user_data) {
+ switch(state->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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include 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 <e.a.gebhart@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+// 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);