diff --git a/build.yaml b/build.yaml index 626e66a8d..2b0cf4083 100644 --- a/build.yaml +++ b/build.yaml @@ -13,8 +13,9 @@ # --- include: - - board: planck_rev6 - - board: corneish_zen_v2_left - - board: corneish_zen_v2_right - - board: glove80_lh - - board: glove80_rh + - board: nice_nano_v2 + shield: clog_left + - board: nice_nano_v2 + shield: clog_right + - board: nice_nano_v2 + shield: settings_reset diff --git a/config/base.keymap b/config/base.keymap index 59d6a2d26..b33b2705c 100644 --- a/config/base.keymap +++ b/config/base.keymap @@ -8,24 +8,34 @@ #else #define _BT_SEL_KEYS_ &trans &trans &trans &trans &trans #endif - #include "zmk-helpers/helper.h" -#include "zmk-helpers/unicode-chars/greek.dtsi" -#include "zmk-helpers/unicode-chars/german.dtsi" -#define DEF 0 -#define NAV 1 -#define FN 2 -#define NUM 3 -#define SYS 4 -#define MOUSE 5 +#define L_DVORAK 0 +#define L_FOCAL 1 +#define L_NUMS 2 +#define L_SYMS 3 #define XXX &none #define ___ &trans +/* 34 KEY MATRIX / LAYOUT MAPPING + + ╭───────────────┬────────────────╮ ╭─────────────────┬─────────────────╮ + ╭────────╯ 0 1 2 3 │ 4 5 6 7 ╰───────╮ ╭───────╯ LT3 LT2 LT1 LT0 │ RT0 RT1 RT2 RT3 ╰───────╮ + │ 8 9 10 11 12 13 │ 14 15 16 17 18 19 │ │ LM5 LM4 LM3 LM2 LM1 LM0 │ RM0 RM1 RM2 RM3 RM4 RM5 │ + ╰───╮ 20 21 22 23 24 │ 25 26 27 28 29 ╭───╯ ╰───╮ LB4 LB3 LB2 LB1 LB0 │ RB0 RB1 RB2 RB3 RB4 ╭───╯ + ╰───────────╮ 30 31 │ 32 33 ╭───────────╯ ╰───────────╮ LH1 LH0 │ RH0 RH1 ╭───────────╯ + ╰────────┴────────╯ ╰─────────┴─────────╯ */ + /* Global settings */ -#define QUICK_TAP_MS 175 +#define QUICK_TAP_MS 150 +#define TAPPING_TERM_LAYERS 150 +#define PRIOR_IDLE_MS 100 +#define TAPPING_TERM_MS 250 + +#undef COMBO_HOOK +#define COMBO_HOOK require-prior-idle-ms = ; &sk { // sticky-key config release-after-ms = <900>; // release after 0.9s @@ -37,19 +47,25 @@ }; < { // layer-tap config - flavor = "balanced"; - tapping-term-ms = <200>; - quick-tap-ms = ; + flavor = "balanced"; + tapping-term-ms = ; + quick-tap-ms = ; }; /* Homerow mods */ -#define KEYS_L LT0 LT1 LT2 LT3 LT4 LM0 LM1 LM2 LM3 LM4 LB0 LB1 LB2 LB3 LB4 // left hand -#define KEYS_R RT0 RT1 RT2 RT3 RT4 RM0 RM1 RM2 RM3 RM4 RB0 RB1 RB2 RB3 RB4 // right hand +#ifndef LM5 // traditional 3x5 + #define KEYS_L LT0 LT1 LT2 LT3 LT4 LM0 LM1 LM2 LM3 LM4 LB0 LB1 LB2 LB3 LB4 // left hand + #define KEYS_R RT0 RT1 RT2 RT3 RT4 RM0 RM1 RM2 RM3 RM4 RB0 RB1 RB2 RB3 RB4 // right hand +#else // pinky-extended 3x5-ish (osprette, steel toe, totem, etc.) + #define KEYS_L LT0 LT1 LT2 LT3 LM0 LM1 LM2 LM3 LM4 LM5 LB0 LB1 LB2 LB3 LB4 // left hand + #define KEYS_R RT0 RT1 RT2 RT3 RM0 RM1 RM2 RM3 RM4 RM5 RB0 RB1 RB2 RB3 RB4 // right hand +#endif + #ifndef LH2 #define THUMBS LH1 LH0 RH0 RH1 // thumbs on 34 keys #else - #define THUMBS LH2 LH1 LH0 RH0 RH1 RH2 // thumbs on 36+ keys + #define THUMBS LH4 LH3 LH2 LH1 LH0 RH0 RH1 RH2 RH3 RH4 // thumbs on 40 keys #endif #define MAKE_HRM(NAME, HOLD, TAP, TRIGGER_POS) \ @@ -72,7 +88,6 @@ MAKE_HRM(hmr, &kp, &kp, KEYS_L THUMBS) // right-hand HRMs /* Combos, leader key sequences, mouse emulation */ -#include "combos.dtsi" // must be sources after HRM-combo hack #include "leader.dtsi" #include "mouse.dtsi" #include "extra_keys.h" @@ -82,8 +97,8 @@ MAKE_HRM(hmr, &kp, &kp, KEYS_L THUMBS) // right-hand HRMs // long-tap action on hold, short-tap action on all interrupts #define MT_CORE \ flavor = "tap-preferred"; \ - tapping-term-ms = <220>; \ - quick-tap-ms = <220>; \ + tapping-term-ms = ; \ + quick-tap-ms = ; \ hold-trigger-key-positions = <0>; &mt { MT_CORE }; @@ -121,30 +136,25 @@ ZMK_MOD_MORPH(smart_shft, #define SMART_NUM &smart_num NUM 0 ZMK_HOLD_TAP(smart_num, flavor = "balanced"; - tapping-term-ms = <200>; + tapping-term-ms = ; quick-tap-ms = ; bindings = <&mo>, <&num_dance>; ) + ZMK_TAP_DANCE(num_dance, - tapping-term-ms = <200>; + tapping-term-ms = ; bindings = <&num_word NUM>, <&sl NUM>; // reverse this for sticky-num on single tap ) // smart-mouse, requires PR #1366 -ZMK_TRI_STATE(smart_mouse, - bindings = <&tog MOUSE>, <&none>, <&tog MOUSE>; - ignored-key-positions = ; - ignored-layers = ; -) +// ZMK_TRI_STATE(smart_mouse, +// bindings = <&tog MOUSE>, <&none>, <&tog MOUSE>; +// ignored-key-positions = ; +// ignored-layers = ; +// ) /* Custom behaviors */ -// Alt+Tab swapper, requires PR #1366 -ZMK_TRI_STATE(swapper, - bindings = <&kt LALT>, <&kp TAB>, <&kt LALT>; - ignored-key-positions = ; -) - // reuse basic mod-morph scheme #define SIMPLE_MORPH(NAME, MOD, BINDING1, BINDING2) \ ZMK_MOD_MORPH(NAME, \ @@ -152,134 +162,147 @@ ZMK_TRI_STATE(swapper, bindings = , ; \ ) -// tap: comma | shift + tap: semicolon | ctrl + shift + tap: < -SIMPLE_MORPH(comma_morph, SFT, &kp COMMA, &comma_inner_morph) -SIMPLE_MORPH(comma_inner_morph, CTL, &kp SEMICOLON, &kp LESS_THAN) - -// tap: dot | shift + tap: colon | ctrl + shift + tap: > -SIMPLE_MORPH(dot_morph, SFT, &kp DOT, &dot_inner_morph) -SIMPLE_MORPH(dot_inner_morph, CTL, &kp COLON, &kp GREATER_THAN) - // tap: qmark | shift + tap: excl -SIMPLE_MORPH(qexcl, SFT, &kp QMARK, &kp EXCL) +// SIMPLE_MORPH(qexcl, SFT, &kp QMARK, &kp EXCL) -// tap: left/right parenthesis | shft + tap: less-than/greater-than -SIMPLE_MORPH(lpar_lt, SFT, &kp LPAR, &kp LT) -SIMPLE_MORPH(rpar_gt, SFT, &kp RPAR, &kp GT) +// tap: copy | double-tap: cut +// ZMK_TAP_DANCE(copy_cut, +// tapping-term-ms = <200>; +// bindings = <&kp LC(INS)>, <&kp LC(X)>; +// ) -// tap: space | shift + tap: dot -> space -> sticky shift | hold: activate layer -ZMK_HOLD_TAP(lt_spc, +/* left-hand HRMs */ +ZMK_BEHAVIOR(hml, hold_tap, flavor = "balanced"; - tapping-term-ms = <200>; - quick-tap-ms = ; - bindings = <&mo>, <&spc_morph>; -) -SIMPLE_MORPH(spc_morph, SFT, &kp SPACE, &dot_spc) -ZMK_MACRO(dot_spc, - wait-ms = <0>; - tap-ms = <5>; - bindings = <&kp DOT &kp SPACE &sk LSHFT>; + tapping-term-ms = ; + quick-tap-ms = ; // repeat on tap-into-hold + require-prior-idle-ms = ; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = ; + hold-trigger-on-release; // delay positional check until key-release ) -// tap: backspace | lshft + tap: delete | rshft + tap: shift-delete -ZMK_MOD_MORPH(bs_del, - bindings = <&kp BSPC>, <&kp DEL>; - mods = <(MOD_LSFT|MOD_RSFT)>; - keep-mods = ; -) - -// tap: copy | double-tap: cut -ZMK_TAP_DANCE(copy_cut, - tapping-term-ms = <200>; - bindings = <&kp LC(INS)>, <&kp LC(X)>; +/* right-hand HRMs */ +ZMK_BEHAVIOR(hmr, hold_tap, + flavor = "balanced"; + tapping-term-ms = ; + quick-tap-ms = ; // repeat on tap-into-hold + require-prior-idle-ms = ; + bindings = <&kp>, <&kp>; + hold-trigger-key-positions = ; + hold-trigger-on-release; // delay positional check until key-release ) -// Sticky shift + leader -ZMK_MACRO(leader_sft, bindings = <&sk LSHFT &leader>;) - // misc aliases -#define CANCEL &kp K_CANCEL // cancel caps-word, num-word and smart-mouse -#define DSK_PREV &hmr LCTRL LG(LC(LEFT)) // previous desktop -#define DSK_NEXT &hmr LALT LG(LC(RIGHT)) // next desktop -#define PIN_WIN &kp LG(LC(LS(Q))) // pin window across desktops -#define PIN_APP &kp LG(LC(LS(A))) // pin application across desktops -#define DSK_MGR &kp LA(GRAVE) // desktop manager -#define VOL_DOWN &hmr RSHFT C_VOL_DN +#define LG_ENTER &mt LGUI ENTER +#define RG_ENTER &mt RGUI ENTER +#define C_S_SPACE &kp LC(LS(SPACE)) +#define A_S_SPACE &kp LA(LS(SPACE)) +#define NUMS_SPACE < L_NUMS SPACE +#define EMOJI_PICKER &kp LG(LS(COMMA)) + +/* Combos and chords, the basis of basically this entire layout. */ +#define COMBO_JOINTLY_MS 20 +#define COMBO_LAZILY_MS 50 + +ZMK_COMBO(c_lsuper, LG_ENTER, LM2 LM1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_rsuper, RG_ENTER, RM1 RM2, L_NUMS, COMBO_JOINTLY_MS) + +ZMK_COMBO(c_bksp, &kp BSPC, 6 7, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_del, &kp DEL, 4 6 7, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_esc, &kp ESC, LT3 LT2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_grv, &kp GRAVE, LT3 LT2 LT0, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_tab, &kp TAB, LM5 LM4, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_ins, &kp INS, LM5 LM4 LB4, ALL, COMBO_JOINTLY_MS) +// See comments below about c_end for some more context on this. +ZMK_COMBO(c_mins, &kp MINUS, RM2 RM3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_slsh, &kp SLASH, RB2 RB3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_pipe, &kp BACKSLASH, RM0 RM2 RM3, ALL, COMBO_JOINTLY_MS) // RM5 busted. Patch to 19 +ZMK_COMBO(c_plus, &kp PLUS, LB0 LB2 LB3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_eql, &kp EQUAL, RB0 RB2 RB3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_lprn, &kp LPAR, LT0 LT1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_rprn, &kp RPAR, RT0 RT1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_lbrk, &kp LBKT, LB0 LB1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_rbrk, &kp RBKT, RB0 RB1, ALL, COMBO_JOINTLY_MS) +// c_lbrc and c_rbrc are implicit (and more forgiving of thumb timing) given LBKT/RBKT +// ([ ]) turning into { } with Shift +ZMK_COMBO(c_arrup, &kp UP, LT1 LT2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_arrleft, &kp LEFT, LM2 LM3, ALL, COMBO_JOINTLY_MS) +// A secondary option since my hands always land here and want to press it anyway +ZMK_COMBO(c_arrleft2, &kp LEFT, LM4 LM3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_arrright, &kp RIGHT, LM0 LM1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_arrdown, &kp DOWN, LB1 LB2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_pgup, &kp PG_UP, RT1 RT2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_home, &kp HOME, RM0 RM1, ALL, COMBO_JOINTLY_MS) +// End key is asymmetrical with the arrow key cluster but makes room for RM2+RM3 +// dash, which feels way better on Choc spacing than what I originally had designed. +ZMK_COMBO(c_end, &kp END, RM2 19, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_pgdn, &kp PG_DN, RB1 RB2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_supup, &kp LG(UP), LT3 LT2 LT1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_supleft, &kp LG(LEFT), LM3 LM2 LM1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_supright, &kp LG(RIGHT), LM2 LM1 LM0, ALL, COMBO_JOINTLY_MS) // Was LMB0. Assumed LM0 +ZMK_COMBO(c_supdn, &kp LG(DOWN), LB3 LB2 LB1, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_lockscreen, &kp LG(HOME), RM0 RM1 RM2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_closewin, &kp LG(END), RM0 RM2 19, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_mfa, &kp LG(O), LT2 LT1 LT0, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_pwd, &kp LG(LC(O)), RT0 RT1 RT2, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_brightup, &kp C_BRI_UP, RT1 RT2 RT3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_brightdn, &kp C_BRI_DN, RB1 RB2 RB3, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_voldn, &kp K_VOL_DN, LB2 LB1 LB0, ALL, COMBO_JOINTLY_MS) +ZMK_COMBO(c_volup, &kp K_VOL_UP, RB0 RB1 RB2, ALL, COMBO_JOINTLY_MS) + +ZMK_COMBO(c_volmute, &kp K_MUTE, LB2 LB1 LB0 RB0 RB1 RB2, ALL, COMBO_LAZILY_MS) +ZMK_COMBO(c_syms, &mo L_SYMS, LH0 RH0, ALL, COMBO_LAZILY_MS) +ZMK_COMBO(c_bootloader, &bootloader, 8 9 20 31 32 18 19 29, ALL, COMBO_LAZILY_MS) /* Keymap */ -ZMK_CONDITIONAL_LAYER(sys, FN NUM, SYS) // FN + NUM --> SYS - -ZMK_LAYER(base, -//╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ - X_LT &kp Q &kp W &kp F &kp P &kp B X_MT &kp J &kp L &kp U &kp Y &kp SQT X_RT -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LM &hml LGUI A &hml LALT R &hml LSHFT S &hml LCTRL T &kp G X_MM &kp M &hmr LCTRL N &hmr RSHFT E &hmr LALT I &hmr LGUI O X_RM -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LB &kp Z &kp X &kp C &kp D &kp V X_MB &kp K &kp H &comma_morph &dot_morph &qexcl X_RB -//├──────┤ ╰─────────────┼─────────────┴─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┴───────────────────────────╯ ├──────┤ - X_LH <_spc NAV 0 < FN RET X_MH SMART_NUM &smart_shft X_RH -//╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ -) - -ZMK_LAYER(nav, -//╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ - X_LT ___ ___ &kp LS(TAB) &swapper ___ X_MT &kp PG_UP NAV_BSPC NAV_UP NAV_DEL ___ X_RT -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LM &sk LGUI &sk LALT &sk LSHFT &sk LCTRL ___ X_MM &kp PG_DN NAV_LEFT NAV_DOWN NAV_RIGHT &kp RET X_RM -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LB ___ ___ ___ ___ ___ X_MB &kp INS &kp TAB ___ ___ ___ X_RB -//├──────┤ ╰─────────────┼─────────────┴─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┴───────────────────────────╯ ├──────┤ - X_LH ___ ___ X_MH ___ CANCEL X_RH -//╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ -) - -ZMK_LAYER(fn, -//╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ - X_LT &kp F12 &kp F7 &kp F8 &kp F9 ___ X_MT ___ &kp C_PREV &kp C_VOL_UP &kp C_NEXT ___ X_RT -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LM &hml LGUI F11 &hml LALT F4 &hml LSHFT F5 &hml LCTRL F6 ___ X_MM ___ DSK_PREV VOL_DOWN DSK_NEXT ___ X_RM -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LB &kp F10 &kp F1 &kp F2 &kp F3 ___ X_MB PIN_APP PIN_WIN DSK_MGR ___ ___ X_RB -//├──────┤ ╰─────────────┼─────────────┴─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┴───────────────────────────╯ ├──────┤ - X_LH ___ ___ X_MH &kp C_MUTE &kp C_PP X_RH -//╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ +ZMK_LAYER(dvorak, +// ╭─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────╮ + &kp COMMA &kp DOT &kp P &kp Y &kp F &kp G &kp C &kp R +// ╭─────────────┬─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┬─────────────╮ + &kp SQT &kp A &kp O &kp E &kp U &hml LGUI I &hmr LGUI D &kp H &kp T &kp N &kp S &kp L +// ╰─────────────├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤─────────────╯ + &kp SEMICOLON &kp Q &kp J &kp K &kp X &kp B &kp M &kp W &kp V &kp Z +// ╰─────────────┴─────────────┴─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┴─────────────┴─────────────╯ + &kp LCTL &kp LSHFT NUMS_SPACE &kp RALT +// ╰─────────────┴─────────────╯ ╰─────────────┴─────────────╯ ) -ZMK_LAYER(num, -//╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ - X_LT ___ &kp N7 &kp N8 &kp N9 ___ X_MT ___ ___ ___ ___ ___ X_RT -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LM &hml LGUI N0 &hml LALT N4 &hml LSHFT N5 &hml LCTRL N6 ___ X_MM ___ ___ ___ ___ ___ X_RM -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LB ___ &kp N1 &kp N2 &kp N3 ___ X_MB ___ ___ ___ ___ ___ X_RB -//├──────┤ ╰─────────────┼─────────────┴─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┴───────────────────────────╯ ├──────┤ - X_LH ___ ___ X_MH ___ ___ X_RH -//╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ +ZMK_LAYER(focal, +// ╭─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────╮ + &kp L &kp H &kp G &kp K &kp Q &kp F &kp O &kp U +// ╭─────────────┬─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┬─────────────╮ + &hmr LCTL V &kp S &kp R &kp N &kp T &hml LGUI B &hmr LGUI Y &kp C &kp A &kp E &kp I &hmr LCTL J +// ╰─────────────├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤─────────────╯ + &kp Z &kp X &kp M &kp D &kp P &kp SQT &kp W &kp DOT &kp SEMICOLON &kp COMMA +// ╰─────────────┴─────────────┴─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┴─────────────┴─────────────╯ + &kp LCTL &kp LSHFT NUMS_SPACE &kp RALT +// ╰─────────────┴─────────────╯ ╰─────────────┴─────────────╯ ) -ZMK_LAYER(sys, -//╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ - X_LT _BT_SEL_KEYS_ X_MT ___ ___ ___ ___ ___ X_RT -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LM ___ ___ ___ ___ &bootloader X_MM &bootloader ___ ___ ___ ___ X_RM -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LB ___ ___ ___ ___ &sys_reset X_MB &sys_reset ___ ___ ___ ___ X_RB -//├──────┤ ╰─────────────┼─────────────┴─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┴───────────────────────────╯ ├──────┤ - X_LH ___ ___ X_MH ___ ___ X_RH -//╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ +ZMK_LAYER(nums, +// ╭─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────╮ + &kp F7 &kp F8 &kp F9 &kp F12 EMOJI_PICKER &kp N7 &kp N8 &kp N9 +// ╭─────────────┬─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┬─────────────╮ + &kp GRAVE XXX &kp F4 &kp F5 &kp F6 &kp F11 &kp MINUS &kp N4 &kp N5 &kp N6 &kp DOT &sl L_SYMS +// ╰─────────────├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤─────────────╯ + XXX &kp F1 &kp F2 &kp F3 &kp F10 &kp SLASH &kp N1 &kp N2 &kp N3 &kp RALT +// ╰─────────────┴─────────────┴─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┴─────────────┴─────────────╯ + ___ &kp LSHFT &kp SPACE &kp N0 +// ╰─────────────┴─────────────╯ ╰─────────────┴─────────────╯ ) -ZMK_LAYER(mouse, -//╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ ╭─────────────┬─────────────┬─────────────┬─────────────┬─────────────╮ ╭──────╮ - X_LT ___ ___ ___ ___ ___ X_MT ___ &kp PG_UP U_MS_U &kp PG_DN ___ X_RT -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LM ___ ___ ___ ___ ___ X_MM U_WH_L U_MS_L U_MS_D U_MS_R U_WH_R X_RM -//├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├──────┤ - X_LB ___ ___ ___ ___ ___ X_MB ___ &mkp LCLK &mkp MCLK &mkp RCLK ___ X_RB -//├──────┤ ╰─────────────┼─────────────┴─────────────┼─────────────┼─────────────┤ ├──────┤ ├─────────────┼─────────────┼─────────────┴───────────────────────────╯ ├──────┤ - X_LH ___ ___ X_MH U_WH_U U_WH_D X_RH -//╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ ╰─────────────┴─────────────╯ ╰──────╯ +ZMK_LAYER(syms, +// ╭─────────────┬─────────────┬─────────────┬─────────────╮ ╭─────────────┬─────────────┬─────────────┬─────────────╮ + &kp EXCL &kp AT &kp POUND &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp STAR +// ╭─────────────┬─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┬─────────────╮ + &kp K_PP XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX &kp K_NEXT +// ╰─────────────├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┼─────────────┼─────────────┤─────────────╯ + XXX XXX XXX XXX &to L_FOCAL &to L_DVORAK XXX XXX XXX XXX +// ╰─────────────┴─────────────┴─────────────┼─────────────┼─────────────┤ ├─────────────┼─────────────┼─────────────┴─────────────┴─────────────╯ + ___ &kp LSHFT &kp SPACE ___ +// ╰─────────────┴─────────────╯ ╰─────────────┴─────────────╯ ) /* vim: set ft=c tw=174: */ diff --git a/config/clog.conf b/config/clog.conf new file mode 100644 index 000000000..3c62566e1 --- /dev/null +++ b/config/clog.conf @@ -0,0 +1,5 @@ +CONFIG_ZMK_KEYBOARD_NAME="Osprette" + +# Combo config, automated by build script +CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY=6 +CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO=8 diff --git a/config/clog.keymap b/config/clog.keymap new file mode 100644 index 000000000..02786f55b --- /dev/null +++ b/config/clog.keymap @@ -0,0 +1,5 @@ +/* source keypos definitions */ +#include "zmk-helpers/key-labels/osprette.h" + +/* source the main keymap */ +#include "base.keymap" diff --git a/config/combos.dtsi b/config/combos.dtsi deleted file mode 100644 index c29f0afdc..000000000 --- a/config/combos.dtsi +++ /dev/null @@ -1,67 +0,0 @@ -/* KEY POSITIONS - - ╭─────────────────────╮ ╭─────────────────────╮ - │ LT4 LT3 LT2 LT1 LT0 │ │ RT0 RT1 RT2 RT3 RT4 │ - │ LM4 LM3 LM2 LM1 LM0 │ │ RM0 RM1 RM2 RM3 RM4 │ - │ LB4 LB3 LB2 LB1 LB0 │ │ RB0 RB1 RB2 RB3 RB4 │ - ╰───────╮ LH2 LH1 LH0 │ │ RH0 RH1 RH2 ╭───────╯ - ╰─────────────╯ ╰─────────────╯ */ - -#define COMBO_TERM_FAST 18 -#define COMBO_TERM_SLOW 30 - -#define COMBO_IDLE_FAST 150 -#define COMBO_IDLE_SLOW 50 - -/* Horizontal combos - left hand */ -ZMK_COMBO(esc, &kp ESC, LT3 LT2, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(ret, &kp RETURN, LT2 LT1, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(mouse, &smart_mouse, LT3 LT1, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) - -// Combos overlapping HRMs are set up as hold-taps themselves to allow for instantaneous -// chording of mods. Custom hold-tap instances can be bootstrapped on the go using the -// 8-argument version of ZMK_COMBO defined in base.keymap. -ZMK_COMBO(tab, &hml LS(LALT)TAB, LM3 LM2, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(ldr, &leader, LM2 LM1, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST, LS(LCTRL), KEYS_R) -ZMK_COMBO(ldrsh, &leader_sft, LM3 LM2 LM1, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST, LS(LC(LALT)), KEYS_R) - -ZMK_COMBO(cut, &kp LC(X), LB3 LB1, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(copy, &kp LC(INS), LB3 LB2, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(paste, &kp LS(INS), LB2 LB1, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) - -/* Horizontal combos - right hand */ -ZMK_COMBO(bspc, &kp BSPC, RT1 RT2, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(del, &kp DEL, RT2 RT3, DEF NAV NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) - -ZMK_COMBO(lpar, &lpar_lt, RM1 RM2, DEF NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST, RS(LCTRL), KEYS_L) -ZMK_COMBO(rpar, &rpar_gt, RM2 RM3, DEF NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST, RS(LALT), KEYS_L) -ZMK_COMBO(lt, &kp LT, RM1 RM2, NAV , COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(gt, &kp GT, RM2 RM3, NAV , COMBO_TERM_FAST, COMBO_IDLE_FAST) - -ZMK_COMBO(lbkt, &kp LBKT, RB1 RB2, DEF NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(rbkt, &kp RBKT, RB2 RB3, DEF NUM, COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(lbrc, &kp LBRC, RB1 RB2, NAV , COMBO_TERM_FAST, COMBO_IDLE_FAST) -ZMK_COMBO(rbrc, &kp RBRC, RB2 RB3, NAV , COMBO_TERM_FAST, COMBO_IDLE_FAST) - -/* Vertical combos - left hand */ -ZMK_COMBO(at, &kp AT, LT3 LM3, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(hash, &kp HASH, LT2 LM2, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(dllr, &kp DLLR, LT1 LM1, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(prcnt, &kp PRCNT, LT0 LM0, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) - -ZMK_COMBO(grave, &kp GRAVE, LM3 LB3, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(bslh, &kp BSLH, LM2 LB2, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(equal, &kp EQUAL, LM1 LB1, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(tilde, &kp TILDE, LM0 LB0, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) - -/* Vertical combos - right hand */ -ZMK_COMBO(caret, &kp CARET, RT0 RM0, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(plus, &kp PLUS, RT1 RM1, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(star, &kp STAR, RT2 RM2, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(amps, &kp AMPS, RT3 RM3, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) - -ZMK_COMBO(under, &kp UNDER, RM0 RB0, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(minus, &kp MINUS, RM1 RB1, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(fslh, &kp FSLH, RM2 RB2, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) -ZMK_COMBO(pipe, &kp PIPE, RM3 RB3, DEF NAV NUM, COMBO_TERM_SLOW, COMBO_IDLE_SLOW) - diff --git a/readme.md b/readme.md index 1f28263b2..87fa72e04 100644 --- a/readme.md +++ b/readme.md @@ -1,442 +1,11 @@ -# urob's zmk-config +# klardotsh's zmk-config This is my personal [ZMK firmware](https://github.com/zmkfirmware/zmk/) -configuration. It consists of a 34-keys base layout that is re-used for various -boards, including my Corneish Zen and my Planck. - -My configuration builds against `v0.1` of upstream ZMK plus a backport of the -merged pointer PR. Custom functionality is added through various ZMK modules. -The state of the entire firmware is pinned in my `west` -[manifest](https://github.com/urob/zmk-config/blob/main/config/west.yml). - -## Highlights - -- ["Timeless" homerow mods](#timeless-homerow-mods) -- Combos replace symbol layer -- Smart numbers and mouse layers auto-toggle off -- Unicode math and international leader key sequences -- Simplified Devicetree syntax using helper macros from - [zmk-helpers](https://github.com/urob/zmk-helpers) -- Base keymap padded with modular structure of "extra keys" to fit on larger - boards -- Arrow-cluster doubles as home, end, begin/end of - document on long-press -- More intuitive shift-actions: , ;, . : and ? - ! -- Fully automated, nix-based - [local build environment](#local-development-workspace) - -![](draw/keymap.png) - -## Timeless homerow mods - -[Homerow mods](https://precondition.github.io/home-row-mods) (aka "HRMs") can be -a game changer -- at least in theory. In practice, they require some finicky -timing: In its most naive implementation, in order to produce a "mod", they must -be held _longer_ than `tapping-term-ms`. In order to produce a "tap", they must -be held _less_ than `tapping-term-ms`. This requires very consistent typing -speeds that, alas, I do not possess. Hence my quest for a "timer-less" HRM -setup.[^1] - -After months of tweaking, I eventually ended up with a HRM setup that is -essentially timer-less, resulting in virtually no misfires. Yet it provides a -fluent typing experience with mostly no delays. - -Let's suppose for a moment we set `tapping-term-ms` to something ridiculously -large, say 5 seconds. This makes the configuration timer-less of sorts. But it -has two problems: (1) To activate a mod we will have to hold the HRM keys for -what feels like eternity. (2) During regular typing, there are delays between -the press of a key and the time it appears on the screen.[^2] Enter two of my -favorite ZMK features: - -- To address the first problem, I use ZMK's `balanced` flavor, which produces a - "hold" if another key is both pressed and released within the tapping-term. - Because that is exactly what I normally do with HRMs, there is virtually never - a need to wait past my long tapping term (see below for two exceptions). -- To address the typing delay, I use ZMK's `require-prior-idle-ms` property, - which immediately resolves a HRM as "tap" when it is pressed shortly _after_ - another key has been tapped. This all but completely eliminates the delay. - -This is great but there are still a few rough edges: - -- When rolling keys, I sometimes unintentionally end up with "nested" key - sequences: `key 1` down, `key 2` down and up, `key 1` up. Because of the - `balanced` flavor, this would falsely register `key 1` as a mod. As a remedy, - I use ZMK's `positional hold-tap` feature to force HRMs to always resolve as - "tap" when the _next_ key is on the same side of the keyboard. Problem solved. -- ... or at least almost. By default, positional-hold-tap performs the - positional check when the next key is _pressed_. This is not ideal, because it - prevents combining multiple modifiers on the same hand. To fix this, I use the - `hold-trigger-on-release` setting, which delays the positional-hold-tap - decision until the next key's _release_. With the setting, multiple mods can - be combined when held, while I still get the benefit from positional-hold-tap - when keys are tapped. -- So far, nothing of the configuration depends on the duration of - `tapping-term-ms`. In practice, there are two reasons why I don't set it to - infinity: - 1. Sometimes, in rare circumstances, I want to combine a mod with a alpha-key - _on the same hand_ (e.g., when using the mouse with the other hand). My - positional hold-tap configuration prevents this _within_ the tapping term. - By setting the tapping term to something large but not crazy large (I use - 280ms), I can still use same-hand `mod` + `alpha` shortcuts by holding the - mod for just a little while before tapping the alpha-key. - 2. Sometimes, I want to press a modifier without another key (e.g., on - Windows, tapping `Win` opens the search menu). Because the `balanced` - flavour only kicks in when another key is pressed, this also requires - waiting past `tapping-term-ms`. -- Finally, it is worth noting that this setup works best in combination with a - dedicated shift for capitalization during normal typing (I like sticky-shift - on a home-thumb). This is because shifting alphas is the one scenario where - pressing a mod may conflict with `require-prior-idle-ms`, which may result in - false negatives when typing fast. - -Here's my configuration (I use a bunch of -[helper macros](https://github.com/urob/zmk-helpers) to simplify the syntax, but -they are not necessary): - -```C++ -/* use helper macros to define left and right hand keys */ -#include "zmk-helpers/key-labels/36.h" // key-position labels -#define KEYS_L LT0 LT1 LT2 LT3 LT4 LM0 LM1 LM2 LM3 LM4 LB0 LB1 LB2 LB3 LB4 // left-hand keys -#define KEYS_R RT0 RT1 RT2 RT3 RT4 RM0 RM1 RM2 RM3 RM4 RB0 RB1 RB2 RB3 RB4 // right-hand keys -#define THUMBS LH2 LH1 LH0 RH0 RH1 RH2 // thumb keys - -/* left-hand HRMs */ -ZMK_HOLD_TAP(hml, - flavor = "balanced"; - tapping-term-ms = <280>; - quick-tap-ms = <175>; // repeat on tap-into-hold - require-prior-idle-ms = <150>; - bindings = <&kp>, <&kp>; - hold-trigger-key-positions = ; - hold-trigger-on-release; // delay positional check until key-release -) - -/* right-hand HRMs */ -ZMK_HOLD_TAP(hmr, - flavor = "balanced"; - tapping-term-ms = <280>; - quick-tap-ms = <175>; // repeat on tap-into-hold - require-prior-idle-ms = <150>; - bindings = <&kp>, <&kp>; - hold-trigger-key-positions = ; - hold-trigger-on-release; // delay positional check until key-release -) -``` - -### Required firmware - -After a recent round of patches, the above configuration now works with upstream -ZMK. - -Other parts of my configuration still require a few PRs that aren't yet in -upstream ZMK. My personal [ZMK fork](https://github.com/urob/zmk) includes all -PRs needed to compile my configuration. If you prefer to maintain your own fork -with a custom selection of PRs, you might find this -[ZMK-centric introduction to Git](https://gist.github.com/urob/68a1e206b2356a01b876ed02d3f542c7) -helpful. - -### Troubleshooting - -Hopefully, the above configuration "just works". If it doesn't, here's a few -smaller (and larger) things to try. - -- **Noticeable delay when tapping HRMs:** Increase `require-prior-idle-ms`. As a - rule of thumb, you want to set it to at least `10500/x` where `x` is your - (relaxed) WPM for English prose.[^3] -- **False negatives (same-hand):** Reduce `tapping-term-ms` (or disable - `hold-trigger-key-positions`) -- **False negatives (cross-hand):** Reduce `require-prior-idle-ms` (or set - flavor to `hold-preferred` -- to continue using `hold-trigger-on-release`, you - must also - [patch ZMK](https://github.com/celejewski/zmk/commit/d7a8482712d87963e59b74238667346221199293) - or use [an already patched branch](https://github.com/urob/zmk)) -- **False positives (same-hand):** Increase `tapping-term-ms` -- **False positives (cross-hand):** Increase `require-prior-idle-ms` (or set - flavor to `tap-preferred`, which requires holding HRMs past tapping term to - activate) - -## Using combos instead of a symbol layer - -I am a big fan of combos for all sort of things. In terms of comfort, I much -prefer them over accessing layers that involve lateral thumb movements to be -activated, especially when switching between different layers in rapid -succession. - -One common concern about overloading the layout with combos is that they lead to -misfires. Fortunately, the above-mentioned `require-prior-idle-ms` option also -works for combos, which in my experience all but completely eliminates the -problem -- even when rolling keys on the home row! - -My combo layout aims to place the most used symbols in easy-to-access locations -while also making them easy to remember. Specifically: - -- the top vertical-combo row matches the symbols on a standard numbers row - (except `+` and `&` being swapped) -- the bottom vertical-combo row is symmetric to the top row (subscript `_` - aligns with superscript `^`; minus `-` aligns with `+`; division `/` aligns - with multiplication `*`; logical-or `|` aligns with logical-and `&`) -- parenthesis, braces, brackets are set up symmetrically as horizontal combos - with `<`, `>`, `{` and `}` being accessed from the Navigation layer (or when - combined with `Shift`) -- left-hand side combos for `tap`, `esc`, `enter`, `cut` (on X + - D), `copy` and `paste` that go well with right-handed mouse usage -- L + Y switches to the Greek layer for a single key - press, L + U + Y activates one-shot shift in - addition -- W + P activates the smart mouse layer - -## Smart layers and other gimmicks - -##### Numword - -Inspired by Jonas Hietala's -[Numword](https://www.jonashietala.se/blog/2021/06/03/the-t-34-keyboard-layout/#where-are-the-digits) -for QMK, I implemented my own -[Auto-layer behavior](https://github.com/urob/zmk-auto-layer) for ZMK to set up -Numword. It is triggered via a single tap on "Smart-Num". Numword continues to -be activated as long as I type numbers, and deactivates automatically on any -other keypress (holding it activates a non-sticky num layer). - -After using Numword for more than a year now, I have been overall very happy -with it. When typing single digits, it effectively is a sticky-layer but with -the added advantage that I can also use it to type multiple digits. - -The main downside is that if a sequence of numbers is _immediately_ followed by -any of the letters on which my numpad is located (WFPRSTXCD), then the automatic -deactivation won't work. But this is rare -- most number sequences are -terminated by `space`, `return` or some form of punctuation/delimination. To -deal with the rare cases where they aren't, there is a `CANCEL` key on the -navigation-layer that deactivates Numword, Capsword and Smart-mouse. (It also -toggles off when pressing `Numword` again, but I find it cognitively easier to -have a dedicated "off-switch" than keeping track of which modes are currently -active.) - -##### Smart-Mouse - -Similarly to Numword, I have a smart-mouse layer (activated by comboing -W + P), which replaces the navigation cluster with scroll -and mouse-movements, and replaces the right thumbs with mouse buttons. Pressing -any other key automatically deactivates the layer. - -##### Capsword - -My right thumb triggers three variations of shift: Tapping yields sticky-shift -(used to capitalize alphas), holding activates a regular shift, and -double-tapping (or equivalently shift + tap) activates ZMK's Caps-word behavior. - -One minor technical detail: While it would be possible to implement the -double-tap functionality as a tap-dance, this would add a delay when using -single taps. To avoid the delays, I instead implemented the double-tap -functionality as a mod-morph. - -##### Multi-purpose Navigation cluster - -To economize on keys, I am using hold-taps on my navigation cluster, which yield -`home`, `end`, `begin/end of document`, and `delete word forward/backward` on -long-presses. The exact implementation is tweaked so that `Ctrl` is silently -absorbed in combination with `home` and `end` to avoid accidental document-wide -operations (which are accessible via the dedicated `begin/end document keys`.) - -##### Swapper - -I am using [Nick Conway](https://github.com/nickconway)'s fantastic -[tri-state](https://github.com/zmkfirmware/zmk/pull/1366) behavior for a -one-handed Alt-Tab switcher (`PWin` and `NWin`). - -##### Leader key - -I am using my own implementation of a -[Leader key](https://github.com/urob/zmk-leader-key) to bind less common -functionality without giving up dedicated keys. Currently, I am using leader -sequences for various system and output controls. I am also using leader key -sequences for convenient access to various Unicode math symbols and -international characters. - -## Local development workspace - -I streamline my local build process using `nix`, `direnv` and `just`. This -automatically sets up a virtual development environment with `west`, the -`zephyr-sdk` and all its dependencies when `cd`-ing into the ZMK-workspace. The -environment is _completely isolated_ and won't pollute your system. - -### Setup - -#### Pre-requisites - -1. Install the `nix` package manager: - - ```bash - # Install Nix with flake support enabled - curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | - sh -s -- install --no-confirm - - # Start the nix daemon without restarting the shell - . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh - ``` - -2. Install [`direnv`](https://direnv.net/) (and optionally but recommended - [`nix-direnv`](https://github.com/nix-community/nix-direnv)[^4]) using your - package manager of choice. E.g., using the `nix` package manager that we just - installed[^5]: - - ``` - nix profile install nixpkgs#direnv nixpkgs#nix-direnv - ``` - -3. Set up the `direnv` [shell-hook](https://direnv.net/docs/hook.html) for your - shell. E.g., for `bash`: - - ```bash - # Install the shell-hook - echo 'eval "$(direnv hook bash)"' >> ~/.bashrc - - # Enable nix-direnv (if installed in the previous step) - mkdir -p ~/.config/direnv - echo 'source $HOME/.nix-profile/share/nix-direnv/direnvrc' >> ~/.config/direnv/direnvrc - - # Optional: make direnv less verbose - echo '[global]\nwarn_timeout = "2m"\nhide_env_diff = true' >> ~/.config/direnv/direnv.toml - - # Source the bashrc to activate the hook (or start a new shell) - source ~/.bashrc - ``` - -#### Set up the workspace - -1. Clone _your fork_ of this repository. I like to name my local clone - `zmk-workspace` as it will be the toplevel of the development environment. - - ```bash - # Replace `urob` with your username - git clone https://github.com/urob/zmk-config zmk-workspace - ``` - -2. Enter the workspace and set up the environment. - - ```bash - # The first time you enter the workspace, you will be prompted to allow direnv - cd zmk-workspace - - # Allow direnv for the workspace, which will set up the environment - direnv allow - - # Initialize the Zephyr workspace and pull in the ZMK dependencies - # (same as `west init -l config && west update && west zephyr-export`) - just init - ``` - -### Usage - -After following the steps above your workspace should look like this: - -```bash -zmk-workspace -├── config -├── firmware (created after building) -├── modules -│ ├── auto-layer -│ ├── helpers -│ └── tri-state -└── zmk - └── ... -``` - -#### Building the firmware - -To build the firmware, simply type `just build all` from anywhere within the -workspace. This will parse `build.yaml` and build the firmware for all board and -shield combinations listed there. - -To only build the firmware for a specific target, use `just build `. -This will build the firmware for all matching board and shield combinations. For -instance, to build the firmware for my Corneish Zen, I can type -`just build zen`, which builds both `corneish_zen_v2_left` and -`corneish_zen_v2_right`. (`just list` shows all valid build targets.) - -Additional arguments to `just build` are passed on to `west`. For instance, a -pristine build can be triggered with `just build all -p`. - -(For this particular example, there is also a `just clean` recipe, which clears -the build cache. To list all available recipes, type `just`. Bonus tip: `just` -provides -[completion scripts](https://github.com/casey/just?tab=readme-ov-file#shell-completion-scripts) -for many shells.) - -#### Drawing the keymap - -The build environment packages -[keymap-drawer](https://github.com/caksoylar/keymap-drawer). `just draw` parses -`base.keymap` and draws it to `draw/base.svg`. I haven't gotten around to -tweaking the output yet, so for now this is just a demonstration of how to set -things up. - -#### Hacking the firmware - -To make changes to the ZMK source or any of the modules, simply edit the files -or use `git` to pull in changes. - -To switch to any remote branches or tags, use `git fetch` inside a module -directory to make the remote refs locally available. Then switch to the desired -branch with `git checkout ` as usual. You may also want to register -additional remotes to work with or consider making them the default in -`config/west.yml`. - -#### Updating the build environment - -To update the ZMK dependencies, use `just update`. This will pull in the latest -version of ZMK and all modules specified in `config/west.yml`. Make sure to -commit and push all local changes you have made to ZMK and the modules before -running this command, as this will overwrite them. - -To upgrade the Zephyr SDK and Python build dependencies, use `just upgrade-sdk`. - -## Issues and workarounds - -Since I switched from QMK to ZMK I have been very impressed with how easy it is -to set up relatively complex layouts in ZMK. For the most parts I don't miss any -functionality (to the contrary, I found that ZMK supports many features natively -that would require complex user-space implementations in QMK). Below are a few -remaining issues: - -- ZMK does not yet support "tap-only" combos - ([#544](https://github.com/zmkfirmware/zmk/issues/544)), requiring a brief - pause when wanting to chord HRMs that overlap with combo positions. As a - workaround, I implemented all homerow combos as homerow-mod-combos. This is - good enough for day-to-day, but does not address all edge cases (eg changing - active mods). -- Very minor: `&bootloader` doesn't work with stm32 boards like the Planck - ([#1086](https://github.com/zmkfirmware/zmk/issues/1086)) - -[^1]: - I call it "timer-less", because the large tapping-term makes the behavior - insensitive to the precise timings. One may say that there is still the - `require-prior-idle` timeout. However, with both a large tapping-term and - positional-hold-taps, the behavior is _not_ actually sensitive to the - `require-prior-idle` timing: All it does is reduce the delay in typing; - i.e., variations in typing speed won't affect _what_ is being typed but - merely _how fast_ it appears on the screen. - -[^2]: - The delay is determined by how quickly a key is released and is not directly - related to the tapping-term. But regardless of its length, most people still - find it noticable and disruptive. - -[^3]: - E.g, if your WPM is 70 or larger, then the default of 150ms (=10500/70) - should work well. The rule of thumb is based on an average character length - of 4.7 for English words. Taking into account 1 extra tap for `space`, this - yields a minimum `require-prior-idle-ms` of (60 _ 1000) / (5.7 _ x) ≈ 10500 - / x milliseconds. The approximation errs on the safe side, as in practice - home row taps tend to be faster than average. - -[^4]: - `nix-direnv` provides a vastly improved caching experience compared to only - having `direnv`, making entering and exiting the workspace instantaneous - after the first time. - -[^5]: - This will permanently install the packages into your local profile, forgoing - many of the benefits that make Nix uniquely powerful. A better approach, - though beyond the scope of this document, is to use `home-manager` to - maintain your user environment. +configuration, based in decent amounts on the works of +[urob](https://github.com/urob/zmk-config) and +[kdb424](https://github.com/kdb424/sweep-zmk). It powers my "smol boards" like +[Sam Mohr's Osprette](https://sammohr.dev/keyboards) and the [HillSideView 40 + +Cirque](https://github.com/wannabecoffeenerd/HillSideView). + +For the code powering my larger boards (like Corne), see [my QMK +configuration](https://github.com/klardotsh/qmk_firmware).