Merge branch 'zmkfirmware:main' into two_percent_milk

This commit is contained in:
Aaron Nunley 2021-06-22 21:27:11 -07:00 committed by GitHub
commit 7af570cdb2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
233 changed files with 18515 additions and 18774 deletions

View file

@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: DoozyX/clang-format-lint-action@v0.11
- uses: DoozyX/clang-format-lint-action@v0.12
with:
source: "./app"
extensions: "h,c"

12
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,12 @@
fail_fast: false
repos:
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.1.1
hooks:
- id: clang-format
args:
- -i
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.2.1
hooks:
- id: prettier

View file

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
conduct@zmkfirmware.dev.
conduct@zmk.dev.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the

View file

@ -7,7 +7,7 @@ you have any questions, please come join us on the
## Code of Conduct
All community members are expected to abide by the [Code of Conduct][code-of-conduct].
For any and all conduct inquiries or concerns, please contact conduct@zmkfirmware.dev.
For any and all conduct inquiries or concerns, please contact conduct@zmk.dev.
[code-of-conduct]: https://github.com/zmkfirmware/zmk/blob/main/CODE_OF_CONDUCT.md
@ -35,8 +35,8 @@ ZMK project.
### Before Submitting a Report
- Review the [Frequently Asked Questions](https://zmkfirmware.dev/docs/faq).
- Check the [Troubleshooting Guide](https://zmkfirmware.dev/docs/troubleshooting) for answers.
- Review the [Frequently Asked Questions](https://zmk.dev/docs/faq).
- Check the [Troubleshooting Guide](https://zmk.dev/docs/troubleshooting) for answers.
- Search the [open issues](https://github.com/zmkfirmware/zmk/issues) for an existing report that
matches your problem.
@ -47,10 +47,10 @@ To open a report:
- Head to https://github.com/zmkfirmware/zmk/issues/new
- Provide an accurate summary of the issue in the title.
- Provide as much detail as you can about the issue including:
- What [board/shield](https://zmkfirmware.dev/docs/faq#what-is-a-board) you are using.
- What [board/shield](https://zmk.dev/docs/faq#what-is-a-board) you are using.
- A link to the user repository, if you used it to build your firmware.
- Exact steps to reproduce the problem.
- Any relevant screenshots or [logs](https://zmkfirmware.dev/docs/dev-guide-usb-logging)
- Any relevant screenshots or [logs](https://zmk.dev/docs/dev-guide-usb-logging)
## Testing
@ -81,12 +81,17 @@ documentation to areas not currently covered are greatly appreciated.
- To get started, from the `docs/` directory, run `npm ci` and then `npm start`.
- Enhancements should be submitted as pull requests to the `main` branch of ZMK.
### Formatting
ZMK uses `prettier` to format documentation files. You can run prettier with `npm run prettier:format`.
You can setup git to run prettier automatically when you commit by installing the pre-commit hooks: `pip3 install pre-commit`, `pre-commit install`.
## Code Contributions
### Development Setup
To get your development environment setup going, start at the
[basic setup](https://zmkfirmware.dev/docs/dev-setup) docs, and make sure you can build and flash
[basic setup](https://zmk.dev/docs/dev-setup) docs, and make sure you can build and flash
your own locally built firmware.
### Formatting
@ -95,6 +100,8 @@ ZMK uses `clang-format` to ensure consist formatting for our source code. Before
changes, make sure you've manually run `clang-format`, or have your IDE configured to auto-format
on save.
You can setup git to run `clang-format` automatically when you commit by installing the pre-commit hooks: `pip3 install pre-commit`, `pre-commit install`.
### Commit Messages
The ZMK project is working towards, but not yet enforcing, the use of
@ -117,4 +124,4 @@ When opening a pull request with your changes, please:
- Requested testing by reviewers or testers.
- Screenshots or logs that support understanding the change.
[discord-invite]: https://zmkfirmware.dev/community/discord/invite
[discord-invite]: https://zmk.dev/community/discord/invite

View file

@ -1,13 +1,13 @@
# Zephyr™ Mechanical Keyboard (ZMK) Firmware
[![Discord](https://img.shields.io/discord/719497620560543766)](https://zmkfirmware.dev/community/discord/invite)
[![Discord](https://img.shields.io/discord/719497620560543766)](https://zmk.dev/community/discord/invite)
[![Build](https://github.com/zmkfirmware/zmk/workflows/Build/badge.svg)](https://github.com/zmkfirmware/zmk/actions)
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md)
[ZMK Firmware](https://zmkfirmware.dev/) is an open source (MIT) keyboard firmware built on the [Zephyr™ Project](https://www.zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues.
[ZMK Firmware](https://zmk.dev/) is an open source (MIT) keyboard firmware built on the [Zephyr™ Project](https://www.zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues.
Check out the website to learn more: https://zmkfirmware.dev/
Check out the website to learn more: https://zmk.dev/
You can also come join our [ZMK Discord Server](https://zmkfirmware.dev/community/discord/invite)
You can also come join our [ZMK Discord Server](https://zmk.dev/community/discord/invite)
To review features, check out the [feature overview](https://zmkfirmware.dev/docs/). ZMK is under active development, and new features are listed with the [enhancement label](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) in GitHub. Please feel free to add 👍 to the issue description of any requests to upvote the feature.
To review features, check out the [feature overview](https://zmk.dev/docs/). ZMK is under active development, and new features are listed with the [enhancement label](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) in GitHub. Please feel free to add 👍 to the issue description of any requests to upvote the feature.

View file

@ -337,11 +337,9 @@ config ZMK_KSCAN_EVENT_QUEUE_SIZE
config ZMK_KSCAN_MOCK_DRIVER
bool "Enable mock kscan driver to simulate key presses"
default n
config ZMK_KSCAN_COMPOSITE_DRIVER
bool "Enable composite kscan driver to combine kscan devices"
default n
#KSCAN Settings
endmenu
@ -421,6 +419,9 @@ config ZMK_WPM
bool "Calculate WPM"
default n
config SENSOR
default y
module = ZMK
module-str = zmk
source "subsys/logging/Kconfig.template.log_config"

View file

@ -42,7 +42,7 @@
, <7 0 &gpio0 24 0> /* D6/A7 D7*/
, <8 0 &gpio0 10 0> /* D8/A8 B4*/
, <9 0 &gpio1 6 0> /* D9/A9 B5*/
, <10 0 &gpio1 13 0> /* D10/A10 B6*/
, <10 0 &gpio1 11 0> /* D10/A10 B6*/
;
};
};

View file

@ -21,7 +21,7 @@
leds {
compatible = "gpio-leds";
blue_led: led_0 {
gpios = <&gpio0 42 GPIO_ACTIVE_HIGH>;
gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>;
label = "Blue LED";
};
};
@ -29,6 +29,7 @@
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
init-delay-ms = <20>;
control-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
};

View file

@ -0,0 +1,8 @@
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/../tools/uf2/utils/uf2conv.py
-c
-b 0x1000
-f 0xADA52840
-o ${PROJECT_BINARY_DIR}/${CONFIG_KERNEL_BIN_NAME}.uf2
${PROJECT_BINARY_DIR}/${CONFIG_KERNEL_BIN_NAME}.bin
)

View file

@ -0,0 +1,8 @@
# Copyright (c) 2021 Nick Winans
# SPDX-License-Identifier: MIT
config BOARD_ENABLE_DCDC
bool "Enable DCDC mode"
select SOC_DCDC_NRF52X
default y
depends on BOARD_NICE60

View file

@ -0,0 +1,6 @@
# Copyright (c) 2021 Nick Winans
# SPDX-License-Identifier: MIT
config BOARD_NICE60
bool "nice!60"
depends on SOC_NRF52840_QIAA

View file

@ -0,0 +1,31 @@
# Copyright (c) 2021 Nick Winans
# SPDX-License-Identifier: MIT
if BOARD_NICE60
config ZMK_KEYBOARD_NAME
default "nice!60"
if USB
config USB_NRFX
default y
config USB_DEVICE_STACK
default y
endif # USB
config BT_CTLR
default BT
config ZMK_BLE
default y
config ZMK_USB
default y
config ZMK_BATTERY_VOLTAGE_DIVIDER
default y
endif # BOARD_NICE60

View file

@ -0,0 +1,9 @@
# nice!60
![nice!60](https://i.imgur.com/0YWv5PE.png)
The nice!60 is a hotswap 60% made by Nice Keyboards. https://nicekeyboards.com/nice-60
## Building nice!60 ZMK firmware
```
west build -p -b nice60
```

View file

@ -0,0 +1,7 @@
# Copyright (c) 2021 Nick Winans
# SPDX-License-Identifier: MIT
set(OPENOCD_NRF5_SUBFAMILY nrf52)
board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset")
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)

View file

@ -0,0 +1,172 @@
/*
* Copyright (c) 2021 Nick Winans
*
* SPDX-License-Identifier: MIT
*/
/dts-v1/;
#include <nordic/nrf52840_qiaa.dtsi>
#include <dt-bindings/zmk/matrix_transform.h>
/ {
model = "nice!60";
compatible = "nice,60";
chosen {
zephyr,code-partition = &code_partition;
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zmk,kscan = &kscan0;
zmk,matrix_transform = &default_transform;
zmk,underglow = &led_strip;
};
default_transform: keymap_transform_0 {
compatible = "zmk,matrix-transform";
columns = <14>;
rows = <5>;
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(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,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,13)
RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,9) RC(4,10) RC(4,11) RC(4,13)
>;
};
kscan0: kscan {
compatible = "zmk,kscan-gpio-matrix";
label = "KSCAN";
diode-direction = "col2row";
row-gpios
= <&gpio1 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&gpio1 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&gpio1 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&gpio1 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&gpio1 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
;
col-gpios
= <&gpio1 15 GPIO_ACTIVE_HIGH>
, <&gpio0 29 GPIO_ACTIVE_HIGH>
, <&gpio0 31 GPIO_ACTIVE_HIGH>
, <&gpio0 30 GPIO_ACTIVE_HIGH>
, <&gpio0 28 GPIO_ACTIVE_HIGH>
, <&gpio0 2 GPIO_ACTIVE_HIGH>
, <&gpio0 3 GPIO_ACTIVE_HIGH>
, <&gpio1 3 GPIO_ACTIVE_HIGH>
, <&gpio1 7 GPIO_ACTIVE_HIGH>
, <&gpio1 4 GPIO_ACTIVE_HIGH>
, <&gpio1 6 GPIO_ACTIVE_HIGH>
, <&gpio1 5 GPIO_ACTIVE_HIGH>
, <&gpio1 1 GPIO_ACTIVE_HIGH>
, <&gpio1 2 GPIO_ACTIVE_HIGH>
;
};
leds {
compatible = "gpio-leds";
blue_led: led_0 {
gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
label = "Blue LED";
};
};
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
control-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
};
vbatt {
compatible = "zmk,battery-voltage-divider";
label = "BATTERY";
io-channels = <&adc 2>;
output-ohms = <2000000>;
full-ohms = <(2000000 + 806000)>;
};
};
&adc {
status = "okay";
};
&gpiote {
status = "okay";
};
&gpio0 {
status = "okay";
};
&gpio1 {
status = "okay";
};
&spi0 {
compatible = "nordic,nrf-spim";
/* Cannot be used together with i2c0. */
status = "okay";
sck-pin = <12>;
mosi-pin = <27>;
miso-pin = <13>;
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 = <12>; /* LED strip length */
spi-one-frame = <0x70>;
spi-zero-frame = <0x40>;
};
};
&usbd {
status = "okay";
};
&flash0 {
/*
* For more information, see:
* http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html
*/
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
sd_partition: partition@0 {
label = "mbr";
reg = <0x00000000 0x00001000>;
};
code_partition: partition@1000 {
label = "code_partition";
reg = <0x00001000 0x000d3000>;
};
/*
* The flash starting at 0x000d4000 and ending at
* 0x000f3fff is reserved for use by the application.
*/
/*
* Storage partition will be used by FCB/LittleFS/NVS
* if enabled.
*/
storage_partition: partition@d4000 {
label = "storage";
reg = <0x000d4000 0x00020000>;
};
boot_partition: partition@f4000 {
label = "adafruit_boot";
reg = <0x000f4000 0x0000c000>;
};
};
};

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2021 Nick Winans
*
* SPDX-License-Identifier: MIT
*/
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/rgb.h>
#include <dt-bindings/zmk/bt.h>
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
// ------------------------------------------------------------------------------------------
// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP |
// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" |
// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER |
// | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT |
// | CTL | WIN | ALT | SPACE | ALT | WIN | MO(1) | CTL |
// ------------------------------------------------------------------------------------------
bindings = <
&gresc &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC
&kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH
&kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET
&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT
&kp LCTRL &kp LGUI &kp LALT &kp SPACE &kp RALT &kp RGUI &mo 1 &kp RCTRL
>;
};
rgb_layer {
// ------------------------------------------------------------------------------------------------
// | BT CLR | F1 | F2 | F3 | F4 | F5 | F6 | F7 | F8 | F9 | F10 | F11 | F12 | EFFECT REV |
// | BT 1 | | UP | | HUEUP | SATUP | BRIUP | SPDUP | | | | | | |
// | BT 2 | LT | DN | RT | HUEDN | SATDN | BRIDN | SPDDN | | | | | EFFECT FORW |
// | BT 3 | | | | | | | | | | | |
// | BT 4 | | | TOG RGB | PRT SCR | | | DEL |
// ------------------------------------------------------------------------------------------------
bindings = <
&bt BT_CLR &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &rgb_ug RGB_EFR
&bt BT_SEL 0 &trans &kp UP &trans &rgb_ug RGB_HUI &rgb_ug RGB_SAI &rgb_ug RGB_BRI &rgb_ug RGB_SPI &trans &trans &trans &trans &trans &trans
&bt BT_SEL 1 &kp LEFT &kp DOWN &kp RIGHT &rgb_ug RGB_HUD &rgb_ug RGB_SAD &rgb_ug RGB_BRD &rgb_ug RGB_SPD &trans &trans &trans &trans &rgb_ug RGB_EFF
&bt BT_SEL 2 &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&bt BT_SEL 3 &trans &trans &rgb_ug RGB_TOG &kp PSCRN &trans &trans &kp DEL
>;
};
};
};

View file

@ -0,0 +1,14 @@
identifier: nice60
name: nice!60
type: mcu
arch: arm
toolchain:
- zephyr
- gnuarmemb
supported:
- adc
- usb_device
- ble
- ieee802154
- pwm
- watchdog

View file

@ -0,0 +1,27 @@
# Copyright (c) 2021 Nick Winans
# SPDX-License-Identifier: MIT
CONFIG_SOC_SERIES_NRF52X=y
CONFIG_SOC_NRF52840_QIAA=y
CONFIG_BOARD_NICE60=y
# Enable MPU
CONFIG_ARM_MPU=y
# enable GPIO
CONFIG_GPIO=y
CONFIG_USE_DT_CODE_PARTITION=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_NVS=y
CONFIG_SETTINGS_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_ZMK_RGB_UNDERGLOW=y
CONFIG_WS2812_STRIP=y
CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=160
CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3

View file

@ -6,3 +6,5 @@ CONFIG_ZMK_BLE=n
CONFIG_LOG=y
CONFIG_LOG_BACKEND_SHOW_COLOR=n
CONFIG_ZMK_LOG_LEVEL_DBG=y
CONFIG_DEBUG=y
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000

View file

@ -4,7 +4,7 @@
if SHIELD_CRADIO_LEFT
config ZMK_KEYBOARD_NAME
default "cradio left"
default "Cradio"
config ZMK_SPLIT_BLE_ROLE_CENTRAL
default y
@ -14,11 +14,11 @@ endif
if SHIELD_CRADIO_RIGHT
config ZMK_KEYBOARD_NAME
default "cradio right"
default "Cradio_Right"
endif
if SHIELD_CRADIO_LEFT || SHIELD_CRADIO_RIGHT
if SHIELD_CRADIO_RIGHT || SHIELD_CRADIO_LEFT
config ZMK_SPLIT
default y

View file

@ -0,0 +1 @@
Cradio is a firmware for a few 34 key keyboards, including Cradio, Hypergolic and Sweep.

View file

View file

@ -4,47 +4,49 @@
* SPDX-License-Identifier: MIT
*/
#include <dt-bindings/zmk/matrix_transform.h>
#include <dt-bindings/zmk/matrix_transform.h>
/ {
chosen {
zmk,kscan = &kscan0;
//zmk,matrix_transform = &default_transform;
zmk,matrix_transform = &default_transform;
};
default_transform: keymap_transform_0 {
compatible = "zmk,matrix-transform";
columns = <34>;
rows = <1>;
compatible = "zmk,matrix-transform";
columns = <34>;
rows = <1>;
map = <
RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17)
RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22)
RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27)
RC(0,15) RC(0,16) RC(0,33) RC(0,32)
>;
RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17)
RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22)
RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27)
RC(0,15) RC(0,16) RC(0,33) RC(0,32)
>;
};
kscan0: kscan {
compatible = "zmk,kscan-gpio-direct";
label = "KSCAN";
input-gpios
= <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
;
};
};
= <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
, <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
;
};
};

View file

@ -9,33 +9,92 @@
#include <dt-bindings/zmk/bt.h>
&mt {
// flavor = "tap-preferred";
// tapping_term_ms = <200>;
};
/ {
combos {
compatible = "zmk,combos";
combo_esc {
timeout-ms = <50>;
key-positions = <0 1>;
bindings = <&kp ESC>;
};
combo_tab {
timeout-ms = <50>;
key-positions = <10 11>;
bindings = <&kp TAB>;
};
combo_ralt {
timeout-ms = <50>;
key-positions = <17 16>;
bindings = <&kp RALT>;
};
combo_lalt {
timeout-ms = <50>;
key-positions = <11 12>;
bindings = <&kp LALT>;
};
combo_lgui {
timeout-ms = <50>;
key-positions = <12 13>;
bindings = <&kp LGUI>;
};
combo_rgui {
timeout-ms = <50>;
key-positions = <17 18>;
bindings = <&kp RGUI>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
default_layer {
bindings = <
&kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P
&kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI
&kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH
&mo 1 &kp LCTRL &kp SPACE &mo 2
>;
};
upper_layer {
bindings = <
&kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0
&bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp H &kp J &kp K &kp L &kp SEMI
&kp LSHFT &trans &trans &trans &trans &trans &trans &trans &trans &trans
&mo 1 &kp LCTRL &kp SPACE &mo 2
&kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P
&kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp QUOT
&mt LSFT Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &mt LSFT RET
&mo 1 &kp LCTL &kp SPC &mo 2
>;
};
lower_layer {
left_layer {
bindings = <
&kp EXCL &kp AT &kp HASH &kp DOLLAR &kp PRCNT &kp CARET &kp AMPS &kp KP_MULTIPLY &kp LPAR &kp RPAR
&trans &trans &trans &trans &trans &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp PIPE
&trans &trans &trans &trans &trans &trans &trans &trans &kp BSLH &kp TILDE
&mo 1 &kp LCTRL &kp SPACE &mo 2
&kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0
&kp TAB &kp LC(S) &kp DQT &kp PIPE2 &kp HASH &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp DEL
&kp ESC &kp TILDE &kp NON_US_BSLH &kp NON_US_HASH &kp TILDE2 &kp MINUS &kp GRAVE &kp LBKT &kp RBKT &kp DEL
&mo 1 &kp LGUI &kp RGUI &mo 2
>;
};
right_layer {
bindings = <
&kp BANG &kp ATSN &kp HASH &kp DLLR &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN
&kp HASH &kp QMARK &kp FSLH &kp COLN &kp SCLN &kp MINUS &kp KP_EQUAL &kp LBRC &kp RBRC &kp BKSP
&kp LSFT &kp KPLS &kp LBKT &kp RBKT &kp BSLH &kp UNDER &kp LEFT &kp DOWN &kp UP &kp RIGHT
&mo 3 &kp LCTL &kp SPC &mo 2
>;
};
tri_layer {
bindings = <
&kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &trans &trans &trans &trans &trans
&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &trans &kp PG_UP &kp K_VOL_UP &kp K_MUTE &trans
&bt BT_CLR &bt BT_NXT &bt BT_PRV &kp F6 &kp F7 &trans &kp PG_DN &kp K_VOL_DN &trans &trans
&trans &trans &trans &trans
>;
};

View file

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

View file

@ -0,0 +1,3 @@
# Uncomment lines below to enable encoder
# CONFIG_EC11=y
# CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y

View file

@ -24,32 +24,37 @@
&kp LSHFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp BSLH &kp RET
&trans &kp LGUI &kp LALT &kp LCTRL &mo 1 &kp SPACE &trans &mo 2 &kp LEFT &kp DOWN &kp UP &kp RIGHT
>;
sensor-bindings = <&inc_dec_kp PG_UP PG_DN>;
};
lower {
lower {
bindings = <
&kp LS(GRAVE) &kp LS(N1) &kp LS(N2) &kp LS(N3) &kp LS(N4) &kp LS(N5) &kp LS(N6) &kp LS(N7) &kp LS(N8) &kp LS(N9) &kp LS(N0) &kp DEL
&kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp UNDER &kp PLUS &kp LT &kp GT &kp PIPE
&trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp LS(HASH) &kp LS(BSLH) &kp HOME &kp END &trans
&trans &trans &trans &trans &trans &trans &trans &mo 3 &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP
>;
};
raise {
sensor-bindings = <&inc_dec_kp C_VOL_UP C_VOL_DN>;
};
raise {
bindings = <
&kp GRAVE &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp BSPC
&kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQUAL &kp LBKT &kp RBKT &kp BSLH
&trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp HASH &kp BSLH &kp PG_UP &kp PG_DN &trans
&trans &trans &trans &trans &mo 3 &trans &trans &trans &kp C_NEXT &kp C_VOL_DN &kp C_VOL_UP &kp C_PP
>;
};
>;
};
control {
bindings = <
&reset &bootloader &bt BT_CLR &bt BT_PRV &bt BT_NXT &trans &trans &trans &trans &trans &trans &trans
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
>;
};
};
>;
};
};
};

View file

@ -11,31 +11,45 @@
zmk,kscan = &kscan0;
};
kscan0: kscan_0 {
compatible = "zmk,kscan-gpio-matrix";
label = "KSCAN";
diode-direction = "col2row";
kscan0: kscan_0 {
compatible = "zmk,kscan-gpio-matrix";
label = "KSCAN";
diode-direction = "col2row";
col-gpios
= <&pro_micro_d 1 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 0 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 2 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 3 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 4 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 5 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 6 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 7 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 8 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 9 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 10 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 16 GPIO_ACTIVE_HIGH>
;
col-gpios
= <&pro_micro_d 1 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 0 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 2 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 3 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 4 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 5 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 6 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 7 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 8 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 9 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 10 GPIO_ACTIVE_HIGH>
, <&pro_micro_d 16 GPIO_ACTIVE_HIGH>
;
row-gpios
= <&pro_micro_d 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_d 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_a 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_a 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
;
};
row-gpios
= <&pro_micro_d 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_d 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_a 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
, <&pro_micro_a 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
;
};
encoder: encoder {
compatible = "alps,ec11";
label = "ENCODER";
a-gpios = <&pro_micro_a 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
b-gpios = <&pro_micro_a 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
resolution = <2>;
status = "okay";
};
sensors {
compatible = "zmk,keymap-sensors";
sensors = <&encoder>;
};
};

