Merge branch 'zmkfirmware:main' into split_battery_service
This commit is contained in:
commit
bbdffd9e38
96 changed files with 1238 additions and 392 deletions
120
.github/workflows/build-user-config.yml
vendored
Normal file
120
.github/workflows/build-user-config.yml
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
name: Reusable user config build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_matrix_path:
|
||||
description: 'Path to the build matrix file'
|
||||
default: 'build.yaml'
|
||||
required: false
|
||||
type: string
|
||||
config_path:
|
||||
description: 'Path to the config directory'
|
||||
default: 'config'
|
||||
required: false
|
||||
type: string
|
||||
fallback_binary:
|
||||
description: 'Fallback binary format, if no *.uf2 file was built'
|
||||
default: 'bin'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
runs-on: ubuntu-latest
|
||||
name: Fetch Build Keyboards
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install yaml2json
|
||||
run: python3 -m pip install remarshal
|
||||
|
||||
- id: set-matrix
|
||||
name: Fetch Build Matrix
|
||||
run: |
|
||||
matrix=$(yaml2json ${{ inputs.build_matrix_path }} | jq -c .)
|
||||
yaml2json ${{ inputs.build_matrix_path }}
|
||||
echo "::set-output name=matrix::${matrix}"
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: zmkfirmware/zmk-build-arm:stable
|
||||
needs: matrix
|
||||
name: Build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{fromJson(needs.matrix.outputs.matrix)}}
|
||||
steps:
|
||||
- name: Prepare variables
|
||||
id: variables
|
||||
run: |
|
||||
if [ -n "${{ matrix.shield }}" ]; then
|
||||
EXTRA_CMAKE_ARGS="-DSHIELD=${{ matrix.shield }}"
|
||||
ARTIFACT_NAME="${{ matrix.shield }}-${{ matrix.board }}-zmk"
|
||||
DISPLAY_NAME="${{ matrix.shield }} - ${{ matrix.board }}"
|
||||
else
|
||||
EXTRA_CMAKE_ARGS=
|
||||
DISPLAY_NAME="${{ matrix.board }}"
|
||||
ARTIFACT_NAME="${{ matrix.board }}-zmk"
|
||||
fi
|
||||
echo ::set-output name=extra-cmake-args::${EXTRA_CMAKE_ARGS}
|
||||
echo ::set-output name=artifact-name::${ARTIFACT_NAME}
|
||||
echo ::set-output name=display-name::${DISPLAY_NAME}
|
||||
echo ::set-output name=zephyr-version::${ZEPHYR_VERSION}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Cache west modules
|
||||
uses: actions/cache@v3.0.1
|
||||
env:
|
||||
cache-name: cache-zephyr-${{ steps.variables.outputs.zephyr-version }}-modules
|
||||
with:
|
||||
path: |
|
||||
modules/
|
||||
tools/
|
||||
zephyr/
|
||||
bootloader/
|
||||
zmk/
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/west.yml', '**/build.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: West Init
|
||||
run: west init -l ${{ inputs.config_path }}
|
||||
|
||||
- name: West Update
|
||||
run: west update
|
||||
|
||||
- name: West Zephyr export
|
||||
run: west zephyr-export
|
||||
|
||||
- name: West Build (${{ steps.variables.outputs.display-name }})
|
||||
run: |
|
||||
west build -s zmk/app -b ${{ matrix.board }} -- -DZMK_CONFIG=${GITHUB_WORKSPACE}/${{ inputs.config_path }} ${{ steps.variables.outputs.extra-cmake-args }} ${{ matrix.cmake-args }}
|
||||
|
||||
- name: ${{ steps.variables.outputs.display-name }} Kconfig file
|
||||
run: cat build/zephyr/.config | grep -v "^#" | grep -v "^$" | sort
|
||||
|
||||
- name: Rename artifacts
|
||||
run: |
|
||||
mkdir build/artifacts
|
||||
if [ -f build/zephyr/zmk.uf2 ]
|
||||
then
|
||||
cp build/zephyr/zmk.uf2 "build/artifacts/${{ steps.variables.outputs.artifact-name }}.uf2"
|
||||
elif [ -f build/zephyr/zmk.${{ inputs.fallback_binary }} ]
|
||||
then
|
||||
cp build/zephyr/zmk.${{ inputs.fallback_binary }} "build/artifacts/${{ steps.variables.outputs.artifact-name }}.${{ inputs.fallback_binary }}"
|
||||
fi
|
||||
|
||||
- name: Archive (${{ steps.variables.outputs.display-name }})
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
path: build/artifacts
|
|
@ -79,6 +79,7 @@ if (CONFIG_ZMK_SPLIT_BLE AND CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
|||
target_sources(app PRIVATE src/battery_split.c)
|
||||
endif()
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/usb.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c)
|
||||
|
|
32
app/Kconfig
32
app/Kconfig
|
@ -141,6 +141,18 @@ config ZMK_BLE_PASSKEY_ENTRY
|
|||
bool "Experimental: Requiring typing passkey from host to pair BLE connection"
|
||||
default n
|
||||
|
||||
config BT_PERIPHERAL_PREF_MIN_INT
|
||||
default 6
|
||||
|
||||
config BT_PERIPHERAL_PREF_MAX_INT
|
||||
default 12
|
||||
|
||||
config BT_PERIPHERAL_PREF_LATENCY
|
||||
default 30
|
||||
|
||||
config BT_PERIPHERAL_PREF_TIMEOUT
|
||||
default 400
|
||||
|
||||
#ZMK_BLE
|
||||
endif
|
||||
|
||||
|
@ -162,6 +174,7 @@ menuconfig ZMK_SPLIT_BLE
|
|||
depends on ZMK_BLE
|
||||
default y
|
||||
select BT_USER_PHY_UPDATE
|
||||
select BT_AUTO_PHY_UPDATE
|
||||
|
||||
if ZMK_SPLIT_BLE
|
||||
|
||||
|
@ -191,7 +204,7 @@ if !ZMK_SPLIT_BLE_ROLE_CENTRAL
|
|||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE
|
||||
int "BLE split peripheral notify thread stack size"
|
||||
default 512
|
||||
default 650
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY
|
||||
int "BLE split peripheral notify thread priority"
|
||||
|
@ -210,8 +223,8 @@ config BT_MAX_PAIRED
|
|||
config BT_MAX_CONN
|
||||
default 1
|
||||
|
||||
config BT_GAP_AUTO_UPDATE_CONN_PARAMS
|
||||
default n
|
||||
config BT_PERIPHERAL_PREF_MAX_INT
|
||||
default 6
|
||||
|
||||
config BT_BAS
|
||||
default y
|
||||
|
@ -453,12 +466,6 @@ config ZMK_KSCAN_EVENT_QUEUE_SIZE
|
|||
int "Size of the event queue for KSCAN events to buffer events"
|
||||
default 4
|
||||
|
||||
config ZMK_KSCAN_MOCK_DRIVER
|
||||
bool "Enable mock kscan driver to simulate key presses"
|
||||
|
||||
config ZMK_KSCAN_COMPOSITE_DRIVER
|
||||
bool "Enable composite kscan driver to combine kscan devices"
|
||||
|
||||
#KSCAN Settings
|
||||
endmenu
|
||||
|
||||
|
@ -482,6 +489,10 @@ if ZMK_USB_LOGGING
|
|||
config ZMK_LOG_LEVEL
|
||||
default 4
|
||||
|
||||
# We do this to avoid log loop where logging to USB generates more log messages.
|
||||
config USB_CDC_ACM_LOG_LEVEL
|
||||
default 1
|
||||
|
||||
config USB_CDC_ACM_RINGBUF_SIZE
|
||||
default 1024
|
||||
|
||||
|
@ -491,6 +502,9 @@ config LOG_BUFFER_SIZE
|
|||
config LOG_STRDUP_BUF_COUNT
|
||||
default 16
|
||||
|
||||
config LOG_PROCESS_THREAD_STARTUP_DELAY_MS
|
||||
default 1000
|
||||
|
||||
#ZMK_USB_LOGGING
|
||||
endif
|
||||
|
||||
|
|
|
@ -24,7 +24,4 @@ config ZMK_BLE
|
|||
config ZMK_USB
|
||||
default y
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
endif # BOARD_BLUEMICRO840_V1
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
leds {
|
||||
|
@ -34,7 +35,7 @@
|
|||
control-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 7>;
|
||||
|
|
|
@ -25,9 +25,6 @@ config ZMK_BLE
|
|||
config ZMK_USB
|
||||
default y
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
config ZMK_KEYBOARD_NAME
|
||||
default "BT60"
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
zmk,kscan = &kscan0;
|
||||
zmk,matrix_transform = &default_transform;
|
||||
};
|
||||
|
@ -46,7 +47,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 2>;
|
||||
|
|
|
@ -17,7 +17,4 @@ config ZMK_USB
|
|||
config ZMK_KSCAN_MATRIX_POLLING
|
||||
default y
|
||||
|
||||
config ZMK_KSCAN_COMPOSITE_DRIVER
|
||||
default y
|
||||
|
||||
endif # BOARD_FERRIS
|
||||
|
|
|
@ -17,8 +17,6 @@ CONFIG_I2C=y
|
|||
|
||||
# ZMK Settings
|
||||
CONFIG_ZMK_USB=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_COMPOSITE_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_MATRIX_POLLING=y
|
||||
CONFIG_USB_SELF_POWERED=n
|
||||
|
||||
|
|
|
@ -34,7 +34,4 @@ choice BOARD_MIKOTO_CHARGER_CURRENT
|
|||
default BOARD_MIKOTO_CHARGER_CURRENT_100MA
|
||||
endchoice
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
endif # BOARD_MIKOTO_520
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
leds {
|
||||
|
@ -34,7 +35,7 @@
|
|||
init-delay-ms = <50>;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 2>;
|
||||
|
|
|
@ -22,7 +22,4 @@ config ZMK_BLE
|
|||
config ZMK_USB
|
||||
default y
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
endif # BOARD_NICE60
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
zmk,kscan = &kscan0;
|
||||
zmk,matrix_transform = &default_transform;
|
||||
zmk,underglow = &led_strip;
|
||||
|
@ -81,7 +82,7 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,5) R
|
|||
control-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 2>;
|
||||
|
|
|
@ -23,17 +23,3 @@ config ZMK_USB
|
|||
default y
|
||||
|
||||
endif # BOARD_NICE_NANO || BOARD_NICE_NANO_V2
|
||||
|
||||
if BOARD_NICE_NANO
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
endif # BOARD_NICE_NANO
|
||||
|
||||
if BOARD_NICE_NANO_V2
|
||||
|
||||
config ZMK_BATTERY_NRF_VDDH
|
||||
default y
|
||||
|
||||
endif # BOARD_NICE_NANO_V2
|
||||
|
|
|
@ -8,13 +8,17 @@
|
|||
#include "nice_nano.dtsi"
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
ext-power {
|
||||
compatible = "zmk,ext-power-generic";
|
||||
label = "EXT_POWER";
|
||||
control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 2>;
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include "nice_nano.dtsi"
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
ext-power {
|
||||
compatible = "zmk,ext-power-generic";
|
||||
label = "EXT_POWER";
|
||||
|
@ -15,7 +19,7 @@
|
|||
init-delay-ms = <50>;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-nrf-vddh";
|
||||
label = "BATTERY";
|
||||
};
|
||||
|
|
|
@ -32,9 +32,6 @@ if BOARD_NRFMICRO_13
|
|||
config BOARD_NRFMICRO_CHARGER
|
||||
default y
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
endif # BOARD_NRFMICRO_13
|
||||
|
||||
endif # BOARD_NRFMICRO_11 || BOARD_NRFMICRO_11_FLIPPED || BOARD_NRFMICRO_13
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
leds {
|
||||
|
@ -33,7 +34,7 @@
|
|||
control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 2>;
|
||||
|
|
|
@ -25,7 +25,4 @@ config ZMK_BLE
|
|||
config ZMK_USB
|
||||
default y
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
default y
|
||||
|
||||
endif # BOARD_S40NC
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
zephyr,sram = &sram0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
zmk,kscan = &kscan0;
|
||||
zmk,matrix_transform = &default_transform;
|
||||
};
|
||||
|
@ -69,7 +70,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 2>;
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=n
|
||||
CONFIG_ZMK_BLE=n
|
||||
CONFIG_LOG=y
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=n
|
||||
# Enable to have the native posix build expose USBIP device(s)
|
||||
# CONFIG_ZMK_USB=y
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
/ {
|
||||
chosen {
|
||||
zephyr,console = &cdc_acm_uart;
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
vbatt {
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-voltage-divider";
|
||||
label = "BATTERY";
|
||||
io-channels = <&adc 7>;
|
||||
|
|
|
@ -5,8 +5,8 @@ zephyr_library_named(zmk__drivers__kscan)
|
|||
zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER debounce.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_matrix.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_direct.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio_demux.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DEMUX kscan_gpio_demux.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_MOCK_DRIVER kscan_mock.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_COMPOSITE_DRIVER kscan_composite.c)
|
||||
|
|
|
@ -1,11 +1,39 @@
|
|||
# Copyright (c) 2020 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
DT_COMPAT_ZMK_KSCAN_COMPOSITE := zmk,kscan-composite
|
||||
DT_COMPAT_ZMK_KSCAN_GPIO_DEMUX := zmk,kscan-gpio-demux
|
||||
DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT := zmk,kscan-gpio-direct
|
||||
DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX := zmk,kscan-gpio-matrix
|
||||
DT_COMPAT_ZMK_KSCAN_MOCK := zmk,kscan-mock
|
||||
|
||||
config ZMK_KSCAN_COMPOSITE_DRIVER
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_COMPOSITE))
|
||||
|
||||
config ZMK_KSCAN_GPIO_DRIVER
|
||||
bool "Enable GPIO kscan driver to detect key presses"
|
||||
default y
|
||||
bool
|
||||
select GPIO
|
||||
|
||||
config ZMK_KSCAN_GPIO_DEMUX
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_DEMUX))
|
||||
select ZMK_KSCAN_GPIO_DRIVER
|
||||
|
||||
config ZMK_KSCAN_GPIO_DIRECT
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_DIRECT))
|
||||
select ZMK_KSCAN_GPIO_DRIVER
|
||||
|
||||
config ZMK_KSCAN_GPIO_MATRIX
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_GPIO_MATRIX))
|
||||
select ZMK_KSCAN_GPIO_DRIVER
|
||||
|
||||
config ZMK_KSCAN_MOCK_DRIVER
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_KSCAN_MOCK))
|
||||
|
||||
if ZMK_KSCAN_GPIO_DRIVER
|
||||
|
||||
config ZMK_KSCAN_MATRIX_POLLING
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
struct kscan_gpio_item_config {
|
||||
char *label;
|
||||
gpio_pin_t pin;
|
||||
|
@ -251,5 +249,3 @@ struct kscan_gpio_item_config {
|
|||
&gpio_driver_api_##n);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
struct kscan_gpio_item_config {
|
||||
char *label;
|
||||
gpio_pin_t pin;
|
||||
|
@ -242,5 +240,3 @@ static const struct kscan_driver_api gpio_driver_api = {
|
|||
&gpio_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
|
|
|
@ -19,8 +19,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#define DT_DRV_COMPAT zmk_kscan_gpio_matrix
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
#define INST_DIODE_DIR(n) DT_ENUM_IDX(DT_DRV_INST(n), diode_direction)
|
||||
#define COND_DIODE_DIR(n, row2col_code, col2row_code) \
|
||||
COND_CODE_0(INST_DIODE_DIR(n), row2col_code, col2row_code)
|
||||
|
@ -51,29 +49,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#define COND_POLL_OR_INTERRUPTS(pollcode, intcode) \
|
||||
COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, pollcode, intcode)
|
||||
|
||||
// TODO (Zephr 2.6): replace the following
|
||||
// kscan_gpio_dt_spec -> gpio_dt_spec
|
||||
// KSCAN_GPIO_DT_SPEC_GET_BY_IDX -> GPIO_DT_SPEC_GET_BY_IDX
|
||||
// gpio_pin_get -> gpio_pin_get_dt
|
||||
// gpio_pin_set -> gpio_pin_set_dt
|
||||
// gpio_pin_interrupt_configure -> gpio_pin_interrupt_configure_dt
|
||||
struct kscan_gpio_dt_spec {
|
||||
const struct device *port;
|
||||
gpio_pin_t pin;
|
||||
gpio_dt_flags_t dt_flags;
|
||||
};
|
||||
|
||||
#define KSCAN_GPIO_DT_SPEC_GET_BY_IDX(node_id, prop, idx) \
|
||||
{ \
|
||||
.port = DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx)), \
|
||||
.pin = DT_GPIO_PIN_BY_IDX(node_id, prop, idx), \
|
||||
.dt_flags = DT_GPIO_FLAGS_BY_IDX(node_id, prop, idx), \
|
||||
}
|
||||
|
||||
#define KSCAN_GPIO_ROW_CFG_INIT(idx, inst_idx) \
|
||||
KSCAN_GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), row_gpios, idx),
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), row_gpios, idx),
|
||||
#define KSCAN_GPIO_COL_CFG_INIT(idx, inst_idx) \
|
||||
KSCAN_GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), col_gpios, idx),
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), col_gpios, idx),
|
||||
|
||||
enum kscan_diode_direction {
|
||||
KSCAN_ROW2COL,
|
||||
|
@ -103,7 +82,7 @@ struct kscan_matrix_data {
|
|||
};
|
||||
|
||||
struct kscan_gpio_list {
|
||||
const struct kscan_gpio_dt_spec *gpios;
|
||||
const struct gpio_dt_spec *gpios;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
|
@ -146,9 +125,9 @@ static int kscan_matrix_set_all_outputs(const struct device *dev, const int valu
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->outputs.len; i++) {
|
||||
const struct kscan_gpio_dt_spec *gpio = &config->outputs.gpios[i];
|
||||
const struct gpio_dt_spec *gpio = &config->outputs.gpios[i];
|
||||
|
||||
int err = gpio_pin_set(gpio->port, gpio->pin, value);
|
||||
int err = gpio_pin_set_dt(gpio, value);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set output %i to %i: %i", i, value, err);
|
||||
return err;
|
||||
|
@ -163,9 +142,9 @@ static int kscan_matrix_interrupt_configure(const struct device *dev, const gpio
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct kscan_gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
|
||||
int err = gpio_pin_interrupt_configure(gpio->port, gpio->pin, flags);
|
||||
int err = gpio_pin_interrupt_configure_dt(gpio, flags);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure interrupt for pin %u on %s", gpio->pin, gpio->port->name);
|
||||
return err;
|
||||
|
@ -248,25 +227,25 @@ static int kscan_matrix_read(const struct device *dev) {
|
|||
|
||||
// Scan the matrix.
|
||||
for (int o = 0; o < config->outputs.len; o++) {
|
||||
const struct kscan_gpio_dt_spec *out_gpio = &config->outputs.gpios[o];
|
||||
const struct gpio_dt_spec *out_gpio = &config->outputs.gpios[o];
|
||||
|
||||
int err = gpio_pin_set(out_gpio->port, out_gpio->pin, 1);
|
||||
int err = gpio_pin_set_dt(out_gpio, 1);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set output %i active: %i", o, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct kscan_gpio_dt_spec *in_gpio = &config->inputs.gpios[i];
|
||||
const struct gpio_dt_spec *in_gpio = &config->inputs.gpios[i];
|
||||
|
||||
const int index = state_index_io(config, i, o);
|
||||
const bool active = gpio_pin_get(in_gpio->port, in_gpio->pin);
|
||||
const bool active = gpio_pin_get_dt(in_gpio);
|
||||
|
||||
debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms,
|
||||
&config->debounce_config);
|
||||
}
|
||||
|
||||
err = gpio_pin_set(out_gpio->port, out_gpio->pin, 0);
|
||||
err = gpio_pin_set_dt(out_gpio, 0);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set output %i inactive: %i", o, err);
|
||||
return err;
|
||||
|
@ -342,14 +321,14 @@ static int kscan_matrix_disable(const struct device *dev) {
|
|||
#endif
|
||||
}
|
||||
|
||||
static int kscan_matrix_init_input_inst(const struct device *dev,
|
||||
const struct kscan_gpio_dt_spec *gpio, const int index) {
|
||||
static int kscan_matrix_init_input_inst(const struct device *dev, const struct gpio_dt_spec *gpio,
|
||||
const int index) {
|
||||
if (!device_is_ready(gpio->port)) {
|
||||
LOG_ERR("GPIO is not ready: %s", gpio->port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int err = gpio_pin_configure(gpio->port, gpio->pin, GPIO_INPUT | gpio->dt_flags);
|
||||
int err = gpio_pin_configure_dt(gpio, GPIO_INPUT);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name);
|
||||
return err;
|
||||
|
@ -377,7 +356,7 @@ static int kscan_matrix_init_inputs(const struct device *dev) {
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct kscan_gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
int err = kscan_matrix_init_input_inst(dev, gpio, i);
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -388,13 +367,13 @@ static int kscan_matrix_init_inputs(const struct device *dev) {
|
|||
}
|
||||
|
||||
static int kscan_matrix_init_output_inst(const struct device *dev,
|
||||
const struct kscan_gpio_dt_spec *gpio) {
|
||||
const struct gpio_dt_spec *gpio) {
|
||||
if (!device_is_ready(gpio->port)) {
|
||||
LOG_ERR("GPIO is not ready: %s", gpio->port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int err = gpio_pin_configure(gpio->port, gpio->pin, GPIO_OUTPUT | gpio->dt_flags);
|
||||
int err = gpio_pin_configure_dt(gpio, GPIO_OUTPUT);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure pin %u on %s for output", gpio->pin, gpio->port->name);
|
||||
return err;
|
||||
|
@ -409,7 +388,7 @@ static int kscan_matrix_init_outputs(const struct device *dev) {
|
|||
const struct kscan_matrix_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->outputs.len; i++) {
|
||||
const struct kscan_gpio_dt_spec *gpio = &config->outputs.gpios[i];
|
||||
const struct gpio_dt_spec *gpio = &config->outputs.gpios[i];
|
||||
int err = kscan_matrix_init_output_inst(dev, gpio);
|
||||
if (err) {
|
||||
return err;
|
||||
|
@ -445,10 +424,10 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
|||
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(index) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \
|
||||
\
|
||||
static const struct kscan_gpio_dt_spec kscan_matrix_rows_##index[] = { \
|
||||
static const struct gpio_dt_spec kscan_matrix_rows_##index[] = { \
|
||||
UTIL_LISTIFY(INST_ROWS_LEN(index), KSCAN_GPIO_ROW_CFG_INIT, index)}; \
|
||||
\
|
||||
static const struct kscan_gpio_dt_spec kscan_matrix_cols_##index[] = { \
|
||||
static const struct gpio_dt_spec kscan_matrix_cols_##index[] = { \
|
||||
UTIL_LISTIFY(INST_COLS_LEN(index), KSCAN_GPIO_COL_CFG_INIT, index)}; \
|
||||
\
|
||||
static struct debounce_state kscan_matrix_state_##index[INST_MATRIX_LEN(index)]; \
|
||||
|
@ -482,5 +461,3 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
|||
CONFIG_APPLICATION_INIT_PRIORITY, &kscan_matrix_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KSCAN_MATRIX_INIT);
|
||||
|
||||
#endif // DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
|
|
@ -1,20 +1,25 @@
|
|||
# Copyright (c) 2020-2021 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
DT_COMPAT_ZMK_BATTERY_NRF_VDDH := zmk,battery-nrf-vddh
|
||||
DT_COMPAT_ZMK_BATTERY_VOLTAGE_DIVIDER := zmk,battery-voltage-divider
|
||||
|
||||
config ZMK_BATTERY
|
||||
bool "ZMK battery monitoring"
|
||||
help
|
||||
Enable battery monitoring
|
||||
|
||||
config ZMK_BATTERY_NRF_VDDH
|
||||
bool "ZMK nRF VDDH battery monitoring"
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BATTERY_NRF_VDDH))
|
||||
select ADC
|
||||
select ZMK_BATTERY
|
||||
help
|
||||
Enable ZMK nRF VDDH voltage driver for battery monitoring.
|
||||
|
||||
config ZMK_BATTERY_VOLTAGE_DIVIDER
|
||||
bool "ZMK battery voltage divider"
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BATTERY_VOLTAGE_DIVIDER))
|
||||
select ADC
|
||||
select ZMK_BATTERY
|
||||
help
|
||||
|
|
|
@ -20,6 +20,8 @@ properties:
|
|||
default: -1
|
||||
quick_tap_ms: # deprecated
|
||||
type: int
|
||||
global-quick-tap:
|
||||
type: boolean
|
||||
flavor:
|
||||
type: string
|
||||
required: false
|
||||
|
|
|
@ -23,7 +23,3 @@ enum zmk_usb_conn_state zmk_usb_get_conn_state();
|
|||
|
||||
static inline bool zmk_usb_is_powered() { return zmk_usb_get_conn_state() != ZMK_USB_CONN_NONE; }
|
||||
static inline bool zmk_usb_is_hid_ready() { return zmk_usb_get_conn_state() == ZMK_USB_CONN_HID; }
|
||||
|
||||
#ifdef CONFIG_ZMK_USB
|
||||
int zmk_usb_hid_send_report(const uint8_t *report, size_t len);
|
||||
#endif /* CONFIG_ZMK_USB */
|
9
app/include/zmk/usb_hid.h
Normal file
9
app/include/zmk/usb_hid.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int zmk_usb_hid_send_report(const uint8_t *report, size_t len);
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <devicetree.h>
|
||||
#include <init.h>
|
||||
#include <kernel.h>
|
||||
#include <drivers/sensor.h>
|
||||
|
@ -18,12 +19,18 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#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; }
|
||||
|
||||
#if DT_HAS_CHOSEN(zmk_battery)
|
||||
static const struct device *const battery = DEVICE_DT_GET(DT_CHOSEN(zmk_battery));
|
||||
#else
|
||||
#warning \
|
||||
"Using a node labeled BATTERY for the battery sensor is deprecated. Set a zmk,battery chosen node instead. (Ignore this if you don't have a battery sensor.)"
|
||||
static const struct device *battery;
|
||||
#endif
|
||||
|
||||
static int zmk_battery_update(const struct device *battery) {
|
||||
struct sensor_value state_of_charge;
|
||||
|
||||
|
@ -75,10 +82,18 @@ static void zmk_battery_timer(struct k_timer *timer) { k_work_submit(&battery_wo
|
|||
K_TIMER_DEFINE(battery_timer, zmk_battery_timer, NULL);
|
||||
|
||||
static int zmk_battery_init(const struct device *_arg) {
|
||||
#if !DT_HAS_CHOSEN(zmk_battery)
|
||||
battery = device_get_binding("BATTERY");
|
||||
|
||||
if (battery == NULL) {
|
||||
LOG_DBG("No battery device labelled BATTERY found.");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LOG_WRN("Finding battery device labeled BATTERY is deprecated. Use zmk,battery chosen node.");
|
||||
#endif
|
||||
|
||||
if (!device_is_ready(battery)) {
|
||||
LOG_ERR("Battery device \"%s\" is not ready", battery->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ struct behavior_hold_tap_config {
|
|||
char *hold_behavior_dev;
|
||||
char *tap_behavior_dev;
|
||||
int quick_tap_ms;
|
||||
bool global_quick_tap;
|
||||
enum flavor flavor;
|
||||
bool retro_tap;
|
||||
int32_t hold_trigger_key_positions_len;
|
||||
|
@ -88,22 +89,33 @@ 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'
|
||||
// Keep track of which key was tapped most recently for the standard, if it is a hold-tap
|
||||
// a position, will be given, if not it will just be INT32_MIN
|
||||
struct last_tapped {
|
||||
int32_t position;
|
||||
int64_t tap_deadline;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
struct last_tapped last_tapped;
|
||||
struct last_tapped last_tapped = {INT32_MIN, INT64_MIN};
|
||||
|
||||
static void store_last_tapped(struct active_hold_tap *hold_tap) {
|
||||
static void store_last_tapped(int64_t timestamp) {
|
||||
if (timestamp > last_tapped.timestamp) {
|
||||
last_tapped.position = INT32_MIN;
|
||||
last_tapped.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
static void store_last_hold_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;
|
||||
last_tapped.timestamp = hold_tap->timestamp;
|
||||
}
|
||||
|
||||
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;
|
||||
if (hold_tap->config->global_quick_tap || last_tapped.position == hold_tap->position) {
|
||||
return (last_tapped.timestamp + hold_tap->config->quick_tap_ms) > hold_tap->timestamp;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int capture_event(const zmk_event_t *event) {
|
||||
|
@ -362,7 +374,7 @@ static int press_binding(struct active_hold_tap *hold_tap) {
|
|||
} else {
|
||||
binding.behavior_dev = hold_tap->config->tap_behavior_dev;
|
||||
binding.param1 = hold_tap->param_tap;
|
||||
store_last_tapped(hold_tap);
|
||||
store_last_hold_tapped(hold_tap);
|
||||
}
|
||||
return behavior_keymap_binding_pressed(&binding, event);
|
||||
}
|
||||
|
@ -619,6 +631,10 @@ static int keycode_state_changed_listener(const zmk_event_t *eh) {
|
|||
// we want to catch layer-up events too... how?
|
||||
struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh);
|
||||
|
||||
if (ev->state && !is_mod(ev->usage_page, ev->keycode)) {
|
||||
store_last_tapped(ev->timestamp);
|
||||
}
|
||||
|
||||
if (undecided_hold_tap == NULL) {
|
||||
// LOG_DBG("0x%02X bubble (no undecided hold_tap active)", ev->keycode);
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
|
@ -680,6 +696,7 @@ static int behavior_hold_tap_init(const struct device *dev) {
|
|||
.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), \
|
||||
.global_quick_tap = DT_INST_PROP(n, global_quick_tap), \
|
||||
.flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \
|
||||
.retro_tap = DT_INST_PROP(n, retro_tap), \
|
||||
.hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \
|
||||
|
|
|
@ -398,10 +398,6 @@ static void connected(struct bt_conn *conn, uint8_t err) {
|
|||
|
||||
LOG_DBG("Connected %s", log_strdup(addr));
|
||||
|
||||
#if IS_SPLIT_PERIPHERAL
|
||||
bt_conn_le_phy_update(conn, BT_CONN_LE_PHY_PARAM_2M);
|
||||
#endif
|
||||
|
||||
if (bt_conn_set_security(conn, BT_SECURITY_L2)) {
|
||||
LOG_ERR("Failed to set security");
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <zmk/endpoints.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <dt-bindings/zmk/hid_usage_pages.h>
|
||||
#include <zmk/usb.h>
|
||||
#include <zmk/usb_hid.h>
|
||||
#include <zmk/hog.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/ble_active_profile_changed.h>
|
||||
|
|
|
@ -483,12 +483,6 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) {
|
|||
BT_HCI_OP_LE_CREATE_CONN);
|
||||
start_scan();
|
||||
}
|
||||
|
||||
err = bt_conn_le_phy_update(slot->conn, BT_CONN_LE_PHY_PARAM_2M);
|
||||
if (err) {
|
||||
LOG_ERR("Update phy conn failed (err %d)", err);
|
||||
start_scan();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -26,41 +26,6 @@ static void raise_usb_status_changed_event(struct k_work *_work) {
|
|||
|
||||
K_WORK_DEFINE(usb_status_notifier_work, raise_usb_status_changed_event);
|
||||
|
||||
#ifdef CONFIG_ZMK_USB
|
||||
|
||||
static const struct device *hid_dev;
|
||||
|
||||
static K_SEM_DEFINE(hid_sem, 1, 1);
|
||||
|
||||
static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); }
|
||||
|
||||
static const struct hid_ops ops = {
|
||||
.int_in_ready = in_ready_cb,
|
||||
};
|
||||
|
||||
int zmk_usb_hid_send_report(const uint8_t *report, size_t len) {
|
||||
switch (usb_status) {
|
||||
case USB_DC_SUSPEND:
|
||||
return usb_wakeup_request();
|
||||
case USB_DC_ERROR:
|
||||
case USB_DC_RESET:
|
||||
case USB_DC_DISCONNECTED:
|
||||
case USB_DC_UNKNOWN:
|
||||
return -ENODEV;
|
||||
default:
|
||||
k_sem_take(&hid_sem, K_MSEC(30));
|
||||
int err = hid_int_ep_write(hid_dev, report, len, NULL);
|
||||
|
||||
if (err) {
|
||||
k_sem_give(&hid_sem);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ZMK_USB */
|
||||
|
||||
enum usb_dc_status_code zmk_usb_get_status() { return usb_status; }
|
||||
|
||||
enum zmk_usb_conn_state zmk_usb_get_conn_state() {
|
||||
|
@ -87,19 +52,6 @@ void usb_status_cb(enum usb_dc_status_code status, const uint8_t *params) {
|
|||
static int zmk_usb_init(const struct device *_arg) {
|
||||
int usb_enable_ret;
|
||||
|
||||
#ifdef CONFIG_ZMK_USB
|
||||
hid_dev = device_get_binding("HID_0");
|
||||
if (hid_dev == NULL) {
|
||||
LOG_ERR("Unable to locate HID device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
usb_hid_register_device(hid_dev, zmk_hid_report_desc, sizeof(zmk_hid_report_desc), &ops);
|
||||
|
||||
usb_hid_init(hid_dev);
|
||||
|
||||
#endif /* CONFIG_ZMK_USB */
|
||||
|
||||
usb_enable_ret = usb_enable(usb_status_cb);
|
||||
|
||||
if (usb_enable_ret != 0) {
|
||||
|
|
64
app/src/usb_hid.c
Normal file
64
app/src/usb_hid.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <usb/usb_device.h>
|
||||
#include <usb/class/usb_hid.h>
|
||||
|
||||
#include <zmk/usb.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/event_manager.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
static const struct device *hid_dev;
|
||||
|
||||
static K_SEM_DEFINE(hid_sem, 1, 1);
|
||||
|
||||
static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); }
|
||||
|
||||
static const struct hid_ops ops = {
|
||||
.int_in_ready = in_ready_cb,
|
||||
};
|
||||
|
||||
int zmk_usb_hid_send_report(const uint8_t *report, size_t len) {
|
||||
switch (zmk_usb_get_status()) {
|
||||
case USB_DC_SUSPEND:
|
||||
return usb_wakeup_request();
|
||||
case USB_DC_ERROR:
|
||||
case USB_DC_RESET:
|
||||
case USB_DC_DISCONNECTED:
|
||||
case USB_DC_UNKNOWN:
|
||||
return -ENODEV;
|
||||
default:
|
||||
k_sem_take(&hid_sem, K_MSEC(30));
|
||||
int err = hid_int_ep_write(hid_dev, report, len, NULL);
|
||||
|
||||
if (err) {
|
||||
k_sem_give(&hid_sem);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
static int zmk_usb_hid_init(const struct device *_arg) {
|
||||
hid_dev = device_get_binding("HID_0");
|
||||
if (hid_dev == NULL) {
|
||||
LOG_ERR("Unable to locate HID device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
usb_hid_register_device(hid_dev, zmk_hid_report_desc, sizeof(zmk_hid_report_desc), &ops);
|
||||
usb_hid_init(hid_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(zmk_usb_hid_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_EMUL=y
|
||||
CONFIG_ZMK_BLE=n
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_EMUL=y
|
||||
CONFIG_ZMK_BLE=n
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_EMUL=y
|
||||
CONFIG_ZMK_BLE=n
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_EMUL=y
|
||||
CONFIG_ZMK_BLE=n
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_EMUL=y
|
||||
CONFIG_ZMK_BLE=n
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_GPIO_EMUL=y
|
||||
CONFIG_ZMK_BLE=n
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,24 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (balanced decision moment key-up)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (balanced decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold-timer (balanced decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (balanced decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,25 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* tap */
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
/* normal quick tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* hold */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* global quick tap */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,12 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold-timer (balanced decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 1 new undecided hold_tap
|
||||
ht_decide: 1 decided hold-timer (balanced decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
|
@ -0,0 +1,20 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* hold the first mod tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
/* hold the second mod tap */
|
||||
ZMK_MOCK_PRESS(0,1,400)
|
||||
/* press the normal key */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
|
||||
/* release the hold taps */
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ht_bal: behavior_balanced {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "MOD_TAP";
|
||||
#binding-cells = <2>;
|
||||
flavor = "balanced";
|
||||
tapping-term-ms = <300>;
|
||||
quick-tap-ms = <300>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
global-quick-tap;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&ht_bal LEFT_SHIFT F &ht_bal LEFT_CONTROL C
|
||||
&kp D &none>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,24 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (hold-preferred decision moment key-up)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (hold-preferred decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold-interrupt (hold-preferred decision moment other-key-down)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (hold-preferred decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,25 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* tap */
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
/* normal quick tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* hold */
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* global quick tap */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,12 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold-timer (hold-preferred decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 1 new undecided hold_tap
|
||||
ht_decide: 1 decided hold-timer (hold-preferred decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
|
@ -0,0 +1,20 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* hold the first mod tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
/* hold the second mod tap */
|
||||
ZMK_MOCK_PRESS(0,1,400)
|
||||
/* press the normal key */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
|
||||
/* release the hold taps */
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
hp: behavior_hold_preferred {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "MOD_TAP";
|
||||
#binding-cells = <2>;
|
||||
flavor = "hold-preferred";
|
||||
tapping-term-ms = <300>;
|
||||
quick-tap-ms = <300>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
global-quick-tap;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&hp LEFT_SHIFT F &hp LEFT_CONTROL G
|
||||
&kp D &none>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,24 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-preferred decision moment key-up)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-preferred decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold-timer (tap-preferred decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-preferred decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,25 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* tap */
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
/* normal quick tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* hold */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* global quick tap */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,12 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided hold-timer (tap-preferred decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 1 new undecided hold_tap
|
||||
ht_decide: 1 decided hold-timer (tap-preferred decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0xe1 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0xe0 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
|
@ -0,0 +1,20 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* hold the first mod tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
/* hold the second mod tap */
|
||||
ZMK_MOCK_PRESS(0,1,400)
|
||||
/* press the normal key */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
|
||||
/* release the hold taps */
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
tp: behavior_tap_preferred {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "MOD_TAP";
|
||||
#binding-cells = <2>;
|
||||
flavor = "tap-preferred";
|
||||
tapping-term-ms = <300>;
|
||||
quick-tap-ms = <300>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
global-quick-tap;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&tp LEFT_SHIFT F &tp LEFT_CONTROL C
|
||||
&kp D &none>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,24 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-unless-interrupted decision moment key-up)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-unless-interrupted decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-unless-interrupted decision moment quick-tap)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
|
@ -0,0 +1,25 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* tap */
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
/* normal quick tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* hold */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,400)
|
||||
/* global quick tap */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*on_hold_tap_binding/ht_binding/p
|
||||
s/.*decide_hold_tap/ht_decide/p
|
||||
s/.*update_hold_status_for_retro_tap/update_hold_status_for_retro_tap/p
|
||||
s/.*decide_retro_tap/decide_retro_tap/p
|
|
@ -0,0 +1,12 @@
|
|||
ht_binding_pressed: 0 new undecided hold_tap
|
||||
ht_decide: 0 decided tap (tap-unless-interrupted decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_pressed: 1 new undecided hold_tap
|
||||
ht_decide: 1 decided tap (tap-unless-interrupted decision moment timer)
|
||||
kp_pressed: usage_page 0x07 keycode 0x0d implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x07 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x09 implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 0 cleaning up hold-tap
|
||||
kp_released: usage_page 0x07 keycode 0x0d implicit_mods 0x00 explicit_mods 0x00
|
||||
ht_binding_released: 1 cleaning up hold-tap
|
|
@ -0,0 +1,20 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
/* hold the first mod tap */
|
||||
ZMK_MOCK_PRESS(0,0,400)
|
||||
/* hold the second mod tap */
|
||||
ZMK_MOCK_PRESS(0,1,400)
|
||||
/* press the normal key */
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
|
||||
/* release the hold taps */
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,29 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ht_tui: behavior_hold_tap_tap_unless_interrupted {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "hold_tap_tap_unless_interrupted";
|
||||
#binding-cells = <2>;
|
||||
flavor = "tap-unless-interrupted";
|
||||
tapping-term-ms = <300>;
|
||||
quick-tap-ms = <300>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
global-quick-tap;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&ht_tui LEFT_SHIFT F &ht_tui LEFT_CONTROL J
|
||||
&kp D &kp RIGHT_CONTROL>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=n
|
||||
CONFIG_ZMK_BLE=n
|
||||
CONFIG_LOG=y
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
CONFIG_KSCAN=n
|
||||
CONFIG_ZMK_KSCAN_MOCK_DRIVER=y
|
||||
CONFIG_ZMK_KSCAN_GPIO_DRIVER=n
|
||||
CONFIG_GPIO=n
|
||||
CONFIG_ZMK_BLE=n
|
||||
CONFIG_LOG=y
|
||||
|
|
|
@ -31,5 +31,6 @@ manifest:
|
|||
- openthread
|
||||
- edtt
|
||||
- trusted-firmware-m
|
||||
- sof
|
||||
self:
|
||||
west-commands: scripts/west-commands.yml
|
||||
|
|
|
@ -74,7 +74,7 @@ The following changes have [already been completed](https://github.com/zmkfirmwa
|
|||
|
||||
### RGB Underglow
|
||||
|
||||
Zephyr's WS2812 `led_strip` driver added a new required property. When adding [underglow](/docs/features/underglow#adding-rgb-underglow-to-a-board) to a board, you now must also add a `color-mapping` property, like:
|
||||
Zephyr's WS2812 `led_strip` driver added a new required property. When adding [underglow](/docs/features/underglow#adding-rgb-underglow-to-a-board) to a board, you now must also add the additional include `#include <dt-bindings/led/led.h>` at the top of your devicetree file, and add a `color-mapping` property like:
|
||||
|
||||
```
|
||||
led_strip: ws2812@0 {
|
||||
|
|
71
docs/blog/2022-04-21-zmk-2yo.md
Normal file
71
docs/blog/2022-04-21-zmk-2yo.md
Normal file
|
@ -0,0 +1,71 @@
|
|||
---
|
||||
title: "ZMK's Second Birthday"
|
||||
author: Pete Johanson
|
||||
author_title: Project Creator
|
||||
author_url: https://gitlab.com/petejohanson
|
||||
author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110
|
||||
tags: [keyboards, firmware, oss]
|
||||
---
|
||||
|
||||
Two years ago, today, I minted the first ever commit for ZMK:
|
||||
|
||||
```
|
||||
commit 85c8be89dea8f7a00e8efb06d38e2b32f3459935
|
||||
Author: Pete Johanson <peter@peterjohanson.com>
|
||||
Date: Tue Apr 21 16:20:34 2020 -0400
|
||||
|
||||
Initial work.
|
||||
|
||||
.gitignore | 1 +
|
||||
.gitmodules | 3 +++
|
||||
CMakeLists.txt | 40 +++++++++++++++++++++++++++++++++++++++
|
||||
src/main.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
src/zmk_lib.h | 7 +++++++
|
||||
zephyr-rust | 1 +
|
||||
6 files changed, 112 insertions(+)
|
||||
```
|
||||
|
||||
I will never forget that commit. Not because of the code it contained (please don't look, it's not worth it!), but for what it started.
|
||||
|
||||
Working on ZMK has given me the opportunity to reconnect with old friends ([@brixmeister](https://twitter.com/brixmeister) was my Gentoo mentor/sponsor when I became a contributor there on my first ever OSS project, and is a current active Zephyr RTOS contributor!), make new ones, and learn so much from the amazing mechanical keyboard community.
|
||||
|
||||
## First Keyboard
|
||||
|
||||
But I'm getting ahead of myself! Back to early ZMK. I present you the first ZMK keyboard:
|
||||
|
||||

|
||||
|
||||
That first "keyboard" taught me a _lot_. It forced me to dust off my long forgotten, rudimentary electronics knowledge, and gave me my first taste of really combining the physical/tangible with code in a way that years of doing backend API development never had.
|
||||
|
||||
I was _hooked_.
|
||||
|
||||
## Zephyr RTOS
|
||||
|
||||
Early in my brainstorming, I knew I needed a foundation to build upon that would get me "a lot for free." I evaluated several different real-time operating systems (RTOSes) and happened upon [Zephyr](https://zephyrproject.org/). It immediately ticked all the boxes I wanted:
|
||||
|
||||
- Robust, open source Bluetooth stack, supporting multiple SoCs. At the time, I was trying out stm32wb thanks to some interest among keyboard designers, but I also so there were other compelling choices that might be a good fit.
|
||||
- An open source, non-copyleft license. I am a firm believer in F/OSS, and wanted to use a license that was as unrestricted as possible.
|
||||
- Had a lot of core APIs available, so I could focus on the keyboard functionality, not the plumbing. I love tinkering, but I wanted to focus my time on the interesting bits, not infrastructure.
|
||||
|
||||
I'm really happy with the choice, it has served us incredibly well the past two years.
|
||||
|
||||
## Real Keyboard
|
||||
|
||||
At some point, somehow, [innovaker] introduced me to [nicell] who graciously sent me a few of the early pre-production nice!nano controllers, which I was able to get running on my Kyria. Doing so required the first split code, as well as lots of general improvements.
|
||||
|
||||

|
||||
|
||||
The day I was finally able to type on a wireless, split keyboard running ZMK was deeply momentous for me!
|
||||
|
||||
## Onward and Upward
|
||||
|
||||
We've come a long way since then, with our [supported hardware](/docs/hardware), [features](/docs/features/keymaps) and [behaviors](/docs/behaviors/key-press) growing regularly.
|
||||
|
||||
ZMK powered keyboards are now available in group buys and in stock at various vendors; compatible controllers have been used in a wide range of builds to empower our users to free themselves from their USB/TRRS cables and move about untethered.
|
||||
|
||||
This progress is only possible thanks to all of the contributors who've joined me in the vision for a wireless-first world. I am so grateful for everyone who has given their time to contribute code, answer questions on our Discord server, write more documentation, and especially all the users who have trusted us to make their input devices work.
|
||||
|
||||
I can't wait to see what we can accomplish together in the next two years.
|
||||
|
||||
[innovaker]: https://github.com/innovaker
|
||||
[nicell]: https://github.com/Nicell
|
BIN
docs/blog/assets/2022-04-21-zmk-2yo/first-zmk-keyboard.jpg
Normal file
BIN
docs/blog/assets/2022-04-21-zmk-2yo/first-zmk-keyboard.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
BIN
docs/blog/assets/2022-04-21-zmk-2yo/kyria-first-split.jpg
Normal file
BIN
docs/blog/assets/2022-04-21-zmk-2yo/kyria-first-split.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
|
@ -48,6 +48,29 @@ If you press a tapped hold-tap again within `quick-tap-ms` milliseconds, it will
|
|||
|
||||
In QMK, unlike ZMK, this functionality is enabled by default, and you turn it off using `TAPPING_FORCE_HOLD`.
|
||||
|
||||
#### `global-quick-tap`
|
||||
|
||||
If global quick tap is enabled, then `quick-tap-ms` will apply not only when the given hold-tap is tapped but for any key tap before it. This effectively disables the hold tap when typing quickly, which can be quite useful for home row mods. It can also have the effect of removing the input delay when typing quickly.
|
||||
|
||||
For example, the following hold-tap configuration enables global quick tap with a 125 millisecond term.
|
||||
|
||||
```
|
||||
gqt: global-quick-tap {
|
||||
compatible = "zmk,behavior-hold-tap";
|
||||
label = "GLOBAL_QUICK_TAP";
|
||||
#binding-cells = <2>;
|
||||
flavor = "tap-preferred";
|
||||
tapping-term-ms = <200>;
|
||||
quick-tap-ms = <125>;
|
||||
global-quick-tap;
|
||||
bindings = <&kp>, <&kp>;
|
||||
};
|
||||
```
|
||||
|
||||
If you press `&kp A` and then `&gqt LEFT_SHIFT B` **within** 125 ms, then `ab` will be output. Importantly, `b` will be output immediately since it was within the `quick-tap-ms`. This quick-tap behavior will work for any key press, whether it is within a behavior like hold-tap, or a simple `&kp`. This means the `&gqt LEFT_SHIFT B` binding will only have its underlying hold-tap behavior if it is pressed 125 ms **after** a key press.
|
||||
|
||||
Note that the higher the `quick-tap-ms` the harder it will be to use the hold behavior, making this less applicable for something like capitalizing letter while typing normally. However, if the hold behavior isn't used during fast typing, then it can be an effective way to mitigate misfires.
|
||||
|
||||
#### `retro-tap`
|
||||
|
||||
If retro tap is enabled, the tap behavior is triggered when releasing the hold-tap key if no other key was pressed in the meantime.
|
||||
|
|
|
@ -46,4 +46,4 @@ You can configure a different tapping term in your keymap:
|
|||
|
||||
### Additional information
|
||||
|
||||
The mod-tap is a [hold-tap](hold-tap.md) under the hood with the "balanced" flavor and tapping-term-ms 200.
|
||||
The mod-tap is a [hold-tap](hold-tap.md) under the hood with the "hold-preferred" flavor and tapping-term-ms 200.
|
||||
|
|
|
@ -7,8 +7,6 @@ sidebar_label: Sticky Key
|
|||
|
||||
A sticky key stays pressed until another key is pressed. It is often used for 'sticky shift'. By using a sticky shift, you don't have to hold the shift key to write a capital.
|
||||
|
||||
By default, sticky keys stay pressed for a second if you don't press any other key. You can configure this with the `release-after-ms` setting (see below).
|
||||
|
||||
### Behavior Binding
|
||||
|
||||
- Reference: `&sk`
|
||||
|
@ -28,11 +26,25 @@ You can use any keycode that works for `&kp` as parameter to `&sk`:
|
|||
|
||||
### Configuration
|
||||
|
||||
You can configure a different `release-after-ms` in your keymap:
|
||||
#### `release-after-ms`
|
||||
|
||||
By default, sticky keys stay pressed for a second if you don't press any other key. You can configure this with the `release-after-ms` setting.
|
||||
|
||||
#### `quick-release`
|
||||
|
||||
Some typists may find that using a sticky shift key interspersed with rapid typing results in two or more capitalized letters instead of one. This happens as the sticky key is active until the next key is released, under which other keys may be pressed and will receive the modifier. You can enable the `quick-release` setting to instead deactivate the sticky key on the next key being pressed, as opposed to released.
|
||||
|
||||
#### `ignore-modifiers`
|
||||
|
||||
This setting is enabled by default. It ensures that if a sticky key modifier is pressed before a previously pressed sticky key is released, the modifiers will get combined so you can add more sticky keys or press a regular key to apply the modifiers. This is to accommodate _callum-style mods_ where you are prone to rolling sticky keys. If you want sticky key modifiers to only chain after release, you can disable this setting.
|
||||
|
||||
#### Example
|
||||
|
||||
```
|
||||
&sk {
|
||||
release-after-ms = <2000>;
|
||||
quick-release;
|
||||
/delete-property/ ignore-modifiers;
|
||||
};
|
||||
|
||||
/ {
|
||||
|
@ -42,6 +54,27 @@ You can configure a different `release-after-ms` in your keymap:
|
|||
};
|
||||
```
|
||||
|
||||
This configuration would apply to all sticky keys. This may not be appropriate if using `quick-release` as you'll lose the ability to chain sticky key modifiers. A better approach for this use case would be to create a new behavior:
|
||||
|
||||
```
|
||||
/ {
|
||||
behaviors {
|
||||
skq: sticky_key_quick_release {
|
||||
compatible = "zmk,behavior-sticky-key";
|
||||
label = "STICKY_KEY_QUICK_RELEASE";
|
||||
#binding-cells = <1>;
|
||||
bindings = <&kp>;
|
||||
release-after-ms = <1000>;
|
||||
quick-release;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
...
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Advanced usage
|
||||
|
||||
Sticky keys can be combined; if you tap `&sk LCTRL` and then `&sk LSHIFT` and then `&kp A`, the output will be ctrl+shift+a.
|
||||
|
|
|
@ -6,7 +6,11 @@ sidebar_label: Backlight
|
|||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
Backlight is a feature used to control array of LEDs, usually placed through or under switches. Unlike [RGB Underglow](underglow.md), backlight currently allows only one color per LED, also LEDs are not addressable, so you can't control individual LEDs.
|
||||
Backlight is a feature used to control an array of LEDs, usually placed through or under switches.
|
||||
|
||||
:::info
|
||||
Unlike [RGB Underglow](underglow.md), backlight can only control single color LEDs. Additionally, because backlight LEDs all receive the same power, it's not possible to dim individual LEDs.
|
||||
:::
|
||||
|
||||
## Enabling Backlight
|
||||
|
||||
|
@ -99,7 +103,7 @@ Finally you need to add backlight to the `chosen` element of the root devicetree
|
|||
chosen {
|
||||
zmk,backlight = &backlight;
|
||||
};
|
||||
}:
|
||||
};
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
|
38
docs/docs/features/battery.md
Normal file
38
docs/docs/features/battery.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
title: Battery Level
|
||||
sidebar_label: Battery Level
|
||||
---
|
||||
|
||||
If your keyboard has a battery sensor, ZMK will report its battery level to the connected bluetooth host and show it on the keyboard's display, if it has one.
|
||||
|
||||
For split keyboards, only the battery level of the central (usually left) side is reported over bluetooth.
|
||||
|
||||
:::note
|
||||
|
||||
Windows may not properly ask the keyboard to notify it of changes in battery level, so the level shown may be out of date.
|
||||
|
||||
:::
|
||||
|
||||
## Adding a Battery Sensor to a Board
|
||||
|
||||
To enable a battery sensor on a new board, add the driver for the sensor to your board's `.dts` file. ZMK provides two drivers for estimating the battery level using its voltage:
|
||||
|
||||
- `zmk,battery-voltage-divider`: Reads the voltage on an analog input pin.
|
||||
- `zmk,battery-nrf-vddh`: Reads the power supply voltage on a Nordic nRF52's VDDH pin.
|
||||
|
||||
Zephyr also provides some drivers for fuel gauge ICs such as the TI bq274xx series and Maxim MAX17xxx series. If you use a battery sensor that does not have an existing driver, you will need to write a new driver that supports the `SENSOR_CHAN_GAUGE_STATE_OF_CHARGE` sensor channel and contribute it to Zephyr or ZMK.
|
||||
|
||||
Once you have the sensor driver defined, add a `zmk,battery` property to the `chosen` node and set it to reference the sensor node. For example:
|
||||
|
||||
```
|
||||
/ {
|
||||
chosen {
|
||||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
vbatt: vbatt {
|
||||
compatible = "zmk,battery-nrf-vddh";
|
||||
label = "VBATT";
|
||||
};
|
||||
}
|
||||
```
|
|
@ -1,6 +1,10 @@
|
|||
---
|
||||
title: OLED Displays
|
||||
sidebar_label: OLED Displays
|
||||
title: Displays
|
||||
sidebar_label: Displays
|
||||
---
|
||||
|
||||
TODO: Documentation on OLED displays.
|
||||
Displays in ZMK are currently a proof of concept and official support is coming soon.
|
||||
|
||||
:::info
|
||||
Although ZMK-powered keyboards _are_ capable of utilizing OLED and ePaper displays, the Displays feature is not yet considered production-ready due to an issue where the display remains blank after resuming from [external power cutoff](../behaviors/power.md#external-power-control). This issue can be tracked on GitHub at [zmkfirmware/zmk #674](https://github.com/zmkfirmware/zmk/issues/674).
|
||||
:::
|
||||
|
|
|
@ -5,6 +5,10 @@ sidebar_label: RGB Underglow
|
|||
|
||||
RGB underglow is a feature used to control "strips" of RGB LEDs. Most of the time this is called underglow and creates a glow underneath the board using a ring of LEDs around the edge, hence the name. However, this can be extended to be used to control anything from a single LED to a long string of LEDs anywhere on the keyboard.
|
||||
|
||||
:::info
|
||||
RGB underglow can also be used for under-key lighting. If you have RGB LEDs on your keyboard, this is what you want. For PWM/single color LEDs, see [Backlight](backlight.md).
|
||||
:::
|
||||
|
||||
ZMK supports all the RGB LEDs supported by Zephyr. Here's the current list supported:
|
||||
|
||||
- WS2812-ish (WS2812B, WS2813, SK6812, or compatible)
|
||||
|
|
|
@ -6,12 +6,48 @@ sidebar_label: Supported Hardware
|
|||
import HardwareList from "@site/src/components/hardware-list";
|
||||
import Metadata from "@site/src/data/hardware-metadata.json";
|
||||
|
||||
import Heading from "@theme/Heading";
|
||||
|
||||
import { groupedMetadata } from "@site/src/components/hardware-utils";
|
||||
|
||||
export const toc = [
|
||||
{
|
||||
value: "Onboard Controller Keyboards",
|
||||
id: "onboard",
|
||||
level: 2,
|
||||
},
|
||||
{
|
||||
value: "Composite Keyboards",
|
||||
id: "composite",
|
||||
level: 2,
|
||||
},
|
||||
...Object.values(groupedMetadata(Metadata).interconnects).map(
|
||||
({ interconnect }) => ({
|
||||
value: `${interconnect.name} Interconnect`,
|
||||
id: interconnect.id,
|
||||
level: 3,
|
||||
})
|
||||
),
|
||||
{
|
||||
value: "Other Hardware",
|
||||
id: "other-hardware",
|
||||
level: 2,
|
||||
},
|
||||
{
|
||||
value: "Contributing",
|
||||
id: "contributing",
|
||||
level: 2,
|
||||
},
|
||||
];
|
||||
|
||||
With the solid technical foundation of Zephyr™ RTOS, ZMK can support a wide diversity of hardware targets.
|
||||
That being said, there are currently only a few specific [boards](/docs/faq#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been implemented and tested by the ZMK contributors.
|
||||
|
||||
<HardwareList items={Metadata} />
|
||||
|
||||
## Other Hardware
|
||||
<Heading as="h2" id="other-hardware">
|
||||
Other Hardware
|
||||
</Heading>
|
||||
|
||||
In addition to the basic keyboard functionality, there is some initial support for additional keyboard hardware:
|
||||
|
||||
|
@ -22,6 +58,8 @@ In addition to the basic keyboard functionality, there is some initial support f
|
|||
|
||||
Until detailed documentation is available, feel free to ask questions about how these are supported in the [Discord server](https://zmk.dev/community/discord/invite).
|
||||
|
||||
## Contributing
|
||||
<Heading as="h2" id="contributing">
|
||||
Contributing
|
||||
</Heading>
|
||||
|
||||
If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation.
|
||||
|
|
|
@ -32,7 +32,7 @@ ZMK is currently missing some features found in other popular firmware. This tab
|
|||
| [Backlight](features/backlight.md) | ✅ | ✅ | ✅ |
|
||||
| One Shot Keys | ✅ | ✅ | ✅ |
|
||||
| [Combo Keys](features/combos.md) | ✅ | | ✅ |
|
||||
| [Macros](behaviors/macros) | ✅ | ✅ | ✅ |
|
||||
| [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ |
|
||||
| Mouse Keys | 🚧 | ✅ | ✅ |
|
||||
| Low Active Power Usage | ✅ | | |
|
||||
| Low Power Sleep States | ✅ | ✅ | |
|
||||
|
|
|
@ -105,7 +105,7 @@ Some users may experience a poor connection between the keyboard and the host. T
|
|||
CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
|
||||
```
|
||||
|
||||
For the `nRF52840`, the value `PLUS_8` can be set to any multiple of four between `MINUS_20` and `PLUS_8`. The default value for this config is `0`, but if you are having connection issues it is recommended to set it to `PLUS_8` because the power consumption difference is negligible. For more information on changing the transmit power of your BLE device, please refer to [the Zephyr docs.](https://docs.zephyrproject.org/latest/reference/kconfig/CONFIG_BT_CTLR_TX_PWR_PLUS_8.html)
|
||||
For the `nRF52840`, the value `PLUS_8` can be set to any multiple of four between `MINUS_20` and `PLUS_8`. The default value for this config is `0`, but if you are having connection issues it is recommended to set it to `PLUS_8` because the power consumption difference is negligible. For more information on changing the transmit power of your BLE device, please refer to [the Zephyr docs.](https://docs.zephyrproject.org/latest/kconfig.html#CONFIG_BT_CTLR_TX_PWR)
|
||||
|
||||
### Other notes and warnings
|
||||
|
||||
|
|
122
docs/package-lock.json
generated
122
docs/package-lock.json
generated
|
@ -4825,11 +4825,23 @@
|
|||
}
|
||||
},
|
||||
"@fortawesome/react-fontawesome": {
|
||||
"version": "0.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.16.tgz",
|
||||
"integrity": "sha512-aLmzDwC9rEOAJv2UJdMns89VZR5Ry4IHu5dQQh24Z/lWKEm44lfQr1UNalZlkUaQN8d155tNh+CS7ntntj1VMA==",
|
||||
"version": "0.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.18.tgz",
|
||||
"integrity": "sha512-RwLIB4TZw0M9gvy5u+TusAA0afbwM4JQIimNH/j3ygd6aIvYPQLqXMhC9ErY26J23rDPyDZldIfPq/HpTTJ/tQ==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2"
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@hapi/hoek": {
|
||||
|
@ -5858,9 +5870,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"async": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
}
|
||||
|
@ -7569,21 +7581,29 @@
|
|||
"dev": true
|
||||
},
|
||||
"eslint-mdx": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-mdx/-/eslint-mdx-1.13.0.tgz",
|
||||
"integrity": "sha512-Yqc5mnh2JMEm9yTp6NUnfOg1wXGLibCqQTjvb5+EQH4LtQEmWG0DtqWUXWHRy0gmy/3lBdN9Zkc5KGwAizaTrQ==",
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-mdx/-/eslint-mdx-1.17.0.tgz",
|
||||
"integrity": "sha512-O8+JRfwCzpoR2P6zUI1GDAAM/bsuzcoBS1ArvpQrgQO/E2Km0vBmM15ukiJxZ+YUh5d+qDlrqha0fZB50MojJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cosmiconfig": "^7.0.1",
|
||||
"remark-mdx": "^1.6.22",
|
||||
"remark-parse": "^8.0.3",
|
||||
"tslib": "^2.2.0",
|
||||
"unified": "^9.2.1"
|
||||
"remark-stringify": "^8.1.1",
|
||||
"tslib": "^2.3.1",
|
||||
"unified": "^9.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
|
||||
"dev": true
|
||||
},
|
||||
"unified": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz",
|
||||
"integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==",
|
||||
"version": "9.2.2",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.2.tgz",
|
||||
"integrity": "sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bail": "^1.0.0",
|
||||
|
@ -7597,58 +7617,32 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-markdown": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.0.tgz",
|
||||
"integrity": "sha512-Ctuc7aP1tU92qnFwVO1wDLEzf1jqMxwRkcSTw7gjbvnEqfh5CKUcTXM0sxg8CB2KDXrqpTuMZPgJ1XE9Olr7KA==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-markdown/-/eslint-plugin-markdown-2.2.1.tgz",
|
||||
"integrity": "sha512-FgWp4iyYvTFxPwfbxofTvXxgzPsDuSKHQy2S+a8Ve6savbujey+lgrFFbXQA0HPygISpRYWYBjooPzhYSF81iA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mdast-util-from-markdown": "^0.8.5"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-mdx": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mdx/-/eslint-plugin-mdx-1.13.0.tgz",
|
||||
"integrity": "sha512-oZ/R9OmSx1gZs52CO58HTHlJXRKoZtF6ZMaWP+sOcSGMFxoddoPr9PDgpP52ab5TWu5yVl5guR9D+GMfzkR2Uw==",
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mdx/-/eslint-plugin-mdx-1.17.0.tgz",
|
||||
"integrity": "sha512-Kicizy+fbfsB2UxTDXP92qTtFqITApu4v4DRQUfXMoPwBHeQRvZnaEtXu2S9aia51GYRYsMSqUvoPPih/5oB+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cosmiconfig": "^7.0.0",
|
||||
"eslint-mdx": "^1.13.0",
|
||||
"eslint-plugin-markdown": "^2.1.0",
|
||||
"remark-mdx": "^1.6.22",
|
||||
"remark-parse": "^8.0.3",
|
||||
"remark-stringify": "^8.1.1",
|
||||
"synckit": "^0.1.5",
|
||||
"tslib": "^2.2.0",
|
||||
"unified": "^9.2.1",
|
||||
"eslint-mdx": "^1.17.0",
|
||||
"eslint-plugin-markdown": "^2.2.1",
|
||||
"synckit": "^0.4.1",
|
||||
"tslib": "^2.3.1",
|
||||
"vfile": "^4.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"cosmiconfig": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
|
||||
"integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"parse-json": "^5.0.0",
|
||||
"path-type": "^4.0.0",
|
||||
"yaml": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"unified": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz",
|
||||
"integrity": "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bail": "^1.0.0",
|
||||
"extend": "^3.0.0",
|
||||
"is-buffer": "^2.0.0",
|
||||
"is-plain-obj": "^2.0.0",
|
||||
"trough": "^1.0.0",
|
||||
"vfile": "^4.0.0"
|
||||
}
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -12815,19 +12809,19 @@
|
|||
}
|
||||
},
|
||||
"synckit": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.1.5.tgz",
|
||||
"integrity": "sha512-s9rDbMJAF5SDEwBGH/DvbN/fb5N1Xu1boL4Uv66idbCbtosNX3ikUsFvGhROmPXsvlMYMcT5ksmkU5RSnkFi9Q==",
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.4.1.tgz",
|
||||
"integrity": "sha512-ngUh0+s+DOqEc0sGnrLaeNjbXp0CWHjSGFBqPlQmQ+oN/OfoDoYDBXPh+b4qs1M5QTk5nuQ3AmVz9+2xiY/ldw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.2.0",
|
||||
"tslib": "^2.3.1",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"@docusaurus/preset-classic": "^2.0.0-beta.18",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.16",
|
||||
"@fortawesome/react-fontawesome": "^0.1.18",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"classnames": "^2.2.6",
|
||||
"js-yaml": "^4.1.0",
|
||||
|
@ -52,7 +52,7 @@
|
|||
"@types/react-router-dom": "^5.1.7",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-mdx": "^1.13.0",
|
||||
"eslint-plugin-mdx": "^1.17.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"json-schema-to-typescript": "^10.1.5",
|
||||
"mustache": "^4.2.0",
|
||||
|
|
|
@ -17,6 +17,7 @@ module.exports = {
|
|||
"features/encoders",
|
||||
"features/underglow",
|
||||
"features/backlight",
|
||||
"features/battery",
|
||||
"features/beta-testing",
|
||||
],
|
||||
Behaviors: [
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import React from "react";
|
||||
|
||||
import {
|
||||
Board,
|
||||
HardwareMetadata,
|
||||
Interconnect,
|
||||
Shield,
|
||||
} from "../hardware-metadata";
|
||||
import Heading from "@theme/Heading";
|
||||
|
||||
import { HardwareMetadata } from "../hardware-metadata";
|
||||
import { groupedMetadata, InterconnectDetails } from "./hardware-utils";
|
||||
|
||||
interface HardwareListProps {
|
||||
items: HardwareMetadata[];
|
||||
|
@ -53,12 +51,6 @@ function HardwareLineItem({ item }: { item: HardwareMetadata }) {
|
|||
);
|
||||
}
|
||||
|
||||
interface InterconnectDetails {
|
||||
interconnect?: Interconnect;
|
||||
boards: Board[];
|
||||
shields: Shield[];
|
||||
}
|
||||
|
||||
function mapInterconnect({
|
||||
interconnect,
|
||||
boards,
|
||||
|
@ -70,15 +62,17 @@ function mapInterconnect({
|
|||
|
||||
return (
|
||||
<div key={interconnect.id}>
|
||||
<h4>{interconnect.name} Interconnect</h4>
|
||||
<Heading as="h3" id={interconnect.id}>
|
||||
{interconnect.name} Interconnect
|
||||
</Heading>
|
||||
{interconnect.description && <p>{interconnect.description}</p>}
|
||||
<h5>Boards</h5>
|
||||
<Heading as="h4">Boards</Heading>
|
||||
<ul>
|
||||
{boards.map((s) => (
|
||||
<HardwareLineItem key={s.id} item={s} />
|
||||
))}
|
||||
</ul>
|
||||
<h5>Shields</h5>
|
||||
<Heading as="h4">Shields</Heading>
|
||||
<ul>
|
||||
{shields.map((s) => (
|
||||
<HardwareLineItem key={s.id} item={s} />
|
||||
|
@ -88,88 +82,41 @@ function mapInterconnect({
|
|||
);
|
||||
}
|
||||
|
||||
interface GroupedMetadata {
|
||||
onboard: Board[];
|
||||
interconnects: Record<string, InterconnectDetails>;
|
||||
}
|
||||
|
||||
function groupedBoard(agg: GroupedMetadata, board: Board) {
|
||||
if (board.features?.includes("keys")) {
|
||||
agg.onboard.push(board);
|
||||
} else if (board.exposes) {
|
||||
board.exposes.forEach((element) => {
|
||||
let ic = agg.interconnects[element] ?? {
|
||||
boards: [],
|
||||
shields: [],
|
||||
};
|
||||
ic.boards.push(board);
|
||||
agg.interconnects[element] = ic;
|
||||
});
|
||||
} else {
|
||||
console.error("Board without keys or interconnect");
|
||||
}
|
||||
|
||||
return agg;
|
||||
}
|
||||
|
||||
function groupedShield(agg: GroupedMetadata, shield: Shield) {
|
||||
shield.requires.forEach((id) => {
|
||||
let ic = agg.interconnects[id] ?? { boards: [], shields: [] };
|
||||
ic.shields.push(shield);
|
||||
agg.interconnects[id] = ic;
|
||||
});
|
||||
|
||||
return agg;
|
||||
}
|
||||
|
||||
function groupedInterconnect(agg: GroupedMetadata, item: Interconnect) {
|
||||
let ic = agg.interconnects[item.id] ?? { boards: [], shields: [] };
|
||||
ic.interconnect = item;
|
||||
agg.interconnects[item.id] = ic;
|
||||
|
||||
return agg;
|
||||
}
|
||||
|
||||
function HardwareList({ items }: HardwareListProps) {
|
||||
let grouped = items.reduce<GroupedMetadata>(
|
||||
(agg, hm) => {
|
||||
switch (hm.type) {
|
||||
case "board":
|
||||
return groupedBoard(agg, hm);
|
||||
case "shield":
|
||||
return groupedShield(agg, hm);
|
||||
case "interconnect":
|
||||
return groupedInterconnect(agg, hm);
|
||||
}
|
||||
},
|
||||
{ onboard: [] as Board[], interconnects: {} }
|
||||
);
|
||||
let grouped = groupedMetadata(items);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h2>Keyboards</h2>
|
||||
<h3>Onboard Controller Keyboards</h3>
|
||||
<p>
|
||||
Keyboards with onboard controllers are single PCBs that contain all the
|
||||
components of a keyboard, including the controller chip, switch
|
||||
footprints, etc.
|
||||
</p>
|
||||
<ul>
|
||||
{grouped["onboard"]
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((s) => (
|
||||
<HardwareLineItem key={s.id} item={s} />
|
||||
))}
|
||||
</ul>
|
||||
<h3>Composite Keyboards</h3>
|
||||
<p>
|
||||
Composite keyboards are composed of two main PCBs: a small controller
|
||||
board with exposed pads, and a larger keyboard PCB (a shield, in ZMK
|
||||
lingo) with switch footprints and a location where the controller is
|
||||
added. This location is called an interconnect. Multiple interconnects
|
||||
can be found below.
|
||||
</p>
|
||||
{Object.values(grouped.interconnects).map(mapInterconnect)}
|
||||
<section>
|
||||
<Heading as="h2" id="onboard">
|
||||
Onboard Controller Keyboards
|
||||
</Heading>
|
||||
<p>
|
||||
Keyboards with onboard controllers are single PCBs that contain all
|
||||
the components of a keyboard, including the controller chip, switch
|
||||
footprints, etc.
|
||||
</p>
|
||||
<ul>
|
||||
{grouped["onboard"]
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((s) => (
|
||||
<HardwareLineItem key={s.id} item={s} />
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<Heading as="h2" id="composite">
|
||||
Composite Keyboards
|
||||
</Heading>
|
||||
<p>
|
||||
Composite keyboards are composed of two main PCBs: a small controller
|
||||
board with exposed pads, and a larger keyboard PCB (a shield, in ZMK
|
||||
lingo) with switch footprints and a location where the controller is
|
||||
added. This location is called an interconnect. Multiple interconnects
|
||||
can be found below.
|
||||
</p>
|
||||
{Object.values(grouped.interconnects).map(mapInterconnect)}
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
70
docs/src/components/hardware-utils.ts
Normal file
70
docs/src/components/hardware-utils.ts
Normal file
|
@ -0,0 +1,70 @@
|
|||
import {
|
||||
Board,
|
||||
HardwareMetadata,
|
||||
Interconnect,
|
||||
Shield,
|
||||
} from "../hardware-metadata";
|
||||
|
||||
export interface InterconnectDetails {
|
||||
interconnect?: Interconnect;
|
||||
boards: Board[];
|
||||
shields: Shield[];
|
||||
}
|
||||
|
||||
export interface GroupedMetadata {
|
||||
onboard: Board[];
|
||||
interconnects: Record<string, InterconnectDetails>;
|
||||
}
|
||||
|
||||
function groupedBoard(agg: GroupedMetadata, board: Board) {
|
||||
if (board.features?.includes("keys")) {
|
||||
agg.onboard.push(board);
|
||||
} else if (board.exposes) {
|
||||
board.exposes.forEach((element) => {
|
||||
let ic = agg.interconnects[element] ?? {
|
||||
boards: [],
|
||||
shields: [],
|
||||
};
|
||||
ic.boards.push(board);
|
||||
agg.interconnects[element] = ic;
|
||||
});
|
||||
} else {
|
||||
console.error("Board without keys or interconnect");
|
||||
}
|
||||
|
||||
return agg;
|
||||
}
|
||||
|
||||
function groupedShield(agg: GroupedMetadata, shield: Shield) {
|
||||
shield.requires.forEach((id) => {
|
||||
let ic = agg.interconnects[id] ?? { boards: [], shields: [] };
|
||||
ic.shields.push(shield);
|
||||
agg.interconnects[id] = ic;
|
||||
});
|
||||
|
||||
return agg;
|
||||
}
|
||||
|
||||
function groupedInterconnect(agg: GroupedMetadata, item: Interconnect) {
|
||||
let ic = agg.interconnects[item.id] ?? { boards: [], shields: [] };
|
||||
ic.interconnect = item;
|
||||
agg.interconnects[item.id] = ic;
|
||||
|
||||
return agg;
|
||||
}
|
||||
|
||||
export function groupedMetadata(items: HardwareMetadata[]) {
|
||||
return items.reduce<GroupedMetadata>(
|
||||
(agg, hm) => {
|
||||
switch (hm.type) {
|
||||
case "board":
|
||||
return groupedBoard(agg, hm);
|
||||
case "shield":
|
||||
return groupedShield(agg, hm);
|
||||
case "interconnect":
|
||||
return groupedInterconnect(agg, hm);
|
||||
}
|
||||
},
|
||||
{ onboard: [] as Board[], interconnects: {} }
|
||||
);
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
"extends": "@tsconfig/docusaurus/tsconfig.json",
|
||||
"include": ["src/"],
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"types": ["node", "@docusaurus/theme-classic"],
|
||||
"moduleResolution": "Node",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
|
|
Loading…
Add table
Reference in a new issue