Merge branch 'zmkfirmware:main' into main

This commit is contained in:
JW2586 2022-03-31 15:47:05 +01:00 committed by GitHub
commit 8bb66aadc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
144 changed files with 3114 additions and 86 deletions

View file

@ -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_sticky_key.c)
target_sources(app PRIVATE src/behaviors/behavior_caps_word.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_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_momentary_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_mod_morph.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_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_toggle_layer.c)
target_sources(app PRIVATE src/behaviors/behavior_to_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_transparent.c)
target_sources(app PRIVATE src/behaviors/behavior_none.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/behaviors/behavior_sensor_rotate_key_press.c)
target_sources(app PRIVATE src/combo.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/conditional_layer.c)
target_sources(app PRIVATE src/keymap.c) target_sources(app PRIVATE src/keymap.c)
endif() endif()

View file

@ -410,6 +410,14 @@ config ZMK_COMBO_MAX_KEYS_PER_COMBO
#Combo options #Combo options
endmenu 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 "Advanced"
menu "Initialization Priorities" menu "Initialization Priorities"

View file

@ -11,6 +11,9 @@ CONFIG_FPU=y
# enable GPIO # enable GPIO
CONFIG_GPIO=y CONFIG_GPIO=y
# Needed for matrix to properly work
CONFIG_ZMK_KSCAN_DIRECT_POLLING=y
# Enable pinmux # Enable pinmux
CONFIG_PINMUX=y CONFIG_PINMUX=y

View file

@ -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(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(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(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) 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)
>; >;
}; };

View file

@ -8,3 +8,7 @@ description: |
The SparkFun Pro Micro grew popular as a low cost ATmega32U4 board with sufficient GPIO and peripherals 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, 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. 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.

View file

@ -0,0 +1,9 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT
if SHIELD_BAT43
config ZMK_KEYBOARD_NAME
default "Bat43"
endif

View file

@ -0,0 +1,5 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT
config SHIELD_BAT43
def_bool $(shields_list_contains,bat43)

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
#include <dt-bindings/zmk/outputs.h>
#define LOWER 1
#define RAISE 2
#define L_SPC &lt LOWER SPACE
#define R_RET &lt 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
>;
};
};
};

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/matrix_transform.h>
/ {
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)>
;
};
};

View file

@ -0,0 +1,8 @@
file_format: "1"
id: bat43
name: BAT43
type: shield
url: https://kbd.dailycraft.jp/bat43/
requires: [pro_micro]
features:
- keys

View file

@ -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

View file

@ -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)

View file

@ -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;
};
};

View file

@ -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

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/matrix_transform.h>
/ {
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>;
};
};

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
#include <dt-bindings/zmk/outputs.h>
#define LOWR 1
#define RAIS 2
#define ADJT 3
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&lt 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
>;
};
};
};

View file

@ -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

View file

@ -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>
;
};

View file

@ -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>
;
};

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
/ {
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>;
};
};
};

View file

@ -11,5 +11,5 @@ features:
- encoder - encoder
- underglow - underglow
siblings: siblings:
- kyria_left - kyria_rev2_left
- kyria_right - kyria_rev2_right

View file

@ -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

View file

@ -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)

View file

@ -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.

View file

@ -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

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/matrix_transform.h>
/ {
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>;
};
};

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors.dtsi>
#include <dt-bindings/zmk/outputs.h>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
// 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 &lt 1 RET &lt 2 MINUS &kp LGUI &kp LGUI &lt 2 EQUAL &lt 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>;
};
};
};

View file

@ -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

View file

@ -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";
};

View file

@ -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";
};

View file

@ -53,7 +53,7 @@
// ------------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------------
// | | | | | | | | | | | | | | // | | | | | | | | | | | | | |
// | ` | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | | // | ` | 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 | | | | + | - | = | [ | ] | \ | // | F7 | F8 | F9 | F10 | F11 | F12 | | | | + | - | = | [ | ] | \ |
// | | | | | | | | | | // | | | | | | | | | |
bindings = < bindings = <

View file

@ -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

View file

@ -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)

View file

@ -0,0 +1,2 @@
# Copyright (c) 2022 The ZMK Contributors
# SPDX-License-Identifier: MIT

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&kp X
&kp Z
>;
};
};
};

View file

@ -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)>
;
};
};

View file

@ -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

View file

@ -17,3 +17,4 @@
#include <behaviors/caps_word.dtsi> #include <behaviors/caps_word.dtsi>
#include <behaviors/key_repeat.dtsi> #include <behaviors/key_repeat.dtsi>
#include <behaviors/backlight.dtsi> #include <behaviors/backlight.dtsi>
#include <behaviors/macros.dtsi>

View file

@ -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>;
};
};
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <kernel.h>
#include <stdint.h>
#include <zmk/behavior.h>
int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding behavior,
bool press, uint32_t wait);

66
app/src/behavior_queue.c Normal file
View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <zmk/behavior_queue.h>
#include <kernel.h>
#include <logging/log.h>
#include <drivers/behavior.h>
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;
}

View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT zmk_behavior_macro
#include <device.h>
#include <drivers/behavior.h>
#include <logging/log.h>
#include <zmk/behavior.h>
#include <zmk/behavior_queue.h>
#include <zmk/keymap.h>
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) */

View file