View file

@ -13,6 +13,9 @@
#define RSE 2
#define ADJ 3
&lt { quick_tap_ms = <200>; };
&mt { quick_tap_ms = <200>; };
/ {
keymap {
compatible = "zmk,keymap";
@ -26,7 +29,7 @@
bindings = <
&kp LWIN &kp GRAVE &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &mt RWIN RBKT
&kp LCTRL &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &mt RCTRL SQT
&kp LALT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp BSLH
&kp LALT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &mt RALT BSLH
&lt RSE TAB &mt LSHFT SPACE &lt LWR RET &lt LWR ESC &mt RSHFT BSPC &lt RSE DEL
>;
};

View file

@ -9,5 +9,41 @@ config ZMK_KEYBOARD_NAME
config ZMK_USB
default y
endif
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,29 @@
# Building ZMK for the Nibble
Some general notes/commands for building standard nibble layouts from the assembly documentation.
## LED Notes
If you built your nibble without the LEDs _and_ are using a nice!nano board, you'll need to change the following in your local nibble config or add them to the end of the file.
```
CONFIG_ZMK_RGB_UNDERGLOW=n
CONFIG_WS2812_STRIP=n
```
## Encoder Notes
If you built your nibble without an encoder, you'll need to change the following in your local nibble config or add them to the end of the file.
```
CONFIG_EC11=n
CONFIG_EC11_TRIGGER_GLOBAL_THREAD=n
```
## OLED Builds
If using an OLED screen, you'll need to change the following in your local nibble config or add them to the end of the file.
```
CONFIG_ZMK_DISPLAY=y
```

View file

@ -0,0 +1,4 @@
# Enable underglow
CONFIG_ZMK_RGB_UNDERGLOW=y
# Use the STRIP config specific to the LEDs you're using
CONFIG_WS2812_STRIP=y

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
&spi1 {
compatible = "nordic,nrf-spim";
status = "okay";
mosi-pin = <11>;
// 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 = <10>; /* number of LEDs */
spi-one-frame = <0x70>;
spi-zero-frame = <0x40>;
};
};
/ {
chosen {
zmk,underglow = &led_strip;
};
};

View file

@ -0,0 +1,6 @@
# Copyright (c) 2020 The ZMK Contributors
# SPDX-License-Identifier: MIT
# Enable Encoders
CONFIG_EC11=y
CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y

View file

