feat(behaviors): Add behavior metadata information.
* For upcoming ZMK studio work, make a set of rich metadata available to provide a friendly name for a behavior, and allow super flexible descriptions of the parameters the behaviors take. * Add ability to validate a zmk_behavior_binding against the behavior metadata available.
This commit is contained in:
parent
7cdf1e42ea
commit
03099b04b6
42 changed files with 965 additions and 14 deletions
|
@ -1,6 +1,12 @@
|
||||||
# Copyright (c) 2023 The ZMK Contributors
|
# Copyright (c) 2023 The ZMK Contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
config ZMK_BEHAVIOR_METADATA
|
||||||
|
bool "Metadata"
|
||||||
|
help
|
||||||
|
Enabling this option adds APIs for documenting and fetching
|
||||||
|
metadata describing a behaviors name, and supported parameters.
|
||||||
|
|
||||||
config ZMK_BEHAVIOR_KEY_TOGGLE
|
config ZMK_BEHAVIOR_KEY_TOGGLE
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
/omit-if-no-ref/ bl: bcklight {
|
/omit-if-no-ref/ bl: bcklight {
|
||||||
compatible = "zmk,behavior-backlight";
|
compatible = "zmk,behavior-backlight";
|
||||||
#binding-cells = <2>;
|
#binding-cells = <2>;
|
||||||
|
display-name = "Backlight";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ bt: bluetooth {
|
/omit-if-no-ref/ bt: bluetooth {
|
||||||
compatible = "zmk,behavior-bluetooth";
|
compatible = "zmk,behavior-bluetooth";
|
||||||
#binding-cells = <2>;
|
#binding-cells = <2>;
|
||||||
|
display-name = "Bluetooth";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
compatible = "zmk,behavior-caps-word";
|
compatible = "zmk,behavior-caps-word";
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
continue-list = <UNDERSCORE BACKSPACE DELETE>;
|
continue-list = <UNDERSCORE BACKSPACE DELETE>;
|
||||||
|
display-name = "Caps Word";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
ext_power: extpower {
|
ext_power: extpower {
|
||||||
compatible = "zmk,behavior-ext-power";
|
compatible = "zmk,behavior-ext-power";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "External Power";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
bindings = <&kp ESC>, <&kp GRAVE>;
|
bindings = <&kp ESC>, <&kp GRAVE>;
|
||||||
mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
|
mods = <(MOD_LGUI|MOD_LSFT|MOD_RGUI|MOD_RSFT)>;
|
||||||
|
display-name = "Grave/Escape";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
/omit-if-no-ref/ cp: kp: key_press {
|
/omit-if-no-ref/ cp: kp: key_press {
|
||||||
compatible = "zmk,behavior-key-press";
|
compatible = "zmk,behavior-key-press";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "Key Press";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
compatible = "zmk,behavior-key-repeat";
|
compatible = "zmk,behavior-key-repeat";
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
usage-pages = <HID_USAGE_KEY>;
|
usage-pages = <HID_USAGE_KEY>;
|
||||||
|
display-name = "Key Repeat";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ kt: key_toggle {
|
/omit-if-no-ref/ kt: key_toggle {
|
||||||
compatible = "zmk,behavior-key-toggle";
|
compatible = "zmk,behavior-key-toggle";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "Key Toggle";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
flavor = "tap-preferred";
|
flavor = "tap-preferred";
|
||||||
tapping-term-ms = <200>;
|
tapping-term-ms = <200>;
|
||||||
bindings = <&mo>, <&kp>;
|
bindings = <&mo>, <&kp>;
|
||||||
|
display-name = "Layer-Tap";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
flavor = "hold-preferred";
|
flavor = "hold-preferred";
|
||||||
tapping-term-ms = <200>;
|
tapping-term-ms = <200>;
|
||||||
bindings = <&kp>, <&kp>;
|
bindings = <&kp>, <&kp>;
|
||||||
|
display-name = "Mod-Tap";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ mo: momentary_layer {
|
/omit-if-no-ref/ mo: momentary_layer {
|
||||||
compatible = "zmk,behavior-momentary-layer";
|
compatible = "zmk,behavior-momentary-layer";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "Momentary Layer";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ none: none {
|
/omit-if-no-ref/ none: none {
|
||||||
compatible = "zmk,behavior-none";
|
compatible = "zmk,behavior-none";
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
|
display-name = "None";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ out: outputs {
|
/omit-if-no-ref/ out: outputs {
|
||||||
compatible = "zmk,behavior-outputs";
|
compatible = "zmk,behavior-outputs";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "Output Selection";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
sys_reset: sysreset {
|
sys_reset: sysreset {
|
||||||
compatible = "zmk,behavior-reset";
|
compatible = "zmk,behavior-reset";
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
|
display-name = "Reset";
|
||||||
};
|
};
|
||||||
|
|
||||||
// Behavior can be invoked on peripherals, so name must be <= 8 characters.
|
// Behavior can be invoked on peripherals, so name must be <= 8 characters.
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
compatible = "zmk,behavior-reset";
|
compatible = "zmk,behavior-reset";
|
||||||
type = <RST_UF2>;
|
type = <RST_UF2>;
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
|
display-name = "Bootloader";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
rgb_ug: rgb_ug {
|
rgb_ug: rgb_ug {
|
||||||
compatible = "zmk,behavior-rgb-underglow";
|
compatible = "zmk,behavior-rgb-underglow";
|
||||||
#binding-cells = <2>;
|
#binding-cells = <2>;
|
||||||
|
display-name = "Underglow";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
release-after-ms = <1000>;
|
release-after-ms = <1000>;
|
||||||
bindings = <&kp>;
|
bindings = <&kp>;
|
||||||
ignore-modifiers;
|
ignore-modifiers;
|
||||||
|
display-name = "Sticky Key";
|
||||||
};
|
};
|
||||||
/omit-if-no-ref/ sl: sticky_layer {
|
/omit-if-no-ref/ sl: sticky_layer {
|
||||||
compatible = "zmk,behavior-sticky-key";
|
compatible = "zmk,behavior-sticky-key";
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
release-after-ms = <1000>;
|
release-after-ms = <1000>;
|
||||||
bindings = <&mo>;
|
bindings = <&mo>;
|
||||||
quick-release;
|
quick-release;
|
||||||
|
display-name = "Sticky Layer";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ to: to_layer {
|
/omit-if-no-ref/ to: to_layer {
|
||||||
compatible = "zmk,behavior-to-layer";
|
compatible = "zmk,behavior-to-layer";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "To Layer";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ tog: toggle_layer {
|
/omit-if-no-ref/ tog: toggle_layer {
|
||||||
compatible = "zmk,behavior-toggle-layer";
|
compatible = "zmk,behavior-toggle-layer";
|
||||||
#binding-cells = <1>;
|
#binding-cells = <1>;
|
||||||
|
display-name = "Toggle Layer";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
/omit-if-no-ref/ trans: transparent {
|
/omit-if-no-ref/ trans: transparent {
|
||||||
compatible = "zmk,behavior-transparent";
|
compatible = "zmk,behavior-transparent";
|
||||||
#binding-cells = <0>;
|
#binding-cells = <0>;
|
||||||
|
display-name = "Transparent";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
6
app/dts/bindings/behaviors/behavior-metadata.yaml
Normal file
6
app/dts/bindings/behaviors/behavior-metadata.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) 2024 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
properties:
|
||||||
|
display-name:
|
||||||
|
type: string
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (c) 2020 The ZMK Contributors
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
include: behavior-metadata.yaml
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
label:
|
label:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (c) 2020 The ZMK Contributors
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
include: behavior-metadata.yaml
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
label:
|
label:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (c) 2020 The ZMK Contributors
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
include: behavior-metadata.yaml
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
label:
|
label:
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -23,6 +23,39 @@
|
||||||
* (Internal use only.)
|
* (Internal use only.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct behavior_parameter_value_metadata {
|
||||||
|
char *display_name;
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint32_t value;
|
||||||
|
struct {
|
||||||
|
int32_t min;
|
||||||
|
int32_t max;
|
||||||
|
} range;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BEHAVIOR_PARAMETER_VALUE_TYPE_NIL = 0,
|
||||||
|
BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE = 1,
|
||||||
|
BEHAVIOR_PARAMETER_VALUE_TYPE_RANGE = 2,
|
||||||
|
BEHAVIOR_PARAMETER_VALUE_TYPE_HID_USAGE = 3,
|
||||||
|
BEHAVIOR_PARAMETER_VALUE_TYPE_LAYER_INDEX = 4,
|
||||||
|
} type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct behavior_parameter_metadata_set {
|
||||||
|
size_t param1_values_len;
|
||||||
|
const struct behavior_parameter_value_metadata *param1_values;
|
||||||
|
|
||||||
|
size_t param2_values_len;
|
||||||
|
const struct behavior_parameter_value_metadata *param2_values;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct behavior_parameter_metadata {
|
||||||
|
size_t sets_len;
|
||||||
|
const struct behavior_parameter_metadata_set *sets;
|
||||||
|
};
|
||||||
|
|
||||||
enum behavior_sensor_binding_process_mode {
|
enum behavior_sensor_binding_process_mode {
|
||||||
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER,
|
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER,
|
||||||
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD,
|
BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD,
|
||||||
|
@ -37,6 +70,10 @@ typedef int (*behavior_sensor_keymap_binding_accept_data_callback_t)(
|
||||||
struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event,
|
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_config *sensor_config, size_t channel_data_size,
|
||||||
const struct zmk_sensor_channel_data channel_data[channel_data_size]);
|
const struct zmk_sensor_channel_data channel_data[channel_data_size]);
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
typedef int (*behavior_get_parameter_metadata_t)(
|
||||||
|
const struct device *behavior, struct behavior_parameter_metadata *param_metadata);
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
enum behavior_locality {
|
enum behavior_locality {
|
||||||
BEHAVIOR_LOCALITY_CENTRAL,
|
BEHAVIOR_LOCALITY_CENTRAL,
|
||||||
|
@ -51,23 +88,54 @@ __subsystem struct behavior_driver_api {
|
||||||
behavior_keymap_binding_callback_t binding_released;
|
behavior_keymap_binding_callback_t binding_released;
|
||||||
behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data;
|
behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data;
|
||||||
behavior_sensor_keymap_binding_process_callback_t sensor_binding_process;
|
behavior_sensor_keymap_binding_process_callback_t sensor_binding_process;
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
behavior_get_parameter_metadata_t get_parameter_metadata;
|
||||||
|
const struct behavior_parameter_metadata *parameter_metadata;
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @endcond
|
* @endcond
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct zmk_behavior_metadata {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
const char *display_name;
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
};
|
||||||
|
|
||||||
struct zmk_behavior_ref {
|
struct zmk_behavior_ref {
|
||||||
const struct device *device;
|
const struct device *device;
|
||||||
|
const struct zmk_behavior_metadata metadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ZMK_BEHAVIOR_REF_DT_NAME(node_id) _CONCAT(zmk_behavior_, DEVICE_DT_NAME_GET(node_id))
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
#define ZMK_BEHAVIOR_METADATA_INITIALIZER(node_id) \
|
||||||
|
{ .display_name = DT_PROP_OR(node_id, display_name, DEVICE_DT_NAME(node_id)), }
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define ZMK_BEHAVIOR_METADATA_INITIALIZER(node_id) \
|
||||||
|
{}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
#define ZMK_BEHAVIOR_REF_INITIALIZER(node_id, _dev) \
|
||||||
|
{ .device = _dev, .metadata = ZMK_BEHAVIOR_METADATA_INITIALIZER(node_id), }
|
||||||
|
|
||||||
|
#define ZMK_BEHAVIOR_REF_DEFINE(name, node_id, _dev) \
|
||||||
|
static const STRUCT_SECTION_ITERABLE(zmk_behavior_ref, name) = \
|
||||||
|
ZMK_BEHAVIOR_REF_INITIALIZER(node_id, _dev)
|
||||||
|
|
||||||
|
#define ZMK_BEHAVIOR_REF_DT_DEFINE(node_id) \
|
||||||
|
ZMK_BEHAVIOR_REF_DEFINE(ZMK_BEHAVIOR_REF_DT_NAME(node_id), node_id, DEVICE_DT_GET(node_id))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers @p node_id as a behavior.
|
* Registers @p node_id as a behavior.
|
||||||
*/
|
*/
|
||||||
#define BEHAVIOR_DEFINE(node_id) \
|
#define BEHAVIOR_DEFINE(node_id) ZMK_BEHAVIOR_REF_DT_DEFINE(node_id)
|
||||||
static const STRUCT_SECTION_ITERABLE(zmk_behavior_ref, \
|
|
||||||
_CONCAT(zmk_behavior_, DEVICE_DT_NAME_GET(node_id))) = { \
|
|
||||||
.device = DEVICE_DT_GET(node_id), \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Like DEVICE_DT_DEFINE(), but also registers the device as a behavior.
|
* @brief Like DEVICE_DT_DEFINE(), but also registers the device as a behavior.
|
||||||
|
@ -89,6 +157,52 @@ struct zmk_behavior_ref {
|
||||||
DEVICE_DT_INST_DEFINE(inst, __VA_ARGS__); \
|
DEVICE_DT_INST_DEFINE(inst, __VA_ARGS__); \
|
||||||
BEHAVIOR_DEFINE(DT_DRV_INST(inst))
|
BEHAVIOR_DEFINE(DT_DRV_INST(inst))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validate a given behavior binding is valid, including parameter validation
|
||||||
|
* if the metadata feature is enablued.
|
||||||
|
*
|
||||||
|
* @param binding The behavior binding to validate.
|
||||||
|
*
|
||||||
|
* @retval 0 if the passed in binding is valid.
|
||||||
|
* @retval -ENODEV if the binding references a non-existant behavior.
|
||||||
|
* @retval -EINVAL if parameters are not valid for the behavior metadata.
|
||||||
|
*/
|
||||||
|
int zmk_behavior_validate_binding(const struct zmk_behavior_binding *binding);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
int zmk_behavior_get_empty_param_metadata(const struct device *dev,
|
||||||
|
struct behavior_parameter_metadata *metadata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Validate a given behavior parameters match the behavior metadata.
|
||||||
|
*
|
||||||
|
* @param metadata The behavior metadata to validate against
|
||||||
|
* @param param1 The first parameter value
|
||||||
|
* @param param2 The second parameter value
|
||||||
|
*
|
||||||
|
* @retval 0 if the passed in parameters are valid.
|
||||||
|
* @retval -ENODEV if metadata is NULL.
|
||||||
|
* @retval -EINVAL if parameters are not valid for the metadata.
|
||||||
|
*/
|
||||||
|
int zmk_behavior_check_params_match_metadata(const struct behavior_parameter_metadata *metadata,
|
||||||
|
uint32_t param1, uint32_t param2);
|
||||||
|
/**
|
||||||
|
* @brief Validate a given behavior parameter matches the behavior metadata parameter values.
|
||||||
|
*
|
||||||
|
* @param values The values to validate against
|
||||||
|
* @param values_len How many values to check
|
||||||
|
* @param param The value to check.
|
||||||
|
*
|
||||||
|
* @retval 0 if the passed in parameter is valid.
|
||||||
|
* @retval -ENODEV if values is NULL.
|
||||||
|
* @retval -EINVAL if parameter is not valid for the value metadata.
|
||||||
|
*/
|
||||||
|
int zmk_behavior_validate_param_values(const struct behavior_parameter_value_metadata *values,
|
||||||
|
size_t values_len, uint32_t param);
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syscall wrapper for zmk_behavior_get_binding().
|
* Syscall wrapper for zmk_behavior_get_binding().
|
||||||
*
|
*
|
||||||
|
@ -120,6 +234,40 @@ static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent
|
||||||
return api->binding_convert_central_state_dependent_params(binding, event);
|
return api->binding_convert_central_state_dependent_params(binding, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determine where the behavior should be run
|
||||||
|
* @param behavior Pointer to the device structure for the driver instance.
|
||||||
|
*
|
||||||
|
* @retval Zero if successful.
|
||||||
|
* @retval Negative errno code if failure.
|
||||||
|
*/
|
||||||
|
__syscall int behavior_get_parameter_metadata(const struct device *behavior,
|
||||||
|
struct behavior_parameter_metadata *param_metadata);
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
z_impl_behavior_get_parameter_metadata(const struct device *behavior,
|
||||||
|
struct behavior_parameter_metadata *param_metadata) {
|
||||||
|
if (behavior == NULL || param_metadata == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct behavior_driver_api *api = (const struct behavior_driver_api *)behavior->api;
|
||||||
|
|
||||||
|
if (api->get_parameter_metadata) {
|
||||||
|
return api->get_parameter_metadata(behavior, param_metadata);
|
||||||
|
} else if (api->parameter_metadata) {
|
||||||
|
*param_metadata = *api->parameter_metadata;
|
||||||
|
} else {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Determine where the behavior should be run
|
* @brief Determine where the behavior should be run
|
||||||
* @param behavior Pointer to the device structure for the driver instance.
|
* @param behavior Pointer to the device structure for the driver instance.
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#define ZMK_BEHAVIOR_TRANSPARENT 1
|
#define ZMK_BEHAVIOR_TRANSPARENT 1
|
||||||
|
|
||||||
struct zmk_behavior_binding {
|
struct zmk_behavior_binding {
|
||||||
char *behavior_dev;
|
const char *behavior_dev;
|
||||||
uint32_t param1;
|
uint32_t param1;
|
||||||
uint32_t param2;
|
uint32_t param2;
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <drivers/behavior.h>
|
#include <drivers/behavior.h>
|
||||||
#include <zmk/behavior.h>
|
#include <zmk/behavior.h>
|
||||||
|
#include <zmk/hid.h>
|
||||||
|
#include <zmk/matrix.h>
|
||||||
|
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
@ -39,6 +41,150 @@ const struct device *z_impl_behavior_get_binding(const char *name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
int zmk_behavior_get_empty_param_metadata(const struct device *dev,
|
||||||
|
struct behavior_parameter_metadata *metadata) {
|
||||||
|
metadata->sets_len = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
static int validate_hid_usage(uint16_t usage_page, uint16_t usage_id) {
|
||||||
|
LOG_DBG("Validate usage %d in page %d", usage_id, usage_page);
|
||||||
|
switch (usage_page) {
|
||||||
|
case HID_USAGE_KEY:
|
||||||
|
if (usage_id == 0 || (usage_id > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE &&
|
||||||
|
usage_id < LEFT_CONTROL && usage_id > RIGHT_GUI)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HID_USAGE_CONSUMER:
|
||||||
|
if (usage_id >
|
||||||
|
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC), (0xFF), (0xFFF))) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WRN("Unsupported HID usage page %d", usage_page);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PARAM_MATCHES 0
|
||||||
|
|
||||||
|
static int check_param_matches_value(const struct behavior_parameter_value_metadata *value_meta,
|
||||||
|
uint32_t param) {
|
||||||
|
switch (value_meta->type) {
|
||||||
|
case BEHAVIOR_PARAMETER_VALUE_TYPE_NIL:
|
||||||
|
if (param == 0) {
|
||||||
|
return PARAM_MATCHES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BEHAVIOR_PARAMETER_VALUE_TYPE_HID_USAGE:
|
||||||
|
if (validate_hid_usage(ZMK_HID_USAGE_PAGE(param), ZMK_HID_USAGE_ID(param)) >= 0) {
|
||||||
|
return PARAM_MATCHES;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BEHAVIOR_PARAMETER_VALUE_TYPE_LAYER_INDEX:
|
||||||
|
if (param >= 0 && param < ZMK_KEYMAP_LEN) {
|
||||||
|
return PARAM_MATCHES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* TODO: Restore with HSV -> RGB refactor
|
||||||
|
case BEHAVIOR_PARAMETER_STANDARD_DOMAIN_HSV:
|
||||||
|
// TODO: No real way to validate? Maybe max brightness?
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE:
|
||||||
|
if (param == value_meta->value) {
|
||||||
|
return PARAM_MATCHES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BEHAVIOR_PARAMETER_VALUE_TYPE_RANGE:
|
||||||
|
if (param >= value_meta->range.min && param <= value_meta->range.max) {
|
||||||
|
return PARAM_MATCHES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_WRN("Unknown type %d", value_meta->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_behavior_validate_param_values(const struct behavior_parameter_value_metadata *values,
|
||||||
|
size_t values_len, uint32_t param) {
|
||||||
|
if (values_len == 0) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int v = 0; v < values_len; v++) {
|
||||||
|
int ret = check_param_matches_value(&values[v], param);
|
||||||
|
if (ret >= 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zmk_behavior_check_params_match_metadata(const struct behavior_parameter_metadata *metadata,
|
||||||
|
uint32_t param1, uint32_t param2) {
|
||||||
|
if (!metadata || metadata->sets_len == 0) {
|
||||||
|
if (!metadata) {
|
||||||
|
LOG_ERR("No metadata to check against");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (param1 == 0 && param2 == 0) ? 0 : -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int s = 0; s < metadata->sets_len; s++) {
|
||||||
|
const struct behavior_parameter_metadata_set *set = &metadata->sets[s];
|
||||||
|
int param1_ret =
|
||||||
|
zmk_behavior_validate_param_values(set->param1_values, set->param1_values_len, param1);
|
||||||
|
int param2_ret =
|
||||||
|
zmk_behavior_validate_param_values(set->param2_values, set->param2_values_len, param2);
|
||||||
|
|
||||||
|
if ((param1_ret >= 0 || (param1_ret == -ENODEV && param1 == 0)) &&
|
||||||
|
(param2_ret >= 0 || (param2_ret == -ENODEV && param2 == 0))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
int zmk_behavior_validate_binding(const struct zmk_behavior_binding *binding) {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev);
|
||||||
|
|
||||||
|
if (!behavior) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct behavior_parameter_metadata metadata;
|
||||||
|
int ret = behavior_get_parameter_metadata(behavior, &metadata);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_WRN("Failed getting metadata for %s: %d", binding->behavior_dev, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zmk_behavior_check_params_match_metadata(&metadata, binding->param1, binding->param2);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_LOG)
|
#if IS_ENABLED(CONFIG_LOG)
|
||||||
static int check_behavior_names(void) {
|
static int check_behavior_names(void) {
|
||||||
// Behavior names must be unique, but we don't have a good way to enforce this
|
// Behavior names must be unique, but we don't have a good way to enforce this
|
||||||
|
|
|
@ -18,6 +18,82 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata no_arg_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Toggle On/Off",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_TOG_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Turn On",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_ON_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Turn OFF",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_OFF_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Increase Brightness",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_INC_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Decrease Brightness",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_DEC_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Cycle Brightness",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_CYCLE_CMD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata one_arg_p1_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Set Brightness",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BL_SET_CMD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata one_arg_p2_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Brightness",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_RANGE,
|
||||||
|
.range =
|
||||||
|
{
|
||||||
|
.min = 0,
|
||||||
|
.max = 255,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set no_args_set = {
|
||||||
|
.param1_values = no_arg_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(no_arg_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set one_args_set = {
|
||||||
|
.param1_values = one_arg_p1_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(one_arg_p1_values),
|
||||||
|
.param2_values = one_arg_p2_values,
|
||||||
|
.param2_values_len = ARRAY_SIZE(one_arg_p2_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set sets[] = {no_args_set, one_args_set};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(sets),
|
||||||
|
.sets = sets,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static int behavior_backlight_init(const struct device *dev) { return 0; }
|
static int behavior_backlight_init(const struct device *dev) { return 0; }
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -89,6 +165,9 @@ static const struct behavior_driver_api behavior_backlight_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_released,
|
||||||
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_backlight_init, NULL, NULL, NULL, POST_KERNEL,
|
BEHAVIOR_DT_INST_DEFINE(0, behavior_backlight_init, NULL, NULL, NULL, POST_KERNEL,
|
||||||
|
|
|
@ -20,6 +20,74 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata no_arg_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Next Profile",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BT_NXT_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Previous Profile",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BT_PRV_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Clear All Profiles",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BT_CLR_ALL_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Clear Selected Profile",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BT_CLR_CMD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set no_args_set = {
|
||||||
|
.param1_values = no_arg_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(no_arg_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata prof_index_param1_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Select Profile",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BT_SEL_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Disconnect Profile",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = BT_DISC_CMD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata prof_index_param2_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Profile",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_RANGE,
|
||||||
|
.range = {.min = 0, .max = ZMK_BLE_PROFILE_COUNT},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set profile_index_metadata_set = {
|
||||||
|
.param1_values = prof_index_param1_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(prof_index_param1_values),
|
||||||
|
.param2_values = prof_index_param2_values,
|
||||||
|
.param2_values_len = ARRAY_SIZE(prof_index_param2_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set metadata_sets[] = {no_args_set,
|
||||||
|
profile_index_metadata_set};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(metadata_sets),
|
||||||
|
.sets = metadata_sets,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event) {
|
struct zmk_behavior_binding_event event) {
|
||||||
switch (binding->param1) {
|
switch (binding->param1) {
|
||||||
|
@ -54,6 +122,9 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
static const struct behavior_driver_api behavior_bt_driver_api = {
|
static const struct behavior_driver_api behavior_bt_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_bt_init, NULL, NULL, NULL, POST_KERNEL,
|
BEHAVIOR_DT_INST_DEFINE(0, behavior_bt_init, NULL, NULL, NULL, POST_KERNEL,
|
||||||
|
|
|
@ -68,6 +68,12 @@ struct behavior_hold_tap_config {
|
||||||
int32_t hold_trigger_key_positions[];
|
int32_t hold_trigger_key_positions[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct behavior_hold_tap_data {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
struct behavior_parameter_metadata_set set;
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
};
|
||||||
|
|
||||||
// this data is specific for each hold-tap
|
// this data is specific for each hold-tap
|
||||||
struct active_hold_tap {
|
struct active_hold_tap {
|
||||||
int32_t position;
|
int32_t position;
|
||||||
|
@ -652,9 +658,52 @@ static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
static int hold_tap_parameter_metadata(const struct device *hold_tap,
|
||||||
|
struct behavior_parameter_metadata *param_metadata) {
|
||||||
|
const struct behavior_hold_tap_config *cfg = hold_tap->config;
|
||||||
|
struct behavior_hold_tap_data *data = hold_tap->data;
|
||||||
|
int err;
|
||||||
|
struct behavior_parameter_metadata child_meta;
|
||||||
|
|
||||||
|
err = behavior_get_parameter_metadata(zmk_behavior_get_binding(cfg->hold_behavior_dev),
|
||||||
|
&child_meta);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_WRN("Failed to get the hold behavior parameter: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_meta.sets_len > 0) {
|
||||||
|
data->set.param1_values = child_meta.sets[0].param1_values;
|
||||||
|
data->set.param1_values_len = child_meta.sets[0].param1_values_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = behavior_get_parameter_metadata(zmk_behavior_get_binding(cfg->tap_behavior_dev),
|
||||||
|
&child_meta);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_WRN("Failed to get the tap behavior parameter: %d", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_meta.sets_len > 0) {
|
||||||
|
data->set.param2_values = child_meta.sets[0].param1_values;
|
||||||
|
data->set.param2_values_len = child_meta.sets[0].param1_values_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
param_metadata->sets = &data->set;
|
||||||
|
param_metadata->sets_len = 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_hold_tap_driver_api = {
|
static const struct behavior_driver_api behavior_hold_tap_driver_api = {
|
||||||
.binding_pressed = on_hold_tap_binding_pressed,
|
.binding_pressed = on_hold_tap_binding_pressed,
|
||||||
.binding_released = on_hold_tap_binding_released,
|
.binding_released = on_hold_tap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.get_parameter_metadata = hold_tap_parameter_metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int position_state_changed_listener(const zmk_event_t *eh) {
|
static int position_state_changed_listener(const zmk_event_t *eh) {
|
||||||
|
@ -791,7 +840,7 @@ static int behavior_hold_tap_init(const struct device *dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KP_INST(n) \
|
#define KP_INST(n) \
|
||||||
static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \
|
static const struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \
|
||||||
.tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \
|
.tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \
|
||||||
.hold_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)), \
|
.hold_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 0)), \
|
||||||
.tap_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 1)), \
|
.tap_behavior_dev = DEVICE_DT_NAME(DT_INST_PHANDLE_BY_IDX(n, bindings, 1)), \
|
||||||
|
@ -807,9 +856,10 @@ static int behavior_hold_tap_init(const struct device *dev) {
|
||||||
.hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \
|
.hold_trigger_key_positions = DT_INST_PROP(n, hold_trigger_key_positions), \
|
||||||
.hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions), \
|
.hold_trigger_key_positions_len = DT_INST_PROP_LEN(n, hold_trigger_key_positions), \
|
||||||
}; \
|
}; \
|
||||||
BEHAVIOR_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, NULL, &behavior_hold_tap_config_##n, \
|
static struct behavior_hold_tap_data behavior_hold_tap_data_##n = {}; \
|
||||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
BEHAVIOR_DT_INST_DEFINE(n, behavior_hold_tap_init, NULL, &behavior_hold_tap_data_##n, \
|
||||||
&behavior_hold_tap_driver_api);
|
&behavior_hold_tap_config_##n, POST_KERNEL, \
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_hold_tap_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,27 @@
|
||||||
|
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata param_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Key",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_HID_USAGE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set param_metadata_set[] = {{
|
||||||
|
.param1_values = param_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(param_values),
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(param_metadata_set),
|
||||||
|
.sets = param_metadata_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int behavior_key_press_init(const struct device *dev) { return 0; };
|
static int behavior_key_press_init(const struct device *dev) { return 0; };
|
||||||
|
|
||||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
|
@ -31,7 +52,12 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_key_press_driver_api = {
|
static const struct behavior_driver_api behavior_key_press_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
|
.binding_released = on_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
};
|
||||||
|
|
||||||
#define KP_INST(n) \
|
#define KP_INST(n) \
|
||||||
BEHAVIOR_DT_INST_DEFINE(n, behavior_key_press_init, NULL, NULL, NULL, POST_KERNEL, \
|
BEHAVIOR_DT_INST_DEFINE(n, behavior_key_press_init, NULL, NULL, NULL, POST_KERNEL, \
|
||||||
|
|
|
@ -31,9 +31,34 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata param_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Key",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_STANDARD,
|
||||||
|
.standard = BEHAVIOR_PARAMETER_STANDARD_DOMAIN_HID_USAGE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set param_metadata_set[] = {{
|
||||||
|
.param1_values = param_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(param_values),
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(param_metadata_set),
|
||||||
|
.sets = param_metadata_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_key_toggle_driver_api = {
|
static const struct behavior_driver_api behavior_key_toggle_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KT_INST(n) \
|
#define KT_INST(n) \
|
||||||
|
|
|
@ -34,6 +34,10 @@ struct behavior_macro_trigger_state {
|
||||||
struct behavior_macro_state {
|
struct behavior_macro_state {
|
||||||
struct behavior_macro_trigger_state release_state;
|
struct behavior_macro_trigger_state release_state;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
struct behavior_parameter_metadata_set set;
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
uint32_t press_bindings_count;
|
uint32_t press_bindings_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -209,9 +213,100 @@ static int on_macro_binding_released(struct zmk_behavior_binding *binding,
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static void assign_values_to_set(enum param_source param_source,
|
||||||
|
struct behavior_parameter_metadata_set *set,
|
||||||
|
const struct behavior_parameter_value_metadata *values,
|
||||||
|
size_t values_len) {
|
||||||
|
if (param_source == PARAM_SOURCE_MACRO_1ST) {
|
||||||
|
set->param1_values = values;
|
||||||
|
set->param1_values_len = values_len;
|
||||||
|
} else {
|
||||||
|
set->param2_values = values;
|
||||||
|
set->param2_values_len = values_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function will dynamically determine the parameter metadata for a particular macro by
|
||||||
|
// inspecting the macro *bindings* to see what behaviors in that list receive the macro parameters,
|
||||||
|
// and then using the metadata from those behaviors for the macro itself.
|
||||||
|
//
|
||||||
|
// Care need be taken, where a behavior in the list takes two parameters, and the macro passes along
|
||||||
|
// a value for the *second* parameter, we need to make sure we find the right metadata set for the
|
||||||
|
// referenced behavior that matches the first parameter.
|
||||||
|
static int get_macro_parameter_metadata(const struct device *macro,
|
||||||
|
struct behavior_parameter_metadata *param_metadata) {
|
||||||
|
const struct behavior_macro_config *cfg = macro->config;
|
||||||
|
struct behavior_macro_state *data = macro->data;
|
||||||
|
struct behavior_macro_trigger_state state = {0};
|
||||||
|
|
||||||
|
for (int i = 0; (i < cfg->count) && (!data->set.param1_values || !data->set.param2_values);
|
||||||
|
i++) {
|
||||||
|
if (handle_control_binding(&state, &cfg->bindings[i]) ||
|
||||||
|
(state.param1_source == PARAM_SOURCE_BINDING &&
|
||||||
|
state.param2_source == PARAM_SOURCE_BINDING)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("checking %d for the given state", i);
|
||||||
|
|
||||||
|
struct behavior_parameter_metadata binding_meta;
|
||||||
|
int err = behavior_get_parameter_metadata(
|
||||||
|
zmk_behavior_get_binding(cfg->bindings[i].behavior_dev), &binding_meta);
|
||||||
|
if (err < 0 || binding_meta.sets_len == 0) {
|
||||||
|
LOG_WRN("Failed to fetch macro binding parameter details %d", err);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both macro parameters get passed to this one entry, use
|
||||||
|
// the metadata for this behavior verbatim.
|
||||||
|
if (state.param1_source != PARAM_SOURCE_BINDING &&
|
||||||
|
state.param2_source != PARAM_SOURCE_BINDING) {
|
||||||
|
param_metadata->sets_len = binding_meta.sets_len;
|
||||||
|
param_metadata->sets = binding_meta.sets;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.param1_source != PARAM_SOURCE_BINDING) {
|
||||||
|
assign_values_to_set(state.param1_source, &data->set,
|
||||||
|
binding_meta.sets[0].param1_values,
|
||||||
|
binding_meta.sets[0].param1_values_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.param2_source != PARAM_SOURCE_BINDING) {
|
||||||
|
// For the param2 metadata, we need to find a set that matches fully bound first
|
||||||
|
// parameter of our macro entry, and use the metadata from that set.
|
||||||
|
for (int s = 0; s < binding_meta.sets_len; s++) {
|
||||||
|
if (zmk_behavior_validate_param_values(binding_meta.sets[s].param1_values,
|
||||||
|
binding_meta.sets[s].param1_values_len,
|
||||||
|
cfg->bindings[i].param1) >= 0) {
|
||||||
|
assign_values_to_set(state.param2_source, &data->set,
|
||||||
|
binding_meta.sets[s].param2_values,
|
||||||
|
binding_meta.sets[s].param2_values_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.param1_source = PARAM_SOURCE_BINDING;
|
||||||
|
state.param2_source = PARAM_SOURCE_BINDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
param_metadata->sets_len = 1;
|
||||||
|
param_metadata->sets = &data->set;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_macro_driver_api = {
|
static const struct behavior_driver_api behavior_macro_driver_api = {
|
||||||
.binding_pressed = on_macro_binding_pressed,
|
.binding_pressed = on_macro_binding_pressed,
|
||||||
.binding_released = on_macro_binding_released,
|
.binding_released = on_macro_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.get_parameter_metadata = get_macro_parameter_metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TRANSFORMED_BEHAVIORS(n) \
|
#define TRANSFORMED_BEHAVIORS(n) \
|
||||||
|
|
|
@ -15,6 +15,27 @@
|
||||||
|
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata param_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Layer",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_LAYER_INDEX,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set param_metadata_set[] = {{
|
||||||
|
.param1_values = param_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(param_values),
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(param_metadata_set),
|
||||||
|
.sets = param_metadata_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
struct behavior_mo_config {};
|
struct behavior_mo_config {};
|
||||||
struct behavior_mo_data {};
|
struct behavior_mo_data {};
|
||||||
|
|
||||||
|
@ -33,7 +54,12 @@ static int mo_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_mo_driver_api = {
|
static const struct behavior_driver_api behavior_mo_driver_api = {
|
||||||
.binding_pressed = mo_keymap_binding_pressed, .binding_released = mo_keymap_binding_released};
|
.binding_pressed = mo_keymap_binding_pressed,
|
||||||
|
.binding_released = mo_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
};
|
||||||
|
|
||||||
static const struct behavior_mo_config behavior_mo_config = {};
|
static const struct behavior_mo_config behavior_mo_config = {};
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
static const struct behavior_driver_api behavior_none_driver_api = {
|
static const struct behavior_driver_api behavior_none_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_none_init, NULL, NULL, NULL, POST_KERNEL,
|
BEHAVIOR_DT_INST_DEFINE(0, behavior_none_init, NULL, NULL, NULL, POST_KERNEL,
|
||||||
|
|
|
@ -20,6 +20,42 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata std_values[] = {
|
||||||
|
{
|
||||||
|
.value = OUT_TOG,
|
||||||
|
.display_name = "Toggle Outputs",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
},
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_USB)
|
||||||
|
{
|
||||||
|
.value = OUT_USB,
|
||||||
|
.display_name = "USB Output",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
},
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_USB)
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
||||||
|
{
|
||||||
|
.value = OUT_BLE,
|
||||||
|
.display_name = "BLE Output",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
},
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BLE)
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set std_set = {
|
||||||
|
.param1_values = std_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(std_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = 1,
|
||||||
|
.sets = &std_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event) {
|
struct zmk_behavior_binding_event event) {
|
||||||
switch (binding->param1) {
|
switch (binding->param1) {
|
||||||
|
@ -40,6 +76,9 @@ static int behavior_out_init(const struct device *dev) { return 0; }
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_outputs_driver_api = {
|
static const struct behavior_driver_api behavior_outputs_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_out_init, NULL, NULL, NULL, POST_KERNEL,
|
BEHAVIOR_DT_INST_DEFINE(0, behavior_out_init, NULL, NULL, NULL, POST_KERNEL,
|
||||||
|
|
|
@ -18,6 +18,119 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata no_arg_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Toggle On/Off",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_TOG_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Turn On",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_ON_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Turn OFF",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_OFF_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Hue Up",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_HUI_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Hue Down",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_HUD_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Saturation Up",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_SAI_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Saturation Down",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_SAD_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Brightness Up",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_BRI_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Brightness Down",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_BRD_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Speed Up",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_SPI_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Speed Down",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_SPD_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Next Effect",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_EFF_CMD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.display_name = "Previous Effect",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_EFR_CMD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set no_args_set = {
|
||||||
|
.param1_values = no_arg_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(no_arg_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
static const struct behavior_parameter_value_metadata hsv_p1_value_metadata_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Set Color",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE,
|
||||||
|
.value = RGB_COLOR_HSB_CMD,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata hsv_p2_value_metadata_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Color",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_STANDARD,
|
||||||
|
.standard = BEHAVIOR_PARAMETER_STANDARD_DOMAIN_HSV,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set hsv_value_metadata_set = {
|
||||||
|
.param1_values = hsv_p1_value_metadata_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(hsv_p1_value_metadata_values),
|
||||||
|
.param_values = hsv_p2_value_metadata_values,
|
||||||
|
.param_values_len = ARRAY_SIZE(hsv_p2_value_metadata_values),
|
||||||
|
};
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set sets[] = {
|
||||||
|
no_args_set,
|
||||||
|
// hsv_value_metadata_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(sets),
|
||||||
|
.sets = sets,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static int behavior_rgb_underglow_init(const struct device *dev) { return 0; }
|
static int behavior_rgb_underglow_init(const struct device *dev) { return 0; }
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -147,6 +260,9 @@ static const struct behavior_driver_api behavior_rgb_underglow_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_released,
|
||||||
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_rgb_underglow_init, NULL, NULL, NULL, POST_KERNEL,
|
BEHAVIOR_DT_INST_DEFINE(0, behavior_rgb_underglow_init, NULL, NULL, NULL, POST_KERNEL,
|
||||||
|
|
|
@ -74,6 +74,9 @@ static const struct behavior_driver_api behavior_soft_off_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_released,
|
||||||
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
.locality = BEHAVIOR_LOCALITY_GLOBAL,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BSO_INST(n) \
|
#define BSO_INST(n) \
|
||||||
|
|
|
@ -188,9 +188,41 @@ static int on_sticky_key_binding_released(struct zmk_behavior_binding *binding,
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static int sticky_key_parameter_domains(const struct device *sk,
|
||||||
|
struct behavior_parameter_metadata *param_metadata) {
|
||||||
|
const struct behavior_sticky_key_config *cfg = sk->config;
|
||||||
|
|
||||||
|
struct behavior_parameter_metadata child_metadata;
|
||||||
|
|
||||||
|
int err = behavior_get_parameter_metadata(zmk_behavior_get_binding(cfg->behavior.behavior_dev),
|
||||||
|
&child_metadata);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_WRN("Failed to get the sticky key bound behavior parameter: %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int s = 0; s < child_metadata.sets_len; s++) {
|
||||||
|
const struct behavior_parameter_metadata_set *set = &child_metadata.sets[s];
|
||||||
|
|
||||||
|
if (set->param2_values_len > 0) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*param_metadata = child_metadata;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_sticky_key_driver_api = {
|
static const struct behavior_driver_api behavior_sticky_key_driver_api = {
|
||||||
.binding_pressed = on_sticky_key_binding_pressed,
|
.binding_pressed = on_sticky_key_binding_pressed,
|
||||||
.binding_released = on_sticky_key_binding_released,
|
.binding_released = on_sticky_key_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.get_parameter_metadata = sticky_key_parameter_domains,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh);
|
static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh);
|
||||||
|
@ -337,7 +369,7 @@ struct behavior_sticky_key_data {};
|
||||||
static struct behavior_sticky_key_data behavior_sticky_key_data;
|
static struct behavior_sticky_key_data behavior_sticky_key_data;
|
||||||
|
|
||||||
#define KP_INST(n) \
|
#define KP_INST(n) \
|
||||||
static struct behavior_sticky_key_config behavior_sticky_key_config_##n = { \
|
static const struct behavior_sticky_key_config behavior_sticky_key_config_##n = { \
|
||||||
.behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, DT_DRV_INST(n)), \
|
.behavior = ZMK_KEYMAP_EXTRACT_BINDING(0, DT_DRV_INST(n)), \
|
||||||
.release_after_ms = DT_INST_PROP(n, release_after_ms), \
|
.release_after_ms = DT_INST_PROP(n, release_after_ms), \
|
||||||
.quick_release = DT_INST_PROP(n, quick_release), \
|
.quick_release = DT_INST_PROP(n, quick_release), \
|
||||||
|
|
|
@ -189,6 +189,9 @@ void behavior_tap_dance_timer_handler(struct k_work *item) {
|
||||||
static const struct behavior_driver_api behavior_tap_dance_driver_api = {
|
static const struct behavior_driver_api behavior_tap_dance_driver_api = {
|
||||||
.binding_pressed = on_tap_dance_binding_pressed,
|
.binding_pressed = on_tap_dance_binding_pressed,
|
||||||
.binding_released = on_tap_dance_binding_released,
|
.binding_released = on_tap_dance_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int tap_dance_position_state_changed_listener(const zmk_event_t *eh);
|
static int tap_dance_position_state_changed_listener(const zmk_event_t *eh);
|
||||||
|
|
|
@ -32,9 +32,34 @@ static int to_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata param_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Layer",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_STANDARD,
|
||||||
|
.standard = BEHAVIOR_PARAMETER_STANDARD_DOMAIN_LAYER_INDEX,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set param_metadata_set[] = {{
|
||||||
|
.param1_values = param_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(param_values),
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(param_metadata_set),
|
||||||
|
.sets = param_metadata_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_to_driver_api = {
|
static const struct behavior_driver_api behavior_to_driver_api = {
|
||||||
.binding_pressed = to_keymap_binding_pressed,
|
.binding_pressed = to_keymap_binding_pressed,
|
||||||
.binding_released = to_keymap_binding_released,
|
.binding_released = to_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, POST_KERNEL,
|
BEHAVIOR_DT_INST_DEFINE(0, behavior_to_init, NULL, NULL, NULL, POST_KERNEL,
|
||||||
|
|
|
@ -34,9 +34,34 @@ static int tog_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
|
static const struct behavior_parameter_value_metadata param_values[] = {
|
||||||
|
{
|
||||||
|
.display_name = "Layer",
|
||||||
|
.type = BEHAVIOR_PARAMETER_VALUE_TYPE_STANDARD,
|
||||||
|
.standard = BEHAVIOR_PARAMETER_STANDARD_DOMAIN_LAYER_INDEX,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata_set param_metadata_set[] = {{
|
||||||
|
.param1_values = param_values,
|
||||||
|
.param1_values_len = ARRAY_SIZE(param_values),
|
||||||
|
}};
|
||||||
|
|
||||||
|
static const struct behavior_parameter_metadata metadata = {
|
||||||
|
.sets_len = ARRAY_SIZE(param_metadata_set),
|
||||||
|
.sets = param_metadata_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_tog_driver_api = {
|
static const struct behavior_driver_api behavior_tog_driver_api = {
|
||||||
.binding_pressed = tog_keymap_binding_pressed,
|
.binding_pressed = tog_keymap_binding_pressed,
|
||||||
.binding_released = tog_keymap_binding_released,
|
.binding_released = tog_keymap_binding_released,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
.parameter_metadata = &metadata,
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct behavior_tog_config behavior_tog_config = {};
|
static const struct behavior_tog_config behavior_tog_config = {};
|
||||||
|
|
Loading…
Add table
Reference in a new issue