diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 25f6c6cd..0d547fbe 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -51,15 +51,18 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c) target_sources(app PRIVATE src/behaviors/behavior_caps_word.c) target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c) + target_sources(app PRIVATE src/behaviors/behavior_macro.c) target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c) target_sources(app PRIVATE src/behaviors/behavior_outputs.c) + target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) target_sources(app PRIVATE src/behaviors/behavior_to_layer.c) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) target_sources(app PRIVATE src/combo.c) + target_sources(app PRIVATE src/behavior_queue.c) target_sources(app PRIVATE src/conditional_layer.c) target_sources(app PRIVATE src/keymap.c) endif() diff --git a/app/Kconfig b/app/Kconfig index 1c9f929d..81637336 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -410,6 +410,14 @@ config ZMK_COMBO_MAX_KEYS_PER_COMBO #Combo options endmenu +menu "Behavior Options" + +config ZMK_BEHAVIORS_QUEUE_SIZE + int "Maximum number of behaviors to allow queueing from a macro or other complex behavior" + default 64 + +endmenu + menu "Advanced" menu "Initialization Priorities" diff --git a/app/boards/arm/bdn9/bdn9_rev2_defconfig b/app/boards/arm/bdn9/bdn9_rev2_defconfig index 91f54eb4..31395716 100644 --- a/app/boards/arm/bdn9/bdn9_rev2_defconfig +++ b/app/boards/arm/bdn9/bdn9_rev2_defconfig @@ -11,6 +11,9 @@ CONFIG_FPU=y # enable GPIO CONFIG_GPIO=y +# Needed for matrix to properly work +CONFIG_ZMK_KSCAN_DIRECT_POLLING=y + # Enable pinmux CONFIG_PINMUX=y diff --git a/app/boards/arm/bt60/bt60_v1.dts b/app/boards/arm/bt60/bt60_v1.dts index 83da2c07..8b2f0cb4 100644 --- a/app/boards/arm/bt60/bt60_v1.dts +++ b/app/boards/arm/bt60/bt60_v1.dts @@ -22,7 +22,7 @@ RC(0,0) 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(0,11) RC(0,12) RC(0,13) RC(1,0) 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) RC(1,11) RC(1,12) RC(1,13) 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) RC(2,10) RC(2,11) RC(2,13) - RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) + RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(4,0) RC(4,1) RC(4,2) RC(4,6) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) >; }; diff --git a/app/boards/interconnects/pro_micro/pro_micro.zmk.yml b/app/boards/interconnects/pro_micro/pro_micro.zmk.yml index 6992593c..78aa14a1 100644 --- a/app/boards/interconnects/pro_micro/pro_micro.zmk.yml +++ b/app/boards/interconnects/pro_micro/pro_micro.zmk.yml @@ -8,3 +8,7 @@ description: | The SparkFun Pro Micro grew popular as a low cost ATmega32U4 board with sufficient GPIO and peripherals to work for many keyboard needs. Since the original Pro Micro, many pin compatible boards have appeared, with various changes or improvements, such as the Elite-C w/ USB-C, nice!nano with nRF52840 wireless. + + Note: ZMK doesn't support boards with AVR 8-bit processors, such as the ATmega32U4, because Zephyr™ only + supports 32-bit and 64-bit platforms. As a result, controllers like the SparkFun Pro Micro and the Elite-C + are *not* supported by ZMK. diff --git a/app/boards/shields/bat43/Kconfig.defconfig b/app/boards/shields/bat43/Kconfig.defconfig new file mode 100644 index 00000000..43de1fa8 --- /dev/null +++ b/app/boards/shields/bat43/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_BAT43 + +config ZMK_KEYBOARD_NAME + default "Bat43" + +endif diff --git a/app/boards/shields/bat43/Kconfig.shield b/app/boards/shields/bat43/Kconfig.shield new file mode 100644 index 00000000..10ee88ce --- /dev/null +++ b/app/boards/shields/bat43/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_BAT43 + def_bool $(shields_list_contains,bat43) diff --git a/app/boards/shields/bat43/bat43.keymap b/app/boards/shields/bat43/bat43.keymap new file mode 100644 index 00000000..0f7e2d55 --- /dev/null +++ b/app/boards/shields/bat43/bat43.keymap @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define LOWER 1 +#define RAISE 2 + +#define L_SPC < LOWER SPACE +#define R_RET < RAISE RET + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < +&kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp MINUS +&kp TAB &kp A &kp S &kp D &kp F &kp G &kp BSPC &kp H &kp J &kp K &kp L &kp SEMI &kp RSHFT +&kp LCTRL &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp LANG2 L_SPC R_RET &kp LANG1 &kp RALT + &bt BT_CLR &out OUT_TOG &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 + >; + }; + lower_layer { + bindings = < +&trans &none &none &none &none &none &none &kp EQUAL &kp PLUS &kp STAR &kp PRCNT &trans +&trans &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &trans &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &trans +&trans &none &none &none &none &none &none &none &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans + >; + }; + raise_layer { + bindings = < +&trans &kp BSLH &kp EXCL &kp AMPS &kp PIPE &none &none &kp EQUAL &kp PLUS &kp STAR &kp PRCNT &trans +&trans &kp HASH &kp GRAVE &kp DQT &kp SQT &kp TILDE &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &kp DLLR &trans +&trans &none &none &kp LBRC &kp LBKT &kp LPAR &kp RPAR &kp RBKT &kp RBRC &kp AT &kp CARET &trans + &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/bat43/bat43.overlay b/app/boards/shields/bat43/bat43.overlay new file mode 100644 index 00000000..fc906e0f --- /dev/null +++ b/app/boards/shields/bat43/bat43.overlay @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <6>; + rows = <7>; + + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(3,0) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) RC(6,5) + RC(3,3) RC(3,4) RC(3,5) RC(7,0) RC(7,1) RC(7,2) + RC(7,5) RC(7,4) RC(7,3) RC(3,1) RC(3,2) + >; + }; + + kscan0: kscan_0 { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 9 GPIO_ACTIVE_HIGH> + , <&pro_micro 8 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&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)> + , <&pro_micro 18 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 19 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/bat43/bat43.zmk.yml b/app/boards/shields/bat43/bat43.zmk.yml new file mode 100644 index 00000000..a84bf862 --- /dev/null +++ b/app/boards/shields/bat43/bat43.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: bat43 +name: BAT43 +type: shield +url: https://kbd.dailycraft.jp/bat43/ +requires: [pro_micro] +features: + - keys diff --git a/app/boards/shields/elephant42/Kconfig.defconfig b/app/boards/shields/elephant42/Kconfig.defconfig new file mode 100644 index 00000000..db2fa230 --- /dev/null +++ b/app/boards/shields/elephant42/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_ELEPHANT42_LEFT + +config ZMK_KEYBOARD_NAME + default "Elephant42" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SHIELD_ELEPHANT42_LEFT || SHIELD_ELEPHANT42_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LVGL_HOR_RES_MAX + default 128 + +config LVGL_VER_RES_MAX + default 32 + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif \ No newline at end of file diff --git a/app/boards/shields/elephant42/Kconfig.shield b/app/boards/shields/elephant42/Kconfig.shield new file mode 100644 index 00000000..25841868 --- /dev/null +++ b/app/boards/shields/elephant42/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_ELEPHANT42_LEFT + def_bool $(shields_list_contains,elephant42_left) + +config SHIELD_ELEPHANT42_RIGHT + def_bool $(shields_list_contains,elephant42_right) \ No newline at end of file diff --git a/app/boards/shields/elephant42/boards/nice_nano_v2.overlay b/app/boards/shields/elephant42/boards/nice_nano_v2.overlay new file mode 100644 index 00000000..6cd5de8c --- /dev/null +++ b/app/boards/shields/elephant42/boards/nice_nano_v2.overlay @@ -0,0 +1,28 @@ +&spi1 { + compatible = "nordic,nrf-spim"; + /* Cannot be used together with i2c0. */ + status = "okay"; + mosi-pin = <6>; + // Unused pins, needed for SPI definition, but not used by the ws2812 driver itself. + sck-pin = <5>; + miso-pin = <7>; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "WS2812"; + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <27>; /* There are per-key RGB and the LAST 6 are underglow */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.conf b/app/boards/shields/elephant42/elephant42.conf new file mode 100644 index 00000000..1b41763f --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Elephant42 RGB Underglow +# CONFIG_ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Elephant42 OLED Display +# CONFIG_ZMK_DISPLAY=y \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.dtsi b/app/boards/shields/elephant42/elephant42.dtsi new file mode 100644 index 00000000..e2b708ca --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.dtsi @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <4>; + map = < +RC(0,0) 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(0,11) +RC(1,0) 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) RC(1,11) + 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) RC(2,10) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.keymap b/app/boards/shields/elephant42/elephant42.keymap new file mode 100644 index 00000000..8594c117 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.keymap @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#define LOWR 1 +#define RAIS 2 +#define ADJT 3 + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + < ADJT ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp DEL + &mt LCTRL TAB &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH + &kp LSHFT &mo LOWR &kp LGUI &kp BSPC &kp SPACE &kp ENTER &mo RAIS &kp LALT + >; + }; + + lower { + bindings = < + &kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp C_PLAY_PAUSE + &trans &trans &trans &trans &trans &trans &kp LEFT &kp DOWN &kp UP &kp RIGHT &trans &trans + &trans &trans &trans &trans &kp LBKT &kp RBKT &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + raise { + bindings = < + &kp TILDE &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp C_PLAY_PAUSE + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp BSLH + &trans &trans &trans &trans &kp LBKT &kp RBKT &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans + >; + }; + + adjust { + bindings = < + &trans &bt BT_NXT &bt BT_PRV &trans &trans &bt BT_CLR &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 + &out OUT_TOG &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42.zmk.yml b/app/boards/shields/elephant42/elephant42.zmk.yml new file mode 100644 index 00000000..60eb3777 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: elephant42 +name: Elephant42 +type: shield +url: https://github.com/illness072/elephant42 +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - underglow +siblings: + - elephant42_left + - elephant42_right diff --git a/app/boards/shields/elephant42/elephant42_left.overlay b/app/boards/shields/elephant42/elephant42_left.overlay new file mode 100644 index 00000000..72fe2251 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42_left.overlay @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "elephant42.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 21 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + ; +}; \ No newline at end of file diff --git a/app/boards/shields/elephant42/elephant42_right.overlay b/app/boards/shields/elephant42/elephant42_right.overlay new file mode 100644 index 00000000..35bd5895 --- /dev/null +++ b/app/boards/shields/elephant42/elephant42_right.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "elephant42.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 20 GPIO_ACTIVE_HIGH> + , <&pro_micro 21 GPIO_ACTIVE_HIGH> + ; +}; diff --git a/app/boards/shields/kyria/kyria_rev2.keymap b/app/boards/shields/kyria/kyria_rev2.keymap new file mode 100644 index 00000000..a8804dd9 --- /dev/null +++ b/app/boards/shields/kyria/kyria_rev2.keymap @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// --------------------------------------------------------------------------------------------------------------------------------- +// | ESC | Q | W | E | R | T | | Y | U | I | O | P | \ | +// | TAB | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHIFT | Z | X | C | V | B | L SHIFT | L SHIFT | | L SHIFT | L SHIFT | N | M | , | . | / | CTRL | +// | GUI | DEL | RET | SPACE | ESC | | RET | SPACE | TAB | BSPC | R-ALT | + bindings = < + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp TAB &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 LSHFT &kp LSHFT &kp LSHFT &kp LSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RCTRL + &kp LGUI &kp DEL &kp RET &kp SPACE &kp ESC &kp RET &kp SPACE &kp TAB &kp BSPC &kp RALT + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN &inc_dec_kp PG_UP PG_DN>; + }; + }; +}; diff --git a/app/boards/shields/kyria/kyria_rev2.zmk.yml b/app/boards/shields/kyria/kyria_rev2.zmk.yml index d6b3b108..6488f690 100644 --- a/app/boards/shields/kyria/kyria_rev2.zmk.yml +++ b/app/boards/shields/kyria/kyria_rev2.zmk.yml @@ -11,5 +11,5 @@ features: - encoder - underglow siblings: - - kyria_left - - kyria_right + - kyria_rev2_left + - kyria_rev2_right diff --git a/app/boards/shields/leeloo/Kconfig.defconfig b/app/boards/shields/leeloo/Kconfig.defconfig new file mode 100644 index 00000000..615f890b --- /dev/null +++ b/app/boards/shields/leeloo/Kconfig.defconfig @@ -0,0 +1,55 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_LEELOO_LEFT + +config ZMK_KEYBOARD_NAME + default "Leeloo" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif + +if SHIELD_LEELOO_LEFT || SHIELD_LEELOO_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LVGL_HOR_RES_MAX + default 128 + +config LVGL_VER_RES_MAX + default 32 + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/leeloo/Kconfig.shield b/app/boards/shields/leeloo/Kconfig.shield new file mode 100644 index 00000000..1736c6eb --- /dev/null +++ b/app/boards/shields/leeloo/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_LEELOO_LEFT + def_bool $(shields_list_contains,leeloo_left) + +config SHIELD_LEELOO_RIGHT + def_bool $(shields_list_contains,leeloo_right) diff --git a/app/boards/shields/leeloo/README.md b/app/boards/shields/leeloo/README.md new file mode 100644 index 00000000..db705656 --- /dev/null +++ b/app/boards/shields/leeloo/README.md @@ -0,0 +1,42 @@ +# Clickety Split | Leeloo + +![Leeloo](https://cdn.shopify.com/s/files/1/0599/3460/5491/files/Leeloo-rev1.0-w.jpg?v=1646798726) + +Keyboard Designer: [clicketysplit.ca](https://clicketysplit.ca) +GitHub: [ClicketySplit](https://github.com/ClicketySplit) +Hardware Supported: Pro Micro, Elite-C, nice!nano v2 + +Albeit, there is no doubt where Leeloo's heritage is derived from—Lily58, and Corne. It is not a copy-paste-modify implementation. + +Leeloo has been designed from scratch; everything from the schematic to its PCB footprints, and column stagger. There are some subtle differences that may not be apparent; however, its subtle changes enable an interesting future. + +Features: +* 4x6x5m Split Keyboard +* Support for MX/Box or Low Profile Choc switches. +* 90% of the switches are socketed; with the exception to the rotary encoder positions—6 positions require soldering. +* Support for 128x32 OLED Displays. +* The option to select one of three positions for an EC11 rotary encoder on each half. +* Support for Alps Alpine Micro Switch +* Support for 3.7v 301230 LiPo Battery + +# Building Your Firmware +ZMK Firmware: [Introduction to ZMK](https://zmk.dev/docs/) +Installation: [Installing ZMK](https://zmk.dev/docs/user-setup) +Customization: [Customizing ZMK](https://zmk.dev/docs/customization) +Development Environment: [Basic Setup](https://zmk.dev/docs/development/setup) + +Build command for the default keymap of Leeloo: + + west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left + west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right + +Build command for your custom keymap of Leeloo: + + west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right -DZMK_CONFIG="C:\dev\zmk\[yourNmae]\leeloo\config" + west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left -DZMK_CONFIG="C:\dev\zmk\[yourName]\leeloo\config" + +# Support +If you have any questions with regards to Leeloo, please [Contact Us](https://clicketysplit.ca/pages/contact-us). + +Clickety Split +For the love of split keyboards. diff --git a/app/boards/shields/leeloo/leeloo.conf b/app/boards/shields/leeloo/leeloo.conf new file mode 100644 index 00000000..a652bb65 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.conf @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +# Uncomment the following line to enable the OLED Display +# CONFIG_ZMK_DISPLAY=y + +# Uncomment these two lines to add support for encoders +# CONFIG_EC11=y +# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y diff --git a/app/boards/shields/leeloo/leeloo.dtsi b/app/boards/shields/leeloo/leeloo.dtsi new file mode 100644 index 00000000..83e7651d --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.dtsi @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <12>; + rows = <5>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | +// | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | +// | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | SW29 | | SW29 | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | +// | SW25 | SW26 | SW27 | SW28 | | SW28 | SW27 | SW26 | SW25 | + map = < +RC(0,0) 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(0,11) +RC(1,0) 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) RC(1,11) +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) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) RC(4,9) RC(4,10) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + label = "LEFT_ENCODER"; + a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <4>; + }; + + right_encoder: encoder_right { + compatible = "alps,ec11"; + label = "RIGHT_ENCODER"; + a-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <4>; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder &right_encoder>; + }; +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/leeloo/leeloo.keymap b/app/boards/shields/leeloo/leeloo.keymap new file mode 100644 index 00000000..4104cc3a --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.keymap @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#include +#include +#include +#include + +// Layers +#define DEFAULT 0 // default_layer +#define LOWER 1 // lower_layer +#define RAISE 2 // raise_layer + +/ { + + keymap { + compatible = "zmk,keymap"; + + default_layer { + 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 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 N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT + &kp LALT &kp LCTRL < 1 RET < 2 MINUS &kp LGUI &kp LGUI < 2 EQUAL < 1 SPACE &kp BSPC &kp DEL + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + lower_layer { + bindings = < +&trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 +&trans &trans &trans &trans &trans &trans &kp PG_UP &kp HOME &kp UP &kp END &trans &kp F12 +&trans &trans &trans &trans &trans &trans &kp PG_DN &kp LEFT &kp DOWN &kp RIGHT &trans &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + raise_layer { + bindings = < +&trans &trans &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans +&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &reset &bootloader +&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 &bt BT_CLR &trans + >; + + sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>; + }; + + }; +}; diff --git a/app/boards/shields/leeloo/leeloo.zmk.yml b/app/boards/shields/leeloo/leeloo.zmk.yml new file mode 100644 index 00000000..c7e0e6e8 --- /dev/null +++ b/app/boards/shields/leeloo/leeloo.zmk.yml @@ -0,0 +1,14 @@ +file_format: "1" +id: leeloo +name: Leeloo +type: shield +url: https://clicketysplit.ca/pages/leeloo +requires: [pro_micro] +exposes: [i2c_oled] +features: + - keys + - display + - encoder +siblings: + - leeloo_left + - leeloo_right diff --git a/app/boards/shields/leeloo/leeloo_left.overlay b/app/boards/shields/leeloo/leeloo_left.overlay new file mode 100644 index 00000000..1d6424fd --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_left.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#include "leeloo.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro 19 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 10 GPIO_ACTIVE_HIGH> + ; +}; + +&left_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/leeloo/leeloo_right.overlay b/app/boards/shields/leeloo/leeloo_right.overlay new file mode 100644 index 00000000..2f3fbf5c --- /dev/null +++ b/app/boards/shields/leeloo/leeloo_right.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#include "leeloo.dtsi" + +&default_transform { + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro 10 GPIO_ACTIVE_HIGH> + , <&pro_micro 16 GPIO_ACTIVE_HIGH> + , <&pro_micro 14 GPIO_ACTIVE_HIGH> + , <&pro_micro 15 GPIO_ACTIVE_HIGH> + , <&pro_micro 18 GPIO_ACTIVE_HIGH> + , <&pro_micro 19 GPIO_ACTIVE_HIGH> + ; +}; + +&right_encoder { + status = "okay"; +}; diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap index 7708eb21..dd935c7a 100644 --- a/app/boards/shields/lily58/lily58.keymap +++ b/app/boards/shields/lily58/lily58.keymap @@ -53,7 +53,7 @@ // ------------------------------------------------------------------------------------------------------------ // | | | | | | | | | | | | | | // | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | -// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | ^ | v | -> | | +// | F1 | F2 | F3 | F4 | F5 | F6 | | | <- | v | ^ | -> | | // | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ | // | | | | | | | | | | bindings = < diff --git a/app/boards/shields/two_percent_milk/Kconfig.defconfig b/app/boards/shields/two_percent_milk/Kconfig.defconfig new file mode 100644 index 00000000..1046f53c --- /dev/null +++ b/app/boards/shields/two_percent_milk/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_TWO_PERCENT_MILK + +config ZMK_KEYBOARD_NAME + default "2% Milk" + +endif diff --git a/app/boards/shields/two_percent_milk/Kconfig.shield b/app/boards/shields/two_percent_milk/Kconfig.shield new file mode 100644 index 00000000..ec2c3b1f --- /dev/null +++ b/app/boards/shields/two_percent_milk/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_TWO_PERCENT_MILK + def_bool $(shields_list_contains,two_percent_milk) diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.conf b/app/boards/shields/two_percent_milk/two_percent_milk.conf new file mode 100644 index 00000000..fb23f20c --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.conf @@ -0,0 +1,2 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.keymap b/app/boards/shields/two_percent_milk/two_percent_milk.keymap new file mode 100644 index 00000000..71152de2 --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.keymap @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include + #include + #include + + / { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp X + &kp Z + >; + }; + }; + }; \ No newline at end of file diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.overlay b/app/boards/shields/two_percent_milk/two_percent_milk.overlay new file mode 100644 index 00000000..d43ed321 --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + + label = "KSCAN"; + + input-gpios + = <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + + }; + +}; \ No newline at end of file diff --git a/app/boards/shields/two_percent_milk/two_percent_milk.zmk.yml b/app/boards/shields/two_percent_milk/two_percent_milk.zmk.yml new file mode 100644 index 00000000..c53c2df2 --- /dev/null +++ b/app/boards/shields/two_percent_milk/two_percent_milk.zmk.yml @@ -0,0 +1,8 @@ +file_format: "1" +id: two_percent_milk +name: 2% Milk +type: shield +url: https://github.com/Spaceboards/SpaceboardsHardware/tree/master/Keyboards/2%25%20Milk +requires: [pro_micro] +features: + - keys diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 3e797cc9..c1dacbcd 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -17,3 +17,4 @@ #include #include #include +#include \ No newline at end of file diff --git a/app/dts/behaviors/macros.dtsi b/app/dts/behaviors/macros.dtsi new file mode 100644 index 00000000..76153291 --- /dev/null +++ b/app/dts/behaviors/macros.dtsi @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define ZMK_MACRO_STRINGIFY(x) #x +#define ZMK_MACRO(name,...) \ + name: name { \ + label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \ + compatible = "zmk,behavior-macro"; \ + #binding-cells = <0>; \ + __VA_ARGS__ \ + }; + + / { + behaviors { + macro_tap: macro_control_mode_tap { + compatible = "zmk,macro-control-mode-tap"; + label = "MAC_TAP"; + #binding-cells = <0>; + }; + + macro_press: macro_control_mode_press { + compatible = "zmk,macro-control-mode-press"; + label = "MAC_PRESS"; + #binding-cells = <0>; + }; + + macro_release: macro_control_mode_release { + compatible = "zmk,macro-control-mode-release"; + label = "MAC_REL"; + #binding-cells = <0>; + }; + + macro_tap_time: macro_control_tap_time { + compatible = "zmk,macro-control-tap-time"; + label = "MAC_TAP_TIME"; + #binding-cells = <1>; + }; + + macro_wait_time: macro_control_wait_time { + compatible = "zmk,macro-control-wait-time"; + label = "MAC_WAIT_TIME"; + #binding-cells = <1>; + }; + + macro_pause_for_release: macro_pause_for_release { + compatible = "zmk,macro-pause-for-release"; + label = "MAC_WAIT_REL"; + #binding-cells = <0>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-macro.yaml b/app/dts/bindings/behaviors/zmk,behavior-macro.yaml new file mode 100644 index 00000000..ba5bcb07 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-macro.yaml @@ -0,0 +1,21 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Behavior + +compatible: "zmk,behavior-macro" + +include: zero_param.yaml + +properties: + bindings: + type: phandle-array + required: true + wait-ms: + type: int + default: 100 + description: The default time to wait (in milliseconds) before triggering the next behavior in the macro bindings list. + tap-ms: + type: int + default: 100 + description: The default time to wait (in milliseconds) between the press and release events on a tapped macro behavior binding \ No newline at end of file diff --git a/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml b/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml new file mode 100644 index 00000000..8f01effc --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-tap-dance.yaml @@ -0,0 +1,16 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Tap Dance Behavior + +compatible: "zmk,behavior-tap-dance" + +include: zero_param.yaml + +properties: + bindings: + type: phandle-array + required: true + tapping-term-ms: + type: int + default: 200 \ No newline at end of file diff --git a/app/dts/bindings/macros/zmk,macro-control-mode-press.yaml b/app/dts/bindings/macros/zmk,macro-control-mode-press.yaml new file mode 100644 index 00000000..64b3939b --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-mode-press.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro To Press Mode + +compatible: "zmk,macro-control-mode-press" + +include: zero_param.yaml \ No newline at end of file diff --git a/app/dts/bindings/macros/zmk,macro-control-mode-release.yaml b/app/dts/bindings/macros/zmk,macro-control-mode-release.yaml new file mode 100644 index 00000000..c1c27882 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-mode-release.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro To Release Mode + +compatible: "zmk,macro-control-mode-release" + +include: zero_param.yaml \ No newline at end of file diff --git a/app/dts/bindings/macros/zmk,macro-control-mode-tap.yaml b/app/dts/bindings/macros/zmk,macro-control-mode-tap.yaml new file mode 100644 index 00000000..dde32c91 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-mode-tap.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro To Tap Mode + +compatible: "zmk,macro-control-mode-tap" + +include: zero_param.yaml diff --git a/app/dts/bindings/macros/zmk,macro-control-tap-time.yaml b/app/dts/bindings/macros/zmk,macro-control-tap-time.yaml new file mode 100644 index 00000000..8dacdc2a --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-tap-time.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro Tap Duration + +compatible: "zmk,macro-control-tap-time" + +include: one_param.yaml \ No newline at end of file diff --git a/app/dts/bindings/macros/zmk,macro-control-wait-time.yaml b/app/dts/bindings/macros/zmk,macro-control-wait-time.yaml new file mode 100644 index 00000000..9e9beac2 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-control-wait-time.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Set Macro Wait Duration + +compatible: "zmk,macro-control-wait-time" + +include: one_param.yaml \ No newline at end of file diff --git a/app/dts/bindings/macros/zmk,macro-pause-for-release.yaml b/app/dts/bindings/macros/zmk,macro-pause-for-release.yaml new file mode 100644 index 00000000..e89d8b24 --- /dev/null +++ b/app/dts/bindings/macros/zmk,macro-pause-for-release.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2022 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Macro Pause Until Release Marker + +compatible: "zmk,macro-pause-for-release" + +include: zero_param.yaml \ No newline at end of file diff --git a/app/include/zmk/behavior_queue.h b/app/include/zmk/behavior_queue.h new file mode 100644 index 00000000..8a184e4a --- /dev/null +++ b/app/include/zmk/behavior_queue.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding behavior, + bool press, uint32_t wait); diff --git a/app/src/behavior_queue.c b/app/src/behavior_queue.c new file mode 100644 index 00000000..a3cd8d47 --- /dev/null +++ b/app/src/behavior_queue.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct q_item { + uint32_t position; + struct zmk_behavior_binding binding; + bool press : 1; + uint32_t wait : 31; +}; + +K_MSGQ_DEFINE(zmk_behavior_queue_msgq, sizeof(struct q_item), CONFIG_ZMK_BEHAVIORS_QUEUE_SIZE, 4); + +static void behavior_queue_process_next(struct k_work *work); +static K_DELAYED_WORK_DEFINE(queue_work, behavior_queue_process_next); + +static void behavior_queue_process_next(struct k_work *work) { + struct q_item item = {.wait = 0}; + + while (k_msgq_get(&zmk_behavior_queue_msgq, &item, K_NO_WAIT) == 0) { + LOG_DBG("Invoking %s: 0x%02x 0x%02x", log_strdup(item.binding.behavior_dev), + item.binding.param1, item.binding.param2); + + struct zmk_behavior_binding_event event = {.position = item.position, + .timestamp = k_uptime_get()}; + + if (item.press) { + behavior_keymap_binding_pressed(&item.binding, event); + } else { + behavior_keymap_binding_released(&item.binding, event); + } + + LOG_DBG("Processing next queued behavior in %dms", item.wait); + + if (item.wait > 0) { + k_delayed_work_submit(&queue_work, K_MSEC(item.wait)); + break; + } + } +} + +int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding binding, bool press, + uint32_t wait) { + struct q_item item = {.press = press, .binding = binding, .wait = wait}; + + const int ret = k_msgq_put(&zmk_behavior_queue_msgq, &item, K_NO_WAIT); + if (ret < 0) { + return ret; + } + + if (!k_delayed_work_pending(&queue_work)) { + behavior_queue_process_next(&queue_work.work); + } + + return 0; +} diff --git a/app/src/behaviors/behavior_macro.c b/app/src/behaviors/behavior_macro.c new file mode 100644 index 00000000..92ee2c43 --- /dev/null +++ b/app/src/behaviors/behavior_macro.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_macro + +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +enum behavior_macro_mode { + MACRO_MODE_TAP, + MACRO_MODE_PRESS, + MACRO_MODE_RELEASE, +}; + +struct behavior_macro_trigger_state { + uint32_t wait_ms; + uint32_t tap_ms; + enum behavior_macro_mode mode; + uint16_t start_index; + uint16_t count; +}; + +struct behavior_macro_state { + struct behavior_macro_trigger_state release_state; + + uint32_t press_bindings_count; +}; + +struct behavior_macro_config { + uint32_t default_wait_ms; + uint32_t default_tap_ms; + uint32_t count; + struct zmk_behavior_binding bindings[]; +}; + +#define TAP_MODE DT_LABEL(DT_INST(0, zmk_macro_control_mode_tap)) +#define PRESS_MODE DT_LABEL(DT_INST(0, zmk_macro_control_mode_press)) +#define REL_MODE DT_LABEL(DT_INST(0, zmk_macro_control_mode_release)) + +#define TAP_TIME DT_LABEL(DT_INST(0, zmk_macro_control_tap_time)) +#define WAIT_TIME DT_LABEL(DT_INST(0, zmk_macro_control_wait_time)) +#define WAIT_REL DT_LABEL(DT_INST(0, zmk_macro_pause_for_release)) + +#define ZM_IS_NODE_MATCH(a, b) (strcmp(a, b) == 0) +#define IS_TAP_MODE(dev) ZM_IS_NODE_MATCH(dev, TAP_MODE) +#define IS_PRESS_MODE(dev) ZM_IS_NODE_MATCH(dev, PRESS_MODE) +#define IS_RELEASE_MODE(dev) ZM_IS_NODE_MATCH(dev, REL_MODE) + +#define IS_TAP_TIME(dev) ZM_IS_NODE_MATCH(dev, TAP_TIME) +#define IS_WAIT_TIME(dev) ZM_IS_NODE_MATCH(dev, WAIT_TIME) +#define IS_PAUSE(dev) ZM_IS_NODE_MATCH(dev, WAIT_REL) + +static bool handle_control_binding(struct behavior_macro_trigger_state *state, + const struct zmk_behavior_binding *binding) { + if (IS_TAP_MODE(binding->behavior_dev)) { + state->mode = MACRO_MODE_TAP; + LOG_DBG("macro mode set: tap"); + } else if (IS_PRESS_MODE(binding->behavior_dev)) { + state->mode = MACRO_MODE_PRESS; + LOG_DBG("macro mode set: press"); + } else if (IS_RELEASE_MODE(binding->behavior_dev)) { + state->mode = MACRO_MODE_RELEASE; + LOG_DBG("macro mode set: release"); + } else if (IS_TAP_TIME(binding->behavior_dev)) { + state->tap_ms = binding->param1; + LOG_DBG("macro tap time set: %d", state->tap_ms); + } else if (IS_WAIT_TIME(binding->behavior_dev)) { + state->wait_ms = binding->param1; + LOG_DBG("macro wait time set: %d", state->wait_ms); + } else { + return false; + } + + return true; +} + +static int behavior_macro_init(const struct device *dev) { + const struct behavior_macro_config *cfg = dev->config; + struct behavior_macro_state *state = dev->data; + state->press_bindings_count = cfg->count; + state->release_state.start_index = cfg->count; + state->release_state.count = 0; + + LOG_DBG("Precalculate initial release state:"); + for (int i = 0; i < cfg->count; i++) { + if (handle_control_binding(&state->release_state, &cfg->bindings[i])) { + // Updated state used for initial state on release. + } else if (IS_PAUSE(cfg->bindings[i].behavior_dev)) { + state->release_state.start_index = i + 1; + state->release_state.count = cfg->count - state->release_state.start_index; + state->press_bindings_count = i; + LOG_DBG("Release will resume at %d", state->release_state.start_index); + break; + } else { + // Ignore regular invokable bindings + } + } + + return 0; +}; + +static void queue_macro(uint32_t position, const struct zmk_behavior_binding bindings[], + struct behavior_macro_trigger_state state) { + LOG_DBG("Iterating macro bindings - starting: %d, count: %d", state.start_index, state.count); + for (int i = state.start_index; i < state.start_index + state.count; i++) { + if (!handle_control_binding(&state, &bindings[i])) { + switch (state.mode) { + case MACRO_MODE_TAP: + zmk_behavior_queue_add(position, bindings[i], true, state.tap_ms); + zmk_behavior_queue_add(position, bindings[i], false, state.wait_ms); + break; + case MACRO_MODE_PRESS: + zmk_behavior_queue_add(position, bindings[i], true, state.wait_ms); + break; + case MACRO_MODE_RELEASE: + zmk_behavior_queue_add(position, bindings[i], false, state.wait_ms); + break; + default: + LOG_ERR("Unknown macro mode: %d", state.mode); + break; + } + } + } +} + +static int on_macro_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_macro_config *cfg = dev->config; + struct behavior_macro_state *state = dev->data; + struct behavior_macro_trigger_state trigger_state = {.mode = MACRO_MODE_TAP, + .tap_ms = cfg->default_tap_ms, + .wait_ms = cfg->default_wait_ms, + .start_index = 0, + .count = state->press_bindings_count}; + + queue_macro(event.position, cfg->bindings, trigger_state); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_macro_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_macro_config *cfg = dev->config; + struct behavior_macro_state *state = dev->data; + + queue_macro(event.position, cfg->bindings, state->release_state); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_macro_driver_api = { + .binding_pressed = on_macro_binding_pressed, + .binding_released = on_macro_binding_released, +}; + +#define BINDING_WITH_COMMA(idx, drv_inst) ZMK_KEYMAP_EXTRACT_BINDING(idx, DT_DRV_INST(drv_inst)), + +#define TRANSFORMED_BEHAVIORS(n) \ + {UTIL_LISTIFY(DT_PROP_LEN(DT_DRV_INST(n), bindings), BINDING_WITH_COMMA, n)}, + +#define MACRO_INST(n) \ + static struct behavior_macro_state behavior_macro_state_##n = {}; \ + static struct behavior_macro_config behavior_macro_config_##n = { \ + .default_wait_ms = DT_INST_PROP_OR(n, wait_ms, 100), \ + .default_tap_ms = DT_INST_PROP_OR(n, tap_ms, 100), \ + .count = DT_INST_PROP_LEN(n, bindings), \ + .bindings = TRANSFORMED_BEHAVIORS(n)}; \ + DEVICE_DT_INST_DEFINE(n, behavior_macro_init, device_pm_control_nop, \ + &behavior_macro_state_##n, &behavior_macro_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MACRO_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_sticky_key.c b/app/src/behaviors/behavior_sticky_key.c index 3c75a7a3..7909e1af 100644 --- a/app/src/behaviors/behavior_sticky_key.c +++ b/app/src/behaviors/behavior_sticky_key.c @@ -188,6 +188,9 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { if (ev == NULL) { return ZMK_EV_EVENT_BUBBLE; } + + // keep track whether the event has been reraised, so we only reraise it once + bool event_reraised = false; for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) { struct active_sticky_key *sticky_key = &active_sticky_keys[i]; if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) { @@ -223,10 +226,12 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { if (sticky_key->timer_started) { stop_timer(sticky_key); if (sticky_key->config->quick_release) { - // continue processing the event. Release the sticky key afterwards. - ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key); + // immediately release the sticky key after the key press is handled. + if (!event_reraised) { + ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key); + event_reraised = true; + } release_sticky_key_behavior(sticky_key, ev->timestamp); - return ZMK_EV_EVENT_CAPTURED; } } sticky_key->modified_key_usage_page = ev->usage_page; @@ -240,6 +245,9 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) { } } } + if (event_reraised) { + return ZMK_EV_EVENT_CAPTURED; + } return ZMK_EV_EVENT_BUBBLE; } diff --git a/app/src/behaviors/behavior_tap_dance.c b/app/src/behaviors/behavior_tap_dance.c new file mode 100644 index 00000000..4b35e4de --- /dev/null +++ b/app/src/behaviors/behavior_tap_dance.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_tap_dance + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#define ZMK_BHV_TAP_DANCE_MAX_HELD 10 + +#define ZMK_BHV_TAP_DANCE_POSITION_FREE ULONG_MAX + +struct behavior_tap_dance_config { + uint32_t tapping_term_ms; + size_t behavior_count; + struct zmk_behavior_binding *behaviors; +}; + +struct active_tap_dance { + // Tap Dance Data + int counter; + uint32_t position; + uint32_t param1; + uint32_t param2; + bool is_pressed; + const struct behavior_tap_dance_config *config; + + // Timer Data + bool timer_started; + bool timer_cancelled; + bool tap_dance_decided; + int64_t release_at; + struct k_delayed_work release_timer; +}; + +struct active_tap_dance active_tap_dances[ZMK_BHV_TAP_DANCE_MAX_HELD] = {}; + +static struct active_tap_dance *find_tap_dance(uint32_t position) { + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + if (active_tap_dances[i].position == position && !active_tap_dances[i].timer_cancelled) { + return &active_tap_dances[i]; + } + } + return NULL; +} + +static int new_tap_dance(uint32_t position, const struct behavior_tap_dance_config *config, + struct active_tap_dance **tap_dance) { + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + struct active_tap_dance *const ref_dance = &active_tap_dances[i]; + if (ref_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) { + ref_dance->counter = 0; + ref_dance->position = position; + ref_dance->config = config; + ref_dance->release_at = 0; + ref_dance->is_pressed = true; + ref_dance->timer_started = true; + ref_dance->timer_cancelled = false; + ref_dance->tap_dance_decided = false; + *tap_dance = ref_dance; + return 0; + } + } + return -ENOMEM; +} + +static void clear_tap_dance(struct active_tap_dance *tap_dance) { + tap_dance->position = ZMK_BHV_TAP_DANCE_POSITION_FREE; +} + +static int stop_timer(struct active_tap_dance *tap_dance) { + int timer_cancel_result = k_delayed_work_cancel(&tap_dance->release_timer); + if (timer_cancel_result == -EINPROGRESS) { + // too late to cancel, we'll let the timer handler clear up. + tap_dance->timer_cancelled = true; + } + return timer_cancel_result; +} + +static void reset_timer(struct active_tap_dance *tap_dance, + struct zmk_behavior_binding_event event) { + tap_dance->release_at = event.timestamp + tap_dance->config->tapping_term_ms; + int32_t ms_left = tap_dance->release_at - k_uptime_get(); + if (ms_left > 0) { + k_delayed_work_submit(&tap_dance->release_timer, K_MSEC(ms_left)); + LOG_DBG("Successfully reset timer at position %d", tap_dance->position); + } +} + +static inline int press_tap_dance_behavior(struct active_tap_dance *tap_dance, int64_t timestamp) { + tap_dance->tap_dance_decided = true; + struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1]; + struct zmk_behavior_binding_event event = { + .position = tap_dance->position, + .timestamp = timestamp, + }; + return behavior_keymap_binding_pressed(&binding, event); +} + +static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance, + int64_t timestamp) { + struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1]; + struct zmk_behavior_binding_event event = { + .position = tap_dance->position, + .timestamp = timestamp, + }; + clear_tap_dance(tap_dance); + return behavior_keymap_binding_released(&binding, event); +} + +static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_tap_dance_config *cfg = dev->config; + struct active_tap_dance *tap_dance; + tap_dance = find_tap_dance(event.position); + if (tap_dance == NULL) { + if (new_tap_dance(event.position, cfg, &tap_dance) == -ENOMEM) { + LOG_ERR("Unable to create new tap dance. Insufficient space in active_tap_dances[]."); + return ZMK_BEHAVIOR_OPAQUE; + } + LOG_DBG("%d created new tap dance", event.position); + } + tap_dance->is_pressed = true; + LOG_DBG("%d tap dance pressed", event.position); + stop_timer(tap_dance); + // Increment the counter on keypress. If the counter has reached its maximum + // value, invoke the last binding available. + if (tap_dance->counter < cfg->behavior_count) { + tap_dance->counter++; + } + if (tap_dance->counter == cfg->behavior_count) { + // LOG_DBG("Tap dance has been decided via maximum counter value"); + press_tap_dance_behavior(tap_dance, event.timestamp); + return ZMK_EV_EVENT_BUBBLE; + } + reset_timer(tap_dance, event); + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_tap_dance_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("%d tap dance keybind released", event.position); + struct active_tap_dance *tap_dance = find_tap_dance(event.position); + if (tap_dance == NULL) { + LOG_ERR("ACTIVE TAP DANCE CLEARED TOO EARLY"); + return ZMK_BEHAVIOR_OPAQUE; + } + tap_dance->is_pressed = false; + if (tap_dance->tap_dance_decided) { + release_tap_dance_behavior(tap_dance, event.timestamp); + } + return ZMK_BEHAVIOR_OPAQUE; +} + +void behavior_tap_dance_timer_handler(struct k_work *item) { + struct active_tap_dance *tap_dance = CONTAINER_OF(item, struct active_tap_dance, release_timer); + if (tap_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) { + return; + } + if (tap_dance->timer_cancelled) { + return; + } + LOG_DBG("Tap dance has been decided via timer. Counter reached: %d", tap_dance->counter); + press_tap_dance_behavior(tap_dance, tap_dance->release_at); + if (tap_dance->is_pressed) { + return; + } + release_tap_dance_behavior(tap_dance, tap_dance->release_at); +} + +static const struct behavior_driver_api behavior_tap_dance_driver_api = { + .binding_pressed = on_tap_dance_binding_pressed, + .binding_released = on_tap_dance_binding_released, +}; + +static int tap_dance_position_state_changed_listener(const zmk_event_t *eh); + +ZMK_LISTENER(behavior_tap_dance, tap_dance_position_state_changed_listener); +ZMK_SUBSCRIPTION(behavior_tap_dance, zmk_position_state_changed); + +static int tap_dance_position_state_changed_listener(const zmk_event_t *eh) { + struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh); + if (ev == NULL) { + return ZMK_EV_EVENT_BUBBLE; + } + if (!ev->state) { + LOG_DBG("Ignore upstroke at position %d.", ev->position); + return ZMK_EV_EVENT_BUBBLE; + } + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + struct active_tap_dance *tap_dance = &active_tap_dances[i]; + if (tap_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) { + continue; + } + if (tap_dance->position == ev->position) { + continue; + } + stop_timer(tap_dance); + LOG_DBG("Tap dance interrupted, activating tap-dance at %d", tap_dance->position); + if (!tap_dance->tap_dance_decided) { + press_tap_dance_behavior(tap_dance, ev->timestamp); + if (!tap_dance->is_pressed) { + release_tap_dance_behavior(tap_dance, ev->timestamp); + } + return ZMK_EV_EVENT_BUBBLE; + } + } + return ZMK_EV_EVENT_BUBBLE; +} + +static int behavior_tap_dance_init(const struct device *dev) { + static bool init_first_run = true; + if (init_first_run) { + for (int i = 0; i < ZMK_BHV_TAP_DANCE_MAX_HELD; i++) { + k_delayed_work_init(&active_tap_dances[i].release_timer, + behavior_tap_dance_timer_handler); + clear_tap_dance(&active_tap_dances[i]); + } + } + init_first_run = false; + return 0; +} + +#define _TRANSFORM_ENTRY(idx, node) ZMK_KEYMAP_EXTRACT_BINDING(idx, node), + +#define TRANSFORMED_BINDINGS(node) \ + { UTIL_LISTIFY(DT_INST_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, DT_DRV_INST(node)) } + +#define KP_INST(n) \ + static struct zmk_behavior_binding \ + behavior_tap_dance_config_##n##_bindings[DT_INST_PROP_LEN(n, bindings)] = \ + TRANSFORMED_BINDINGS(n); \ + static struct behavior_tap_dance_config behavior_tap_dance_config_##n = { \ + .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \ + .behaviors = behavior_tap_dance_config_##n##_bindings, \ + .behavior_count = DT_INST_PROP_LEN(n, bindings)}; \ + DEVICE_AND_API_INIT(behavior_tap_dance_##n, DT_INST_LABEL(n), behavior_tap_dance_init, NULL, \ + &behavior_tap_dance_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tap_dance_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif \ No newline at end of file diff --git a/app/tests/macros/basic/events.patterns b/app/tests/macros/basic/events.patterns new file mode 100644 index 00000000..0a5f25ca --- /dev/null +++ b/app/tests/macros/basic/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*behavior_queue_process_next/queue_process_next/p \ No newline at end of file diff --git a/app/tests/macros/basic/keycode_events.snapshot b/app/tests/macros/basic/keycode_events.snapshot new file mode 100644 index 00000000..b238a2ff --- /dev/null +++ b/app/tests/macros/basic/keycode_events.snapshot @@ -0,0 +1,18 @@ +queue_process_next: Invoking KEY_PRESS: 0x70004 0x00 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking KEY_PRESS: 0x70004 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +queue_process_next: Invoking KEY_PRESS: 0x70005 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking KEY_PRESS: 0x70005 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +queue_process_next: Invoking KEY_PRESS: 0x70006 0x00 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking KEY_PRESS: 0x70006 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms diff --git a/app/tests/macros/basic/native_posix.keymap b/app/tests/macros/basic/native_posix.keymap new file mode 100644 index 00000000..6a2391db --- /dev/null +++ b/app/tests/macros/basic/native_posix.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/behavior_keymap.dtsi b/app/tests/macros/behavior_keymap.dtsi new file mode 100644 index 00000000..7399cd5b --- /dev/null +++ b/app/tests/macros/behavior_keymap.dtsi @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + ZMK_MACRO(abc_macro, + wait-ms = <10>; + tap-ms = <50>; + bindings = <&kp A &kp B &kp C>; + ) + + ZMK_MACRO(hold_shift_macro, + bindings + = <¯o_press &kp LSHFT> + , <¯o_tap> + , <&kp D &kp O &kp G> + , <¯o_release &kp LSHFT> + ; + ) + + ZMK_MACRO(custom_timing, + bindings + = <¯o_wait_time 50> + , <&kp A> + , <¯o_tap_time 20> + , <&kp B &kp C> + ; + ) + + ZMK_MACRO(dual_sequence_macro, + wait-ms = <10>; + tap-ms = <40>; + bindings + = <¯o_press &kp LALT> + , <¯o_tap> + , <&kp TAB> + , <¯o_pause_for_release> + , <¯o_release &kp LALT> + ; + ) + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &abc_macro &mo 1 + &hold_shift_macro &custom_timing>; + }; + + extra_layer { + bindings = < + &dual_sequence_macro &trans + &kp TAB &none>; + + }; + + }; +}; diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/events.patterns b/app/tests/macros/mo-plus-modifier-from-hold-tap/events.patterns new file mode 100644 index 00000000..3c9d3f83 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/keycode_events.snapshot b/app/tests/macros/mo-plus-modifier-from-hold-tap/keycode_events.snapshot new file mode 100644 index 00000000..9f47e064 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/keycode_events.snapshot @@ -0,0 +1,4 @@ +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix.keymap b/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix.keymap new file mode 100644 index 00000000..2f3b943a --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-from-hold-tap/native_posix.keymap @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + ZMK_MACRO( + mo_mod_macro, + wait-ms = <0>; + tap-ms = <20>; + bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT>; + ) + }; + + behaviors { + mth: macro_tap_hold { + compatible = "zmk,behavior-hold-tap"; + label = "MACRO_TAP_HOLD"; + #binding-cells = <2>; + flavor = "tap-unless-interrupted"; + tapping-term-ms = <200>; + bindings = <&mo_mod_macro>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mth 0 TAB &kp A + &kp B &kp C>; + }; + + extra_layer { + bindings = < + &kp D &kp E + &kp F &kp G>; + + }; + + }; +}; + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/mo-plus-modifier-macro/events.patterns b/app/tests/macros/mo-plus-modifier-macro/events.patterns new file mode 100644 index 00000000..3c9d3f83 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-macro/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/mo-plus-modifier-macro/keycode_events.snapshot b/app/tests/macros/mo-plus-modifier-macro/keycode_events.snapshot new file mode 100644 index 00000000..9f47e064 --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-macro/keycode_events.snapshot @@ -0,0 +1,4 @@ +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/mo-plus-modifier-macro/native_posix.keymap b/app/tests/macros/mo-plus-modifier-macro/native_posix.keymap new file mode 100644 index 00000000..c264a9ab --- /dev/null +++ b/app/tests/macros/mo-plus-modifier-macro/native_posix.keymap @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + macros { + ZMK_MACRO( + mo_mod_macro, + wait-ms = <0>; + tap-ms = <20>; + bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT>; + ) + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mo_mod_macro &kp A + &kp B &kp C>; + }; + + extra_layer { + bindings = < + &kp D &kp E + &kp F &kp G>; + + }; + + }; +}; + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/press-mid-macro/events.patterns b/app/tests/macros/press-mid-macro/events.patterns new file mode 100644 index 00000000..cedbda8b --- /dev/null +++ b/app/tests/macros/press-mid-macro/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*keymap_apply_position_state/pos_state/p \ No newline at end of file diff --git a/app/tests/macros/press-mid-macro/keycode_events.snapshot b/app/tests/macros/press-mid-macro/keycode_events.snapshot new file mode 100644 index 00000000..22393a3a --- /dev/null +++ b/app/tests/macros/press-mid-macro/keycode_events.snapshot @@ -0,0 +1,10 @@ +pos_state: layer: 0 position: 0, binding name: ZM_abc_macro +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pos_state: layer: 0 position: 0, binding name: ZM_abc_macro +pos_state: layer: 0 position: 1, binding name: MO +pos_state: layer: 0 position: 1, binding name: MO +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 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/press-mid-macro/native_posix.keymap b/app/tests/macros/press-mid-macro/native_posix.keymap new file mode 100644 index 00000000..a075a443 --- /dev/null +++ b/app/tests/macros/press-mid-macro/native_posix.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/press-release/events.patterns b/app/tests/macros/press-release/events.patterns new file mode 100644 index 00000000..3c9d3f83 --- /dev/null +++ b/app/tests/macros/press-release/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode/kp/p \ No newline at end of file diff --git a/app/tests/macros/press-release/keycode_events.snapshot b/app/tests/macros/press-release/keycode_events.snapshot new file mode 100644 index 00000000..ebe69d5c --- /dev/null +++ b/app/tests/macros/press-release/keycode_events.snapshot @@ -0,0 +1,8 @@ +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x12 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x12 implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x0a implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x0a implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/macros/press-release/native_posix.keymap b/app/tests/macros/press-release/native_posix.keymap new file mode 100644 index 00000000..6814d542 --- /dev/null +++ b/app/tests/macros/press-release/native_posix.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/timing-override/events.patterns b/app/tests/macros/timing-override/events.patterns new file mode 100644 index 00000000..0a5f25ca --- /dev/null +++ b/app/tests/macros/timing-override/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*behavior_queue_process_next/queue_process_next/p \ No newline at end of file diff --git a/app/tests/macros/timing-override/keycode_events.snapshot b/app/tests/macros/timing-override/keycode_events.snapshot new file mode 100644 index 00000000..650d6747 --- /dev/null +++ b/app/tests/macros/timing-override/keycode_events.snapshot @@ -0,0 +1,18 @@ +queue_process_next: Invoking KEY_PRESS: 0x70004 0x00 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 100ms +queue_process_next: Invoking KEY_PRESS: 0x70004 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking KEY_PRESS: 0x70005 0x00 +kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 20ms +queue_process_next: Invoking KEY_PRESS: 0x70005 0x00 +kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms +queue_process_next: Invoking KEY_PRESS: 0x70006 0x00 +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 20ms +queue_process_next: Invoking KEY_PRESS: 0x70006 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 50ms diff --git a/app/tests/macros/timing-override/native_posix.keymap b/app/tests/macros/timing-override/native_posix.keymap new file mode 100644 index 00000000..343926a7 --- /dev/null +++ b/app/tests/macros/timing-override/native_posix.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/macros/wait-macro-release/events.patterns b/app/tests/macros/wait-macro-release/events.patterns new file mode 100644 index 00000000..02e0c505 --- /dev/null +++ b/app/tests/macros/wait-macro-release/events.patterns @@ -0,0 +1,3 @@ +s/.*hid_listener_keycode/kp/p +s/.*behavior_queue_process_next/queue_process_next/p +s/.*queue_macro/qm/p \ No newline at end of file diff --git a/app/tests/macros/wait-macro-release/keycode_events.snapshot b/app/tests/macros/wait-macro-release/keycode_events.snapshot new file mode 100644 index 00000000..509a1c48 --- /dev/null +++ b/app/tests/macros/wait-macro-release/keycode_events.snapshot @@ -0,0 +1,16 @@ +qm: Iterating macro bindings - starting: 0, count: 4 +queue_process_next: Invoking KEY_PRESS: 0x700e2 0x00 +kp_pressed: usage_page 0x07 keycode 0xe2 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +queue_process_next: Invoking KEY_PRESS: 0x7002b 0x00 +kp_pressed: usage_page 0x07 keycode 0x2b implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 40ms +queue_process_next: Invoking KEY_PRESS: 0x7002b 0x00 +kp_released: usage_page 0x07 keycode 0x2b implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 10ms +kp_pressed: usage_page 0x07 keycode 0x2b implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x2b implicit_mods 0x00 explicit_mods 0x00 +qm: Iterating macro bindings - starting: 5, count: 2 +queue_process_next: Invoking KEY_PRESS: 0x700e2 0x00 +kp_released: usage_page 0x07 keycode 0xe2 implicit_mods 0x00 explicit_mods 0x00 +queue_process_next: Processing next queued behavior in 0ms diff --git a/app/tests/macros/wait-macro-release/native_posix.keymap b/app/tests/macros/wait-macro-release/native_posix.keymap new file mode 100644 index 00000000..6dabaeca --- /dev/null +++ b/app/tests/macros/wait-macro-release/native_posix.keymap @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = ; +}; \ No newline at end of file diff --git a/app/tests/sticky-keys/10-sl-sl-kp/events.patterns b/app/tests/sticky-keys/10-sl-sl-kp/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/sticky-keys/10-sl-sl-kp/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot b/app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot new file mode 100644 index 00000000..fc0f29b9 --- /dev/null +++ b/app/tests/sticky-keys/10-sl-sl-kp/keycode_events.snapshot @@ -0,0 +1,8 @@ +pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/sticky-keys/10-sl-sl-kp/native_posix.keymap b/app/tests/sticky-keys/10-sl-sl-kp/native_posix.keymap new file mode 100644 index 00000000..e9b87f42 --- /dev/null +++ b/app/tests/sticky-keys/10-sl-sl-kp/native_posix.keymap @@ -0,0 +1,65 @@ +#include +#include +#include + +/* + sticky layers should quick-release. + Thus, the second keypress should be on the default layer, not on the lower_layer. +*/ + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &sl 1 &kp A + &none &none>; + }; + + layer_1 { + bindings = < + &sl 2 &none + &none &none>; + }; + + layer_2 { + bindings = < + &none &kp NUM_1 + &none &none>; + }; + }; +}; + +&kscan { + events = < + /* press sl 1 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press sl 2 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press 1 */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* press A */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + + /* repeat test to check if cleanup is done correctly */ + /* press sl 1 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press sl 2 */ + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + /* press 1 */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + /* press A */ + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/1a-tap1/events.patterns b/app/tests/tap-dance/1a-tap1/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/1a-tap1/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/1a-tap1/keycode_events.snapshot b/app/tests/tap-dance/1a-tap1/keycode_events.snapshot new file mode 100644 index 00000000..38bc54c3 --- /dev/null +++ b/app/tests/tap-dance/1a-tap1/keycode_events.snapshot @@ -0,0 +1,5 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/1a-tap1/native_posix.keymap b/app/tests/tap-dance/1a-tap1/native_posix.keymap new file mode 100644 index 00000000..1e5dff06 --- /dev/null +++ b/app/tests/tap-dance/1a-tap1/native_posix.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/1b-tap2/events.patterns b/app/tests/tap-dance/1b-tap2/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/1b-tap2/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/1b-tap2/keycode_events.snapshot b/app/tests/tap-dance/1b-tap2/keycode_events.snapshot new file mode 100644 index 00000000..c23537b9 --- /dev/null +++ b/app/tests/tap-dance/1b-tap2/keycode_events.snapshot @@ -0,0 +1,7 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +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/tests/tap-dance/1b-tap2/native_posix.keymap b/app/tests/tap-dance/1b-tap2/native_posix.keymap new file mode 100644 index 00000000..c5e1c8db --- /dev/null +++ b/app/tests/tap-dance/1b-tap2/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/1c-tap3/events.patterns b/app/tests/tap-dance/1c-tap3/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/1c-tap3/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/1c-tap3/keycode_events.snapshot b/app/tests/tap-dance/1c-tap3/keycode_events.snapshot new file mode 100644 index 00000000..1e68bae9 --- /dev/null +++ b/app/tests/tap-dance/1c-tap3/keycode_events.snapshot @@ -0,0 +1,9 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/1c-tap3/native_posix.keymap b/app/tests/tap-dance/1c-tap3/native_posix.keymap new file mode 100644 index 00000000..6813393e --- /dev/null +++ b/app/tests/tap-dance/1c-tap3/native_posix.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/2a-hold1/events.patterns b/app/tests/tap-dance/2a-hold1/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/2a-hold1/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/2a-hold1/keycode_events.snapshot b/app/tests/tap-dance/2a-hold1/keycode_events.snapshot new file mode 100644 index 00000000..2a0965dc --- /dev/null +++ b/app/tests/tap-dance/2a-hold1/keycode_events.snapshot @@ -0,0 +1,5 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/2a-hold1/native_posix.keymap b/app/tests/tap-dance/2a-hold1/native_posix.keymap new file mode 100644 index 00000000..f4c7a2d2 --- /dev/null +++ b/app/tests/tap-dance/2a-hold1/native_posix.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/2b-hold2/events.patterns b/app/tests/tap-dance/2b-hold2/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/2b-hold2/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/2b-hold2/keycode_events.snapshot b/app/tests/tap-dance/2b-hold2/keycode_events.snapshot new file mode 100644 index 00000000..dbccfc94 --- /dev/null +++ b/app/tests/tap-dance/2b-hold2/keycode_events.snapshot @@ -0,0 +1,7 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xe2 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xe2 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/2b-hold2/native_posix.keymap b/app/tests/tap-dance/2b-hold2/native_posix.keymap new file mode 100644 index 00000000..0fec2e40 --- /dev/null +++ b/app/tests/tap-dance/2b-hold2/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/2c-hold3/events.patterns b/app/tests/tap-dance/2c-hold3/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/2c-hold3/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/2c-hold3/keycode_events.snapshot b/app/tests/tap-dance/2c-hold3/keycode_events.snapshot new file mode 100644 index 00000000..3ac8e0e6 --- /dev/null +++ b/app/tests/tap-dance/2c-hold3/keycode_events.snapshot @@ -0,0 +1,9 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +td_binding_released: 0 tap dance keybind released +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xe3 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xe3 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/2c-hold3/native_posix.keymap b/app/tests/tap-dance/2c-hold3/native_posix.keymap new file mode 100644 index 00000000..8375c6f6 --- /dev/null +++ b/app/tests/tap-dance/2c-hold3/native_posix.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3a-tap-int-mid/events.patterns b/app/tests/tap-dance/3a-tap-int-mid/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/3a-tap-int-mid/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3a-tap-int-mid/keycode_events.snapshot b/app/tests/tap-dance/3a-tap-int-mid/keycode_events.snapshot new file mode 100644 index 00000000..715d0143 --- /dev/null +++ b/app/tests/tap-dance/3a-tap-int-mid/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3a-tap-int-mid/native_posix.keymap b/app/tests/tap-dance/3a-tap-int-mid/native_posix.keymap new file mode 100644 index 00000000..8a62430c --- /dev/null +++ b/app/tests/tap-dance/3a-tap-int-mid/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3b-tap-int-seq/events.patterns b/app/tests/tap-dance/3b-tap-int-seq/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/3b-tap-int-seq/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot b/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot new file mode 100644 index 00000000..a973e426 --- /dev/null +++ b/app/tests/tap-dance/3b-tap-int-seq/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3b-tap-int-seq/native_posix.keymap b/app/tests/tap-dance/3b-tap-int-seq/native_posix.keymap new file mode 100644 index 00000000..4a76bdb0 --- /dev/null +++ b/app/tests/tap-dance/3b-tap-int-seq/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3c-tap-int-after/events.patterns b/app/tests/tap-dance/3c-tap-int-after/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/3c-tap-int-after/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3c-tap-int-after/keycode_events.snapshot b/app/tests/tap-dance/3c-tap-int-after/keycode_events.snapshot new file mode 100644 index 00000000..2c715537 --- /dev/null +++ b/app/tests/tap-dance/3c-tap-int-after/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3c-tap-int-after/native_posix.keymap b/app/tests/tap-dance/3c-tap-int-after/native_posix.keymap new file mode 100644 index 00000000..e1b6d979 --- /dev/null +++ b/app/tests/tap-dance/3c-tap-int-after/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3d-hold-int-mid/events.patterns b/app/tests/tap-dance/3d-hold-int-mid/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/3d-hold-int-mid/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3d-hold-int-mid/keycode_events.snapshot b/app/tests/tap-dance/3d-hold-int-mid/keycode_events.snapshot new file mode 100644 index 00000000..7631c4ac --- /dev/null +++ b/app/tests/tap-dance/3d-hold-int-mid/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3d-hold-int-mid/native_posix.keymap b/app/tests/tap-dance/3d-hold-int-mid/native_posix.keymap new file mode 100644 index 00000000..55a98d36 --- /dev/null +++ b/app/tests/tap-dance/3d-hold-int-mid/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3e-hold-int-seq/events.patterns b/app/tests/tap-dance/3e-hold-int-seq/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/3e-hold-int-seq/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3e-hold-int-seq/keycode_events.snapshot b/app/tests/tap-dance/3e-hold-int-seq/keycode_events.snapshot new file mode 100644 index 00000000..ca13f8bc --- /dev/null +++ b/app/tests/tap-dance/3e-hold-int-seq/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3e-hold-int-seq/native_posix.keymap b/app/tests/tap-dance/3e-hold-int-seq/native_posix.keymap new file mode 100644 index 00000000..b31e92dc --- /dev/null +++ b/app/tests/tap-dance/3e-hold-int-seq/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/3f-hold-int-after/events.patterns b/app/tests/tap-dance/3f-hold-int-after/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/3f-hold-int-after/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/3f-hold-int-after/keycode_events.snapshot b/app/tests/tap-dance/3f-hold-int-after/keycode_events.snapshot new file mode 100644 index 00000000..044018e0 --- /dev/null +++ b/app/tests/tap-dance/3f-hold-int-after/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 0 created new tap dance +td_binding_pressed: 0 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 0 tap dance keybind released +kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/3f-hold-int-after/native_posix.keymap b/app/tests/tap-dance/3f-hold-int-after/native_posix.keymap new file mode 100644 index 00000000..6397fbb3 --- /dev/null +++ b/app/tests/tap-dance/3f-hold-int-after/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,400) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/4a-single/events.patterns b/app/tests/tap-dance/4a-single/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/4a-single/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/4a-single/keycode_events.snapshot b/app/tests/tap-dance/4a-single/keycode_events.snapshot new file mode 100644 index 00000000..6d60e842 --- /dev/null +++ b/app/tests/tap-dance/4a-single/keycode_events.snapshot @@ -0,0 +1,5 @@ +td_binding_pressed: 1 created new tap dance +td_binding_pressed: 1 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 1 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x16 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/4a-single/native_posix.keymap b/app/tests/tap-dance/4a-single/native_posix.keymap new file mode 100644 index 00000000..348a6827 --- /dev/null +++ b/app/tests/tap-dance/4a-single/native_posix.keymap @@ -0,0 +1,11 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(0,1,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5a-tdint-mid/events.patterns b/app/tests/tap-dance/5a-tdint-mid/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/5a-tdint-mid/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5a-tdint-mid/keycode_events.snapshot b/app/tests/tap-dance/5a-tdint-mid/keycode_events.snapshot new file mode 100644 index 00000000..301dc914 --- /dev/null +++ b/app/tests/tap-dance/5a-tdint-mid/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 3 tap dance keybind released +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5a-tdint-mid/native_posix.keymap b/app/tests/tap-dance/5a-tdint-mid/native_posix.keymap new file mode 100644 index 00000000..2188fd02 --- /dev/null +++ b/app/tests/tap-dance/5a-tdint-mid/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_RELEASE(1,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5b-tdint-seq/events.patterns b/app/tests/tap-dance/5b-tdint-seq/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/5b-tdint-seq/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5b-tdint-seq/keycode_events.snapshot b/app/tests/tap-dance/5b-tdint-seq/keycode_events.snapshot new file mode 100644 index 00000000..567ec079 --- /dev/null +++ b/app/tests/tap-dance/5b-tdint-seq/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_released: 3 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5b-tdint-seq/native_posix.keymap b/app/tests/tap-dance/5b-tdint-seq/native_posix.keymap new file mode 100644 index 00000000..320b7199 --- /dev/null +++ b/app/tests/tap-dance/5b-tdint-seq/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_RELEASE(1,1,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5c-tdint-after/events.patterns b/app/tests/tap-dance/5c-tdint-after/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/5c-tdint-after/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5c-tdint-after/keycode_events.snapshot b/app/tests/tap-dance/5c-tdint-after/keycode_events.snapshot new file mode 100644 index 00000000..cc1da902 --- /dev/null +++ b/app/tests/tap-dance/5c-tdint-after/keycode_events.snapshot @@ -0,0 +1,10 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 3 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5c-tdint-after/native_posix.keymap b/app/tests/tap-dance/5c-tdint-after/native_posix.keymap new file mode 100644 index 00000000..17e538bd --- /dev/null +++ b/app/tests/tap-dance/5c-tdint-after/native_posix.keymap @@ -0,0 +1,13 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/5d-tdint-multiple/events.patterns b/app/tests/tap-dance/5d-tdint-multiple/events.patterns new file mode 100644 index 00000000..1768fc21 --- /dev/null +++ b/app/tests/tap-dance/5d-tdint-multiple/events.patterns @@ -0,0 +1,2 @@ +s/.*hid_listener_keycode/kp/p +s/.*on_tap_dance_binding/td_binding/p \ No newline at end of file diff --git a/app/tests/tap-dance/5d-tdint-multiple/keycode_events.snapshot b/app/tests/tap-dance/5d-tdint-multiple/keycode_events.snapshot new file mode 100644 index 00000000..afb32824 --- /dev/null +++ b/app/tests/tap-dance/5d-tdint-multiple/keycode_events.snapshot @@ -0,0 +1,15 @@ +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 3 created new tap dance +td_binding_pressed: 3 tap dance pressed +td_binding_released: 3 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00 +td_binding_pressed: 2 created new tap dance +td_binding_pressed: 2 tap dance pressed +td_binding_released: 2 tap dance keybind released +kp_pressed: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 +kp_released: usage_page 0x07 keycode 0x1e implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/tap-dance/5d-tdint-multiple/native_posix.keymap b/app/tests/tap-dance/5d-tdint-multiple/native_posix.keymap new file mode 100644 index 00000000..150f6d05 --- /dev/null +++ b/app/tests/tap-dance/5d-tdint-multiple/native_posix.keymap @@ -0,0 +1,15 @@ +#include +#include +#include +#include "../behavior_keymap.dtsi" + +&kscan { + events = < + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,10) + ZMK_MOCK_PRESS(1,1,10) + ZMK_MOCK_RELEASE(1,1,10) + ZMK_MOCK_PRESS(1,0,10) + ZMK_MOCK_RELEASE(1,0,200) + >; +}; \ No newline at end of file diff --git a/app/tests/tap-dance/behavior_keymap.dtsi b/app/tests/tap-dance/behavior_keymap.dtsi new file mode 100644 index 00000000..5e95cd50 --- /dev/null +++ b/app/tests/tap-dance/behavior_keymap.dtsi @@ -0,0 +1,60 @@ +#include +#include +#include + +/ { + behaviors { + ht: hold_tap { + compatible = "zmk,behavior-hold-tap"; + label = "HOLD_TAP"; + #binding-cells = <2>; + tapping-term-ms = <200>; + quick_tap_ms = <0>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + + tdm: tap_dance_mixed { + compatible = "zmk,behavior-tap-dance"; + label = "TAP_DANCE_MOD"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&ht LSHIFT A>, <&ht LALT B>, <&ht LGUI C>; + }; + + tdb: tap_dance_basic { + compatible = "zmk,behavior-tap-dance"; + label = "TAP_DANCE_BASIC"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp N1>, <&kp N2>, <&kp N3>; + }; + + td2: tap_dance_basic_2 { + compatible = "zmk,behavior-tap-dance"; + label = "TAP_DANCE_BASIC_2"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp A>, <&kp B>, <&kp C>; + }; + + tds: tap_dance_single { + compatible = "zmk,behavior-tap-dance"; + label = "TAP_DANCE_SINGlE"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp S>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &tdm &tds + &tdb &td2>; + }; + }; +}; diff --git a/docs/blog/2022-03-08-zephyr-3-0-upgrade-prep.md b/docs/blog/2022-03-08-zephyr-3-0-upgrade-prep.md new file mode 100644 index 00000000..2f3c79ee --- /dev/null +++ b/docs/blog/2022-03-08-zephyr-3-0-upgrade-prep.md @@ -0,0 +1,29 @@ +--- +title: "Zephyr 3.0 Update Preparation" +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [firmware, zephyr, core] +--- + +As preparation for completing the [work](https://github.com/zmkfirmware/zmk/pull/1143) to upgrade ZMK to [Zephyr 3.0](https://docs.zephyrproject.org/3.0.0/releases/release-notes-3.0.html), users with user config repositories who wish to avoid future build failures with their GitHub Actions workflows can take steps to adjust +their repositories now. + +GitHub Actions needs to use our latest Docker image to ensure continued compatibility with the ZMK codebase on Zephyr 3.0 (and beyond). You should: + +- Open `.github/workflows/build.yml` in your editor/IDE +- Change `zmkfirmware/zmk-build-arm:2.5` to `zmkfirmware/zmk-build-arm:stable` wherever it is found + +Once the changes are committed and pushed, the build will run as expected. + +A future blog post will outline the complete Zephyr 3.0 changes once that work is finalized. + +:::note + +If you created your user config repository a while ago, you may find that your `build.yml` file instead references +a `zephyr-west-action-arm` custom GitHub Action instead. In this case, the upgrade is not as direct. We suggest that +instead you [re-create your config repository](/docs/user-setup) to get an updated setup using the new automation +approach. + +::: diff --git a/docs/docs/assets/tap-dance/timing_diagram.svg b/docs/docs/assets/tap-dance/timing_diagram.svg new file mode 100644 index 00000000..ab02dcaf --- /dev/null +++ b/docs/docs/assets/tap-dance/timing_diagram.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/docs/assets/troubleshooting/splitpairing/corecoverage.png b/docs/docs/assets/troubleshooting/splitpairing/corecoverage.png new file mode 100755 index 00000000..a2a928be Binary files /dev/null and b/docs/docs/assets/troubleshooting/splitpairing/corecoverage.png differ diff --git a/docs/docs/behaviors/bluetooth.md b/docs/docs/behaviors/bluetooth.md index df264cee..d21f3832 100644 --- a/docs/docs/behaviors/bluetooth.md +++ b/docs/docs/behaviors/bluetooth.md @@ -82,7 +82,7 @@ ZMK support bluetooth “profiles” which allows connection to multiple devices The bluetooth MAC address and negotiated keys during pairing are stored in the permanent storage on your chip and can be reused even after reflashing the firmware. If for some reason you want to delete the stored information, you can bind the `BT_CLR` behavior described above to a key and use it to clear the _current_ profile. :::note Number of Profiles -Please note there are only five available Bluetooth profiles by default. If you need to increase the number of available profiles you can set `CONFIG_BT_MAX_CONN` in your `zmk-config` `.conf` file. +Please note there are five available Bluetooth profiles by default. If you need to adjust the number of available profiles, set `CONFIG_BT_MAX_CONN` _and_ `CONFIG_BT_MAX_PAIRED` to the desired number of profiles, `n`, or `n+1` for split keyboards, in your `zmk-config` `.conf` file. ::: :::note diff --git a/docs/docs/behaviors/macros.md b/docs/docs/behaviors/macros.md new file mode 100644 index 00000000..aca9eb7a --- /dev/null +++ b/docs/docs/behaviors/macros.md @@ -0,0 +1,227 @@ +--- +title: Macro Behavior +sidebar_label: Macros +--- + +## Summary + +The macro behavior allows configuring a list of other behaviors to invoke +when the macro is pressed and/or released. + +## Macro Definition + +Each macro you want to use in your keymap gets defined first, then bound in your keymap. + +A macro definition looks like: + +``` +/ { + macros { + zed_em_kay: zed_em_kay { + label = "ZM_zed_em_kay"; + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <¯o_press &kp LSHFT> + , <¯o_tap &kp Z &kp M &kp K> + , <¯o_release &kp LSHFT> + ; + }; + }; +}; +``` + +:::note +The text before the colon (`:`) in the declaration of the macro node is the "node label", and is the text +used to reference the macro in your keymap +::: + +The macro can then be bound in your keymap by referencing it by the label `&zed_em_kay`, e.g.: + +``` + raise_layer { + bindings = <&zed_em_kay>; + }; +``` + +### Bindings + +Like [hold-taps](/docs/behaviors/hold-tap), macros are created by composing other behaviors, and any of those behaviors can +be added to the `bindings` list, e.g.: + +``` +bindings + = <&to 1> + , <&bl BL_ON> + , <&kp Z &kp M &kp K &kp EXCLAMATION> + ; +``` + +## Macro Controls + +There are a set of special macro controls that can be included in the `bindings` list to modify the +way the macro is processed. + +### Binding Activation Mode + +Bindings in a macro are activated differently, depending on the current "activation mode" of the macro. + +Available modes: + +- Tap - The default mode; when in this mode, the macro will press, then release, each behavior in the `bindings` list. This mode is useful for + basic keycode output to hosts, i.e. when activating a `&kp` behavior. +- Press - In this mode, the macro will only trigger a press on each behavior in the `bindings` list. This is useful for holding down modifiers for some duration of a macro, e.g. `&kp LALT`. +- Release - In this mode, the macro will only trigger a release on each behavior in the `bindings` list. This is useful for releasing modifiers previously pressed earlier in the macro processing, e.g. `&kp LALT`. + +To modify the activation mode, macro controls can be added at any point in the `bindings` list. + +- `¯o_tap` +- `¯o_press` +- `¯o_release` + +A concrete example, used to hold a modifier, tap multiple keys, then release the modifier, would look like: + +``` +bindings + = <¯o_press &kp LSHFT> + , <¯o_tap &kp Z &kp M &kp K> + , <¯o_release &kp LSHFT> + ; +``` + +### Processing Continuation on Release + +The macro can be paused so that only part of the `bindings` list is processed when the macro is pressed, and the remainder is processed once +the macro itself is released. + +To pause the macro until release, use `¯o_pause_for_release`. For example, this macro will press a modifier and activate a layer when the macro is pressed. Once the macro is released, it will release the modifier and deactivate the layer by releasing the `&mo`: + +``` +bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT> + ; +``` + +### Wait Time + +The wait time setting controls how long of a delay is introduced between behaviors in the `bindings` list. The initial wait time for a macro, 100ms by default, can +be set by assigning a value to the `wait-ms` property of the macro, e.g. `wait-ms = <20>;`. If you want to update the wait time at any +point in the macro bindings list, use `¯o_wait_time`, e.g. `¯o_wait_time 30`. A full example: + +``` +wait-ms = <10>; +bindings + = <&kp F &kp A &kp S &kp T> + , <¯o_wait_time 500> + , <&kp S &kp L &kp O &kp W> + ; +``` + +### Tap Time + +The tap time setting controls how long a tapped behavior is held in the `bindings` list. The initial tap time for a macro, 100ms by default, can +be set by assigning a value to the `tap-ms` property of the macro, e.g. `tap-ms = <20>;`. If you want to update the tap time at any +point in a macro bindings list, use `¯o_tap_time`, e.g. `¯o_tap_time 30`. A full example: + +``` +bindings + = <¯o_tap_time 10> + , <&kp S &kp H &kp O &kp R &kp T> + , <¯o_tap_time 500> + , <&kp L &kp O &kp N &kp G> + ; +``` + +## Common Patterns + +Below are some examples of how the macro behavior can be used for various useful functionality. + +### Layer Activation + More + +Macros make it easy to combine a [layer behavior](/docs/behaviors/layers), e.g. `&mo` with another behavior at the same time. +Common examples are enabling one or more modifiers when the layer is active, or changing the RBG underglow color. + +To achieve this, a combination of a 0ms wait time and splitting the press and release between a `¯o_pause_for_release` is used: + +#### Layer + Modifier + +``` +wait-ms = <0>; +bindings + = <¯o_press &mo 1 &kp LSHFT> + , <¯o_pause_for_release> + , <¯o_release &mo 1 &kp LSHFT>; +``` + +#### Layer + Underglow Color + +To trigger a different underglow when the macro is pressed, and when it is released, we use the macro "press" activation mode whenever triggering the `&rgb_ug` behavior: + +``` +wait-ms = <0>; +tap-ms = <0>; +bindings + = <¯o_press &mo 1> + , <¯o_tap &rgb_ug RGB_COLOR_HSB(128,100,100)> + , <¯o_pause_for_release> + , <¯o_release &mo 1> + , <¯o_tap &rgb_ug RGB_COLOR_HSB(300,100,50)>; +``` + +### Keycode Sequences + +The other common use case for macros is to sending sequences of keycodes to the connected host. Here, a wait and tap time of at least 30ms is recommended to +avoid having HID notifications grouped at the BLE protocol level and then processed out of order: + +``` +wait-ms = <40>; +tap-ms = <40>; +bindings + = <&kp Z &kp M &kp K> + , <&kp SPACE> + , <&kp R &kp O &kp C &kp K &kp S> + ; +``` + +### Unicode Sequences + +Many operating systems allow a special sequence to input unicode characters, e.g. [Windows alt codes](https://support.microsoft.com/en-us/office/insert-ascii-or-unicode-latin-based-symbols-and-characters-d13f58d3-7bcb-44a7-a4d5-972ee12e50e0). You can use macros to automate inputting the sequences, e.g. below macro inserts `£` on Windows: + +``` +wait-ms = <40>; +tap-ms = <40>; +bindings + = <¯o_press &kp LALT> + , <¯o_tap &kp KP_N0 &kp KP_N1 &kp KP_N6 &kp KP_N3> + , <¯o_release &kp LALT> + ; +``` + +## Convenience C Macro + +To avoid repetition or possible typos when declaring a macro, a convenience _C_ macro, named `ZMK_MACRO(name, props)` can be used to simplify things: + +``` + ZMK_MACRO(my_macro, + wait-ms = <30>; + tap-ms = <40>; + bindings = <&kp Z &kp M &kp K>; + ) +``` + +This can be used instead of a complete macro definition. During the firmware build process, the example above would produce the complete macro definition below: + +``` + my_macro: my_macro { + compatible = "zmk,behavior-macro"; + label = "ZM_my_macro"; + #binding-cells = <0>; + wait-ms = <30>; + tap-ms = <40>; + bindings = <&kp Z &kp M &kp K>; + }; +``` + +Using the C macro is entirely optional, and is provided only as a convenience. diff --git a/docs/docs/behaviors/tap-dance.md b/docs/docs/behaviors/tap-dance.md new file mode 100644 index 00000000..af49ca3c --- /dev/null +++ b/docs/docs/behaviors/tap-dance.md @@ -0,0 +1,76 @@ +--- +title: Tap-Dance Behavior +sidebar_label: Tap-Dance +--- + +## Summary + +A tap-dance key invokes a different behavior (e.g. `kp`) corresponding +to how many times it is pressed. For example, you could configure a +tap-dance key that acts as `LSHIFT` if tapped once, or Caps _Lock_ if tapped twice. +The expandability of the number of [`bindings`](#bindings) attached to a +particular tap-dance is a great way to add more functionality to a single key, +especially for keyboards with a limited number of keys. +Tap-dances are completely custom, so for every unique tap-dance key, +a new tap-dance must be defined in your keymap's `behaviors`. + +Tap-dances are designed to resolve immediately when interrupted by another keypress. +Meaning, when a keybind is pressed other than any active tap-dances, +the tap-dance will activate according to the current value of its +counter before the interrupting keybind is registered. + +### Configuration + +#### `tapping-term-ms` + +Defines the maximum elapsed time after the last tap-dance keybind press +before a binding is selected from [`bindings`](#bindings). +Default value is `200`ms. + +#### `bindings` + +An array of one or more keybinds. This list can include [any ZMK keycode](../codes/) and bindings for ZMK behaviors. + +#### Example Usage + +This example configures a tap-dance named `td0` that outputs the number of times it is pressed from 1-3. + +``` +#include +#include + +/ { + behaviors { + td0: tap_dance_0 { + compatible = "zmk,behavior-tap-dance"; + label = "TAP_DANCE_0"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&kp N1>, <&kp N2>, <&kp N3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &td0 + >; + }; + }; +}; +``` + +The following image describes the behavior of this particular tap-dance. + +![Timing Diagram](../assets/tap-dance/timing_diagram.svg) + +:::note +Alphanumeric [`key press`](key-press.md) bindings, like those used for `td0`, +will release as soon as an interrupting key press occurs. +For instance, if a modifier key like `LSHIFT` were to replace the `N1` +binding in the last example above, it would remain pressed until `td0`'s +binding is released and the output would instead be `J`. Any following +alphanumeric key presses would be capitalized as long as `td0` is held down. +::: diff --git a/docs/docs/intro.md b/docs/docs/intro.md index b8a6316c..91b4e21b 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -23,6 +23,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | Split Keyboard Support | ✅ | ✅ | ✅ | | [Keymaps and Layers](behaviors/layers.md) | ✅ | ✅ | ✅ | | [Hold-Tap](behaviors/hold-tap.md) (which includes [Mod-Tap](behaviors/mod-tap.md) and [Layer-Tap](behaviors/layers.md/#layer-tap)) | ✅ | ✅ | ✅ | +| [Tap-Dance](behaviors/tap-dance.md) | ✅ | ✅[^3] | ✅ | | [Keyboard Codes](codes/index.mdx#keyboard) | ✅ | ✅ | ✅ | | [Media](codes/index.mdx#media-controls) & [Consumer](codes/index.mdx#consumer-controls) Codes | ✅ | ✅ | ✅ | | [Encoders](features/encoders.md)[^1] | ✅ | ✅ | ✅ | @@ -31,7 +32,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | [Backlight](features/backlight.md) | ✅ | ✅ | ✅ | | One Shot Keys | ✅ | ✅ | ✅ | | [Combo Keys](features/combos.md) | ✅ | | ✅ | -| Macros | 🚧 | ✅ | ✅ | +| [Macros](behaviors/macros) | ✅ | ✅ | ✅ | | Mouse Keys | 🚧 | ✅ | ✅ | | Low Active Power Usage | ✅ | | | | Low Power Sleep States | ✅ | ✅ | | @@ -42,6 +43,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | AVR/8 Bit | | | ✅ | | [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | +[^3]: Tap-Dances are limited to single and double-tap on BlueMicro [^2]: Encoders are not currently supported on peripheral side splits. [^1]: OLEDs are currently proof of concept in ZMK. diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 3055c131..0f2ea4c9 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -37,6 +37,10 @@ This can be verified by checking the file in question, found in `mkdir/app/build After opening the `.dts.pre.tmp:` and scrolling down to the referenced line, one can locate errors within their shield's keymap by checking if the referenced keycodes were properly converted into the correct [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12). +:::note +If you are reviewing these errors in the GitHub Actions tab, the contents of `.dts.pre.tmp` is output (with line numbers) in the next step of the build process. +::: + | ![Unhealthy Keymap Temp](../docs/assets/troubleshooting/keymaps/unhealthyEDIT.png) | | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | | An incorrectly defined keymap unable to compile. As shown in red, `&kp SPAC` is not a valid reference to the [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12) used for "Keyboard Spacebar" | @@ -47,23 +51,44 @@ After opening the `.dts.pre.tmp:` and scrolling down to the ### Split Keyboard Halves Unable to Pair -Previously, pairing split keyboard halves involved a **BLE Reset** via a combination of held keys that removed all bluetooth profile information from the keyboard. -Since then, a much simpler procedure of performing a bluetooth reset for split keyboards has come about, without the need for any file modification: +Split keyboard halves pairing issue can be resolved by flashing a settings reset firmware to both controllers. You will first need to acquire the reset UF2 image file with one of the following options: -**New Procedure:** +#### Option 1: Build Reset UF2 in 'zmk-config' + +Find the `build.yaml` file in your `zmk-config` folder and add an additional settings reset build for the board used by your split keyboard. For example assuming that the config repo is setup for nice!nano v2 with Corne, append the `settings_reset` shield to the `build.yaml` file as follows: + +```yml +include: + - board: nice_nano_v2 + shield: corne_left + - board: nice_nano_v2 + shield: corne_right + - board: nice_nano_v2 + shield: settings_reset +``` + +Save the file, commit the changes and push them to GitHub. Download the new firmware zip file build by the latest GitHub Actions job. In it you will find an additional `settings_reset` UF2 image file. + +#### Option 2: Download Reset UF2 from ZMK's Workflow 1. [Open the GitHub `Actions` tab and select the `Build` workflow](https://github.com/zmkfirmware/zmk/actions?query=workflow%3ABuild+branch%3Amain+event%3Apush). -1. Select the top 'result' on that page. -1. From the next page under "Artifacts", download the `$boardname-settings_reset-zmk` zip file. -1. Unzip the downloaded file. -1. Put each half of the split keyboard into bootloader mode -1. Flash one of the halves of the split with the "settings clear" UF2 image from step 1. Immediately after flashing "settings clear" to the chosen half, immediately put it into bootloader mode - to avoid accidental bonding between the halves. -1. Repeat step 3 with the other half of the split keyboard -1. Flash the actual image for each half of the split keyboard (e.g `my_board_left.uf2` to the left half, `my_board_right.uf2` to the right half) +1. Find one of the 'results' for which the core-coverage job was successfully run, indicated by a green checkmark in the core-coverage bubble like the image example below. +1. From the next page under "Artifacts", download and unzip the `-settings_reset-zmk` zip file for the UF2 image. -After completing these steps, pair the halves of the split keyboard together by resetting them at the same time. Most commonly, this is done by grounding the reset pins -for each of your keyboard's microcontrollers or pressing the reset buttons at the same time. +| ![Successful core-coverage Job](../docs/assets/troubleshooting/splitpairing/corecoverage.png) | +| :-------------------------------------------------------------------------------------------: | +| An example of a successful core-coverage job which will produce a settings_reset firmware. | + +#### Reset Split Keyboard Procedure + +Perform the following steps to reset both halves of your split keyboard: + +1. Put each half of the split keyboard into bootloader mode. +1. Flash one of the halves of the split with the downloaded settings reset UF2 image. Immediately after flashing the chosen half, put it into bootloader mode to avoid accidental bonding between the halves. +1. Repeat step 2 with the other half of the split keyboard. +1. Flash the actual image for each half of the split keyboard (e.g `my_board_left.uf2` to the left half, `my_board_right.uf2` to the right half). + +After completing these steps, pair the halves of the split keyboard together by resetting them at the same time. Most commonly, this is done by grounding the reset pins for each of your keyboard's microcontrollers or pressing the reset buttons at the same time. ### Connectivity Issues diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index ed018f30..b1c1b5c0 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -11,6 +11,7 @@ module.exports = { plugins: [ path.resolve(__dirname, "src/docusaurus-tree-sitter-plugin"), path.resolve(__dirname, "src/hardware-metadata-collection-plugin"), + path.resolve(__dirname, "src/hardware-metadata-static-plugin"), path.resolve(__dirname, "src/hardware-schema-typescript-plugin"), path.resolve(__dirname, "src/setup-script-generation-plugin"), ], diff --git a/docs/netlify.toml b/docs/netlify.toml index 9b0fd727..87462006 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -14,4 +14,9 @@ [[redirects]] from = "https://www.zmkfirmware.dev/*" to = "https://www.zmk.dev/:splat" - force = true \ No newline at end of file + force = true + +[[headers]] + for = "/hardware-metadata.json" + [headers.values] + Access-Control-Allow-Origin = "*" \ No newline at end of file diff --git a/docs/package-lock.json b/docs/package-lock.json index 166a8d72..d8d3cf9b 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -25,7 +25,9 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "^2.0.0-beta.3", + "@docusaurus/types": "^2.0.0-beta.3", "@tsconfig/docusaurus": "^1.0.2", + "@types/js-yaml": "^4.0.5", "@types/react": "^17.0.3", "@types/react-helmet": "^6.1.0", "@types/react-router-dom": "^5.1.7", @@ -6303,14 +6305,6 @@ "node": ">=12" } }, - "node_modules/@docusaurus/theme-classic/node_modules/prism-react-renderer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz", - "integrity": "sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg==", - "peerDependencies": { - "react": ">=0.14.9" - } - }, "node_modules/@docusaurus/theme-common": { "version": "2.0.0-beta.3", "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.0.0-beta.3.tgz", @@ -6368,6 +6362,76 @@ "webpack-merge": "^5.8.0" } }, + "node_modules/@docusaurus/types/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + }, + "node_modules/@docusaurus/types/node_modules/acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@docusaurus/types/node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack": { + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.2", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, "node_modules/@docusaurus/utils": { "version": "2.0.0-beta.3", "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.0.0-beta.3.tgz", @@ -6982,9 +7046,9 @@ "integrity": "sha512-15spi3V28QdevleWBNXE4pIls3nFZmBbUGrW9IVPwiQczuSb9n76TCB4bsk8TSel+I1OkHEdPhu5QKMfY6rQHA==" }, "node_modules/@sideway/address": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", - "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "dependencies": { "@hapi/hoek": "^9.0.0" } @@ -7506,9 +7570,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -7552,6 +7616,12 @@ "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", "integrity": "sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==" }, + "node_modules/@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -10464,9 +10534,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", + "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -12249,9 +12319,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, "node_modules/gray-matter": { "version": "4.0.3", @@ -13830,13 +13900,13 @@ } }, "node_modules/joi": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.1.tgz", - "integrity": "sha512-gDPOwQ5sr+BUxXuPDGrC1pSNcVR/yGGcTI0aCnjYxZEa3za60K/iCQ+OFIkEHWZGVCUcUlXlFKvMmrlmxrG6UQ==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.0", + "@sideway/address": "^4.1.3", "@sideway/formula": "^3.0.0", "@sideway/pinpoint": "^2.0.0" } @@ -16359,6 +16429,14 @@ "node": ">=4" } }, + "node_modules/prism-react-renderer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz", + "integrity": "sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ==", + "peerDependencies": { + "react": ">=0.14.9" + } + }, "node_modules/prismjs": { "version": "1.24.1", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.24.1.tgz", @@ -20034,9 +20112,9 @@ } }, "node_modules/watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -20751,9 +20829,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "engines": { "node": ">=10.13.0" } @@ -25780,12 +25858,6 @@ "jsonfile": "^6.0.1", "universalify": "^2.0.0" } - }, - "prism-react-renderer": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz", - "integrity": "sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg==", - "requires": {} } } }, @@ -25829,6 +25901,55 @@ "querystring": "0.2.0", "webpack": "^5.40.0", "webpack-merge": "^5.8.0" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + }, + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "requires": {} + }, + "webpack": { + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.2", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + } + } } }, "@docusaurus/utils": { @@ -26315,9 +26436,9 @@ "integrity": "sha512-15spi3V28QdevleWBNXE4pIls3nFZmBbUGrW9IVPwiQczuSb9n76TCB4bsk8TSel+I1OkHEdPhu5QKMfY6rQHA==" }, "@sideway/address": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", - "integrity": "sha512-idTz8ibqWFrPU8kMirL0CoPH/A29XOzzAzpyN3zQ4kAWnzmNfFmRaoMNN6VI8ske5M73HZyhIaW4OuSFIdM4oA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", "requires": { "@hapi/hoek": "^9.0.0" } @@ -26690,9 +26811,9 @@ } }, "@types/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "requires": { "@types/eslint": "*", "@types/estree": "*" @@ -26736,6 +26857,12 @@ "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", "integrity": "sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==" }, + "@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -29017,9 +29144,9 @@ } }, "enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", + "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -30405,9 +30532,9 @@ } }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, "gray-matter": { "version": "4.0.3", @@ -31589,13 +31716,13 @@ } }, "joi": { - "version": "17.4.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.4.1.tgz", - "integrity": "sha512-gDPOwQ5sr+BUxXuPDGrC1pSNcVR/yGGcTI0aCnjYxZEa3za60K/iCQ+OFIkEHWZGVCUcUlXlFKvMmrlmxrG6UQ==", + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", + "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", "requires": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.0", + "@sideway/address": "^4.1.3", "@sideway/formula": "^3.0.0", "@sideway/pinpoint": "^2.0.0" } @@ -33457,6 +33584,12 @@ "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==" }, + "prism-react-renderer": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz", + "integrity": "sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ==", + "requires": {} + }, "prismjs": { "version": "1.24.1", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.24.1.tgz", @@ -36265,9 +36398,9 @@ } }, "watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "requires": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -36834,9 +36967,9 @@ } }, "webpack-sources": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.1.tgz", - "integrity": "sha512-t6BMVLQ0AkjBOoRTZgqrWm7xbXMBzD+XDq2EZ96+vMfn3qKgsvdXZhbPZ4ElUOpdv4u+iiGe+w3+J75iy/bYGA==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" }, "websocket-driver": { "version": "0.7.4", diff --git a/docs/package.json b/docs/package.json index 6a5b9f2f..8941645e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -44,7 +44,9 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "^2.0.0-beta.3", + "@docusaurus/types": "^2.0.0-beta.3", "@tsconfig/docusaurus": "^1.0.2", + "@types/js-yaml": "^4.0.5", "@types/react": "^17.0.3", "@types/react-helmet": "^6.1.0", "@types/react-router-dom": "^5.1.7", diff --git a/docs/sidebars.js b/docs/sidebars.js index 647399a7..cbeceef7 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -26,8 +26,10 @@ module.exports = { "behaviors/hold-tap", "behaviors/mod-tap", "behaviors/mod-morph", + "behaviors/macros", "behaviors/sticky-key", "behaviors/sticky-layer", + "behaviors/tap-dance", "behaviors/caps-word", "behaviors/key-repeat", "behaviors/reset", diff --git a/docs/src/components/hardware-list.tsx b/docs/src/components/hardware-list.tsx index ec7e8a10..e611f5cf 100644 --- a/docs/src/components/hardware-list.tsx +++ b/docs/src/components/hardware-list.tsx @@ -70,7 +70,7 @@ function mapInterconnect({ return (
-

