Merge branch 20230706/rafaelromao/main
into 20230706/rafaelromao/leader-key
This commit is contained in:
commit
e05a70e9b4
49 changed files with 1148 additions and 372 deletions
|
@ -43,8 +43,8 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_caps_word.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_key_repeat.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_macro.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_LEADER_KEY app PRIVATE src/behaviors/behavior_leader_key.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MACRO app PRIVATE src/behaviors/behavior_macro.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_mod_morph.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_outputs.c)
|
||||
|
@ -79,8 +79,8 @@ endif()
|
|||
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/behaviors/behavior_backlight.c)
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/battery.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/events/battery_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/battery.c)
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_SPLIT app PRIVATE src/events/split_peripheral_status_changed.c)
|
||||
add_subdirectory(src/split)
|
||||
|
|
35
app/Kconfig
35
app/Kconfig
|
@ -114,12 +114,16 @@ menuconfig ZMK_BLE
|
|||
select BT_SMP_APP_PAIRING_ACCEPT
|
||||
select BT_PERIPHERAL
|
||||
select BT_DIS
|
||||
select BT_BAS
|
||||
select BT_SETTINGS
|
||||
select SETTINGS
|
||||
imply ZMK_BATTERY_REPORTING
|
||||
|
||||
if ZMK_BLE
|
||||
|
||||
# BT_TINYCRYPT_ECC is required for BT_SMP_SC_PAIR_ONLY when using HCI
|
||||
config BT_TINYCRYPT_ECC
|
||||
default y if BT_HCI && !BT_CTLR
|
||||
|
||||
choice BT_LL_SW_LLCP_IMPL
|
||||
default BT_LL_SW_LLCP_LEGACY
|
||||
|
||||
|
@ -131,7 +135,7 @@ config SYSTEM_WORKQUEUE_STACK_SIZE
|
|||
|
||||
config ZMK_BLE_THREAD_STACK_SIZE
|
||||
int "BLE notify thread stack size"
|
||||
default 512
|
||||
default 768
|
||||
|
||||
config ZMK_BLE_THREAD_PRIORITY
|
||||
int "BLE notify thread priority"
|
||||
|
@ -160,8 +164,9 @@ config BT_DEVICE_APPEARANCE
|
|||
default 961
|
||||
|
||||
config ZMK_BLE_PASSKEY_ENTRY
|
||||
bool "Experimental: Requiring typing passkey from host to pair BLE connection"
|
||||
bool "Require passkey entry on the keyboard to complete pairing"
|
||||
default n
|
||||
select RING_BUFFER
|
||||
|
||||
config BT_PERIPHERAL_PREF_MIN_INT
|
||||
default 6
|
||||
|
@ -305,6 +310,12 @@ endmenu
|
|||
|
||||
menu "Power Management"
|
||||
|
||||
config ZMK_BATTERY_REPORTING
|
||||
bool "Battery level detection/reporting"
|
||||
default n
|
||||
select SENSOR
|
||||
select BT_BAS if ZMK_BLE
|
||||
|
||||
config ZMK_IDLE_TIMEOUT
|
||||
int "Milliseconds of inactivity before entering idle state (OLED shutoff, etc)"
|
||||
default 30000
|
||||
|
@ -540,8 +551,24 @@ config ZMK_WPM
|
|||
bool "Calculate WPM"
|
||||
default n
|
||||
|
||||
config SENSOR
|
||||
config ZMK_KEYMAP_SENSORS
|
||||
bool "Enable Keymap Sensors support"
|
||||
default y
|
||||
depends on DT_HAS_ZMK_KEYMAP_SENSORS_ENABLED
|
||||
select SENSOR
|
||||
|
||||
if ZMK_KEYMAP_SENSORS
|
||||
|
||||
config ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION
|
||||
int "Default triggers per rotation"
|
||||
help
|
||||
Unless overridden for a sensor in the board/shield/devicetree, this value
|
||||
determines how many times to trigger the bound behavior per full rotation.
|
||||
For tactile encoders with detents, this usually should match the number of
|
||||
detents per rotation of the encoder.
|
||||
default 20
|
||||
|
||||
endif # ZMK_KEYMAP_SENSORS
|
||||
|
||||
choice CBPRINTF_IMPLEMENTATION
|
||||
default CBPRINTF_NANO
|
||||
|
|
|
@ -21,4 +21,9 @@ config ZMK_BEHAVIOR_SENSOR_ROTATE_VAR
|
|||
bool
|
||||
default y
|
||||
depends on DT_HAS_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR_ENABLED
|
||||
select ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
|
||||
select ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
|
||||
|
||||
config ZMK_BEHAVIOR_MACRO
|
||||
bool
|
||||
default y
|
||||
depends on DT_HAS_ZMK_BEHAVIOR_MACRO_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_ONE_PARAM_ENABLED || DT_HAS_ZMK_BEHAVIOR_MACRO_TWO_PARAM_ENABLED
|
|
@ -17,22 +17,22 @@
|
|||
uart0_sleep: uart0_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(UART_RX, 0, 8)>,
|
||||
<NRF_PSEL(UART_TX, 0, 6)>;
|
||||
<NRF_PSEL(UART_TX, 0, 6)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_default: i2c0_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(TWIM_SDA, 0, 17)>,
|
||||
<NRF_PSEL(TWIM_SCL, 0, 20)>;
|
||||
psels = <NRF_PSEL(TWIM_SDA, 0, 15)>,
|
||||
<NRF_PSEL(TWIM_SCL, 0, 17)>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_sleep: i2c0_sleep {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(TWIM_SDA, 0, 17)>,
|
||||
<NRF_PSEL(TWIM_SCL, 0, 20)>;
|
||||
psels = <NRF_PSEL(TWIM_SDA, 0, 15)>,
|
||||
<NRF_PSEL(TWIM_SCL, 0, 17)>;
|
||||
low-power-enable;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,6 +8,9 @@ CONFIG_BOARD_PILLBUG=y
|
|||
# Enable MPU
|
||||
CONFIG_ARM_MPU=y
|
||||
|
||||
# Use pinctrl
|
||||
CONFIG_PINCTRL=y
|
||||
|
||||
# enable GPIO
|
||||
CONFIG_GPIO=y
|
||||
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
|
||||
&arduino_i2c {
|
||||
// Default buffer size is too small for use with displays.
|
||||
zephyr,concat-buf-size = <512>;
|
||||
zephyr,concat-buf-size = <1024>;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
/ {
|
||||
// First, delete the existing basic GPIO based instance.
|
||||
/delete-node/ encoder;
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
qdec_default: qdec_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(QDEC_A, 1, 11)>,
|
||||
<NRF_PSEL(QDEC_B, 1, 10)>;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Set up the QDEC hardware based driver and give it the same label as the deleted node.
|
||||
encoder: &qdec0 {
|
||||
status = "okay";
|
||||
led-pre = <0>;
|
||||
steps = <80>;
|
||||
pinctrl-0 = <&qdec_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
|
@ -40,10 +40,10 @@
|
|||
|
||||
// Commented out until we add more powerful power domain support
|
||||
// external_power {
|
||||
// compatible = "zmk,ext-power-generic";
|
||||
// label = "EXT_POWER";
|
||||
// init-delay-ms = <200>;
|
||||
// control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
|
||||
// compatible = "zmk,ext-power-generic";
|
||||
// label = "EXT_POWER";
|
||||
// init-delay-ms = <200>;
|
||||
// control-gpios = <&arduino_header 1 GPIO_ACTIVE_LOW>;
|
||||
// };
|
||||
|
||||
rgb_power {
|
||||
|
@ -128,14 +128,14 @@
|
|||
diode-direction = "col2row";
|
||||
|
||||
col-gpios
|
||||
= <&arduino_header 10 GPIO_ACTIVE_HIGH>
|
||||
, <&arduino_header 9 GPIO_ACTIVE_HIGH>
|
||||
;
|
||||
= <&arduino_header 10 GPIO_ACTIVE_HIGH>
|
||||
, <&arduino_header 9 GPIO_ACTIVE_HIGH>
|
||||
;
|
||||
|
||||
row-gpios
|
||||
= <&arduino_header 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
, <&arduino_header 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
;
|
||||
= <&arduino_header 13 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
, <&arduino_header 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
|
||||
;
|
||||
|
||||
};
|
||||
|
||||
|
@ -144,11 +144,11 @@
|
|||
status = "disabled";
|
||||
|
||||
input-gpios
|
||||
= <&arduino_header 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
;
|
||||
= <&arduino_header 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 11 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
;
|
||||
|
||||
};
|
||||
|
||||
|
@ -157,23 +157,26 @@
|
|||
toggle-mode;
|
||||
|
||||
input-gpios
|
||||
= <&arduino_header 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
;
|
||||
= <&arduino_header 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&arduino_header 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
;
|
||||
};
|
||||
|
||||
encoder: encoder {
|
||||
label = "ENCODER";
|
||||
resolution = <4>;
|
||||
steps = <80>;
|
||||
compatible = "alps,ec11";
|
||||
a-gpios = <&arduino_header 14 GPIO_PULL_UP>;
|
||||
b-gpios = <&arduino_header 15 GPIO_PULL_UP>;
|
||||
a-gpios = <&arduino_header 15 GPIO_PULL_UP>;
|
||||
b-gpios = <&arduino_header 14 GPIO_PULL_UP>;
|
||||
};
|
||||
|
||||
sensors {
|
||||
compatible = "zmk,keymap-sensors";
|
||||
sensors = <&encoder>;
|
||||
triggers-per-rotation = <20>;
|
||||
left {
|
||||
triggers-per-rotation = <20>;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
menuconfig EC11
|
||||
bool "EC11 Incremental Encoder Sensor"
|
||||
default y
|
||||
depends on DT_HAS_ALPS_EC11_ENABLED
|
||||
depends on GPIO
|
||||
help
|
||||
Enable driver for EC11 incremental encoder sensors.
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "ec11.h"
|
||||
|
||||
#define FULL_ROTATION 360
|
||||
|
||||
LOG_MODULE_REGISTER(EC11, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static int ec11_get_ab_state(const struct device *dev) {
|
||||
|
@ -59,9 +61,14 @@ static int ec11_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
|||
drv_data->pulses += delta;
|
||||
drv_data->ab_state = val;
|
||||
|
||||
drv_data->ticks = drv_data->pulses / drv_cfg->resolution;
|
||||
drv_data->delta = delta;
|
||||
drv_data->pulses %= drv_cfg->resolution;
|
||||
// TODO: Temporary code for backwards compatibility to support
|
||||
// the sensor channel rotation reporting *ticks* instead of delta of degrees.
|
||||
// REMOVE ME
|
||||
if (drv_cfg->steps == 0) {
|
||||
drv_data->ticks = drv_data->pulses / drv_cfg->resolution;
|
||||
drv_data->delta = delta;
|
||||
drv_data->pulses %= drv_cfg->resolution;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,13 +76,26 @@ static int ec11_sample_fetch(const struct device *dev, enum sensor_channel chan)
|
|||
static int ec11_channel_get(const struct device *dev, enum sensor_channel chan,
|
||||
struct sensor_value *val) {
|
||||
struct ec11_data *drv_data = dev->data;
|
||||
const struct ec11_config *drv_cfg = dev->config;
|
||||
int32_t pulses = drv_data->pulses;
|
||||
|
||||
if (chan != SENSOR_CHAN_ROTATION) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
val->val1 = drv_data->ticks;
|
||||
val->val2 = drv_data->delta;
|
||||
drv_data->pulses = 0;
|
||||
|
||||
if (drv_cfg->steps > 0) {
|
||||
val->val1 = (pulses * FULL_ROTATION) / drv_cfg->steps;
|
||||
val->val2 = (pulses * FULL_ROTATION) % drv_cfg->steps;
|
||||
if (val->val2 != 0) {
|
||||
val->val2 *= 1000000;
|
||||
val->val2 /= drv_cfg->steps;
|
||||
}
|
||||
} else {
|
||||
val->val1 = drv_data->ticks;
|
||||
val->val2 = drv_data->delta;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,7 +152,8 @@ int ec11_init(const struct device *dev) {
|
|||
const struct ec11_config ec11_cfg_##n = { \
|
||||
.a = GPIO_DT_SPEC_INST_GET(n, a_gpios), \
|
||||
.b = GPIO_DT_SPEC_INST_GET(n, b_gpios), \
|
||||
COND_CODE_0(DT_INST_NODE_HAS_PROP(n, resolution), (1), (DT_INST_PROP(n, resolution))), \
|
||||
.resolution = DT_INST_PROP_OR(n, resolution, 1), \
|
||||
.steps = DT_INST_PROP_OR(n, steps, 0), \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(n, ec11_init, NULL, &ec11_data_##n, &ec11_cfg_##n, POST_KERNEL, \
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &ec11_driver_api);
|
||||
|
|
|
@ -14,6 +14,7 @@ struct ec11_config {
|
|||
const struct gpio_dt_spec a;
|
||||
const struct gpio_dt_spec b;
|
||||
|
||||
const uint16_t steps;
|
||||
const uint8_t resolution;
|
||||
};
|
||||
|
||||
|
|
|
@ -18,4 +18,9 @@ properties:
|
|||
resolution:
|
||||
type: int
|
||||
description: Number of pulses per tick
|
||||
deprecated: true
|
||||
required: false
|
||||
steps:
|
||||
type: int
|
||||
description: Number of pulses in one full rotation
|
||||
required: false
|
||||
|
|
|
@ -4,16 +4,33 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define MACRO_PLACEHOLDER 0
|
||||
#define ZMK_MACRO_STRINGIFY(x) #x
|
||||
#define ZMK_MACRO(name,...) \
|
||||
name: name { \
|
||||
label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
|
||||
compatible = "zmk,behavior-macro"; \
|
||||
#binding-cells = <0>; \
|
||||
__VA_ARGS__ \
|
||||
};
|
||||
name: name { \
|
||||
label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
|
||||
compatible = "zmk,behavior-macro"; \
|
||||
#binding-cells = <0>; \
|
||||
__VA_ARGS__ \
|
||||
};
|
||||
|
||||
/ {
|
||||
#define ZMK_MACRO1(name,...) \
|
||||
name: name { \
|
||||
label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
|
||||
compatible = "zmk,behavior-macro-one-param"; \
|
||||
#binding-cells = <1>; \
|
||||
__VA_ARGS__ \
|
||||
};
|
||||
|
||||
#define ZMK_MACRO2(name,...) \
|
||||
name: name { \
|
||||
label = ZMK_MACRO_STRINGIFY(ZM_ ## name); \
|
||||
compatible = "zmk,behavior-macro-two-param"; \
|
||||
#binding-cells = <2>; \
|
||||
__VA_ARGS__ \
|
||||
};
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
macro_tap: macro_control_mode_tap {
|
||||
compatible = "zmk,macro-control-mode-tap";
|
||||
|
@ -50,5 +67,29 @@
|
|||
label = "MAC_WAIT_REL";
|
||||
#binding-cells = <0>;
|
||||
};
|
||||
|
||||
macro_param_1to1: macro_param_1to1 {
|
||||
compatible = "zmk,macro-param-1to1";
|
||||
label = "MAC_PARAM_1TO1";
|
||||
#binding-cells = <0>;
|
||||
};
|
||||
|
||||
macro_param_1to2: macro_param_1to2 {
|
||||
compatible = "zmk,macro-param-1to2";
|
||||
label = "MAC_PARAM_1TO2";
|
||||
#binding-cells = <0>;
|
||||
};
|
||||
|
||||
macro_param_2to1: macro_param_2to1 {
|
||||
compatible = "zmk,macro-param-2to1";
|
||||
label = "MAC_PARAM_2TO1";
|
||||
#binding-cells = <0>;
|
||||
};
|
||||
|
||||
macro_param_2to2: macro_param_2to2 {
|
||||
compatible = "zmk,macro-param-2to2";
|
||||
label = "MAC_PARAM_2TO2";
|
||||
#binding-cells = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
13
app/dts/bindings/behaviors/macro_base.yaml
Normal file
13
app/dts/bindings/behaviors/macro_base.yaml
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
properties:
|
||||
bindings:
|
||||
type: phandle-array
|
||||
required: true
|
||||
wait-ms:
|
||||
type: int
|
||||
description: The default time to wait (in milliseconds) before triggering the next behavior in the macro bindings list.
|
||||
tap-ms:
|
||||
type: int
|
||||
description: The default time to wait (in milliseconds) between the press and release events on a tapped macro behavior binding
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Macro Behavior
|
||||
|
||||
compatible: "zmk,behavior-macro-one-param"
|
||||
|
||||
include: [one_param.yaml, macro_base.yaml]
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Macro Behavior
|
||||
|
||||
compatible: "zmk,behavior-macro-two-param"
|
||||
|
||||
include: [two_param.yaml, macro_base.yaml]
|
|
@ -5,15 +5,4 @@ description: Macro Behavior
|
|||
|
||||
compatible: "zmk,behavior-macro"
|
||||
|
||||
include: zero_param.yaml
|
||||
|
||||
properties:
|
||||
bindings:
|
||||
type: phandle-array
|
||||
required: true
|
||||
wait-ms:
|
||||
type: int
|
||||
description: The default time to wait (in milliseconds) before triggering the next behavior in the macro bindings list.
|
||||
tap-ms:
|
||||
type: int
|
||||
description: The default time to wait (in milliseconds) between the press and release events on a tapped macro behavior binding
|
||||
include: [zero_param.yaml, macro_base.yaml]
|
||||
|
|
8
app/dts/bindings/macros/zmk,macro-param-1to1.yaml
Normal file
8
app/dts/bindings/macros/zmk,macro-param-1to1.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Macro Parameter One Substituted Into Next Binding's First Parameter
|
||||
|
||||
compatible: "zmk,macro-param-1to1"
|
||||
|
||||
include: zero_param.yaml
|
8
app/dts/bindings/macros/zmk,macro-param-1to2.yaml
Normal file
8
app/dts/bindings/macros/zmk,macro-param-1to2.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Macro Parameter One Substituted Into Next Binding's Second Parameter
|
||||
|
||||
compatible: "zmk,macro-param-1to2"
|
||||
|
||||
include: zero_param.yaml
|
8
app/dts/bindings/macros/zmk,macro-param-2to1.yaml
Normal file
8
app/dts/bindings/macros/zmk,macro-param-2to1.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Macro Parameter Two Substituted Into Next Binding's First Parameter
|
||||
|
||||
compatible: "zmk,macro-param-2to1"
|
||||
|
||||
include: zero_param.yaml
|
8
app/dts/bindings/macros/zmk,macro-param-2to2.yaml
Normal file
8
app/dts/bindings/macros/zmk,macro-param-2to2.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Macro Parameter Two Substituted Into Next Binding's Second Parameter
|
||||
|
||||
compatible: "zmk,macro-param-2to2"
|
||||
|
||||
include: zero_param.yaml
|
|
@ -9,4 +9,14 @@ compatible: "zmk,keymap-sensors"
|
|||
properties:
|
||||
sensors:
|
||||
type: phandles
|
||||
required: true
|
||||
required: false
|
||||
triggers-per-rotation:
|
||||
type: int
|
||||
required: false
|
||||
|
||||
child-binding:
|
||||
description: Per-sensor configuration settings
|
||||
properties:
|
||||
triggers-per-rotation:
|
||||
type: int
|
||||
required: false
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <string.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zmk/keys.h>
|
||||
#include <zmk/sensors.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
/**
|
||||
|
@ -22,11 +23,20 @@
|
|||
* (Internal use only.)
|
||||
*/
|
||||
|
||||
enum behavior_sensor_binding_process_mode {
|
||||
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER,
|
||||
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD,
|
||||
};
|
||||
|
||||
typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event);
|
||||
typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor,
|
||||
struct zmk_behavior_binding_event event);
|
||||
typedef int (*behavior_sensor_keymap_binding_process_callback_t)(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode);
|
||||
typedef int (*behavior_sensor_keymap_binding_accept_data_callback_t)(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data channel_data[channel_data_size]);
|
||||
|
||||
enum behavior_locality {
|
||||
BEHAVIOR_LOCALITY_CENTRAL,
|
||||
|
@ -39,7 +49,8 @@ __subsystem struct behavior_driver_api {
|
|||
behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params;
|
||||
behavior_keymap_binding_callback_t binding_pressed;
|
||||
behavior_keymap_binding_callback_t binding_released;
|
||||
behavior_sensor_keymap_binding_callback_t sensor_binding_triggered;
|
||||
behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data;
|
||||
behavior_sensor_keymap_binding_process_callback_t sensor_binding_process;
|
||||
};
|
||||
/**
|
||||
* @endcond
|
||||
|
@ -149,7 +160,7 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the a sensor keymap binding being triggered
|
||||
* @brief Handle the a sensor keymap binding processing any incoming data from the sensor
|
||||
* @param binding Sensor keymap binding which was triggered.
|
||||
* @param sensor Pointer to the sensor device structure for the sensor driver instance.
|
||||
* @param virtual_key_position ZMK_KEYMAP_LEN + sensor number
|
||||
|
@ -158,14 +169,15 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi
|
|||
* @retval 0 If successful.
|
||||
* @retval Negative errno code if failure.
|
||||
*/
|
||||
__syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor,
|
||||
struct zmk_behavior_binding_event event);
|
||||
__syscall int behavior_sensor_keymap_binding_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data);
|
||||
|
||||
static inline int
|
||||
z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
static inline int z_impl_behavior_sensor_keymap_binding_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data) {
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
|
||||
if (dev == NULL) {
|
||||
|
@ -174,11 +186,47 @@ z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *bin
|
|||
|
||||
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
|
||||
|
||||
if (api->sensor_binding_triggered == NULL) {
|
||||
if (api->sensor_binding_accept_data == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return api->sensor_binding_triggered(binding, sensor, event);
|
||||
return api->sensor_binding_accept_data(binding, event, sensor_config, channel_data_size,
|
||||
channel_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle the keymap sensor binding being triggered after updating any local data
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param param1 User parameter specified at time of behavior binding.
|
||||
* @param param2 User parameter specified at time of behavior binding.
|
||||
*
|
||||
* @retval 0 If successful.
|
||||
* @retval Negative errno code if failure.
|
||||
*/
|
||||
// clang-format off
|
||||
__syscall int behavior_sensor_keymap_binding_process(
|
||||
struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode);
|
||||
// clang-format on
|
||||
|
||||
static inline int
|
||||
z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode) {
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
|
||||
if (dev == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api;
|
||||
|
||||
if (api->sensor_binding_process == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return api->sensor_binding_process(binding, event, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL))
|
||||
|
||||
#if ZMK_BLE_IS_CENTRAL
|
||||
#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
|
||||
#define ZMK_SPLIT_BLE_PERIPHERAL_COUNT 1
|
||||
#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS)
|
||||
#define ZMK_SPLIT_BLE_PERIPHERAL_COUNT CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS
|
||||
#else
|
||||
#define ZMK_BLE_PROFILE_COUNT CONFIG_BT_MAX_PAIRED
|
||||
#endif
|
||||
|
@ -34,5 +34,5 @@ char *zmk_ble_active_profile_name();
|
|||
int zmk_ble_unpair_all();
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr);
|
||||
int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr);
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||
|
|
|
@ -6,13 +6,22 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/sensors.h>
|
||||
|
||||
// TODO: Move to Kconfig when we need more than one channel
|
||||
#define ZMK_SENSOR_EVENT_MAX_CHANNELS 1
|
||||
|
||||
struct zmk_sensor_event {
|
||||
uint8_t sensor_number;
|
||||
const struct device *sensor;
|
||||
size_t channel_data_size;
|
||||
struct zmk_sensor_channel_data channel_data[ZMK_SENSOR_EVENT_MAX_CHANNELS];
|
||||
|
||||
int64_t timestamp;
|
||||
|
||||
uint8_t sensor_index;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_sensor_event);
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
|
||||
#define ZMK_KEYMAP_SENSORS_NODE DT_INST(0, zmk_keymap_sensors)
|
||||
#define ZMK_KEYMAP_HAS_SENSORS DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_NODE, okay)
|
||||
#define ZMK_KEYMAP_SENSORS_BY_IDX(idx) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_SENSORS_NODE, sensors, idx)
|
||||
|
@ -15,3 +17,14 @@
|
|||
#else
|
||||
#define ZMK_KEYMAP_SENSORS_LEN 0
|
||||
#endif
|
||||
|
||||
const struct zmk_sensor_config *zmk_sensors_get_config_at_index(uint8_t sensor_index);
|
||||
|
||||
struct zmk_sensor_config {
|
||||
uint16_t triggers_per_rotation;
|
||||
};
|
||||
|
||||
struct zmk_sensor_channel_data {
|
||||
enum sensor_channel channel;
|
||||
struct sensor_value value;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
*/
|
||||
#define ZMK_VIRTUAL_KEY_POSITION_SENSOR(index) (ZMK_KEYMAP_LEN + (index))
|
||||
|
||||
/**
|
||||
* Gets the sensor number from the virtual key position.
|
||||
*/
|
||||
#define ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(vkp) ((vkp)-ZMK_KEYMAP_LEN)
|
||||
|
||||
/**
|
||||
* Gets the virtual key position to use for the combo with the given index.
|
||||
*/
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_macro
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -15,20 +13,22 @@
|
|||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
enum behavior_macro_mode {
|
||||
MACRO_MODE_TAP,
|
||||
MACRO_MODE_PRESS,
|
||||
MACRO_MODE_RELEASE,
|
||||
};
|
||||
|
||||
enum param_source { PARAM_SOURCE_BINDING, PARAM_SOURCE_MACRO_1ST, PARAM_SOURCE_MACRO_2ND };
|
||||
|
||||
struct behavior_macro_trigger_state {
|
||||
uint32_t wait_ms;
|
||||
uint32_t tap_ms;
|
||||
enum behavior_macro_mode mode;
|
||||
uint16_t start_index;
|
||||
uint16_t count;
|
||||
enum param_source param1_source;
|
||||
enum param_source param2_source;
|
||||
};
|
||||
|
||||
struct behavior_macro_state {
|
||||
|
@ -52,6 +52,11 @@ struct behavior_macro_config {
|
|||
#define WAIT_TIME DT_PROP(DT_INST(0, zmk_macro_control_wait_time), label)
|
||||
#define WAIT_REL DT_PROP(DT_INST(0, zmk_macro_pause_for_release), label)
|
||||
|
||||
#define P1TO1 DT_PROP(DT_INST(0, zmk_macro_param_1to1), label)
|
||||
#define P1TO2 DT_PROP(DT_INST(0, zmk_macro_param_1to2), label)
|
||||
#define P2TO1 DT_PROP(DT_INST(0, zmk_macro_param_2to1), label)
|
||||
#define P2TO2 DT_PROP(DT_INST(0, zmk_macro_param_2to2), label)
|
||||
|
||||
#define ZM_IS_NODE_MATCH(a, b) (strcmp(a, b) == 0)
|
||||
#define IS_TAP_MODE(dev) ZM_IS_NODE_MATCH(dev, TAP_MODE)
|
||||
#define IS_PRESS_MODE(dev) ZM_IS_NODE_MATCH(dev, PRESS_MODE)
|
||||
|
@ -61,6 +66,11 @@ struct behavior_macro_config {
|
|||
#define IS_WAIT_TIME(dev) ZM_IS_NODE_MATCH(dev, WAIT_TIME)
|
||||
#define IS_PAUSE(dev) ZM_IS_NODE_MATCH(dev, WAIT_REL)
|
||||
|
||||
#define IS_P1TO1(dev) ZM_IS_NODE_MATCH(dev, P1TO1)
|
||||
#define IS_P1TO2(dev) ZM_IS_NODE_MATCH(dev, P1TO2)
|
||||
#define IS_P2TO1(dev) ZM_IS_NODE_MATCH(dev, P2TO1)
|
||||
#define IS_P2TO2(dev) ZM_IS_NODE_MATCH(dev, P2TO2)
|
||||
|
||||
static bool handle_control_binding(struct behavior_macro_trigger_state *state,
|
||||
const struct zmk_behavior_binding *binding) {
|
||||
if (IS_TAP_MODE(binding->behavior_dev)) {
|
||||
|
@ -78,6 +88,18 @@ static bool handle_control_binding(struct behavior_macro_trigger_state *state,
|
|||
} else if (IS_WAIT_TIME(binding->behavior_dev)) {
|
||||
state->wait_ms = binding->param1;
|
||||
LOG_DBG("macro wait time set: %d", state->wait_ms);
|
||||
} else if (IS_P1TO1(binding->behavior_dev)) {
|
||||
state->param1_source = PARAM_SOURCE_MACRO_1ST;
|
||||
LOG_DBG("macro param: 1to1");
|
||||
} else if (IS_P1TO2(binding->behavior_dev)) {
|
||||
state->param2_source = PARAM_SOURCE_MACRO_1ST;
|
||||
LOG_DBG("macro param: 1to2");
|
||||
} else if (IS_P2TO1(binding->behavior_dev)) {
|
||||
state->param1_source = PARAM_SOURCE_MACRO_2ND;
|
||||
LOG_DBG("macro param: 2to1");
|
||||
} else if (IS_P2TO2(binding->behavior_dev)) {
|
||||
state->param2_source = PARAM_SOURCE_MACRO_2ND;
|
||||
LOG_DBG("macro param: 2to2");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -110,21 +132,47 @@ static int behavior_macro_init(const struct device *dev) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
static uint32_t select_param(enum param_source param_source, uint32_t source_binding,
|
||||
const struct zmk_behavior_binding *macro_binding) {
|
||||
switch (param_source) {
|
||||
case PARAM_SOURCE_MACRO_1ST:
|
||||
return macro_binding->param1;
|
||||
case PARAM_SOURCE_MACRO_2ND:
|
||||
return macro_binding->param2;
|
||||
default:
|
||||
return source_binding;
|
||||
}
|
||||
};
|
||||
|
||||
static void replace_params(struct behavior_macro_trigger_state *state,
|
||||
struct zmk_behavior_binding *binding,
|
||||
const struct zmk_behavior_binding *macro_binding) {
|
||||
binding->param1 = select_param(state->param1_source, binding->param1, macro_binding);
|
||||
binding->param2 = select_param(state->param2_source, binding->param2, macro_binding);
|
||||
|
||||
state->param1_source = PARAM_SOURCE_BINDING;
|
||||
state->param2_source = PARAM_SOURCE_BINDING;
|
||||
}
|
||||
|
||||
static void queue_macro(uint32_t position, const struct zmk_behavior_binding bindings[],
|
||||
struct behavior_macro_trigger_state state) {
|
||||
struct behavior_macro_trigger_state state,
|
||||
const struct zmk_behavior_binding *macro_binding) {
|
||||
LOG_DBG("Iterating macro bindings - starting: %d, count: %d", state.start_index, state.count);
|
||||
for (int i = state.start_index; i < state.start_index + state.count; i++) {
|
||||
if (!handle_control_binding(&state, &bindings[i])) {
|
||||
struct zmk_behavior_binding binding = bindings[i];
|
||||
replace_params(&state, &binding, macro_binding);
|
||||
|
||||
switch (state.mode) {
|
||||
case MACRO_MODE_TAP:
|
||||
zmk_behavior_queue_add(position, bindings[i], true, state.tap_ms);
|
||||
zmk_behavior_queue_add(position, bindings[i], false, state.wait_ms);
|
||||
zmk_behavior_queue_add(position, binding, true, state.tap_ms);
|
||||
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
|
||||
break;
|
||||
case MACRO_MODE_PRESS:
|
||||
zmk_behavior_queue_add(position, bindings[i], true, state.wait_ms);
|
||||
zmk_behavior_queue_add(position, binding, true, state.wait_ms);
|
||||
break;
|
||||
case MACRO_MODE_RELEASE:
|
||||
zmk_behavior_queue_add(position, bindings[i], false, state.wait_ms);
|
||||
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unknown macro mode: %d", state.mode);
|
||||
|
@ -145,7 +193,7 @@ static int on_macro_binding_pressed(struct zmk_behavior_binding *binding,
|
|||
.start_index = 0,
|
||||
.count = state->press_bindings_count};
|
||||
|
||||
queue_macro(event.position, cfg->bindings, trigger_state);
|
||||
queue_macro(event.position, cfg->bindings, trigger_state, binding);
|
||||
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
}
|
||||
|
@ -156,7 +204,7 @@ static int on_macro_binding_released(struct zmk_behavior_binding *binding,
|
|||
const struct behavior_macro_config *cfg = dev->config;
|
||||
struct behavior_macro_state *state = dev->data;
|
||||
|
||||
queue_macro(event.position, cfg->bindings, state->release_state);
|
||||
queue_macro(event.position, cfg->bindings, state->release_state, binding);
|
||||
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
}
|
||||
|
@ -166,22 +214,20 @@ static const struct behavior_driver_api behavior_macro_driver_api = {
|
|||
.binding_released = on_macro_binding_released,
|
||||
};
|
||||
|
||||
#define BINDING_WITH_COMMA(idx, drv_inst) ZMK_KEYMAP_EXTRACT_BINDING(idx, DT_DRV_INST(drv_inst))
|
||||
|
||||
#define TRANSFORMED_BEHAVIORS(n) \
|
||||
{LISTIFY(DT_PROP_LEN(DT_DRV_INST(n), bindings), BINDING_WITH_COMMA, (, ), n)},
|
||||
{LISTIFY(DT_PROP_LEN(n, bindings), ZMK_KEYMAP_EXTRACT_BINDING, (, ), n)},
|
||||
|
||||
#define MACRO_INST(n) \
|
||||
static struct behavior_macro_state behavior_macro_state_##n = {}; \
|
||||
static struct behavior_macro_config behavior_macro_config_##n = { \
|
||||
.default_wait_ms = DT_INST_PROP_OR(n, wait_ms, CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS), \
|
||||
.default_tap_ms = DT_INST_PROP_OR(n, tap_ms, CONFIG_ZMK_MACRO_DEFAULT_TAP_MS), \
|
||||
.count = DT_INST_PROP_LEN(n, bindings), \
|
||||
.bindings = TRANSFORMED_BEHAVIORS(n)}; \
|
||||
DEVICE_DT_INST_DEFINE(n, behavior_macro_init, NULL, &behavior_macro_state_##n, \
|
||||
&behavior_macro_config_##n, APPLICATION, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api);
|
||||
#define MACRO_INST(inst) \
|
||||
static struct behavior_macro_state behavior_macro_state_##inst = {}; \
|
||||
static struct behavior_macro_config behavior_macro_config_##inst = { \
|
||||
.default_wait_ms = DT_PROP_OR(inst, wait_ms, CONFIG_ZMK_MACRO_DEFAULT_WAIT_MS), \
|
||||
.default_tap_ms = DT_PROP_OR(inst, tap_ms, CONFIG_ZMK_MACRO_DEFAULT_TAP_MS), \
|
||||
.count = DT_PROP_LEN(inst, bindings), \
|
||||
.bindings = TRANSFORMED_BEHAVIORS(inst)}; \
|
||||
DEVICE_DT_DEFINE(inst, behavior_macro_init, NULL, &behavior_macro_state_##inst, \
|
||||
&behavior_macro_config_##inst, APPLICATION, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_macro_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MACRO_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
||||
DT_FOREACH_STATUS_OKAY(zmk_behavior_macro, MACRO_INST)
|
||||
DT_FOREACH_STATUS_OKAY(zmk_behavior_macro_one_param, MACRO_INST)
|
||||
DT_FOREACH_STATUS_OKAY(zmk_behavior_macro_two_param, MACRO_INST)
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
#include "behavior_sensor_rotate_common.h"
|
||||
|
||||
static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
||||
.sensor_binding_triggered = zmk_behavior_sensor_rotate_common_trigger};
|
||||
.sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data,
|
||||
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
||||
|
||||
static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
|
||||
|
||||
|
@ -33,8 +34,10 @@ static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
|
|||
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
|
||||
.override_params = false, \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE( \
|
||||
n, behavior_sensor_rotate_init, NULL, NULL, &behavior_sensor_rotate_config_##n, \
|
||||
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_driver_api);
|
||||
static struct behavior_sensor_rotate_data behavior_sensor_rotate_data_##n = {}; \
|
||||
DEVICE_DT_INST_DEFINE(n, behavior_sensor_rotate_init, NULL, &behavior_sensor_rotate_data_##n, \
|
||||
&behavior_sensor_rotate_config_##n, APPLICATION, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_sensor_rotate_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
|
||||
|
|
|
@ -5,48 +5,93 @@
|
|||
#include <zephyr/kernel.h>
|
||||
|
||||
#include <zmk/behavior_queue.h>
|
||||
#include <zmk/virtual_key_position.h>
|
||||
|
||||
#include "behavior_sensor_rotate_common.h"
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_trigger(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
int zmk_behavior_sensor_rotate_common_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data) {
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct behavior_sensor_rotate_config *cfg = dev->config;
|
||||
struct behavior_sensor_rotate_data *data = dev->data;
|
||||
|
||||
struct sensor_value value;
|
||||
const struct sensor_value value = channel_data[0].value;
|
||||
int triggers;
|
||||
int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
||||
|
||||
const int err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
|
||||
// Some funky special casing for "old encoder behavior" where ticks where reported in val2 only,
|
||||
// instead of rotational degrees in val1.
|
||||
// REMOVE ME: Remove after a grace period of old ec11 sensor behavior
|
||||
if (value.val1 == 0) {
|
||||
triggers = value.val2;
|
||||
} else {
|
||||
struct sensor_value remainder = data->remainder[sensor_index];
|
||||
|
||||
if (err < 0) {
|
||||
LOG_WRN("Failed to get sensor rotation value: %d", err);
|
||||
return err;
|
||||
remainder.val1 += value.val1;
|
||||
remainder.val2 += value.val2;
|
||||
|
||||
if (remainder.val2 >= 1000000 || remainder.val2 <= 1000000) {
|
||||
remainder.val1 += remainder.val2 / 1000000;
|
||||
remainder.val2 %= 1000000;
|
||||
}
|
||||
|
||||
int trigger_degrees = 360 / sensor_config->triggers_per_rotation;
|
||||
triggers = remainder.val1 / trigger_degrees;
|
||||
remainder.val1 %= trigger_degrees;
|
||||
|
||||
data->remainder[sensor_index] = remainder;
|
||||
}
|
||||
|
||||
LOG_DBG(
|
||||
"val1: %d, val2: %d, remainder: %d/%d triggers: %d inc keycode 0x%02X dec keycode 0x%02X",
|
||||
value.val1, value.val2, data->remainder[sensor_index].val1,
|
||||
data->remainder[sensor_index].val2, triggers, binding->param1, binding->param2);
|
||||
|
||||
data->triggers[sensor_index] = triggers;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode) {
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct behavior_sensor_rotate_config *cfg = dev->config;
|
||||
struct behavior_sensor_rotate_data *data = dev->data;
|
||||
|
||||
const int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
||||
|
||||
if (mode != BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER) {
|
||||
data->triggers[sensor_index] = 0;
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
}
|
||||
|
||||
int triggers = data->triggers[sensor_index];
|
||||
|
||||
struct zmk_behavior_binding triggered_binding;
|
||||
switch (value.val1) {
|
||||
case 1:
|
||||
if (triggers > 0) {
|
||||
triggered_binding = cfg->cw_binding;
|
||||
if (cfg->override_params) {
|
||||
triggered_binding.param1 = binding->param1;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
} else if (triggers < 0) {
|
||||
triggers = -triggers;
|
||||
triggered_binding = cfg->ccw_binding;
|
||||
if (cfg->override_params) {
|
||||
triggered_binding.param1 = binding->param2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
} else {
|
||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
||||
}
|
||||
|
||||
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
|
||||
|
||||
zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms);
|
||||
zmk_behavior_queue_add(event.position, triggered_binding, false, 0);
|
||||
for (int i = 0; i < triggers; i++) {
|
||||
zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms);
|
||||
zmk_behavior_queue_add(event.position, triggered_binding, false, 0);
|
||||
}
|
||||
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/sensors.h>
|
||||
|
||||
struct behavior_sensor_rotate_config {
|
||||
struct zmk_behavior_binding cw_binding;
|
||||
|
@ -8,6 +15,15 @@ struct behavior_sensor_rotate_config {
|
|||
bool override_params;
|
||||
};
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_trigger(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor,
|
||||
struct zmk_behavior_binding_event event);
|
||||
struct behavior_sensor_rotate_data {
|
||||
struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN];
|
||||
int triggers[ZMK_KEYMAP_SENSORS_LEN];
|
||||
};
|
||||
|
||||
int zmk_behavior_sensor_rotate_common_accept_data(
|
||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
||||
const struct zmk_sensor_config *sensor_config, size_t channel_data_size,
|
||||
const struct zmk_sensor_channel_data *channel_data);
|
||||
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event,
|
||||
enum behavior_sensor_binding_process_mode mode);
|
|
@ -13,7 +13,8 @@
|
|||
#include "behavior_sensor_rotate_common.h"
|
||||
|
||||
static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = {
|
||||
.sensor_binding_triggered = zmk_behavior_sensor_rotate_common_trigger};
|
||||
.sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data,
|
||||
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
||||
|
||||
static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0; };
|
||||
|
||||
|
@ -24,8 +25,10 @@ static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0;
|
|||
.tap_ms = DT_INST_PROP(n, tap_ms), \
|
||||
.override_params = true, \
|
||||
}; \
|
||||
static struct behavior_sensor_rotate_data behavior_sensor_rotate_var_data_##n = {}; \
|
||||
DEVICE_DT_INST_DEFINE( \
|
||||
n, behavior_sensor_rotate_var_init, NULL, NULL, &behavior_sensor_rotate_var_config_##n, \
|
||||
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_var_driver_api);
|
||||
n, behavior_sensor_rotate_var_init, NULL, &behavior_sensor_rotate_var_data_##n, \
|
||||
&behavior_sensor_rotate_var_config_##n, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||
&behavior_sensor_rotate_var_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)
|
||||
|
|
101
app/src/ble.c
101
app/src/ble.c
|
@ -13,6 +13,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/sys/ring_buffer.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
|
@ -42,17 +43,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#define PASSKEY_DIGITS 6
|
||||
|
||||
static struct bt_conn *auth_passkey_entry_conn;
|
||||
static uint8_t passkey_entries[PASSKEY_DIGITS] = {};
|
||||
static uint8_t passkey_digit = 0;
|
||||
RING_BUF_DECLARE(passkey_entries, PASSKEY_DIGITS);
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
|
||||
#else
|
||||
#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
|
||||
#endif
|
||||
|
||||
enum advertising_type {
|
||||
ZMK_ADV_NONE,
|
||||
ZMK_ADV_DIR,
|
||||
|
@ -84,7 +78,7 @@ static const struct bt_data zmk_ble_ad[] = {
|
|||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
|
||||
static bt_addr_le_t peripheral_addr;
|
||||
static bt_addr_le_t peripheral_addrs[ZMK_SPLIT_BLE_PERIPHERAL_COUNT];
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||
|
||||
|
@ -283,9 +277,34 @@ char *zmk_ble_active_profile_name() { return profiles[active_profile].name; }
|
|||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
|
||||
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) {
|
||||
memcpy(&peripheral_addr, addr, sizeof(bt_addr_le_t));
|
||||
settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t));
|
||||
int zmk_ble_put_peripheral_addr(const bt_addr_le_t *addr) {
|
||||
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
|
||||
// If the address is recognized and already stored in settings, return
|
||||
// index and no additional action is necessary.
|
||||
if (!bt_addr_le_cmp(&peripheral_addrs[i], addr)) {
|
||||
return i;
|
||||
}
|
||||
|
||||
// If the peripheral address slot is open, store new peripheral in the
|
||||
// slot and return index. This compares against BT_ADDR_LE_ANY as that
|
||||
// is the zero value.
|
||||
if (!bt_addr_le_cmp(&peripheral_addrs[i], BT_ADDR_LE_ANY)) {
|
||||
char addr_str[BT_ADDR_LE_STR_LEN];
|
||||
bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
|
||||
LOG_DBG("Storing peripheral %s in slot %d", addr_str, i);
|
||||
bt_addr_le_copy(&peripheral_addrs[i], addr);
|
||||
|
||||
char setting_name[32];
|
||||
sprintf(setting_name, "ble/peripheral_addresses/%d", i);
|
||||
settings_save_one(setting_name, addr, sizeof(bt_addr_le_t));
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// The peripheral does not match a known peripheral and there is no
|
||||
// available slot.
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||
|
@ -340,15 +359,20 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c
|
|||
}
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
else if (settings_name_steq(name, "peripheral_address", &next) && !next) {
|
||||
else if (settings_name_steq(name, "peripheral_addresses", &next) && next) {
|
||||
if (len != sizeof(bt_addr_le_t)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int err = read_cb(cb_arg, &peripheral_addr, sizeof(bt_addr_le_t));
|
||||
if (err <= 0) {
|
||||
LOG_ERR("Failed to handle peripheral address from settings (err %d)", err);
|
||||
return err;
|
||||
int i = atoi(next);
|
||||
if (i < 0 || i >= ZMK_SPLIT_BLE_PERIPHERAL_COUNT) {
|
||||
LOG_ERR("Failed to store peripheral address in memory");
|
||||
} else {
|
||||
int err = read_cb(cb_arg, &peripheral_addrs[i], sizeof(bt_addr_le_t));
|
||||
if (err <= 0) {
|
||||
LOG_ERR("Failed to handle peripheral address from settings (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -469,7 +493,7 @@ static void auth_passkey_entry(struct bt_conn *conn) {
|
|||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
LOG_DBG("Passkey entry requested for %s", addr);
|
||||
passkey_digit = 0;
|
||||
ring_buf_reset(&passkey_entries);
|
||||
auth_passkey_entry_conn = bt_conn_ref(conn);
|
||||
}
|
||||
|
||||
|
@ -486,7 +510,7 @@ static void auth_cancel(struct bt_conn *conn) {
|
|||
auth_passkey_entry_conn = NULL;
|
||||
}
|
||||
|
||||
passkey_digit = 0;
|
||||
ring_buf_reset(&passkey_entries);
|
||||
#endif
|
||||
|
||||
LOG_DBG("Pairing cancelled: %s", addr);
|
||||
|
@ -605,7 +629,7 @@ static int zmk_ble_init(const struct device *_arg) {
|
|||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||
|
||||
static bool zmk_ble_numeric_usage_to_value(const zmk_key_t key, const zmk_key_t one,
|
||||
const zmk_key_t zero, uint32_t *value) {
|
||||
const zmk_key_t zero, uint8_t *value) {
|
||||
if (key < one || key > zero) {
|
||||
return false;
|
||||
}
|
||||
|
@ -634,7 +658,23 @@ static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) {
|
|||
return ZMK_EV_EVENT_HANDLED;
|
||||
}
|
||||
|
||||
uint32_t val;
|
||||
if (key == HID_USAGE_KEY_KEYBOARD_RETURN || key == HID_USAGE_KEY_KEYBOARD_RETURN_ENTER) {
|
||||
uint8_t digits[PASSKEY_DIGITS];
|
||||
uint32_t count = ring_buf_get(&passkey_entries, digits, PASSKEY_DIGITS);
|
||||
|
||||
uint32_t passkey = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
passkey = (passkey * 10) + digits[i];
|
||||
}
|
||||
|
||||
LOG_DBG("Final passkey: %d", passkey);
|
||||
bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey);
|
||||
bt_conn_unref(auth_passkey_entry_conn);
|
||||
auth_passkey_entry_conn = NULL;
|
||||
return ZMK_EV_EVENT_HANDLED;
|
||||
}
|
||||
|
||||
uint8_t val;
|
||||
if (!(zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYBOARD_1_AND_EXCLAMATION,
|
||||
HID_USAGE_KEY_KEYBOARD_0_AND_RIGHT_PARENTHESIS, &val) ||
|
||||
zmk_ble_numeric_usage_to_value(key, HID_USAGE_KEY_KEYPAD_1_AND_END,
|
||||
|
@ -643,20 +683,13 @@ static int zmk_ble_handle_key_user(struct zmk_keycode_state_changed *event) {
|
|||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
passkey_entries[passkey_digit++] = val;
|
||||
LOG_DBG("value entered: %d, digits collected so far: %d", val, passkey_digit);
|
||||
|
||||
if (passkey_digit == PASSKEY_DIGITS) {
|
||||
uint32_t passkey = 0;
|
||||
for (int i = 0; i < PASSKEY_DIGITS; i++) {
|
||||
passkey = (passkey * 10) + passkey_entries[i];
|
||||
}
|
||||
|
||||
LOG_DBG("Final passkey: %d", passkey);
|
||||
bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey);
|
||||
bt_conn_unref(auth_passkey_entry_conn);
|
||||
auth_passkey_entry_conn = NULL;
|
||||
if (ring_buf_space_get(&passkey_entries) <= 0) {
|
||||
uint8_t discard_val;
|
||||
ring_buf_get(&passkey_entries, &discard_val, 1);
|
||||
}
|
||||
ring_buf_put(&passkey_entries, &val, 1);
|
||||
LOG_DBG("value entered: %d, digits collected so far: %d", val,
|
||||
ring_buf_size_get(&passkey_entries));
|
||||
|
||||
return ZMK_EV_EVENT_HANDLED;
|
||||
}
|
||||
|
|
|
@ -252,41 +252,58 @@ int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pr
|
|||
}
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
int zmk_keymap_sensor_triggered(uint8_t sensor_number, const struct device *sensor,
|
||||
int64_t timestamp) {
|
||||
for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= _zmk_keymap_layer_default; layer--) {
|
||||
if (zmk_keymap_layer_active(layer)) {
|
||||
struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_number];
|
||||
const struct device *behavior;
|
||||
int ret;
|
||||
int zmk_keymap_sensor_event(uint8_t sensor_index,
|
||||
const struct zmk_sensor_channel_data *channel_data,
|
||||
size_t channel_data_size, int64_t timestamp) {
|
||||
bool opaque_response = false;
|
||||
|
||||
LOG_DBG("layer: %d sensor_number: %d, binding name: %s", layer, sensor_number,
|
||||
binding->behavior_dev);
|
||||
for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= 0; layer--) {
|
||||
struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_index];
|
||||
|
||||
behavior = device_get_binding(binding->behavior_dev);
|
||||
LOG_DBG("layer: %d sensor_index: %d, binding name: %s", layer, sensor_index,
|
||||
binding->behavior_dev);
|
||||
|
||||
if (!behavior) {
|
||||
LOG_DBG("No behavior assigned to %d on layer %d", sensor_number, layer);
|
||||
continue;
|
||||
}
|
||||
const struct device *behavior = device_get_binding(binding->behavior_dev);
|
||||
if (!behavior) {
|
||||
LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_number), .timestamp = timestamp};
|
||||
ret = behavior_sensor_keymap_binding_triggered(binding, sensor, event);
|
||||
struct zmk_behavior_binding_event event = {
|
||||
.layer = layer,
|
||||
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index),
|
||||
.timestamp = timestamp,
|
||||
};
|
||||
|
||||
if (ret > 0) {
|
||||
LOG_DBG("behavior processing to continue to next layer");
|
||||
continue;
|
||||
} else if (ret < 0) {
|
||||
LOG_DBG("Behavior returned error: %d", ret);
|
||||
return ret;
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
int ret = behavior_sensor_keymap_binding_accept_data(
|
||||
binding, event, zmk_sensors_get_config_at_index(sensor_index), channel_data_size,
|
||||
channel_data);
|
||||
|
||||
if (ret < 0) {
|
||||
LOG_WRN("behavior data accept for behavior %s returned an error (%d). Processing to "
|
||||
"continue to next layer",
|
||||
binding->behavior_dev, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
enum behavior_sensor_binding_process_mode mode =
|
||||
(!opaque_response && layer >= _zmk_keymap_layer_default &&
|
||||
zmk_keymap_layer_active(layer))
|
||||
? BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER
|
||||
: BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD;
|
||||
|
||||
ret = behavior_sensor_keymap_binding_process(binding, event, mode);
|
||||
|
||||
if (ret == ZMK_BEHAVIOR_OPAQUE) {
|
||||
LOG_DBG("sensor event processing complete, behavior response was opaque");
|
||||
opaque_response = true;
|
||||
} else if (ret < 0) {
|
||||
LOG_DBG("Behavior returned error: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
@ -301,8 +318,8 @@ int keymap_listener(const zmk_event_t *eh) {
|
|||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
const struct zmk_sensor_event *sensor_ev;
|
||||
if ((sensor_ev = as_zmk_sensor_event(eh)) != NULL) {
|
||||
return zmk_keymap_sensor_triggered(sensor_ev->sensor_number, sensor_ev->sensor,
|
||||
sensor_ev->timestamp);
|
||||
return zmk_keymap_sensor_event(sensor_ev->sensor_index, sensor_ev->channel_data,
|
||||
sensor_ev->channel_data_size, sensor_ev->timestamp);
|
||||
}
|
||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
||||
|
||||
|
|
|
@ -18,65 +18,133 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
|
||||
struct sensors_data_item {
|
||||
uint8_t sensor_number;
|
||||
struct sensors_item_cfg {
|
||||
const struct zmk_sensor_config *config;
|
||||
const struct device *dev;
|
||||
struct sensor_trigger trigger;
|
||||
uint8_t sensor_index;
|
||||
};
|
||||
|
||||
#define _SENSOR_ITEM(node) \
|
||||
#define _SENSOR_ITEM(idx, node) \
|
||||
{ \
|
||||
.dev = NULL, .trigger = {.type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ROTATION } \
|
||||
.dev = DEVICE_DT_GET_OR_NULL(node), \
|
||||
.trigger = {.type = SENSOR_TRIG_DATA_READY, .chan = SENSOR_CHAN_ROTATION}, \
|
||||
.config = &configs[idx] \
|
||||
}
|
||||
#define SENSOR_ITEM(idx, _i) _SENSOR_ITEM(idx, ZMK_KEYMAP_SENSORS_BY_IDX(idx))
|
||||
|
||||
#define PLUS_ONE(n) +1
|
||||
#define ZMK_KEYMAP_SENSORS_CHILD_COUNT (0 DT_FOREACH_CHILD(ZMK_KEYMAP_SENSORS_NODE, PLUS_ONE))
|
||||
#define SENSOR_CHILD_ITEM(node) \
|
||||
{ \
|
||||
.triggers_per_rotation = \
|
||||
DT_PROP_OR(node, triggers_per_rotation, \
|
||||
DT_PROP_OR(ZMK_KEYMAP_SENSORS_NODE, triggers_per_rotation, \
|
||||
CONFIG_ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION)) \
|
||||
}
|
||||
#define SENSOR_CHILD_DEFAULTS(idx, arg) \
|
||||
{ \
|
||||
.triggers_per_rotation = \
|
||||
DT_PROP_OR(ZMK_KEYMAP_SENSORS_NODE, triggers_per_rotation, \
|
||||
CONFIG_ZMK_KEYMAP_SENSORS_DEFAULT_TRIGGERS_PER_ROTATION) \
|
||||
}
|
||||
|
||||
#define SENSOR_ITEM(idx, _node) \
|
||||
COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \
|
||||
(_SENSOR_ITEM(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), ({}))
|
||||
static struct zmk_sensor_config configs[] = {
|
||||
#if ZMK_KEYMAP_SENSORS_CHILD_COUNT > 0
|
||||
DT_FOREACH_CHILD_SEP(ZMK_KEYMAP_SENSORS_NODE, SENSOR_CHILD_ITEM, (, ))
|
||||
#else
|
||||
LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_CHILD_DEFAULTS, (, ), 0)
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct sensors_data_item sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
|
||||
static struct sensors_item_cfg sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
|
||||
|
||||
static void zmk_sensors_trigger_handler(const struct device *dev,
|
||||
const struct sensor_trigger *trigger) {
|
||||
static ATOMIC_DEFINE(pending_sensors, ZMK_KEYMAP_SENSORS_LEN);
|
||||
|
||||
const struct zmk_sensor_config *zmk_sensors_get_config_at_index(uint8_t sensor_index) {
|
||||
if (sensor_index > ARRAY_SIZE(configs)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &configs[sensor_index];
|
||||
}
|
||||
|
||||
static void trigger_sensor_data_for_position(uint32_t sensor_index) {
|
||||
int err;
|
||||
const struct sensors_data_item *item = CONTAINER_OF(trigger, struct sensors_data_item, trigger);
|
||||
const struct sensors_item_cfg *item = &sensors[sensor_index];
|
||||
|
||||
LOG_DBG("sensor %d", item->sensor_number);
|
||||
|
||||
err = sensor_sample_fetch(dev);
|
||||
err = sensor_sample_fetch(item->dev);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to fetch sample from device %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
ZMK_EVENT_RAISE(new_zmk_sensor_event((struct zmk_sensor_event){
|
||||
.sensor_number = item->sensor_number, .sensor = dev, .timestamp = k_uptime_get()}));
|
||||
}
|
||||
struct sensor_value value;
|
||||
err = sensor_channel_get(item->dev, item->trigger.chan, &value);
|
||||
|
||||
static void zmk_sensors_init_item(const char *node, uint8_t i, uint8_t abs_i) {
|
||||
LOG_DBG("Init %s at index %d with sensor_number %d", node, i, abs_i);
|
||||
|
||||
sensors[i].dev = device_get_binding(node);
|
||||
sensors[i].sensor_number = abs_i;
|
||||
|
||||
if (!sensors[i].dev) {
|
||||
LOG_WRN("Failed to find device for %s", node);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to get channel data from device %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
sensor_trigger_set(sensors[i].dev, &sensors[i].trigger, zmk_sensors_trigger_handler);
|
||||
ZMK_EVENT_RAISE(new_zmk_sensor_event(
|
||||
(struct zmk_sensor_event){.sensor_index = item->sensor_index,
|
||||
.channel_data_size = 1,
|
||||
.channel_data = {(struct zmk_sensor_channel_data){
|
||||
.value = value, .channel = item->trigger.chan}},
|
||||
.timestamp = k_uptime_get()}));
|
||||
}
|
||||
|
||||
#define _SENSOR_INIT(node) \
|
||||
zmk_sensors_init_item(DT_PROP(node, label), local_index++, absolute_index++);
|
||||
#define SENSOR_INIT(idx, _i) \
|
||||
COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \
|
||||
(_SENSOR_INIT(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), (absolute_index++;))
|
||||
static void run_sensors_data_trigger(struct k_work *work) {
|
||||
for (int i = 0; i < ARRAY_SIZE(sensors); i++) {
|
||||
if (atomic_test_and_clear_bit(pending_sensors, i)) {
|
||||
trigger_sensor_data_for_position(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(sensor_data_work, run_sensors_data_trigger);
|
||||
|
||||
static void zmk_sensors_trigger_handler(const struct device *dev,
|
||||
const struct sensor_trigger *trigger) {
|
||||
const struct sensors_item_cfg *test_item =
|
||||
CONTAINER_OF(trigger, struct sensors_item_cfg, trigger);
|
||||
int sensor_index = test_item - sensors;
|
||||
|
||||
if (sensor_index < 0 || sensor_index >= ARRAY_SIZE(sensors)) {
|
||||
LOG_ERR("Invalid sensor item triggered our callback");
|
||||
return;
|
||||
}
|
||||
|
||||
if (k_is_in_isr()) {
|
||||
atomic_set_bit(pending_sensors, sensor_index);
|
||||
k_work_submit(&sensor_data_work);
|
||||
} else {
|
||||
trigger_sensor_data_for_position(sensor_index);
|
||||
}
|
||||
}
|
||||
|
||||
static void zmk_sensors_init_item(uint8_t i) {
|
||||
LOG_DBG("Init sensor at index %d", i);
|
||||
|
||||
sensors[i].sensor_index = i;
|
||||
|
||||
if (!sensors[i].dev) {
|
||||
LOG_DBG("No local device for %d", i);
|
||||
return;
|
||||
}
|
||||
|
||||
int err = sensor_trigger_set(sensors[i].dev, &sensors[i].trigger, zmk_sensors_trigger_handler);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to set sensor trigger (%d)", err);
|
||||
}
|
||||
}
|
||||
|
||||
#define SENSOR_INIT(idx, _t) zmk_sensors_init_item(idx);
|
||||
|
||||
static int zmk_sensors_init(const struct device *_arg) {
|
||||
int local_index = 0;
|
||||
int absolute_index = 0;
|
||||
|
||||
LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_INIT, (), 0)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,10 @@ config ZMK_SPLIT_ROLE_CENTRAL
|
|||
|
||||
if ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
config ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS
|
||||
int "Number of peripherals that will connect to the central."
|
||||
default 1
|
||||
|
||||
config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE
|
||||
int "Max number of key position state events to queue when received from peripherals"
|
||||
default 5
|
||||
|
@ -29,6 +33,18 @@ config ZMK_SPLIT_BLE_CENTRAL_SPLIT_RUN_QUEUE_SIZE
|
|||
int "Max number of behavior run events to queue to send to the peripheral(s)"
|
||||
default 5
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_INT
|
||||
int "Connection interval to use for split central/peripheral connection"
|
||||
default 6
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_LATENCY
|
||||
int "Latency to use for split central/peripheral connection"
|
||||
default 30
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_TIMEOUT
|
||||
int "Supervision timeout to use for split central/peripheral connection"
|
||||
default 400
|
||||
|
||||
endif # ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
if !ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
@ -54,8 +70,9 @@ config BT_MAX_PAIRED
|
|||
config BT_MAX_CONN
|
||||
default 1
|
||||
|
||||
config BT_PERIPHERAL_PREF_MAX_INT
|
||||
default 6
|
||||
# Allow central to specify connection parameters.
|
||||
config BT_GAP_AUTO_UPDATE_CONN_PARAMS
|
||||
default n
|
||||
|
||||
#!ZMK_SPLIT_ROLE_CENTRAL
|
||||
endif
|
||||
|
|
|
@ -26,7 +26,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
|
||||
static int start_scan(void);
|
||||
static int start_scanning(void);
|
||||
|
||||
#define POSITION_STATE_DATA_LEN 16
|
||||
|
||||
|
@ -49,6 +49,8 @@ struct peripheral_slot {
|
|||
|
||||
static struct peripheral_slot peripherals[ZMK_SPLIT_BLE_PERIPHERAL_COUNT];
|
||||
|
||||
static bool is_scanning = false;
|
||||
|
||||
static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID);
|
||||
|
||||
K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed),
|
||||
|
@ -130,8 +132,9 @@ int release_peripheral_slot(int index) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int reserve_peripheral_slot() {
|
||||
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
|
||||
int reserve_peripheral_slot(const bt_addr_le_t *addr) {
|
||||
int i = zmk_ble_put_peripheral_addr(addr);
|
||||
if (i >= 0) {
|
||||
if (peripherals[i].state == PERIPHERAL_SLOT_STATE_OPEN) {
|
||||
// Be sure the slot is fully reinitialized.
|
||||
release_peripheral_slot(i);
|
||||
|
@ -344,9 +347,56 @@ static void split_central_process_connection(struct bt_conn *conn) {
|
|||
|
||||
LOG_DBG("New connection params: Interval: %d, Latency: %d, PHY: %d", info.le.interval,
|
||||
info.le.latency, info.le.phy->rx_phy);
|
||||
|
||||
// Restart scanning if necessary.
|
||||
start_scanning();
|
||||
}
|
||||
|
||||
static bool split_central_eir_found(struct bt_data *data, void *user_data) {
|
||||
static int stop_scanning() {
|
||||
LOG_DBG("Stopping peripheral scanning");
|
||||
is_scanning = false;
|
||||
|
||||
int err = bt_le_scan_stop();
|
||||
if (err < 0) {
|
||||
LOG_ERR("Stop LE scan failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool split_central_eir_found(const bt_addr_le_t *addr) {
|
||||
LOG_DBG("Found the split service");
|
||||
|
||||
// Stop scanning so we can connect to the peripheral device.
|
||||
int err = stop_scanning();
|
||||
if (err < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int slot_idx = reserve_peripheral_slot(addr);
|
||||
if (slot_idx < 0) {
|
||||
LOG_ERR("Failed to reserve peripheral slot (err %d)", slot_idx);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct peripheral_slot *slot = &peripherals[slot_idx];
|
||||
|
||||
LOG_DBG("Initiating new connnection");
|
||||
struct bt_le_conn_param *param =
|
||||
BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_INT, CONFIG_ZMK_SPLIT_BLE_PREF_INT,
|
||||
CONFIG_ZMK_SPLIT_BLE_PREF_LATENCY, CONFIG_ZMK_SPLIT_BLE_PREF_TIMEOUT);
|
||||
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &slot->conn);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, BT_HCI_OP_LE_CREATE_CONN);
|
||||
release_peripheral_slot(slot_idx);
|
||||
start_scanning();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool split_central_eir_parse(struct bt_data *data, void *user_data) {
|
||||
bt_addr_le_t *addr = user_data;
|
||||
int i;
|
||||
|
||||
|
@ -361,9 +411,7 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) {
|
|||
}
|
||||
|
||||
for (i = 0; i < data->data_len; i += 16) {
|
||||
struct bt_le_conn_param *param;
|
||||
struct bt_uuid_128 uuid;
|
||||
int err;
|
||||
|
||||
if (!bt_uuid_create(&uuid.uuid, &data->data[i], 16)) {
|
||||
LOG_ERR("Unable to load UUID");
|
||||
|
@ -381,46 +429,7 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) {
|
|||
continue;
|
||||
}
|
||||
|
||||
LOG_DBG("Found the split service");
|
||||
|
||||
zmk_ble_set_peripheral_addr(addr);
|
||||
|
||||
err = bt_le_scan_stop();
|
||||
if (err) {
|
||||
LOG_ERR("Stop LE scan failed (err %d)", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t slot_idx = reserve_peripheral_slot();
|
||||
if (slot_idx < 0) {
|
||||
LOG_ERR("Faild to reserve peripheral slot (err %d)", slot_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct peripheral_slot *slot = &peripherals[slot_idx];
|
||||
|
||||
slot->conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
|
||||
if (slot->conn) {
|
||||
LOG_DBG("Found existing connection");
|
||||
split_central_process_connection(slot->conn);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400);
|
||||
|
||||
LOG_DBG("Initiating new connnection");
|
||||
|
||||
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &slot->conn);
|
||||
if (err) {
|
||||
LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err,
|
||||
BT_HCI_OP_LE_CREATE_CONN);
|
||||
start_scan();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return split_central_eir_found(addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,15 +445,34 @@ static void split_central_device_found(const bt_addr_le_t *addr, int8_t rssi, ui
|
|||
|
||||
/* We're only interested in connectable events */
|
||||
if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
|
||||
bt_data_parse(ad, split_central_eir_found, (void *)addr);
|
||||
bt_data_parse(ad, split_central_eir_parse, (void *)addr);
|
||||
}
|
||||
}
|
||||
|
||||
static int start_scan(void) {
|
||||
int err;
|
||||
static int start_scanning(void) {
|
||||
// No action is necessary if central is already scanning.
|
||||
if (is_scanning) {
|
||||
LOG_DBG("Scanning already running");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, split_central_device_found);
|
||||
if (err) {
|
||||
// If all the devices are connected, there is no need to scan.
|
||||
bool has_unconnected = false;
|
||||
for (int i = 0; i < CONFIG_ZMK_SPLIT_BLE_CENTRAL_PERIPHERALS; i++) {
|
||||
if (peripherals[i].conn == NULL) {
|
||||
has_unconnected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_unconnected) {
|
||||
LOG_DBG("All devices are connected, scanning is unnecessary");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Start scanning otherwise.
|
||||
is_scanning = true;
|
||||
int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, split_central_device_found);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Scanning failed to start (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
@ -471,7 +499,7 @@ static void split_central_connected(struct bt_conn *conn, uint8_t conn_err) {
|
|||
|
||||
release_peripheral_slot_for_conn(conn);
|
||||
|
||||
start_scan();
|
||||
start_scanning();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -495,7 +523,7 @@ static void split_central_disconnected(struct bt_conn *conn, uint8_t reason) {
|
|||
return;
|
||||
}
|
||||
|
||||
start_scan();
|
||||
start_scanning();
|
||||
}
|
||||
|
||||
static struct bt_conn_cb conn_callbacks = {
|
||||
|
@ -527,6 +555,10 @@ void split_central_split_run_callback(struct k_work *work) {
|
|||
LOG_ERR("Source not connected");
|
||||
continue;
|
||||
}
|
||||
if (!peripherals[payload_wrapper.source].run_behavior_handle) {
|
||||
LOG_ERR("Run behavior handle not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
int err = bt_gatt_write_without_response(
|
||||
peripherals[payload_wrapper.source].conn,
|
||||
|
@ -590,7 +622,7 @@ int zmk_split_bt_central_init(const struct device *_arg) {
|
|||
CONFIG_ZMK_BLE_THREAD_PRIORITY, NULL);
|
||||
bt_conn_cb_register(&conn_callbacks);
|
||||
|
||||
return start_scan();
|
||||
return start_scanning();
|
||||
}
|
||||
|
||||
SYS_INIT(zmk_split_bt_central_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
|
||||
|
|
1
app/tests/macros/place-holder-parameters/events.patterns
Normal file
1
app/tests/macros/place-holder-parameters/events.patterns
Normal file
|
@ -0,0 +1 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
|
@ -0,0 +1,16 @@
|
|||
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x38 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x38 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x34 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_pressed: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_released: usage_page 0x07 keycode 0x08 implicit_mods 0x00 explicit_mods 0x00
|
||||
kp_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
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
|
||||
/ {
|
||||
macros {
|
||||
slash_macro: slash_macro {
|
||||
#binding-cells = <2>;
|
||||
label = "ZM_SLASH";
|
||||
compatible = "zmk,behavior-macro-two-param";
|
||||
wait-ms = <40>;
|
||||
tap-ms = <40>;
|
||||
bindings = <
|
||||
¯o_param_1to1 &kp MACRO_PLACEHOLDER
|
||||
&kp SLASH
|
||||
¯o_param_2to1 &kp MACRO_PLACEHOLDER>;
|
||||
};
|
||||
|
||||
to_second_macro: to_second_macro {
|
||||
#binding-cells = <2>;
|
||||
label = "ZMK_TO_SECOND";
|
||||
compatible = "zmk,behavior-macro-two-param";
|
||||
wait-ms = <40>;
|
||||
tap-ms = <40>;
|
||||
bindings = <
|
||||
¯o_param_1to2 &mt LSHIFT MACRO_PLACEHOLDER
|
||||
¯o_param_2to2 &mt RSHIFT MACRO_PLACEHOLDER>;
|
||||
};
|
||||
|
||||
quote_letter_macro: quote_letter_macro {
|
||||
#binding-cells = <1>;
|
||||
label = "ZMK_QLET";
|
||||
compatible = "zmk,behavior-macro-one-param";
|
||||
wait-ms = <40>;
|
||||
tap-ms = <40>;
|
||||
bindings = <
|
||||
&kp QUOT
|
||||
¯o_param_1to1 &kp MACRO_PLACEHOLDER
|
||||
&kp QUOT>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label = "Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&slash_macro A B "e_letter_macro B
|
||||
&to_second_macro E F &kp C>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&kscan {
|
||||
events = <ZMK_MOCK_PRESS(0,0,20) ZMK_MOCK_PRESS(0,1,10) ZMK_MOCK_RELEASE(0,1,10) ZMK_MOCK_RELEASE(0,0,10) ZMK_MOCK_PRESS(1,0,10) ZMK_MOCK_RELEASE(1,0,1000)>;
|
||||
};
|
119
docs/blog/2023-06-18-encoder-refactors.md
Normal file
119
docs/blog/2023-06-18-encoder-refactors.md
Normal file
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
title: "Major Encoder Refactor"
|
||||
author: Pete Johanson
|
||||
author_title: Project Creator
|
||||
author_url: https://gitlab.com/petejohanson
|
||||
author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110
|
||||
tags: [firmware, zephyr, sensors, encoders]
|
||||
---
|
||||
|
||||
Today, we merged a significant change to the low level sensor code that is used to support encoders. In particular,
|
||||
this paves the way for completing the work on supporting split peripheral sensors/encoders, and other future sensors
|
||||
like pointing devices.
|
||||
|
||||
As part of the work, backwards compatibility for existing shields has been retained, but only for a grace period to allow out-of-tree shields to move to the new approach for encoders.
|
||||
|
||||
Special thanks to [joelspadin] for the _thorough_ code review and testing throughout the development of the refactor.
|
||||
|
||||
## Summary of Changes
|
||||
|
||||
The following items have been merged:
|
||||
|
||||
1. Split configuration of hardware details, and behavior configuration to allow more flexible functionality of sensors/encoders, in particular linear encoders that lack detents/"clicks" as they rotate.
|
||||
2. Support for upstream Zephyr sensor drivers, including the NRFX QDEC driver that can be used on nRF52 based keyboards.
|
||||
3. Sensor data handling changes that pave the way for split sensor handling easily.
|
||||
|
||||
## Configuration Changes
|
||||
|
||||
The major changes to configuration in the devicetree files relates to how the number of steps/triggers for a given encoder are set. In particular, the number of pulses/steps for a given encoder is configured first, allowing ZMK to determine the exact angular degrees of change that is represented by a single pulse on the data lines to that encoder.
|
||||
|
||||
Once that angular degrees mapping is completed, now independently there is a configuration setting to control how many triggers of the behavior in the keymap should occur for each full rotation of the sensor. Another way to think of this is "how many degrees of rotation results in a triggering of the sensor behavior in your keymap layer".
|
||||
|
||||
Splitting these two parts of the encoder configuration allows greater flexibility, and fine grained control of encoder behavior for linear encoders that don't have fixed detents.
|
||||
|
||||
### Old Configuration
|
||||
|
||||
Previously, an encoder configuration looked like:
|
||||
|
||||
```
|
||||
left_encoder: encoder_left {
|
||||
compatible = "alps,ec11";
|
||||
label = "LEFT_ENCODER";
|
||||
a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
|
||||
b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
|
||||
resolution = <4>;
|
||||
};
|
||||
```
|
||||
|
||||
Here, the `resolution` property was used to indicate how many encoder pulses should trigger the sensor behavior one time. Next, the encoder is selected in the sensors node:
|
||||
|
||||
```
|
||||
sensors {
|
||||
compatible = "zmk,keymap-sensors";
|
||||
sensors = <&left_encoder &right_encoder>;
|
||||
};
|
||||
```
|
||||
|
||||
That was the entirety of the configuration for encoders.
|
||||
|
||||
### New Configuration
|
||||
|
||||
```
|
||||
left_encoder: encoder_left {
|
||||
compatible = "alps,ec11";
|
||||
label = "LEFT_ENCODER";
|
||||
a-gpios = <&pro_micro 21 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
|
||||
b-gpios = <&pro_micro 20 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>;
|
||||
steps = <80>;
|
||||
};
|
||||
```
|
||||
|
||||
Here, the `steps` property is now used to indicate how many encoder pulses there are in a single complete rotation of the encoder. Next, the encoder is selected in the sensors node as before, but an additional configuration is used to indicate how many times the encoder should trigger the behavior in your keymap per rotation:
|
||||
|
||||
```
|
||||
sensors {
|
||||
compatible = "zmk,keymap-sensors";
|
||||
sensors = <&left_encoder &right_encoder>;
|
||||
triggers-per-rotation = <20>;
|
||||
};
|
||||
```
|
||||
|
||||
For tactile encoders that have detents, the `triggers-per-rotation` would match the number of detents on the encoder. For linear encoders, the value can be chosen to suit your needs.
|
||||
|
||||
## Zephyr Sensor Drivers
|
||||
|
||||
The configuration changes bring ZMK's code in line with how upstream Zephyr sensor drivers handle rotations. This has the added advantage of allowing us to leverage other sensor drivers. On Nordic MCUs, like nRF52840, the NRFX QDEC driver can be used, for example:
|
||||
|
||||
```
|
||||
&pinctrl {
|
||||
qdec_default: qdec_default {
|
||||
group1 {
|
||||
psels = <NRF_PSEL(QDEC_A, 1, 11)>,
|
||||
<NRF_PSEL(QDEC_B, 1, 10)>;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Set up the QDEC hardware based driver and give it the same label as the deleted node.
|
||||
encoder: &qdec0 {
|
||||
status = "okay";
|
||||
led-pre = <0>;
|
||||
steps = <80>;
|
||||
pinctrl-0 = <&qdec_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
```
|
||||
|
||||
The NRFX QDEC driver has the advantage of supporting optical encoders as well, and although it polls, it does so in hardware without waking the MCU core; initial basic power profiling is promising.
|
||||
|
||||
## Split Sensor/Encoder Support
|
||||
|
||||
In addition to the refactors for splitting the configuration, the changes merged included refactors designed to simplify and move forward with the long outstanding feature of supporting encoders on the peripheral side of split keyboards. That work is planned as a follow up.
|
||||
|
||||
## Deprecation
|
||||
|
||||
The old configuration will be supported for a period of one month, and then removed, giving users a grace period to complete the migration to the new separated configuration.
|
||||
|
||||
[petejohanson]: https://github.com/petejohanson
|
||||
[joelspadin]: https://github.com/joelspadin
|
|
@ -49,6 +49,22 @@ For use cases involving sending a single keycode with modifiers, for instance ct
|
|||
with [modifier functions](../codes/modifiers.mdx#modifier-functions) can be used instead of a macro.
|
||||
:::
|
||||
|
||||
### Parameterized Macros
|
||||
|
||||
Macros can also be "parameterized", allowing them to be bound in your keymap with unique values passed into them, e.g.:
|
||||
|
||||
```
|
||||
raise_layer {
|
||||
bindings = <&my_cool_macro A>
|
||||
};
|
||||
```
|
||||
|
||||
When defining a parameterized macro, a different `compatible` value will be used depending on how many parameters are passed into it:
|
||||
|
||||
- `zmk,behavior-macro` - a parameter that takes no parameters.
|
||||
- `zmk,behavior-macro-one-param` - a parameter that takes one parameter when used.
|
||||
- `zmk,behavior-macro-two-param` - a parameter that takes two parameters when used.
|
||||
|
||||
### Bindings
|
||||
|
||||
Like [hold-taps](/docs/behaviors/hold-tap), macros are created by composing other behaviors, and any of those behaviors can
|
||||
|
@ -67,6 +83,30 @@ bindings
|
|||
There are a set of special macro controls that can be included in the `bindings` list to modify the
|
||||
way the macro is processed.
|
||||
|
||||
### Parameters
|
||||
|
||||
When creating a macro that takes parameter(s), there are macro controls that change when the parameters passed to the macro are used
|
||||
within the macro itself. All of the controls are "one shot" and will change how the passed in parameters are used for the very next non-macro control behavior in the `bindings` list of the macro.
|
||||
|
||||
For example, to pass the first parameter from the macro into a `&kp` used in the macro, you would use:
|
||||
|
||||
```
|
||||
bindings
|
||||
= <¯o_param_1to1>
|
||||
, <&kp MACRO_PLACEHOLDER>
|
||||
;
|
||||
```
|
||||
|
||||
Because `kp` takes one parameter, you can't simply make the second entry `<&kp>` in the `bindings` list. Whatever value you do pass in will be replaced when the macro is triggered, so you can put _any_ value there, e.g. `0`, `A` keycode, etc. To make it very obvious that the parameter there is not actually going to be used, you can use `MACRO_PLACEHOLDER` which is simply an alias for `0`.
|
||||
|
||||
The available parameter controls are:
|
||||
|
||||
- `¯o_param_1to1` - pass the first parameter of the macro into the first parameter of the next behavior in the `bindings` list.
|
||||
- `¯o_param_1to2` - pass the first parameter of the macro into the second parameter of the next behavior in the `bindings` list.
|
||||
|
||||
* `¯o_param_2to1` - pass the second parameter of the macro into the first parameter of the next behavior in the `bindings` list.
|
||||
* `¯o_param_2to2` - pass the second parameter of the macro into the second parameter of the next behavior in the `bindings` list.
|
||||
|
||||
### Binding Activation Mode
|
||||
|
||||
Bindings in a macro are activated differently, depending on the current "activation mode" of the macro.
|
||||
|
|
|
@ -38,6 +38,8 @@ These functions take the form: `XX(code)`
|
|||
- `&kp LS(A)` = `LEFT_SHIFT`+`A` (a capitalized **A**).
|
||||
- They can be combined:
|
||||
- `&kp LC(RA(B))` = `LEFT_CONTROL`+`RIGHT_ALT`+`B`
|
||||
- They can be applied to a modifier keycode to create combined modifier keys:
|
||||
- `&kp LS(LALT)` = `LEFT_SHIFT` + `LEFT_ALT`
|
||||
- Some basic codes already include a modifier function in their definition:
|
||||
- `DOLLAR` = `LS(NUMBER_4)`
|
||||
- There are left- and right-handed versions of each modifier (also see table above):
|
||||
|
|
|
@ -9,6 +9,7 @@ See [Configuration Overview](index.md) for instructions on how to change these s
|
|||
|
||||
## Kconfig
|
||||
|
||||
| Option | Type | Description | Default |
|
||||
| ------------------------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||
| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y |
|
||||
| Option | Type | Description | Default |
|
||||
| ------------------------------------- | ---- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
||||
| `CONFIG_ZMK_BLE_PASSKEY_ENTRY` | bool | Enable passkey entry during pairing for enhanced security. (Note: After enabling this, you will need to re-pair all previously paired hosts) | n |
|
||||
| `CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION` | bool | Low level setting for GATT subscriptions. Set to `n` to work around an annoying Windows bug with battery notifications. | y |
|
||||
|
|
|
@ -130,8 +130,8 @@ The above build commands generate a UF2 file in `build/zephyr` (or
|
|||
`build/left|right/zephyr` if you followed the instructions for splits) and is by
|
||||
default named `zmk.uf2`. If your board supports USB Flashing Format (UF2), copy
|
||||
that file onto the root of the USB mass storage device for your board. The
|
||||
controller should flash your built firmware and automatically restart once
|
||||
flashing is complete.
|
||||
controller should flash your built firmware, unmount the USB storage device and
|
||||
automatically restart once flashing is complete.
|
||||
|
||||
Alternatively, if your board supports flashing and you're not developing from
|
||||
within a Dockerized environment, enable Device Firmware Upgrade (DFU) mode on
|
||||
|
|
|
@ -88,36 +88,41 @@ powershell -Command "iex ((New-Object System.Net.WebClient).DownloadString('http
|
|||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Keyboard Selection
|
||||
|
||||
When prompted, enter the number for the corresponding keyboard you would like to target:
|
||||
|
||||
```
|
||||
Keyboard Selection:
|
||||
1) 2% Milk 19) Ferris 0.2 37) Nibble
|
||||
2) A. Dux 20) Fourier Rev. 1 38) nice!60
|
||||
3) BAT43 21) Helix 39) Osprette
|
||||
4) BDN9 Rev2 22) Hummingbird 40) Pancake
|
||||
5) BFO-9000 23) Iris 41) Planck Rev6
|
||||
6) Boardsource 3x4 Macropad 24) etc...
|
||||
Pick an keyboard:
|
||||
```
|
||||
|
||||
:::note For a keyboard not in the included list:
|
||||
If you are building firmware for a new keyboard that is not included in the built-in
|
||||
list of keyboards, you can choose any keyboard from the list that is similar to yours (e.g. in terms of unibody/split and [onboard controller](hardware.mdx#onboard)/[composite](hardware.mdx#composite)) to generate the repository,
|
||||
and edit / add necessary files. You can follow the [new shield guide](development/new-shield.md) if you are adding support for a composite keyboard.
|
||||
:::
|
||||
|
||||
### MCU Board Selection
|
||||
|
||||
If the keyboard selected uses an onboard controller you will skip this step.
|
||||
When prompted, enter the number for the corresponding MCU board you would like to target:
|
||||
|
||||
```
|
||||
MCU Board Selection:
|
||||
1) nice!nano
|
||||
2) QMK Proton-C
|
||||
3) Quit
|
||||
1) BlueMicro840 v1 5) nRF52840 M.2 Module 9) QMK Proton-C
|
||||
2) Mikoto 5.20 6) nRFMicro 1.1 (flipped) 10) Seeeduino XIAO
|
||||
3) nice!nano v1 7) nRFMicro 1.1/1.2 11) Seeeduino XIAO BLE
|
||||
4) nice!nano v2 8) nRFMicro 1.3/1.4 12) Quit
|
||||
Pick an MCU board:
|
||||
```
|
||||
|
||||
### Keyboard Shield Selection
|
||||
|
||||
:::note
|
||||
If you are building firmware for a new keyboard shield that is not included in the built-in
|
||||
list of shields, you can choose any shield from the list that is similar to yours to generate the repository,
|
||||
and edit / add necessary files according to the [guide for adding new keyboard shield](development/new-shield.md).
|
||||
:::
|
||||
|
||||
When prompted, enter the number for the corresponding keyboard shield you would like to target:
|
||||
|
||||
```
|
||||
Keyboard Shield Selection:
|
||||
1) Kyria
|
||||
2) Lily58
|
||||
3) Quit
|
||||
Pick an keyboard:
|
||||
```
|
||||
|
||||
### Keymap Customization
|
||||
|
||||
At the next prompt, you have an opportunity to decide if you want the stock keymap file copied in
|
||||
|
@ -193,8 +198,9 @@ To flash the firmware, first put your board into bootloader mode by double click
|
|||
or the one that is part of your keyboard). The controller should appear in your OS as a new USB storage device.
|
||||
|
||||
Once this happens, copy the correct UF2 file (e.g. left or right if working on a split), and paste it onto the root of that USB mass
|
||||
storage device. Once the flash is complete, the controller should automatically restart, and load your newly flashed firmware. It is
|
||||
recommended that you test your keyboard works over USB first to rule out hardware issues, before trying to connect to it wirelessly.
|
||||
storage device. Once the flash is complete, the controller should unmount the USB storage, automatically restart and load your newly
|
||||
flashed firmware. It is recommended that you test your keyboard works over USB first to rule out hardware issues, before trying to
|
||||
connect to it wirelessly.
|
||||
|
||||
:::caution Split keyboards
|
||||
|
||||
|
|
81
docs/package-lock.json
generated
81
docs/package-lock.json
generated
|
@ -42,7 +42,7 @@
|
|||
"prettier": "^2.8.7",
|
||||
"string-replace-loader": "^3.1.0",
|
||||
"typescript": "^5.0.4",
|
||||
"webpack": "^5.80.0"
|
||||
"webpack": "^5.86.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@algolia/autocomplete-core": {
|
||||
|
@ -3950,9 +3950,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/acorn-import-assertions": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
|
||||
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
|
||||
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
}
|
||||
|
@ -6069,9 +6069,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz",
|
||||
"integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==",
|
||||
"version": "5.14.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz",
|
||||
"integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
|
@ -13612,31 +13612,20 @@
|
|||
}
|
||||
},
|
||||
"node_modules/serve-handler": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz",
|
||||
"integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==",
|
||||
"version": "6.1.5",
|
||||
"resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz",
|
||||
"integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==",
|
||||
"dependencies": {
|
||||
"bytes": "3.0.0",
|
||||
"content-disposition": "0.5.2",
|
||||
"fast-url-parser": "1.1.3",
|
||||
"mime-types": "2.1.18",
|
||||
"minimatch": "3.0.4",
|
||||
"minimatch": "3.1.2",
|
||||
"path-is-inside": "1.0.2",
|
||||
"path-to-regexp": "2.2.1",
|
||||
"range-parser": "1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-handler/node_modules/minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-handler/node_modules/path-to-regexp": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
|
||||
|
@ -15401,9 +15390,9 @@
|
|||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.80.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz",
|
||||
"integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==",
|
||||
"version": "5.86.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz",
|
||||
"integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
|
@ -15411,10 +15400,10 @@
|
|||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.13.0",
|
||||
"enhanced-resolve": "^5.14.1",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
|
@ -18910,9 +18899,9 @@
|
|||
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA=="
|
||||
},
|
||||
"acorn-import-assertions": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
|
||||
"integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
|
||||
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
|
||||
"requires": {}
|
||||
},
|
||||
"acorn-jsx": {
|
||||
|
@ -20437,9 +20426,9 @@
|
|||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "5.13.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz",
|
||||
"integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==",
|
||||
"version": "5.14.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.1.tgz",
|
||||
"integrity": "sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
|
@ -25765,28 +25754,20 @@
|
|||
}
|
||||
},
|
||||
"serve-handler": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.3.tgz",
|
||||
"integrity": "sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==",
|
||||
"version": "6.1.5",
|
||||
"resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.5.tgz",
|
||||
"integrity": "sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg==",
|
||||
"requires": {
|
||||
"bytes": "3.0.0",
|
||||
"content-disposition": "0.5.2",
|
||||
"fast-url-parser": "1.1.3",
|
||||
"mime-types": "2.1.18",
|
||||
"minimatch": "3.0.4",
|
||||
"minimatch": "3.1.2",
|
||||
"path-is-inside": "1.0.2",
|
||||
"path-to-regexp": "2.2.1",
|
||||
"range-parser": "1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz",
|
||||
|
@ -27050,9 +27031,9 @@
|
|||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.80.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.80.0.tgz",
|
||||
"integrity": "sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA==",
|
||||
"version": "5.86.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.86.0.tgz",
|
||||
"integrity": "sha512-3BOvworZ8SO/D4GVP+GoRC3fVeg5MO4vzmq8TJJEkdmopxyazGDxN8ClqN12uzrZW9Tv8EED8v5VSb6Sqyi0pg==",
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
|
@ -27060,10 +27041,10 @@
|
|||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.7.6",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"browserslist": "^4.14.5",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.13.0",
|
||||
"enhanced-resolve": "^5.14.1",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
|
|
|
@ -61,6 +61,6 @@
|
|||
"prettier": "^2.8.7",
|
||||
"string-replace-loader": "^3.1.0",
|
||||
"typescript": "^5.0.4",
|
||||
"webpack": "^5.80.0"
|
||||
"webpack": "^5.86.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3477,7 +3477,7 @@ export default [
|
|||
},
|
||||
{
|
||||
names: ["INTERNATIONAL_6", "INT6", "INT_KPJPCOMMA"],
|
||||
description: ", [カソマ] (International 6)",
|
||||
description: ", [カンマ] (International 6)",
|
||||
context: "Keyboard",
|
||||
clarify: false,
|
||||
usages: [
|
||||
|
|
Loading…
Add table
Reference in a new issue