diff options
author | Eric Gebhart <e.a.gebhart@gmail.com> | 2018-06-08 19:06:25 +0200 |
---|---|---|
committer | Drashna Jaelre <drashna@live.com> | 2018-06-08 10:06:25 -0700 |
commit | 984621835d929b79a22ef33c0a4e602adb1ecc5b (patch) | |
tree | 11637c54105b229f3127b019ff0cc962926fb770 /users/ericgebhart | |
parent | 03c9deb7456d84a8d8cc31496ae2736305bbafd3 (diff) |
Keyboard that works on Qwerty or Bepo OS keyboards. (#3149)
* New layout.
* new dvorak bepo layout.
* first commit of new ergodox_ez dvorak keyboard for qwerty and bepo.
Diffstat (limited to 'users/ericgebhart')
-rwxr-xr-x | users/ericgebhart/config.h | 33 | ||||
-rw-r--r-- | users/ericgebhart/ericgebhart.c | 637 | ||||
-rw-r--r-- | users/ericgebhart/ericgebhart.h | 429 | ||||
-rwxr-xr-x | users/ericgebhart/flash-ergodox | 1 | ||||
-rw-r--r-- | users/ericgebhart/readme.md | 124 | ||||
-rwxr-xr-x | users/ericgebhart/rules.mk | 18 | ||||
-rwxr-xr-x | users/ericgebhart/switch-kbd | 74 |
7 files changed, 1316 insertions, 0 deletions
diff --git a/users/ericgebhart/config.h b/users/ericgebhart/config.h new file mode 100755 index 0000000000..934c3debba --- /dev/null +++ b/users/ericgebhart/config.h @@ -0,0 +1,33 @@ +#ifndef USERSPACE_CONFIG_H +#define USERSPACE_CONFIG_H + +#include "../../config.h" + +// Sets good default for the speed of the mouse. +#undef MOUSEKEY_INTERVAL +#undef MOUSEKEY_DELAY +#undef MOUSEKEY_TIME_TO_MAX +#undef MOUSEKEY_MAX_SPEED + +#define MOUSEKEY_INTERVAL 20 +#define MOUSEKEY_DELAY 100 +#define MOUSEKEY_TIME_TO_MAX 60 +#define MOUSEKEY_MAX_SPEED 7 + +#undef MOUSEKEY_WHEEL_MAX_SPEED +#undef MOUSEKEY_WHEEL_TIME_TO_MAX +#undef MOUSEKEY_WHEEL_DELAY + +#define MOUSEKEY_WHEEL_MAX_SPEED 5 +#define MOUSEKEY_WHEEL_TIME_TO_MAX 60 +#define MOUSEKEY_WHEEL_DELAY 100 + +#undef TAPPING_TOGGLE +#undef TAPPING_TERM +#undef IGNORE_MOD_TAP_INTERRUPT + +#define TAPPING_TOGGLE 1 +#define TAPPING_TERM 200 +#define IGNORE_MOD_TAP_INTERRUPT + +#endif diff --git a/users/ericgebhart/ericgebhart.c b/users/ericgebhart/ericgebhart.c new file mode 100644 index 0000000000..69aa450e0a --- /dev/null +++ b/users/ericgebhart/ericgebhart.c @@ -0,0 +1,637 @@ +/* + 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 "ericgebhart.h" + +#include "quantum.h" +#include "version.h" +#include "action.h" +#include "action_layer.h" +#include "process_keycode/process_tap_dance.h" +#include "keymap_bepo.h" + +float tone_copy[][2] = SONG(SCROLL_LOCK_ON_SOUND); +float tone_paste[][2] = SONG(SCROLL_LOCK_OFF_SOUND); + +static uint16_t copy_paste_timer; +userspace_config_t userspace_config; + +void tap(uint16_t keycode){ register_code(keycode); unregister_code(keycode); }; + + +// Add reconfigurable functions here, for keymap customization +// This allows for a global, userspace functions, and continued +// customization of the keymap. Use _keymap instead of _user +// functions in the keymaps +__attribute__ ((weak)) +void matrix_init_keymap(void) {} + +__attribute__ ((weak)) +void matrix_scan_keymap(void) {} + +__attribute__ ((weak)) +bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { + return true; +} + +__attribute__ ((weak)) +bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { + return true; +} + +__attribute__ ((weak)) +uint32_t layer_state_set_keymap (uint32_t state) { + return state; +} + +__attribute__ ((weak)) +void led_set_keymap(uint8_t usb_led) {} + +// Runs just one time when the keyboard initializes. +void matrix_init_user(void) { + //ACTION_DEFAULT_LAYER_SET(DVORAK) ; +} + +// check default layerstate to see which layer we are on. +// if (biton32(layer_state) == _DIABLO) { --- current layer +// if (biton32(default_layer_state) == _DIABLO) { --- current default layer +// check for left shift on. +// if (mods & MOD_BIT(KC_LSFT)) register_code(KC_LSFT); + +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; + } +*/ + +// 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 +// reasnably sized array without difficulties. The macro is for the constant declarations +// the function is for when we use it. +const uint8_t key_translations[][2][2] = { + [GR(DB_1)] = {{BP_DQOT, MOD_LSFT}, {BP_DCRC, MOD_LSFT}}, + [GR(DB_2)] = {{BP_LGIL, MOD_LSFT}, {BP_AT, MOD_NONE}}, + [GR(DB_3)] = {{BP_RGIL, MOD_LSFT}, {BP_DLR, MOD_LSFT}}, + [GR(DB_4)] = {{BP_LPRN, MOD_LSFT}, {BP_DLR, MOD_NONE}}, + [GR(DB_5)] = {{BP_RPRN, MOD_LSFT}, {BP_PERC, MOD_NONE}}, + [GR(DB_6)] = {{BP_AT, MOD_LSFT}, {BP_AT, MOD_BIT(KC_RALT)}}, + [GR(DB_7)] = {{BP_PLUS, MOD_LSFT}, {BP_P, MOD_BIT(KC_RALT)}}, + [GR(DB_8)] = {{BP_MINS, MOD_LSFT}, {BP_ASTR, MOD_NONE}}, + [GR(DB_9)] = {{BP_SLASH, MOD_LSFT}, {BP_LPRN, MOD_NONE}}, + [GR(DB_0)] = {{BP_ASTR, MOD_LSFT}, {BP_RPRN, MOD_NONE}}, + [GR(DB_GRV)] = {{BP_PERC, MOD_LSFT}, {BP_K, MOD_BIT(KC_RALT)}}, + [GR(DB_SCOLON)] = {{BP_COMM, MOD_LSFT}, {BP_DOT, MOD_LSFT}}, + [GR(DB_SLASH)] = {{BP_SLASH, MOD_NONE}, {BP_APOS, MOD_LSFT}}, + [GR(DB_BACKSLASH)] = {{BP_AGRV, MOD_BIT(KC_RALT)}, {BP_B, MOD_BIT(KC_RALT)}}, + [GR(DB_EQL)] = {{BP_EQL, MOD_NONE}, {BP_PLUS, MOD_NONE}}, + [GR(DB_COMM)] = {{BP_COMMA, MOD_NONE}, {BP_LGIL, MOD_BIT(KC_RALT)}}, + [GR(DB_DOT)] = {{BP_DOT, MOD_NONE}, {BP_RGIL, MOD_BIT(KC_RALT)}}, + [GR(DB_QUOT)] = {{BP_APOS, MOD_NONE}, {BP_DQOT, MOD_NONE}}, + [GR(DB_MINUS)] = {{BP_MINUS, MOD_NONE}, {KC_SPC, MOD_BIT(KC_RALT)}}, + [GR(DB_LPRN)] = {{BP_LPRN, MOD_NONE}, {BP_LPRN, MOD_BIT(KC_RALT)}}, + [GR(DB_RPRN)] = {{BP_RPRN, MOD_NONE}, {BP_RPRN, MOD_BIT(KC_RALT)}}, + [GR(DB_LBRC)] = {{BP_Y, MOD_BIT(KC_RALT)}, {BP_LPRN, MOD_BIT(KC_RALT)}}, + [GR(DB_RBRC)] = {{BP_X, MOD_BIT(KC_RALT)}, {BP_RPRN, MOD_BIT(KC_RALT)}}, + // For the symbol layer + [GR(DB_HASH)] = {{BP_DLR, MOD_LSFT}, {BP_DLR, MOD_LSFT}}, + [GR(DB_LCBR)] = {{BP_LPRN, MOD_BIT(KC_RALT)}, {BP_LPRN, MOD_BIT(KC_RALT)}}, + [GR(DB_RCBR)] = {{BP_LPRN, MOD_BIT(KC_RALT)}, {BP_RPRN, MOD_BIT(KC_RALT)}}, + [GR(DB_PIPE)] = {{BP_B, MOD_BIT(KC_RALT)}, {BP_B, MOD_BIT(KC_RALT)}}, + [GR(DB_TILD)] = {{BP_K, MOD_BIT(KC_RALT)}, {BP_K, MOD_BIT(KC_RALT)}}, + [GR(DB_CIRC)] = {{BP_AT, MOD_BIT(KC_RALT)}, {BP_AT, MOD_BIT(KC_RALT)}}, + [GR(DB_LESS)] = {{BP_LGIL, MOD_BIT(KC_RALT)}, {BP_LGIL, MOD_BIT(KC_RALT)}}, + [GR(DB_GRTR)] = {{BP_RGIL, MOD_BIT(KC_RALT)}, {BP_RGIL, MOD_BIT(KC_RALT)}}, + + +}; + + +uint8_t gr(uint8_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(uint8_t kc){ + uint8_t tmp_mods = get_mods(); + bool is_shifted = ( tmp_mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) ); + //uint8_t key[2][2] = key_translations[GR(kc)]; + // 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_code(SHIFTED_KEY(kc)); + unregister_code(SHIFTED_KEY(kc)); + unregister_mods(SHIFTED_MODS(kc)); + } else{ + register_mods(UNSHIFTED_MODS(kc)); + register_code(UNSHIFTED_KEY(kc)); + unregister_code(UNSHIFTED_KEY(kc)); + unregister_mods(UNSHIFTED_MODS(kc)); + } + clear_mods(); + register_mods(tmp_mods); +} + + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + +// If console is enabled, it will print the matrix position and status of each key pressed +#ifdef KEYLOGGER_ENABLE +xprintf("KL: row: %u, column: %u, pressed: %u\n", record->event.key.col, record->event.key.row, record->event.pressed); +#endif //KEYLOGGER_ENABLE + +// still dont know how to make #&_ And RALT is not ALTGR, That isn't working in the bepo keyboard +// either. No {} either probably for the same reasons. ALtGR is the key to some of these. + switch (keycode) { + // Handle the key translations for Dvorak on bepo. It's best if these are the first + // enums after SAFE_RANGE. + case DB_1: + case DB_2: + case DB_3: + case DB_4: + case DB_5: + case DB_6: + case DB_7: + case DB_8: + case DB_9: + case DB_0: + case DB_GRV: + case DB_SCOLON: + case DB_SLASH: + case DB_BACKSLASH: + case DB_EQL: + case DB_DOT: + case DB_COMM: + case DB_QUOT: + case DB_MINUS: + case DB_LPRN: + case DB_RPRN: + case DB_LBRC: + case DB_RBRC: + if(record->event.pressed) + send_keycode(keycode); + unregister_code(keycode); + break; + + case KC_QWERTY: + if (record->event.pressed) { + set_single_persistent_default_layer(QWERTY); + } + return false; + break; + case KC_COLEMAK: + if (record->event.pressed) { + set_single_persistent_default_layer(COLEMAK); + } + return false; + break; + case KC_DVORAK: + if (record->event.pressed) { + set_single_persistent_default_layer(DVORAK); + } + return false; + break; + case KC_WORKMAN: + if (record->event.pressed) { + set_single_persistent_default_layer(WORKMAN); + } + return false; + break; + + case KC_MAKE: // Compiles the firmware, and adds the flash command based on keyboard bootloader + if (!record->event.pressed) { + SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP +#if (defined(BOOTLOADER_DFU) || defined(BOOTLOADER_LUFA_DFU) || defined(BOOTLOADER_QMK_DFU)) + ":dfu" +#elif defined(BOOTLOADER_HALFKAY) + ":teensy" +#elif defined(BOOTLOADER_CATERINA) + ":avrdude" +#endif // bootloader options + SS_TAP(X_ENTER)); + } + return false; + break; + + + case KC_RESET: // Custom RESET code + if (!record->event.pressed) { + reset_keyboard(); + } + return false; + break; + + + case EPRM: // Resets EEPROM + if (record->event.pressed) { + eeconfig_init(); + default_layer_set(1UL<<eeconfig_read_default_layer()); + layer_state_set(layer_state); + } + return false; + break; + case VRSN: // Prints firmware version + if (record->event.pressed) { + SEND_STRING(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION ", Built on: " QMK_BUILDDATE); + } + return false; + break; + + /* Code has been depreciated + case KC_SECRET_1 ... KC_SECRET_5: // Secrets! Externally defined strings, not stored in repo + if (!record->event.pressed) { + clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); + send_string(decoy_secret[keycode - KC_SECRET_1]); + } + return false; + break; + */ + + // These are a serious of gaming macros. + // Only enables for the viterbi, basically, + // to save on firmware space, since it's limited. +#ifdef MACROS_ENABLED + case KC_OVERWATCH: // Toggle's if we hit "ENTER" or "BACKSPACE" to input macros + if (record->event.pressed) { userspace_config.is_overwatch ^= 1; eeprom_update_byte(EECONFIG_USERSPACE, userspace_config.raw); } + return false; break; +#endif // MACROS_ENABLED + + case KC_CCCV: // One key copy/paste + if(record->event.pressed){ + copy_paste_timer = timer_read(); + } else { + if (timer_elapsed(copy_paste_timer) > TAPPING_TERM) { // Hold, copy + register_code(KC_LCTL); + tap(KC_C); + unregister_code(KC_LCTL); +#ifdef AUDIO_ENABLE + PLAY_SONG(tone_copy); +#endif + } else { // Tap, paste + register_code(KC_LCTL); + tap(KC_V); + unregister_code(KC_LCTL); +#ifdef AUDIO_ENABLE + PLAY_SONG(tone_paste); +#endif + } + } + return false; + break; + case CLICKY_TOGGLE: +#ifdef AUDIO_CLICKY + userspace_config.clicky_enable = clicky_enable; + eeprom_update_byte(EECONFIG_USERSPACE, userspace_config.raw); +#endif + break; +#ifdef UNICODE_ENABLE + case UC_FLIP: // (╯°□°)╯ ︵ ┻━┻ + if (record->event.pressed) { + register_code(KC_RSFT); + tap(KC_9); + unregister_code(KC_RSFT); + process_unicode((0x256F | QK_UNICODE), record); // Arm + process_unicode((0x00B0 | QK_UNICODE), record); // Eye + process_unicode((0x25A1 | QK_UNICODE), record); // Mouth + process_unicode((0x00B0 | QK_UNICODE), record); // Eye + register_code(KC_RSFT); + tap(KC_0); + unregister_code(KC_RSFT); + process_unicode((0x256F | QK_UNICODE), record); // Arm + tap(KC_SPC); + process_unicode((0x0361 | QK_UNICODE), record); // Flippy + tap(KC_SPC); + process_unicode((0x253B | QK_UNICODE), record); // Table + process_unicode((0x2501 | QK_UNICODE), record); // Table + process_unicode((0x253B | QK_UNICODE), record); // Table + } + return false; + break; +#endif // UNICODE_ENABLE + +} + +return true; + // return process_record_keymap(keycode, record) && process_record_secrets(keycode, record); +} + +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)); + return (deflayer < DVORAK_ON_BEPO); +} + +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_ON_BEPO); + 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_ON_BEPO); + break; + case 2: + layer_invert(MDIA); + break; + case 3: + layer_invert(LAYERS); + 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_ON_BEPO); + 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_ON_BEPO); + break; + case 2: + switch_default_layer(BEPO); + break; + default: + switch_default_layer(DVORAK_ON_BEPO); + 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 +} +//instanalize an instance of 'tap' for the 'x' tap dance. +static tdtap xtap_state = { + .is_press_action = true, + .state = 0 +}; +/* + This so I can have a single key that acts like LGUI in DVORAK no + matter which keymap is my current default. + It also allows for the + shift gui and ctl gui, on the same key, So the same key is Escape, + and the mostcommon modifiers in my xmonad control keymap, while also + insuring that dvorak is active for the xmonad command key + Single tap = ESC + tap and hold = dvorak with L_GUI + double tap = One shot dvorak layer with LSFT LGUI mods + double hold = dvorak with LCTL LGUI + double single tap = esc. +*/ +int get_xmonad_layer(){ + int qwerty = on_qwerty(); + + if (qwerty) + return(XMONAD); + else + return(XMONAD_FR); +} + + +void x_finished (qk_tap_dance_state_t *state, void *user_data) { + int xmonad_layer = get_xmonad_layer(); + xtap_state.state = cur_dance(state); + switch (xtap_state.state) { + case SINGLE_TAP: + register_code(KC_ESC); + break; + case SINGLE_HOLD: + layer_on(xmonad_layer); + set_oneshot_mods (MOD_LGUI); + //set_oneshot_layer (DVORAK, ONESHOT_START); + break; + case DOUBLE_TAP: + set_oneshot_mods ((MOD_LCTL | MOD_LGUI)); + layer_on (xmonad_layer); + set_oneshot_layer (xmonad_layer, ONESHOT_START); + break; + case DOUBLE_HOLD: + set_oneshot_mods (MOD_LSFT | MOD_LGUI); + if (xmonad_layer != -1) + layer_on(xmonad_layer); + break; + case DOUBLE_SINGLE_TAP: + register_code(KC_ESC); + unregister_code(KC_ESC); + register_code(KC_ESC); + //Last case is for fast typing. Assuming your key is `f`: + //For example, when typing the word `buffer`, and you want to make sure that you send `ff` and not `Esc`. + //In order to type `ff` when typing fast, the next character will have to be hit within the `TAPPING_TERM`, which by default is 200ms. + } +} + +void x_reset (qk_tap_dance_state_t *state, void *user_data) { + int xmonad_layer = get_xmonad_layer(); + switch (xtap_state.state) { + case SINGLE_TAP: + unregister_code(KC_ESC); + break; + case SINGLE_HOLD: + layer_off(xmonad_layer); + break; + case DOUBLE_TAP: + set_oneshot_layer (xmonad_layer, ONESHOT_PRESSED); + break; + case DOUBLE_HOLD: + layer_off(xmonad_layer); + break; + case DOUBLE_SINGLE_TAP: + unregister_code(KC_ESC); + } + xtap_state.state = 0; +} + +//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_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_XMONAD_ESC] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished, x_reset), + [TD_MOUSE_BTNS] = ACTION_TAP_DANCE_FN(tap_dance_mouse_btns) +}; diff --git a/users/ericgebhart/ericgebhart.h b/users/ericgebhart/ericgebhart.h new file mode 100644 index 0000000000..6eb11ddfc0 --- /dev/null +++ b/users/ericgebhart/ericgebhart.h @@ -0,0 +1,429 @@ +/* + 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 QMK_KEYBOARD_H + +#ifndef ericgebhart +#define ericgebhart + +#include "quantum.h" +#include "process_keycode/process_tap_dance.h" + + +void tap(uint16_t keycode); +bool process_record_secrets(uint16_t keycode, keyrecord_t *record); + + +#define EECONFIG_USERSPACE (uint8_t *)19 + +typedef union { + uint8_t raw; + struct { + bool clicky_enable :1; + bool rgb_layer_change :1; + bool is_overwatch :1; + bool nuke_switch :1; + }; +} userspace_config_t; + +#define ___ KC_TRNS +#define XXX KC_NO + +// The most portable copy/paste keys (windows (mostly), linux, and some terminal emulators). +#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 DVORAK 0 // dvorak layout (default) +#define QWERTY 1 +#define COLEMAK 2 +#define WORKMAN 3 +#define NORMAN 4 +// bepo layers +#define DVORAK_ON_BEPO 6 // dvorak layout (default) +#define BEPO 7 // Bepo +// non-default layers +#define SYMB 8 // symbols and numbers +#define SYMB_ON_BEPO 9 // symbols and numbers +#define MDIA 10 // mouse knd media eys +#define LAYERS 11 // layers and right mousekeys. +#define XMONAD 12 // xmonad ie. dvorak. +#define XMONAD_FR 13 // xmonad ie. dvorak. + + +// for the creation of dvorak keys on an Bepo keyboard at the OS layer. + +// so we can create an array of reasonable size +// for our translation keys. We have to create a +// good range of numbers +#define GR(x) (x-SAFE_RANGE) + +uint8_t gr(uint8_t); +void send_keycode(uint8_t); + +#define MOD_NONE 0x00 + +// indexs for the keycode translation table. +#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] + + +enum userspace_custom_keycodes { + // keep the keycodes using the send_key function close to SAFE_RANGE + // so the array of keycodes remains a reasonbale size. + DB_1 = SAFE_RANGE, // can always be here + DB_2, + DB_3, + DB_4, + DB_5, + DB_6, + DB_7, + DB_8, + DB_9, + DB_0, + DB_GRV, + DB_SCOLON, + DB_SLASH, + DB_BACKSLASH, + DB_EQL, + DB_DOT, + DB_COMM, + DB_QUOT, + DB_MINUS, + DB_RPRN, + DB_LPRN, + DB_RBRC, + DB_LBRC, + // for symbols layer + DB_HASH, + DB_LCBR, + DB_RCBR, + DB_PIPE, + DB_TILD, + DB_CIRC, + DB_LESS, + DB_GRTR, + // End of dvorak on bepo translation keys. + + EPRM, + VRSN, + KC_DVORAK_ON_BEPO, + KC_BEPO, + KC_NORMAN, + KC_QWERTY, + KC_COLEMAK, + KC_DVORAK, + KC_WORKMAN, + KC_MAKE, + KC_RESET, + KC_RGB_T, + KC_SECRET_1, + KC_SECRET_2, + KC_SECRET_3, + KC_SECRET_4, + KC_SECRET_5, + KC_CCCV +}; + +#define SFTGUI_T(kc) { MT(MOD_LGUI | MOD_LSFT, kc) } +#define SFT_GUI_ESC MT(MOD_LSFT | MOD_LGUI, KC_PGDN) // shift LGUI or Escape. +#define ALT_ENT ALT_T(KC_ENT) // Alt or enter +#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(SYMB)) // Alt gre or toggle symbol layer + +#define KC_SFT_T_U SFT_T(KC_U) +#define KC_SFT_T_H SFT_T(KC_H) +#define KC_LT_SYMB_I LT(SYMB, KC_I) +#define KC_LT_SYMB_D LT(SYMB, KC_D) + +// for dvorak on bepo +#define BP_SFT_T_U SFT_T(BP_U) +#define BP_SFT_T_H SFT_T(BP_H) +#define BP_LT_SYMB_D LT(SYMB, BP_D) + + +// for bepo on bepo +#define BP_SFT_T_T SFT_T(BP_T) +#define BP_LT_SYMB_C LT(SYMB_ON_BEPO, BP_C) +#define BP_LT_SYMB_I LT(SYMB_ON_BEPO, BP_I) +#define BP_SFT_T_E SFT_T(BP_E) +#define BP_SFT_T_ECRC SFT_T(BP_ECRC) +#define BP_SFT_T_CCED SFT_T(BP_CCED) +#define BP_LT_SYMB_COMM LT(SYMB,BP_COMM) + +// OSM keycodes, to keep things clean and easy to change +#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 + + +//// 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 + }; + + +// Tap dance +#define TAB_BKTAB TD(TD_TAB_BKTAB) // Tab or backtab tapdance. +#define MDIA_SYMB TD(TD_MDIA_SYMB) // MDIA or Symb 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 + + +int on_qwerty(void); +int get_xmonad_layer(void); +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); + + +// Blocks for each of the four major keyboard layouts +// Organized so we can quickly adapt and modify all of them +// at once, rather than for each keyboard, one at a time. +// And this allows for much cleaner blocks in the keymaps. +// For instance Tap/Hold for Control on all of the layouts + +// NOTE: These are all the same length. If you do a search/replace +// then you need to add/remove underscores to keep the +// lengths consistent. + +// Since our quirky block definitions are basically a list of comma separated +// arguments, we need a wrapper in order for these definitions to be +// expanded before being used as arguments to the LAYOUT_xxx macro. +#if (!defined(LAYOUT) && defined(KEYMAP)) +#define LAYOUT KEYMAP +#endif + +#define LAYOUT_ergodox_wrapper(...) LAYOUT_ergodox(__VA_ARGS__) +#define LAYOUT_ergodox_pretty_wrapper(...) LAYOUT_ergodox_pretty(__VA_ARGS__) +#define KEYMAP_wrapper(...) LAYOUT(__VA_ARGS__) +#define LAYOUT_wrapper(...) LAYOUT(__VA_ARGS__) + +//Dvorak on a qwerty software layer in the OS +#define ___DVORAK_L1___ KC_QUOT, KC_COMM, KC_DOT, KC_P, KC_Y +#define ___DVORAK_L2___ KC_A, KC_O, KC_E, KC_SFT_T_U, KC_LT_SYMB_I +#define ___DVORAK_L3___ KC_SCLN, KC_Q, KC_J, KC_K, KC_X + +#define ___DVORAK_R1___ KC_F, KC_G, KC_C, KC_R, KC_L +#define ___DVORAK_R2___ KC_LT_SYMB_D, KC_SFT_T_H, KC_T, KC_N, KC_S +#define ___DVORAK_R3___ KC_B, KC_M, KC_W, KC_V, KC_Z + + +// Dvorak on fr-bepo software layer in the OS. +// for dvorak and all the other qwerty like keyboards on bepo +#define ___NUMBER_BEPO_L___ DB_1, DB_2, DB_3, DB_4, DB_5 +#define ___NUMBER_BEPO_R___ DB_6, DB_7, DB_8, DB_9, DB_0 + +#define ___DVORAK_FR_L1___ DB_QUOT, DB_COMM, DB_DOT, BP_P, BP_Y +#define ___DVORAK_FR_L2___ BP_A, BP_O, BP_E, BP_SFT_T_U, BP_LT_SYMB_I +#define ___DVORAK_FR_L3___ DB_SCOLON, BP_Q, BP_J, BP_K, BP_X + +#define ___DVORAK_FR_R1___ BP_F, BP_G, BP_C, BP_R, BP_L +#define ___DVORAK_FR_R2___ BP_LT_SYMB_D, BP_SFT_T_H, BP_T, BP_N, BP_S +#define ___DVORAK_FR_R3___ BP_B, BP_M, BP_W, BP_V, BP_Z + + +// Bepo on fr-bepo software layer +// for bepo on bepo +#define ___SYMBOL_BEPO_L___ /* BP_DLR */ BP_DQOT, BP_LGIL, BP_RGIL, BP_LPRN, BP_RPRN +#define ___SYMBOL_BEPO_R___ BP_AT, BP_PLUS, BP_MINS, BP_SLASH, BP_ASTR /* BP_EQL, BP_PERC */ + +#define ___BEPO_FR_L1___ BP_B, BP_ECUT, BP_P, BP_O, BP_EGRV +#define ___BEPO_FR_L2___ BP_A, BP_U, BP_I, BP_SFT_T_E, BP_LT_SYMB_COMM +#define ___BEPO_FR_L3___ /*BP_ECRC*/ BP_AGRV, BP_Y, BP_X, BP_DOT, BP_K + +#define ___BEPO_FR_R1___ /* BP_DCRC*/ BP_V, BP_D, BP_L, BP_J, BP_Z //, BP_W +#define ___BEPO_FR_R2___ /* BP_C */ BP_SFT_T_T, BP_S, BP_R, BP_N, BP_M //BP_CCED +#define ___BEPO_FR_R3___ BP_APOS, BP_Q, BP_G, BP_H, BP_F + +// the bottom rows for keyboards on bepo. +#define ___ERGODOX_BOTTOM_RIGHT_FR___ KC_UP, KC_DOWN, DB_BACKSLASH, LCTL(BP_V), LCTL(BP_C) +#define ___ERGODOX_BOTTOM_LEFT_FR___ LCTL(BP_C), LCTL(BP_V), KC_INS, KC_LEFT, KC_RIGHT + +// Since we have 7 default layouts (QWERTY, DVORAK, COLEMAK and WORKMAN, NORMAN, +// 2 of them based on a Bepo software keyboard, --- DVORAK_ON_BEPO and BEPO), +// this allows us to quickly modify the bottom row for all of the layouts +// so we don't have to alter it 4 times and hope that we haven't missed +// anything +#define ___ERGODOX_BOTTOM_LEFT___ LCTL(KC_C), LCTL(KC_V), KC_INS, KC_LEFT, KC_RIGHT +#define ___ERGODOX_BOTTOM_RIGHT___ KC_UP, KC_DOWN, KC_BSLASH, LCTL(KC_V), LCTL(KC_C) + +#define ___ERGODOX_THUMB_LEFT___ \ + KC_RALT, ALGR_SYMB, \ + HOME_END, \ + CTL_BSPC, ALT_DEL, XMONAD_ESC + +#define ___ERGODOX_THUMB_RIGHT___ \ + ALGR_SYMB, TD_MOUSE_BTNS, \ + KC_PGUP, \ + KC_PGDN, ALT_ENT, CTL_SPC |