Eric Gebhart user space and keymaps (#17487)

Co-authored-by: Drashna Jaelre <drashna@live.com>
This commit is contained in:
Eric Gebhart 2022-11-12 00:09:41 +01:00 committed by GitHub
parent 49a78b8114
commit 050472a4d0
Failed to generate hash of commit
147 changed files with 13177 additions and 4102 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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]

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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;}

View file

@ -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

View file

@ -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

View file

@ -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
}
}

View file

@ -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;
}
}

View file

@ -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:

View file

@ -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"
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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; }

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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
}

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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"
}
}

View file

@ -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;

View file

@ -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
}

View file

@ -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);