@ -188,6 +188,9 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
if (ev == NULL) { if (ev == NULL) {
return ZMK_EV_EVENT_BUBBLE; 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++) { for (int i = 0; i < ZMK_BHV_STICKY_KEY_MAX_HELD; i++) {
struct active_sticky_key *sticky_key = &active_sticky_keys[i]; struct active_sticky_key *sticky_key = &active_sticky_keys[i];
if (sticky_key->position == ZMK_BHV_STICKY_KEY_POSITION_FREE) { 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) { if (sticky_key->timer_started) {
stop_timer(sticky_key); stop_timer(sticky_key);
if (sticky_key->config->quick_release) { if (sticky_key->config->quick_release) {
// continue processing the event. Release the sticky key afterwards. // immediately release the sticky key after the key press is handled.
if (!event_reraised) {
ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key); ZMK_EVENT_RAISE_AFTER(eh, behavior_sticky_key);
event_reraised = true;
}
release_sticky_key_behavior(sticky_key, ev->timestamp); release_sticky_key_behavior(sticky_key, ev->timestamp);
return ZMK_EV_EVENT_CAPTURED;
} }
} }
sticky_key->modified_key_usage_page = ev->usage_page; 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; return ZMK_EV_EVENT_BUBBLE;
} }

View file

@ -0,0 +1,259 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT zmk_behavior_tap_dance
#include <device.h>
#include <drivers/behavior.h>
#include <logging/log.h>
#include <zmk/behavior.h>
#include <zmk/keymap.h>
#include <zmk/matrix.h>
#include <zmk/event_manager.h>
#include <zmk/events/position_state_changed.h>
#include <zmk/events/keycode_state_changed.h>
#include <zmk/hid.h>
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

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*behavior_queue_process_next/queue_process_next/p

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <ZMK_MOCK_PRESS(0,0,10) ZMK_MOCK_RELEASE(0,0,1000)>;
};

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
/ {
macros {
ZMK_MACRO(abc_macro,
wait-ms = <10>;
tap-ms = <50>;
bindings = <&kp A &kp B &kp C>;
)
ZMK_MACRO(hold_shift_macro,
bindings
= <&macro_press &kp LSHFT>
, <&macro_tap>
, <&kp D &kp O &kp G>
, <&macro_release &kp LSHFT>
;
)
ZMK_MACRO(custom_timing,
bindings
= <&macro_wait_time 50>
, <&kp A>
, <&macro_tap_time 20>
, <&kp B &kp C>
;
)
ZMK_MACRO(dual_sequence_macro,
wait-ms = <10>;
tap-ms = <40>;
bindings
= <&macro_press &kp LALT>
, <&macro_tap>
, <&kp TAB>
, <&macro_pause_for_release>
, <&macro_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>;
};
};
};

View file

@ -0,0 +1 @@
s/.*hid_listener_keycode/kp/p

View file

@ -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

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
/ {
macros {
ZMK_MACRO(
mo_mod_macro,
wait-ms = <0>;
tap-ms = <20>;
bindings
= <&macro_press &mo 1 &kp LSHFT>
, <&macro_pause_for_release>
, <&macro_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 = <ZMK_MOCK_PRESS(0,0,20) ZMK_MOCK_PRESS(0,1,10) ZMK_MOCK_RELEASE(0,1,10) ZMK_MOCK_RELEASE(0,0,1000)>;
};

View file

@ -0,0 +1 @@
s/.*hid_listener_keycode/kp/p

View file

@ -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

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
/ {
macros {
ZMK_MACRO(
mo_mod_macro,
wait-ms = <0>;
tap-ms = <20>;
bindings
= <&macro_press &mo 1 &kp LSHFT>
, <&macro_pause_for_release>
, <&macro_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 = <ZMK_MOCK_PRESS(0,0,20) ZMK_MOCK_PRESS(0,1,10) ZMK_MOCK_RELEASE(0,1,10) ZMK_MOCK_RELEASE(0,0,1000)>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*keymap_apply_position_state/pos_state/p

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <ZMK_MOCK_PRESS(0,0,10) ZMK_MOCK_RELEASE(0,0,1) ZMK_MOCK_PRESS(0,1,10) ZMK_MOCK_RELEASE(0,1,1000)>;
};

View file

@ -0,0 +1 @@
s/.*hid_listener_keycode/kp/p

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_RELEASE(1,0,1000)>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*behavior_queue_process_next/queue_process_next/p

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <ZMK_MOCK_PRESS(1,1,10) ZMK_MOCK_RELEASE(1,1,750)>;
};

View file

@ -0,0 +1,3 @@
s/.*hid_listener_keycode/kp/p
s/.*behavior_queue_process_next/queue_process_next/p
s/.*queue_macro/qm/p

View file

@ -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

View file

@ -0,0 +1,14 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <ZMK_MOCK_PRESS(0,1,10) ZMK_MOCK_PRESS(0,0,400) ZMK_MOCK_PRESS(1,0,400) ZMK_MOCK_RELEASE(1,0,10) ZMK_MOCK_RELEASE(0,0,1000) ZMK_MOCK_RELEASE(0,1,1000)>;
};

View file

@ -0,0 +1 @@
s/.*hid_listener_keycode_//p

View file

@ -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

View file

@ -0,0 +1,65 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan-mock.h>
/*
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)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,11 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_RELEASE(0,0,200)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,13 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#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)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,15 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#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)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,11 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#include "../behavior_keymap.dtsi"
&kscan {
events = <
ZMK_MOCK_PRESS(0,0,400)
ZMK_MOCK_RELEASE(0,0,10)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,13 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#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)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,15 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#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)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

View file

@ -0,0 +1,13 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan_mock.h>
#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)
>;
};

View file

@ -0,0 +1,2 @@
s/.*hid_listener_keycode/kp/p
s/.*on_tap_dance_binding/td_binding/p

View file

@ -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

Some files were not shown because too many files have changed in this diff Show more