@ -8,30 +8,40 @@
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
#define DEFAULT 0
#define FUNC 1
/ {
keymap {
compatible = "zmk,keymap";
sensors {
compatible = "zmk,keymap-sensors";
sensors = <&encoder_1>;
};
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 MINUS &kp EQUAL &kp BSPC &kp HOME
&kp C_VOL_UP &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp DEL
&kp C_VOL_DN &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP
&trans &kp LSHFT &trans &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN
&trans &kp LCTRL &kp LGUI &kp LALT &kp SPACE &mo FUNC &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT
>;
};
func {
bindings = <
&kp TILDE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &kp END
&bt BT_CLR &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bootloader
&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&bt BT_PRV &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &kp C_PREV &kp C_PP &kp C_NEXT
>;
};
};
keymap {
compatible = "zmk,keymap";
default_layer {
label = "Default";
sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>;
bindings = <
&kp ESC &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS &kp EQUAL &kp BSPC &kp HOME
&kp C_MUTE &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp DEL
&trans &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT &kp RET &kp PG_UP
&trans &kp LSHFT &trans &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp RSHFT &kp UP &kp PG_DN
&trans &kp LCTRL &kp LGUI &kp LALT &kp SPACE &mo 1 &kp RALT &kp RCTRL &kp LEFT &kp DOWN &kp RIGHT
>;
};
function_layer {
label = "Function";
sensor-bindings = <&inc_dec_kp C_VOLUME_UP C_VOLUME_DOWN>;
bindings = <
&kp TILDE &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &kp END
&kp C_MUTE &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bootloader
&bt BT_CLR &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&bt BT_PRV &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
&bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &kp C_PREV &kp C_PP &kp C_NEXT
>;
};
};
};

View file

@ -12,6 +12,15 @@
zmk,matrix_transform = &default_transform;
};
encoder_1: encoder_1 {
compatible = "alps,ec11";
label = "Encoder 1";
a-gpios = <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
b-gpios = <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
resolution = <4>;
status = "okay";
};
kscan0: kscan {
compatible = "zmk,kscan-gpio-demux";
label = "KSCAN";
@ -36,14 +45,30 @@
columns = <16>;
rows = <5>;
//TODO: Add a keymap graphic here
map = <
RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15)
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,14) RC(1,15)
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,12) RC(2,14) RC(2,15)
RC(3,0) RC(3,1) RC(0,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(3,14) RC(3,15)
RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,6) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15)
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,14) RC(0,15)
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,14) RC(1,15)
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,12) RC(2,14) RC(2,15)
RC(3,0) RC(3,1) RC(0,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(3,14) RC(3,15)
RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,6) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15)
>;
};
};
&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>;
com-sequential;
prechargep = <0x22>;
};
};

View file

@ -18,7 +18,7 @@
compatible = "zmk,behavior-hold-tap";
label = "homerow mods";
#binding-cells = <2>;
tapping_term_ms = <225>;
tapping-term-ms = <225>;
flavor = "tap-preferred";
bindings = <&kp>, <&kp>;
};

View file

@ -16,7 +16,7 @@ endif
if SHIELD_SPLITREUS62_RIGHT
config ZMK_KEYBOARD_NAME
default "Splitreus62 Right"
default "Splitreus62 Rt"
endif

View file

@ -14,7 +14,7 @@
compatible = "zmk,behavior-hold-tap";
label = "Hold Tap";
#binding-cells = <2>;
tapping_term_ms = <200>;
tapping-term-ms = <200>;
flavor = "tap-preferred";
bindings = <&kp>, <&kp>;
};

View file

@ -6,7 +6,6 @@ if SHIELD_TIDBIT
config ZMK_KEYBOARD_NAME
default "tidbit"
endif
if ZMK_DISPLAY
@ -43,3 +42,5 @@ choice LVGL_COLOR_DEPTH
endchoice
endif # LVGL
endif

View file

@ -1 +0,0 @@
CONFIG_SENSOR=y

View file

@ -2,7 +2,7 @@
# SPDX-License-Identifier: MIT
config ZMK_KSCAN_GPIO_DRIVER
bool "Enable GPIO kscan driver to simulate key presses"
bool "Enable GPIO kscan driver to detect key presses"
default y
select GPIO
@ -10,11 +10,9 @@ if ZMK_KSCAN_GPIO_DRIVER
config ZMK_KSCAN_MATRIX_POLLING
bool "Poll for key event triggers instead of using interrupts on matrix boards."
default n
config ZMK_KSCAN_DIRECT_POLLING
bool "Poll for key event triggers instead of using interrupts on direct wired boards."
default n
endif

View file