{interconnect.name} Keyboards

+

{interconnect.name} Interconnect

{interconnect.description &&

{interconnect.description}

}
Boards
    @@ -148,7 +148,7 @@ function HardwareList({ items }: HardwareListProps) { return ( <>

    Keyboards

    -

    Onboard Controller Boards

    +

    Onboard Controller Keyboards

    Keyboards with onboard controllers are single PCBs that contain all the components of a keyboard, including the controller chip, switch @@ -161,12 +161,13 @@ function HardwareList({ items }: HardwareListProps) { ))}

-

Composite Boards

+

Composite Keyboards

Composite keyboards are composed of two main PCBs: a small controller board with exposed pads, and a larger keyboard PCB (a shield, in ZMK - lingo) with switch footprints and location a where the controller is - added. + lingo) with switch footprints and a location where the controller is + added. This location is called an interconnect. Multiple interconnects + can be found below.

{Object.values(grouped.interconnects).map(mapInterconnect)} diff --git a/docs/src/hardware-metadata-static-plugin/index.js b/docs/src/hardware-metadata-static-plugin/index.js new file mode 100644 index 00000000..7fb6ad83 --- /dev/null +++ b/docs/src/hardware-metadata-static-plugin/index.js @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +//@ts-check +"use strict"; + +/** @typedef {import('../hardware-metadata').HardwareMetadata} HardwareMetadata */ +/** @typedef {HardwareMetadata & { directory: string}} LocatedHardwareMetadata */ + +const fs = require("fs").promises; +const glob = require("util").promisify(require("glob")); +const path = require("path"); +const yaml = require("js-yaml"); + +const BASE_DIR = ".."; +const METADATA_GLOB = path.posix.join(BASE_DIR, "app/boards/**/*.zmk.yml"); + +/** + * @param {string} file + */ +async function readMetadata(file) { + /** @type HardwareMetadata[] */ + // @ts-ignore + const documents = yaml.loadAll(await fs.readFile(file, "utf-8")); + + return documents.map( + (metadata) => + /** @type LocatedHardwareMetadata */ + ({ + ...metadata, + // External tools need a way to locate this hardware within the repo. + // Append each item's relative path. + directory: path.posix.dirname(path.posix.relative(BASE_DIR, file)), + }) + ); +} + +async function aggregateMetadata() { + const files = await glob(METADATA_GLOB); + const data = await Promise.all(files.map(readMetadata)); + + return data.flat(); +} + +/** + * Aggregates .zmk.yml files and writes hardware-metadata.json to the site's + * static files post-build. + * + * This is very similar to hardware-metadata-collection-plugin but adjusts the + * output for consumption by external tools rather than the website build system. + * + * @type {import('@docusaurus/types').PluginModule} + */ +module.exports = function () { + return { + name: "hardware-metadata-static-plugin", + + async postBuild({ outDir }) { + const hardware = await aggregateMetadata(); + + const hardwarePath = path.join(outDir, "hardware-metadata.json"); + await fs.writeFile(hardwarePath, JSON.stringify(hardware)); + }, + }; +};