Add configurable sensor bindings
This commit is contained in:
parent
4e11913127
commit
41d2c5cfd4
10 changed files with 265 additions and 5 deletions
|
@ -52,6 +52,8 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
target_sources(app PRIVATE src/behaviors/behavior_to_layer.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_none.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE app PRIVATE src/behaviors/behavior_sensor_rotate.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
|
||||
target_sources(app PRIVATE src/combo.c)
|
||||
target_sources(app PRIVATE src/behavior_queue.c)
|
||||
|
|
12
app/Kconfig
12
app/Kconfig
|
@ -477,6 +477,18 @@ choice CBPRINTF_IMPLEMENTATION
|
|||
|
||||
endchoice
|
||||
|
||||
DT_COMPAT_ZMK_BEHAVIOR_SENSOR_ROTATE := zmk,behavior-sensor-rotate
|
||||
|
||||
config ZMK_BEHAVIOR_SENSOR_ROTATE
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BEHAVIOR_SENSOR_ROTATE))
|
||||
|
||||
DT_COMPAT_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR := zmk,behavior-sensor-rotate-var
|
||||
|
||||
config ZMK_BEHAVIOR_SENSOR_ROTATE_VAR
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR))
|
||||
|
||||
module = ZMK
|
||||
module-str = zmk
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
behaviors {
|
||||
/* DEPRECATED: `inc_dec_cp` will be removed in the future */
|
||||
/omit-if-no-ref/ inc_dec_cp: inc_dec_kp: behavior_sensor_rotate_key_press {
|
||||
compatible = "zmk,behavior-sensor-rotate-key-press";
|
||||
compatible = "zmk,behavior-sensor-rotate-var";
|
||||
label = "ENC_KEY_PRESS";
|
||||
#sensor-binding-cells = <2>;
|
||||
bindings = <&kp>, <&kp>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Sensor rotate behavior
|
||||
|
||||
compatible: "zmk,behavior-sensor-rotate-var"
|
||||
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
required: true
|
||||
"#sensor-binding-cells":
|
||||
type: int
|
||||
required: true
|
||||
const: 2
|
||||
bindings:
|
||||
type: phandles
|
||||
required: true
|
||||
tap-ms:
|
||||
type: int
|
||||
default: 5
|
||||
|
||||
sensor-binding-cells:
|
||||
- param1
|
||||
- param2
|
21
app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
Normal file
21
app/dts/bindings/behaviors/zmk,behavior-sensor-rotate.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Sensor rotate behavior
|
||||
|
||||
compatible: "zmk,behavior-sensor-rotate"
|
||||
|
||||
properties:
|
||||
label:
|
||||
type: string
|
||||
required: true
|
||||
"#sensor-binding-cells":
|
||||
type: int
|
||||
required: true
|
||||
const: 0
|
||||
bindings:
|
||||
type: phandle-array
|
||||
required: true
|
||||
tap-ms:
|
||||
type: int
|
||||
default: 5
|
86
app/src/behaviors/behavior_sensor_rotate.c
Normal file
86
app/src/behaviors/behavior_sensor_rotate.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_sensor_rotate
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include <drivers/sensor.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/keycode_state_changed.h>
|
||||
#include <zmk/behavior_queue.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
struct behavior_sensor_rotate_config {
|
||||
struct zmk_behavior_binding cw_binding;
|
||||
struct zmk_behavior_binding ccw_binding;
|
||||
int tap_ms;
|
||||
};
|
||||
|
||||
static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor, int64_t timestamp) {
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct behavior_sensor_rotate_config *cfg = dev->config;
|
||||
|
||||
struct sensor_value value;
|
||||
int err;
|
||||
|
||||
err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Failed to get sensor rotation value: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct zmk_behavior_binding *triggered_binding;
|
||||
switch (value.val1) {
|
||||
case 1:
|
||||
triggered_binding = (struct zmk_behavior_binding *)&cfg->cw_binding;
|
||||
break;
|
||||
case -1:
|
||||
triggered_binding = (struct zmk_behavior_binding *)&cfg->ccw_binding;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
LOG_DBG("Sensor binding: %s", log_strdup(binding->behavior_dev));
|
||||
|
||||
zmk_behavior_queue_add(0, *triggered_binding, true, cfg->tap_ms);
|
||||
zmk_behavior_queue_add(0, *triggered_binding, false, 0);
|
||||
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
||||
.sensor_binding_triggered = on_sensor_binding_triggered};
|
||||
|
||||
static int behavior_sensor_rotate_init(const struct device *dev) { return 0; };
|
||||
|
||||
#define _TRANSFORM_ENTRY(idx, node) \
|
||||
{ \
|
||||
.behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \
|
||||
.param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \
|
||||
(DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \
|
||||
.param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), \
|
||||
(DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \
|
||||
}
|
||||
|
||||
#define SENSOR_ROTATE_INST(n) \
|
||||
static struct behavior_sensor_rotate_config behavior_sensor_rotate_config_##n = { \
|
||||
.cw_binding = _TRANSFORM_ENTRY(0, n), \
|
||||
.ccw_binding = _TRANSFORM_ENTRY(1, n), \
|
||||
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
|
||||
}; \
|
||||
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);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
|
79
app/src/behaviors/behavior_sensor_rotate_var.c
Normal file
79
app/src/behaviors/behavior_sensor_rotate_var.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_sensor_rotate_var
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include <drivers/sensor.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/keycode_state_changed.h>
|
||||
#include <zmk/behavior_queue.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
struct behavior_sensor_rotate_var_config {
|
||||
char *cw_behavior_dev;
|
||||
char *ccw_behavior_dev;
|
||||
int tap_ms;
|
||||
};
|
||||
|
||||
static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding,
|
||||
const struct device *sensor, int64_t timestamp) {
|
||||
const struct device *dev = device_get_binding(binding->behavior_dev);
|
||||
const struct behavior_sensor_rotate_var_config *cfg = dev->config;
|
||||
|
||||
struct sensor_value value;
|
||||
int err;
|
||||
|
||||
err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value);
|
||||
|
||||
if (err) {
|
||||
LOG_WRN("Failed to get sensor rotation value: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct zmk_behavior_binding triggered_binding;
|
||||
switch (value.val1) {
|
||||
case 1:
|
||||
triggered_binding.behavior_dev = cfg->cw_behavior_dev;
|
||||
triggered_binding.param1 = binding->param1;
|
||||
break;
|
||||
case -1:
|
||||
triggered_binding.behavior_dev = cfg->ccw_behavior_dev;
|
||||
triggered_binding.param1 = binding->param2;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
LOG_DBG("Sensor binding: %s", log_strdup(binding->behavior_dev));
|
||||
|
||||
zmk_behavior_queue_add(0, triggered_binding, true, cfg->tap_ms);
|
||||
zmk_behavior_queue_add(0, triggered_binding, false, 0);
|
||||
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = {
|
||||
.sensor_binding_triggered = on_sensor_binding_triggered};
|
||||
|
||||
static int behavior_sensor_rotate_var_init(const struct device *dev) { return 0; };
|
||||
|
||||
#define SENSOR_ROTATE_VAR_INST(n) \
|
||||
static struct behavior_sensor_rotate_var_config behavior_sensor_rotate_var_config_##n = { \
|
||||
.cw_behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)), \
|
||||
.ccw_behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(n, bindings, 1)), \
|
||||
.tap_ms = DT_INST_PROP(n, tap_ms), \
|
||||
}; \
|
||||
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);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)
|
33
docs/docs/behaviors/sensor-rotate.md
Normal file
33
docs/docs/behaviors/sensor-rotate.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: Sensor Rotation
|
||||
sidebar_label: Sensor Rotation
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The Sensor Rotation behavior triggers a different behavior, depending on whether the sensor is rotated clockwise or counter-clockwise.
|
||||
|
||||
- If rotated counter-clockwise, the first behavior is triggered.
|
||||
- If rotated clockwise, the second behavior is triggered.
|
||||
|
||||
### Configuration
|
||||
|
||||
An example implementation of an encoder that changes RGB brightness is shown below:
|
||||
|
||||
```
|
||||
/ {
|
||||
behaviors {
|
||||
rgb_encoder: rgb_encoder {
|
||||
compatible = "zmk,behavior-sensor-rotate";
|
||||
label = "RGB_ENCODER";
|
||||
#sensor-binding-cells = <0>;
|
||||
bindings = <&rgb_ug RGB_BRD>, <&rgb_ug RGB_BRI>;
|
||||
};
|
||||
};
|
||||
|
||||
keymap {
|
||||
...
|
||||
sensor-bindings = <&rgb_encoder>
|
||||
};
|
||||
};
|
||||
```
|
|
@ -23,17 +23,17 @@ Keyboards and macropads with encoder support will typically take the two EC11 pi
|
|||
|
||||
### Rotation
|
||||
|
||||
Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`, which is defined in each keymap layer in the following format:
|
||||
Rotation is handled separately as a type of sensor. The behavior for this is set in `sensor-bindings`. See [Sensor Rotation](../behaviors/sensor-rotate.md) for customizing this behavior.
|
||||
|
||||
```
|
||||
sensor-bindings = <BINDING CW_KEY CCW_KEY>;
|
||||
sensor-bindings = <BINDING [CW_KEY] [CCW_KEY]>;
|
||||
```
|
||||
|
||||
- `BINDING`, for now, has only one behavior available; `&inc_dec_kp` for key presses (see [Key Press](../behaviors/key-press.md) for details on available keycodes).
|
||||
- `BINDING` is either a user-defined behavior, or `&inc_dec_kp` for key presses (see [Key Press](../behaviors/key-press.md) for details on available keycodes).
|
||||
- `CW_KEY` is the keycode activated by a clockwise turn.
|
||||
- `CCW_KEY` is the keycode activated by a counter-clockwise turn.
|
||||
|
||||
Additional encoders can be configured by adding more `BINDING CW_KEY CCW_KEY` sets immediately after the first.
|
||||
Additional encoders can be configured by adding more bindings immediately after the first.
|
||||
|
||||
As an example, a complete `sensor-bindings` for a Kyria with two encoders could look like:
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ module.exports = {
|
|||
"behaviors/tap-dance",
|
||||
"behaviors/caps-word",
|
||||
"behaviors/key-repeat",
|
||||
"behaviors/sensor-rotate",
|
||||
"behaviors/reset",
|
||||
"behaviors/bluetooth",
|
||||
"behaviors/outputs",
|
||||
|
|
Loading…
Add table
Reference in a new issue