@ -113,6 +113,8 @@ struct kscan_gpio_item_config {
&kscan_gpio_output_configs_##n(dev)[bit]; \
gpio_pin_set(out_dev, out_cfg->pin, state); \
} \
/* Let the col settle before reading the rows */ \
k_usleep(1); \
\
for (int i = 0; i < INST_MATRIX_INPUTS(n); i++) { \
/* Get the input device (port) */ \

View file

@ -83,7 +83,7 @@ static int kscan_gpio_config_interrupts(const struct device *dev, gpio_flags_t f
int err = gpio_pin_interrupt_configure(dev, cfg->pin, flags);
if (err) {
LOG_ERR("Unable to enable matrix GPIO interrupt");
LOG_ERR("Unable to enable direct GPIO interrupt");
return err;
}
}

View file

@ -51,6 +51,11 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
}
#endif
#define COND_POLLING(code) COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (code), ())
#define COND_INTERRUPTS(code) COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), (code))
#define COND_POLL_OR_INTERRUPTS(pollcode, intcode) \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, pollcode, intcode)
#define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios)
#define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios)
#define INST_OUTPUT_LEN(n) \
@ -61,19 +66,21 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
(INST_MATRIX_ROWS(n)))
#define GPIO_INST_INIT(n) \
struct kscan_gpio_irq_callback_##n { \
struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \
struct gpio_callback callback; \
const struct device *dev; \
}; \
static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \
COND_INTERRUPTS( \
struct kscan_gpio_irq_callback_##n { \
struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * \
work; \
struct gpio_callback callback; \
const struct device *dev; \
}; \
static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)];) \
struct kscan_gpio_config_##n { \
struct kscan_gpio_item_config rows[INST_MATRIX_ROWS(n)]; \
struct kscan_gpio_item_config cols[INST_MATRIX_COLS(n)]; \
}; \
struct kscan_gpio_data_##n { \
kscan_callback_t callback; \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (struct k_timer poll_timer;), ()) \
COND_POLLING(struct k_timer poll_timer;) \
struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \
bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \
const struct device *rows[INST_MATRIX_ROWS(n)]; \
@ -102,17 +109,16 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
return ( \
COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \
} \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \
( \
static int kscan_gpio_enable_interrupts_##n(const struct device *dev) { \
return kscan_gpio_config_interrupts( \
kscan_gpio_input_devices_##n(dev), kscan_gpio_input_configs_##n(dev), \
INST_INPUT_LEN(n), GPIO_INT_LEVEL_ACTIVE); \
} static int kscan_gpio_disable_interrupts_##n(const struct device *dev) { \
return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \
kscan_gpio_input_configs_##n(dev), \
INST_INPUT_LEN(n), GPIO_INT_DISABLE); \
})) \
COND_INTERRUPTS( \
static int kscan_gpio_enable_interrupts_##n(const struct device *dev) { \
return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \
kscan_gpio_input_configs_##n(dev), \
INST_INPUT_LEN(n), GPIO_INT_LEVEL_ACTIVE); \
} static int kscan_gpio_disable_interrupts_##n(const struct device *dev) { \
return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \
kscan_gpio_input_configs_##n(dev), \
INST_INPUT_LEN(n), GPIO_INT_DISABLE); \
}) \
static void kscan_gpio_set_output_state_##n(const struct device *dev, int value) { \
int err; \
for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \
@ -132,17 +138,22 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
(output_index))] = value; \
} \
static int kscan_gpio_read_##n(const struct device *dev) { \
bool submit_follow_up_read = false; \
COND_INTERRUPTS(bool submit_follow_up_read = false;) \
struct kscan_gpio_data_##n *data = dev->data; \
static bool read_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \
int err; \
/* Disable our interrupts temporarily while we scan, to avoid */ \
/* re-entry while we iterate columns and set them active one by one */ \
/* to get pressed state for each matrix cell. */ \
kscan_gpio_set_output_state_##n(dev, 0); \
COND_INTERRUPTS(kscan_gpio_set_output_state_##n(dev, 0);) \
for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \
const struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \
const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \
gpio_pin_set(out_dev, out_cfg->pin, 1); \
err = gpio_pin_set(out_dev, out_cfg->pin, 1); \
if (err) { \
LOG_ERR("Failed to set output active (err %d)", err); \
return err; \
} \
for (int i = 0; i < INST_INPUT_LEN(n); i++) { \
const struct device *in_dev = kscan_gpio_input_devices_##n(dev)[i]; \
const struct kscan_gpio_item_config *in_cfg = \
@ -150,16 +161,20 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
kscan_gpio_set_matrix_state_##n(read_state, i, o, \
gpio_pin_get(in_dev, in_cfg->pin) > 0); \
} \
gpio_pin_set(out_dev, out_cfg->pin, 0); \
err = gpio_pin_set(out_dev, out_cfg->pin, 0); \
if (err) { \
LOG_ERR("Failed to set output inactive (err %d)", err); \
return err; \
} \
} \
/* Set all our outputs as active again. */ \
kscan_gpio_set_output_state_##n(dev, 1); \
COND_INTERRUPTS(kscan_gpio_set_output_state_##n(dev, 1);) \
for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \
for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \
bool pressed = read_state[r][c]; \
/* Follow up reads needed because further interrupts won't fire on already tripped \
* input GPIO pins */ \
submit_follow_up_read = (submit_follow_up_read || pressed); \
COND_INTERRUPTS(submit_follow_up_read = (submit_follow_up_read || pressed);) \
if (pressed != data->matrix_state[r][c]) { \
LOG_DBG("Sending event at %d,%d state %s", r, c, (pressed ? "on" : "off")); \
data->matrix_state[r][c] = pressed; \
@ -167,33 +182,31 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
} \
} \
} \
if (submit_follow_up_read) { \
COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(&data->work); }), ({ \
k_delayed_work_cancel(&data->work); \
k_delayed_work_submit(&data->work, K_MSEC(5)); \
})) \
} else { \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \
(kscan_gpio_enable_interrupts_##n(dev);)) \
} \
COND_INTERRUPTS( \
if (submit_follow_up_read) { \
COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(&data->work); }), \
({ \
k_delayed_work_cancel(&data->work); \
k_delayed_work_submit(&data->work, K_MSEC(5)); \
})) \
} else { kscan_gpio_enable_interrupts_##n(dev); }) \
return 0; \
} \
static void kscan_gpio_work_handler_##n(struct k_work *work) { \
struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \
kscan_gpio_read_##n(data->dev); \
} \
static void kscan_gpio_irq_callback_handler_##n( \
COND_INTERRUPTS(static void kscan_gpio_irq_callback_handler_##n( \
const struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pin) { \
struct kscan_gpio_irq_callback_##n *data = \
CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \
(kscan_gpio_disable_interrupts_##n(data->dev);)) \
kscan_gpio_disable_interrupts_##n(data->dev); \
COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \
k_delayed_work_cancel(data->work); \
k_delayed_work_submit(data->work, \
K_MSEC(DT_INST_PROP(n, debounce_period))); \
})) \
} \
}) \
\
static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \
.rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \
@ -207,25 +220,22 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
return 0; \
}; \
static int kscan_gpio_enable_##n(const struct device *dev) { \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \
(struct kscan_gpio_data_##n *data = dev->data; \
k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); return 0;), \
(int err = kscan_gpio_enable_interrupts_##n(dev); \
if (err) { return err; } return kscan_gpio_read_##n(dev);)) \
COND_POLL_OR_INTERRUPTS((struct kscan_gpio_data_##n *data = dev->data; \
k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \
return 0;), \
(int err = kscan_gpio_enable_interrupts_##n(dev); \
if (err) { return err; } return kscan_gpio_read_##n(dev);)) \
}; \
static int kscan_gpio_disable_##n(const struct device *dev) { \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \
(struct kscan_gpio_data_##n *data = dev->data; \
k_timer_stop(&data->poll_timer); return 0;), \
(return kscan_gpio_disable_interrupts_##n(dev);)) \
COND_POLL_OR_INTERRUPTS((struct kscan_gpio_data_##n *data = dev->data; \
k_timer_stop(&data->poll_timer); return 0;), \
(return kscan_gpio_disable_interrupts_##n(dev);)) \
}; \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \
(static void kscan_gpio_timer_handler(struct k_timer *timer) { \
struct kscan_gpio_data_##n *data = \
CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \
k_work_submit(&data->work.work); \
}), \
()) \
COND_POLLING(static void kscan_gpio_timer_handler_##n(struct k_timer *timer) { \
struct kscan_gpio_data_##n *data = \
CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \
k_work_submit(&data->work.work); \
}) \
static int kscan_gpio_init_##n(const struct device *dev) { \
struct kscan_gpio_data_##n *data = dev->data; \
int err; \
@ -244,15 +254,15 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
} else { \
LOG_DBG("Configured pin %d on %s for input", in_cfg->pin, in_cfg->label); \
} \
irq_callbacks_##n[i].work = &data->work; \
irq_callbacks_##n[i].dev = dev; \
gpio_init_callback(&irq_callbacks_##n[i].callback, \
kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \
err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \
if (err) { \
LOG_ERR("Error adding the callback to the column device"); \
return err; \
} \
COND_INTERRUPTS( \
irq_callbacks_##n[i].work = &data->work; irq_callbacks_##n[i].dev = dev; \
gpio_init_callback(&irq_callbacks_##n[i].callback, \
kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \
err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \
if (err) { \
LOG_ERR("Error adding the callback to the input device"); \
return err; \
}) \
} \
const struct device **output_devices = kscan_gpio_output_devices_##n(dev); \
for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \
@ -262,8 +272,8 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
LOG_ERR("Unable to find output GPIO device"); \
return -EINVAL; \
} \
err = gpio_pin_configure(output_devices[o], out_cfg->pin, \
GPIO_OUTPUT_ACTIVE | out_cfg->flags); \
err = \
gpio_pin_configure(output_devices[o], out_cfg->pin, GPIO_OUTPUT | out_cfg->flags); \
if (err) { \
LOG_ERR("Unable to configure pin %d on %s for output", out_cfg->pin, \
out_cfg->label); \
@ -271,10 +281,12 @@ static int kscan_gpio_config_interrupts(const struct device **devices,
} \
} \
data->dev = dev; \
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \
(k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \
(COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \
&data->work, kscan_gpio_work_handler_##n); \
COND_POLL_OR_INTERRUPTS( \
(k_timer_init(&data->poll_timer, kscan_gpio_timer_handler_##n, NULL); \
kscan_gpio_set_output_state_##n(dev, 0);), \
(kscan_gpio_set_output_state_##n(dev, 1);)) \
return 0; \
} \
static const struct kscan_driver_api gpio_driver_api_##n = { \

View file

@ -77,6 +77,9 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan)
LOG_DBG("Failed to enable ADC power GPIO: %d", rc);
return rc;
}
// wait for any capacitance to charge up
k_sleep(K_MSEC(10));
}
// Read ADC
@ -90,7 +93,7 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan)
&val);
uint16_t millivolts = val * (uint64_t)drv_cfg->full_ohm / drv_cfg->output_ohm;
LOG_DBG("ADC raw %d ~ %d mV => %d mV\n", drv_data->adc_raw, val, millivolts);
LOG_DBG("ADC raw %d ~ %d mV => %d mV", drv_data->adc_raw, val, millivolts);
uint8_t percent = lithium_ion_mv_to_pct(millivolts);
LOG_DBG("Percent: %d", percent);

View file

@ -6,7 +6,7 @@
/ {
behaviors {
bt: behavior_bluetooth {
/omit-if-no-ref/ bt: behavior_bluetooth {
compatible = "zmk,behavior-bluetooth";
label = "BLUETOOTH";
#binding-cells = <2>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
ext_power: behavior_ext_power {
/omit-if-no-ref/ ext_power: behavior_ext_power {
compatible = "zmk,behavior-ext-power";
label = "EXT_POWER_BEHAVIOR";
#binding-cells = <1>;

View file

@ -7,7 +7,7 @@
/ {
behaviors {
/* DEPRECATED: `cp` will be removed in the future */
cp: kp: behavior_key_press {
/omit-if-no-ref/ cp: kp: behavior_key_press {
compatible = "zmk,behavior-key-press";
label = "KEY_PRESS";
#binding-cells = <1>;

View file

@ -6,12 +6,12 @@
/ {
behaviors {
lt: behavior_layer_tap {
/omit-if-no-ref/ lt: behavior_layer_tap {
compatible = "zmk,behavior-hold-tap";
label = "LAYER_TAP";
#binding-cells = <2>;
flavor = "tap-preferred";
tapping_term_ms = <200>;
tapping-term-ms = <200>;
bindings = <&mo>, <&kp>;
};
};

View file

@ -6,12 +6,12 @@
/ {
behaviors {
mt: behavior_mod_tap {
/omit-if-no-ref/ mt: behavior_mod_tap {
compatible = "zmk,behavior-hold-tap";
label = "MOD_TAP";
#binding-cells = <2>;
flavor = "hold-preferred";
tapping_term_ms = <200>;
tapping-term-ms = <200>;
bindings = <&kp>, <&kp>;
};
};

View file

@ -6,7 +6,7 @@
/ {
behaviors {
mo: behavior_momentary_layer {
/omit-if-no-ref/ mo: behavior_momentary_layer {
compatible = "zmk,behavior-momentary-layer";
label = "MO";
#binding-cells = <1>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
none: behavior_none {
/omit-if-no-ref/ none: behavior_none {
compatible = "zmk,behavior-none";
label = "NONE";
#binding-cells = <0>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
out: behavior_outputs {
/omit-if-no-ref/ out: behavior_outputs {
compatible = "zmk,behavior-outputs";
label = "OUTPUTS";
#binding-cells = <1>;

View file

@ -8,13 +8,13 @@
/ {
behaviors {
reset: behavior_reset {
/omit-if-no-ref/ reset: behavior_reset {
compatible = "zmk,behavior-reset";
label = "RESET";
#binding-cells = <0>;
};
bootloader: behavior_reset_dfu {
/omit-if-no-ref/ bootloader: behavior_reset_dfu {
compatible = "zmk,behavior-reset";
label = "BOOTLOADER_RESET";
type = <RST_UF2>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
rgb_ug: behavior_rgb_underglow {
/omit-if-no-ref/ rgb_ug: behavior_rgb_underglow {
compatible = "zmk,behavior-rgb-underglow";
label = "RGB_UNDERGLOW";
#binding-cells = <2>;

View file

@ -7,7 +7,7 @@
/ {
behaviors {
/* DEPRECATED: `inc_dec_cp` will be removed in the future */
inc_dec_cp: inc_dec_kp: behavior_sensor_rotate_key_press {
/omit-if-no-ref/ inc_dec_cp: inc_dec_kp: behavior_sensor_rotate_key_press {
compatible = "zmk,behavior-sensor-rotate-key-press";
label = "ENC_KEY_PRESS";
#sensor-binding-cells = <2>;

View file

@ -6,14 +6,14 @@
/ {
behaviors {
sk: behavior_sticky_key {
/omit-if-no-ref/ sk: behavior_sticky_key {
compatible = "zmk,behavior-sticky-key";
label = "STICKY_KEY";
#binding-cells = <1>;
release-after-ms = <1000>;
bindings = <&kp>;
};
sl: behavior_sticky_layer {
/omit-if-no-ref/ sl: behavior_sticky_layer {
compatible = "zmk,behavior-sticky-key";
label = "STICKY_LAYER";
#binding-cells = <1>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
to: behavior_to_layer {
/omit-if-no-ref/ to: behavior_to_layer {
compatible = "zmk,behavior-to-layer";
label = "TO_LAYER";
#binding-cells = <1>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
tog: behavior_toggle_layer {
/omit-if-no-ref/ tog: behavior_toggle_layer {
compatible = "zmk,behavior-toggle-layer";
label = "TOGGLE_LAYER";
#binding-cells = <1>;

View file

@ -6,7 +6,7 @@
/ {
behaviors {
trans: behavior_transparent {
/omit-if-no-ref/ trans: behavior_transparent {
compatible = "zmk,behavior-transparent";
label = "TRANS";
#binding-cells = <0>;

View file

@ -11,7 +11,14 @@ properties:
bindings:
type: phandles
required: true
tapping_term_ms:
tapping-term-ms:
type: int
tapping_term_ms: # deprecated
type: int
quick-tap-ms:
type: int
default: -1
quick_tap_ms: # deprecated
type: int
flavor:
type: string
@ -21,3 +28,5 @@ properties:
- "hold-preferred"
- "balanced"
- "tap-preferred"
retro-tap:
type: boolean

View file

@ -20,3 +20,6 @@ child-binding:
default: 50
slow-release:
type: boolean
layers:
type: array
default: [-1]

View file

@ -15,3 +15,7 @@ properties:
label:
type: string
required: true
init-delay-ms:
type: int
description: Number of milliseconds to delay after initializing driver
required: false

View file

@ -27,6 +27,7 @@ typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_bin
int64_t timestamp);
__subsystem struct behavior_driver_api {
behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params;
behavior_keymap_binding_callback_t binding_pressed;
behavior_keymap_binding_callback_t binding_released;
behavior_sensor_keymap_binding_callback_t sensor_binding_triggered;
@ -35,6 +36,30 @@ __subsystem struct behavior_driver_api {
* @endcond
*/
/**
* @brief Handle the keymap binding which needs to be converted from relative "toggle" to absolute
* "turn on"
* @param binding Pointer to the details so of the binding
* @param event The event that triggered use of the binding
*
* @retval 0 If successful.
* @retval Negative errno code if failure.
*/
__syscall int behavior_keymap_binding_convert_central_state_dependent_params(
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event);
static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent_params(
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) {
const struct device *dev = device_get_binding(binding->behavior_dev);
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
if (api->binding_convert_central_state_dependent_params == NULL) {
return 0;
}
return api->binding_convert_central_state_dependent_params(binding, event);
}
/**
* @brief Handle the keymap binding being pressed
* @param dev Pointer to the device structure for the driver instance.

View file

@ -768,6 +768,7 @@
/* Keyboard Left Shift */
#define LEFT_SHIFT (HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_LEFTSHIFT))
#define LSHIFT (LEFT_SHIFT)
#define LSHFT (LEFT_SHIFT)
#define LSFT (LEFT_SHIFT) // WARNING: DEPRECATED (DO NOT USE)
@ -792,6 +793,7 @@
/* Keyboard Right Shift */
#define RIGHT_SHIFT (HID_USAGE(HID_USAGE_KEY, HID_USAGE_KEY_KEYBOARD_RIGHTSHIFT))
#define RSHIFT (RIGHT_SHIFT)
#define RSHFT (RIGHT_SHIFT)
#define RSFT (RIGHT_SHIFT) // WARNING: DEPRECATED (DO NOT USE)

View file

@ -5,19 +5,23 @@
*/
#define RGB_TOG_CMD 0
#define RGB_HUI_CMD 1
#define RGB_HUD_CMD 2
#define RGB_SAI_CMD 3
#define RGB_SAD_CMD 4
#define RGB_BRI_CMD 5
#define RGB_BRD_CMD 6
#define RGB_SPI_CMD 7
#define RGB_SPD_CMD 8
#define RGB_EFF_CMD 9
#define RGB_EFR_CMD 10
#define RGB_COLOR_HSB_CMD 11
#define RGB_ON_CMD 1
#define RGB_OFF_CMD 2
#define RGB_HUI_CMD 3
#define RGB_HUD_CMD 4
#define RGB_SAI_CMD 5
#define RGB_SAD_CMD 6
#define RGB_BRI_CMD 7
#define RGB_BRD_CMD 8
#define RGB_SPI_CMD 9
#define RGB_SPD_CMD 10
#define RGB_EFF_CMD 11
#define RGB_EFR_CMD 12
#define RGB_COLOR_HSB_CMD 13
#define RGB_TOG RGB_TOG_CMD 0
#define RGB_ON RGB_ON_CMD 0
#define RGB_OFF RGB_OFF_CMD 0
#define RGB_HUI RGB_HUI_CMD 0
#define RGB_HUD RGB_HUD_CMD 0
#define RGB_SAI RGB_SAI_CMD 0
@ -28,5 +32,6 @@
#define RGB_SPD RGB_SPD_CMD 0
#define RGB_EFF RGB_EFF_CMD 0
#define RGB_EFR RGB_EFR_CMD 0
#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD(((h) << 16) + ((s) << 8) + (v))
#define RGB_COLOR_HSB_VAL(h, s, v) (((h) << 16) + ((s) << 8) + (v))
#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD##(RGB_COLOR_HSB_VAL(h, s, v))
#define RGB_COLOR_HSV RGB_COLOR_HSB

View file

@ -0,0 +1,9 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#pragma once
uint8_t zmk_battery_state_of_charge();

View file

@ -19,3 +19,12 @@ int zmk_keymap_layer_to(uint8_t layer);
const char *zmk_keymap_layer_label(uint8_t layer);
int zmk_keymap_position_state_changed(uint32_t position, bool pressed, int64_t timestamp);
#define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \
{ \
.behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(drv_inst, bindings, idx)), \
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param1), (0), \
(DT_PHA_BY_IDX(drv_inst, bindings, idx, param1))), \
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(drv_inst, bindings, idx, param2), (0), \
(DT_PHA_BY_IDX(drv_inst, bindings, idx, param2))), \
}

View file

@ -6,10 +6,22 @@
#pragma once
struct zmk_led_hsb {
uint16_t h;
uint8_t s;
uint8_t b;
};
int zmk_rgb_underglow_toggle();
int zmk_rgb_underglow_get_state(bool *state);
int zmk_rgb_underglow_on();
int zmk_rgb_underglow_off();
int zmk_rgb_underglow_cycle_effect(int direction);
struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction);
struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction);
struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction);
int zmk_rgb_underglow_change_hue(int direction);
int zmk_rgb_underglow_change_sat(int direction);
int zmk_rgb_underglow_change_brt(int direction);
int zmk_rgb_underglow_change_spd(int direction);
int zmk_rgb_underglow_set_hsb(uint16_t hue, uint8_t saturation, uint8_t brightness);
int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color);

View file

@ -17,7 +17,7 @@ testcases=$(find $path -name native_posix.keymap -exec dirname \{\} \;)
num_cases=$(echo "$testcases" | wc -l)
if [ $num_cases -gt 1 ]; then
echo "" > ./build/tests/pass-fail.log
echo "$testcases" | xargs -L 1 -P 4 ./run-test.sh
echo "$testcases" | xargs -L 1 -P ${J:-4} ./run-test.sh
err=$?
sort -k2 ./build/tests/pass-fail.log
exit $err

View file

@ -15,10 +15,15 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/event_manager.h>
#include <zmk/battery.h>
#include <zmk/events/battery_state_changed.h>
const struct device *battery;
static uint8_t last_state_of_charge = 0;
uint8_t zmk_battery_state_of_charge() { return last_state_of_charge; }
static int zmk_battery_update(const struct device *battery) {
struct sensor_value state_of_charge;
@ -36,17 +41,23 @@ static int zmk_battery_update(const struct device *battery) {
return rc;
}
LOG_DBG("Setting BAS GATT battery level to %d.", state_of_charge.val1);
if (last_state_of_charge != state_of_charge.val1) {
last_state_of_charge = state_of_charge.val1;
rc = bt_bas_set_battery_level(state_of_charge.val1);
LOG_DBG("Setting BAS GATT battery level to %d.", last_state_of_charge);
if (rc != 0) {
LOG_WRN("Failed to set BAS GATT battery level (err %d)", rc);
return rc;
rc = bt_bas_set_battery_level(last_state_of_charge);
if (rc != 0) {
LOG_WRN("Failed to set BAS GATT battery level (err %d)", rc);
return rc;
}
rc = ZMK_EVENT_RAISE(new_zmk_battery_state_changed(
(struct zmk_battery_state_changed){.state_of_charge = last_state_of_charge}));
}
return ZMK_EVENT_RAISE(new_zmk_battery_state_changed(
(struct zmk_battery_state_changed){.state_of_charge = state_of_charge.val1}));
return rc;
}
static void zmk_battery_work(struct k_work *work) {

View file

@ -17,6 +17,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/ble.h>
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
switch (binding->param1) {
@ -49,3 +51,5 @@ static const struct behavior_driver_api behavior_bt_driver_api = {
DEVICE_AND_API_INIT(behavior_bt, DT_INST_LABEL(0), behavior_bt_init, NULL, NULL, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_bt_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -16,6 +16,24 @@
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int
on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *ext_power = device_get_binding("EXT_POWER");
if (ext_power == NULL) {
LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1);
return -EIO;
}
if (binding->param1 == EXT_POWER_TOGGLE_CMD) {
binding->param1 = ext_power_get(ext_power) > 0 ? EXT_POWER_OFF_CMD : EXT_POWER_ON_CMD;
}
return 0;
}
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *ext_power = device_get_binding("EXT_POWER");
@ -49,9 +67,13 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
static int behavior_ext_power_init(const struct device *dev) { return 0; };
static const struct behavior_driver_api behavior_ext_power_driver_api = {
.binding_convert_central_state_dependent_params =
on_keymap_binding_convert_central_state_dependent_params,
.binding_pressed = on_keymap_binding_pressed,
.binding_released = on_keymap_binding_released,
};
DEVICE_AND_API_INIT(behavior_ext_power, DT_INST_LABEL(0), behavior_ext_power_init, NULL, NULL,
APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -18,10 +18,11 @@
#include <zmk/events/position_state_changed.h>
#include <zmk/events/keycode_state_changed.h>
#include <zmk/behavior.h>
#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_NODE_EXISTS(DT_DRV_INST(0))
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
#define ZMK_BHV_HOLD_TAP_MAX_HELD 10
#define ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS 40
@ -30,31 +31,42 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999
enum flavor {
ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0,
ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1,
ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED = 2,
FLAVOR_HOLD_PREFERRED,
FLAVOR_BALANCED,
FLAVOR_TAP_PREFERRED,
};
struct behavior_hold_tap_behaviors {
struct zmk_behavior_binding tap;
struct zmk_behavior_binding hold;
enum status {
STATUS_UNDECIDED,
STATUS_TAP,
STATUS_HOLD_INTERRUPT,
STATUS_HOLD_TIMER,
};
enum decision_moment {
HT_KEY_UP,
HT_OTHER_KEY_DOWN,
HT_OTHER_KEY_UP,
HT_TIMER_EVENT,
HT_QUICK_TAP,
};
struct behavior_hold_tap_config {
int tapping_term_ms;
struct behavior_hold_tap_behaviors *behaviors;
char *hold_behavior_dev;
char *tap_behavior_dev;
int quick_tap_ms;
enum flavor flavor;
bool retro_tap;
};
// this data is specific for each hold-tap
struct active_hold_tap {
int32_t position;
// todo: move these params into the config->behaviors->tap and
uint32_t param_hold;
uint32_t param_tap;
int64_t timestamp;
bool is_decided;
bool is_hold;
enum status status;
const struct behavior_hold_tap_config *config;
struct k_delayed_work work;
bool work_is_cancelled;
@ -70,6 +82,24 @@ struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {};
// We capture most position_state_changed events and some modifiers_state_changed events.
const zmk_event_t *captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {};
// Keep track of which key was tapped most recently for 'quick_tap_ms'
struct last_tapped {
int32_t position;
int64_t tap_deadline;
};
struct last_tapped last_tapped;
static void store_last_tapped(struct active_hold_tap *hold_tap) {
last_tapped.position = hold_tap->position;
last_tapped.tap_deadline = hold_tap->timestamp + hold_tap->config->quick_tap_ms;
}
static bool is_quick_tap(struct active_hold_tap *hold_tap) {
return last_tapped.position == hold_tap->position &&
last_tapped.tap_deadline > hold_tap->timestamp;
}
static int capture_event(const zmk_event_t *event) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) {
if (captured_events[i] == NULL) {
@ -171,8 +201,7 @@ static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_
continue;
}
active_hold_taps[i].position = position;
active_hold_taps[i].is_decided = false;
active_hold_taps[i].is_hold = false;
active_hold_taps[i].status = STATUS_UNDECIDED;
active_hold_taps[i].config = config;
active_hold_taps[i].param_hold = param_hold;
active_hold_taps[i].param_tap = param_tap;
@ -184,29 +213,24 @@ static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_
static void clear_hold_tap(struct active_hold_tap *hold_tap) {
hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED;
hold_tap->is_decided = false;
hold_tap->is_hold = false;
hold_tap->status = STATUS_UNDECIDED;
hold_tap->work_is_cancelled = false;
}
enum decision_moment {
HT_KEY_UP = 0,
HT_OTHER_KEY_DOWN = 1,
HT_OTHER_KEY_UP = 2,
HT_TIMER_EVENT = 3,
};
static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) {
switch (event) {
case HT_KEY_UP:
hold_tap->is_hold = 0;
hold_tap->is_decided = true;
break;
hold_tap->status = STATUS_TAP;
return;
case HT_OTHER_KEY_UP:
hold_tap->status = STATUS_HOLD_INTERRUPT;
return;
case HT_TIMER_EVENT:
hold_tap->is_hold = 1;
hold_tap->is_decided = true;
break;
hold_tap->status = STATUS_HOLD_TIMER;
return;
case HT_QUICK_TAP:
hold_tap->status = STATUS_TAP;
return;
default:
return;
}
@ -215,13 +239,14 @@ static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_mome
static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) {
switch (event) {
case HT_KEY_UP:
hold_tap->is_hold = 0;
hold_tap->is_decided = true;
break;
hold_tap->status = STATUS_TAP;
return;
case HT_TIMER_EVENT:
hold_tap->is_hold = 1;
hold_tap->is_decided = true;
break;
hold_tap->status = STATUS_HOLD_TIMER;
return;
case HT_QUICK_TAP:
hold_tap->status = STATUS_TAP;
return;
default:
return;
}
@ -230,33 +255,113 @@ static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision
static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) {
switch (event) {
case HT_KEY_UP:
hold_tap->is_hold = 0;
hold_tap->is_decided = true;
break;
hold_tap->status = STATUS_TAP;
return;
case HT_OTHER_KEY_DOWN:
hold_tap->status = STATUS_HOLD_INTERRUPT;
return;
case HT_TIMER_EVENT:
hold_tap->is_hold = 1;
hold_tap->is_decided = true;
break;
hold_tap->status = STATUS_HOLD_TIMER;
return;
case HT_QUICK_TAP:
hold_tap->status = STATUS_TAP;
return;
default:
return;
}
}
static inline char *flavor_str(enum flavor flavor) {
static inline const char *flavor_str(enum flavor flavor) {
switch (flavor) {
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED:
case FLAVOR_HOLD_PREFERRED:
return "hold-preferred";
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED:
case FLAVOR_BALANCED:
return "balanced";
case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED:
case FLAVOR_TAP_PREFERRED:
return "tap-preferred";
default:
return "UNKNOWN FLAVOR";
}
return "UNKNOWN FLAVOR";
}
static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event_type) {
if (hold_tap->is_decided) {
static inline const char *status_str(enum status status) {
switch (status) {
case STATUS_UNDECIDED:
return "undecided";
case STATUS_HOLD_TIMER:
return "hold-timer";
case STATUS_HOLD_INTERRUPT:
return "hold-interrupt";
case STATUS_TAP:
return "tap";
default:
return "UNKNOWN STATUS";
}
}
static inline const char *decision_moment_str(enum decision_moment decision_moment) {
switch (decision_moment) {
case HT_KEY_UP:
return "key-up";
case HT_OTHER_KEY_DOWN:
return "other-key-down";
case HT_OTHER_KEY_UP:
return "other-key-up";
case HT_QUICK_TAP:
return "quick-tap";
case HT_TIMER_EVENT:
return "timer";
default:
return "UNKNOWN STATUS";
}
}
static int press_binding(struct active_hold_tap *hold_tap) {
if (hold_tap->config->retro_tap && hold_tap->status == STATUS_HOLD_TIMER) {
return 0;
}
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
};
struct zmk_behavior_binding binding = {0};
if (hold_tap->status == STATUS_HOLD_TIMER || hold_tap->status == STATUS_HOLD_INTERRUPT) {
binding.behavior_dev = hold_tap->config->hold_behavior_dev;
binding.param1 = hold_tap->param_hold;
} else {
binding.behavior_dev = hold_tap->config->tap_behavior_dev;
binding.param1 = hold_tap->param_tap;
store_last_tapped(hold_tap);
}
return behavior_keymap_binding_pressed(&binding, event);
}
static int release_binding(struct active_hold_tap *hold_tap) {
if (hold_tap->config->retro_tap && hold_tap->status == STATUS_HOLD_TIMER) {
return 0;
}
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
};
struct zmk_behavior_binding binding = {0};
if (hold_tap->status == STATUS_HOLD_TIMER || hold_tap->status == STATUS_HOLD_INTERRUPT) {
binding.behavior_dev = hold_tap->config->hold_behavior_dev;
binding.param1 = hold_tap->param_hold;
} else {
binding.behavior_dev = hold_tap->config->tap_behavior_dev;
binding.param1 = hold_tap->param_tap;
}
return behavior_keymap_binding_released(&binding, event);
}
static void decide_hold_tap(struct active_hold_tap *hold_tap,
enum decision_moment decision_moment) {
if (hold_tap->status != STATUS_UNDECIDED) {
return;
}
@ -266,41 +371,55 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome
}
switch (hold_tap->config->flavor) {
case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED:
decide_hold_preferred(hold_tap, event_type);
case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED:
decide_balanced(hold_tap, event_type);
case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED:
decide_tap_preferred(hold_tap, event_type);
case FLAVOR_HOLD_PREFERRED:
decide_hold_preferred(hold_tap, decision_moment);
case FLAVOR_BALANCED:
decide_balanced(hold_tap, decision_moment);
case FLAVOR_TAP_PREFERRED:
decide_tap_preferred(hold_tap, decision_moment);
}
if (!hold_tap->is_decided) {
if (hold_tap->status == STATUS_UNDECIDED) {
return;
}
LOG_DBG("%d decided %s (%s event %d)", hold_tap->position, hold_tap->is_hold ? "hold" : "tap",
flavor_str(hold_tap->config->flavor), event_type);
LOG_DBG("%d decided %s (%s decision moment %s)", hold_tap->position,
status_str(hold_tap->status), flavor_str(hold_tap->config->flavor),
decision_moment_str(decision_moment));
undecided_hold_tap = NULL;
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
};
struct zmk_behavior_binding binding;
if (hold_tap->is_hold) {
binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev;
binding.param1 = hold_tap->param_hold;
binding.param2 = 0;
} else {
binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev;
binding.param1 = hold_tap->param_tap;
binding.param2 = 0;
}
behavior_keymap_binding_pressed(&binding, event);
press_binding(hold_tap);
release_captured_events();
}
static void decide_retro_tap(struct active_hold_tap *hold_tap) {
if (!hold_tap->config->retro_tap) {
return;
}
if (hold_tap->status == STATUS_HOLD_TIMER) {
release_binding(hold_tap);
LOG_DBG("%d retro tap", hold_tap->position);
hold_tap->status = STATUS_TAP;
press_binding(hold_tap);
return;
}
}
static void update_hold_status_for_retro_tap(uint32_t ignore_position) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) {
struct active_hold_tap *hold_tap = &active_hold_taps[i];
if (hold_tap->position == ignore_position ||
hold_tap->position == ZMK_BHV_HOLD_TAP_POSITION_NOT_USED ||
hold_tap->config->retro_tap == false) {
continue;
}
if (hold_tap->status == STATUS_HOLD_TIMER) {
LOG_DBG("Update hold tap %d status to hold-interrupt", hold_tap->position);
hold_tap->status = STATUS_HOLD_INTERRUPT;
press_binding(hold_tap);
}
}
}
static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
const struct device *dev = device_get_binding(binding->behavior_dev);
@ -323,12 +442,14 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
LOG_DBG("%d new undecided hold_tap", event.position);
undecided_hold_tap = hold_tap;
if (is_quick_tap(hold_tap)) {
decide_hold_tap(hold_tap, HT_QUICK_TAP);
}
// if this behavior was queued we have to adjust the timer to only
// wait for the remaining time.
int32_t tapping_term_ms_left = (hold_tap->timestamp + cfg->tapping_term_ms) - k_uptime_get();
if (tapping_term_ms_left > 0) {
k_delayed_work_submit(&hold_tap->work, K_MSEC(tapping_term_ms_left));
}
k_delayed_work_submit(&hold_tap->work, K_MSEC(tapping_term_ms_left));
return ZMK_BEHAVIOR_OPAQUE;
}
@ -349,24 +470,8 @@ static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding,
}
decide_hold_tap(hold_tap, HT_KEY_UP);
// todo: set up the binding and data items inside of the active_hold_tap struct
struct zmk_behavior_binding_event sub_behavior_data = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
};
struct zmk_behavior_binding sub_behavior_binding;
if (hold_tap->is_hold) {
sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev;
sub_behavior_binding.param1 = hold_tap->param_hold;
sub_behavior_binding.param2 = 0;
} else {
sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev;
sub_behavior_binding.param1 = hold_tap->param_tap;
sub_behavior_binding.param2 = 0;
}
behavior_keymap_binding_released(&sub_behavior_binding, sub_behavior_data);
decide_retro_tap(hold_tap);
release_binding(hold_tap);
if (work_cancel_result == -EINPROGRESS) {
// let the timer handler clean up
@ -389,6 +494,8 @@ static const struct behavior_driver_api behavior_hold_tap_driver_api = {
static int position_state_changed_listener(const zmk_event_t *eh) {
struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh);
update_hold_status_for_retro_tap(ev->position);
if (undecided_hold_tap == NULL) {
LOG_DBG("%d bubble (no undecided hold_tap active)", ev->position);
return ZMK_EV_EVENT_BUBBLE;
@ -489,23 +596,14 @@ static int behavior_hold_tap_init(const struct device *dev) {
struct behavior_hold_tap_data {};
static struct behavior_hold_tap_data behavior_hold_tap_data;
/* todo: get rid of unused param1 and param2. */
#define _TRANSFORM_ENTRY(idx, node) \
{ \
.behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \
.param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \
(DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \
.param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), \
(DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \
},
#define KP_INST(n) \
static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_##n = { \
.hold = _TRANSFORM_ENTRY(0, n).tap = _TRANSFORM_ENTRY(1, n)}; \
static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \
.behaviors = &behavior_hold_tap_behaviors_##n, \
.tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \
.hold_behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)), \
.tap_behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(n, bindings, 1)), \
.quick_tap_ms = DT_INST_PROP(n, quick_tap_ms), \
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
.retro_tap = DT_INST_PROP(n, retro_tap), \
}; \
DEVICE_AND_API_INIT(behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \
&behavior_hold_tap_data, &behavior_hold_tap_config_##n, APPLICATION, \
@ -513,4 +611,4 @@ static struct behavior_hold_tap_data behavior_hold_tap_data;
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
#endif
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -15,8 +15,7 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct behavior_none_config {};
struct behavior_none_data {};
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int behavior_none_init(const struct device *dev) { return 0; };
@ -35,10 +34,7 @@ static const struct behavior_driver_api behavior_none_driver_api = {
.binding_released = on_keymap_binding_released,
};
static const struct behavior_none_config behavior_none_config = {};
DEVICE_AND_API_INIT(behavior_none, DT_INST_LABEL(0), behavior_none_init, NULL, NULL, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_none_driver_api);
static struct behavior_none_data behavior_none_data;
DEVICE_AND_API_INIT(behavior_none, DT_INST_LABEL(0), behavior_none_init, &behavior_none_data,
&behavior_none_config, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&behavior_none_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -18,6 +18,8 @@
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
switch (binding->param1) {
@ -42,3 +44,5 @@ static const struct behavior_driver_api behavior_outputs_driver_api = {
DEVICE_AND_API_INIT(behavior_out, DT_INST_LABEL(0), behavior_out_init, NULL, NULL, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_outputs_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -15,6 +15,7 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
struct behavior_reset_config {
int type;
};
@ -45,3 +46,5 @@ static const struct behavior_driver_api behavior_reset_driver_api = {
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_reset_driver_api);
DT_INST_FOREACH_STATUS_OKAY(RST_INST)
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -16,13 +16,85 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int behavior_rgb_underglow_init(const struct device *dev) { return 0; }
static int
on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
switch (binding->param1) {
case RGB_TOG_CMD: {
bool state;
int err = zmk_rgb_underglow_get_state(&state);
if (err) {
LOG_ERR("Failed to get RGB underglow state (err %d)", err);
return err;
}
binding->param1 = state ? RGB_OFF_CMD : RGB_ON_CMD;
break;
}
case RGB_BRI_CMD: {
struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(1);
binding->param1 = RGB_COLOR_HSB_CMD;
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
break;
}
case RGB_BRD_CMD: {
struct zmk_led_hsb color = zmk_rgb_underglow_calc_brt(-1);
binding->param1 = RGB_COLOR_HSB_CMD;
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
break;
}
case RGB_HUI_CMD: {
struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(1);
binding->param1 = RGB_COLOR_HSB_CMD;
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
break;
}
case RGB_HUD_CMD: {
struct zmk_led_hsb color = zmk_rgb_underglow_calc_hue(-1);
binding->param1 = RGB_COLOR_HSB_CMD;
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
break;
}
case RGB_SAI_CMD: {
struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(1);
binding->param1 = RGB_COLOR_HSB_CMD;
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
break;
}
case RGB_SAD_CMD: {
struct zmk_led_hsb color = zmk_rgb_underglow_calc_sat(-1);
binding->param1 = RGB_COLOR_HSB_CMD;
binding->param2 = RGB_COLOR_HSB_VAL(color.h, color.s, color.b);
break;
}
default:
return 0;
}
LOG_DBG("RGB relative convert to absolute (%d/%d)", binding->param1, binding->param2);
return 0;
};
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
switch (binding->param1) {
case RGB_TOG_CMD:
return zmk_rgb_underglow_toggle();
case RGB_ON_CMD:
return zmk_rgb_underglow_on();
case RGB_OFF_CMD:
return zmk_rgb_underglow_off();
case RGB_HUI_CMD:
return zmk_rgb_underglow_change_hue(1);
case RGB_HUD_CMD:
@ -44,8 +116,9 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
case RGB_EFR_CMD:
return zmk_rgb_underglow_cycle_effect(-1);
case RGB_COLOR_HSB_CMD:
return zmk_rgb_underglow_set_hsb((binding->param2 >> 16) & 0xFFFF,
(binding->param2 >> 8) & 0xFF, binding->param2 & 0xFF);
return zmk_rgb_underglow_set_hsb((struct zmk_led_hsb){.h = (binding->param2 >> 16) & 0xFFFF,
.s = (binding->param2 >> 8) & 0xFF,
.b = binding->param2 & 0xFF});
}
return -ENOTSUP;
@ -57,6 +130,8 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
}
static const struct behavior_driver_api behavior_rgb_underglow_driver_api = {
.binding_convert_central_state_dependent_params =
on_keymap_binding_convert_central_state_dependent_params,
.binding_pressed = on_keymap_binding_pressed,
.binding_released = on_keymap_binding_released,
};
@ -64,3 +139,5 @@ static const struct behavior_driver_api behavior_rgb_underglow_driver_api = {
DEVICE_AND_API_INIT(behavior_rgb_underglow, DT_INST_LABEL(0), behavior_rgb_underglow_init, NULL,
NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&behavior_rgb_underglow_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -16,6 +16,8 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int behavior_sensor_rotate_key_press_init(const struct device *dev) { return 0; };
static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding,
@ -63,3 +65,5 @@ static const struct behavior_driver_api behavior_sensor_rotate_key_press_driver_
&behavior_sensor_rotate_key_press_driver_api);
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -18,6 +18,7 @@
#include <zmk/events/keycode_state_changed.h>
#include <zmk/events/modifiers_state_changed.h>
#include <zmk/hid.h>
#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -176,6 +177,11 @@ static const struct behavior_driver_api behavior_sticky_key_driver_api = {
.binding_released = on_sticky_key_binding_released,
};
static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh);
ZMK_LISTENER(behavior_sticky_key, sticky_key_keycode_state_changed_listener);
ZMK_SUBSCRIPTION(behavior_sticky_key, zmk_keycode_state_changed);
static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh);
if (ev == NULL) {
@ -211,7 +217,10 @@ 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);
release_sticky_key_behavior(sticky_key, ev->timestamp);
return ZMK_EV_EVENT_CAPTURED;
}
}
sticky_key->modified_key_usage_page = ev->usage_page;
@ -228,9 +237,6 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
return ZMK_EV_EVENT_BUBBLE;
}
ZMK_LISTENER(behavior_sticky_key, sticky_key_keycode_state_changed_listener);
ZMK_SUBSCRIPTION(behavior_sticky_key, zmk_keycode_state_changed);
void behavior_sticky_key_timer_handler(struct k_work *item) {
struct active_sticky_key *sticky_key =
CONTAINER_OF(item, struct active_sticky_key, release_timer);
@ -260,18 +266,10 @@ static int behavior_sticky_key_init(const struct device *dev) {
struct behavior_sticky_key_data {};
static struct behavior_sticky_key_data behavior_sticky_key_data;
#define _TRANSFORM_ENTRY(idx, node) \
{ \
.behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \
.param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \
(DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \
.param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), \
(DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \
},
#define KP_INST(n) \
static struct behavior_sticky_key_config behavior_sticky_key_config_##n = { \
.behavior = _TRANSFORM_ENTRY(0, n).release_after_ms = DT_INST_PROP(n, release_after_ms), \
.behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, DT_DRV_INST(n)), \
.release_after_ms = DT_INST_PROP(n, release_after_ms), \
.quick_release = DT_INST_PROP(n, quick_release), \
}; \
DEVICE_AND_API_INIT(behavior_sticky_key_##n, DT_INST_LABEL(n), behavior_sticky_key_init, \

View file

@ -15,6 +15,8 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int behavior_to_init(const struct device *dev) { return 0; };
static int to_keymap_binding_pressed(struct zmk_behavior_binding *binding,
@ -37,3 +39,5 @@ static const struct behavior_driver_api behavior_to_driver_api = {
DEVICE_AND_API_INIT(behavior_to, DT_INST_LABEL(0), behavior_to_init, NULL, NULL, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_to_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -15,6 +15,8 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
struct behavior_tog_config {};
struct behavior_tog_data {};
@ -44,3 +46,5 @@ static struct behavior_tog_data behavior_tog_data;
DEVICE_AND_API_INIT(behavior_tog, DT_INST_LABEL(0), behavior_tog_init, &behavior_tog_data,
&behavior_tog_config, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&behavior_tog_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -15,8 +15,7 @@
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct behavior_transparent_config {};
struct behavior_transparent_data {};
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
static int behavior_transparent_init(const struct device *dev) { return 0; };
@ -35,10 +34,8 @@ static const struct behavior_driver_api behavior_transparent_driver_api = {
.binding_released = on_keymap_binding_released,
};
static const struct behavior_transparent_config behavior_transparent_config = {};
DEVICE_AND_API_INIT(behavior_transparent, DT_INST_LABEL(0), behavior_transparent_init, NULL, NULL,
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
&behavior_transparent_driver_api);
static struct behavior_transparent_data behavior_transparent_data;
DEVICE_AND_API_INIT(behavior_transparent, DT_INST_LABEL(0), behavior_transparent_init,
&behavior_transparent_data, &behavior_transparent_config, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_transparent_driver_api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -7,6 +7,7 @@
#include <device.h>
#include <init.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
@ -63,6 +64,8 @@ static uint8_t active_profile;
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
BUILD_ASSERT(DEVICE_NAME_LEN <= 16, "ERROR: BLE device name is too long. Max length: 16");
#define IS_HOST_PERIPHERAL \
(!IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
#define IS_SPLIT_PERIPHERAL \
@ -248,6 +251,10 @@ static int ble_save_profile() {
}
int zmk_ble_prof_select(uint8_t index) {
if (index >= PROFILE_COUNT) {
return -ERANGE;
}
LOG_DBG("profile %d", index);
if (active_profile == index) {
return 0;
@ -429,7 +436,7 @@ static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t l
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
LOG_DBG("%s: interval %d latency %d timeout %d", addr, interval, latency, timeout);
LOG_DBG("%s: interval %d latency %d timeout %d", log_strdup(addr), interval, latency, timeout);
}
static struct bt_conn_cb conn_callbacks = {

View file

@ -17,6 +17,7 @@
#include <zmk/events/position_state_changed.h>
#include <zmk/hid.h>
#include <zmk/matrix.h>
#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@ -33,6 +34,8 @@ struct combo_cfg {
// the virtual key position is a key position outside the range used by the keyboard.
// it is necessary so hold-taps can uniquely identify a behavior.
int32_t virtual_key_position;
int32_t layers_len;
int8_t layers[];
};
struct active_combo {
@ -104,17 +107,35 @@ static int initialize_combo(struct combo_cfg *new_combo) {
return 0;
}
static bool combo_active_on_layer(struct combo_cfg *combo, uint8_t layer) {
if (combo->layers[0] == -1) {
// -1 in the first layer position is global layer scope
return true;
}
for (int j = 0; j < combo->layers_len; j++) {
if (combo->layers[j] == layer) {
return true;
}
}
return false;
}
static int setup_candidates_for_first_keypress(int32_t position, int64_t timestamp) {
int number_of_combo_candidates = 0;
uint8_t highest_active_layer = zmk_keymap_highest_layer_active();
for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) {
struct combo_cfg *combo = combo_lookup[position][i];
if (combo == NULL) {
return i;
return number_of_combo_candidates;
}
if (combo_active_on_layer(combo, highest_active_layer)) {
candidates[number_of_combo_candidates].combo = combo;
candidates[number_of_combo_candidates].timeout_at = timestamp + combo->timeout_ms;
number_of_combo_candidates++;
}
candidates[i].combo = combo;
candidates[i].timeout_at = timestamp + combo->timeout_ms;
// LOG_DBG("combo timeout %d %d %d", position, i, candidates[i].timeout_at);
}
return CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY;
return number_of_combo_candidates;
}
static int filter_candidates(int32_t position) {
@ -167,11 +188,18 @@ static int64_t first_candidate_timeout() {
static inline bool candidate_is_completely_pressed(struct combo_cfg *candidate) {
// this code assumes set(pressed_keys) <= set(candidate->key_positions)
// this invariant is enforced by filter_candidates
// the only thing we need to do is check if len(pressed_keys) == len(combo->key_positions)
return pressed_keys[candidate->key_position_len - 1] != NULL;
// since events may have been reraised after clearing one or more slots at
// the start of pressed_keys (see: release_pressed_keys), we have to check
// that each key needed to trigger the combo was pressed, not just the last.
for (int i = 0; i < candidate->key_position_len; i++) {
if (pressed_keys[i] == NULL) {
return false;
}
}
return true;
}
static void cleanup();
static int cleanup();
static int filter_timed_out_candidates(int64_t timestamp) {
int num_candidates = 0;
@ -203,7 +231,7 @@ static int clear_candidates() {
}
static int capture_pressed_key(const zmk_event_t *ev) {
for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) {
for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO; i++) {
if (pressed_keys[i] != NULL) {
continue;
}
@ -215,23 +243,25 @@ static int capture_pressed_key(const zmk_event_t *ev) {
const struct zmk_listener zmk_listener_combo;
static void release_pressed_keys() {
// release the first key that was pressed
if (pressed_keys[0] == NULL) {
return;
}
ZMK_EVENT_RELEASE(pressed_keys[0])
pressed_keys[0] = NULL;
// reprocess events (see tests/combo/fully-overlapping-combos-3 for why this is needed)
for (int i = 1; i < CONFIG_ZMK_COMBO_MAX_COMBOS_PER_KEY; i++) {
if (pressed_keys[i] == NULL) {
return;
}
static int release_pressed_keys() {
for (int i = 0; i < CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO; i++) {
const zmk_event_t *captured_event = pressed_keys[i];
if (pressed_keys[i] == NULL) {
return i;
}
pressed_keys[i] = NULL;
ZMK_EVENT_RAISE(captured_event);
if (i == 0) {
LOG_DBG("combo: releasing position event %d",
as_zmk_position_state_changed(captured_event)->position);
ZMK_EVENT_RELEASE(captured_event)
} else {
// reprocess events (see tests/combo/fully-overlapping-combos-3 for why this is needed)
LOG_DBG("combo: reraising position event %d",
as_zmk_position_state_changed(captured_event)->position);
ZMK_EVENT_RAISE(captured_event);
}
}
return CONFIG_ZMK_COMBO_MAX_KEYS_PER_COMBO;
}
static inline int press_combo_behavior(struct combo_cfg *combo, int32_t timestamp) {
@ -339,14 +369,14 @@ static bool release_combo_key(int32_t position, int64_t timestamp) {
return false;
}
static void cleanup() {
static int cleanup() {
k_delayed_work_cancel(&timeout_task);
clear_candidates();
if (fully_pressed_combo != NULL) {
activate_combo(fully_pressed_combo);
fully_pressed_combo = NULL;
}
release_pressed_keys();
return release_pressed_keys();
}
static void update_timeout_task() {
@ -378,6 +408,7 @@ static int position_state_down(const zmk_event_t *ev, struct zmk_position_state_
update_timeout_task();
struct combo_cfg *candidate_combo = candidates[0].combo;
LOG_DBG("combo: capturing position event %d", data->position);
int ret = capture_pressed_key(ev);
switch (num_candidates) {
case 0:
@ -397,13 +428,18 @@ static int position_state_down(const zmk_event_t *ev, struct zmk_position_state_
}
}
static int position_state_up(struct zmk_position_state_changed *ev) {
cleanup();
if (release_combo_key(ev->position, ev->timestamp)) {
static int position_state_up(const zmk_event_t *ev, struct zmk_position_state_changed *data) {
int released_keys = cleanup();
if (release_combo_key(data->position, data->timestamp)) {
return ZMK_EV_EVENT_HANDLED;
} else {
return 0;
}
if (released_keys > 1) {
// The second and further key down events are re-raised. To preserve
// correct order for e.g. hold-taps, reraise the key up event too.
ZMK_EVENT_RAISE(ev);
return ZMK_EV_EVENT_CAPTURED;
}
return 0;
}
static void combo_timeout_handler(struct k_work *item) {
@ -426,7 +462,7 @@ static int position_state_changed_listener(const zmk_event_t *ev) {
if (data->state) { // keydown
return position_state_down(ev, data);
} else { // keyup
return position_state_up(data);
return position_state_up(ev, data);
}
}
@ -451,6 +487,8 @@ ZMK_SUBSCRIPTION(combo, zmk_position_state_changed);
.behavior = KEY_BINDING_TO_STRUCT(0, n), \
.virtual_key_position = ZMK_KEYMAP_LEN + __COUNTER__, \
.slow_release = DT_PROP(n, slow_release), \
.layers = DT_PROP(n, layers), \
.layers_len = DT_PROP_LEN(n, layers), \
};
#define INITIALIZE_COMBO(n) initialize_combo(&combo_config_##n);

View file

@ -38,12 +38,20 @@ void display_timer_cb() { k_work_submit(&display_tick_work); }
K_TIMER_DEFINE(display_timer, display_timer_cb, NULL);
static void start_display_updates() {
if (display == NULL) {
return;
}
display_blanking_off(display);
k_timer_start(&display_timer, K_MSEC(10), K_MSEC(10));
}
static void stop_display_updates() {
if (display == NULL) {
return;
}
display_blanking_on(display);
k_timer_stop(&display_timer);

View file

@ -22,24 +22,25 @@ int zmk_event_manager_handle_from(zmk_event_t *event, uint8_t start_index) {
uint8_t len = __event_subscriptions_end - __event_subscriptions_start;
for (int i = start_index; i < len; i++) {
struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i;
if (ev_sub->event_type == event->event) {
ret = ev_sub->listener->callback(event);
if (ret < 0) {
LOG_DBG("Listener returned an error: %d", ret);
goto release;
} else if (ret > 0) {
switch (ret) {
case ZMK_EV_EVENT_HANDLED:
LOG_DBG("Listener handled the event");
ret = 0;
goto release;
case ZMK_EV_EVENT_CAPTURED:
LOG_DBG("Listener captured the event");
event->last_listener_index = i;
// Listeners are expected to free events they capture
return 0;
}
}
if (ev_sub->event_type != event->event) {
continue;
}
ret = ev_sub->listener->callback(event);
switch (ret) {
case ZMK_EV_EVENT_BUBBLE:
continue;
case ZMK_EV_EVENT_HANDLED:
LOG_DBG("Listener handled the event");
ret = 0;
goto release;
case ZMK_EV_EVENT_CAPTURED:
LOG_DBG("Listener captured the event");
event->last_listener_index = i;
// Listeners are expected to free events they capture
return 0;
default:
LOG_DBG("Listener returned an error: %d", ret);
goto release;
}
}

View file

@ -23,6 +23,7 @@ struct ext_power_generic_config {
const char *label;
const uint8_t pin;
const uint8_t flags;
const uint16_t init_delay_ms;
};
struct ext_power_generic_data {
@ -171,6 +172,10 @@ static int ext_power_generic_init(const struct device *dev) {
ext_power_enable(dev);
#endif
if (config->init_delay_ms) {
k_msleep(config->init_delay_ms);
}
return 0;
}
@ -210,7 +215,8 @@ static int ext_power_generic_pm_control(const struct device *dev, uint32_t ctrl_
static const struct ext_power_generic_config config = {
.label = DT_INST_GPIO_LABEL(0, control_gpios),
.pin = DT_INST_GPIO_PIN(0, control_gpios),
.flags = DT_INST_GPIO_FLAGS(0, control_gpios)};
.flags = DT_INST_GPIO_FLAGS(0, control_gpios),
.init_delay_ms = DT_INST_PROP_OR(0, init_delay_ms, 0)};
static struct ext_power_generic_data data = {
.status = false,
@ -223,13 +229,15 @@ static const struct ext_power_api api = {.enable = ext_power_generic_enable,
.disable = ext_power_generic_disable,
.get = ext_power_generic_get};
#define ZMK_EXT_POWER_INIT_PRIORITY 81
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
DEVICE_DEFINE(ext_power_generic, DT_INST_LABEL(0), ext_power_generic_init,
&ext_power_generic_pm_control, &data, &config, APPLICATION,
CONFIG_APPLICATION_INIT_PRIORITY, &api);
&ext_power_generic_pm_control, &data, &config, POST_KERNEL,
ZMK_EXT_POWER_INIT_PRIORITY, &api);
#else
DEVICE_AND_API_INIT(ext_power_generic, DT_INST_LABEL(0), ext_power_generic_init, &data, &config,
APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, &api);
POST_KERNEL, ZMK_EXT_POWER_INIT_PRIORITY, &api);
#endif /* CONFIG_DEVICE_POWER_MANAGEMENT */
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

View file

@ -28,18 +28,10 @@ static uint8_t _zmk_keymap_layer_default = 0;
#define ZMK_KEYMAP_NODE DT_DRV_INST(0)
#define ZMK_KEYMAP_LAYERS_LEN (DT_INST_FOREACH_CHILD(0, LAYER_CHILD_LEN) 0)
#define LAYER_NODE(l) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, l)
#define BINDING_WITH_COMMA(idx, drv_inst) ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst),
#define _TRANSFORM_ENTRY(idx, layer) \
{ \
.behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, bindings, idx)), \
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param1), (0), \
(DT_PHA_BY_IDX(layer, bindings, idx, param1))), \
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param2), (0), \
(DT_PHA_BY_IDX(layer, bindings, idx, param2))), \
},
#define TRANSFORMED_LAYER(node) {UTIL_LISTIFY(DT_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, node)},
#define TRANSFORMED_LAYER(node) \
{UTIL_LISTIFY(DT_PROP_LEN(node, bindings), BINDING_WITH_COMMA, node)},
#if ZMK_KEYMAP_HAS_SENSORS
#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \
@ -161,7 +153,9 @@ const char *zmk_keymap_layer_label(uint8_t layer) {
}
int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, int64_t timestamp) {
struct zmk_behavior_binding *binding = &zmk_keymap[layer][position];
// We want to make a copy of this, since it may be converted from
// relative to absolute before being invoked
struct zmk_behavior_binding binding = zmk_keymap[layer][position];
const struct device *behavior;
struct zmk_behavior_binding_event event = {
.layer = layer,
@ -170,19 +164,25 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed,
};
LOG_DBG("layer: %d position: %d, binding name: %s", layer, position,
log_strdup(binding->behavior_dev));
log_strdup(binding.behavior_dev));
behavior = device_get_binding(binding->behavior_dev);
behavior = device_get_binding(binding.behavior_dev);
if (!behavior) {
LOG_DBG("No behavior assigned to %d on layer %d", position, layer);
return 1;
}
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event);
if (err) {
LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err);
return err;
}
if (pressed) {
return behavior_keymap_binding_pressed(binding, event);
return behavior_keymap_binding_pressed(&binding, event);
} else {
return behavior_keymap_binding_released(binding, event);
return behavior_keymap_binding_released(&binding, event);
}
}

View file

@ -47,7 +47,7 @@ void zmk_kscan_process_msgq(struct k_work *item) {
while (k_msgq_get(&zmk_kscan_msgq, &ev, K_NO_WAIT) == 0) {
bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED);
uint32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column);
LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s\n", ev.row, ev.column, position,
LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s", ev.row, ev.column, position,
(pressed ? "true" : "false"));
ZMK_EVENT_RAISE(new_zmk_position_state_changed((struct zmk_position_state_changed){
.state = pressed, .position = position, .timestamp = k_uptime_get()}));

View file

@ -17,11 +17,17 @@
#include <drivers/led_strip.h>
#include <drivers/ext_power.h>
#include <zmk/rgb_underglow.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow))
#define STRIP_NUM_PIXELS DT_PROP(DT_CHOSEN(zmk_underglow), chain_length)
#define HUE_MAX 360
#define SAT_MAX 100
#define BRT_MAX 100
enum rgb_underglow_effect {
UNDERGLOW_EFFECT_SOLID,
UNDERGLOW_EFFECT_BREATHE,
@ -30,16 +36,8 @@ enum rgb_underglow_effect {
UNDERGLOW_EFFECT_NUMBER // Used to track number of underglow effects
};
struct led_hsb {
uint16_t h;
uint8_t s;
uint8_t b;
};
struct rgb_underglow_state {
uint16_t hue;
uint8_t saturation;
uint8_t brightness;
struct zmk_led_hsb color;
uint8_t animation_speed;
uint8_t current_effect;
uint16_t animation_step;
@ -56,13 +54,13 @@ static struct rgb_underglow_state state;
static const struct device *ext_power;
#endif
static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
double r, g, b;
uint8_t i = hsb.h / 60;
double v = hsb.b / 100.0;
double s = hsb.s / 100.0;
double f = hsb.h / 360.0 * 6 - i;
double v = hsb.b / ((float)BRT_MAX);
double s = hsb.s / ((float)SAT_MAX);
double f = hsb.h / ((float)HUE_MAX) * 6 - i;
double p = v * (1 - s);
double q = v * (1 - f * s);
double t = v * (1 - (1 - f) * s);
@ -105,33 +103,16 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
return rgb;
}
static void zmk_rgb_underglow_off() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
}
led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
}
static void zmk_rgb_underglow_effect_solid() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
int hue = state.hue;
int sat = state.saturation;
int brt = state.brightness;
struct led_hsb hsb = {hue, sat, brt};
pixels[i] = hsb_to_rgb(hsb);
pixels[i] = hsb_to_rgb(state.color);
}
}
static void zmk_rgb_underglow_effect_breathe() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
int hue = state.hue;
int sat = state.saturation;
int brt = abs(state.animation_step - 1200) / 12;
struct led_hsb hsb = {hue, sat, brt};
struct zmk_led_hsb hsb = state.color;
hsb.b = abs(state.animation_step - 1200) / 12;
pixels[i] = hsb_to_rgb(hsb);
}
@ -145,32 +126,26 @@ static void zmk_rgb_underglow_effect_breathe() {
static void zmk_rgb_underglow_effect_spectrum() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
int hue = state.animation_step;
int sat = state.saturation;
int brt = state.brightness;
struct led_hsb hsb = {hue, sat, brt};
struct zmk_led_hsb hsb = state.color;
hsb.h = state.animation_step;
pixels[i] = hsb_to_rgb(hsb);
}
state.animation_step += state.animation_speed;
state.animation_step = state.animation_step % 360;
state.animation_step = state.animation_step % HUE_MAX;
}
static void zmk_rgb_underglow_effect_swirl() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
int hue = (360 / STRIP_NUM_PIXELS * i + state.animation_step) % 360;
int sat = state.saturation;
int brt = state.brightness;
struct led_hsb hsb = {hue, sat, brt};
struct zmk_led_hsb hsb = state.color;
hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX;
pixels[i] = hsb_to_rgb(hsb);
}
state.animation_step += state.animation_speed * 2;
state.animation_step = state.animation_step % 360;
state.animation_step = state.animation_step % HUE_MAX;
}
static void zmk_rgb_underglow_tick(struct k_work *work) {
@ -196,10 +171,6 @@ K_WORK_DEFINE(underglow_work, zmk_rgb_underglow_tick);
static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) {
if (!state.on) {
zmk_rgb_underglow_off();
k_timer_stop(timer);
return;
}
@ -255,9 +226,11 @@ static int zmk_rgb_underglow_init(const struct device *_arg) {
#endif
state = (struct rgb_underglow_state){
hue : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
saturation : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START,
brightness : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START,
color : {
h : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
s : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START,
b : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START,
},
animation_speed : CONFIG_ZMK_RGB_UNDERGLOW_SPD_START,
current_effect : CONFIG_ZMK_RGB_UNDERGLOW_EFF_START,
animation_step : 0,
@ -292,20 +265,65 @@ int zmk_rgb_underglow_save_state() {
#endif
}
int zmk_rgb_underglow_get_state(bool *on_off) {
if (!led_strip)
return -ENODEV;
*on_off = state.on;
return 0;
}
int zmk_rgb_underglow_on() {
if (!led_strip)
return -ENODEV;
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
if (ext_power != NULL) {
int rc = ext_power_enable(ext_power);
if (rc != 0) {
LOG_ERR("Unable to enable EXT_POWER: %d", rc);
}
}
#endif
state.on = true;
state.animation_step = 0;
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_off() {
if (!led_strip)
return -ENODEV;
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
if (ext_power != NULL) {
int rc = ext_power_disable(ext_power);
if (rc != 0) {
LOG_ERR("Unable to disable EXT_POWER: %d", rc);
}
}
#endif
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
}
led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
k_timer_stop(&underglow_tick);
state.on = false;
return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_cycle_effect(int direction) {
if (!led_strip)
return -ENODEV;
if (state.current_effect == 0 && direction < 0) {
state.current_effect = UNDERGLOW_EFFECT_NUMBER - 1;
return 0;
}
state.current_effect += direction;
if (state.current_effect >= UNDERGLOW_EFFECT_NUMBER) {
state.current_effect = 0;
}
state.current_effect += UNDERGLOW_EFFECT_NUMBER + direction;
state.current_effect %= UNDERGLOW_EFFECT_NUMBER;
state.animation_step = 0;
@ -313,63 +331,61 @@ int zmk_rgb_underglow_cycle_effect(int direction) {
}
int zmk_rgb_underglow_toggle() {
if (!led_strip)
return -ENODEV;
state.on = !state.on;
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
if (ext_power != NULL) {
int rc;
if (state.on) {
rc = ext_power_enable(ext_power);
} else {
rc = ext_power_disable(ext_power);
}
if (rc != 0) {
LOG_ERR("Unable to toggle EXT_POWER: %d", rc);
}
}
#endif
if (state.on) {
state.animation_step = 0;
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
} else {
zmk_rgb_underglow_off();
k_timer_stop(&underglow_tick);
}
return zmk_rgb_underglow_save_state();
return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on();
}
int zmk_rgb_underglow_set_hsb(uint16_t hue, uint8_t saturation, uint8_t brightness) {
if (hue > 360 || saturation > 100 || brightness > 100) {
int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color) {
if (color.h > HUE_MAX || color.s > SAT_MAX || color.b > BRT_MAX) {
return -ENOTSUP;
}
state.hue = hue;
state.saturation = saturation;
state.brightness = brightness;
state.color = color;
return 0;
}
struct zmk_led_hsb zmk_rgb_underglow_calc_hue(int direction) {
struct zmk_led_hsb color = state.color;
color.h += HUE_MAX + (direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP);
color.h %= HUE_MAX;
return color;
}
struct zmk_led_hsb zmk_rgb_underglow_calc_sat(int direction) {
struct zmk_led_hsb color = state.color;
int s = color.s + (direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP);
if (s < 0) {
s = 0;
} else if (s > SAT_MAX) {
s = SAT_MAX;
}
color.s = s;
return color;
}
struct zmk_led_hsb zmk_rgb_underglow_calc_brt(int direction) {
struct zmk_led_hsb color = state.color;
int b = color.b + (direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP);
if (b < 0) {
b = 0;
} else if (b > BRT_MAX) {
b = BRT_MAX;
}
color.b = b;
return color;
}
int zmk_rgb_underglow_change_hue(int direction) {
if (!led_strip)
return -ENODEV;
if (state.hue == 0 && direction < 0) {
state.hue = 360 - CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
return 0;
}
state.hue += direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
state.hue = state.hue % 360;
state.color = zmk_rgb_underglow_calc_hue(direction);
return zmk_rgb_underglow_save_state();
}
@ -378,15 +394,7 @@ int zmk_rgb_underglow_change_sat(int direction) {
if (!led_strip)
return -ENODEV;
if (state.saturation == 0 && direction < 0) {
return 0;
}
state.saturation += direction * CONFIG_ZMK_RGB_UNDERGLOW_SAT_STEP;
if (state.saturation > 100) {
state.saturation = 100;
}
state.color = zmk_rgb_underglow_calc_sat(direction);
return zmk_rgb_underglow_save_state();
}
@ -395,15 +403,7 @@ int zmk_rgb_underglow_change_brt(int direction) {
if (!led_strip)
return -ENODEV;
if (state.brightness == 0 && direction < 0) {
return 0;
}
state.brightness += direction * CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP;
if (state.brightness > 100) {
state.brightness = 100;
}
state.color = zmk_rgb_underglow_calc_brt(direction);
return zmk_rgb_underglow_save_state();
}

View file

@ -1,2 +1 @@
s/.*hid_listener_keycode_//p
s/.*combo//p

View file

@ -1,2 +1 @@
s/.*hid_listener_keycode_//p
s/.*combo//p

View file

@ -1,2 +1 @@
s/.*hid_listener_keycode_//p
s/.*combo//p

View file

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

View file

@ -0,0 +1,8 @@
pressed: usage_page 0x07 keycode 0x1b implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x1b 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 0x1c implicit_mods 0x00 explicit_mods 0x00
released: usage_page 0x07 keycode 0x1c 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,78 @@
#include <dt-bindings/zmk/keys.h>
#include <behaviors.dtsi>
#include <dt-bindings/zmk/kscan-mock.h>
/* it is useful to set timeout to a large value when attaching a debugger. */
#define TIMEOUT (60*60*1000)
/ {
combos {
compatible = "zmk,combos";
combo_one {
timeout-ms = <TIMEOUT>;
key-positions = <0 1>;
bindings = <&kp X>;
layers = <0>;
};
combo_two {
timeout-ms = <TIMEOUT>;
key-positions = <0 1>;
bindings = <&kp Y>;
layers = <1>;
};
combo_three {
timeout-ms = <TIMEOUT>;
key-positions = <0 2>;
bindings = <&kp Z>;
};
};
keymap {
compatible = "zmk,keymap";
label ="Default keymap";
default_layer {
bindings = <
&kp A &kp B
&kp C &tog 1
>;
};
filtered_layer {
bindings = <
&kp A &kp B
&kp C &tog 0
>;
};
};
};
&kscan {
events = <
/* Combo One */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,0,10)
ZMK_MOCK_RELEASE(0,1,10)
/* Combo Three */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_PRESS(1,1,10)
ZMK_MOCK_RELEASE(0,0,10)
ZMK_MOCK_RELEASE(1,1,10)
/* Toggle Layer */
ZMK_MOCK_PRESS(1,1,10)
ZMK_MOCK_RELEASE(1,1,10)
/* Combo Two */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_PRESS(0,1,10)
ZMK_MOCK_RELEASE(0,0,10)
ZMK_MOCK_RELEASE(0,1,10)
/* Combo Three */
ZMK_MOCK_PRESS(0,0,10)
ZMK_MOCK_PRESS(1,1,10)
ZMK_MOCK_RELEASE(0,0,10)
ZMK_MOCK_RELEASE(1,1,10)
>;
};

View file

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

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