diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5a05bcace9a..94904d0a1d3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -430,7 +430,7 @@ jobs: uses: actions/checkout@v4 with: persist-credentials: false - - uses: tj-actions/changed-files@v44 + - uses: tj-actions/changed-files@v45 id: changed-files with: json: true diff --git a/app/Kconfig b/app/Kconfig index 899331a0d18..f35e860c94d 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -258,6 +258,26 @@ rsource "src/split/Kconfig" #Basic Keyboard Setup endmenu +menu "Keymaps" + +config ZMK_KEYMAP_LAYER_REORDERING + bool "Layer Reordering Support" + +config ZMK_KEYMAP_SETTINGS_STORAGE + bool "Settings Save/Load" + depends on SETTINGS + depends on ZMK_BEHAVIOR_LOCAL_IDS + +if ZMK_KEYMAP_SETTINGS_STORAGE + +config ZMK_KEYMAP_LAYER_NAME_MAX_LEN + int "Max Layer Name Length" + default 20 + +endif + +endmenu # Keymaps + rsource "src/studio/Kconfig" menu "Display/LED Options" diff --git a/app/boards/arm/bdn9/bdn9_rev2.keymap b/app/boards/arm/bdn9/bdn9_rev2.keymap index 1e2c192dd6f..0f522492cec 100644 --- a/app/boards/arm/bdn9/bdn9_rev2.keymap +++ b/app/boards/arm/bdn9/bdn9_rev2.keymap @@ -4,6 +4,8 @@ * SPDX-License-Identifier: MIT */ +#undef ZMK_BEHAVIORS_KEEP_ALL + #include #include diff --git a/app/boards/arm/bt60/bt60_v1.keymap b/app/boards/arm/bt60/bt60_v1.keymap index 10575428540..be3b206a161 100644 --- a/app/boards/arm/bt60/bt60_v1.keymap +++ b/app/boards/arm/bt60/bt60_v1.keymap @@ -31,7 +31,7 @@ #ifdef ANSI default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | @@ -94,7 +94,7 @@ #elif defined(ISO) default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | // | SHIFT | | | Z | X | C | V | B | N | M | , | . | / | SHIFT | @@ -122,7 +122,7 @@ #elif defined(ALL_1U) default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHFT | UP | 1 | @@ -150,7 +150,7 @@ #else default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP| DEL | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BSPC| DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | 1 | diff --git a/app/boards/arm/bt60/bt60_v1_hs.keymap b/app/boards/arm/bt60/bt60_v1_hs.keymap index 6c26756e35a..f1e483e3a1b 100644 --- a/app/boards/arm/bt60/bt60_v1_hs.keymap +++ b/app/boards/arm/bt60/bt60_v1_hs.keymap @@ -8,7 +8,7 @@ default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | DEL // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | diff --git a/app/boards/arm/ckp/bt60_v2.keymap b/app/boards/arm/ckp/bt60_v2.keymap index 39ba186ee59..f72401f67e1 100644 --- a/app/boards/arm/ckp/bt60_v2.keymap +++ b/app/boards/arm/ckp/bt60_v2.keymap @@ -29,7 +29,7 @@ #ifdef ANSI default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | @@ -65,7 +65,7 @@ #elif defined(ISO) default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | // | SHIFT | \ | Z | X | C | V | B | N | M | , | . | / | SHIFT | @@ -101,7 +101,7 @@ #elif defined(ALL_1U) default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP | DEL | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BSPC | DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHFT |NONE| Z | X | C | V | B | N | M | , | . | / | SHFT | UP | 1 | @@ -118,7 +118,7 @@ }; raise { // ------------------------------------------------------------------------------------------ - // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 |BKSP | DEL | + // |GRAVE| F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 |BSPC | DEL | // | TAB | Q | W | E | HUI | HUD | Y | U | INS | O |PSCRN| SLCK| P_B | RGB_TOG | // | CAPS | A | S | D | BRI | BRD | H | J | K | L | HOME| PGUP| BOOT | // | SHFT |NONE|VOLDN|VOLUP|MUTE|BLINC|BLDEC| N | M | , | END | PGDN | SHFT|BL_TOG| 1 | @@ -136,7 +136,7 @@ #elif defined(HHKB) default_layer { // ------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | diff --git a/app/boards/arm/ckp/bt65_v1.keymap b/app/boards/arm/ckp/bt65_v1.keymap index 86db14cb1a6..a4041084490 100644 --- a/app/boards/arm/ckp/bt65_v1.keymap +++ b/app/boards/arm/ckp/bt65_v1.keymap @@ -29,7 +29,7 @@ #ifdef ANSI default_layer { // ------------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | INS | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| @@ -37,7 +37,7 @@ // ------------------------------------------------------------------------------------------------ bindings = < - &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp INS &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN @@ -65,7 +65,7 @@ #elif defined(ISO) default_layer { // ------------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | INS | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | PGUP| // |SHIFT | \ | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| @@ -73,7 +73,7 @@ // ------------------------------------------------------------------------------------------------ bindings = < - &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp INS &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NON_US_HASH &kp RET &kp PG_UP &kp LSHFT &kp NON_US_BSLH &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN @@ -101,7 +101,7 @@ #elif defined(ALL_1U) default_layer { // ------------------------------------------------------------------------------------------------- - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP | DEL | HOME| + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BSPC | DEL | HOME| // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | END | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| // |SHIFT|NONE | Z | X | C | V | B | N | M | , | . | / |SHIFT|NONE | UP | PGDN| @@ -136,7 +136,7 @@ #elif defined(HHKB) default_layer { // ------------------------------------------------------------------------------------------------ - // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | HOME| // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | END | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | PGUP| @@ -144,7 +144,7 @@ // ------------------------------------------------------------------------------------------------ bindings = < - &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp HOME &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp END &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp PG_UP diff --git a/app/boards/arm/ckp/bt75_v1.keymap b/app/boards/arm/ckp/bt75_v1.keymap index 285df1a8686..888dcb643d9 100644 --- a/app/boards/arm/ckp/bt75_v1.keymap +++ b/app/boards/arm/ckp/bt75_v1.keymap @@ -27,7 +27,7 @@ default_layer { // ------------------------------------------------------------------------------------------------ // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN|HOME| END | - // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | INS | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| @@ -35,7 +35,7 @@ // ------------------------------------------------------------------------------------------------ bindings = < &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PSCRN &kp HOME &kp END - &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp INS &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN @@ -66,7 +66,7 @@ default_layer { // ------------------------------------------------------------------------------------------------ // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN|HOME| END | - // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | DEL | + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | DEL | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | | INS | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | # | ENTER | PGUP| // |SHIFT | \ | Z | X | C | V | B | N | M | , | . | / | SHIFT | UP | PGDN| @@ -74,7 +74,7 @@ // ------------------------------------------------------------------------------------------------ bindings = < &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PSCRN &kp HOME &kp END - &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BKSP &kp DEL + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp DEL &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp INS &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp NON_US_HASH &kp RET &kp PG_UP &kp LSHFT &kp NON_US_BSLH &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN @@ -105,7 +105,7 @@ default_layer { // ------------------------------------------------------------------------------------------------- // | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F9 | F9 | F10 | F11 | F12 |PSCRN| P_B | INS | - // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BKSP | DEL | HOME| + // |GRAVE| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = |BSPC | DEL | HOME| // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | END | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | PGUP| // |SHIFT|NONE | Z | X | C | V | B | N | M | , | . | / |SHIFT|NONE | UP | PGDN| diff --git a/app/boards/arm/corneish_zen/corneish_zen.keymap b/app/boards/arm/corneish_zen/corneish_zen.keymap index 06eee01c1fa..8dbb7d3b9af 100644 --- a/app/boards/arm/corneish_zen/corneish_zen.keymap +++ b/app/boards/arm/corneish_zen/corneish_zen.keymap @@ -23,7 +23,7 @@ default_layer { display-name = "QWERTY"; // -------------------------------------------------------------------------------- -// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | // | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | // | GUI | LWR | SPC | | ENT | RSE | ALT | @@ -38,7 +38,7 @@ lower_layer { display-name = "NUMBER"; // ----------------------------------------------------------------------------------------- -// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BSPC | // | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | // | SHFT | | | | | | | | | | | | | // | GUI | | SPC | | ENT | | ALT | @@ -53,7 +53,7 @@ raise_layer { display-name = "SYMBOL"; // ----------------------------------------------------------------------------------------- -// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BSPC | // | CTRL | | | | | | | - | = | [ | ] | \ | ` | // | SHFT | | | | | | | _ | + | { | } | "|" | ~ | // | GUI | | SPC | | ENT | | ALT | diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap b/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap index e8cc6a7a884..eaf5d5daba0 100644 --- a/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap @@ -7,7 +7,7 @@ default_layer { // ------------------------------------------------------------------------------------------ -// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | SHIFT(/) | ^ | DEL | diff --git a/app/boards/arm/ferris/ferris_rev02.dts b/app/boards/arm/ferris/ferris_rev02.dts index a0e28f03833..235a92e458d 100644 --- a/app/boards/arm/ferris/ferris_rev02.dts +++ b/app/boards/arm/ferris/ferris_rev02.dts @@ -10,6 +10,12 @@ #include +#include + +&cuddlykeyboards_ferris_layout { + transform = <&transform>; +}; + / { model = "Ferris rev0.2"; compatible = "ferris,rev02", "st,stm32f072"; @@ -18,7 +24,6 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zmk,kscan = &kscan; - zmk,matrix-transform = &transform; /* TODO: Enable once we support the IC for underglow zmk,underglow = &led_strip; */ @@ -114,6 +119,9 @@ zephyr_udc0: &usb { pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>; pinctrl-names = "default"; + + // Overridden to lower RAM usage. + num-bidir-endpoints = <4>; }; &clk_hsi { diff --git a/app/boards/arm/ferris/ferris_rev02.keymap b/app/boards/arm/ferris/ferris_rev02.keymap index b7668416b3c..1e686a6d04c 100644 --- a/app/boards/arm/ferris/ferris_rev02.keymap +++ b/app/boards/arm/ferris/ferris_rev02.keymap @@ -4,6 +4,8 @@ * SPDX-License-Identifier: MIT */ +#undef ZMK_BEHAVIORS_KEEP_ALL + #include #include #include @@ -33,16 +35,16 @@ default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp H &hm RSHFT J &hm RCTRL K &hm LALT L &hm LGUI QUOT + &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp H &hm RSHFT J &hm RCTRL K &hm LALT L &hm LGUI SQT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH - < NAV_L TAB &kp ENTER < NUM_L SPACE < SYM_L BKSP + < NAV_L TAB &kp ENTER < NUM_L SPACE < SYM_L BSPC >; }; nav_layer { bindings = < &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW + &trans &trans &trans &trans &trans &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp PG_UP &kp END &trans &trans &kp ESC &kp DEL >; diff --git a/app/boards/arm/nice60/nice60-pinctrl.dtsi b/app/boards/arm/nice60/nice60-pinctrl.dtsi index 9b0e198d396..e808eaa78a7 100644 --- a/app/boards/arm/nice60/nice60-pinctrl.dtsi +++ b/app/boards/arm/nice60/nice60-pinctrl.dtsi @@ -9,4 +9,11 @@ psels = ; }; }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; }; diff --git a/app/boards/arm/nice60/nice60.dts b/app/boards/arm/nice60/nice60.dts index 4eefbb9d8f3..fec8a678e76 100644 --- a/app/boards/arm/nice60/nice60.dts +++ b/app/boards/arm/nice60/nice60.dts @@ -110,7 +110,8 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,5) R compatible = "nordic,nrf-spim"; pinctrl-0 = <&spi3_default>; - pinctrl-names = "default"; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; status = "okay"; led_strip: ws2812@0 { diff --git a/app/boards/arm/nice60/nice60.keymap b/app/boards/arm/nice60/nice60.keymap index 3a35716321b..ba98ec23c25 100644 --- a/app/boards/arm/nice60/nice60.keymap +++ b/app/boards/arm/nice60/nice60.keymap @@ -15,7 +15,7 @@ default_layer { // ------------------------------------------------------------------------------------------ -// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | diff --git a/app/boards/arm/planck/planck_rev6.keymap b/app/boards/arm/planck/planck_rev6.keymap index 1386eadd18b..22fe2868ad8 100644 --- a/app/boards/arm/planck/planck_rev6.keymap +++ b/app/boards/arm/planck/planck_rev6.keymap @@ -21,12 +21,12 @@ // | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC | // | ESC | A | S | D | F | G | H | J | K | L | ; | ' | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | RET | - // | | LCTL | LALT | LGUI | LOWR | SPACE | RAIS | LARW | DARW | UARW | RARW | + // | | LCTRL | LALT | LGUI | LOWR | SPACE | RAIS | LEFT | DOWN | UP | RIGHT | bindings = < &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RET - &trans &kp LCTL &kp LALT &kp LGUI &mo 1 &trans &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + &trans &kp LCTRL &kp LALT &kp LGUI &mo 1 &trans &kp SPACE &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT >; sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; }; diff --git a/app/boards/native_posix_64.overlay b/app/boards/native_posix_64.overlay index d0526ca38eb..5b8e23d3087 100644 --- a/app/boards/native_posix_64.overlay +++ b/app/boards/native_posix_64.overlay @@ -1,4 +1,4 @@ -#include + #include #include @@ -8,7 +8,7 @@ zmk,kscan = &kscan; }; - kscan: kscan { + kscan: native_posix_64_kscan_mock { compatible = "zmk,kscan-mock"; rows = <2>; diff --git a/app/boards/shields/boardsource5x12/boardsource5x12.keymap b/app/boards/shields/boardsource5x12/boardsource5x12.keymap index cb851c35cac..8ae9939810b 100644 --- a/app/boards/shields/boardsource5x12/boardsource5x12.keymap +++ b/app/boards/shields/boardsource5x12/boardsource5x12.keymap @@ -20,7 +20,7 @@ // | TAB | Q | W | E | R | T | Y | U | I | O | P | \ | // | SHIFT | A | S | D | F | G | H | J | K | L | ; | ' | // | CTRL | Z | X | C | V | B | N | M | , | . | / | ENTER | - // |ADJUST | LCTL | LALT | LGUI | LOWR | SPACE| SPACE | RAIS | LARW | DARW | UARW | RARW | + // |ADJUST | LCTL | LALT | LGUI | LOWR | SPACE| SPACE | RAIS | LEFT | DOWN | UARW | RARW | bindings = < diff --git a/app/boards/shields/corne/corne.dtsi b/app/boards/shields/corne/corne.dtsi index e1edcce81e4..e4339e617d5 100644 --- a/app/boards/shields/corne/corne.dtsi +++ b/app/boards/shields/corne/corne.dtsi @@ -6,11 +6,21 @@ #include +#include + +&foostan_corne_6col_layout { + transform = <&default_transform>; +}; + +&foostan_corne_5col_layout { + transform = <&five_column_transform>; +}; + / { chosen { zephyr,display = &oled; zmk,kscan = &kscan0; - zmk,matrix-transform = &default_transform; + zmk,physical-layout = &foostan_corne_6col_layout; }; default_transform: keymap_transform_0 { @@ -36,7 +46,7 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) // | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | // | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | // | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | -// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | +// | SW19 | SW20 | SW21 | | SW21 | SW20 | SW19 | map = < RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) diff --git a/app/boards/shields/corne/corne.keymap b/app/boards/shields/corne/corne.keymap index 01350bd5b51..ea4c2e8997e 100644 --- a/app/boards/shields/corne/corne.keymap +++ b/app/boards/shields/corne/corne.keymap @@ -14,7 +14,7 @@ default_layer { // ----------------------------------------------------------------------------------------- -// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | // | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | // | GUI | LWR | SPC | | ENT | RSE | ALT | @@ -27,7 +27,7 @@ }; lower_layer { // ----------------------------------------------------------------------------------------- -// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BSPC | // | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | // | SHFT | | | | | | | | | | | | | // | GUI | | SPC | | ENT | | ALT | @@ -41,7 +41,7 @@ raise_layer { // ----------------------------------------------------------------------------------------- -// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BSPC | // | CTRL | | | | | | | - | = | [ | ] | \ | ` | // | SHFT | | | | | | | _ | + | { | } | "|" | ~ | // | GUI | | SPC | | ENT | | ALT | diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi index b510c636f64..c2947e55855 100644 --- a/app/boards/shields/cradio/cradio.dtsi +++ b/app/boards/shields/cradio/cradio.dtsi @@ -5,12 +5,15 @@ */ #include +#include -/ { +&cuddlykeyboards_ferris_layout { + transform = <&default_transform>; +}; +/ { chosen { zmk,kscan = &kscan0; - zmk,matrix-transform = &default_transform; }; default_transform: keymap_transform_0 { diff --git a/app/boards/shields/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap index ab4591babb6..ab952fb8462 100644 --- a/app/boards/shields/cradio/cradio.keymap +++ b/app/boards/shields/cradio/cradio.keymap @@ -56,7 +56,7 @@ &kp INS &kp N1 &kp N2 &kp N3 &trans &kp HOME &kp PG_DN &kp PG_UP &kp END &kp COLON //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ //│ DELETE │ 4 │ 5 │ 6 │ │ │ LEFT │ DOWN │ UP │ RIGHT │ ; │ - &kp DEL &kp N4 &kp N5 &kp N6 &trans &kp LARW &kp DARW &kp UARW &kp RARW &kp SEMI + &kp DEL &kp N4 &kp N5 &kp N6 &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp SEMI //├──────────┼──────────┼──────────┼──────────┼──────────┤ ├──────────┼──────────┼──────────┼──────────┼──────────┤ //│ CAPS │ 7 │ 8 │ 9 │ 0 │ │ │ │ │ │ │ &caps_word &kp N7 &kp N8 &kp N9 &kp N0 &trans &trans &trans &trans &trans diff --git a/app/boards/shields/crbn/crbn.keymap b/app/boards/shields/crbn/crbn.keymap index f963ba84434..08eab59ca1b 100644 --- a/app/boards/shields/crbn/crbn.keymap +++ b/app/boards/shields/crbn/crbn.keymap @@ -17,12 +17,12 @@ // | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC | // | ESC | A | S | D | F | G | H | J | K | L | ; | ' | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | RET | - // | | LCTL | LALT | LGUI | LOWR | SPACE | RAIS | LARW | DARW | UARW | RARW | + // | | LCTRL | LALT | LGUI | LOWR | SPACE | RAIS | LEFT | DOWN | UP | RIGHT | bindings = < &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSPC &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp SLASH &kp RET - &trans &kp LCTL &kp LALT &kp LGUI &mo 1 &kp SPACE &trans &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT + &trans &kp LCTRL &kp LALT &kp LGUI &mo 1 &kp SPACE &trans &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT >; sensor-bindings = <&inc_dec_kp PG_UP PG_DN>; diff --git a/app/boards/shields/fourier/fourier.keymap b/app/boards/shields/fourier/fourier.keymap index f0912bf1f73..819ddf61e34 100644 --- a/app/boards/shields/fourier/fourier.keymap +++ b/app/boards/shields/fourier/fourier.keymap @@ -14,7 +14,7 @@ compatible = "zmk,keymap"; // ---------------------------------------------- ---------------------------------------------- -// | ESC | Q | W | E | R | T | | Y | U | I | O | P | | BKSP | +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | | BSPC | // | TAB | A | S | D | F | G | | H | J | K | L | ' | ENTER | // | SHIFT | Z | X | C | V | B | | N | M | , | . | / | RSHFT | // | LCTRL | LALT| LGUI | SPACE | | SPACE/L1 | L2 | RGUI | RALT |RCTRL| diff --git a/app/boards/shields/hummingbird/hummingbird.keymap b/app/boards/shields/hummingbird/hummingbird.keymap index c96071f6c25..31e33254eba 100644 --- a/app/boards/shields/hummingbird/hummingbird.keymap +++ b/app/boards/shields/hummingbird/hummingbird.keymap @@ -58,17 +58,17 @@ default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp H &kp U &kp I &kp O &kp P - &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp N &hm RSHFT J &hm RCTRL K &hm LALT L &hm RGUI QUOT + &hm LGUI A &hm LALT S &hm LCTRL D &hm LSHFT F &kp G &kp N &hm RSHFT J &hm RCTRL K &hm LALT L &hm RGUI SQT &kp X &kp C &kp V &kp M &kp COMMA &kp DOT - < NAV_L TAB &kp RET < NUM_L SPACE < SYM_L BKSP + < NAV_L TAB &kp RET < NUM_L SPACE < SYM_L BSPC >; }; nav_layer { display-name = "Nav"; bindings = < - &trans &trans &trans &trans &trans &trans &kp HOME &kp UARW &kp PG_UP &trans - &trans &trans &trans &trans &trans &trans &kp LARW &kp DARW &kp RARW &trans + &trans &trans &trans &trans &trans &trans &kp HOME &kp UP &kp PG_UP &trans + &trans &trans &trans &trans &trans &trans &kp LEFT &kp DOWN &kp RIGHT &trans &trans &trans &trans &kp END &trans &kp PG_DN &trans &trans &kp ESC &kp DEL >; diff --git a/app/boards/shields/hummingbird/hummingbird.overlay b/app/boards/shields/hummingbird/hummingbird.overlay index 2474d089dff..b077804e5b3 100644 --- a/app/boards/shields/hummingbird/hummingbird.overlay +++ b/app/boards/shields/hummingbird/hummingbird.overlay @@ -6,12 +6,11 @@ #include +#include + / { chosen { zmk,kscan = &kscan0; - zmk,matrix-transform = &default_transform; - /delete-property/ zephyr,console; - /delete-property/ zephyr,shell-uart; }; default_transform: keymap_transform_0 { @@ -51,7 +50,45 @@ ; }; -}; -&xiao_spi { status = "disabled"; }; -&xiao_serial { status = "disabled"; }; + layout_0: layout_0 { + compatible = "zmk,physical-layout"; + display-name = "Default"; + + transform = <&default_transform>; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 75 0 0 0> + , <&key_physical_attrs 100 100 100 25 0 0 0> + , <&key_physical_attrs 100 100 200 0 0 0 0> + , <&key_physical_attrs 100 100 300 25 0 0 0> + , <&key_physical_attrs 100 100 400 75 0 0 0> + , <&key_physical_attrs 100 100 600 75 0 0 0> + , <&key_physical_attrs 100 100 700 25 0 0 0> + , <&key_physical_attrs 100 100 800 0 0 0 0> + , <&key_physical_attrs 100 100 900 25 0 0 0> + , <&key_physical_attrs 100 100 1000 75 0 0 0> + , <&key_physical_attrs 100 100 0 175 0 0 0> + , <&key_physical_attrs 100 100 100 125 0 0 0> + , <&key_physical_attrs 100 100 200 100 0 0 0> + , <&key_physical_attrs 100 100 300 125 0 0 0> + , <&key_physical_attrs 100 100 400 175 0 0 0> + , <&key_physical_attrs 100 100 600 175 0 0 0> + , <&key_physical_attrs 100 100 700 125 0 0 0> + , <&key_physical_attrs 100 100 800 100 0 0 0> + , <&key_physical_attrs 100 100 900 125 0 0 0> + , <&key_physical_attrs 100 100 1000 175 0 0 0> + , <&key_physical_attrs 100 100 100 225 0 0 0> + , <&key_physical_attrs 100 100 200 200 0 0 0> + , <&key_physical_attrs 100 100 300 225 0 0 0> + , <&key_physical_attrs 100 100 700 225 0 0 0> + , <&key_physical_attrs 100 100 800 200 0 0 0> + , <&key_physical_attrs 100 100 900 225 0 0 0> + , <&key_physical_attrs 100 100 325 350 0 0 0> + , <&key_physical_attrs 100 100 425 375 0 0 0> + , <&key_physical_attrs 100 100 575 375 0 0 0> + , <&key_physical_attrs 100 100 675 350 0 0 0> + ; + }; + +}; diff --git a/app/boards/shields/jian/jian.keymap b/app/boards/shields/jian/jian.keymap index bfd2918cc74..b0235bd7ec3 100644 --- a/app/boards/shields/jian/jian.keymap +++ b/app/boards/shields/jian/jian.keymap @@ -25,7 +25,7 @@ // | GUI | ~ | Q | W | E | R | T | | Y | U | I | O | P | [ | GUI/] | // | CTRL | A | S | D | F | G | | H | J | K | L | ; |CTRL/'| // | LALT | Z | X | C | V | B | | N | M | , | . | / | RALT | -// | RSE | SPC | LWR | | LWR | BKSP | RSE | +// | RSE | SPC | LWR | | LWR | BSPC | RSE | bindings = < &kp LWIN &kp GRAVE &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &mt RWIN RBKT &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &mt RCTRL SQT diff --git a/app/boards/shields/jorne/jorne.keymap b/app/boards/shields/jorne/jorne.keymap index 2a109fe8ef1..56ffe617916 100644 --- a/app/boards/shields/jorne/jorne.keymap +++ b/app/boards/shields/jorne/jorne.keymap @@ -22,7 +22,7 @@ // | GUI | ~ | Q | W | E | R | T | | Y | U | I | O | P | [ | GUI/] | // | CTRL | A | S | D | F | G | | H | J | K | L | ; |CTRL/'| // | LALT | Z | X | C | V | B | | N | M | , | . | / | RALT | -// | RSE | SPC | LWR | | LWR | BKSP | RSE | +// | RSE | SPC | LWR | | LWR | BSPC | RSE | bindings = < &kp LWIN &kp GRAVE &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &mt RWIN RBKT &kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &mt RCTRL SQT diff --git a/app/boards/shields/leeloo/leeloo.keymap b/app/boards/shields/leeloo/leeloo.keymap index 91e4f333448..79a1ce0e9a0 100644 --- a/app/boards/shields/leeloo/leeloo.keymap +++ b/app/boards/shields/leeloo/leeloo.keymap @@ -28,7 +28,7 @@ display-name = " QWERTY"; bindings = < &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSLH -&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp GRAV +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp GRAVE &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LGUI &kp LGUI &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL @@ -64,4 +64,4 @@ }; }; -}; \ No newline at end of file +}; diff --git a/app/boards/shields/leeloo/leeloo_rev2.keymap b/app/boards/shields/leeloo/leeloo_rev2.keymap index a2eda050f2b..59d7286654d 100644 --- a/app/boards/shields/leeloo/leeloo_rev2.keymap +++ b/app/boards/shields/leeloo/leeloo_rev2.keymap @@ -40,7 +40,7 @@ display-name = " QWERTY"; bindings = < &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSLH -&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp GRAV +&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp GRAVE &kp CAPS &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp LGUI &kp RGUI &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL @@ -76,4 +76,4 @@ RGBOFF RGBEFF RGBHUD RGBSAD RGBBRD &trans &trans &tr }; }; -}; \ No newline at end of file +}; diff --git a/app/boards/shields/leeloo_micro/leeloo_micro.keymap b/app/boards/shields/leeloo_micro/leeloo_micro.keymap index 2317015c106..e6821991e38 100644 --- a/app/boards/shields/leeloo_micro/leeloo_micro.keymap +++ b/app/boards/shields/leeloo_micro/leeloo_micro.keymap @@ -77,7 +77,7 @@ bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI -&mt LSFT Z &kp X &kp C &kp V &kp B &mo QC_N &kp RGUI &kp N &kp M &kp COMMA &kp DOT &mt RSFT FSLH +&mt LSHFT Z &kp X &kp C &kp V &kp B &mo QC_N &kp RGUI &kp N &kp M &kp COMMA &kp DOT &mt RSHFT FSLH &kp LALT &kp LCTRL < 1 RET < 2 MINUS < 2 EQUAL < 1 SPACE &kp BSPC &mo QC_B >; @@ -88,7 +88,7 @@ display-name = " Lower"; bindings = < &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 -&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp QUOT +&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp SQT &kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp RSHFT &trans &trans &trans &trans &trans &trans &trans &trans >; @@ -101,7 +101,7 @@ bindings = < &kp TAB &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &kp BSLH &kp CAPS &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &kp GRAVE -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &mt RSFT TILDE +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &mt RSHFT TILDE &trans &trans &trans &trans &trans &trans &kp DEL &trans >; diff --git a/app/boards/shields/m60/m60.keymap b/app/boards/shields/m60/m60.keymap index 8daa6b7cd7a..fd187da5716 100644 --- a/app/boards/shields/m60/m60.keymap +++ b/app/boards/shields/m60/m60.keymap @@ -14,7 +14,7 @@ default_layer { // ------------------------------------------------------------------------------------------ -// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BSPC | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | diff --git a/app/boards/shields/microdox/microdox.keymap b/app/boards/shields/microdox/microdox.keymap index 34b2984bca8..f13f58f44f8 100644 --- a/app/boards/shields/microdox/microdox.keymap +++ b/app/boards/shields/microdox/microdox.keymap @@ -28,7 +28,7 @@ nav_layer { // ----------------------------------------------------------------------------------------- // |BTCLR| | ESC | ~ | | | TAB | HOME | UP | END | DEL | -// | BT1 | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BKSP | +// | BT1 | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BSPC | // | BT2 | | | | | | \ | ENT | | | | // | | | | | | | | bindings = < diff --git a/app/boards/shields/minivan_studio_tester/Kconfig.defconfig b/app/boards/shields/minivan_studio_tester/Kconfig.defconfig new file mode 100644 index 00000000000..d6dd3d5077f --- /dev/null +++ b/app/boards/shields/minivan_studio_tester/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_MINIVAN_STUDIO_TESTER + +config ZMK_KEYBOARD_NAME + default "MiniVan Tester" + +endif diff --git a/app/boards/shields/minivan_studio_tester/Kconfig.shield b/app/boards/shields/minivan_studio_tester/Kconfig.shield new file mode 100644 index 00000000000..787d46f82ee --- /dev/null +++ b/app/boards/shields/minivan_studio_tester/Kconfig.shield @@ -0,0 +1,9 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_MINIVAN_STUDIO_TESTER + def_bool $(shields_list_contains,minivan_studio_tester) + select ZMK_STUDIO + select UART_NATIVE_POSIX_PORT_1_ENABLE + select CBPRINTF_LIBC_SUBSTS + select ZMK_STUDIO_TRANSPORT_UART diff --git a/app/boards/shields/minivan_studio_tester/minivan_studio_tester.conf b/app/boards/shields/minivan_studio_tester/minivan_studio_tester.conf new file mode 100644 index 00000000000..a771e5f7bf3 --- /dev/null +++ b/app/boards/shields/minivan_studio_tester/minivan_studio_tester.conf @@ -0,0 +1 @@ +CONFIG_ZMK_STUDIO_LOCKING=n \ No newline at end of file diff --git a/app/boards/shields/minivan_studio_tester/minivan_studio_tester.keymap b/app/boards/shields/minivan_studio_tester/minivan_studio_tester.keymap new file mode 100644 index 00000000000..a9a77260029 --- /dev/null +++ b/app/boards/shields/minivan_studio_tester/minivan_studio_tester.keymap @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define ZMK_BEHAVIORS_KEEP_ALL + +#include +#include + +#define NAV_L 1 +#define NUM_L 2 +#define MED_L 3 +#define FUN_L 4 + +/ { + keymap { + compatible = "zmk,keymap"; + + base_layer { + display-name = "Base"; + bindings = < + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BKSP + &gresc &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp RET + &kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp QUOT + &kp LGUI &kp LALT &mo NAV_L &kp LEFT_SHIFT &kp SPACE &mo NUM_L &kp LALT &kp RCTL + >; + }; + + nav_layer { + display-name = "Nav"; + bindings = < +&trans &trans &trans &trans &trans &trans &trans &kp GRAVE &kp TILDE &trans &trans &kp DEL +&trans &trans &trans &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW &trans +&trans &trans &trans &trans &trans &trans &trans &kp HOME &kp PG_DN &kp PG_UP &kp END &trans +&trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + + num_layer { + display-name = "Num"; + bindings = < +&trans &trans &kp N7 &kp N8 &kp N9 &kp RBKT &trans &trans &trans &trans &trans &trans +&trans &kp MINUS &kp N4 &kp N5 &kp N6 &kp EQUAL &trans &trans &trans &trans &trans &trans +&kp PLUS &kp N1 &kp N2 &kp N3 &kp N0 &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &kp ESC &trans &trans + >; + }; + + med_layer { + display-name = "Sym"; + bindings = < +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/minivan_studio_tester/minivan_studio_tester.overlay b/app/boards/shields/minivan_studio_tester/minivan_studio_tester.overlay new file mode 100644 index 00000000000..c1ec25d7af3 --- /dev/null +++ b/app/boards/shields/minivan_studio_tester/minivan_studio_tester.overlay @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +&kscan { + /delete-property/ exit-after; + events = <>; +}; + +&uart1 { status = "okay"; }; + +/ { + chosen { + zmk,physical-layout = &standard_layout; + zmk,studio-rpc-uart = &uart1; + }; + + standard_transform: standard_transform { + compatible = "zmk,matrix-transform"; + rows = <4>; + columns = <12>; + + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(3,5) RC(3,4) RC(3,3) RC(3,2) RC(3,1) RC(3,0) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(5,5) RC(5,4) RC(5,3) RC(5,2) RC(5,1) RC(5,0) + RC(6,0) RC(6,1) RC(6,3) RC(6,4) RC(6,5) RC(7,3) RC(7,2) RC(7,0) + >; + }; + + arrows_transform: arrows_transform { + compatible = "zmk,matrix-transform"; + rows = <4>; + columns = <12>; + + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(3,5) RC(3,4) RC(3,3) RC(3,2) RC(3,1) RC(3,0) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(5,5) RC(5,4) RC(5,3) RC(5,2) RC(5,1) RC(5,0) + RC(6,0) RC(6,1) RC(6,3) RC(6,4) RC(6,5) RC(7,3) RC(7,2) RC(7,1) RC(7,0) + >; + }; + + southpaw_transform: southpaw_transform { + compatible = "zmk,matrix-transform"; + rows = <4>; + columns = <12>; + + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(3,5) RC(3,4) RC(3,3) RC(3,2) RC(3,1) RC(3,0) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(5,5) RC(5,4) RC(5,3) RC(5,2) RC(5,1) RC(5,0) + RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) RC(7,3) RC(7,2) RC(7,0) + >; + }; + + jetvan_transform: jetvan_transform { + compatible = "zmk,matrix-transform"; + rows = <4>; + columns = <12>; + + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(1,5) RC(1,4) RC(1,3) RC(1,2) RC(1,1) RC(1,0) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(3,5) RC(3,4) RC(3,3) RC(3,2) RC(3,1) RC(3,0) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(5,5) RC(5,4) RC(5,3) RC(5,2) RC(5,1) RC(5,0) + RC(6,0) RC(6,1) RC(6,2) RC(6,4) RC(7,3) RC(7,2) RC(7,0) + >; + }; + + standard_layout: standard_layout { + compatible = "zmk,physical-layout"; + display-name = "Standard"; + + transform = <&standard_transform>; + kscan = <&kscan>; + + keys + = <&key_physical_attrs 100 100 000 000 0 0 0> + , <&key_physical_attrs 100 100 100 000 0 0 0> + , <&key_physical_attrs 100 100 200 000 0 0 0> + , <&key_physical_attrs 100 100 300 000 0 0 0> + , <&key_physical_attrs 100 100 400 000 0 0 0> + , <&key_physical_attrs 100 100 500 000 0 0 0> + , <&key_physical_attrs 100 100 600 000 0 0 0> + , <&key_physical_attrs 100 100 700 000 0 0 0> + , <&key_physical_attrs 100 100 800 000 0 0 0> + , <&key_physical_attrs 100 100 900 000 0 0 0> + , <&key_physical_attrs 100 100 1000 000 0 0 0> + , <&key_physical_attrs 175 100 1100 000 0 0 0> + + , <&key_physical_attrs 125 100 000 100 0 0 0> + , <&key_physical_attrs 100 100 125 100 0 0 0> + , <&key_physical_attrs 100 100 225 100 0 0 0> + , <&key_physical_attrs 100 100 325 100 0 0 0> + , <&key_physical_attrs 100 100 425 100 0 0 0> + , <&key_physical_attrs 100 100 525 100 0 0 0> + , <&key_physical_attrs 100 100 625 100 0 0 0> + , <&key_physical_attrs 100 100 725 100 0 0 0> + , <&key_physical_attrs 100 100 825 100 0 0 0> + , <&key_physical_attrs 100 100 925 100 0 0 0> + , <&key_physical_attrs 100 100 1025 100 0 0 0> + , <&key_physical_attrs 150 100 1125 100 0 0 0> + + , <&key_physical_attrs 175 100 000 200 0 0 0> + , <&key_physical_attrs 100 100 175 200 0 0 0> + , <&key_physical_attrs 100 100 275 200 0 0 0> + , <&key_physical_attrs 100 100 375 200 0 0 0> + , <&key_physical_attrs 100 100 475 200 0 0 0> + , <&key_physical_attrs 100 100 575 200 0 0 0> + , <&key_physical_attrs 100 100 675 200 0 0 0> + , <&key_physical_attrs 100 100 775 200 0 0 0> + , <&key_physical_attrs 100 100 875 200 0 0 0> + , <&key_physical_attrs 100 100 975 200 0 0 0> + , <&key_physical_attrs 100 100 1075 200 0 0 0> + , <&key_physical_attrs 100 100 1175 200 0 0 0> + + , <&key_physical_attrs 125 100 000 300 0 0 0> + , <&key_physical_attrs 150 100 125 300 0 0 0> + , <&key_physical_attrs 125 100 275 300 0 0 0> + , <&key_physical_attrs 225 100 400 300 0 0 0> + , <&key_physical_attrs 200 100 625 300 0 0 0> + , <&key_physical_attrs 125 100 825 300 0 0 0> + , <&key_physical_attrs 150 100 950 300 0 0 0> + , <&key_physical_attrs 175 100 1100 300 0 0 0> + ; + }; + + southpaw_layout: southpaw_layout { + compatible = "zmk,physical-layout"; + display-name = "Southpaw"; + + transform = <&southpaw_transform>; + kscan = <&kscan>; + + keys + = <&key_physical_attrs 100 100 000 000 0 0 0> + , <&key_physical_attrs 100 100 100 000 0 0 0> + , <&key_physical_attrs 100 100 200 000 0 0 0> + , <&key_physical_attrs 100 100 300 000 0 0 0> + , <&key_physical_attrs 100 100 400 000 0 0 0> + , <&key_physical_attrs 100 100 500 000 0 0 0> + , <&key_physical_attrs 100 100 600 000 0 0 0> + , <&key_physical_attrs 100 100 700 000 0 0 0> + , <&key_physical_attrs 100 100 800 000 0 0 0> + , <&key_physical_attrs 100 100 900 000 0 0 0> + , <&key_physical_attrs 100 100 1000 000 0 0 0> + , <&key_physical_attrs 175 100 1100 000 0 0 0> + + , <&key_physical_attrs 125 100 000 100 0 0 0> + , <&key_physical_attrs 100 100 125 100 0 0 0> + , <&key_physical_attrs 100 100 225 100 0 0 0> + , <&key_physical_attrs 100 100 325 100 0 0 0> + , <&key_physical_attrs 100 100 425 100 0 0 0> + , <&key_physical_attrs 100 100 525 100 0 0 0> + , <&key_physical_attrs 100 100 625 100 0 0 0> + , <&key_physical_attrs 100 100 725 100 0 0 0> + , <&key_physical_attrs 100 100 825 100 0 0 0> + , <&key_physical_attrs 100 100 925 100 0 0 0> + , <&key_physical_attrs 100 100 1025 100 0 0 0> + , <&key_physical_attrs 150 100 1125 100 0 0 0> + + , <&key_physical_attrs 175 100 000 200 0 0 0> + , <&key_physical_attrs 100 100 175 200 0 0 0> + , <&key_physical_attrs 100 100 275 200 0 0 0> + , <&key_physical_attrs 100 100 375 200 0 0 0> + , <&key_physical_attrs 100 100 475 200 0 0 0> + , <&key_physical_attrs 100 100 575 200 0 0 0> + , <&key_physical_attrs 100 100 675 200 0 0 0> + , <&key_physical_attrs 100 100 775 200 0 0 0> + , <&key_physical_attrs 100 100 875 200 0 0 0> + , <&key_physical_attrs 100 100 975 200 0 0 0> + , <&key_physical_attrs 100 100 1075 200 0 0 0> + , <&key_physical_attrs 100 100 1175 200 0 0 0> + + , <&key_physical_attrs 100 100 000 300 0 0 0> + , <&key_physical_attrs 100 100 100 300 0 0 0> + , <&key_physical_attrs 100 100 200 300 0 0 0> + , <&key_physical_attrs 100 100 300 300 0 0 0> + , <&key_physical_attrs 225 100 400 300 0 0 0> + , <&key_physical_attrs 200 100 625 300 0 0 0> + , <&key_physical_attrs 125 100 825 300 0 0 0> + , <&key_physical_attrs 150 100 950 300 0 0 0> + , <&key_physical_attrs 175 100 1100 300 0 0 0> + ; + }; + + arrows_layout: arrows_layout { + compatible = "zmk,physical-layout"; + display-name = "Arrows"; + + transform = <&arrows_transform>; + kscan = <&kscan>; + + keys + = <&key_physical_attrs 100 100 000 000 0 0 0> + , <&key_physical_attrs 100 100 100 000 0 0 0> + , <&key_physical_attrs 100 100 200 000 0 0 0> + , <&key_physical_attrs 100 100 300 000 0 0 0> + , <&key_physical_attrs 100 100 400 000 0 0 0> + , <&key_physical_attrs 100 100 500 000 0 0 0> + , <&key_physical_attrs 100 100 600 000 0 0 0> + , <&key_physical_attrs 100 100 700 000 0 0 0> + , <&key_physical_attrs 100 100 800 000 0 0 0> + , <&key_physical_attrs 100 100 900 000 0 0 0> + , <&key_physical_attrs 100 100 1000 000 0 0 0> + , <&key_physical_attrs 175 100 1100 000 0 0 0> + + , <&key_physical_attrs 125 100 000 100 0 0 0> + , <&key_physical_attrs 100 100 125 100 0 0 0> + , <&key_physical_attrs 100 100 225 100 0 0 0> + , <&key_physical_attrs 100 100 325 100 0 0 0> + , <&key_physical_attrs 100 100 425 100 0 0 0> + , <&key_physical_attrs 100 100 525 100 0 0 0> + , <&key_physical_attrs 100 100 625 100 0 0 0> + , <&key_physical_attrs 100 100 725 100 0 0 0> + , <&key_physical_attrs 100 100 825 100 0 0 0> + , <&key_physical_attrs 100 100 925 100 0 0 0> + , <&key_physical_attrs 100 100 1025 100 0 0 0> + , <&key_physical_attrs 150 100 1125 100 0 0 0> + + , <&key_physical_attrs 175 100 000 200 0 0 0> + , <&key_physical_attrs 100 100 175 200 0 0 0> + , <&key_physical_attrs 100 100 275 200 0 0 0> + , <&key_physical_attrs 100 100 375 200 0 0 0> + , <&key_physical_attrs 100 100 475 200 0 0 0> + , <&key_physical_attrs 100 100 575 200 0 0 0> + , <&key_physical_attrs 100 100 675 200 0 0 0> + , <&key_physical_attrs 100 100 775 200 0 0 0> + , <&key_physical_attrs 100 100 875 200 0 0 0> + , <&key_physical_attrs 100 100 975 200 0 0 0> + , <&key_physical_attrs 100 100 1075 200 0 0 0> + , <&key_physical_attrs 100 100 1175 200 0 0 0> + + , <&key_physical_attrs 125 100 000 300 0 0 0> + , <&key_physical_attrs 150 100 125 300 0 0 0> + , <&key_physical_attrs 125 100 275 300 0 0 0> + , <&key_physical_attrs 225 100 400 300 0 0 0> + , <&key_physical_attrs 200 100 625 300 0 0 0> + , <&key_physical_attrs 150 100 825 300 0 0 0> + , <&key_physical_attrs 100 100 975 300 0 0 0> + , <&key_physical_attrs 100 100 1075 300 0 0 0> + , <&key_physical_attrs 100 100 1175 300 0 0 0> + ; + }; + + jetvan_layout: jetvan_layout { + compatible = "zmk,physical-layout"; + display-name = "JetVan"; + + transform = <&jetvan_transform>; + kscan = <&kscan>; + + keys + = <&key_physical_attrs 100 100 000 000 0 0 0> + , <&key_physical_attrs 100 100 100 000 0 0 0> + , <&key_physical_attrs 100 100 200 000 0 0 0> + , <&key_physical_attrs 100 100 300 000 0 0 0> + , <&key_physical_attrs 100 100 400 000 0 0 0> + , <&key_physical_attrs 100 100 500 000 0 0 0> + , <&key_physical_attrs 100 100 600 000 0 0 0> + , <&key_physical_attrs 100 100 700 000 0 0 0> + , <&key_physical_attrs 100 100 800 000 0 0 0> + , <&key_physical_attrs 100 100 900 000 0 0 0> + , <&key_physical_attrs 100 100 1000 000 0 0 0> + , <&key_physical_attrs 175 100 1100 000 0 0 0> + + , <&key_physical_attrs 125 100 000 100 0 0 0> + , <&key_physical_attrs 100 100 125 100 0 0 0> + , <&key_physical_attrs 100 100 225 100 0 0 0> + , <&key_physical_attrs 100 100 325 100 0 0 0> + , <&key_physical_attrs 100 100 425 100 0 0 0> + , <&key_physical_attrs 100 100 525 100 0 0 0> + , <&key_physical_attrs 100 100 625 100 0 0 0> + , <&key_physical_attrs 100 100 725 100 0 0 0> + , <&key_physical_attrs 100 100 825 100 0 0 0> + , <&key_physical_attrs 100 100 925 100 0 0 0> + , <&key_physical_attrs 100 100 1025 100 0 0 0> + , <&key_physical_attrs 150 100 1125 100 0 0 0> + + , <&key_physical_attrs 175 100 000 200 0 0 0> + , <&key_physical_attrs 100 100 175 200 0 0 0> + , <&key_physical_attrs 100 100 275 200 0 0 0> + , <&key_physical_attrs 100 100 375 200 0 0 0> + , <&key_physical_attrs 100 100 475 200 0 0 0> + , <&key_physical_attrs 100 100 575 200 0 0 0> + , <&key_physical_attrs 100 100 675 200 0 0 0> + , <&key_physical_attrs 100 100 775 200 0 0 0> + , <&key_physical_attrs 100 100 875 200 0 0 0> + , <&key_physical_attrs 100 100 975 200 0 0 0> + , <&key_physical_attrs 100 100 1075 200 0 0 0> + , <&key_physical_attrs 100 100 1175 200 0 0 0> + + , <&key_physical_attrs 125 100 000 300 0 0 0> + , <&key_physical_attrs 100 100 125 300 0 0 0> + , <&key_physical_attrs 125 100 225 300 0 0 0> + , <&key_physical_attrs 625 100 350 300 0 0 0> + , <&key_physical_attrs 100 100 975 300 0 0 0> + , <&key_physical_attrs 100 100 1075 300 0 0 0> + , <&key_physical_attrs 100 100 1175 300 0 0 0> + ; + }; + + pos_map { + compatible = "zmk,physical-layout-position-map"; + std { + physical-layout = <&standard_layout>; + positions + = < 36 37 38 39 40 41 42 43 44 >; + }; + + arrows { + physical-layout = <&arrows_layout>; + positions + = < 36 37 38 39 40 42 43 44 41>; + }; + + southpaw { + physical-layout = <&southpaw_layout>; + positions + = < 36 37 39 40 41 42 43 44 38>; + }; + + jetvan { + physical-layout = <&jetvan_layout>; + positions + = < 36 37 38 43 39 40 41 42 44>; + }; + + }; +}; diff --git a/app/boards/shields/naked60/naked60.keymap b/app/boards/shields/naked60/naked60.keymap index 1c212cd4544..4f02d9a10cf 100644 --- a/app/boards/shields/naked60/naked60.keymap +++ b/app/boards/shields/naked60/naked60.keymap @@ -20,7 +20,7 @@ // | TAB | Q | W | E | R | T |-------|-------| Y | U | I | O | P | \ | // | SHIFT | A | S | D | F | G |-------|-------| H | J | K | L | ; | ' | // | CTRL | Z | X | C | V | B |-------|-------| N | M | , | . | / | ENTER | - // |-------|ADJUST| LCTL | LALT | LGUI | LOWR | SPACE | SPACE | RAIS | LARW | DARW | UARW | RARW |-------| + // |-------|ADJUST| LCTL | LALT | LGUI | LOWR | SPACE | SPACE | RAIS | LEFT | DOWN | UARW | RARW |-------| bindings = < diff --git a/app/boards/shields/posix_pro_micro/Kconfig.defconfig b/app/boards/shields/posix_pro_micro/Kconfig.defconfig new file mode 100644 index 00000000000..505fe2dd372 --- /dev/null +++ b/app/boards/shields/posix_pro_micro/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_POSIX_PRO_MICRO + +config ZMK_STUDIO + select UART_NATIVE_POSIX_PORT_1_ENABLE + +endif \ No newline at end of file diff --git a/app/boards/shields/posix_pro_micro/Kconfig.shield b/app/boards/shields/posix_pro_micro/Kconfig.shield new file mode 100644 index 00000000000..777043149d4 --- /dev/null +++ b/app/boards/shields/posix_pro_micro/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_POSIX_PRO_MICRO + def_bool $(shields_list_contains,posix_pro_micro) diff --git a/app/boards/shields/posix_pro_micro/posix_pro_micro.overlay b/app/boards/shields/posix_pro_micro/posix_pro_micro.overlay new file mode 100644 index 00000000000..e3677f53d87 --- /dev/null +++ b/app/boards/shields/posix_pro_micro/posix_pro_micro.overlay @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + + /delete-node/ &kscan; + + &uart1 { status = "okay"; }; + + / { + chosen { + zmk,studio-rpc-uart = &uart1; + }; + + pro_micro: connector { + compatible = "arduino-pro-micro"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 0 0> /* D0 */ + , <1 0 &gpio0 1 0> /* D1 */ + , <2 0 &gpio0 2 0> /* D2 */ + , <3 0 &gpio0 3 0> /* D3 */ + , <4 0 &gpio0 4 0> /* D4/A6 */ + , <5 0 &gpio0 5 0> /* D5 */ + , <6 0 &gpio0 6 0> /* D6/A7 */ + , <7 0 &gpio0 7 0> /* D7 */ + , <8 0 &gpio0 8 0> /* D8/A8 */ + , <9 0 &gpio0 9 0> /* D9/A9 */ + , <10 0 &gpio0 10 0> /* D10/A10 */ + , <16 0 &gpio0 11 0> /* D16 */ + , <14 0 &gpio0 12 0> /* D14 */ + , <15 0 &gpio0 13 0> /* D15 */ + , <18 0 &gpio0 14 0> /* D18/A0 */ + , <19 0 &gpio0 15 0> /* D19/A1 */ + , <20 0 &gpio0 16 0> /* D20/A2 */ + , <21 0 &gpio0 17 0> /* D21/A3 */ + ; + }; +}; + +pro_micro_i2c: &i2c0 {}; +pro_micro_spi: &spi0 {}; +pro_micro_serial: &uart0 {}; diff --git a/app/boards/shields/posix_seeed_xiao/Kconfig.defconfig b/app/boards/shields/posix_seeed_xiao/Kconfig.defconfig new file mode 100644 index 00000000000..fa45d9d36e1 --- /dev/null +++ b/app/boards/shields/posix_seeed_xiao/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_POSIX_SEEED_XIAO + +config ZMK_STUDIO + select UART_NATIVE_POSIX_PORT_1_ENABLE + +endif \ No newline at end of file diff --git a/app/boards/shields/posix_seeed_xiao/Kconfig.shield b/app/boards/shields/posix_seeed_xiao/Kconfig.shield new file mode 100644 index 00000000000..85fca2060ae --- /dev/null +++ b/app/boards/shields/posix_seeed_xiao/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2024 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_POSIX_SEEED_XIAO + def_bool $(shields_list_contains,posix_seeed_xiao) diff --git a/app/boards/shields/posix_seeed_xiao/posix_seeed_xiao.overlay b/app/boards/shields/posix_seeed_xiao/posix_seeed_xiao.overlay new file mode 100644 index 00000000000..0e58539fc5f --- /dev/null +++ b/app/boards/shields/posix_seeed_xiao/posix_seeed_xiao.overlay @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + /delete-node/ &kscan; + + &uart1 { status = "okay"; }; + + / { + chosen { + zmk,studio-rpc-uart = &uart1; + }; + + xiao_d: connector { + compatible = "seeed,xiao-gpio"; + #gpio-cells = <2>; + gpio-map-mask = <0xffffffff 0xffffffc0>; + gpio-map-pass-thru = <0 0x3f>; + gpio-map + = <0 0 &gpio0 0 0> /* D0 */ + , <1 0 &gpio0 1 0> /* D1 */ + , <2 0 &gpio0 2 0> /* D2 */ + , <3 0 &gpio0 3 0> /* D3 */ + , <4 0 &gpio0 4 0> /* D4 */ + , <5 0 &gpio0 5 0> /* D5 */ + , <6 0 &gpio0 6 0> /* D6 */ + , <7 0 &gpio0 7 0> /* D7 */ + , <8 0 &gpio0 8 0> /* D8 */ + , <9 0 &gpio0 9 0> /* D9 */ + , <10 0 &gpio0 10 0> /* D10 */ + ; + }; +}; + +xiao_i2c: &i2c0 {}; +xiao_spi: &spi0 {}; +xiao_serial: &uart0 {}; \ No newline at end of file diff --git a/app/boards/shields/redox/redox.keymap b/app/boards/shields/redox/redox.keymap index c88f703beab..ea4c09f9f4b 100644 --- a/app/boards/shields/redox/redox.keymap +++ b/app/boards/shields/redox/redox.keymap @@ -16,7 +16,7 @@ default_layer { // -------------------------------------------------------------------------------------------------------------------------------- -// | ESC | 1 | 2 | 3 | 4 | 5 | --- | 6 | 7 | 8 | 9 | 0 | BKSP | +// | ESC | 1 | 2 | 3 | 4 | 5 | --- | 6 | 7 | 8 | 9 | 0 | BSPC | // | TAB | Q | W | E | R | T | ( | --- | ) | Y | U | I | O | P | - | // | CTRL | A | S | D | F | G | [ | --- | ] | H | J | K | L | ; | ' | // | SHIFT | Z | X | C | V | B | PG_UP | PG_DOWN | --- | HOME | END | N | M | , | . | / | SHFT(RET) | diff --git a/app/boards/shields/reviung41/reviung41.keymap b/app/boards/shields/reviung41/reviung41.keymap index 12f15ad4d17..618052b2999 100644 --- a/app/boards/shields/reviung41/reviung41.keymap +++ b/app/boards/shields/reviung41/reviung41.keymap @@ -15,7 +15,7 @@ default_layer { // ------------------------------------------------------------------------------------- -// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | // | SHFT | Z | X | C | V | B | | N | M | , | . | / | SHFT(RET) | // | ALT | LWR | SPC | RSE | ALT | @@ -46,7 +46,7 @@ // | | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL | // | | - | = | [ | ] | \ | | F1 | F2 | F3 | F4 | F5 | F6 | // | | ESC | GUI | ALT | CAPS| " | | F7 | F8 | F9 | F10 | F11 | F12 | -// | | ADJ | BKSP | | | +// | | ADJ | BSPC | | | bindings = < &trans &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp DEL &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 diff --git a/app/boards/shields/reviung53/reviung53.keymap b/app/boards/shields/reviung53/reviung53.keymap index d00ca6b975b..c3b3999487b 100644 --- a/app/boards/shields/reviung53/reviung53.keymap +++ b/app/boards/shields/reviung53/reviung53.keymap @@ -24,7 +24,7 @@ default_layer { // ---------------------------------------------------------------------------------------- // | | | ESC | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | DEL | -// | TAB | Q | W | E | R | T | Y | U | I | O | P | BKSP | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | BSPC | // | CAPS | A | S | D | F | G | H | J | K | L | ; | RET | // | SHFT | Z | X | C | V | B | N | M | , | . | SHFT(/) | // | CTRL | GUI | ALT | LOWER(SPACE) | RAISE(SPACE)| ALT | GUI | CTRL(\) | diff --git a/app/boards/shields/sofle/sofle.dtsi b/app/boards/shields/sofle/sofle.dtsi index ef89e4a5922..9527f26bc7e 100644 --- a/app/boards/shields/sofle/sofle.dtsi +++ b/app/boards/shields/sofle/sofle.dtsi @@ -5,12 +5,16 @@ */ #include +#include + +&josefadamcik_sofle_layout { + transform = <&default_transform>; +}; / { chosen { zephyr,display = &oled; zmk,kscan = &kscan0; - zmk,matrix-transform = &default_transform; }; default_transform: keymap_transform_0 { diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi index 56833b629c6..d63cdf21406 100644 --- a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.dtsi @@ -6,11 +6,20 @@ #include +#include + +&foostan_corne_6col_layout { + transform = <&default_transform>; +}; + +&foostan_corne_5col_layout { + transform = <&five_column_transform>; +}; + / { chosen { zephyr,display = &oled; - zmk,matrix-transform = &default_transform; }; default_transform: keymap_transform_0 { diff --git a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap index 01350bd5b51..ea4c2e8997e 100644 --- a/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap +++ b/app/boards/shields/splitkb_aurora_corne/splitkb_aurora_corne.keymap @@ -14,7 +14,7 @@ default_layer { // ----------------------------------------------------------------------------------------- -// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BSPC | // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | // | SHFT | Z | X | C | V | B | | N | M | , | . | / | ESC | // | GUI | LWR | SPC | | ENT | RSE | ALT | @@ -27,7 +27,7 @@ }; lower_layer { // ----------------------------------------------------------------------------------------- -// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | TAB | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BSPC | // | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | // | SHFT | | | | | | | | | | | | | // | GUI | | SPC | | ENT | | ALT | @@ -41,7 +41,7 @@ raise_layer { // ----------------------------------------------------------------------------------------- -// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | TAB | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BSPC | // | CTRL | | | | | | | - | = | [ | ] | \ | ` | // | SHFT | | | | | | | _ | + | { | } | "|" | ~ | // | GUI | | SPC | | ENT | | ALT | diff --git a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi index 2586b0c024d..e360528f340 100644 --- a/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi +++ b/app/boards/shields/splitkb_aurora_sofle/splitkb_aurora_sofle.dtsi @@ -6,11 +6,16 @@ #include +#include + +&josefadamcik_sofle_layout { + transform = <&default_transform>; +}; + / { chosen { zephyr,display = &oled; - zmk,matrix-transform = &default_transform; }; default_transform: keymap_transform_0 { diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi index 883636debb4..4e1a0a97df6 100644 --- a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.dtsi @@ -6,11 +6,15 @@ #include -/ { +#include + +&cuddlykeyboards_ferris_layout { + transform = <&default_transform>; +}; +/ { chosen { zephyr,display = &oled; - zmk,matrix-transform = &default_transform; }; default_transform: keymap_transform_0 { diff --git a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap index 9198a5572f0..891a36b6dac 100644 --- a/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap +++ b/app/boards/shields/splitkb_aurora_sweep/splitkb_aurora_sweep.keymap @@ -65,16 +65,16 @@ default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp QUOT - &mt LSFT Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &mt LSFT RET - &mo 1 &kp LCTL &kp SPC &mo 2 + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SQT + &mt LSHFT Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &mt LSHFT RET + &mo 1 &kp LCTRL &kp SPACE &mo 2 >; }; left_layer { bindings = < - &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 - &kp TAB &kp LC(S) &kp DQT &kp PIPE2 &kp HASH &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp DEL + &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 + &kp TAB &kp LC(S) &kp DQT &kp PIPE2 &kp HASH &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp DEL &kp ESC &kp TILDE &kp NON_US_BSLH &kp NON_US_HASH &kp TILDE2 &kp MINUS &kp GRAVE &kp LBKT &kp RBKT &kp DEL &mo 1 &kp LGUI &kp RGUI &mo 2 >; @@ -82,16 +82,16 @@ right_layer { bindings = < - &kp BANG &kp ATSN &kp HASH &kp DLLR &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN - &kp HASH &kp QMARK &kp FSLH &kp COLN &kp SCLN &kp MINUS &kp KP_EQUAL &kp LBRC &kp RBRC &kp BKSP - &kp LSFT &kp KPLS &kp LBKT &kp RBKT &kp BSLH &kp UNDER &kp LEFT &kp DOWN &kp UP &kp RIGHT - &mo 3 &kp LCTL &kp SPC &mo 2 + &kp EXCL &kp AT &kp HASH &kp DLLR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR + &kp HASH &kp QMARK &kp FSLH &kp COLON &kp SEMI &kp MINUS &kp KP_EQUAL &kp LBRC &kp RBRC &kp BSPC + &kp LSHFT &kp KP_PLUS &kp LBKT &kp RBKT &kp BSLH &kp UNDER &kp LEFT &kp DOWN &kp UP &kp RIGHT + &mo 3 &kp LCTRL &kp SPACE &mo 2 >; }; tri_layer { bindings = < - &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &trans &trans &trans &trans &trans + &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &trans &trans &trans &trans &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &trans &kp PG_UP &kp K_VOL_UP &kp K_MUTE &trans &bt BT_CLR &bt BT_NXT &bt BT_PRV &kp F6 &kp F7 &trans &kp PG_DN &kp K_VOL_DN &trans &trans &trans &trans &trans &trans diff --git a/app/boards/shields/splitreus62/splitreus62.keymap b/app/boards/shields/splitreus62/splitreus62.keymap index c7bdb4439aa..096660094ae 100644 --- a/app/boards/shields/splitreus62/splitreus62.keymap +++ b/app/boards/shields/splitreus62/splitreus62.keymap @@ -18,7 +18,7 @@ // | TAB | Q | W | E | R | T | | Y | U | I | O | P | \ | // | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | // | SHIFT | Z | X | C | V | B | | N | M | , | . | / | SHIFT | -// | LCTL | LGUI | LALT | GRAV | | EQL | DEL | BKSP| | RET | SPC | LBKT | RBKT | LBKT | HOME | END | +// | LCTL | LGUI | LALT | GRAV | | EQL | DEL | BSPC| | RET | SPC | LBKT | RBKT | LBKT | HOME | END | bindings = < &kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH diff --git a/app/boards/shields/tidbit/README.md b/app/boards/shields/tidbit/README.md index c68d38b9f17..b5500e12083 100644 --- a/app/boards/shields/tidbit/README.md +++ b/app/boards/shields/tidbit/README.md @@ -1,41 +1,6 @@ -# Building ZMK for the Tidbit +# TIDBIT Compatibility Notes -Some general notes/commands for building standard tidbit layouts from the assembly documentation. - -## Standard "Non Dense" Build - -``` -west build -p -d build/tidbit/default --board nice_nano -- -DSHIELD=tidbit -``` - -## Dense "19 keys" Build - -``` -west build -p -d build/tidbit/19_key --board nice_nano -- -DSHIELD=tidbit_19key -``` - -## LED Notes - -If you built your tidbit without the LEDs _and_ are using a nice!nano board, you'll need to change the following in your local tidbit config or add them to the end of the file. - -``` -CONFIG_ZMK_RGB_UNDERGLOW=n -CONFIG_WS2812_STRIP=n -``` - -## Encoder Notes - -If you built your tidbit without encoders, you'll need to change the following in your local tidbit config or add them to the end of the file. - -``` -CONFIG_EC11=n -CONFIG_EC11_TRIGGER_GLOBAL_THREAD=n -``` - -## OLED Builds - -If using an OLED screen, you'll need to change the following in your local tidbit config or add them to the end of the file. - -``` -CONFIG_ZMK_DISPLAY=y -``` +- The top-left and top-right encoders share the same pins. Install only one, and enable/include EITHER `encoder_1` OR `encoder_1_top_row` in your keymap; not both. +- `encoder_3` cannot be used at the same time as the OLED and/or HT16K33 modules, as it is wired to the same pins. + - While the HT16K33 hardware is supported by Zephyr, functionality may not have been implemented in ZMK for it. +- `encoder_4` cannot be used at the same time as the TRRS jack, as it is wired to the same pins. diff --git a/app/boards/shields/tidbit/boards/nice_nano.conf b/app/boards/shields/tidbit/boards/nice_nano.conf deleted file mode 100644 index 14bed3d0fa3..00000000000 --- a/app/boards/shields/tidbit/boards/nice_nano.conf +++ /dev/null @@ -1,4 +0,0 @@ -# Enable underglow -CONFIG_ZMK_RGB_UNDERGLOW=y -# Use the STRIP config specific to the LEDs you're using -CONFIG_WS2812_STRIP=y \ No newline at end of file diff --git a/app/boards/shields/tidbit/boards/proton_c.conf b/app/boards/shields/tidbit/boards/proton_c.conf deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/boards/shields/tidbit/tidbit.conf b/app/boards/shields/tidbit/tidbit.conf index 2909a855b01..82bd3477eab 100644 --- a/app/boards/shields/tidbit/tidbit.conf +++ b/app/boards/shields/tidbit/tidbit.conf @@ -5,7 +5,11 @@ CONFIG_EC11=y CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y -# Enable underglow +# Uncomment to enable underglow #CONFIG_ZMK_RGB_UNDERGLOW=y # Use the STRIP config specific to the LEDs you're using #CONFIG_WS2812_STRIP=y + +# Uncomment to enable the display +# Note that an I2C OLED cannot be used at the same time as encoder 3. +#CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/tidbit/tidbit.dtsi b/app/boards/shields/tidbit/tidbit.dtsi deleted file mode 100644 index 44fc919275a..00000000000 --- a/app/boards/shields/tidbit/tidbit.dtsi +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include - -/ { - kscan0: kscan { - compatible = "zmk,kscan-gpio-matrix"; - - diode-direction = "row2col"; - - row-gpios - = <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - ; - - col-gpios - = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - ; - - }; - - default_transform: keymap_transform_0 { - compatible = "zmk,matrix-transform"; - columns = <4>; - rows = <5>; - - map = < - RC(0,1) RC(0,2) RC(0,3) - RC(1,0) RC(1,1) RC(1,2) RC(1,3) - RC(2,0) RC(2,1) RC(2,2) RC(2,3) - RC(3,0) RC(3,1) RC(3,2) RC(3,3) - RC(4,0) RC(4,1) RC(4,2) RC(4,3) - >; - }; - - encoder_1_top_row: encoder_1_top_row { - compatible = "alps,ec11"; - a-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - steps = <80>; - status = "disabled"; - }; - - encoder_1: encoder_1 { - compatible = "alps,ec11"; - a-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - steps = <80>; - status = "disabled"; - }; - - encoder_2: encoder_2 { - compatible = "alps,ec11"; - a-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - steps = <80>; - status = "disabled"; - }; - - encoder_3: encoder_3 { - compatible = "alps,ec11"; - a-gpios = <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - steps = <80>; - status = "disabled"; - }; - - encoder_4: encoder_4 { - compatible = "alps,ec11"; - a-gpios = <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - b-gpios = <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; - steps = <80>; - status = "disabled"; - }; - - chosen { - zephyr,display = &oled; - zmk,kscan = &kscan0; - zmk,matrix-transform = &default_transform; - }; -}; - -&pro_micro_i2c { - status = "okay"; - - oled: ssd1306@3c { - compatible = "solomon,ssd1306fb"; - reg = <0x3c>; - width = <128>; - height = <32>; - segment-offset = <0>; - page-offset = <0>; - display-offset = <0>; - multiplex-ratio = <31>; - segment-remap; - com-invdir; - com-sequential; - inversion-on; - prechargep = <0x22>; - }; -}; diff --git a/app/boards/shields/tidbit/tidbit.keymap b/app/boards/shields/tidbit/tidbit.keymap index f212bfe3538..2a311365198 100644 --- a/app/boards/shields/tidbit/tidbit.keymap +++ b/app/boards/shields/tidbit/tidbit.keymap @@ -6,20 +6,40 @@ #include #include -#include #include +#include + -&encoder_1_top_row { +/* Enable ONLY ONE of the &encoder_1 nodes. They are wired to the same pins.*/ +/* +&encoder_1 { + status = "okay"; +}; +&encoder_1_top_left { status = "okay"; }; +*/ -/ { - sensors: sensors { - compatible = "zmk,keymap-sensors"; - sensors = <&encoder_1_top_row>; - triggers-per-rotation = <20>; - }; +/* +&encoder_2 { + status = "okay"; +}; + +&encoder_3 { + status = "okay"; +}; +*/ + +&encoder_4 { + status = "okay"; +}; +/* Add any encoder(s) you have enabled to the sensors node, separated by spaces. */ +&sensors { + sensors = <&encoder_4>; +}; + +/ { keymap { compatible = "zmk,keymap"; @@ -27,9 +47,9 @@ bindings = < &kp KP_NUMLOCK &kp KP_ASTERISK &kp KP_MINUS &kp KP_NUMBER_7 &kp KP_NUMBER_8 &kp KP_NUMBER_9 &kp KP_PLUS - &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &none + &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &kp KP_SLASH &kp KP_NUMBER_1 &kp KP_NUMBER_2 &kp KP_NUMBER_3 < 1 KP_ENTER - &none &kp KP_NUMBER_0 &kp KP_DOT &none + &kp C_MUTE &kp KP_NUMBER_0 &kp KP_DOT &kp KP_ENTER >; sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; @@ -37,10 +57,10 @@ func_layer { bindings = < - &none &sys_reset &bootloader + &none &sys_reset &bootloader &out OUT_TOG &out OUT_USB &out OUT_BLE &none &bt BT_SEL 0 &bt BT_PRV &bt BT_NXT &bt BT_CLR - &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &tog 0 + &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &trans &kp C_MUTE &none &none &none >; diff --git a/app/boards/shields/tidbit/tidbit.overlay b/app/boards/shields/tidbit/tidbit.overlay index dc425618ca5..0f4e07b87bd 100644 --- a/app/boards/shields/tidbit/tidbit.overlay +++ b/app/boards/shields/tidbit/tidbit.overlay @@ -4,4 +4,127 @@ * SPDX-License-Identifier: MIT */ -#include "tidbit.dtsi" +#include + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "row2col"; + wakeup-source; + + row-gpios + = <&pro_micro 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + col-gpios + = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <4>; + rows = <5>; + + map = < + RC(0,1) RC(0,2) RC(0,3) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) + >; + }; + + numpad_transform: keymap_transform_1 { + compatible = "zmk,matrix-transform"; + columns = <4>; + rows = <5>; + + map = < + RC(0,1) RC(0,2) RC(0,3) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) + RC(2,0) RC(2,1) RC(2,2) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) + RC(4,0) RC(4,1) RC(4,2) + >; + }; + + encoder_1_top_row: encoder_1_top_row { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_1: encoder_1 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_2: encoder_2 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_3: encoder_3 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + encoder_4: encoder_4 { + compatible = "alps,ec11"; + a-gpios = <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + steps = <80>; + status = "disabled"; + }; + + sensors: sensors { + compatible = "zmk,keymap-sensors"; + triggers-per-rotation = <20>; + }; + + chosen { + zephyr,display = &oled; + zmk,kscan = &kscan0; + zmk,matrix-transform = &default_transform; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + inversion-on; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/tidbit/tidbit_19key.conf b/app/boards/shields/tidbit/tidbit_19key.conf deleted file mode 100644 index 2909a855b01..00000000000 --- a/app/boards/shields/tidbit/tidbit_19key.conf +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2020 The ZMK Contributors -# SPDX-License-Identifier: MIT - -# Enable Encoders -CONFIG_EC11=y -CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y - -# Enable underglow -#CONFIG_ZMK_RGB_UNDERGLOW=y -# Use the STRIP config specific to the LEDs you're using -#CONFIG_WS2812_STRIP=y diff --git a/app/boards/shields/tidbit/tidbit_19key.keymap b/app/boards/shields/tidbit/tidbit_19key.keymap deleted file mode 100644 index a2991a3f4ca..00000000000 --- a/app/boards/shields/tidbit/tidbit_19key.keymap +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include "tidbit.dtsi" -#include -#include -#include -#include - -&encoder_4 { - status = "okay"; -}; - -/ { - sensors: sensors { - compatible = "zmk,keymap-sensors"; - sensors = <&encoder_4>; - }; - - keymap { - compatible = "zmk,keymap"; - - default_layer { - bindings = < - &tog 1 &kp KP_NUMLOCK &kp KP_SLASH - &kp KP_NUMBER_7 &kp KP_NUMBER_8 &kp KP_NUMBER_9 &kp KP_ASTERISK - &kp KP_NUMBER_4 &kp KP_NUMBER_5 &kp KP_NUMBER_6 &kp KP_MINUS - &kp KP_NUMBER_1 &kp KP_NUMBER_2 &kp KP_NUMBER_3 &kp KP_PLUS - &kp C_MUTE &kp KP_NUMBER_0 &kp KP_DOT &kp KP_ENTER - >; - - sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; - }; - - func_layer { - bindings = < - &tog 0 &sys_reset &bootloader - &out OUT_TOG &out OUT_USB &out OUT_BLE &none - &bt BT_SEL 0 &bt BT_PRV &bt BT_NXT &bt BT_CLR - &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &none - &kp C_MUTE &none &none &none - >; - - sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>; - }; - }; -}; diff --git a/app/boards/shields/tidbit/tidbit_19key.overlay b/app/boards/shields/tidbit/tidbit_19key.overlay deleted file mode 100644 index dc46233ed77..00000000000 --- a/app/boards/shields/tidbit/tidbit_19key.overlay +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include "tidbit.dtsi" -#include "tidbit_19key.keymap" diff --git a/app/dts/behaviors/backlight.dtsi b/app/dts/behaviors/backlight.dtsi index dd045effed3..9b6162e1abb 100644 --- a/app/dts/behaviors/backlight.dtsi +++ b/app/dts/behaviors/backlight.dtsi @@ -4,10 +4,15 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { +#if ZMK_BEHAVIOR_OMIT(BL) + /omit-if-no-ref/ +#endif // Behavior can be invoked on peripherals, so name must be <= 8 characters. - /omit-if-no-ref/ bl: bcklight { + bl: bcklight { compatible = "zmk,behavior-backlight"; #binding-cells = <2>; display-name = "Backlight"; diff --git a/app/dts/behaviors/bluetooth.dtsi b/app/dts/behaviors/bluetooth.dtsi index bece156f8fb..29fed4ce3f4 100644 --- a/app/dts/behaviors/bluetooth.dtsi +++ b/app/dts/behaviors/bluetooth.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ bt: bluetooth { +#if ZMK_BEHAVIOR_OMIT(BT) + /omit-if-no-ref/ +#endif + bt: bluetooth { compatible = "zmk,behavior-bluetooth"; #binding-cells = <2>; display-name = "Bluetooth"; diff --git a/app/dts/behaviors/caps_word.dtsi b/app/dts/behaviors/caps_word.dtsi index 05431bd8db2..99354f4278b 100644 --- a/app/dts/behaviors/caps_word.dtsi +++ b/app/dts/behaviors/caps_word.dtsi @@ -4,11 +4,15 @@ * SPDX-License-Identifier: MIT */ +#include #include / { behaviors { - /omit-if-no-ref/ caps_word: caps_word { +#if ZMK_BEHAVIOR_OMIT(CAPS_WORD) + /omit-if-no-ref/ +#endif + caps_word: caps_word { compatible = "zmk,behavior-caps-word"; #binding-cells = <0>; continue-list = ; diff --git a/app/dts/behaviors/gresc.dtsi b/app/dts/behaviors/gresc.dtsi index 2643a383d81..e3e0935fc70 100644 --- a/app/dts/behaviors/gresc.dtsi +++ b/app/dts/behaviors/gresc.dtsi @@ -4,11 +4,16 @@ * SPDX-License-Identifier: MIT */ + +#include #include / { behaviors { - /omit-if-no-ref/ gresc: grave_escape { +#if ZMK_BEHAVIOR_OMIT(GRESC) + /omit-if-no-ref/ +#endif + gresc: grave_escape { compatible = "zmk,behavior-mod-morph"; #binding-cells = <0>; bindings = <&kp ESC>, <&kp GRAVE>; diff --git a/app/dts/behaviors/key_press.dtsi b/app/dts/behaviors/key_press.dtsi index 2435699b6ab..08adbf79ef1 100644 --- a/app/dts/behaviors/key_press.dtsi +++ b/app/dts/behaviors/key_press.dtsi @@ -4,10 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /* DEPRECATED: `cp` will be removed in the future */ - /omit-if-no-ref/ cp: kp: key_press { +#if ZMK_BEHAVIOR_OMIT(KP) + /omit-if-no-ref/ +#endif + kp: key_press { compatible = "zmk,behavior-key-press"; #binding-cells = <1>; display-name = "Key Press"; diff --git a/app/dts/behaviors/key_repeat.dtsi b/app/dts/behaviors/key_repeat.dtsi index cd5d3771dcb..d2144699ff0 100644 --- a/app/dts/behaviors/key_repeat.dtsi +++ b/app/dts/behaviors/key_repeat.dtsi @@ -4,11 +4,15 @@ * SPDX-License-Identifier: MIT */ +#include #include / { behaviors { - /omit-if-no-ref/ key_repeat: key_repeat { +#if ZMK_BEHAVIOR_OMIT(KEY_REPEAT) + /omit-if-no-ref/ +#endif + key_repeat: key_repeat { compatible = "zmk,behavior-key-repeat"; #binding-cells = <0>; usage-pages = ; diff --git a/app/dts/behaviors/key_toggle.dtsi b/app/dts/behaviors/key_toggle.dtsi index a7b66aab1af..cd43c592b07 100644 --- a/app/dts/behaviors/key_toggle.dtsi +++ b/app/dts/behaviors/key_toggle.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ kt: key_toggle { +#if ZMK_BEHAVIOR_OMIT(KT) + /omit-if-no-ref/ +#endif + kt: key_toggle { compatible = "zmk,behavior-key-toggle"; #binding-cells = <1>; display-name = "Key Toggle"; diff --git a/app/dts/behaviors/layer_tap.dtsi b/app/dts/behaviors/layer_tap.dtsi index 2858bf17bc5..9c1bea1aeac 100644 --- a/app/dts/behaviors/layer_tap.dtsi +++ b/app/dts/behaviors/layer_tap.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ lt: layer_tap { +#if ZMK_BEHAVIOR_OMIT(LT) + /omit-if-no-ref/ +#endif + lt: layer_tap { compatible = "zmk,behavior-hold-tap"; #binding-cells = <2>; flavor = "tap-preferred"; diff --git a/app/dts/behaviors/mod_tap.dtsi b/app/dts/behaviors/mod_tap.dtsi index 0b46f77e739..b5e52e664ed 100644 --- a/app/dts/behaviors/mod_tap.dtsi +++ b/app/dts/behaviors/mod_tap.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ mt: mod_tap { +#if ZMK_BEHAVIOR_OMIT(MT) + /omit-if-no-ref/ +#endif + mt: mod_tap { compatible = "zmk,behavior-hold-tap"; #binding-cells = <2>; flavor = "hold-preferred"; diff --git a/app/dts/behaviors/momentary_layer.dtsi b/app/dts/behaviors/momentary_layer.dtsi index cae08d5f101..c263ef10ddf 100644 --- a/app/dts/behaviors/momentary_layer.dtsi +++ b/app/dts/behaviors/momentary_layer.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ mo: momentary_layer { +#if ZMK_BEHAVIOR_OMIT(MO) + /omit-if-no-ref/ +#endif + mo: momentary_layer { compatible = "zmk,behavior-momentary-layer"; #binding-cells = <1>; display-name = "Momentary Layer"; diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi index 66e327e849e..fcb7666493a 100644 --- a/app/dts/behaviors/mouse_key_press.dtsi +++ b/app/dts/behaviors/mouse_key_press.dtsi @@ -1,6 +1,17 @@ +/* + * Copyright (c) 2023 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include + / { behaviors { - /omit-if-no-ref/ mkp: mouse_key_press { +#if ZMK_BEHAVIOR_OMIT(MKP) + /omit-if-no-ref/ +#endif + mkp: mouse_key_press { compatible = "zmk,behavior-mouse-key-press"; #binding-cells = <1>; }; diff --git a/app/dts/behaviors/none.dtsi b/app/dts/behaviors/none.dtsi index a9a820c30b5..5ac55438be9 100644 --- a/app/dts/behaviors/none.dtsi +++ b/app/dts/behaviors/none.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ none: none { +#if ZMK_BEHAVIOR_OMIT(NONE) + /omit-if-no-ref/ +#endif + none: none { compatible = "zmk,behavior-none"; #binding-cells = <0>; display-name = "None"; diff --git a/app/dts/behaviors/outputs.dtsi b/app/dts/behaviors/outputs.dtsi index 3047852adce..6071dcbdca4 100644 --- a/app/dts/behaviors/outputs.dtsi +++ b/app/dts/behaviors/outputs.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ out: outputs { +#if ZMK_BEHAVIOR_OMIT(OUT) + /omit-if-no-ref/ +#endif + out: outputs { compatible = "zmk,behavior-outputs"; #binding-cells = <1>; display-name = "Output Selection"; diff --git a/app/dts/behaviors/soft_off.dtsi b/app/dts/behaviors/soft_off.dtsi index a5c9d255bc1..68dce9c9b84 100644 --- a/app/dts/behaviors/soft_off.dtsi +++ b/app/dts/behaviors/soft_off.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ soft_off: z_so_off { +#if ZMK_BEHAVIOR_OMIT(SOFT_OFF) + /omit-if-no-ref/ +#endif + soft_off: z_so_off { compatible = "zmk,behavior-soft-off"; #binding-cells = <0>; split-peripheral-off-on-press; diff --git a/app/dts/behaviors/sticky_key.dtsi b/app/dts/behaviors/sticky_key.dtsi index 382a7254e7b..4429ffc45c5 100644 --- a/app/dts/behaviors/sticky_key.dtsi +++ b/app/dts/behaviors/sticky_key.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ sk: sticky_key { +#if ZMK_BEHAVIOR_OMIT(SK) + /omit-if-no-ref/ +#endif + sk: sticky_key { compatible = "zmk,behavior-sticky-key"; #binding-cells = <1>; release-after-ms = <1000>; @@ -14,7 +19,10 @@ ignore-modifiers; display-name = "Sticky Key"; }; - /omit-if-no-ref/ sl: sticky_layer { +#if ZMK_BEHAVIOR_OMIT(STICKY_LAYER) + /omit-if-no-ref/ +#endif + sl: sticky_layer { compatible = "zmk,behavior-sticky-key"; #binding-cells = <1>; release-after-ms = <1000>; diff --git a/app/dts/behaviors/to_layer.dtsi b/app/dts/behaviors/to_layer.dtsi index 3c740209cb1..532636a6ed2 100644 --- a/app/dts/behaviors/to_layer.dtsi +++ b/app/dts/behaviors/to_layer.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ to: to_layer { +#if ZMK_BEHAVIOR_OMIT(TO) + /omit-if-no-ref/ +#endif + to: to_layer { compatible = "zmk,behavior-to-layer"; #binding-cells = <1>; display-name = "To Layer"; diff --git a/app/dts/behaviors/toggle_layer.dtsi b/app/dts/behaviors/toggle_layer.dtsi index ea9b25b7c1d..81846e77c02 100644 --- a/app/dts/behaviors/toggle_layer.dtsi +++ b/app/dts/behaviors/toggle_layer.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ tog: toggle_layer { +#if ZMK_BEHAVIOR_OMIT(TOG) + /omit-if-no-ref/ +#endif + tog: toggle_layer { compatible = "zmk,behavior-toggle-layer"; #binding-cells = <1>; display-name = "Toggle Layer"; diff --git a/app/dts/behaviors/transparent.dtsi b/app/dts/behaviors/transparent.dtsi index 03ec36a64e8..09d29a4a275 100644 --- a/app/dts/behaviors/transparent.dtsi +++ b/app/dts/behaviors/transparent.dtsi @@ -4,9 +4,14 @@ * SPDX-License-Identifier: MIT */ +#include + / { behaviors { - /omit-if-no-ref/ trans: transparent { +#if ZMK_BEHAVIOR_OMIT(TRANS) + /omit-if-no-ref/ +#endif + trans: transparent { compatible = "zmk,behavior-transparent"; #binding-cells = <0>; display-name = "Transparent"; diff --git a/app/dts/layouts/cuddlykeyboards/ferris.dtsi b/app/dts/layouts/cuddlykeyboards/ferris.dtsi new file mode 100644 index 00000000000..6c1df4f5c54 --- /dev/null +++ b/app/dts/layouts/cuddlykeyboards/ferris.dtsi @@ -0,0 +1,45 @@ +#include + +/ { + cuddlykeyboards_ferris_layout: cuddlykeyboards_ferris_layout { + compatible = "zmk,physical-layout"; + display-name = "Default"; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 95 0 0 0> + , <&key_physical_attrs 100 100 100 32 0 0 0> + , <&key_physical_attrs 100 100 200 0 0 0 0> + , <&key_physical_attrs 100 100 300 28 0 0 0> + , <&key_physical_attrs 100 100 400 42 0 0 0> + , <&key_physical_attrs 100 100 700 42 0 0 0> + , <&key_physical_attrs 100 100 800 28 0 0 0> + , <&key_physical_attrs 100 100 900 0 0 0 0> + , <&key_physical_attrs 100 100 1000 32 0 0 0> + , <&key_physical_attrs 100 100 1100 95 0 0 0> + , <&key_physical_attrs 100 100 0 195 0 0 0> + , <&key_physical_attrs 100 100 100 132 0 0 0> + , <&key_physical_attrs 100 100 200 100 0 0 0> + , <&key_physical_attrs 100 100 300 129 0 0 0> + , <&key_physical_attrs 100 100 400 142 0 0 0> + , <&key_physical_attrs 100 100 700 142 0 0 0> + , <&key_physical_attrs 100 100 800 129 0 0 0> + , <&key_physical_attrs 100 100 900 100 0 0 0> + , <&key_physical_attrs 100 100 1000 132 0 0 0> + , <&key_physical_attrs 100 100 1100 195 0 0 0> + , <&key_physical_attrs 100 100 0 295 0 0 0> + , <&key_physical_attrs 100 100 100 231 0 0 0> + , <&key_physical_attrs 100 100 200 200 0 0 0> + , <&key_physical_attrs 100 100 300 229 0 0 0> + , <&key_physical_attrs 100 100 400 242 0 0 0> + , <&key_physical_attrs 100 100 700 242 0 0 0> + , <&key_physical_attrs 100 100 800 229 0 0 0> + , <&key_physical_attrs 100 100 900 200 0 0 0> + , <&key_physical_attrs 100 100 1000 231 0 0 0> + , <&key_physical_attrs 100 100 1100 295 0 0 0> + , <&key_physical_attrs 100 100 330 355 1500 430 455> + , <&key_physical_attrs 100 100 430 355 3000 430 455> + , <&key_physical_attrs 100 100 670 355 (-3000) 770 455> + , <&key_physical_attrs 100 100 770 355 (-1500) 770 455> + ; + }; +}; diff --git a/app/dts/layouts/foostan/corne.dtsi b/app/dts/layouts/foostan/corne.dtsi new file mode 100644 index 00000000000..ddafc789960 --- /dev/null +++ b/app/dts/layouts/foostan/corne.dtsi @@ -0,0 +1,121 @@ +#include + +/ { + foostan_corne_6col_layout: foostan_corne_6col_layout { + compatible = "zmk,physical-layout"; + display-name = "6-column"; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 37 0 0 0> + , <&key_physical_attrs 100 100 100 37 0 0 0> + , <&key_physical_attrs 100 100 200 12 0 0 0> + , <&key_physical_attrs 100 100 300 0 0 0 0> + , <&key_physical_attrs 100 100 400 12 0 0 0> + , <&key_physical_attrs 100 100 500 24 0 0 0> + , <&key_physical_attrs 100 100 800 24 0 0 0> + , <&key_physical_attrs 100 100 900 12 0 0 0> + , <&key_physical_attrs 100 100 1000 0 0 0 0> + , <&key_physical_attrs 100 100 1100 12 0 0 0> + , <&key_physical_attrs 100 100 1200 37 0 0 0> + , <&key_physical_attrs 100 100 1300 37 0 0 0> + , <&key_physical_attrs 100 100 0 137 0 0 0> + , <&key_physical_attrs 100 100 100 137 0 0 0> + , <&key_physical_attrs 100 100 200 112 0 0 0> + , <&key_physical_attrs 100 100 300 100 0 0 0> + , <&key_physical_attrs 100 100 400 112 0 0 0> + , <&key_physical_attrs 100 100 500 124 0 0 0> + , <&key_physical_attrs 100 100 800 124 0 0 0> + , <&key_physical_attrs 100 100 900 112 0 0 0> + , <&key_physical_attrs 100 100 1000 100 0 0 0> + , <&key_physical_attrs 100 100 1100 112 0 0 0> + , <&key_physical_attrs 100 100 1200 137 0 0 0> + , <&key_physical_attrs 100 100 1300 137 0 0 0> + , <&key_physical_attrs 100 100 0 237 0 0 0> + , <&key_physical_attrs 100 100 100 237 0 0 0> + , <&key_physical_attrs 100 100 200 212 0 0 0> + , <&key_physical_attrs 100 100 300 200 0 0 0> + , <&key_physical_attrs 100 100 400 212 0 0 0> + , <&key_physical_attrs 100 100 500 224 0 0 0> + , <&key_physical_attrs 100 100 800 224 0 0 0> + , <&key_physical_attrs 100 100 900 212 0 0 0> + , <&key_physical_attrs 100 100 1000 200 0 0 0> + , <&key_physical_attrs 100 100 1100 212 0 0 0> + , <&key_physical_attrs 100 100 1200 237 0 0 0> + , <&key_physical_attrs 100 100 1300 237 0 0 0> + , <&key_physical_attrs 100 100 350 312 0 0 0> + , <&key_physical_attrs 100 100 450 312 1200 450 412> + , <&key_physical_attrs 100 150 548 283 2400 548 433> + , <&key_physical_attrs 100 150 752 283 (-2400) 852 433> + , <&key_physical_attrs 100 100 850 312 (-1200) 950 412> + , <&key_physical_attrs 100 100 950 312 0 0 0> + ; + }; + + foostan_corne_5col_layout: foostan_corne_5col_layout { + compatible = "zmk,physical-layout"; + display-name = "5-column"; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 37 0 0 0> + , <&key_physical_attrs 100 100 100 12 0 0 0> + , <&key_physical_attrs 100 100 200 0 0 0 0> + , <&key_physical_attrs 100 100 300 12 0 0 0> + , <&key_physical_attrs 100 100 400 24 0 0 0> + , <&key_physical_attrs 100 100 700 24 0 0 0> + , <&key_physical_attrs 100 100 800 12 0 0 0> + , <&key_physical_attrs 100 100 900 0 0 0 0> + , <&key_physical_attrs 100 100 1000 12 0 0 0> + , <&key_physical_attrs 100 100 1100 37 0 0 0> + , <&key_physical_attrs 100 100 0 137 0 0 0> + , <&key_physical_attrs 100 100 100 112 0 0 0> + , <&key_physical_attrs 100 100 200 100 0 0 0> + , <&key_physical_attrs 100 100 300 112 0 0 0> + , <&key_physical_attrs 100 100 400 124 0 0 0> + , <&key_physical_attrs 100 100 700 124 0 0 0> + , <&key_physical_attrs 100 100 800 112 0 0 0> + , <&key_physical_attrs 100 100 900 100 0 0 0> + , <&key_physical_attrs 100 100 1000 112 0 0 0> + , <&key_physical_attrs 100 100 1100 137 0 0 0> + , <&key_physical_attrs 100 100 0 237 0 0 0> + , <&key_physical_attrs 100 100 100 212 0 0 0> + , <&key_physical_attrs 100 100 200 200 0 0 0> + , <&key_physical_attrs 100 100 300 212 0 0 0> + , <&key_physical_attrs 100 100 400 224 0 0 0> + , <&key_physical_attrs 100 100 700 224 0 0 0> + , <&key_physical_attrs 100 100 800 212 0 0 0> + , <&key_physical_attrs 100 100 900 200 0 0 0> + , <&key_physical_attrs 100 100 1000 212 0 0 0> + , <&key_physical_attrs 100 100 1100 237 0 0 0> + , <&key_physical_attrs 100 100 250 312 0 0 0> + , <&key_physical_attrs 100 100 350 312 1200 350 412> + , <&key_physical_attrs 100 150 448 283 2400 448 433> + , <&key_physical_attrs 100 150 652 283 (-2400) 752 433> + , <&key_physical_attrs 100 100 750 312 (-1200) 850 412> + , <&key_physical_attrs 100 100 850 312 0 0 0> + ; + }; + + foostan_corne_position_map { + compatible = "zmk,physical-layout-position-map"; + + complete; + + twelve { + physical-layout = <&foostan_corne_6col_layout>; + positions + = < 0 1 2 3 4 5 6 7 8 9 10 11> + , <12 13 14 15 16 17 18 19 20 21 22 23> + , <24 25 26 27 28 29 30 31 32 33 34 35> + , < 36 37 38 39 40 41 >; + }; + + ten { + physical-layout = <&foostan_corne_5col_layout>; + positions + = <36 0 1 2 3 4 5 6 7 8 9 37> + , <38 10 11 12 13 14 15 16 17 18 19 39> + , <40 20 21 22 23 24 25 26 27 28 29 41> + , < 30 31 32 33 34 35 >; + }; + }; +}; \ No newline at end of file diff --git a/app/dts/layouts/josefadamcik/sofle.dtsi b/app/dts/layouts/josefadamcik/sofle.dtsi new file mode 100644 index 00000000000..9c858e2d580 --- /dev/null +++ b/app/dts/layouts/josefadamcik/sofle.dtsi @@ -0,0 +1,71 @@ +#include + +/ { + josefadamcik_sofle_layout: josefadamcik_sofle_layout { + compatible = "zmk,physical-layout"; + display-name = "Sofle"; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 37 0 0 0> + , <&key_physical_attrs 100 100 100 37 0 0 0> + , <&key_physical_attrs 100 100 200 12 0 0 0> + , <&key_physical_attrs 100 100 300 0 0 0 0> + , <&key_physical_attrs 100 100 400 12 0 0 0> + , <&key_physical_attrs 100 100 500 24 0 0 0> + , <&key_physical_attrs 100 100 900 24 0 0 0> + , <&key_physical_attrs 100 100 1000 12 0 0 0> + , <&key_physical_attrs 100 100 1100 0 0 0 0> + , <&key_physical_attrs 100 100 1200 12 0 0 0> + , <&key_physical_attrs 100 100 1300 37 0 0 0> + , <&key_physical_attrs 100 100 1400 37 0 0 0> + , <&key_physical_attrs 100 100 0 137 0 0 0> + , <&key_physical_attrs 100 100 100 137 0 0 0> + , <&key_physical_attrs 100 100 200 112 0 0 0> + , <&key_physical_attrs 100 100 300 100 0 0 0> + , <&key_physical_attrs 100 100 400 112 0 0 0> + , <&key_physical_attrs 100 100 500 124 0 0 0> + , <&key_physical_attrs 100 100 900 124 0 0 0> + , <&key_physical_attrs 100 100 1000 112 0 0 0> + , <&key_physical_attrs 100 100 1100 100 0 0 0> + , <&key_physical_attrs 100 100 1200 112 0 0 0> + , <&key_physical_attrs 100 100 1300 137 0 0 0> + , <&key_physical_attrs 100 100 1400 137 0 0 0> + , <&key_physical_attrs 100 100 0 237 0 0 0> + , <&key_physical_attrs 100 100 100 237 0 0 0> + , <&key_physical_attrs 100 100 200 212 0 0 0> + , <&key_physical_attrs 100 100 300 200 0 0 0> + , <&key_physical_attrs 100 100 400 212 0 0 0> + , <&key_physical_attrs 100 100 500 224 0 0 0> + , <&key_physical_attrs 100 100 900 224 0 0 0> + , <&key_physical_attrs 100 100 1000 212 0 0 0> + , <&key_physical_attrs 100 100 1100 200 0 0 0> + , <&key_physical_attrs 100 100 1200 212 0 0 0> + , <&key_physical_attrs 100 100 1300 237 0 0 0> + , <&key_physical_attrs 100 100 1400 237 0 0 0> + , <&key_physical_attrs 100 100 0 337 0 0 0> + , <&key_physical_attrs 100 100 100 337 0 0 0> + , <&key_physical_attrs 100 100 200 312 0 0 0> + , <&key_physical_attrs 100 100 300 300 0 0 0> + , <&key_physical_attrs 100 100 400 312 0 0 0> + , <&key_physical_attrs 100 100 500 324 0 0 0> + , <&key_physical_attrs 100 100 600 274 0 0 0> + , <&key_physical_attrs 100 100 800 274 0 0 0> + , <&key_physical_attrs 100 100 900 324 0 0 0> + , <&key_physical_attrs 100 100 1000 312 0 0 0> + , <&key_physical_attrs 100 100 1100 300 0 0 0> + , <&key_physical_attrs 100 100 1200 312 0 0 0> + , <&key_physical_attrs 100 100 1300 337 0 0 0> + , <&key_physical_attrs 100 100 1400 337 0 0 0> + , <&key_physical_attrs 100 100 175 437 0 0 0> + , <&key_physical_attrs 100 100 275 412 0 0 0> + , <&key_physical_attrs 100 100 375 412 0 0 0> + , <&key_physical_attrs 100 100 490 412 1200 490 412> + , <&key_physical_attrs 100 150 600 383 2400 600 433> + , <&key_physical_attrs 100 150 800 383 (-2400) 900 433> + , <&key_physical_attrs 100 100 910 412 (-1200) 1010 412> + , <&key_physical_attrs 100 100 1025 412 0 0 0> + , <&key_physical_attrs 100 100 1125 412 0 0 0> + , <&key_physical_attrs 100 100 1225 437 0 0 0> + ; + }; +}; \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/behaviors.h b/app/include/dt-bindings/zmk/behaviors.h new file mode 100644 index 00000000000..abfb91f48c3 --- /dev/null +++ b/app/include/dt-bindings/zmk/behaviors.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define ZMK_BEHAVIOR_OMIT(_name) \ + !(defined(ZMK_BEHAVIORS_KEEP_##_name) || \ + (defined(ZMK_BEHAVIORS_KEEP_ALL) && !defined(ZMK_BEHAVIORS_OMIT_##_name))) \ No newline at end of file diff --git a/app/include/linker/zmk-rpc-subsystem-settings-reset.ld b/app/include/linker/zmk-rpc-subsystem-settings-reset.ld new file mode 100644 index 00000000000..207d1c8f509 --- /dev/null +++ b/app/include/linker/zmk-rpc-subsystem-settings-reset.ld @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +ITERABLE_SECTION_ROM(zmk_rpc_subsystem_settings_reset, 4) diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 0d7dbaf33b3..50b358ba92a 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -12,17 +12,63 @@ #define ZMK_KEYMAP_LAYERS_LEN \ (DT_FOREACH_CHILD(DT_INST(0, zmk_keymap), ZMK_LAYER_CHILD_LEN_PLUS_ONE) 0) +/** + * @brief A layer ID is a stable identifier to refer to a layer, regardless of ordering. + */ +typedef uint8_t zmk_keymap_layer_id_t; + +/** + * @brief A way to return/reference a missing or invalid layer ID + */ +#define ZMK_KEYMAP_LAYER_ID_INVAL UINT8_MAX + +/** + * @brief A layer index is a identifier to refer layer at a particular position in the order. + */ +typedef uint8_t zmk_keymap_layer_index_t; + typedef uint32_t zmk_keymap_layers_state_t; -uint8_t zmk_keymap_layer_default(void); +zmk_keymap_layer_id_t zmk_keymap_layer_index_to_id(zmk_keymap_layer_index_t layer_index); + +zmk_keymap_layer_id_t zmk_keymap_layer_default(void); zmk_keymap_layers_state_t zmk_keymap_layer_state(void); -bool zmk_keymap_layer_active(uint8_t layer); -uint8_t zmk_keymap_highest_layer_active(void); -int zmk_keymap_layer_activate(uint8_t layer); -int zmk_keymap_layer_deactivate(uint8_t layer); -int zmk_keymap_layer_toggle(uint8_t layer); -int zmk_keymap_layer_to(uint8_t layer); -const char *zmk_keymap_layer_name(uint8_t layer); +bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer); +zmk_keymap_layer_id_t zmk_keymap_highest_layer_active(void); +int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer); +int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer); +int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer); +int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer); +const char *zmk_keymap_layer_name(zmk_keymap_layer_id_t layer); + +const struct zmk_behavior_binding *zmk_keymap_get_layer_binding_at_idx(zmk_keymap_layer_id_t layer, + uint8_t binding_idx); +int zmk_keymap_set_layer_binding_at_idx(zmk_keymap_layer_id_t layer, uint8_t binding_idx, + const struct zmk_behavior_binding binding); + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +int zmk_keymap_add_layer(void); +int zmk_keymap_remove_layer(zmk_keymap_layer_index_t index); +int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t at_index); + +int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx); + +int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size); + +#endif + +/** + * @brief Check if there are any unsaved keymap changes. + * + * @retval 0 if there are no changes. + * @retval 1 if there are changes. + */ +int zmk_keymap_check_unsaved_changes(void); + +int zmk_keymap_save_changes(void); +int zmk_keymap_discard_changes(void); +int zmk_keymap_reset_settings(void); int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed, int64_t timestamp); diff --git a/app/include/zmk/physical_layouts.h b/app/include/zmk/physical_layouts.h index 8d8188e3c91..e78602e3811 100644 --- a/app/include/zmk/physical_layouts.h +++ b/app/include/zmk/physical_layouts.h @@ -40,4 +40,5 @@ int zmk_physical_layouts_check_unsaved_selection(void); int zmk_physical_layouts_save_selected(void); int zmk_physical_layouts_revert_selected(void); -int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t *map); +int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, size_t map_size, + uint32_t map[map_size]); diff --git a/app/include/zmk/studio/rpc.h b/app/include/zmk/studio/rpc.h index 07bd98e4646..e223b7a5af9 100644 --- a/app/include/zmk/studio/rpc.h +++ b/app/include/zmk/studio/rpc.h @@ -56,6 +56,12 @@ struct zmk_rpc_subsystem_handler { enum zmk_studio_rpc_handler_security security; }; +typedef int (*zmk_rpc_subsystem_settings_reset_func)(void); + +struct zmk_rpc_subsystem_settings_reset { + zmk_rpc_subsystem_settings_reset_func callback; +}; + /** * @brief Generate a "meta" subsystem response indicating an "empty" response to an RPC request. */ @@ -103,6 +109,14 @@ struct zmk_rpc_subsystem_handler { .security = _security, \ }; +#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET(prefix, _callback) \ + STRUCT_SECTION_ITERABLE(zmk_rpc_subsystem_settings_reset, _##prefix##_settings_reset) = { \ + .callback = _callback, \ + }; + +#define ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(_var) \ + STRUCT_SECTION_FOREACH(zmk_rpc_subsystem_settings_reset, _var) + /** * @brief Create a zmk_studio_Notification struct for the given subsystem and type, including initialization of the inner fields. diff --git a/app/scripts/west_commands/test.py b/app/scripts/west_commands/test.py index 531334913b4..737622dea03 100644 --- a/app/scripts/west_commands/test.py +++ b/app/scripts/west_commands/test.py @@ -2,11 +2,11 @@ # SPDX-License-Identifier: MIT """Test runner for ZMK.""" -import os import subprocess +from pathlib import Path -from west.commands import WestCommand from west import log # use this for user output +from west.commands import WestCommand class Test(WestCommand): @@ -17,6 +17,8 @@ def __init__(self): description="Run the ZMK testsuite.", ) + self.appdir = Path(__file__).resolve().parents[2] + def do_add_parser(self, parser_adder): parser = parser_adder.add_parser( self.name, @@ -34,8 +36,7 @@ def do_add_parser(self, parser_adder): def do_run(self, args, unknown_args): # the run-test script assumes the app directory is the current dir. - os.chdir(f"{self.topdir}/app") completed_process = subprocess.run( - [f"{self.topdir}/app/run-test.sh", args.test_path] + ["./run-test.sh", args.test_path], cwd=self.appdir ) exit(completed_process.returncode) diff --git a/app/snippets/studio-rpc-usb-uart/snippet.yml b/app/snippets/studio-rpc-usb-uart/snippet.yml index e0e334de183..ea5a17b2886 100644 --- a/app/snippets/studio-rpc-usb-uart/snippet.yml +++ b/app/snippets/studio-rpc-usb-uart/snippet.yml @@ -3,5 +3,6 @@ name: studio-rpc-usb-uart append: + DTS_EXTRA_CPPFLAGS: -DZMK_BEHAVIORS_KEEP_ALL EXTRA_DTC_OVERLAY_FILE: studio-rpc-usb-uart.overlay EXTRA_CONF_FILE: studio-rpc-usb-uart.conf diff --git a/app/src/behaviors/behavior_backlight.c b/app/src/behaviors/behavior_backlight.c index d67ce2e7a8a..45edd4c923e 100644 --- a/app/src/behaviors/behavior_backlight.c +++ b/app/src/behaviors/behavior_backlight.c @@ -68,7 +68,7 @@ static const struct behavior_parameter_value_metadata one_arg_p2_values[] = { .range = { .min = 0, - .max = 255, + .max = 100, }, }, }; diff --git a/app/src/ble.c b/app/src/ble.c index 776730fe5c3..2308de52024 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -659,7 +659,7 @@ static int zmk_ble_complete_startup(void) { char setting_name[15]; sprintf(setting_name, "ble/profiles/%d", i); - err = settings_delete(setting_name); + int err = settings_delete(setting_name); if (err) { LOG_ERR("Failed to delete setting: %d", err); } diff --git a/app/src/keymap.c b/app/src/keymap.c index 94bd12048cf..dabe338d07d 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -6,10 +6,12 @@ #include #include +#include #include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#include #include #include #include @@ -27,7 +29,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0; -static uint8_t _zmk_keymap_layer_default = 0; +static zmk_keymap_layer_id_t _zmk_keymap_layer_default = 0; #define DT_DRV_COMPAT zmk_keymap @@ -38,7 +40,11 @@ static uint8_t _zmk_keymap_layer_default = 0; #endif #define TRANSFORMED_LAYER(node) \ - { LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node) } + { \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, bindings), \ + (LISTIFY(DT_PROP_LEN(node, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), node)), ()) \ + } #if ZMK_KEYMAP_HAS_SENSORS #define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ @@ -58,7 +64,7 @@ static uint8_t _zmk_keymap_layer_default = 0; #endif /* ZMK_KEYMAP_HAS_SENSORS */ -#define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, NULL)) +#define LAYER_NAME(node) DT_PROP_OR(node, display_name, DT_PROP_OR(node, label, "")) // State @@ -67,12 +73,36 @@ static uint8_t _zmk_keymap_layer_default = 0; // still send the release event to the behavior in that layer also. static uint32_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN]; -static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { - DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))}; +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +static uint8_t keymap_layer_orders[ZMK_KEYMAP_LAYERS_LEN]; + +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +#define KEYMAP_VAR(_name, _opts) \ + static _opts struct zmk_behavior_binding _name[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { \ + COND_CODE_1(IS_ENABLED(CONFIG_ZMK_STUDIO), \ + (DT_INST_FOREACH_CHILD_SEP(0, TRANSFORMED_LAYER, (, ))), \ + (DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(0, TRANSFORMED_LAYER, (, ))))}; + +KEYMAP_VAR(zmk_keymap, ) + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +KEYMAP_VAR(zmk_stock_keymap, const) + +static char zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN][CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN] = { + DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))}; + +static uint32_t changed_layer_names = 0; + +#else static const char *zmk_keymap_layer_names[ZMK_KEYMAP_LAYERS_LEN] = { DT_INST_FOREACH_CHILD_SEP(0, LAYER_NAME, (, ))}; +#endif + #if ZMK_KEYMAP_HAS_SENSORS static struct zmk_behavior_binding @@ -81,23 +111,50 @@ static struct zmk_behavior_binding #endif /* ZMK_KEYMAP_HAS_SENSORS */ -static inline int set_layer_state(uint8_t layer, bool state) { +#define ASSERT_LAYER_VAL(_layer, _fail_ret) \ + if ((_layer) >= ZMK_KEYMAP_LAYERS_LEN) { \ + return (_fail_ret); \ + } + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) { + for (uint8_t i = 0; i < ZMK_KEYMAP_LAYERS_LEN; i++) { + if (keymap_layer_orders[i] == layer_id) { + return i; + } + } + + return ZMK_KEYMAP_LAYER_ID_INVAL; +} + +#define LAYER_INDEX_TO_ID(_layer) keymap_layer_orders[_layer] +#define LAYER_ID_TO_INDEX(_layer) map_layer_id_to_index(_layer) + +#else + +#define LAYER_INDEX_TO_ID(_layer) _layer +#define LAYER_ID_TO_INDEX(_layer) _layer + +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +static inline int set_layer_state(zmk_keymap_layer_id_t layer_id, bool state) { int ret = 0; - if (layer >= ZMK_KEYMAP_LAYERS_LEN) { + if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) { return -EINVAL; } // Default layer should *always* remain active - if (layer == _zmk_keymap_layer_default && !state) { + if (layer_id == _zmk_keymap_layer_default && !state) { return 0; } zmk_keymap_layers_state_t old_state = _zmk_keymap_layer_state; - WRITE_BIT(_zmk_keymap_layer_state, layer, state); + WRITE_BIT(_zmk_keymap_layer_state, layer_id, state); // Don't send state changes unless there was an actual change if (old_state != _zmk_keymap_layer_state) { - LOG_DBG("layer_changed: layer %d state %d", layer, state); - ret = raise_layer_state_changed(layer, state); + LOG_DBG("layer_changed: layer %d state %d", layer_id, state); + ret = raise_layer_state_changed(layer_id, state); if (ret < 0) { LOG_WRN("Failed to raise layer state changed (%d)", ret); } @@ -106,21 +163,28 @@ static inline int set_layer_state(uint8_t layer, bool state) { return ret; } -uint8_t zmk_keymap_layer_default(void) { return _zmk_keymap_layer_default; } +zmk_keymap_layer_id_t zmk_keymap_layer_index_to_id(zmk_keymap_layer_index_t layer_index) { + ASSERT_LAYER_VAL(layer_index, UINT8_MAX); + + return LAYER_INDEX_TO_ID(layer_index); +} + +zmk_keymap_layer_id_t zmk_keymap_layer_default(void) { return _zmk_keymap_layer_default; } zmk_keymap_layers_state_t zmk_keymap_layer_state(void) { return _zmk_keymap_layer_state; } -bool zmk_keymap_layer_active_with_state(uint8_t layer, zmk_keymap_layers_state_t state_to_test) { +bool zmk_keymap_layer_active_with_state(zmk_keymap_layer_id_t layer, + zmk_keymap_layers_state_t state_to_test) { // The default layer is assumed to be ALWAYS ACTIVE so we include an || here to ensure nobody // breaks up that assumption by accident return (state_to_test & (BIT(layer))) == (BIT(layer)) || layer == _zmk_keymap_layer_default; }; -bool zmk_keymap_layer_active(uint8_t layer) { +bool zmk_keymap_layer_active(zmk_keymap_layer_id_t layer) { return zmk_keymap_layer_active_with_state(layer, _zmk_keymap_layer_state); }; -uint8_t zmk_keymap_highest_layer_active(void) { +zmk_keymap_layer_id_t zmk_keymap_highest_layer_active(void) { for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) { if (zmk_keymap_layer_active(layer)) { return layer; @@ -129,11 +193,13 @@ uint8_t zmk_keymap_highest_layer_active(void) { return zmk_keymap_layer_default(); } -int zmk_keymap_layer_activate(uint8_t layer) { return set_layer_state(layer, true); }; +int zmk_keymap_layer_activate(zmk_keymap_layer_id_t layer) { return set_layer_state(layer, true); }; -int zmk_keymap_layer_deactivate(uint8_t layer) { return set_layer_state(layer, false); }; +int zmk_keymap_layer_deactivate(zmk_keymap_layer_id_t layer) { + return set_layer_state(layer, false); +}; -int zmk_keymap_layer_toggle(uint8_t layer) { +int zmk_keymap_layer_toggle(zmk_keymap_layer_id_t layer) { if (zmk_keymap_layer_active(layer)) { return zmk_keymap_layer_deactivate(layer); } @@ -141,7 +207,7 @@ int zmk_keymap_layer_toggle(uint8_t layer) { return zmk_keymap_layer_activate(layer); }; -int zmk_keymap_layer_to(uint8_t layer) { +int zmk_keymap_layer_to(zmk_keymap_layer_id_t layer) { for (int i = ZMK_KEYMAP_LAYERS_LEN - 1; i >= 0; i--) { zmk_keymap_layer_deactivate(i); } @@ -151,18 +217,365 @@ int zmk_keymap_layer_to(uint8_t layer) { return 0; } -bool is_active_layer(uint8_t layer, zmk_keymap_layers_state_t layer_state) { - return (layer_state & BIT(layer)) == BIT(layer) || layer == _zmk_keymap_layer_default; +const char *zmk_keymap_layer_name(zmk_keymap_layer_id_t layer_id) { + ASSERT_LAYER_VAL(layer_id, NULL) + + return zmk_keymap_layer_names[layer_id]; } -const char *zmk_keymap_layer_name(uint8_t layer) { - if (layer >= ZMK_KEYMAP_LAYERS_LEN) { +const struct zmk_behavior_binding * +zmk_keymap_get_layer_binding_at_idx(zmk_keymap_layer_id_t layer_id, uint8_t binding_idx) { + if (binding_idx >= ZMK_KEYMAP_LEN) { return NULL; } - return zmk_keymap_layer_names[layer]; + ASSERT_LAYER_VAL(layer_id, NULL) + + return &zmk_keymap[layer_id][binding_idx]; +} + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +#define PENDING_ARRAY_SIZE DIV_ROUND_UP(ZMK_KEYMAP_LEN, 8) + +static uint8_t zmk_keymap_layer_pending_changes[ZMK_KEYMAP_LAYERS_LEN][PENDING_ARRAY_SIZE]; + +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +int zmk_keymap_set_layer_binding_at_idx(zmk_keymap_layer_id_t layer_id, uint8_t binding_idx, + struct zmk_behavior_binding binding) { + if (binding_idx >= ZMK_KEYMAP_LEN) { + return -EINVAL; + } + + ASSERT_LAYER_VAL(layer_id, -EINVAL) + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + uint8_t *pending = zmk_keymap_layer_pending_changes[layer_id]; + + WRITE_BIT(pending[binding_idx / 8], binding_idx % 8, 1); +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + + // TODO: Need a mutex to protect access to the keymap data? + memcpy(&zmk_keymap[layer_id][binding_idx], &binding, sizeof(binding)); + + return 0; +} + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +static uint8_t settings_layer_orders[ZMK_KEYMAP_LAYERS_LEN]; + +#endif + +int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx) { + ASSERT_LAYER_VAL(start_idx, -EINVAL) + ASSERT_LAYER_VAL(dest_idx, -EINVAL) + + if (start_idx == dest_idx) { + return 0; + } else if (dest_idx > start_idx) { + uint8_t val = keymap_layer_orders[start_idx]; + + for (int i = start_idx; i < dest_idx; i++) { + keymap_layer_orders[i] = keymap_layer_orders[i + 1]; + } + + keymap_layer_orders[dest_idx] = val; + } else { + uint8_t val = keymap_layer_orders[start_idx]; + + for (int i = start_idx; i > dest_idx; i--) { + keymap_layer_orders[i] = keymap_layer_orders[i - 1]; + } + + keymap_layer_orders[dest_idx] = val; + } + + return 0; } +int zmk_keymap_add_layer(void) { + uint32_t seen_layer_ids = 0; + LOG_HEXDUMP_DBG(keymap_layer_orders, ZMK_KEYMAP_LAYERS_LEN, "Order"); + + for (int index = 0; index < ZMK_KEYMAP_LAYERS_LEN; index++) { + zmk_keymap_layer_id_t id = LAYER_INDEX_TO_ID(index); + + if (id != ZMK_KEYMAP_LAYER_ID_INVAL) { + WRITE_BIT(seen_layer_ids, id, 1); + continue; + } + + for (int candidate_id = 0; candidate_id < ZMK_KEYMAP_LAYERS_LEN; candidate_id++) { + if (!(seen_layer_ids & BIT(candidate_id))) { + keymap_layer_orders[index] = candidate_id; + return index; + } + } + } + + return -ENOSPC; +} + +int zmk_keymap_remove_layer(zmk_keymap_layer_index_t index) { + ASSERT_LAYER_VAL(index, -EINVAL); + + if (keymap_layer_orders[index] == ZMK_KEYMAP_LAYER_ID_INVAL) { + return -EINVAL; + } + + LOG_DBG("Removing layer index %d which is ID %d", index, keymap_layer_orders[index]); + LOG_HEXDUMP_DBG(keymap_layer_orders, ZMK_KEYMAP_LAYERS_LEN, "Order"); + + while (index < ZMK_KEYMAP_LAYERS_LEN - 1) { + keymap_layer_orders[index] = keymap_layer_orders[index + 1]; + index++; + } + + keymap_layer_orders[ZMK_KEYMAP_LAYERS_LEN - 1] = ZMK_KEYMAP_LAYER_ID_INVAL; + + LOG_HEXDUMP_DBG(keymap_layer_orders, ZMK_KEYMAP_LAYERS_LEN, "Order"); + + return 0; +} + +int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t at_index) { + ASSERT_LAYER_VAL(at_index, -EINVAL); + ASSERT_LAYER_VAL(id, -ENODEV); + + for (zmk_keymap_layer_index_t index = ZMK_KEYMAP_LAYERS_LEN - 1; index > at_index; index--) { + keymap_layer_orders[index] = keymap_layer_orders[index - 1]; + } + + keymap_layer_orders[at_index] = id; + + return 0; +} + +int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size) { + ASSERT_LAYER_VAL(id, -EINVAL); + + if (size >= CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN) { + return -ENOSPC; + } + + strlcpy(zmk_keymap_layer_names[id], name, CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN); + + // Ensure we properly null terminate our name if we previously had a longer one. + if (size < CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN - 1) { + zmk_keymap_layer_names[id][size] = 0; + } + + WRITE_BIT(changed_layer_names, id, 1); + + return 0; +} + +#else + +int zmk_keymap_move_layer(zmk_keymap_layer_index_t layer, zmk_keymap_layer_index_t dest) { + return -ENOTSUP; +} + +int zmk_keymap_add_layer(void) { return -ENOTSUP; } + +int zmk_keymap_remove_layer(zmk_keymap_layer_index_t index) { return -ENOTSUP; } + +int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t at_index) { + return -ENOTSUP; +} + +int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size) { + return -ENOTSUP; +} + +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +#define PENDING_ARRAY_SIZE DIV_ROUND_UP(ZMK_KEYMAP_LEN, 8) + +static uint8_t zmk_keymap_layer_pending_changes[ZMK_KEYMAP_LAYERS_LEN][PENDING_ARRAY_SIZE]; + +struct zmk_behavior_binding_setting { + zmk_behavior_local_id_t behavior_local_id; + uint32_t param1; + uint32_t param2; +} __packed; + +int zmk_keymap_check_unsaved_changes(void) { + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + uint8_t *pending = zmk_keymap_layer_pending_changes[l]; + for (int kp = 0; kp < ZMK_KEYMAP_LEN; kp++) { + if (pending[kp / 8] & BIT(kp % 8)) { + return 1; + } + } + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + if (settings_layer_orders[l] != keymap_layer_orders[l]) { + return 1; + } +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + } + + return 0; +} + +#define LAYER_ORDER_SETTINGS_KEY "keymap/layer_order" +#define LAYER_NAME_SETTINGS_KEY "keymap/l_n/%d" +#define LAYER_BINDING_SETTINGS_KEY "keymap/l/%d/%d" + +static void save_bindings(void) { + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + uint8_t *pending = zmk_keymap_layer_pending_changes[l]; + + for (int kp = 0; kp < ZMK_KEYMAP_LEN; kp++) { + if (pending[kp / 8] & BIT(kp % 8)) { + LOG_DBG("Pending save for layer %d at key position %d", l, kp); + + struct zmk_behavior_binding *binding = &zmk_keymap[l][kp]; + struct zmk_behavior_binding_setting binding_setting = { + .behavior_local_id = zmk_behavior_get_local_id(binding->behavior_dev), + .param1 = binding->param1, + .param2 = binding->param2, + }; + + // We can skip any trailing zero params, regardless of the behavior + // and if those params are meaningful. + size_t len = sizeof(binding_setting); + if (binding_setting.param2 == 0) { + len -= 4; + + if (binding_setting.param1 == 0) { + len -= 4; + } + } + + char setting_name[20]; + sprintf(setting_name, LAYER_BINDING_SETTINGS_KEY, l, kp); + + settings_save_one(setting_name, &binding_setting, len); + } + } + + *pending = 0; + } +} + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) +static void save_layer_orders(void) { + settings_save_one(LAYER_ORDER_SETTINGS_KEY, keymap_layer_orders, + ARRAY_SIZE(keymap_layer_orders)); + memcpy(settings_layer_orders, keymap_layer_orders, ARRAY_SIZE(keymap_layer_orders)); +} +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +static void save_layer_names(void) { + for (int id = 0; id < ZMK_KEYMAP_LAYERS_LEN; id++) { + if (changed_layer_names & BIT(id)) { + char setting_name[14]; + sprintf(setting_name, LAYER_NAME_SETTINGS_KEY, id); + settings_save_one(setting_name, zmk_keymap_layer_names[id], + strlen(zmk_keymap_layer_names[id])); + } + } + + changed_layer_names = 0; +} + +int zmk_keymap_save_changes(void) { + save_bindings(); + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + save_layer_orders(); +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + + save_layer_names(); + + return 0; +} + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + +#define KEYMAP_LAYER_ORDER_INIT(n) \ + keymap_layer_orders[i] = i; \ + settings_layer_orders[i] = i; \ + i++; + +static void load_stock_keymap_layer_ordering() { + int i = 0; + DT_INST_FOREACH_CHILD_STATUS_OKAY(0, KEYMAP_LAYER_ORDER_INIT) + while (i < ZMK_KEYMAP_LAYERS_LEN) { + keymap_layer_orders[i] = ZMK_KEYMAP_LAYER_ID_INVAL; + i++; + } +} +#endif + +static void reload_from_stock_keymap(void) { + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + for (int k = 0; k < ZMK_KEYMAP_LEN; k++) { + zmk_keymap[l][k] = zmk_stock_keymap[l][k]; + } + } +} + +int zmk_keymap_discard_changes(void) { + load_stock_keymap_layer_ordering(); + reload_from_stock_keymap(); + + int ret = settings_load_subtree("keymap"); + if (ret >= 0) { + changed_layer_names = 0; + + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + memset(zmk_keymap_layer_pending_changes[l], 0, PENDING_ARRAY_SIZE); + } + } + + return ret; +} + +int zmk_keymap_reset_settings(void) { + settings_delete(LAYER_ORDER_SETTINGS_KEY); + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + char layer_name_setting_name[14]; + sprintf(layer_name_setting_name, LAYER_NAME_SETTINGS_KEY, l); + settings_delete(layer_name_setting_name); + + for (int k = 0; k < ZMK_KEYMAP_LEN; k++) { + if (memcmp(&zmk_keymap[l][k], &zmk_stock_keymap[l][k], + sizeof(struct zmk_behavior_binding_setting)) == 0) { + continue; + } + + char setting_name[20]; + sprintf(setting_name, LAYER_BINDING_SETTINGS_KEY, l, k); + settings_delete(setting_name); + } + } + + load_stock_keymap_layer_ordering(); + + reload_from_stock_keymap(); + + return 0; +} + +#else + +int zmk_keymap_save_changes(void) { return -ENOTSUP; } + +int zmk_keymap_discard_changes(void) { return -ENOTSUP; } + +int zmk_keymap_reset_settings(void) { return -ENOTSUP; } + +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, bool pressed) { if (pressed) { @@ -172,24 +585,28 @@ int invoke_locally(struct zmk_behavior_binding *binding, struct zmk_behavior_bin } } -int zmk_keymap_apply_position_state(uint8_t source, int layer, uint32_t position, bool pressed, - int64_t timestamp) { +int zmk_keymap_apply_position_state(uint8_t source, zmk_keymap_layer_id_t layer_id, + uint32_t position, bool pressed, int64_t timestamp) { // We want to make a copy of this, since it may be converted from // relative to absolute before being invoked - struct zmk_behavior_binding binding = zmk_keymap[layer][position]; + + ASSERT_LAYER_VAL(layer_id, -EINVAL); + + struct zmk_behavior_binding binding = zmk_keymap[layer_id][position]; const struct device *behavior; struct zmk_behavior_binding_event event = { - .layer = layer, + .layer = layer_id, .position = position, .timestamp = timestamp, }; - LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, binding.behavior_dev); + LOG_DBG("layer_id: %d position: %d, binding name: %s", layer_id, position, + binding.behavior_dev); behavior = zmk_behavior_get_binding(binding.behavior_dev); if (!behavior) { - LOG_WRN("No behavior assigned to %d on layer %d", position, layer); + LOG_WRN("No behavior assigned to %d on layer %d", position, layer_id); return 1; } @@ -236,9 +653,19 @@ int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pr if (pressed) { zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state; } - for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) { - if (zmk_keymap_layer_active_with_state(layer, zmk_keymap_active_behavior_layer[position])) { - int ret = zmk_keymap_apply_position_state(source, layer, position, pressed, timestamp); + + // We use int here to be sure we don't loop layer_idx back to UINT8_MAX + for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1; + layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); layer_idx--) { + zmk_keymap_layer_id_t layer_id = LAYER_INDEX_TO_ID(layer_idx); + + if (layer_id == ZMK_KEYMAP_LAYER_ID_INVAL) { + continue; + } + if (zmk_keymap_layer_active_with_state(layer_id, + zmk_keymap_active_behavior_layer[position])) { + int ret = + zmk_keymap_apply_position_state(source, layer_id, position, pressed, timestamp); if (ret > 0) { LOG_DBG("behavior processing to continue to next layer"); continue; @@ -260,20 +687,26 @@ int zmk_keymap_sensor_event(uint8_t sensor_index, size_t channel_data_size, int64_t timestamp) { bool opaque_response = false; - for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= 0; layer--) { - struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_index]; + for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1; layer_idx >= 0; layer_idx--) { + uint8_t layer_id = LAYER_INDEX_TO_ID(layer_idx); + + if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) { + continue; + } + + struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer_id][sensor_index]; - LOG_DBG("layer: %d sensor_index: %d, binding name: %s", layer, sensor_index, - binding->behavior_dev); + LOG_DBG("layer idx: %d, layer id: %d sensor_index: %d, binding name: %s", layer_idx, + layer_id, sensor_index, binding->behavior_dev); const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev); if (!behavior) { - LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer); + LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer_id); continue; } struct zmk_behavior_binding_event event = { - .layer = layer, + .layer = layer_id, .position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index), .timestamp = timestamp, }; @@ -290,8 +723,8 @@ int zmk_keymap_sensor_event(uint8_t sensor_index, } enum behavior_sensor_binding_process_mode mode = - (!opaque_response && layer >= _zmk_keymap_layer_default && - zmk_keymap_layer_active(layer)) + (!opaque_response && layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default) && + zmk_keymap_layer_active(layer_id)) ? BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER : BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD; @@ -335,3 +768,140 @@ ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed); #if ZMK_KEYMAP_HAS_SENSORS ZMK_SUBSCRIPTION(keymap, zmk_sensor_event); #endif /* ZMK_KEYMAP_HAS_SENSORS */ + +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +static int keymap_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) { + const char *next; + + LOG_DBG("Setting Keymap setting %s", name); + + if (settings_name_steq(name, "l_n", &next) && next) { + char *endptr; + zmk_keymap_layer_id_t layer = strtoul(next, &endptr, 10); + + if (*endptr != '\0') { + LOG_WRN("Invalid layer number: %s with endptr %s", next, endptr); + return -EINVAL; + } + + if (layer >= ZMK_KEYMAP_LAYERS_LEN) { + LOG_WRN("Found layer name for invalid layer ID %d", layer); + } + + int err = read_cb(cb_arg, zmk_keymap_layer_names[layer], + MIN(len, CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN - 1)); + if (err <= 0) { + LOG_ERR("Failed to handle keymap layer name from settings (err %d)", err); + return err; + } + } else if (settings_name_steq(name, "l", &next) && next) { + char *endptr; + uint8_t layer = strtoul(next, &endptr, 10); + if (*endptr != '/') { + LOG_WRN("Invalid layer number: %s with endptr %s", next, endptr); + return -EINVAL; + } + + uint8_t key_position = strtoul(endptr + 1, &endptr, 10); + + if (*endptr != '\0') { + LOG_WRN("Invalid key_position number: %s with endptr %s", next, endptr); + return -EINVAL; + } + + if (len > sizeof(struct zmk_behavior_binding_setting)) { + LOG_ERR("Too large binding setting size (got %d expected %d)", len, + sizeof(struct zmk_behavior_binding_setting)); + return -EINVAL; + } + + if (layer >= ZMK_KEYMAP_LAYERS_LEN) { + LOG_WRN("Layer %d is larger than max of %d", layer, ZMK_KEYMAP_LAYERS_LEN); + return -EINVAL; + } + + if (key_position >= ZMK_KEYMAP_LEN) { + LOG_WRN("Key position %d is larger than max of %d", key_position, ZMK_KEYMAP_LEN); + return -EINVAL; + } + + struct zmk_behavior_binding_setting binding_setting = {0}; + int err = read_cb(cb_arg, &binding_setting, len); + if (err <= 0) { + LOG_ERR("Failed to handle keymap binding from settings (err %d)", err); + return err; + } + + const char *name = + zmk_behavior_find_behavior_name_from_local_id(binding_setting.behavior_local_id); + + if (!name) { + LOG_WRN("Loaded device %d from settings but no device found by that local ID", + binding_setting.behavior_local_id); + } + + zmk_keymap[layer][key_position] = (struct zmk_behavior_binding) { +#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS) + .local_id = binding_setting.behavior_local_id, +#endif + .behavior_dev = name, .param1 = binding_setting.param1, + .param2 = binding_setting.param2, + }; + } +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + else if (settings_name_steq(name, "layer_order", &next) && !next) { + int err = + read_cb(cb_arg, settings_layer_orders, MIN(len, ARRAY_SIZE(settings_layer_orders))); + if (err <= 0) { + LOG_ERR("Failed to handle keymap layer orders from settings (err %d)", err); + return err; + } + + LOG_HEXDUMP_DBG(settings_layer_orders, ARRAY_SIZE(settings_layer_orders), + "Settings Layer Order"); + + memcpy(keymap_layer_orders, settings_layer_orders, + MIN(len, ARRAY_SIZE(settings_layer_orders))); + } +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + + return 0; +}; + +static int keymap_handle_commit(void) { +#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS) + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + for (int p = 0; p < ZMK_KEYMAP_LEN; p++) { + struct zmk_behavior_binding *binding = &zmk_keymap[l][p]; + + if (binding->local_id > 0 && !binding->behavior_dev) { + binding->behavior_dev = + zmk_behavior_find_behavior_name_from_local_id(binding->local_id); + + if (!binding->behavior_dev) { + LOG_ERR("Failed to finding device for local ID %d after settings load", + binding->local_id); + } + } + } + } +#endif + + return 0; +} + +SETTINGS_STATIC_HANDLER_DEFINE(keymap, "keymap", NULL, keymap_handle_set, keymap_handle_commit, + NULL); + +#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE) + +int keymap_init(void) { +#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING) + load_stock_keymap_layer_ordering(); +#endif + + return 0; +} + +SYS_INIT(keymap_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/physical_layouts.c b/app/src/physical_layouts.c index 16b13e710c9..00cfa29e780 100644 --- a/app/src/physical_layouts.c +++ b/app/src/physical_layouts.c @@ -72,9 +72,17 @@ struct position_map_entry { const uint32_t positions[ZMK_POS_MAP_LEN]; }; +#define ZMK_POS_MAP_LEN_CHECK(node_id) \ + BUILD_ASSERT(ZMK_POS_MAP_LEN == DT_PROP_LEN(node_id, positions), \ + "Position maps must all have the same number of entries") + +DT_FOREACH_CHILD_SEP(DT_INST(0, POS_MAP_COMPAT), ZMK_POS_MAP_LEN_CHECK, (;)); + #define ZMK_POS_MAP_ENTRY(node_id) \ { \ - .layout = &_CONCAT(_zmk_physical_layout_, DT_PHANDLE(node_id, physical_layout)), \ + .layout = COND_CODE_1( \ + DT_HAS_COMPAT_STATUS_OKAY(DT_PHANDLE(node_id, physical_layout)), \ + (&_CONCAT(_zmk_physical_layout_, DT_PHANDLE(node_id, physical_layout))), (NULL)), \ .positions = DT_PROP(node_id, positions), \ } @@ -275,13 +283,15 @@ int zmk_physical_layouts_save_selected(void) { int zmk_physical_layouts_revert_selected(void) { return zmk_physical_layouts_select_initial(); } -int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t *map) { +int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, size_t map_size, + uint32_t map[map_size]) { if (source >= ARRAY_SIZE(layouts) || dest >= ARRAY_SIZE(layouts)) { return -EINVAL; } const struct zmk_physical_layout *src_layout = layouts[source]; const struct zmk_physical_layout *dest_layout = layouts[dest]; + int max_kp = dest_layout->keys_len; #if HAVE_POS_MAP const struct position_map_entry *src_pos_map = NULL; @@ -296,11 +306,24 @@ int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t dest_pos_map = &positions_maps[pm]; } } + + // Maps can place items "off the end" of other layouts so they are + // preserved but not visible, so adjust our max here if that is being used. + if (src_pos_map && dest_pos_map) { + for (int mp = 0; mp < ZMK_POS_MAP_LEN; mp++) { + max_kp = + MAX(max_kp, MAX(src_pos_map->positions[mp] + 1, dest_pos_map->positions[mp] + 1)); + } + } #endif - memset(map, UINT32_MAX, dest_layout->keys_len); + if (map_size < max_kp) { + return -EINVAL; + } + + memset(map, UINT32_MAX, map_size); - for (int b = 0; b < dest_layout->keys_len; b++) { + for (int b = 0; b < max_kp; b++) { bool found = false; #if HAVE_POS_MAP @@ -329,13 +352,9 @@ int zmk_physical_layouts_get_position_map(uint8_t source, uint8_t dest, uint32_t } } #endif - - if (!found || map[b] >= src_layout->keys_len) { - map[b] = UINT32_MAX; - } } - return dest_layout->keys_len; + return max_kp; } #if IS_ENABLED(CONFIG_SETTINGS) diff --git a/app/src/studio/CMakeLists.txt b/app/src/studio/CMakeLists.txt index e8f0d49d261..a8417dd7688 100644 --- a/app/src/studio/CMakeLists.txt +++ b/app/src/studio/CMakeLists.txt @@ -3,6 +3,7 @@ zephyr_linker_sources(DATA_SECTIONS ../../include/linker/zmk-rpc-subsystems.ld) zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-handlers.ld) +zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-subsystem-settings-reset.ld) zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-event-mappers.ld) zephyr_linker_sources(SECTIONS ../../include/linker/zmk-rpc-transport.ld) @@ -11,5 +12,6 @@ target_sources(app PRIVATE rpc.c) target_sources(app PRIVATE core.c) target_sources(app PRIVATE behavior_subsystem.c) target_sources(app PRIVATE core_subsystem.c) +target_sources(app PRIVATE keymap_subsystem.c) target_sources_ifdef(CONFIG_ZMK_STUDIO_TRANSPORT_UART app PRIVATE uart_rpc_transport.c) target_sources_ifdef(CONFIG_ZMK_STUDIO_TRANSPORT_BLE app PRIVATE gatt_rpc_transport.c) \ No newline at end of file diff --git a/app/src/studio/Kconfig b/app/src/studio/Kconfig index ebe680bb8cc..d1315070e6d 100644 --- a/app/src/studio/Kconfig +++ b/app/src/studio/Kconfig @@ -41,6 +41,8 @@ menuconfig ZMK_STUDIO_RPC select ZMK_BEHAVIOR_METADATA select ZMK_BEHAVIOR_LOCAL_IDS select RING_BUFFER + select ZMK_KEYMAP_SETTINGS_STORAGE + select ZMK_KEYMAP_LAYER_REORDERING help Add firmware support for studio RPC protocol diff --git a/app/src/studio/core_subsystem.c b/app/src/studio/core_subsystem.c index 001aed9b9ca..2cdc9d7ce48 100644 --- a/app/src/studio/core_subsystem.c +++ b/app/src/studio/core_subsystem.c @@ -61,8 +61,21 @@ zmk_studio_Response get_lock_state(const zmk_studio_Request *req) { return CORE_RESPONSE(get_lock_state, resp); } +zmk_studio_Response reset_settings(const zmk_studio_Request *req) { + ZMK_RPC_SUBSYSTEM_SETTINGS_RESET_FOREACH(sub) { + int ret = sub->callback(); + if (ret < 0) { + LOG_ERR("Failed to reset settings: %d", ret); + return CORE_RESPONSE(reset_settings, false); + } + } + + return CORE_RESPONSE(reset_settings, true); +} + ZMK_RPC_SUBSYSTEM_HANDLER(core, get_device_info, ZMK_STUDIO_RPC_HANDLER_UNSECURED); ZMK_RPC_SUBSYSTEM_HANDLER(core, get_lock_state, ZMK_STUDIO_RPC_HANDLER_UNSECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(core, reset_settings, ZMK_STUDIO_RPC_HANDLER_SECURED); static int core_event_mapper(const zmk_event_t *eh, zmk_studio_Notification *n) { struct zmk_studio_core_lock_state_changed *lock_ev = as_zmk_studio_core_lock_state_changed(eh); diff --git a/app/src/studio/keymap_subsystem.c b/app/src/studio/keymap_subsystem.c new file mode 100644 index 00000000000..aa4b9799206 --- /dev/null +++ b/app/src/studio/keymap_subsystem.c @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +LOG_MODULE_DECLARE(zmk_studio, CONFIG_ZMK_STUDIO_LOG_LEVEL); + +#include + +#include +#include +#include +#include +#include + +#include + +ZMK_RPC_SUBSYSTEM(keymap) + +#define KEYMAP_RESPONSE(type, ...) ZMK_RPC_RESPONSE(keymap, type, __VA_ARGS__) +#define KEYMAP_NOTIFICATION(type, ...) ZMK_RPC_NOTIFICATION(keymap, type, __VA_ARGS__) + +static bool encode_layer_bindings(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { + const zmk_keymap_layer_id_t layer_id = *(uint8_t *)*arg; + + for (int b = 0; b < ZMK_KEYMAP_LEN; b++) { + const struct zmk_behavior_binding *binding = + zmk_keymap_get_layer_binding_at_idx(layer_id, b); + + zmk_keymap_BehaviorBinding bb = zmk_keymap_BehaviorBinding_init_zero; + + if (binding && binding->behavior_dev) { + bb.behavior_id = zmk_behavior_get_local_id(binding->behavior_dev); + bb.param1 = binding->param1; + bb.param2 = binding->param2; + } + + if (!pb_encode_tag_for_field(stream, field)) { + return false; + } + + if (!pb_encode_submessage(stream, &zmk_keymap_BehaviorBinding_msg, &bb)) { + return false; + } + } + + return true; +} + +static bool encode_layer_name(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { + const zmk_keymap_layer_index_t layer_idx = *(uint8_t *)*arg; + + const char *name = zmk_keymap_layer_name(layer_idx); + + if (!name) { + return true; + } + + if (!pb_encode_tag_for_field(stream, field)) { + return false; + } + + return pb_encode_string(stream, name, strlen(name)); +} + +static bool encode_keymap_layers(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { + for (zmk_keymap_layer_index_t l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + zmk_keymap_layer_id_t layer_id = zmk_keymap_layer_index_to_id(l); + + if (layer_id == UINT8_MAX) { + break; + } + + if (!pb_encode_tag_for_field(stream, field)) { + LOG_WRN("Failed to encode tag"); + return false; + } + + zmk_keymap_Layer layer = zmk_keymap_Layer_init_zero; + layer.id = layer_id; + + layer.name.funcs.encode = encode_layer_name; + layer.name.arg = &layer_id; + + layer.bindings.funcs.encode = encode_layer_bindings; + layer.bindings.arg = &layer_id; + + if (!pb_encode_submessage(stream, &zmk_keymap_Layer_msg, &layer)) { + LOG_WRN("Failed to encode layer submessage"); + return false; + } + } + + return true; +} + +zmk_studio_Response get_keymap(const zmk_studio_Request *req) { + zmk_keymap_Keymap resp = zmk_keymap_Keymap_init_zero; + + resp.layers.funcs.encode = encode_keymap_layers; + + resp.available_layers = 0; + + for (zmk_keymap_layer_index_t index = 0; index < ZMK_KEYMAP_LAYERS_LEN; index++) { + zmk_keymap_layer_id_t id = zmk_keymap_layer_index_to_id(index); + + if (id == UINT8_MAX) { + resp.available_layers = ZMK_KEYMAP_LAYERS_LEN - index; + break; + } + } + + return KEYMAP_RESPONSE(get_keymap, resp); +} + +zmk_studio_Response set_layer_binding(const zmk_studio_Request *req) { + const zmk_keymap_SetLayerBindingRequest *set_req = + &req->subsystem.keymap.request_type.set_layer_binding; + + zmk_behavior_local_id_t bid = set_req->binding.behavior_id; + + const char *behavior_name = zmk_behavior_find_behavior_name_from_local_id(bid); + + if (!behavior_name) { + return KEYMAP_RESPONSE( + set_layer_binding, + zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_INVALID_BEHAVIOR); + } + + struct zmk_behavior_binding binding = (struct zmk_behavior_binding){ + .behavior_dev = behavior_name, + .param1 = set_req->binding.param1, + .param2 = set_req->binding.param2, + }; + + int ret = zmk_behavior_validate_binding(&binding); + if (ret < 0) { + return KEYMAP_RESPONSE( + set_layer_binding, + zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_INVALID_PARAMETERS); + } + + ret = zmk_keymap_set_layer_binding_at_idx(set_req->layer_id, set_req->key_position, binding); + + if (ret < 0) { + LOG_WRN("Setting the binding failed with %d", ret); + switch (ret) { + case -EINVAL: + return KEYMAP_RESPONSE( + set_layer_binding, + zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_INVALID_LOCATION); + default: + return ZMK_RPC_SIMPLE_ERR(GENERIC); + } + } + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + + return KEYMAP_RESPONSE(set_layer_binding, + zmk_keymap_SetLayerBindingResponse_SET_LAYER_BINDING_RESP_OK); +} + +zmk_studio_Response check_unsaved_changes(const zmk_studio_Request *req) { + int layout_changes = zmk_physical_layouts_check_unsaved_selection(); + int keymap_changes = zmk_keymap_check_unsaved_changes(); + + return KEYMAP_RESPONSE(check_unsaved_changes, layout_changes > 0 || keymap_changes > 0); +} + +zmk_studio_Response save_changes(const zmk_studio_Request *req) { + int ret = zmk_physical_layouts_save_selected(); + + if (ret < 0) { + return ZMK_RPC_SIMPLE_ERR(GENERIC); + } + + ret = zmk_keymap_save_changes(); + if (ret < 0) { + return ZMK_RPC_SIMPLE_ERR(GENERIC); + } + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, false)}); + + return KEYMAP_RESPONSE(save_changes, true); +} + +zmk_studio_Response discard_changes(const zmk_studio_Request *req) { + int ret = zmk_physical_layouts_revert_selected(); + if (ret < 0) { + return ZMK_RPC_SIMPLE_ERR(GENERIC); + } + + ret = zmk_keymap_discard_changes(); + if (ret < 0) { + return ZMK_RPC_SIMPLE_ERR(GENERIC); + } + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, false)}); + + return KEYMAP_RESPONSE(discard_changes, true); +} + +static int keymap_settings_reset(void) { return zmk_keymap_reset_settings(); } + +ZMK_RPC_SUBSYSTEM_SETTINGS_RESET(keymap, keymap_settings_reset); + +static bool encode_layout_name(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { + struct zmk_physical_layout *layout = (struct zmk_physical_layout *)*arg; + + if (!layout->display_name) { + return true; + } + + if (!pb_encode_tag_for_field(stream, field)) { + LOG_WRN("Failed to encode tag"); + return false; + } + + pb_encode_string(stream, layout->display_name, strlen(layout->display_name)); + + return true; +} + +static bool encode_layout_keys(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { + struct zmk_physical_layout *layout = (struct zmk_physical_layout *)*arg; + + for (int kp = 0; kp < layout->keys_len; kp++) { + const struct zmk_key_physical_attrs *layout_kp = &layout->keys[kp]; + + if (!pb_encode_tag_for_field(stream, field)) { + LOG_WRN("Failed to encode tag"); + return false; + } + + zmk_keymap_KeyPhysicalAttrs layout_kp_msg = { + .width = layout_kp->width, + .height = layout_kp->height, + .x = layout_kp->x, + .y = layout_kp->y, + .r = layout_kp->r, + .rx = layout_kp->rx, + .ry = layout_kp->ry, + }; + + if (!pb_encode_submessage(stream, &zmk_keymap_KeyPhysicalAttrs_msg, &layout_kp_msg)) { + LOG_WRN("Failed to encode layout key position submessage"); + return false; + } + } + return true; +} + +static bool encode_layouts(pb_ostream_t *stream, const pb_field_t *field, void *const *arg) { + struct zmk_physical_layout const *const *layouts; + const size_t layout_count = zmk_physical_layouts_get_list(&layouts); + + for (int i = 0; i < layout_count; i++) { + const struct zmk_physical_layout *l = layouts[i]; + + if (!pb_encode_tag_for_field(stream, field)) { + LOG_WRN("Failed to encode tag"); + return false; + } + + zmk_keymap_PhysicalLayout layout = zmk_keymap_PhysicalLayout_init_zero; + + layout.name.funcs.encode = encode_layout_name; + layout.name.arg = l; + + layout.keys.funcs.encode = encode_layout_keys; + layout.keys.arg = l; + + if (!pb_encode_submessage(stream, &zmk_keymap_PhysicalLayout_msg, &layout)) { + LOG_WRN("Failed to encode layout submessage"); + return false; + } + } + + return true; +} + +zmk_studio_Response get_physical_layouts(const zmk_studio_Request *req) { + zmk_keymap_PhysicalLayouts resp = zmk_keymap_PhysicalLayouts_init_zero; + resp.active_layout_index = zmk_physical_layouts_get_selected(); + resp.layouts.funcs.encode = encode_layouts; + return KEYMAP_RESPONSE(get_physical_layouts, resp); +} + +static void migrate_keymap(const uint8_t old) { + int new = zmk_physical_layouts_get_selected(); + + uint32_t new_to_old_map[ZMK_KEYMAP_LEN]; + int layout_size = + zmk_physical_layouts_get_position_map(old, new, ZMK_KEYMAP_LEN, new_to_old_map); + + if (layout_size < 0) { + return; + } + + for (int l = 0; l < ZMK_KEYMAP_LAYERS_LEN; l++) { + struct zmk_behavior_binding new_layer[ZMK_KEYMAP_LEN]; + + for (int b = 0; b < layout_size; b++) { + uint32_t old_b = new_to_old_map[b]; + + if (old_b == UINT32_MAX) { + memset(&new_layer[b], 0, sizeof(struct zmk_behavior_binding)); + continue; + } + + const struct zmk_behavior_binding *binding = + zmk_keymap_get_layer_binding_at_idx(l, old_b); + + if (!binding) { + memset(&new_layer[b], 0, sizeof(struct zmk_behavior_binding)); + continue; + } + + memcpy(&new_layer[b], binding, sizeof(struct zmk_behavior_binding)); + } + + for (int b = 0; b < layout_size; b++) { + zmk_keymap_set_layer_binding_at_idx(l, b, new_layer[b]); + } + } + + // TODO: Migrate combos? +} + +zmk_studio_Response set_active_physical_layout(const zmk_studio_Request *req) { + uint8_t index = (uint8_t)req->subsystem.keymap.request_type.set_active_physical_layout; + int old = zmk_physical_layouts_get_selected(); + + zmk_keymap_SetActivePhysicalLayoutResponse resp = + zmk_keymap_SetActivePhysicalLayoutResponse_init_zero; + resp.which_result = zmk_keymap_SetActivePhysicalLayoutResponse_ok_tag; + resp.result.ok.layers.funcs.encode = encode_keymap_layers; + + if (old == index) { + return KEYMAP_RESPONSE(set_active_physical_layout, resp); + } + + int ret = zmk_physical_layouts_select(index); + if (ret >= 0) { + migrate_keymap(old); + } else { + resp.which_result = zmk_keymap_SetActivePhysicalLayoutResponse_err_tag; + resp.result.err = + zmk_keymap_SetActivePhysicalLayoutErrorCode_SET_ACTIVE_PHYSICAL_LAYOUT_ERR_GENERIC; + } + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + + return KEYMAP_RESPONSE(set_active_physical_layout, resp); +} + +zmk_studio_Response move_layer(const zmk_studio_Request *req) { + const zmk_keymap_MoveLayerRequest *move_req = &req->subsystem.keymap.request_type.move_layer; + + zmk_keymap_MoveLayerResponse resp = zmk_keymap_MoveLayerResponse_init_zero; + + int ret = zmk_keymap_move_layer(move_req->start_index, move_req->dest_index); + + if (ret >= 0) { + resp.which_result = zmk_keymap_SetActivePhysicalLayoutResponse_ok_tag; + resp.result.ok.layers.funcs.encode = encode_keymap_layers; + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + } else { + LOG_WRN("Failed to move layer: %d", ret); + resp.which_result = zmk_keymap_MoveLayerResponse_err_tag; + resp.result.err = zmk_keymap_MoveLayerErrorCode_MOVE_LAYER_ERR_GENERIC; + } + + return KEYMAP_RESPONSE(move_layer, resp); +} + +zmk_studio_Response add_layer(const zmk_studio_Request *req) { + // Use a static here to keep the value valid during serialization + static zmk_keymap_layer_id_t layer_id = 0; + + zmk_keymap_AddLayerResponse resp = zmk_keymap_AddLayerResponse_init_zero; + + int ret = zmk_keymap_add_layer(); + + if (ret >= 0) { + layer_id = zmk_keymap_layer_index_to_id(ret); + + resp.which_result = zmk_keymap_AddLayerResponse_ok_tag; + + resp.result.ok.index = ret; + + resp.result.ok.has_layer = true; + resp.result.ok.layer.id = layer_id; + + resp.result.ok.layer.name.funcs.encode = encode_layer_name; + resp.result.ok.layer.name.arg = &layer_id; + + resp.result.ok.layer.bindings.funcs.encode = encode_layer_bindings; + resp.result.ok.layer.bindings.arg = &layer_id; + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + } else { + LOG_WRN("Failed to add layer: %d", ret); + resp.which_result = zmk_keymap_AddLayerResponse_err_tag; + switch (ret) { + case -ENOSPC: + resp.result.err = zmk_keymap_AddLayerErrorCode_ADD_LAYER_ERR_NO_SPACE; + break; + default: + resp.result.err = zmk_keymap_AddLayerErrorCode_ADD_LAYER_ERR_GENERIC; + break; + } + } + + return KEYMAP_RESPONSE(add_layer, resp); +} + +zmk_studio_Response remove_layer(const zmk_studio_Request *req) { + const zmk_keymap_RemoveLayerRequest *rm_req = &req->subsystem.keymap.request_type.remove_layer; + + zmk_keymap_RemoveLayerResponse resp = zmk_keymap_RemoveLayerResponse_init_zero; + + int ret = zmk_keymap_remove_layer(rm_req->layer_index); + + if (ret >= 0) { + resp.which_result = zmk_keymap_RemoveLayerResponse_ok_tag; + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + } else { + LOG_WRN("Failed to rm layer: %d", ret); + resp.which_result = zmk_keymap_RemoveLayerResponse_err_tag; + switch (ret) { + case -EINVAL: + resp.result.err = zmk_keymap_RemoveLayerErrorCode_REMOVE_LAYER_ERR_INVALID_INDEX; + break; + default: + resp.result.err = zmk_keymap_RemoveLayerErrorCode_REMOVE_LAYER_ERR_GENERIC; + break; + } + } + + return KEYMAP_RESPONSE(remove_layer, resp); +} + +zmk_studio_Response restore_layer(const zmk_studio_Request *req) { + const zmk_keymap_RestoreLayerRequest *restore_req = + &req->subsystem.keymap.request_type.restore_layer; + + zmk_keymap_RestoreLayerResponse resp = zmk_keymap_RestoreLayerResponse_init_zero; + + int ret = zmk_keymap_restore_layer(restore_req->layer_id, restore_req->at_index); + + if (ret >= 0) { + resp.which_result = zmk_keymap_RemoveLayerResponse_ok_tag; + resp.result.ok.id = restore_req->layer_id; + + resp.result.ok.name.funcs.encode = encode_layer_name; + resp.result.ok.name.arg = &restore_req->layer_id; + + resp.result.ok.bindings.funcs.encode = encode_layer_bindings; + resp.result.ok.bindings.arg = &restore_req->layer_id; + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + } else { + LOG_WRN("Failed to restore layer: %d", ret); + resp.which_result = zmk_keymap_RestoreLayerResponse_err_tag; + switch (ret) { + case -EINVAL: + resp.result.err = zmk_keymap_RestoreLayerErrorCode_RESTORE_LAYER_ERR_INVALID_INDEX; + break; + default: + resp.result.err = zmk_keymap_RestoreLayerErrorCode_RESTORE_LAYER_ERR_GENERIC; + break; + } + } + + return KEYMAP_RESPONSE(restore_layer, resp); +} + +zmk_studio_Response set_layer_props(const zmk_studio_Request *req) { + const zmk_keymap_SetLayerPropsRequest *set_req = + &req->subsystem.keymap.request_type.set_layer_props; + + zmk_keymap_SetLayerPropsResponse resp = + zmk_keymap_SetLayerPropsResponse_SET_LAYER_PROPS_RESP_OK; + + if (strlen(set_req->name) <= 0) { + return KEYMAP_RESPONSE(set_layer_props, resp); + } + + int ret = zmk_keymap_set_layer_name(set_req->layer_id, set_req->name, strlen(set_req->name)); + + if (ret >= 0) { + + raise_zmk_studio_rpc_notification((struct zmk_studio_rpc_notification){ + .notification = KEYMAP_NOTIFICATION(unsaved_changes_status_changed, true)}); + } else { + LOG_WRN("Failed to set layer props: %d", ret); + switch (ret) { + case -EINVAL: + resp = zmk_keymap_SetLayerPropsResponse_SET_LAYER_PROPS_RESP_ERR_INVALID_ID; + break; + default: + resp = zmk_keymap_SetLayerPropsResponse_SET_LAYER_PROPS_RESP_ERR_GENERIC; + break; + } + } + + return KEYMAP_RESPONSE(set_layer_props, resp); +} + +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, get_keymap, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_layer_binding, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, check_unsaved_changes, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, save_changes, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, discard_changes, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, get_physical_layouts, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_active_physical_layout, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, move_layer, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, add_layer, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, remove_layer, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, restore_layer, ZMK_STUDIO_RPC_HANDLER_SECURED); +ZMK_RPC_SUBSYSTEM_HANDLER(keymap, set_layer_props, ZMK_STUDIO_RPC_HANDLER_SECURED); + +static int event_mapper(const zmk_event_t *eh, zmk_studio_Notification *n) { return 0; } + +ZMK_RPC_EVENT_MAPPER(keymap, event_mapper); diff --git a/app/src/studio/rpc.c b/app/src/studio/rpc.c index 3d5bfcd7a1a..8dfb025d5f8 100644 --- a/app/src/studio/rpc.c +++ b/app/src/studio/rpc.c @@ -245,7 +245,7 @@ static void refresh_selected_transport(void) { k_mutex_lock(&rpc_transport_mutex, K_FOREVER); if (selected_transport && selected_transport->transport == transport) { - return; + goto exit_refresh; } if (selected_transport) { @@ -272,6 +272,7 @@ static void refresh_selected_transport(void) { LOG_WRN("Failed to select a transport!"); } +exit_refresh: k_mutex_unlock(&rpc_transport_mutex); } diff --git a/app/tests/macros/press-mid-macro/keycode_events.snapshot b/app/tests/macros/press-mid-macro/keycode_events.snapshot index 0ec7ccb3cd6..28551b1ccd5 100644 --- a/app/tests/macros/press-mid-macro/keycode_events.snapshot +++ b/app/tests/macros/press-mid-macro/keycode_events.snapshot @@ -1,8 +1,8 @@ -pos_state: layer: 0 position: 0, binding name: abc_macro +pos_state: layer_id: 0 position: 0, binding name: abc_macro kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 -pos_state: layer: 0 position: 0, binding name: abc_macro -pos_state: layer: 0 position: 1, binding name: momentary_layer -pos_state: layer: 0 position: 1, binding name: momentary_layer +pos_state: layer_id: 0 position: 0, binding name: abc_macro +pos_state: layer_id: 0 position: 1, binding name: momentary_layer +pos_state: layer_id: 0 position: 1, binding name: momentary_layer kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/west.yml b/app/west.yml index ac4964f3706..5737bd004b1 100644 --- a/app/west.yml +++ b/app/west.yml @@ -34,7 +34,7 @@ manifest: path: modules/lib/nanopb remote: zephyrproject-rtos - name: zmk-studio-messages - revision: 42446798e357e8021c5202a01ea250a34a776e85 + revision: a79267a9661241a6603b6da3d2b3f71e8023a9d9 path: modules/msgs/zmk-studio-messages remote: zmkfirmware self: diff --git a/docs/docs/assets/hardware-integration/shift-register-daisy.png b/docs/docs/assets/hardware-integration/shift-register-daisy.png new file mode 100644 index 00000000000..db4031a66e2 Binary files /dev/null and b/docs/docs/assets/hardware-integration/shift-register-daisy.png differ diff --git a/docs/docs/config/studio.md b/docs/docs/config/studio.md new file mode 100644 index 00000000000..ddfb25df213 --- /dev/null +++ b/docs/docs/config/studio.md @@ -0,0 +1,41 @@ +--- +title: ZMK Studio Configuration +sidebar_label: ZMK Studio +--- + +:::warning[Alpha Feature] + +ZMK Studio is still in active development and the below information is for development purposes only. For up to date information, join the [ZMK Discord](https://zmk.dev/community/discord/invite) server and discuss in `#studio-development`. + +::: + +The following settings affect the ZMK Studio portions of ZMK. See the [ZMK Studio feature](../features/studio.md) for more information on enabling and building with ZMK Studio enabled. + +See [Configuration Overview](index.md) for instructions on how to change these settings. + +## Kconfig + +Definition file: [zmk/app/src/studio/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/src/studio/Kconfig) + +### Keymaps + +| Config | Type | Description | Default | +| -------------------------------------- | ---- | --------------------------------------- | ------- | +| `CONFIG_ZMK_KEYMAP_LAYER_NAME_MAX_LEN` | int | Max allowable keymap layer display name | 20 | + +### Locking + +| Config | Type | Description | Default | +| ----------------------------------------- | ---- | ----------------------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_STUDIO_LOCKING` | bool | Enable/disable locking for ZMK Studio | y | +| `CONFIG_ZMK_STUDIO_LOCK_IDLE_TIMEOUT_SEC` | int | Seconds of inactivity in ZMK Studio before automatically locking | 500 | +| `CONFIG_ZMK_STUDIO_LOCK_ON_DISCONNECT` | bool | Whether to automatically lock again whenever ZMK Studio disconnects from the device | y | + +### Transport/Protocol Details + +| Config | Type | Description | Default | +| ---------------------------------------------- | ---- | ----------------------------------------------------------------------------- | ------- | +| `CONFIG_ZMK_STUDIO_TRANSPORT_BLE_PREF_LATENCY` | int | Lower latency to request while ZMK Studio is active to improve responsiveness | 10 | +| `CONFIG_ZMK_STUDIO_RPC_THREAD_STACK_SIZE` | int | Stack size for the dedicated RPC thread | 1800 | +| `CONFIG_ZMK_STUDIO_RPC_RX_BUF_SIZE` | int | Number of bytes available for buffering incoming messages | 30 | +| `CONFIG_ZMK_STUDIO_RPC_TX_BUF_SIZE` | int | Number of bytes available for buffering outgoing messages | 64 | diff --git a/docs/docs/development/hardware-integration/shift-registers.md b/docs/docs/development/hardware-integration/shift-registers.md new file mode 100644 index 00000000000..0b575bc584a --- /dev/null +++ b/docs/docs/development/hardware-integration/shift-registers.md @@ -0,0 +1,151 @@ +--- +title: Configuring Shift Registers +sidebar_label: Shift Registers +--- + +Shift registers are the recommended method of adding additional GPIO pins to MCUs and boards, when a standard matrix results in an insufficient number of keys. They are recommended because they simultaneously have very low power consumption and are quite cheap. This page serves as a (brief) introduction to shift registers, how to use them in your design, and how to configure ZMK to use them correctly. + +:::note +This page assumes that you are using a SIPO shift register with the part number 74HC595. Other shift registers can work as well but this is the most commonly used one. +::: + +:::tip +To understand how shift registers work, we recommend reading through ["How does the 74HC595 Shift Register work?"](https://lastminuteengineers.com/74hc595-shift-register-arduino-tutorial/#how-does-the-74hc595-shift-register-work). +::: + +## Design Guidelines + +The shift register output pins should act as MCU outputs in your design. All MCU inputs should remain connected directly to MCU/board pins. This is to allow the inputs to trigger "interrupts" on the MCU/board, upon which it will begin scanning the keys. Using a shift register for MCU inputs is also possible, but requires you to use a PISO shift register and will harm your battery life. Note that a [direct kscan](../../config/kscan.md#direct-gpio-driver) keyboard does not have any MCU output pins, but a diodeless keyboard is still possible by making use of a single row pin and using the [matrix kscan](../../config/kscan.md#matrix-driver) driver. + +:::info +In a diode matrix, MCU output pins are those connected to the [anodes of your diodes](https://learn.sparkfun.com/tutorials/diodes/all#ideal-diodes). You most likely will need to rearrange your matrix to maximize the use of shift register output pins, in order to reduce the total number of GPIO pins connected to your MCU. For example, a 9 column 5 row `col2row` matrix could be rearranged to use 16 columns and 3 rows. +::: + +You will want to make sure that the data and clock pins of the shift register are connected to high frequency/SPI-capable pins on your MCU. Make sure that these lie on the same SPI bus for your microcontroller, if applicable -- for instance RP2040 controllers require this, while nRF52840 ones do not. It is generally recommended that you use the pre-defined pins for SPI, if your board comes with them. + +ZMK allows you to daisy-chain up to four shift registers. Below is a fragment of a schematic showing two shift registers that are daisy-chained. + +![A fragment of a schematic featuring two shift registers daisy chained together.](../../assets/hardware-integration/shift-register-daisy.png) + +## Configuration + +In ZMK, the SPI bus of your MCU is used to communicate with shift registers, using MOSI for SIPO shift registers and MISO for PISO shift registers. Thus you will first need to ensure that your board has SPI configured accordingly. Some boards, such as Seeed Studio's Xiao series, already has particular pins defined and configured for SPI (these can be changed if the MCU allows for alternative selections of SPI pins). Others, such as the nice!nano or any custom board, will need to be configured by you manually. Shift registers can share the SPI bus with other devices with no issues. + +### Configuring the SPI bus + +Configuring the pins directly varies depending on your architecture. Presented are methods for overwriting the default SPI bus definitions for boards running the nRF52840 MCU. Alternative MCUs will be similar; refer to the [Zephyr documentation](https://docs.zephyrproject.org/3.5.0/hardware/pinctrl/index.html) for these. Also refer to [Zephyr documentation](https://docs.zephyrproject.org/3.5.0/hardware/pinctrl/index.html) if you are defining a new bus rather than reconfiguring an existing one. + +:::info +This section can be skipped if you are using the default pins for SPI of a board, e.g. for the Seeed Studio Xiao the pin D8 for the clock signal and D10 for the data signal. However, if you are not making use of the MISO pin and wish to use said pin for alternative purposes, you will need to override the definition. +::: + +First, identify the high frequency pins that you are using for SPI by their port and pin number. This example will assume that: + +- Your SPI clock pin is port 1, pin 11 +- Your SPI MOSI pin is port 1, pin 12 + +Next, you'll need to identify the node label of the SPI bus you're overwriting. Look through your board's devicetree files, following the includes, for a node with `compatible = "nordic,nrf-spi";`. This node should have some properties marked as `pinctrl-X`, where `X` is a number. For example, you might find a node like below: + +```dts title="boards/arm/seeeduino_xiao_ble/seeeduino_xiao_ble.dts" +&spi2 { + compatible = "nordic,nrf-spi"; + pinctrl-0 = <&spi2_default>; + pinctrl-1 = <&spi2_sleep>; + pinctrl-names = "default", "sleep"; +}; +``` + +You will need to overwrite the pinctrl nodes to use your desired pins. Look through the devicetree files once again, this time looking for `spi2_default` and `spi2_sleep` (or the equivalently named nodes for your board). You should find nodes that look similar to below: + +```dts title="boards/arm/seeeduino_xiao_ble/seeeduino_xiao_ble-pinctrl.dtsi" +spi2_default: spi2_default { + group1 { + psels = , + , + ; + }; +}; + +spi2_sleep: spi2_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; +}; +``` + +Overwrite the pin definitions like so: + +```dts +&spi2_default { + group1 { + psels = , + ; + }; +}; + +&spi2_sleep { + group1 { + psels = , + ; + }; +}; +``` + +Note that for convenience, ZMK gives the `spi2` node of the Seeed Studio XIAO series the label `xiao_spi`. + +:::tip +If you are making a shield, add a `/boards/.overlay` file rather than editing the board's files directly. This will then be included in your board's definition when you build with your shield. +::: + +### Enable SPI + +Add the following line to `.defconfig`, inside of your device's `if` block: + +```kconfig title=".defconfig" +config SPI + default y +``` + +### Shift Register SPI Device + +To add your shift register as a SPI device, you'll need to overwrite your board's SPI configuration. For example, if your SPI bus has the node label `xiao_spi`, then you would add the following to your `.overlay`: + +```dts title=".overlay" +&xiao_spi { + status = "okay"; + cs-gpios = <&xiao_d 9 GPIO_ACTIVE_LOW>; + shifter: 595@0 { + compatible = "zmk,gpio-595"; + status = "okay"; + gpio-controller; + spi-max-frequency = <200000>; + reg = <0>; + #gpio-cells = <2>; + ngpios = <8>; + }; +}; +``` + +If there is more than one device on the SPI bus, you will need to add additional pins to the `cs-gpios` phandle array - one for each device. The `@0` number marks the index of the `cs-gpios` pin used to control a device. If you have daisy chained multiple shift registers, you'll also want to increase the number of GPIOs that the shift register provides by editing the `ngpios` node - set this to your number of output pins (should be one of 8, 16, 24, 32). You may also need to increase `spi-max-frequency` to a higher value if you have daisy chained shift registers, otherwise quick key presses may on occasion not trigger. + +### Using Shift Register Pins In Kscan + +Once all of this is set up, you can refer to pins from the shift register using `&shifter X` where X is the pin number. Use this to define your kscan, for example: + +```dts title=".overlay" +kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + diode-direction = "col2row"; + col-gpios + = <&shifter 7 GPIO_ACTIVE_HIGH> + , <&shifter 6 GPIO_ACTIVE_HIGH> + , <&shifter 5 GPIO_ACTIVE_HIGH> + , <&shifter 4 GPIO_ACTIVE_HIGH> + , <&shifter 3 GPIO_ACTIVE_HIGH> + , <&shifter 2 GPIO_ACTIVE_HIGH> + ; +}; +``` diff --git a/docs/docs/development/hardware-integration/studio-setup.md b/docs/docs/development/hardware-integration/studio-setup.md new file mode 100644 index 00000000000..dfa8002037c --- /dev/null +++ b/docs/docs/development/hardware-integration/studio-setup.md @@ -0,0 +1,140 @@ +--- +title: ZMK Studio Setup +--- + +:::warning[Alpha Feature] + +ZMK Studio support is in alpha. Although best efforts are being made, backwards compatibility during active development is not guaranteed. + +::: + +This guide will walk you through enabling ZMK Studio support for a keyboard. + +The main additional pieces needed for ZMK Studio support involve additional metadata needed in order +to properly to display the physical layouts available for the particular keyboard. + +# Physical Layout Positions + +Physical layouts are described as part of the [new shield guide](./new-shield.mdx#physical-layout) with the exception of the `keys` property that is required for ZMK Studio support. This is used to describe the physical attributes of each key position present in that layout and its items are listed in the same order as keymap bindings, matrix transforms, etc. The properties available are: + +| Property | Type | Description | Unit | +| ---------- | -------- | ------------------------------------ | ------------------------------------------------------- | +| Width | int (>0) | Key(cap) width | [centi-](https://en.wikipedia.org/wiki/Centi-)"keyunit" | +| Height | int (>0) | Key(cap) height | [centi-](https://en.wikipedia.org/wiki/Centi-)"keyunit" | +| X | uint | Key X position (top-left point) | [centi-](https://en.wikipedia.org/wiki/Centi-)"keyunit" | +| Y | uint | Key Y position (top-left point) | [centi-](https://en.wikipedia.org/wiki/Centi-)"keyunit" | +| Rotation | int | Key rotation (positive => clockwise) | [centi-](https://en.wikipedia.org/wiki/Centi-)degree | +| Rotation X | int | Rotation origin X position | [centi-](https://en.wikipedia.org/wiki/Centi-)"keyunit" | +| Rotation Y | int | Rotation origin Y position | [centi-](https://en.wikipedia.org/wiki/Centi-)"keyunit" | + +:::note +You can specify negative values in devicetree using parentheses around it, e.g. `(-3000)` for a 30 degree counterclockwise rotation. +::: + +## Header Include + +To pull in the necessary definition for creating physical layouts, a new include should be added to the top of the devicetree file: + +``` +#include +``` + +## Example + +Here is an example physical layout for a 2x2 macropad: + +```dts + macropad_physical_layout: macropad_physical_layout { + compatible = "zmk,physical-layout"; + display-name = "Macro Pad"; + + keys // w h x y rot rx ry + = <&key_physical_attrs 100 100 0 0 0 0 0> + , <&key_physical_attrs 100 100 100 0 0 0 0> + , <&key_physical_attrs 100 100 0 100 0 0 0> + , <&key_physical_attrs 100 100 100 100 0 0 0> + ; + }; +``` + +# Position Map + +When switching between layouts with ZMK Studio, the keymap of the previously selected layout is used to populate the keymap in the new layout. To determine which keymap entry maps to which entry in the new layout, keys between the two layouts that share the exact same physical attributes are matched. + +However, keys between layouts might not be in exactly the same positions, in which case a position map can be used. The position map includes a sequence for every relevant layout, and the corresponding entries in `positions` property will be used to determine the mapping between layouts. By default, the physical attribute matching behavior will be used as a fallback for positions not specified in the map, but the `complete` property can be added to the map to specify that no matching fallback should occur. + +:::info + +Key positions in the maps are numbered like the keys in your keymap, starting at 0. So the first position in the layout is position `0`, the next key position is `1`, etc. + +::: + +## Examples + +### Basic Map + +For example, the following position map correctly maps the 5-column and 6-column Corne keymap layouts. + +```dts + foostan_corne_position_map { + compatible = "zmk,physical-layout-position-map"; + + complete; + + twelve { + physical-layout = <&foostan_corne_6col_layout>; + positions + = < 1 2 3 4 5 6 7 8 9 10> + , <13 14 15 16 17 18 19 20 21 22> + , <25 26 27 28 29 30 31 32 33 34> + , < 36 37 38 39 40 41 >; + }; + + ten { + physical-layout = <&foostan_corne_5col_layout>; + positions + = < 0 1 2 3 4 5 6 7 8 9> + , <10 11 12 13 14 15 16 17 18 19> + , <20 21 22 23 24 25 26 27 28 29> + , < 30 31 32 33 34 35 >; + }; + }; +``` + +The first entries in the two mappings have values `1` and `0` respectively, which means that position `1` in the 6-column layout will map to position `0` in the 5-column layout, the second entries show that position `2` in the 6-column layout corresponds to position `1` in the 5-column layout, etc. + +### Full Preserving Map + +The above basic example has one major downside. Because the keys on the outer columns of the 6-column layout aren't mapped into any locations in the 5-column layout, when a user switches to the 5-column layout and then back to the 6-column layout, the bindings for those outer columns will have been lost/dropped at the first step. + +In order to preserve those bindings that are in "missing" keys in other layouts, we can include those locations in the map, but map them "off the end" of the smaller layout key positions. + +Here is a fixed up Corne mapping: + +```dts + foostan_corne_position_map { + compatible = "zmk,physical-layout-position-map"; + + complete; + + twelve { + physical-layout = <&foostan_corne_6col_layout>; + positions + = < 0 1 2 3 4 5 6 7 8 9 10 11> + , <12 13 14 15 16 17 18 19 20 21 22 23> + , <24 25 26 27 28 29 30 31 32 33 34 35> + , < 36 37 38 39 40 41 >; + }; + + ten { + physical-layout = <&foostan_corne_5col_layout>; + positions + = <36 0 1 2 3 4 5 6 7 8 9 37> + , <38 10 11 12 13 14 15 16 17 18 19 39> + , <40 20 21 22 23 24 25 26 27 28 29 41> + , < 30 31 32 33 34 35 >; + }; + }; +``` + +Notice how the outer column positions in the 6-column layout are mapped to positions 36, 37, etc. in the 5-column layout. The 5-column layout only uses key positions up to 35, so those bindings in the outer columns will get migrated into the "extra space" that is ignored by the smaller layout, preserved to get mapped back in place when the user switches back. diff --git a/docs/docs/development/studio-rpc-protocol.md b/docs/docs/development/studio-rpc-protocol.md index da737a131d7..5cfafbba72c 100644 --- a/docs/docs/development/studio-rpc-protocol.md +++ b/docs/docs/development/studio-rpc-protocol.md @@ -1,5 +1,5 @@ --- -title: Studio RPC Protocol +title: ZMK Studio RPC Protocol --- :::warning[Alpha Feature] @@ -20,13 +20,13 @@ The protocol consists of [protocol buffer](https://protobuf.dev/programming-guid ## Protobuf Messages -The messages for ZMK Studio are defined in a dedicated [zmk-studio-messages](https://github.com/zmkfirmware/zmk-studio-messages) repository. Fundamentally, the [`Request`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L11) message is used to send any requests from the Studio client to the ZMK device, and the [`Response`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L21) messages are sent from the ZMK device to the Studio client. +The messages for ZMK Studio are defined in a dedicated [zmk-studio-messages](https://github.com/zmkfirmware/zmk-studio-messages) repository. Fundamentally, the [`Request`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L11) message is used to send any requests from the ZMK Studio client to the ZMK device, and the [`Response`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L21) messages are sent from the ZMK device to the Studio client. -Responses can either be [`RequestResponses`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L28) that are sent in response to an incoming `Request` or a [`Notification`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L38) which is sent at any point from the ZMK device to the Studio client to inform the client about state changes on the device, e.g. that the device is unlocked. +Responses can either be [`RequestResponses`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L28) that are sent in response to an incoming `Request` or a [`Notification`](https://github.com/zmkfirmware/zmk-studio-messages/blob/main/proto/zmk/studio.proto#L38) which is sent at any point from the ZMK device to the ZMK Studio client to inform the client about state changes on the device, e.g. that the device is unlocked. ## Message Framing -Studio uses a simple framing protocol to easily identify the start and end of a given message, with basic escaping to allow for unrestricted content. +ZMK Studio uses a simple framing protocol to easily identify the start and end of a given message, with basic escaping to allow for unrestricted content. The following special bytes are used for the framing protocol: @@ -136,7 +136,7 @@ Two transports are available right now, over USB or Bluetooth connections. ### USB (Serial) -The USB transport is actually a basic serial/UART transport, that happens to use the CDC/ACM USB class for a serial connection. Framed messages are sent between Studio client and ZMK device using simple UART transmission. +The USB transport is actually a basic serial/UART transport, that happens to use the CDC/ACM USB class for a serial connection. Framed messages are sent between ZMK Studio client and ZMK device using simple UART transmission. ### Bluetooth (GATT) diff --git a/docs/docs/features/studio.md b/docs/docs/features/studio.md new file mode 100644 index 00000000000..f8d4059b957 --- /dev/null +++ b/docs/docs/features/studio.md @@ -0,0 +1,111 @@ +--- +title: ZMK Studio +--- + +:::warning[Alpha Feature] + +ZMK Studio support is in alpha. Although best efforts are being made, keeping compatibility during active development is not guaranteed. + +::: + +ZMK Studio provides runtime update functionality to ZMK powered devices, allowing users to change their keymap layers without flashing new firmware to their keyboards. Studio is still under active development, and is not yet ready for casual end user use. + +## Building + +Building for ZMK Studio involves two main additional items. + +- Build with the `studio-rpc-usb-uart` snippet to enable the endpoint used for ZMK Studio communication over USB. +- Enable the `ZMK_STUDIO` Kconfig setting. + +### GitHub Actions + +First add a `studio-rpc-usb-uart` to the `snippet` property of your build configuration. For a split keyboard, you should do this _only_ for your central/left side, e.g.: + +``` +--- +include: + - board: nice_nano_v2 + shield: corne_left + snippet: studio-rpc-usb-uart + - board: nice_nano_v2 + shield: corne_right +``` + +Next, enable the `ZMK_STUDIO` Kconfig symbol, for example by adding the following line to your .conf file: + +``` +CONFIG_ZMK_STUDIO=y +``` + +### Local Build + +When building locally, use the `-S` parameter to include the `studio-rpc-usb-uart` snippet. Instead of adding it to your config file, you can also append the `ZMK_STUDIO` Kconfig as an additional CMake argument, e.g.: + +```bash +west build -d build/cl_studio -b nice_nano_v2 \ + -S studio-rpc-usb-uart -- -DSHIELD=corne_left -DCONFIG_ZMK_STUDIO=y +``` + +## Including Unreferenced Behaviors + +Normally, ZMK will only build and include behaviors that are referenced by your keymap and unused behavior will be skipped. However, ZMK Studio builds using the `studio-rpc-usb-uart` snippet will automatically define the `ZMK_BEHAVIORS_KEEP_ALL` value, which changes the approach and builds all possible behaviors into the firmware. This lets those behaviors be used in ZMK Studio. + +A few controls are available to override this behavior for fine-grained control of what behaviors are built. Behaviors can be kept or omitted by defining certain values in the top of your keymap file, _before_ the standard `behaviors.dtsi` file is included. + +By convention, the defines used to keep/omit a given behavior are typically upper-cased versions of the behavior label, e.g. for the `&kt` behavior, the suffix to use would be `_KT`. + +### Omit Specific Behaviors + +You can omit a specific behaviors by defining a variable like `ZMK_BEHAVIORS_OMIT_KT` at the top of your keymap: + +```dts +#define ZMK_BEHAVIORS_OMIT_KT + +#include +``` + +### Keep Only Selective Behaviors + +To override the default "keep all" functionality, you can undefine the `ZMK_BEHAVIORS_KEEP_ALL` flag, and then keep only specific behaviors with a flag like `ZMK_BEHAVIORS_KEEP_KT`, e.g.: + +```dts +#undef ZMK_BEHAVIORS_KEEP_ALL + +#define ZMK_BEHAVIORS_KEEP_SK +#define ZMK_BEHAVIORS_KEEP_MT +#define ZMK_BEHAVIORS_KEEP_KT + +#include +``` + +## Including Extra Layers + +By default, a build with ZMK Studio enabled will only allow as many layers as are defined in your standard keymap. To make additional layers available for use through ZMK Studio, you simply add new empty layers to your keymap with a status of `reserved`, e.g.: + +```dts +/ { + keymap { + compatible = "zmk,keymap"; + + base { + display-name = "Base"; + bindings = // etc. + }; + + fn_layer { + display-name = "Fn"; + bindings = // etc. + }; + + extra1 { + status = "reserved"; + }; + + extra2 { + status = "reserved"; + }; + } +} +``` + +The reserved layers will be ignored during regular ZMK builds but will become available for ZMK Studio enabled builds. diff --git a/docs/docs/keymaps/behaviors/index.mdx b/docs/docs/keymaps/behaviors/index.mdx index 64bbea793b7..c876beb111e 100644 --- a/docs/docs/keymaps/behaviors/index.mdx +++ b/docs/docs/keymaps/behaviors/index.mdx @@ -74,6 +74,12 @@ Below is a summary of pre-defined behavior bindings and user-definable behaviors | `&ext_power` | [Power management](power.md#behavior-binding) | Allows enabling or disabling the VCC power output to save power | | `&soft_off` | [Soft off](soft-off.md#behavior-binding) | Turns the keyboard off. | +## ZMK Studio Behaviors + +| Binding | Behavior | Description | +| ---------------- | ------------------------------------------------------ | --------------------------------------------------------- | +| `&studio_unlock` | [ZMK Studio Unlock](studio-unlock.md#behavior-binding) | Unlocks the device so that ZMK Studio UI can make changes | + ## User-Defined Behaviors | Behavior | Description | diff --git a/docs/docs/keymaps/behaviors/studio-unlock.md b/docs/docs/keymaps/behaviors/studio-unlock.md new file mode 100644 index 00000000000..d6e87b835dc --- /dev/null +++ b/docs/docs/keymaps/behaviors/studio-unlock.md @@ -0,0 +1,25 @@ +--- +title: ZMK Studio Unlock Behavior +sidebar_label: ZMK Studio Unlock +--- + +:::warning +ZMK Studio is still in active development. This behavior is documented in preparation for its general availability. +::: + +## Summary + +## ZMK Studio Unlock + +The ZMK Studio unlock behavior is used to grant [ZMK Studio](../../features/studio.md) access to make changes to your ZMK device. The device will remain unlocked until a certain amount of time of inactivity in ZMK Studio, or on disconnect. Those trigger events for relocking can be configured with [studio configuration](../../config/studio.md). + +### Behavior Binding + +- Reference: `&studio_unlock` +- Parameters: None + +Example: + +```dts +&studio_unlock +``` diff --git a/docs/docs/keymaps/index.mdx b/docs/docs/keymaps/index.mdx index 2d3e204f9d0..0409cecb082 100644 --- a/docs/docs/keymaps/index.mdx +++ b/docs/docs/keymaps/index.mdx @@ -145,6 +145,7 @@ Each layer should have: 1. A `bindings` property this will be a list of [behavior bindings](behaviors/index.mdx), one for each key position for the keyboard. 1. (Optional) A `sensor-bindings` property that will be a list of behavior bindings for each sensor on the keyboard. (Currently, only encoders are supported as sensor hardware, but in the future devices like trackpoints would be supported the same way) +1. (Optional) A `display-name` property that is a string used by certain features, such as the layer status display widget. ### Multiple Layers diff --git a/docs/sidebars.js b/docs/sidebars.js index da619e5ec45..8825746f451 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -41,6 +41,7 @@ module.exports = { "features/displays", "features/backlight", "features/underglow", + "features/studio", ], }, { @@ -83,6 +84,7 @@ module.exports = { "keymaps/behaviors/backlight", "keymaps/behaviors/power", "keymaps/behaviors/soft-off", + "keymaps/behaviors/studio-unlock", ], }, "keymaps/modifiers", @@ -112,6 +114,7 @@ module.exports = { "config/power", "config/underglow", "config/system", + "config/studio", ], }, { @@ -124,6 +127,8 @@ module.exports = { "development/hardware-integration/new-shield", "development/hardware-integration/hardware-metadata-files", "development/hardware-integration/boards-shields-keymaps", + "development/hardware-integration/studio-setup", + "development/hardware-integration/shift-registers", ], }, {