├── .gitignore ├── combos.c ├── config.h ├── keymap.c ├── precondition_keymap.h ├── readme.md ├── rules.mk ├── swap_hand.c ├── tapdance.c └── visualisation ├── heatmap └── all_layers.png ├── keymapviz └── keymapviz.ini └── kle ├── keyboard-layout-editor.json └── kle-base-sym-nav.png /.gitignore: -------------------------------------------------------------------------------- 1 | misc 2 | keymap.c.bac 3 | venv 4 | -------------------------------------------------------------------------------- /combos.c: -------------------------------------------------------------------------------- 1 | #include QMK_KEYBOARD_H 2 | #include "precondition_keymap.h" 3 | #include "action_tapping.h" // necessary for action_tapping_process 4 | #ifdef CONSOLE_ENABLE 5 | #include "print.h" 6 | #endif 7 | 8 | enum combo_events { 9 | /* Backspace steno-lite combos */ 10 | // These let me type common words and n-grams 11 | // more quickly, in one single stroke. 12 | BSPCEV_EVERY, 13 | BSPCU_YOU, 14 | BSPCA_AND, 15 | BSPCW_WITH, 16 | BSPCF_FOR, 17 | BSPCH_HERE, 18 | BSPCT_THE, 19 | BSPCM_MENT, 20 | BSPCG_ING, 21 | BSPCO_OUGH, 22 | BSPCOL_OULD, 23 | BSPCI_ION, 24 | BSPCIS_IONS, 25 | BSPCTA_THAT, 26 | BSPCQ_QUE, 27 | // I use the word "key" much more frequently than the common folk 28 | // and if you're reading this, you probably do too 29 | BSPCK_KEY, 30 | BSPCTS_THIS, 31 | BSPCDN_DONT, 32 | BSPCIT_IN_THE, 33 | 34 | /* Other steno-lite combos */ 35 | // Additional steno-lite combos for common words and n-grams 36 | // that do not involve the backspace thumb key because these 37 | // combinations of keys do not generate too many conflicts 38 | // in normal typing. 39 | HV_HAVE, 40 | QK_QMK, 41 | KB_KEYBOARD, 42 | WA_WHAT, 43 | 44 | /* Non-alphanumeric combos */ 45 | // Combos for which the output isn't one or more alphanumeric characters 46 | UYCLN_INDEX, 47 | OS_SFT_CAPS, 48 | REPEATX_BSLS, 49 | BSPCE_ESC, 50 | DOTSLASH_UPDIR, 51 | ZEROEIGHT_COMMA, 52 | EIGHTNINE_DOT, 53 | PT_MOUSE, 54 | 55 | // This must be the last item in the enum. 56 | // This is used to automatically update the combo count. 57 | COMBO_LENGTH 58 | }; 59 | uint16_t COMBO_LEN = COMBO_LENGTH; 60 | 61 | const uint16_t PROGMEM BSPC_E_V_COMBO[] = {KC_BSPC, HOME_E, KC_V, COMBO_END}; 62 | const uint16_t PROGMEM BSPC_U_COMBO[] = {KC_BSPC, KC_U, COMBO_END}; 63 | const uint16_t PROGMEM BSPC_A_COMBO[] = {KC_BSPC, HOME_A, COMBO_END}; 64 | const uint16_t PROGMEM BSPC_N_COMBO[] = {KC_BSPC, HOME_N, COMBO_END}; 65 | const uint16_t PROGMEM BSPC_W_COMBO[] = {KC_BSPC, KC_W, COMBO_END}; 66 | const uint16_t PROGMEM BSPC_F_COMBO[] = {KC_BSPC, KC_F, COMBO_END}; 67 | const uint16_t PROGMEM BSPC_H_COMBO[] = {KC_BSPC, KC_H, COMBO_END}; 68 | const uint16_t PROGMEM BSPC_T_COMBO[] = {KC_BSPC, HOME_T, COMBO_END}; 69 | const uint16_t PROGMEM BSPC_M_COMBO[] = {KC_BSPC, KC_M, COMBO_END}; 70 | const uint16_t PROGMEM BSPC_G_COMBO[] = {KC_BSPC, KC_G, COMBO_END}; 71 | const uint16_t PROGMEM BSPC_O_COMBO[] = {KC_BSPC, HOME_O, COMBO_END}; 72 | const uint16_t PROGMEM BSPC_O_L_COMBO[] = {KC_BSPC, HOME_O, KC_L, COMBO_END}; 73 | const uint16_t PROGMEM BSPC_I_COMBO[] = {KC_BSPC, HOME_I, COMBO_END}; 74 | const uint16_t PROGMEM BSPC_I_S_COMBO[] = {KC_BSPC, HOME_I, HOME_S, COMBO_END}; 75 | const uint16_t PROGMEM BSPC_Q_COMBO[] = {KC_BSPC, KC_Q, COMBO_END}; 76 | const uint16_t PROGMEM BSPC_K_COMBO[] = {KC_BSPC, KC_K, COMBO_END}; 77 | const uint16_t PROGMEM BSPC_T_S_COMBO[] = {KC_BSPC, HOME_T, HOME_S, COMBO_END}; 78 | const uint16_t PROGMEM K_B_COMBO[] = {KC_K, KC_B, COMBO_END}; 79 | const uint16_t PROGMEM BSPC_T_A_COMBO[] = {KC_BSPC, HOME_T, HOME_A, COMBO_END}; 80 | const uint16_t PROGMEM BSPC_D_N_COMBO[] = {KC_BSPC, KC_D, HOME_N, COMBO_END}; 81 | const uint16_t PROGMEM BSPC_I_T_COMBO[] = {KC_BSPC, HOME_I, HOME_T, COMBO_END}; 82 | const uint16_t PROGMEM H_V_COMBO[] = {KC_H, KC_V, COMBO_END}; 83 | const uint16_t PROGMEM Q_K_COMBO[] = {KC_Q, KC_K, COMBO_END}; 84 | const uint16_t PROGMEM W_A_COMBO[] = {KC_W, HOME_A, COMBO_END}; 85 | const uint16_t PROGMEM U_Y_SCLN_COMBO[] = {KC_U, KC_Y, KC_SCLN, COMBO_END}; 86 | const uint16_t PROGMEM OS_SFT_COMBO[] = {OS_LSFT, OS_RSFT, COMBO_END}; 87 | const uint16_t PROGMEM REPEAT_X_COMBO[] = {REPEAT, KC_X, COMBO_END}; 88 | const uint16_t PROGMEM BSPC_E_COMBO[] = {KC_BSPC, HOME_E, COMBO_END}; 89 | const uint16_t PROGMEM DOT_SLASH_COMBO[] = {TD_DOT, KC_SLSH, COMBO_END}; 90 | const uint16_t PROGMEM ZERO_EIGHT_COMBO[] = {KC_0, KC_8, COMBO_END}; 91 | const uint16_t PROGMEM EIGHT_NINE_COMBO[] = {KC_8, KC_9, COMBO_END}; 92 | const uint16_t PROGMEM P_T_COMBO[] = {KC_P, HOME_T, COMBO_END}; 93 | 94 | combo_t key_combos[] = { 95 | [BSPCEV_EVERY] = COMBO_ACTION(BSPC_E_V_COMBO), 96 | [BSPCU_YOU] = COMBO_ACTION(BSPC_U_COMBO), 97 | [BSPCA_AND] = COMBO_ACTION(BSPC_A_COMBO), 98 | [BSPCW_WITH] = COMBO_ACTION(BSPC_W_COMBO), 99 | [BSPCF_FOR] = COMBO_ACTION(BSPC_F_COMBO), 100 | [BSPCH_HERE] = COMBO_ACTION(BSPC_H_COMBO), 101 | [BSPCT_THE] = COMBO_ACTION(BSPC_T_COMBO), 102 | [BSPCM_MENT] = COMBO_ACTION(BSPC_M_COMBO), 103 | [BSPCG_ING] = COMBO_ACTION(BSPC_G_COMBO), 104 | [BSPCO_OUGH] = COMBO_ACTION(BSPC_O_COMBO), 105 | [BSPCOL_OULD] = COMBO_ACTION(BSPC_O_L_COMBO), 106 | [BSPCI_ION] = COMBO_ACTION(BSPC_I_COMBO), 107 | [BSPCIS_IONS] = COMBO_ACTION(BSPC_I_S_COMBO), 108 | [BSPCTA_THAT] = COMBO_ACTION(BSPC_T_A_COMBO), 109 | [BSPCQ_QUE] = COMBO_ACTION(BSPC_Q_COMBO), 110 | [BSPCK_KEY] = COMBO_ACTION(BSPC_K_COMBO), 111 | [BSPCTS_THIS] = COMBO_ACTION(BSPC_T_S_COMBO), 112 | [BSPCDN_DONT] = COMBO_ACTION(BSPC_D_N_COMBO), 113 | [BSPCIT_IN_THE] = COMBO_ACTION(BSPC_I_T_COMBO), 114 | [HV_HAVE] = COMBO_ACTION(H_V_COMBO), 115 | [QK_QMK] = COMBO_ACTION(Q_K_COMBO), 116 | [KB_KEYBOARD] = COMBO_ACTION(K_B_COMBO), 117 | [WA_WHAT] = COMBO_ACTION(W_A_COMBO), 118 | [OS_SFT_CAPS] = COMBO(OS_SFT_COMBO, CAPS_WORD_LOCK), 119 | [REPEATX_BSLS] = COMBO(REPEAT_X_COMBO, KC_BACKSLASH), 120 | [BSPCE_ESC] = COMBO(BSPC_E_COMBO, KC_ESC), 121 | [DOTSLASH_UPDIR] = COMBO_ACTION(DOT_SLASH_COMBO), 122 | [ZEROEIGHT_COMMA] = COMBO(ZERO_EIGHT_COMBO, KC_COMMA), 123 | [EIGHTNINE_DOT] = COMBO(EIGHT_NINE_COMBO, KC_DOT), 124 | [UYCLN_INDEX] = COMBO_ACTION(U_Y_SCLN_COMBO), 125 | [PT_MOUSE] = COMBO(P_T_COMBO, MOUSE), 126 | }; 127 | 128 | void process_combo_event(uint16_t combo_index, bool pressed) { 129 | // Process mod-taps before the combo is fired, 130 | // this helps making modifier-aware combos, 131 | // like UYCLN_INDEX more fluid 132 | // when I use them with home row mods. 133 | action_tapping_process((keyrecord_t){}); 134 | const uint8_t mod_state = get_mods(); 135 | const uint8_t oneshot_mod_state = get_oneshot_mods(); 136 | #ifdef CONSOLE_ENABLE 137 | combo_t *combo = &key_combos[combo_index]; 138 | uint8_t idx = 0; 139 | uint16_t combo_keycode; 140 | while ((combo_keycode = pgm_read_word(&combo->keys[idx])) != COMBO_END) { 141 | uprintf("0x%04X\t%u\t%u\t0x%X\t%u\t0x%02X\t0x%02X\t0\n", 142 | combo_keycode, 143 | 254, 144 | 254, 145 | layer_state|default_layer_state, 146 | pressed, 147 | get_mods(), 148 | get_oneshot_mods() 149 | /* tap_count==0 */ 150 | ); 151 | idx++; 152 | } 153 | #endif 154 | switch(combo_index) { 155 | 156 | case UYCLN_INDEX: 157 | if (pressed) { 158 | if (mod_state & MOD_MASK_SHIFT) { 159 | del_mods(MOD_MASK_SHIFT); 160 | SEND_STRING("[1]"); 161 | set_mods(mod_state); 162 | } 163 | else if (mod_state & MOD_MASK_CTRL) { 164 | del_mods(MOD_MASK_CTRL); 165 | SEND_STRING("[0]"); 166 | set_mods(mod_state); 167 | } 168 | else { 169 | SEND_STRING("[i]"); 170 | } 171 | } 172 | break; 173 | 174 | case HV_HAVE: 175 | if (pressed) { 176 | SEND_STRING("have"); 177 | } 178 | break; 179 | 180 | case QK_QMK: 181 | if (pressed) { 182 | if (mod_state & MOD_MASK_SHIFT || oneshot_mod_state & MOD_MASK_SHIFT) { 183 | del_mods(MOD_MASK_SHIFT); 184 | del_oneshot_mods(MOD_MASK_SHIFT); 185 | SEND_STRING("QMK"); 186 | set_mods(mod_state); 187 | } 188 | else { 189 | SEND_STRING("qmk"); 190 | } 191 | } 192 | break; 193 | 194 | case BSPCEV_EVERY: 195 | if (pressed) { 196 | SEND_STRING("every"); 197 | } 198 | break; 199 | 200 | case BSPCU_YOU: 201 | if (pressed) { 202 | SEND_STRING("you"); 203 | } 204 | break; 205 | 206 | case BSPCA_AND: 207 | if (pressed) { 208 | SEND_STRING("and"); 209 | } 210 | break; 211 | 212 | case BSPCW_WITH: 213 | if (pressed) { 214 | SEND_STRING("with"); 215 | } 216 | break; 217 | 218 | case BSPCF_FOR: 219 | if (pressed) { 220 | SEND_STRING("for"); 221 | } 222 | break; 223 | 224 | case BSPCH_HERE: 225 | if (pressed) { 226 | SEND_STRING("here"); 227 | } 228 | break; 229 | 230 | case BSPCT_THE: 231 | if (pressed) { 232 | SEND_STRING("the"); 233 | } 234 | break; 235 | 236 | case BSPCM_MENT: 237 | if (pressed) { 238 | SEND_STRING("ment"); 239 | } 240 | break; 241 | 242 | case BSPCG_ING: 243 | if (pressed) { 244 | SEND_STRING("ing"); 245 | } 246 | break; 247 | 248 | case BSPCO_OUGH: 249 | if (pressed) { 250 | SEND_STRING("ough"); 251 | } 252 | break; 253 | 254 | case BSPCOL_OULD: 255 | if (pressed) { 256 | SEND_STRING("ould"); 257 | } 258 | break; 259 | 260 | case BSPCI_ION: 261 | if (pressed) { 262 | SEND_STRING("ion"); 263 | } 264 | break; 265 | 266 | case BSPCIS_IONS: 267 | if (pressed) { 268 | SEND_STRING("ions"); 269 | } 270 | break; 271 | 272 | case BSPCTA_THAT: 273 | if (pressed) { 274 | SEND_STRING("that"); 275 | } 276 | break; 277 | 278 | case BSPCQ_QUE: 279 | if (pressed) { 280 | SEND_STRING("que"); 281 | } 282 | break; 283 | 284 | case BSPCK_KEY: 285 | if (pressed) { 286 | SEND_STRING("key"); 287 | } 288 | break; 289 | 290 | case KB_KEYBOARD: 291 | if (pressed) { 292 | SEND_STRING("keyboard"); 293 | } 294 | break; 295 | 296 | case WA_WHAT: 297 | if (pressed) { 298 | SEND_STRING("what"); 299 | } 300 | break; 301 | 302 | case BSPCTS_THIS: 303 | if (pressed) { 304 | SEND_STRING("this"); 305 | } 306 | break; 307 | 308 | case BSPCDN_DONT: 309 | if (pressed) { 310 | SEND_STRING("don't"); 311 | } 312 | break; 313 | 314 | case BSPCIT_IN_THE: 315 | if (pressed) { 316 | SEND_STRING("in the"); 317 | } 318 | break; 319 | 320 | case DOTSLASH_UPDIR: 321 | if (pressed) { 322 | SEND_STRING("../"); 323 | } 324 | break; 325 | } 326 | }; 327 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Home row mods settings // 4 | 5 | // Default tapping term is 200 6 | #define TAPPING_TERM 170 7 | #define TAPPING_TERM_PER_KEY // See bottom of keymap.c 8 | 9 | // This prevents accidental repeats of the tap-hold keys when typing quickly. 10 | #define QUICK_TAP_TERM_PER_KEY 11 | 12 | // Disable PERMISSIVE_HOLD 13 | // (It's enabled dy default for all Dactyl Manuform boards, 14 | // so it requires explicit undef to disable) 15 | #undef PERMISSIVE_HOLD 16 | 17 | // Other settings // 18 | #define HOLD_ON_OTHER_KEY_PRESS_PER_KEY 19 | 20 | #define COMBO_TERM 70 21 | 22 | // Limits the max. amount of layers to 8 to save firmware memory. 23 | #define LAYER_STATE_8BIT 24 | 25 | // Save firmware space 26 | // Strip away all prints except `uprintf` 27 | #define USER_PRINT 28 | // Disable hardware lock switches support to free up space 29 | #undef LOCKING_SUPPORT_ENABLE 30 | #undef LOCKING_RESYNC_ENABLE 31 | 32 | // Shamelessly stolen mouse key settings from @pierrechevalier83 // 33 | 34 | // Set the mouse settings to a comfortable speed/accuracy trade-off 35 | // Assume the screen refresh rate is 60 Hz or higher 36 | // The default is 50. This makes the mouse ~3 times faster and more accurate 37 | // #undef to override default settings 38 | #undef MOUSEKEY_INTERVAL 39 | #define MOUSEKEY_INTERVAL 16 40 | // The default is 20. Since we made the mouse about 3 times faster with the previous setting, 41 | // give it more time to accelerate to max speed to retain precise control over short distances. 42 | #undef MOUSEKEY_TIME_TO_MAX 43 | #define MOUSEKEY_TIME_TO_MAX 40 44 | // The default is 300. Let's try and make this as low as possible while keeping the cursor responsive 45 | #undef MOUSEKEY_DELAY 46 | #define MOUSEKEY_DELAY 100 47 | -------------------------------------------------------------------------------- /keymap.c: -------------------------------------------------------------------------------- 1 | /* Colemak DHm with home row mods and hybrid steno 2 | * for the Dactyl Manuform 5x6 Keyboard */ 3 | 4 | #include QMK_KEYBOARD_H 5 | #ifdef CONSOLE_ENABLE 6 | #include "print.h" 7 | #endif 8 | #include "version.h" // For QK_VERS 9 | 10 | // All custom keycodes and aliases can be found in precondition_keymap.h 11 | #include "precondition_keymap.h" 12 | 13 | /*MAKE SURE THAT ADJUST AND QK_BOOT ARE ACCESSIBLE ON BOTH HALVES!*/ 14 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { 15 | 16 | /* ,-------------------------------. ,-------------------------------. 17 | * ,---------------| ` | BNAV | F4 | F5 | | ¨ | ^ | È | É |--------------. 18 | * | UNDO | REDO |-------+-------+-------+-------| |-------+-------+-------+-------| F10 | F11 | 19 | * |-------+-------| W | F | P | B | | J | L | U | Y |-------+------| 20 | * | À | Q |-------+-------+-------+-------| |-------+-------+-------+-------| : ; | - _ | 21 | * |-------+-------| R/⎇ | S/⇧ | T/⎈ | G | | M | N/⎈ | E/⇧ | I/⎇ |-------+------| 22 | * | ESC | A/◆ |-------+-------+-------+-------| |-------+-------+-------+-------| O/◆ | ' " | 23 | * |-------+-------| X | C | D | V | | K | H | , < | . > |-------+------| 24 | * | Z |REPEAT |-------+-------+---------------' `---------------+-------+-------| / ? |-> => | 25 | * `---------------|TG_MIC | Ç | | AltGr | ` |--------------' 26 | * `---------------' `---------------' 27 | * ,---------------. ,---------------. 28 | * |TAB/NAV| SPC | | BSPC | ⏎/SYM | 29 | * |-------+-------| |-------+-------| 30 | * |COMPOSE|1-SHOT⇧| |1-SHOT⇧| UP | 31 | * |-------+-------| |-------+-------| 32 | * |PLOVER |CAPS/MS| |SWAPHND| DOWN | 33 | * `---------------' `---------------' generated by [keymapviz] */ 34 | [_COLEMAK_DH] = LAYOUT_5x6( 35 | UNDO, REDO , KC_GRV, BNAV , KC_F4 , KC_F5 , DED_UML,DED_CIR,E_GRAVE,E_ACUTE, KC_F10, KC_F11, 36 | A_GRAVE, KC_Q , KC_W , KC_F , KC_P , KC_B , KC_J , KC_L , KC_U , KC_Y ,KC_SCLN,KC_MINS, 37 | KC_ESC, HOME_A, HOME_R, HOME_S, HOME_T, KC_G , KC_M , HOME_N, HOME_E, HOME_I, HOME_O,KC_QUOT, 38 | KC_Z, REPEAT, KC_X , KC_C , KC_D , KC_V , KC_K , KC_H ,KC_COMM, TD_DOT,KC_SLSH,ARROW_R, 39 | TG_MIC,C_CDILA, KC_RALT, KC_GRV, 40 | NAV_TAB, KC_SPC, KC_BSPC,SYM_ENT, 41 | COMPOSE,OS_LSFT, OS_RSFT, KC_UP , 42 | PLOVER ,MS_CAPS, SH_OS ,KC_DOWN 43 | ), 44 | 45 | /* ,-------------------------------. ,-------------------------------. 46 | * ,---------------| #2 | #3 | #4 | #5 | | #6 | #7 | #8 | #9 |--------------. 47 | * | | #1 |-------+-------+-------+-------| |-------+-------+-------+-------| NA | BSPC | 48 | * |-------+-------| Z | N | X | *1 | | *3 | e | n | z |-------+------| 49 | * | | F |-------+-------+-------+-------| |-------+-------+-------+-------| f | -D | 50 | * |-------+-------| C | P | R | *2 | | *4 | a | p | c |-------+------| 51 | * | | S |-------+-------+-------+-------| |-------+-------+-------+-------| s | -Z | 52 | * |-------+-------|1-SHOT⎇|1-SHOT⇧|1-SHOT⎈| | | |1-SHOT⎈|1-SHOT⇧|1-SHOT⎇|-------+------| 53 | * | |1-SHOT◆|-------+-------+---------------' `---------------+-------+-------|1-SHOT◆| | 54 | * `---------------| | | | | |--------------' 55 | * `---------------' `---------------' 56 | * ,---------------. ,---------------. 57 | * | I | U | | u | i | 58 | * |-------+-------| |-------+-------| 59 | * | |TAB/NAV| | ⏎/SYM | | 60 | * |-------+-------| |-------+-------| 61 | * |PLOVER | | | | | 62 | * `---------------' `---------------' generated by [keymapviz] */ 63 | [_PLOVER] = LAYOUT_5x6( 64 | _______, STN_N1, STN_N2, STN_N3, STN_N4, STN_N5, STN_N6, STN_N7, STN_N8, STN_N9, STN_NA, KC_BSPC, 65 | _______, STN_S1, STN_TL, STN_PL, STN_HL,STN_ST1, STN_ST3, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, 66 | _______, STN_S2, STN_KL, STN_WL, STN_RL,STN_ST2, STN_ST4, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, 67 | _______,OS_LGUI,OS_LALT,OS_LSFT,OS_LCTL,_______, _______,OS_RCTL, OS_RSFT, OS_LALT, OS_RGUI,_______, 68 | _______,_______, _______,_______, 69 | STN_A, STN_O, STN_E, STN_U, 70 | _______,NAV_TAB, SYM_ENT,_______, 71 | PLOVER ,_______, _______,_______ 72 | ), 73 | 74 | /* ,-------------------------------. ,-------------------------------. 75 | * ,---------------| F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 |--------------. 76 | * | F12 | F1 |-------+-------+-------+-------| |-------+-------+-------+-------| F10 | F11 | 77 | * |-------+-------| 2 | 3 | 1 | 5 | | 6 | 0 | 8 | 9 |-------+------| 78 | * | X | 4 |-------+-------+-------+-------| |-------+-------+-------+-------| 7 | - _ | 79 | * |-------+-------| [ | ] | "] | » | | {⏎ | { | ( | ) |-------+------| 80 | * | « | [" |-------+-------+-------+-------| |-------+-------+-------+-------| } | }⏎ | 81 | * |-------+-------| @ | # | $ | % | | ^ | & | * | = |-------+------| 82 | * | ~ | ! |-------+-------+---------------' `---------------+-------+-------| + | ` | 83 | * `---------------| | | | , < | . > |--------------' 84 | * `---------------' `---------------' 85 | * ,---------------. ,---------------. 86 | * | NAV | | | | | 87 | * |-------+-------| |-------+-------| 88 | * | | | | | | 89 | * |-------+-------| |-------+-------| 90 | * | | | |ADJUST |ADJUST | 91 | * `---------------' `---------------' generated by [keymapviz] */ 92 | [_SYM] = LAYOUT_5x6( 93 | KC_F12 , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_F6 , KC_F7 , KC_F8 , KC_F9 , KC_F10, KC_F11, 94 | KC_X, KC_4 , KC_2 , KC_3 , KC_1 , KC_5 , KC_6 , KC_0 , KC_8 , KC_9 , KC_7 ,KC_MINS, 95 | GUILL_L,O_BRQOT,KC_LBRC,KC_RBRC,C_BRQOT,GUILL_R, O_BRACE,KC_LCBR,KC_LPRN,KC_RPRN,KC_RCBR,C_BRACE, 96 | KC_TILD,KC_EXLM, KC_AT ,KC_HASH,KC_DLR ,KC_PERC, KC_CIRC,KC_AMPR,KC_ASTR,KC_EQL ,KC_PLUS, KC_GRV, 97 | _______,_______, KC_COMM, KC_DOT, 98 | NAV ,_______, _______,_______, 99 | _______,_______, _______,_______, 100 | _______,_______, ADJUST, ADJUST 101 | ), 102 | 103 | /* ,-------------------------------. ,-------------------------------. 104 | * ,---------------| F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 |--------------. 105 | * | F12 | F1 |-------+-------+-------+-------| |-------+-------+-------+-------| F10 | F11 | 106 | * |-------+-------|NumLock|ScrLock| Ins | BNAV | | | PGUP | UP | PGDN |-------+------| 107 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | MUTE | 108 | * |-------+-------|LALT ⎇ |LSFT ⇧ |LCTL ⎈ | GNAV | | HOME | LEFT | DOWN | RGHT |-------+------| 109 | * |CAPS/MS|LGUI ◆ |-------+-------+-------+-------| |-------+-------+-------+-------| END | VOLU | 110 | * |-------+-------|Ctrl+A |Ctrl+C |Ctrl+V | | | |PrintSc| { | } |-------+------| 111 | * | |COUTLN |-------+-------+---------------' `---------------+-------+-------| Ins | VOLD | 112 | * `---------------| | | | BRID | BRIU |--------------' 113 | * `---------------' `---------------' 114 | * ,---------------. ,---------------. 115 | * | | | | | | 116 | * |-------+-------| |-------+-------| 117 | * | | | | | | 118 | * |-------+-------| |-------+-------| 119 | * |ADJUST |ADJUST | | | | 120 | * `---------------' `---------------' generated by [keymapviz] */ 121 | [_NAV] = LAYOUT_5x6( 122 | KC_F12 , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_F6 , KC_F7 , KC_F8 , KC_F9 ,KC_F10 , KC_F11, 123 | _______,_______,KC_NUM,KC_SCRL,KC_INS , BNAV , _______,KC_PGUP, KC_UP ,KC_PGDN,_______,KC_MUTE, 124 | MS_CAPS,KC_LGUI,KC_LALT,KC_LSFT,KC_LCTL, GNAV , KC_HOME,KC_LEFT,KC_DOWN,KC_RGHT,KC_END ,KC_VOLU, 125 | _______, COUTLN,C(KC_A),C(KC_C),C(KC_V),_______, _______,KC_PSCR,KC_LCBR,KC_RCBR,KC_INS ,KC_VOLD, 126 | _______,_______, KC_BRID,KC_BRIU, 127 | _______,_______, _______,_______, 128 | _______,_______, _______,_______, 129 | ADJUST,ADJUST, _______,_______ 130 | ), 131 | 132 | /* ,-------------------------------. ,-------------------------------. 133 | * ,---------------| | | | | | | | | |--------------. 134 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 135 | * |-------+-------| | | | | | | | G_UP | |-------+------| 136 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 137 | * |-------+-------| | | | | |G_HOME | |G_DOWN | |-------+------| 138 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| G_END | | 139 | * |-------+-------| | | | | | | | | |-------+------| 140 | * | | |-------+-------+---------------' `---------------+-------+-------| | | 141 | * `---------------| | | | | |--------------' 142 | * `---------------' `---------------' 143 | * ,---------------. ,---------------. 144 | * | | | | | | 145 | * |-------+-------| |-------+-------| 146 | * | | | | | | 147 | * |-------+-------| |-------+-------| 148 | * | | | | | | 149 | * `---------------' `---------------' generated by [keymapviz] */ 150 | [_GNAV] = LAYOUT_5x6( 151 | _______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______, 152 | _______,_______,_______,_______,_______,_______, _______,_______, G_UP ,_______,_______,_______, 153 | _______,_______,_______,_______,_______,_______, G_HOME ,_______, G_DOWN,_______, G_END ,_______, 154 | _______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______, 155 | _______,_______, _______,_______, 156 | _______,_______, _______,_______, 157 | _______,_______, _______,_______, 158 | _______,_______, _______,_______ 159 | ), 160 | 161 | /* ,-------------------------------. ,-------------------------------. 162 | * ,---------------| | | | | | | | | |--------------. 163 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 164 | * |-------+-------| | | | | | |B_PREV | B_UP |B_NEXT |-------+------| 165 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 166 | * |-------+-------| | | | | | |B_LEFT |B_DOWN |B_RIGHT|-------+------| 167 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------|B_VERT | | 168 | * |-------+-------| | | | | |B_PASTE|B_CPY_M|B_CREAT|B_CLOSE|-------+------| 169 | * | | |-------+-------+---------------' `---------------+-------+-------|B_HORIZ|B_ZOOM| 170 | * `---------------| | | | | |--------------' 171 | * `---------------' `---------------' 172 | * ,---------------. ,---------------. 173 | * | | | | | | 174 | * |-------+-------| |-------+-------| 175 | * | | | | | | 176 | * |-------+-------| |-------+-------| 177 | * | | | | | | 178 | * `---------------' `---------------' generated by [keymapviz] */ 179 | [_BNAV] = LAYOUT_5x6( 180 | _______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______, 181 | _______,_______,_______,_______,_______,_______, _______, B_PREV, B_UP , B_NEXT,_______,_______, 182 | _______,_______,_______,_______,_______,_______, _______, B_LEFT, B_DOWN,B_RIGHT, B_VERT,_______, 183 | _______,_______,_______,_______,_______,_______, B_PASTE,B_CPY_M,B_CREAT,B_CLOSE,B_HORIZ, B_ZOOM, 184 | _______,_______, _______,_______, 185 | _______,_______, _______,_______, 186 | _______,_______, _______,_______, 187 | _______,_______, _______,_______ 188 | ), 189 | 190 | 191 | #ifdef MOUSEKEY_ENABLE 192 | /* ,-------------------------------. ,-------------------------------. 193 | * ,---------------| | | | | | | | | |--------------. 194 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 195 | * |-------+-------| | | | | | | ⯬ |MOUSE ↑| ⯮ |-------+------| 196 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 197 | * |-------+-------|LALT ⎇ |LSFT ⇧ |LCTL ⎈ | | | |MOUSE ←|MOUSE ↓|MOUSE →|-------+------| 198 | * | |LGUI ◆ |-------+-------+-------+-------| |-------+-------+-------+-------| | | 199 | * |-------+-------| | | | | | | BTN3 |WHEEL ↓|WHEEL ↑|-------+------| 200 | * | | |-------+-------+---------------' `---------------+-------+-------| | | 201 | * `---------------| | | | | |--------------' 202 | * `---------------' `---------------' 203 | * ,---------------. ,---------------. 204 | * | | | | BTN1 | BTN2 | 205 | * |-------+-------| |-------+-------| 206 | * | | | | BTN3 | | 207 | * |-------+-------| |-------+-------| 208 | * | | | | | | 209 | * `---------------' `---------------' generated by [keymapviz] */ 210 | [_MOUSE] = LAYOUT_5x6( 211 | _______,_______,_______,_______,_______,_______, _______,_______,_______,_______,_______,_______, 212 | _______,_______,_______,_______,_______,_______, _______,KC_WBAK,KC_MS_U,KC_WFWD,_______,_______, 213 | _______,KC_LGUI,KC_LALT,KC_LSFT,KC_LCTL,_______, _______,KC_MS_L,KC_MS_D,KC_MS_R,_______,_______, 214 | _______,_______,_______,_______,_______,_______, _______,KC_BTN3,KC_WH_D,KC_WH_U,_______,_______, 215 | _______,_______, _______,_______, 216 | _______,_______, KC_BTN1,KC_BTN2, 217 | _______,_______, KC_BTN3,_______, 218 | _______,_______, _______,_______ 219 | ), 220 | #endif 221 | 222 | /* ,-------------------------------. ,-------------------------------. 223 | * ,---------------| | | | | | | | INT8 | LNG9 |--------------. 224 | * | UNDO | AGAIN |-------+-------+-------+-------| |-------+-------+-------+-------| PB_10 | | 225 | * |-------+-------| | FIND | |EE_CLR | | |NKROon | | |-------+------| 226 | * | | |-------+-------+-------+-------| |-------+-------+-------+-------| | | 227 | * |-------+-------| ⏹ | ⏯ | ⏭ |QK_RBT | |QK_VERS| | (/⇧ | )/⇧ |-------+------| 228 | * |` ~/Esc| ⏮ |-------+-------+-------+-------| |-------+-------+-------+-------| |\NUHS|| 229 | * |-------+-------| CUT | COPY | PASTE |QK_BOOT| |QK_BOOT|NKROoff| | |-------+------| 230 | * |\NUBS| | |-------+-------+---------------' `---------------+-------+-------| KP / | | 231 | * `---------------| | | | | |--------------' 232 | * `---------------' `---------------' 233 | * ,---------------. ,---------------. 234 | * | | | | | | 235 | * |-------+-------| |-------+-------| 236 | * | | | | | | 237 | * |-------+-------| |-------+-------| 238 | * | | | | | | 239 | * `---------------' `---------------' generated by [keymapviz] */ 240 | [_ADJUST] = LAYOUT_5x6( 241 | KC_UNDO,KC_AGIN,_______,_______,_______,_______, _______,_______,KC_INT8,KC_LNG9, PB_10 ,_______, 242 | _______,_______,_______,KC_FIND,_______, EE_CLR, _______, NK_ON ,_______,_______,_______,_______, 243 | QK_GESC,KC_MPRV,KC_MSTP,KC_MPLY,KC_MNXT, QK_RBT, QK_VERS,_______,SC_LSPO,SC_RSPC,_______,KC_NUHS, 244 | KC_NUBS,_______, KC_CUT,KC_COPY,KC_PSTE,QK_BOOT, QK_BOOT, NK_OFF,_______,_______,KC_PSLS,_______, 245 | _______,_______, _______,_______, 246 | _______,_______, _______,_______, 247 | _______,_______, _______,_______, 248 | _______,_______, _______,_______ 249 | ) 250 | }; 251 | 252 | // CAPS_WORD_LOCK: A "smart" Caps Lock key that only capitalizes the next identifier you type 253 | // and then toggles off Caps Lock automatically when you're done. 254 | void caps_word_lock_enable(void) { 255 | caps_word_lock_on = true; 256 | if (!(host_keyboard_led_state().caps_lock)) { 257 | tap_code(KC_CAPS); 258 | } 259 | } 260 | 261 | void caps_word_lock_disable(void) { 262 | caps_word_lock_on = false; 263 | unregister_mods(MOD_MASK_SHIFT); 264 | if (host_keyboard_led_state().caps_lock) { 265 | tap_code(KC_CAPS); 266 | } 267 | } 268 | 269 | inline uint8_t get_tap_kc(uint16_t dual_role_key) { 270 | // Used to extract the basic tapping keycode from a dual-role key. 271 | // Example: get_tap_kc(MT(MOD_RSFT, KC_E)) == KC_E 272 | return dual_role_key & 0xFF; 273 | } 274 | 275 | static void process_caps_word_lock(uint16_t keycode, const keyrecord_t *record) { 276 | // Update caps word state 277 | if (caps_word_lock_on) { 278 | switch (keycode) { 279 | case QK_MOD_TAP ... QK_MOD_TAP_MAX: 280 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: 281 | case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: 282 | // Earlier return if this has not been considered tapped yet 283 | if (record->tap.count == 0) { return; } 284 | // Get the base tapping keycode of a mod- or layer-tap key 285 | keycode = get_tap_kc(keycode); 286 | break; 287 | default: 288 | break; 289 | } 290 | 291 | switch (keycode) { 292 | // Keycodes to shift 293 | case KC_A ... KC_Z: 294 | case A_GRAVE: 295 | case E_ACUTE: 296 | case E_GRAVE: 297 | case C_CDILA: 298 | if (record->event.pressed) { 299 | if (get_oneshot_mods() & MOD_MASK_SHIFT) { 300 | caps_word_lock_disable(); 301 | add_oneshot_mods(MOD_MASK_SHIFT); 302 | } 303 | } 304 | // Keycodes that enable caps word but shouldn't get shifted 305 | case CAPS_WORD_LOCK: 306 | case DED_CIR: 307 | case DED_UML: 308 | case KC_BSPC: 309 | case KC_LPRN: 310 | case KC_MINS: 311 | case KC_PIPE: 312 | case KC_RPRN: 313 | case KC_UNDS: 314 | case OS_LSFT: 315 | case OS_RSFT: 316 | case REPEAT: 317 | // If chording mods, disable caps word 318 | if (record->event.pressed && (get_mods() != MOD_LSFT) && (get_mods() != 0)) { 319 | caps_word_lock_disable(); 320 | } 321 | break; 322 | default: 323 | // Any other keycode should automatically disable caps 324 | if (record->event.pressed && !(get_oneshot_mods() & MOD_MASK_SHIFT)) { 325 | caps_word_lock_disable(); 326 | } 327 | break; 328 | } 329 | } 330 | } 331 | 332 | uint16_t last_keycode = KC_NO; 333 | static void process_repeat_key(uint16_t keycode, const keyrecord_t *record) { 334 | static uint8_t last_modifier = 0; 335 | if (keycode != REPEAT) { 336 | // Early return when holding down a pure layer key 337 | // to retain modifiers 338 | switch (keycode) { 339 | case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: 340 | case QK_MOMENTARY ... QK_MOMENTARY_MAX: 341 | case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: 342 | case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: 343 | case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: 344 | case QK_TO ... QK_TO_MAX: 345 | case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: 346 | return; 347 | } 348 | if (record->event.pressed) { 349 | last_modifier = get_oneshot_mods() | get_mods(); 350 | } 351 | switch (keycode) { 352 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: 353 | case QK_MOD_TAP ... QK_MOD_TAP_MAX: 354 | if (record->event.pressed) { 355 | last_keycode = get_tap_kc(keycode); 356 | } 357 | break; 358 | default: 359 | if (record->event.pressed) { 360 | last_keycode = keycode; 361 | } 362 | break; 363 | } 364 | } else { // keycode == REPEAT 365 | if (record->event.pressed) { 366 | register_mods(last_modifier); 367 | register_code16(last_keycode); 368 | } else { 369 | unregister_code16(last_keycode); 370 | unregister_mods(last_modifier); 371 | } 372 | } 373 | } 374 | 375 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { 376 | #ifdef CONSOLE_ENABLE 377 | const bool is_combo = record->event.type == COMBO_EVENT; 378 | uprintf("0x%04X\t%u\t%u\t0x%X\t%u\t0x%02X\t0x%02X\t%u\n", 379 | keycode, 380 | is_combo ? 254 : record->event.key.row, 381 | is_combo ? 254 : record->event.key.col, 382 | layer_state|default_layer_state, 383 | record->event.pressed, 384 | get_mods(), 385 | get_oneshot_mods(), 386 | record->tap.count 387 | ); 388 | #endif 389 | process_caps_word_lock(keycode, record); 390 | process_repeat_key(keycode, record); 391 | 392 | const uint8_t mod_state = get_mods(); 393 | const uint8_t oneshot_mod_state = get_oneshot_mods(); 394 | switch (keycode) { 395 | 396 | 397 | case CAPS_WORD_LOCK: 398 | // Toggle `caps_word_lock_on` 399 | if (record->event.pressed) { 400 | if (caps_word_lock_on) { 401 | caps_word_lock_disable(); 402 | return false; 403 | } else { 404 | caps_word_lock_enable(); 405 | return false; 406 | } 407 | } 408 | return false; 409 | 410 | 411 | case KC_SPC: 412 | if (oneshot_mod_state & MOD_MASK_SHIFT) { 413 | if (record->event.pressed) { 414 | tap_code(KC_MINS); // The one-shot shift will convert it to an underscore 415 | } 416 | return false; 417 | } 418 | return true; 419 | 420 | case KC_BSPC: 421 | { 422 | static bool delkey_registered; 423 | if (record->event.pressed) { 424 | if (mod_state & MOD_MASK_SHIFT) { 425 | // In case only one shift is held 426 | // see https://stackoverflow.com/questions/1596668/logical-xor-operator-in-c 427 | // This also means that in case of holding both shifts and pressing KC_BSPC, 428 | // Shift+Delete is sent (useful in Firefox) since the shift modifiers aren't deleted. 429 | if (!(mod_state & MOD_BIT(KC_LEFT_SHIFT)) != !(mod_state & MOD_BIT(KC_RIGHT_SHIFT))) { 430 | del_mods(MOD_MASK_SHIFT); 431 | } 432 | register_code(KC_DEL); 433 | delkey_registered = true; 434 | set_mods(mod_state); 435 | return false; 436 | } 437 | } else { 438 | if (delkey_registered) { 439 | unregister_code(KC_DEL); 440 | delkey_registered = false; 441 | return false; 442 | } 443 | } 444 | return true; 445 | } 446 | 447 | case A_GRAVE: 448 | if (record->event.pressed) { 449 | del_mods(MOD_MASK_SHIFT); 450 | del_oneshot_mods(MOD_MASK_SHIFT); 451 | tap_code16(ALGR(KC_GRV)); 452 | set_mods(mod_state); 453 | set_oneshot_mods(oneshot_mod_state); 454 | tap_code(KC_A); 455 | } 456 | return false; 457 | 458 | case E_GRAVE: 459 | if (record->event.pressed) { 460 | del_mods(MOD_MASK_SHIFT); 461 | del_oneshot_mods(MOD_MASK_SHIFT); 462 | tap_code16(ALGR(KC_GRV)); 463 | set_mods(mod_state); 464 | set_oneshot_mods(oneshot_mod_state); 465 | tap_code(KC_E); 466 | } 467 | return false; 468 | 469 | case ARROW_R: 470 | if (record->event.pressed) { 471 | if ((mod_state|oneshot_mod_state) & MOD_MASK_SHIFT) { 472 | del_mods(MOD_MASK_SHIFT); 473 | del_oneshot_mods(MOD_MASK_SHIFT); 474 | SEND_STRING("=>"); 475 | set_mods(mod_state); 476 | } else { 477 | SEND_STRING("->"); 478 | } 479 | } 480 | return false; 481 | 482 | case G_DOWN: 483 | if (record->event.pressed) { 484 | register_code(KC_G); 485 | register_code(KC_DOWN); 486 | } else { 487 | unregister_code(KC_G); 488 | unregister_code(KC_DOWN); 489 | } 490 | return false; 491 | 492 | case G_UP: 493 | if (record->event.pressed) { 494 | register_code(KC_G); 495 | register_code(KC_UP); 496 | } else { 497 | unregister_code(KC_G); 498 | unregister_code(KC_UP); 499 | } 500 | return false; 501 | 502 | case G_HOME: 503 | if (record->event.pressed) { 504 | register_code(KC_G); 505 | register_code(KC_HOME); 506 | } else { 507 | unregister_code(KC_G); 508 | unregister_code(KC_HOME); 509 | } 510 | return false; 511 | 512 | case G_END: 513 | if (record->event.pressed) { 514 | register_code(KC_G); 515 | register_code(KC_END); 516 | } else { 517 | unregister_code(KC_G); 518 | unregister_code(KC_END); 519 | } 520 | return false; 521 | 522 | case GUILL_L: 523 | if (record->event.pressed) { 524 | tap_code(COMPOSE); 525 | tap_code16(KC_LT); 526 | tap_code16(KC_LT); 527 | tap_code(COMPOSE); 528 | tap_code(KC_SPACE); 529 | tap_code(KC_SPACE); 530 | } 531 | return false; 532 | 533 | case GUILL_R: 534 | if (record->event.pressed) { 535 | tap_code(COMPOSE); 536 | tap_code(KC_SPACE); 537 | tap_code(KC_SPACE); 538 | tap_code(COMPOSE); 539 | tap_code16(KC_GT); 540 | tap_code16(KC_GT); 541 | } 542 | return false; 543 | 544 | case UPDIR: 545 | if (record->event.pressed) { 546 | tap_code(KC_DOT); 547 | tap_code(KC_DOT); 548 | tap_code(KC_SLSH); 549 | } 550 | return false; 551 | 552 | case COUTLN: 553 | if (record->event.pressed) { 554 | // ; and : keysyms are swapped on my OS layout 555 | SEND_STRING_DELAY("std;;cout << << \"\\n\":", 10); 556 | for (int i = 0; i < 9; ++i) { 557 | tap_code(KC_LEFT); 558 | } 559 | } 560 | return false; 561 | 562 | case O_BRACE: 563 | if (record->event.pressed) { 564 | tap_code16(KC_LEFT_CURLY_BRACE); 565 | tap_code(KC_ENTER); 566 | } 567 | return false; 568 | 569 | case C_BRACE: 570 | if (record->event.pressed) { 571 | tap_code16(KC_RIGHT_CURLY_BRACE); 572 | tap_code(KC_ENTER); 573 | } 574 | return false; 575 | 576 | case O_BRQOT: 577 | if (record->event.pressed) { 578 | tap_code(KC_LEFT_BRACKET); 579 | tap_code16(KC_DOUBLE_QUOTE); 580 | } 581 | return false; 582 | 583 | case C_BRQOT: 584 | if (record->event.pressed) { 585 | tap_code16(KC_DOUBLE_QUOTE); 586 | tap_code(KC_RIGHT_BRACKET); 587 | } 588 | return false; 589 | 590 | case QK_VERS: 591 | if (record->event.pressed) { 592 | SEND_STRING( 593 | QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION "(" QMK_GIT_HASH ")" \ 594 | ", Built on; " QMK_BUILDDATE 595 | ); 596 | } 597 | return false; 598 | 599 | // tmux window navigation 600 | case B_CREAT: 601 | if (record->event.pressed) { 602 | tap_code16(TMUX_PREFIX_KEY); 603 | tap_code(KC_C); 604 | } 605 | return false; 606 | 607 | case B_PREV: 608 | if (record->event.pressed) { 609 | tap_code16(TMUX_PREFIX_KEY); 610 | tap_code(KC_P); 611 | } 612 | return false; 613 | 614 | case B_NEXT: 615 | if (record->event.pressed) { 616 | tap_code16(TMUX_PREFIX_KEY); 617 | tap_code(KC_N); 618 | } 619 | return false; 620 | 621 | // tmux pane navigation 622 | case B_VERT: 623 | if (record->event.pressed) { 624 | tap_code16(TMUX_PREFIX_KEY); 625 | tap_code16(KC_PERCENT); 626 | } 627 | return false; 628 | 629 | case B_HORIZ: 630 | if (record->event.pressed) { 631 | tap_code16(TMUX_PREFIX_KEY); 632 | tap_code16(KC_DOUBLE_QUOTE); 633 | } 634 | return false; 635 | 636 | case B_UP: 637 | if (record->event.pressed) { 638 | tap_code16(TMUX_PREFIX_KEY); 639 | tap_code(KC_UP); 640 | } 641 | return false; 642 | 643 | case B_LEFT: 644 | if (record->event.pressed) { 645 | tap_code16(TMUX_PREFIX_KEY); 646 | tap_code(KC_LEFT); 647 | } 648 | return false; 649 | 650 | case B_DOWN: 651 | if (record->event.pressed) { 652 | tap_code16(TMUX_PREFIX_KEY); 653 | tap_code(KC_DOWN); 654 | } 655 | return false; 656 | 657 | case B_RIGHT: 658 | if (record->event.pressed) { 659 | tap_code16(TMUX_PREFIX_KEY); 660 | tap_code(KC_RIGHT); 661 | } 662 | return false; 663 | 664 | // tmux copy mode and paste buffer 665 | case B_PASTE: 666 | if (record->event.pressed) { 667 | tap_code16(TMUX_PREFIX_KEY); 668 | tap_code(KC_RIGHT_BRACKET); 669 | } 670 | return false; 671 | 672 | case B_CPY_M: 673 | if (record->event.pressed) { 674 | tap_code16(TMUX_PREFIX_KEY); 675 | tap_code(KC_LEFT_BRACKET); 676 | } 677 | return false; 678 | 679 | // tmux zoom 680 | case B_ZOOM: 681 | if (record->event.pressed) { 682 | tap_code16(TMUX_PREFIX_KEY); 683 | tap_code(KC_Z); 684 | } 685 | return false; 686 | 687 | // tmux clone pane 688 | case B_CLOSE: 689 | if (record->event.pressed) { 690 | tap_code16(TMUX_PREFIX_KEY); 691 | tap_code(KC_X); 692 | } 693 | return false; 694 | 695 | } 696 | return true; 697 | }; 698 | 699 | #ifdef QUICK_TAP_TERM_PER_KEY 700 | uint16_t get_quick_tap_term(uint16_t keycode, keyrecord_t *record) { 701 | switch (keycode) { 702 | case NAV_TAB: 703 | case HOME_R: // I like to hold Ctrl+R to redo many changes in Vim 704 | return 64; 705 | default: 706 | return 64; 707 | } 708 | } 709 | #endif 710 | 711 | #ifdef HOLD_ON_OTHER_KEY_PRESS_PER_KEY 712 | bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) { 713 | switch (keycode) { 714 | case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: 715 | // Immediately select the hold action when another key is pressed. 716 | return true; 717 | default: 718 | // Do not select the hold action when another key is pressed. 719 | return false; 720 | } 721 | } 722 | #endif 723 | 724 | #ifdef TAPPING_TERM_PER_KEY 725 | uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { 726 | switch (keycode) { 727 | case HOME_O: 728 | return TAPPING_TERM + 30; 729 | case SYM_ENT: 730 | // Very low tapping term to make sure I don't hit Enter accidentally. 731 | return TAPPING_TERM - 85; 732 | default: 733 | return TAPPING_TERM; 734 | } 735 | }; 736 | #endif 737 | 738 | #ifdef TAP_DANCE_ENABLE 739 | // Due to keymap introspection, the old `SRC += tapdance.c` technique in rules.mk no longer works 740 | #include "tapdance.c" 741 | #endif 742 | -------------------------------------------------------------------------------- /precondition_keymap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include QMK_KEYBOARD_H 4 | 5 | uint16_t last_keycode; 6 | bool caps_word_lock_on; 7 | 8 | enum layer_names { 9 | _COLEMAK_DH, 10 | _PLOVER, 11 | _SYM, 12 | _NAV, 13 | _GNAV, 14 | _BNAV, 15 | #ifdef MOUSEKEY_ENABLE 16 | _MOUSE, 17 | #endif 18 | _ADJUST, 19 | }; 20 | 21 | // Layer keys 22 | #define NAV_TAB LT(_NAV, KC_TAB) 23 | #define NAV MO(_NAV) 24 | #define GNAV MO(_GNAV) 25 | #define BNAV OSL(_BNAV) 26 | #define SYM MO(_SYM) 27 | #define ADJUST MO(_ADJUST) 28 | #define SYM_ENT LT(_SYM, KC_ENT) 29 | #define PLOVER TG(_PLOVER) 30 | 31 | #ifdef MOUSEKEY_ENABLE 32 | # define MOUSE MO(_MOUSE) 33 | # define MS_CAPS LT(_MOUSE, KC_CAPS) 34 | #else 35 | # define MOUSE KC_TRNS 36 | # define MS_CAPS KC_CAPS 37 | #endif 38 | 39 | 40 | // Miscellaneous keyboard shortcuts in direct access 41 | #define UNDO LCTL(KC_Z) 42 | #define REDO LCTL(KC_Y) 43 | #define COMPOSE KC_APP 44 | #define TG_MIC KC_F20 // Default binding for XF86AudioMicMute 45 | 46 | // Left-hand home row mods 47 | #define HOME_A LGUI_T(KC_A) 48 | #define HOME_R LALT_T(KC_R) 49 | #define HOME_S LSFT_T(KC_S) 50 | #define HOME_T LCTL_T(KC_T) 51 | 52 | // Right-hand home row mods 53 | #define HOME_O RGUI_T(KC_O) 54 | #define HOME_I LALT_T(KC_I) 55 | #define HOME_E RSFT_T(KC_E) 56 | #define HOME_N RCTL_T(KC_N) 57 | 58 | // One Shot Modifiers 59 | #define OS_LSFT OSM(MOD_LSFT) 60 | #define OS_RSFT OSM(MOD_RSFT) 61 | #define OS_LCTL OSM(MOD_LCTL) 62 | #define OS_RCTL OSM(MOD_RCTL) 63 | #define OS_LALT OSM(MOD_LALT) 64 | #define OS_RALT OSM(MOD_RALT) 65 | #define OS_LGUI OSM(MOD_LGUI) 66 | #define OS_RGUI OSM(MOD_RGUI) 67 | 68 | // French accents 69 | // The other common grave accented letters are custom keycodes 70 | // And the rest of other accented letters are accessed using dead keys 71 | #define E_ACUTE ALGR(KC_E) 72 | #define C_CDILA ALGR(KC_COMMA) 73 | // Useful dead keys for French 74 | #define DED_CIR ALGR(KC_6) 75 | #define DED_UML S(ALGR(KC_QUOT)) 76 | 77 | #define TMUX_PREFIX_KEY C(KC_B) 78 | 79 | enum custom_keycodes { 80 | ARROW_R = SAFE_RANGE, 81 | // g navigation to move through screen lines in Vim 82 | G_DOWN, 83 | G_UP, 84 | G_HOME, 85 | G_END, 86 | // « French quotation marks » 87 | GUILL_R, 88 | GUILL_L, 89 | // Macro to refer to the parent directory in Linux ../ 90 | UPDIR, 91 | // French grave accented letters 92 | E_GRAVE, 93 | A_GRAVE, 94 | // Macro for 95 | // std::cout << | << "\n"; 96 | // (with | representing the cursor position) 97 | COUTLN, 98 | REPEAT, 99 | // "Opening brace" 100 | // Macro for 101 | // { 102 | O_BRACE, 103 | // "Closing brace" 104 | // Macro for 105 | // } 106 | C_BRACE, 107 | CAPS_WORD_LOCK, 108 | // "Opening Bracket-Quote" 109 | // Macro for 110 | // [" 111 | O_BRQOT, 112 | // "Closing Bracket-Quote" 113 | // Macro for 114 | // "] 115 | C_BRQOT, 116 | // "QMK Version" 117 | // Prints the keyboard name, QMK version and build date 118 | QK_VERS, 119 | // tmux window navigation 120 | B_CREAT, 121 | B_PREV, 122 | B_NEXT, 123 | // tmux pane navigation 124 | B_VERT, 125 | B_HORIZ, 126 | B_UP, 127 | B_LEFT, 128 | B_DOWN, 129 | B_RIGHT, 130 | // tmux copy mode and paste buffer 131 | B_PASTE, 132 | B_CPY_M, 133 | // tmux zoom 134 | B_ZOOM, 135 | // tmux close pane 136 | B_CLOSE, 137 | }; 138 | 139 | #ifdef TAP_DANCE_ENABLE 140 | enum { 141 | DOT_TD, 142 | }; 143 | 144 | #define TD_DOT TD(DOT_TD) 145 | #else 146 | #define TD_DOT KC_DOT 147 | #endif 148 | 149 | 150 | // The lowest row of thumb keys is wired a little differently from the layout macro on my specific build 151 | #undef LAYOUT_5x6 152 | #define LAYOUT_5x6(\ 153 | L00, L01, L02, L03, L04, L05, R00, R01, R02, R03, R04, R05, \ 154 | L10, L11, L12, L13, L14, L15, R10, R11, R12, R13, R14, R15, \ 155 | L20, L21, L22, L23, L24, L25, R20, R21, R22, R23, R24, R25, \ 156 | L30, L31, L32, L33, L34, L35, R30, R31, R32, R33, R34, R35, \ 157 | L42, L43, R42, R43, \ 158 | L44, L45, R40, R41, \ 159 | L54, L55, R50, R51, \ 160 | L53, L52, R53, R52 \ 161 | ) \ 162 | { \ 163 | { L00, L01, L02, L03, L04, L05 }, \ 164 | { L10, L11, L12, L13, L14, L15 }, \ 165 | { L20, L21, L22, L23, L24, L25 }, \ 166 | { L30, L31, L32, L33, L34, L35 }, \ 167 | { KC_NO, KC_NO, L42, L43, L44, L45 }, \ 168 | { KC_NO, KC_NO, L52, L53, L54, L55 }, \ 169 | \ 170 | { R00, R01, R02, R03, R04, R05 }, \ 171 | { R10, R11, R12, R13, R14, R15 }, \ 172 | { R20, R21, R22, R23, R24, R25 }, \ 173 | { R30, R31, R32, R33, R34, R35 }, \ 174 | { R40, R41, R42, R43, KC_NO, KC_NO }, \ 175 | { R50, R51, R52, R53, KC_NO, KC_NO } \ 176 | } 177 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Precondition's keymap for the Dactyl Manuform 5x6 2 | To be inserted in ~/qmk_firmware/keyboards/handwired/dactyl_manuform/5x6/keymaps/precondition 3 | 4 | ![Heatmap of key presses coming from all layers](visualisation/heatmap/all_layers.png) 5 | Figure 1. Heatmap of key presses coming from all layers. Unlike the ASCII art inside keymap.c, this figure is not automatically generated and may thus go out of date. 6 | 7 | This keymap uses Colemak-DH for its alpha base with the addition of common French accented keys in direct access and dead keys for the less common ones. For use in English, French, and programming. 8 | 9 | Notably, [home row mods](https://precondition.github.io/home-row-mods) are used, as well as tap dance and combos. 10 | 11 | Aside from the usual combos that expand to a single special character or command like \\ or Caps Word Lock, you can find, what I've dubbed, “steno-lite” combos in `combos.c`. Taking inspiration from machine stenography, common n-grams, word parts and words that are too short to abbreviate (in a text expansion program such as AutoKey) are assigned a key chord/combo, most frequently involving the Backspace key. Using Backspace+Letter(s) has the benefit of greatly reducing potential combo misfires as you're unlikely to type a letter and simultaneously delete it. 12 | 13 | Keymap visualisation diagrams are automatically generated with the help of [keymapviz] every time I compile. 14 | 15 | [keymapviz]: https://github.com/yskoht/keymapviz 16 | 17 | ### Keymap Tricks 18 | This keymap contains many nifty QMK tricks that can inspire you for your own keymap. Here's a non-exhaustive list. 19 | 20 | 1. Home row mods: All the modifiers on the home row. 21 | 2. `TD_DOT`: Double tap the dot key to produce .spaceOne-Shot Shift to quickly flow from one sentence to another. 22 | 3. One-Shot Swap Hand: For one-handed typing. 23 | 4. `CAPS_WORD_LOCK`: Capitalizes the next word you type and then automatically toggle off Caps Lock. Perfect for typing all-caps IDENTIFIERS in code. This is a hand-rolled version of [Caps Word](https://docs.qmk.fm/#/feature_caps_word) that works on the basis of Caps Lock, unlike the core QMK feature which is based on weak Shifts. That makes it easier to keep track of its state and better handles corner cases with less firmware size. 24 | 5. `REPEAT`: Repeat the last (modified) keystroke. This is used to eliminate the same-finger use that stems from double-tapping the same key. Ideally, this should be a thumb key but I couldn't fit it in my cluster in a satisfying manner. 25 | 6. `QK_VERS`: Types out firmware build information in the format `QMK_KEYBOARD/QMK_KEYMAP @ QMK_VERSION( QMK_GIT_HASH), Built on: QMK_BUILDDATE` (e.g. `handwired/dactyl_manuform/5x6/precondition @ 0.22.7-dirty(4ebb065f94*), Built on: 2024-10-03-22:50:02`) 26 | 27 | ### OS Setup 28 | 29 | * OS: Xubuntu Linux 30 | * Regional keyboard layout: Modified English US intl. with AltGr dead keys 31 | * Swapped the shift pairs of the semicolon key 32 | -------------------------------------------------------------------------------- /rules.mk: -------------------------------------------------------------------------------- 1 | # Automatically update the keymap visualization when compiling 2 | # The '-' in front of keymapviz is used to ignore errors spewed by keymapviz. 3 | KEYMAP_FOLDER = keyboards/handwired/dactyl_manuform/5x6/keymaps/precondition 4 | .PHONY: % 5 | %: 6 | -keymapviz -k dactyl_manuform5x6 -t ascii -r $(KEYMAP_FOLDER)/keymap.c -c $(KEYMAP_FOLDER)/visualisation/keymapviz/keymapviz.ini > /dev/null 7 | 8 | CONSOLE_ENABLE = no # USER_PRINT is currently bugged, see issue #24987 on qmk/qmk_firmware 9 | MOUSEKEY_ENABLE = yes 10 | TAP_DANCE_ENABLE = yes 11 | COMBO_ENABLE = yes 12 | NKRO_ENABLE = no 13 | STENO_ENABLE = yes 14 | STENO_PROTOCOL = geminipr 15 | SWAP_HANDS_ENABLE = yes 16 | 17 | # Space savings 18 | LTO_ENABLE = yes 19 | COMMAND_ENABLE = no 20 | KEY_LOCK_ENABLE = no 21 | SPACE_CADET_ENABLE = no 22 | GRAVE_ESC_ENABLE = no 23 | MAGIC_ENABLE = no 24 | 25 | # Load the necessary external C files if and only if 26 | # the associated config option has been enabled 27 | ifeq ($(strip $(COMBO_ENABLE)), yes) 28 | INTROSPECTION_KEYMAP_C += combos.c 29 | endif 30 | ifeq ($(strip $(SWAP_HANDS_ENABLE)), yes) 31 | SRC += swap_hand.c 32 | endif 33 | -------------------------------------------------------------------------------- /swap_hand.c: -------------------------------------------------------------------------------- 1 | #include QMK_KEYBOARD_H 2 | const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = { 3 | {{5, 6}, {4, 6}, {3, 6}, {2, 6}, {1, 6}, {0, 6}}, 4 | {{5, 7}, {4, 7}, {3, 7}, {2, 7}, {1, 7}, {0, 7}}, 5 | {{5, 8}, {4, 8}, {3, 8}, {2, 8}, {1, 8}, {0, 8}}, 6 | {{5, 9}, {4, 9}, {3, 9}, {2, 9}, {1, 9}, {0, 9}}, 7 | {{5,10}, {4,10}, {3,10}, {2,10}, {1,10}, {0,10}}, 8 | {{5,11}, {4,11}, {3,11}, {2,11}, {1,11}, {0,11}}, 9 | 10 | {{5, 0}, {4, 0}, {3, 0}, {2, 0}, {1, 0}, {0, 0}}, 11 | {{5, 1}, {4, 1}, {3, 1}, {2, 1}, {1, 1}, {0, 1}}, 12 | {{5, 2}, {4, 2}, {3, 2}, {2, 2}, {1, 2}, {0, 2}}, 13 | {{5, 3}, {4, 3}, {3, 3}, {2, 3}, {1, 3}, {0, 3}}, 14 | {{5, 4}, {4, 4}, {3, 4}, {2, 4}, {1, 4}, {0, 4}}, 15 | {{5, 5}, {4, 5}, {3, 5}, {2, 5}, {1, 5}, {0, 5}} 16 | }; 17 | -------------------------------------------------------------------------------- /tapdance.c: -------------------------------------------------------------------------------- 1 | static void sentence_end(tap_dance_state_t *state, void *user_data) { 2 | switch (state->count) { 3 | 4 | // Double tapping TD_DOT produces 5 | // ". " i.e. dot, space and capitalize next letter. 6 | // This helps to quickly end a sentence and begin another one 7 | // without having to hit shift. 8 | case 2: 9 | /* Check that Shift is inactive */ 10 | if (!(get_mods() & MOD_MASK_SHIFT)) { 11 | tap_code(KC_SPC); 12 | /* Internal code of OSM(MOD_LSFT) */ 13 | add_oneshot_mods(MOD_BIT(KC_LEFT_SHIFT)); 14 | 15 | } else { 16 | // send ">" (KC_DOT + shift → ">") 17 | tap_code(KC_DOT); 18 | } 19 | break; 20 | 21 | // Since `sentence_end` is called on each tap 22 | // and not at the end of the tapping term, 23 | // the third tap needs to cancel the effects 24 | // of the double tap in order to get the expected 25 | // three dots ellipsis. 26 | case 3: 27 | // remove the added space of the double tap case 28 | tap_code(KC_BSPC); 29 | // replace the space with a second dot 30 | tap_code(KC_DOT); 31 | // tap the third dot 32 | tap_code(KC_DOT); 33 | break; 34 | 35 | // send KC_DOT on every normal tap of TD_DOT 36 | default: 37 | tap_code(KC_DOT); 38 | } 39 | }; 40 | 41 | void sentence_end_finished (tap_dance_state_t *state, void *user_data) { 42 | last_keycode = KC_DOT; 43 | } 44 | 45 | tap_dance_action_t tap_dance_actions[] = { 46 | [DOT_TD] = ACTION_TAP_DANCE_FN_ADVANCED(sentence_end, sentence_end_finished, NULL), 47 | }; 48 | 49 | -------------------------------------------------------------------------------- /visualisation/heatmap/all_layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precondition/dactyl-manuform-keymap/ecbb5625276953ca8243095c6fa08f4581f04fb3/visualisation/heatmap/all_layers.png -------------------------------------------------------------------------------- /visualisation/keymapviz/keymapviz.ini: -------------------------------------------------------------------------------- 1 | [legends] 2 | # Transparent keys 3 | _ = 4 | __ = 5 | 6 | # US ANSI symbol keys 7 | KC_EXLM = ! 8 | KC_QUES = ? 9 | KC_GT = > 10 | KC_LT = < 11 | KC_HASH = # 12 | KC_PERC = % 13 | KC_AT = @ 14 | KC_DLR = $ 15 | KC_CIRC = ^ 16 | KC_LCBR = { 17 | KC_LPRN = ( 18 | KC_LBRC = [ 19 | KC_RCBR = } 20 | KC_RPRN = ) 21 | KC_RBRC = ] 22 | KC_PIPE = | 23 | KC_GRV = ` 24 | KC_TILD = ~ 25 | KC_PLUS = + 26 | KC_AMPR = & 27 | KC_UNDS = _ 28 | KC_MINS = - _ 29 | KC_EQL = = 30 | KC_SLSH = / ? 31 | KC_COMM = , < 32 | KC_DOT = . > 33 | KC_ASTR = * 34 | KC_BSLS = \ | 35 | KC_BSLASH = \ | 36 | KC_QUOT = ' " 37 | KC_DQUO = " 38 | KC_DQT = " 39 | KC_SCLN = : ; 40 | KC_NUHS = \NUHS| 41 | KC_NUBS = \NUBS| 42 | 43 | # Common special keys (I have no clue how to call them) 44 | KC_PSCR = PrintSc 45 | KC_INS = Ins 46 | 47 | # Lock keys 48 | KC_NLCK = NumLock 49 | KC_NUM = NumLock 50 | KC_SLCK = ScrLock 51 | KC_SCRL = ScrLock 52 | 53 | # Mouse keys 54 | KC_MS_U = MOUSE ↑ 55 | KC_MS_D = MOUSE ↓ 56 | KC_MS_L = MOUSE ← 57 | KC_MS_R = MOUSE → 58 | KC_WH_U = WHEEL ↑ 59 | KC_WH_D = WHEEL ↓ 60 | KC_WBAK = ⯬ 61 | KC_WFWD = ⯮ 62 | 63 | # Macros 64 | ARROW_R = -> => 65 | GUILL_R = » 66 | GUILL_L = « 67 | UPDIR = ../ 68 | YICODE = $yi{ 69 | O_BRACE = {⏎ 70 | C_BRACE = }⏎ 71 | O_BRQOT = [" 72 | C_BRQOT = "] 73 | 74 | # Pure modifier keys 75 | KC_LGUI = LGUI ◆ 76 | KC_RGUI = RGUI ◆ 77 | KC_LALT = LALT ⎇ 78 | KC_RALT = AltGr 79 | KC_LSFT = LSFT ⇧ 80 | KC_RSFT = RSFT ⇧ 81 | KC_LCTL = LCTL ⎈ 82 | KC_RCTL = RCTL ⎈ 83 | 84 | # One-shot modifiers 85 | OS_LSFT = 1-SHOT⇧ 86 | OS_RSFT = 1-SHOT⇧ 87 | OS_LCTL = 1-SHOT⎈ 88 | OS_RCTL = 1-SHOT⎈ 89 | OS_LGUI = 1-SHOT◆ 90 | OS_RGUI = 1-SHOT◆ 91 | OS_LALT = 1-SHOT⎇ 92 | OS_RALT = 1-SHOT⎇ 93 | 94 | # Control shortcuts 95 | C(KC_A) = Ctrl+A 96 | C(KC_B) = Ctrl+B 97 | C(KC_C) = Ctrl+C 98 | C(KC_D) = Ctrl+D 99 | C(KC_E) = Ctrl+E 100 | C(KC_F) = Ctrl+F 101 | C(KC_G) = Ctrl+G 102 | C(KC_H) = Ctrl+H 103 | C(KC_I) = Ctrl+I 104 | C(KC_J) = Ctrl+J 105 | C(KC_K) = Ctrl+K 106 | C(KC_L) = Ctrl+L 107 | C(KC_M) = Ctrl+M 108 | C(KC_N) = Ctrl+N 109 | C(KC_O) = Ctrl+O 110 | C(KC_P) = Ctrl+P 111 | C(KC_Q) = Ctrl+Q 112 | C(KC_R) = Ctrl+R 113 | C(KC_S) = Ctrl+S 114 | C(KC_T) = Ctrl+T 115 | C(KC_U) = Ctrl+U 116 | C(KC_V) = Ctrl+V 117 | C(KC_W) = Ctrl+W 118 | C(KC_X) = Ctrl+X 119 | C(KC_Y) = Ctrl+Y 120 | C(KC_Z) = Ctrl+Z 121 | 122 | # “Space Cadet” keys (that have no relation to the famous Space Cadet keyboard) 123 | KC_LSPO = (/⇧ 124 | KC_RSPC = )/⇧ 125 | KC_LAPO = (/⎇ 126 | KC_RAPC = )/⎇ 127 | SC_LSPO = (/⇧ 128 | SC_RSPC = )/⇧ 129 | SC_LAPO = (/⎇ 130 | SC_RAPC = )/⎇ 131 | 132 | # Home row mods 133 | HOME_A = A/◆ 134 | HOME_B = B 135 | HOME_C = C 136 | HOME_D = D 137 | HOME_E = E/⇧ 138 | HOME_F = F 139 | HOME_G = G 140 | HOME_H = H 141 | HOME_I = I/⎇ 142 | HOME_J = J 143 | HOME_K = K 144 | HOME_L = L 145 | HOME_M = M 146 | HOME_N = N/⎈ 147 | HOME_O = O/◆ 148 | HOME_P = P 149 | HOME_Q = Q 150 | HOME_R = R/⎇ 151 | HOME_S = S/⇧ 152 | HOME_T = T/⎈ 153 | HOME_U = U 154 | HOME_V = V 155 | HOME_W = W 156 | HOME_X = X 157 | HOME_Y = Y 158 | HOME_Z = Z 159 | 160 | # Mod-tap keys (other than home row mods) 161 | CTL_ESC = ESC/⎈ 162 | CTL_QUOT= ' "/⎈ 163 | ALT_ENT = ⏎ /⎇ 164 | KC_APP = MENU 165 | 166 | # Layer-taps 167 | NAV_TAB = TAB/NAV 168 | MS_CAPS = CAPS/MS 169 | SYM_ENT = ⏎/SYM 170 | NAV_UND = _/NAV 171 | 172 | # Dead diacritic keys 173 | DED_CIR = ^ 174 | DED_UML = ¨ 175 | 176 | # Accented letters 177 | ## acute 178 | A_ACUTE = Á 179 | AE_ACUTE = Ǽ 180 | C_ACUTE = Ć 181 | E_ACUTE = É 182 | G_ACUTE = Ǵ 183 | I_ACUTE = Í 184 | K_ACUTE = Ḱ 185 | L_ACUTE = Ĺ 186 | M_ACUTE = Ḿ 187 | N_ACUTE = Ń 188 | O_ACUTE = Ó 189 | OBAR_ACUTE = Ǿ 190 | P_ACUTE = Ṕ 191 | R_ACUTE = Ŕ 192 | S_ACUTE = Ś 193 | U_ACUTE = Ú 194 | W_ACUTE = Ẃ 195 | Y_ACUTE = Ý 196 | Z_ACUTE = Ź 197 | 198 | ## caron 199 | A_CARON = Ǎ 200 | C_CARON = Č 201 | D_CARON = Ď 202 | E_CARON = Ě 203 | G_CARON = Ǧ 204 | H_CARON = Ȟ 205 | I_CARON = Ǐ 206 | j_CARON = ǰ 207 | K_CARON = Ǩ 208 | L_CARON = Ľ 209 | N_CARON = Ň 210 | O_CARON = Ǒ 211 | R_CARON = Ř 212 | S_CARON = Š 213 | T_CARON = Ť 214 | U_CARON = Ǔ 215 | Z_CARON = Ž 216 | 217 | ## circumflex/hat 218 | A_CIRC = Â 219 | C_CIRC = Ĉ 220 | E_CIRC = Ê 221 | G_CIRC = Ĝ 222 | H_CIRC = Ĥ 223 | I_CIRC = Î 224 | J_CIRC = Ĵ 225 | O_CIRC = Ô 226 | S_CIRC = Ŝ 227 | U_CIRC = Û 228 | W_CIRC = Ŵ 229 | Y_CIRC = Ŷ 230 | Z_CIRC = Ẑ 231 | 232 | ## diaeresis/umlaut/tréma 233 | A_DIA = Ä 234 | E_DIA = Ë 235 | H_DIA = Ḧ 236 | I_DIA = Ï 237 | O_DIA = Ö 238 | t_DIA = ẗ 239 | U_DIA = Ü 240 | W_DIA = Ẅ 241 | X_DIA = Ẍ 242 | Y_DIA = Ÿ 243 | 244 | ## grave 245 | A_GRAVE = À 246 | E_GRAVE = È 247 | 248 | ## cedilla 249 | C_CDILA = Ç 250 | 251 | # Tap dance keys 252 | TD_DOT = . > 253 | 254 | # Magic QMK keys 255 | NK_ON = NKROon 256 | NK_OFF = NKROoff 257 | QK_GESC = ` ~/Esc 258 | RCG_SWP = ⎈ ↔ ◆ 259 | 260 | # Media keys 261 | KC_MPRV = ⏮ 262 | KC_MNXT = ⏭ 263 | KC_MPLY = ⏯ 264 | KC_MSTP = ⏹ 265 | 266 | # Steno keys 267 | # (Midi4Text) 268 | STN_N1 = #1 269 | STN_N2 = #2 270 | STN_N3 = #3 271 | STN_N4 = #4 272 | STN_N5 = #5 273 | STN_N6 = #6 274 | STN_N7 = #7 275 | STN_N8 = #8 276 | STN_N9 = #9 277 | STN_NA = NA 278 | STN_S1 = F 279 | STN_TL = Z 280 | STN_PL = N 281 | STN_HL = X 282 | STN_ST1 = *1 283 | STN_ST3 = *3 284 | STN_FR = e 285 | STN_PR = n 286 | STN_LR = z 287 | STN_TR = f 288 | STN_DR = -D 289 | STN_S2 = S 290 | STN_KL = C 291 | STN_WL = P 292 | STN_RL = R 293 | STN_ST2 = *2 294 | STN_ST4 = *4 295 | STN_RR = a 296 | STN_BR = p 297 | STN_GR = c 298 | STN_SR = s 299 | STN_ZR = -Z 300 | STN_A = I 301 | STN_O = U 302 | STN_E = u 303 | STN_U = i 304 | 305 | # Swap hands keys 306 | SH_OS = SWAPHNDS 307 | 308 | # Obscure basic keys 309 | KC_PSTE = PASTE 310 | KC_AGIN = AGAIN 311 | KC_PSLS = KP / 312 | -------------------------------------------------------------------------------- /visualisation/kle/keyboard-layout-editor.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Dactyl Manuform 5×6", 4 | "author": "precondition", 5 | "notes": "Keymap Repository: https://github.com/precondition/dactyl-manuform-keymap/", 6 | "css": ".keylabel2 {\n /* NAV legend color */\n color: #013766 !important;\n}\n\n.keylabel8 {\n /* SYM legend color */\n color: #ff0000 !important;\n}" 7 | }, 8 | [ 9 | { 10 | "y": 0.15, 11 | "x": 2, 12 | "t": "#000000\n\n\n#ff0000", 13 | "f": 5 14 | }, 15 | "`\n\n\nF2", 16 | "\"\n\n\nF3", 17 | "F4\n\n\nF4", 18 | "F5\n\n\nF5", 19 | { 20 | "x": 5.5 21 | }, 22 | "¨◌\n\n\nF6", 23 | "^◌\n\n\nF7", 24 | "È\n\n\nF8", 25 | "É\n\n\nF9" 26 | ], 27 | [ 28 | { 29 | "y": -0.5 30 | }, 31 | "Undo\n\n\nF12", 32 | "Redo\n\n\nF1", 33 | { 34 | "x": 13.5 35 | }, 36 | "F10\n\n\nF10", 37 | "F11\n\n\nF11" 38 | ], 39 | [ 40 | { 41 | "y": -0.5, 42 | "x": 2 43 | }, 44 | "W\n\n\n2", 45 | "F\n\n\n3", 46 | "P\n\nIns\n1\n", 47 | "B\n\n\n5", 48 | { 49 | "x": 5.5 50 | }, 51 | "J\n\n\n6", 52 | "L\n\n\n0", 53 | "U\n\n↑\n8", 54 | "Y\n\n\n9" 55 | ], 56 | [ 57 | { 58 | "y": -0.5 59 | }, 60 | "À\n\n\nx", 61 | "Q\n\n\n4", 62 | { 63 | "x": 13.5 64 | }, 65 | ";\n:\n\n7", 66 | "_\n-\n\n-" 67 | ], 68 | [ 69 | { 70 | "y": -0.5, 71 | "x": 2, 72 | "fa": [ 73 | 0, 74 | 0, 75 | 0, 76 | 4 77 | ] 78 | }, 79 | "R\n\n\n[\n\n\n\n\n\n⎇", 80 | "S\n\n\n]\n\n\n\n\n\n⇧", 81 | "T\n\n\n\"]\n\n\n\n\n\n", 82 | "G\n\n\n»", 83 | { 84 | "x": 5.5 85 | }, 86 | "M\n\n\n{", 87 | "N\n\n\n{\n\n\n\n\n\n", 88 | "E\n\n↓\n(\n\n\n\n\n\n⇧", 89 | "I\n\n\n)\n\n\n\n\n\n⎇" 90 | ], 91 | [ 92 | { 93 | "y": -0.5, 94 | "c": "#8eb0bb" 95 | }, 96 | "Esc\n\n\n«", 97 | { 98 | "c": "#cccccc" 99 | }, 100 | "A\n\n\n[\"\n\n\n\n\n\n◆", 101 | { 102 | "x": 13.5 103 | }, 104 | "O\n\n\n}\n\n\n\n\n\n◆", 105 | { 106 | "c": "#8eb0bb" 107 | }, 108 | "\"\n'\n\n}" 109 | ], 110 | [ 111 | { 112 | "y": -0.5, 113 | "x": 2, 114 | "c": "#cccccc", 115 | "f": 5 116 | }, 117 | "X\n\n\n@", 118 | { 119 | "f": 5 120 | }, 121 | "C\n\n\n#", 122 | { 123 | "f": 5 124 | }, 125 | "D\n\n\n$", 126 | { 127 | "f": 5 128 | }, 129 | "V\n\n\n%", 130 | { 131 | "x": 5.5, 132 | "f": 5 133 | }, 134 | "K\n\n\n^", 135 | { 136 | "f": 5 137 | }, 138 | "H\n\n\n&", 139 | { 140 | "f": 5 141 | }, 142 | "<\n,\n{\n*", 143 | { 144 | "f": 5 145 | }, 146 | ">\n.\n}\n=" 147 | ], 148 | [ 149 | { 150 | "y": -0.5, 151 | "c": "#8eb0bb", 152 | "f": 5 153 | }, 154 | "Z\n\n\n~", 155 | { 156 | "c": "#cccccc", 157 | "f": 5 158 | }, 159 | "REP\n\n\n!", 160 | { 161 | "x": 13.5, 162 | "f": 5 163 | }, 164 | "?\n/\n\n+", 165 | { 166 | "c": "#8eb0bb", 167 | "f": 4 168 | }, 169 | "=>\n->\n\n`" 170 | ], 171 | [ 172 | { 173 | "y": -0.5, 174 | "x": 2, 175 | "t": "#000000", 176 | "f": 5 177 | }, 178 | "", 179 | "Ç", 180 | { 181 | "x": 9.5, 182 | "a": 7 183 | }, 184 | "AltGr", 185 | { 186 | "a": 4 187 | }, 188 | "~\n`" 189 | ], 190 | [ 191 | { 192 | "r": 30, 193 | "rx": 5.5, 194 | "ry": 4.25, 195 | "y": -0.25, 196 | "x": 1, 197 | "h": 1.5 198 | }, 199 | "_" 200 | ], 201 | [ 202 | { 203 | "y": -0.5, 204 | "t": "#000000\n\n\n\n\n\n\n\n\n#013766", 205 | "h": 1.5 206 | }, 207 | "\n\n\n\n\n\n\n\n\nNAV" 208 | ], 209 | [ 210 | { 211 | "r": 65, 212 | "rx": 13.25, 213 | "y": 6.1, 214 | "x": -0.75, 215 | "t": "#000000", 216 | "a": 5 217 | }, 218 | "⇧\nOSM" 219 | ], 220 | [ 221 | { 222 | "r": 75, 223 | "rx": 5.5, 224 | "y": -1.25, 225 | "x": 3.5, 226 | "a": 4 227 | }, 228 | "" 229 | ], 230 | [ 231 | { 232 | "x": 2.5, 233 | "f": 3 234 | }, 235 | "Cmpse\n\n\n\n\n\n\n\n\n⎄", 236 | { 237 | "a": 7, 238 | "f": 1 239 | }, 240 | "Toggle PLOVER" 241 | ], 242 | [ 243 | { 244 | "r": -75, 245 | "rx": 12, 246 | "y": -1.25, 247 | "x": -4.5, 248 | "a": 4, 249 | "f": 5 250 | }, 251 | "\n\n" 252 | ], 253 | [ 254 | { 255 | "x": -4.5 256 | }, 257 | "\n\n", 258 | "\n\n" 259 | ], 260 | [ 261 | { 262 | "r": -65, 263 | "rx": 13.25, 264 | "y": -2, 265 | "x": -4, 266 | "a": 5 267 | }, 268 | "⇧\nOSM" 269 | ], 270 | [ 271 | { 272 | "r": -30, 273 | "rx": 12, 274 | "y": -0.25, 275 | "x": -2, 276 | "a": 4, 277 | "h": 1.5 278 | }, 279 | "\n" 280 | ], 281 | [ 282 | { 283 | "y": -0.5, 284 | "x": -1, 285 | "t": "#000000\n\n\n\n\n\n\n\n\n#ff0000", 286 | "h": 1.5 287 | }, 288 | "\n\n\n\n\n\n\n\n\nSYM" 289 | ] 290 | ] -------------------------------------------------------------------------------- /visualisation/kle/kle-base-sym-nav.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/precondition/dactyl-manuform-keymap/ecbb5625276953ca8243095c6fa08f4581f04fb3/visualisation/kle/kle-base-sym-nav.png --------------------------------------------------------------------------------