mirror of https://github.com/zmkfirmware/zmk.git
feat: Refactor behaviors, sensor to raise behavior_binding_event
This commit is contained in:
parent
ac7f75b859
commit
d88dbd252c
|
|
@ -38,6 +38,7 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_GPIO_KEY_WAKEUP_TRIGGER app PRIVATE src/gpio_key_wakeup_trigger.c)
|
target_sources_ifdef(CONFIG_ZMK_GPIO_KEY_WAKEUP_TRIGGER app PRIVATE src/gpio_key_wakeup_trigger.c)
|
||||||
target_sources(app PRIVATE src/events/activity_state_changed.c)
|
target_sources(app PRIVATE src/events/activity_state_changed.c)
|
||||||
target_sources(app PRIVATE src/events/position_state_changed.c)
|
target_sources(app PRIVATE src/events/position_state_changed.c)
|
||||||
|
target_sources(app PRIVATE src/events/behavior_binding_event.c)
|
||||||
target_sources(app PRIVATE src/events/sensor_event.c)
|
target_sources(app PRIVATE src/events/sensor_event.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
|
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
|
||||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
|
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
|
||||||
|
|
|
||||||
|
|
@ -56,20 +56,8 @@ struct behavior_parameter_metadata {
|
||||||
const struct behavior_parameter_metadata_set *sets;
|
const struct behavior_parameter_metadata_set *sets;
|
||||||
};
|
};
|
||||||
|
|
||||||
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,
|
typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event);
|
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]);
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
typedef int (*behavior_get_parameter_metadata_t)(
|
typedef int (*behavior_get_parameter_metadata_t)(
|
||||||
const struct device *behavior, struct behavior_parameter_metadata *param_metadata);
|
const struct device *behavior, struct behavior_parameter_metadata *param_metadata);
|
||||||
|
|
@ -86,8 +74,7 @@ __subsystem struct behavior_driver_api {
|
||||||
behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params;
|
behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params;
|
||||||
behavior_keymap_binding_callback_t binding_pressed;
|
behavior_keymap_binding_callback_t binding_pressed;
|
||||||
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_keymap_binding_callback_t sensor_binding_process;
|
||||||
behavior_sensor_keymap_binding_process_callback_t sensor_binding_process;
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
behavior_get_parameter_metadata_t get_parameter_metadata;
|
behavior_get_parameter_metadata_t get_parameter_metadata;
|
||||||
const struct behavior_parameter_metadata *parameter_metadata;
|
const struct behavior_parameter_metadata *parameter_metadata;
|
||||||
|
|
@ -371,41 +358,6 @@ static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_bi
|
||||||
return api->binding_released(binding, event);
|
return api->binding_released(binding, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
* @param timestamp Time at which the binding was triggered.
|
|
||||||
*
|
|
||||||
* @retval 0 If successful.
|
|
||||||
* @retval Negative errno code if failure.
|
|
||||||
*/
|
|
||||||
__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_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 = zmk_behavior_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_accept_data == NULL) {
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
* @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 dev Pointer to the device structure for the driver instance.
|
||||||
|
|
@ -418,14 +370,12 @@ static inline int z_impl_behavior_sensor_keymap_binding_accept_data(
|
||||||
// clang-format off
|
// clang-format off
|
||||||
__syscall int behavior_sensor_keymap_binding_process(
|
__syscall int behavior_sensor_keymap_binding_process(
|
||||||
struct zmk_behavior_binding *binding,
|
struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event,
|
struct zmk_behavior_binding_event event);
|
||||||
enum behavior_sensor_binding_process_mode mode);
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding,
|
z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event,
|
struct zmk_behavior_binding_event event) {
|
||||||
enum behavior_sensor_binding_process_mode mode) {
|
|
||||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||||
|
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
|
|
@ -438,9 +388,8 @@ z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *bindi
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return api->sensor_binding_process(binding, event, mode);
|
return api->sensor_binding_process(binding, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -8,29 +8,10 @@
|
||||||
|
|
||||||
#include <zephyr/device.h>
|
#include <zephyr/device.h>
|
||||||
|
|
||||||
|
// TODO: Remove this
|
||||||
|
|
||||||
#define ZMK_BEHAVIOR_OPAQUE 0
|
#define ZMK_BEHAVIOR_OPAQUE 0
|
||||||
#define ZMK_BEHAVIOR_TRANSPARENT 1
|
#include <zmk/events/behavior_binding_event.h>
|
||||||
|
|
||||||
typedef uint16_t zmk_behavior_local_id_t;
|
|
||||||
|
|
||||||
struct zmk_behavior_binding {
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
|
||||||
zmk_behavior_local_id_t local_id;
|
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
|
||||||
const char *behavior_dev;
|
|
||||||
uint32_t param1;
|
|
||||||
uint32_t param2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct zmk_behavior_binding_event {
|
|
||||||
int layer;
|
|
||||||
uint32_t position;
|
|
||||||
int64_t timestamp;
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
|
||||||
uint8_t source;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a const struct device* for a behavior from its @p name field.
|
* @brief Get a const struct device* for a behavior from its @p name field.
|
||||||
*
|
*
|
||||||
|
|
@ -54,6 +35,8 @@ const struct device *zmk_behavior_get_binding(const char *name);
|
||||||
*
|
*
|
||||||
* @retval 0 If successful.
|
* @retval 0 If successful.
|
||||||
* @retval Negative errno code if failure.
|
* @retval Negative errno code if failure.
|
||||||
|
*
|
||||||
|
* Deprecated. Raise the event directly instead.
|
||||||
*/
|
*/
|
||||||
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
||||||
struct zmk_behavior_binding_event event, bool pressed);
|
struct zmk_behavior_binding_event event, bool pressed);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zmk/event_manager.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
|
||||||
|
typedef uint16_t zmk_behavior_local_id_t;
|
||||||
|
|
||||||
|
struct zmk_behavior_binding {
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
||||||
|
zmk_behavior_local_id_t local_id;
|
||||||
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS_IN_BINDINGS)
|
||||||
|
const char *behavior_dev;
|
||||||
|
uint32_t param1;
|
||||||
|
uint32_t param2;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum trigger_type { PRESS, RELEASE, SENSOR };
|
||||||
|
|
||||||
|
struct zmk_behavior_binding_event {
|
||||||
|
const struct zmk_behavior_binding *binding;
|
||||||
|
int layer;
|
||||||
|
uint32_t position;
|
||||||
|
int64_t timestamp;
|
||||||
|
enum trigger_type type;
|
||||||
|
uint8_t source;
|
||||||
|
};
|
||||||
|
|
||||||
|
ZMK_EVENT_DECLARE(zmk_behavior_binding_event);
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zmk/events/position_state_changed.h>
|
#include <zmk/events/position_state_changed.h>
|
||||||
|
#include <zmk/events/behavior_binding_event.h>
|
||||||
#include <zephyr/sys/util.h>
|
#include <zephyr/sys/util.h>
|
||||||
#include <zephyr/devicetree.h>
|
#include <zephyr/devicetree.h>
|
||||||
|
|
||||||
|
|
@ -68,6 +69,13 @@ int zmk_keymap_restore_layer(zmk_keymap_layer_id_t id, zmk_keymap_layer_index_t
|
||||||
int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx);
|
int zmk_keymap_move_layer(zmk_keymap_layer_index_t start_idx, zmk_keymap_layer_index_t dest_idx);
|
||||||
|
|
||||||
int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size);
|
int zmk_keymap_set_layer_name(zmk_keymap_layer_id_t id, const char *name, size_t size);
|
||||||
|
uint8_t zmk_keymap_map_layer_id_to_index(zmk_keymap_layer_id_t layer_id);
|
||||||
|
|
||||||
|
#define LAYER_ID_TO_INDEX(_layer) zmk_keymap_map_layer_id_to_index(_layer)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define LAYER_ID_TO_INDEX(_layer) _layer
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -83,8 +91,9 @@ int zmk_keymap_save_changes(void);
|
||||||
int zmk_keymap_discard_changes(void);
|
int zmk_keymap_discard_changes(void);
|
||||||
int zmk_keymap_reset_settings(void);
|
int zmk_keymap_reset_settings(void);
|
||||||
|
|
||||||
int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
int zmk_keymap_raise_binding_event_at_layer_index(zmk_keymap_layer_id_t layer_index, uint8_t source,
|
||||||
int64_t timestamp);
|
uint32_t position, enum trigger_type type,
|
||||||
|
int64_t timestamp);
|
||||||
|
|
||||||
#define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \
|
#define ZMK_KEYMAP_EXTRACT_BINDING(idx, drv_inst) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,20 @@ struct zmk_sensor_config {
|
||||||
uint16_t triggers_per_rotation;
|
uint16_t triggers_per_rotation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct zmk_sensor_data {
|
||||||
|
struct sensor_value remainder;
|
||||||
|
int num_triggers;
|
||||||
|
};
|
||||||
|
|
||||||
// This struct is also used for data transfer for splits, so any changes to the size, layout, etc
|
// This struct is also used for data transfer for splits, so any changes to the size, layout, etc
|
||||||
// is a breaking change for the split GATT service protocol.
|
// is a breaking change for the split GATT service protocol.
|
||||||
struct zmk_sensor_channel_data {
|
struct zmk_sensor_channel_data {
|
||||||
struct sensor_value value;
|
struct sensor_value value;
|
||||||
enum sensor_channel channel;
|
enum sensor_channel channel;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct zmk_sensor_data *zmk_sensor_get_data(uint32_t sensor_idx);
|
||||||
|
|
||||||
|
void zmk_sensor_set_num_triggers(uint32_t sensor_idx, int num_triggers);
|
||||||
|
|
||||||
|
void zmk_sensor_set_remainder(uint32_t sensor_idx, struct sensor_value remainder);
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||||
|
|
||||||
int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
|
int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event, bool state);
|
struct zmk_behavior_binding_event *event);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,12 @@
|
||||||
|
|
||||||
#include <drivers/behavior.h>
|
#include <drivers/behavior.h>
|
||||||
#include <zmk/behavior.h>
|
#include <zmk/behavior.h>
|
||||||
|
#include <zmk/event_manager.h>
|
||||||
#include <zmk/hid.h>
|
#include <zmk/hid.h>
|
||||||
#include <zmk/matrix.h>
|
#include <zmk/matrix.h>
|
||||||
|
|
||||||
#include <zmk/events/position_state_changed.h>
|
#include <zmk/events/position_state_changed.h>
|
||||||
|
#include <zmk/events/behavior_binding_event.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);
|
||||||
|
|
@ -55,29 +57,59 @@ const struct device *z_impl_behavior_get_binding(const char *name) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Delete this method as part of a breaking release
|
||||||
|
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
||||||
|
struct zmk_behavior_binding_event event, bool pressed) {
|
||||||
|
LOG_DBG("`zmk_behavior_invoke_binding` is deprecated. Please raise a "
|
||||||
|
"`zmk_behavior_binding_event` instead.");
|
||||||
|
return raise_zmk_behavior_binding_event((struct zmk_behavior_binding_event){
|
||||||
|
.binding = src_binding,
|
||||||
|
.layer = event.layer,
|
||||||
|
.position = event.position,
|
||||||
|
.timestamp = event.timestamp,
|
||||||
|
.type = pressed ? PRESS : RELEASE,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
|
.source = event.source,
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Pass the event in as pointers, rather than copying in the struct
|
||||||
|
// Make this change as part of a breaking release
|
||||||
static int invoke_locally(struct zmk_behavior_binding *binding,
|
static int invoke_locally(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event, bool pressed) {
|
struct zmk_behavior_binding_event *event) {
|
||||||
if (pressed) {
|
switch (event->type) {
|
||||||
return behavior_keymap_binding_pressed(binding, event);
|
case PRESS:
|
||||||
} else {
|
return behavior_keymap_binding_pressed(binding, *event);
|
||||||
return behavior_keymap_binding_released(binding, event);
|
case RELEASE:
|
||||||
|
return behavior_keymap_binding_released(binding, *event);
|
||||||
|
case SENSOR:
|
||||||
|
return behavior_sensor_keymap_binding_process(binding, *event);
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
int behavior_listener(const zmk_event_t *eh) {
|
||||||
struct zmk_behavior_binding_event event, bool pressed) {
|
struct zmk_behavior_binding_event *event = as_zmk_behavior_binding_event(eh);
|
||||||
// We want to make a copy of this, since it may be converted from
|
if (event == NULL) {
|
||||||
// relative to absolute before being invoked
|
LOG_ERR("An invalid event was passed as an argument somehow.");
|
||||||
struct zmk_behavior_binding binding = *src_binding;
|
return -EINVAL;
|
||||||
|
|
||||||
const struct device *behavior = zmk_behavior_get_binding(binding.behavior_dev);
|
|
||||||
|
|
||||||
if (!behavior) {
|
|
||||||
LOG_WRN("No behavior assigned to %d on layer %d", event.position, event.layer);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event);
|
const struct device *behavior = zmk_behavior_get_binding(event->binding->behavior_dev);
|
||||||
|
if (!behavior) {
|
||||||
|
LOG_WRN("No behavior assigned to %d on layer %d", event->position, event->layer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copying the behavior is necessary so that
|
||||||
|
* behavior_keymap_binding_convert_central_state_dependent_params (used for e.g. certain
|
||||||
|
* RGB behaviors) does not modify it, e.g. if the behavior is stored in a combo_cfg
|
||||||
|
*/
|
||||||
|
struct zmk_behavior_binding binding = *(event->binding);
|
||||||
|
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, *event);
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err);
|
LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err);
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -92,29 +124,31 @@ int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
|
||||||
|
|
||||||
switch (locality) {
|
switch (locality) {
|
||||||
case BEHAVIOR_LOCALITY_CENTRAL:
|
case BEHAVIOR_LOCALITY_CENTRAL:
|
||||||
return invoke_locally(&binding, event, pressed);
|
return invoke_locally(&binding, event);
|
||||||
case BEHAVIOR_LOCALITY_EVENT_SOURCE:
|
case BEHAVIOR_LOCALITY_EVENT_SOURCE:
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
if (event.source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) {
|
if (event->source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) {
|
||||||
return invoke_locally(&binding, event, pressed);
|
return invoke_locally(&binding, event);
|
||||||
} else {
|
|
||||||
return zmk_split_central_invoke_behavior(event.source, &binding, event, pressed);
|
|
||||||
}
|
}
|
||||||
|
return zmk_split_central_invoke_behavior(event->source, &binding, event);
|
||||||
#else
|
#else
|
||||||
return invoke_locally(&binding, event, pressed);
|
return invoke_locally(&binding, event);
|
||||||
#endif
|
#endif
|
||||||
case BEHAVIOR_LOCALITY_GLOBAL:
|
case BEHAVIOR_LOCALITY_GLOBAL:
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||||
for (int i = 0; i < ZMK_SPLIT_CENTRAL_PERIPHERAL_COUNT; i++) {
|
for (int i = 0; i < ZMK_SPLIT_CENTRAL_PERIPHERAL_COUNT; i++) {
|
||||||
zmk_split_central_invoke_behavior(i, &binding, event, pressed);
|
zmk_split_central_invoke_behavior(i, &binding, event);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return invoke_locally(&binding, event, pressed);
|
return invoke_locally(&binding, event);
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZMK_LISTENER(behavior, behavior_listener);
|
||||||
|
ZMK_SUBSCRIPTION(behavior, zmk_behavior_binding_event);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
||||||
int zmk_behavior_get_empty_param_metadata(const struct device *dev,
|
int zmk_behavior_get_empty_param_metadata(const struct device *dev,
|
||||||
|
|
|
||||||
|
|
@ -30,24 +30,24 @@ static K_WORK_DELAYABLE_DEFINE(queue_work, behavior_queue_process_next);
|
||||||
|
|
||||||
static void behavior_queue_process_next(struct k_work *work) {
|
static void behavior_queue_process_next(struct k_work *work) {
|
||||||
struct q_item item = {.wait = 0};
|
struct q_item item = {.wait = 0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
while (k_msgq_get(&zmk_behavior_queue_msgq, &item, K_NO_WAIT) == 0) {
|
while (k_msgq_get(&zmk_behavior_queue_msgq, &item, K_NO_WAIT) == 0) {
|
||||||
LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1,
|
LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1,
|
||||||
item.binding.param2);
|
item.binding.param2);
|
||||||
|
|
||||||
struct zmk_behavior_binding_event event = {.position = item.position,
|
struct zmk_behavior_binding_event event = {.binding = &item.binding,
|
||||||
|
.position = item.position,
|
||||||
.timestamp = k_uptime_get(),
|
.timestamp = k_uptime_get(),
|
||||||
|
.type = item.press ? PRESS : RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = item.source
|
.source = item.source
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
ret = raise_zmk_behavior_binding_event(event);
|
||||||
if (item.press) {
|
if (ret < 0) {
|
||||||
zmk_behavior_invoke_binding(&item.binding, event, true);
|
LOG_ERR("Error %d occurred while processing behavior in queue.", ret);
|
||||||
} else {
|
|
||||||
zmk_behavior_invoke_binding(&item.binding, event, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("Processing next queued behavior in %dms", item.wait);
|
LOG_DBG("Processing next queued behavior in %dms", item.wait);
|
||||||
|
|
||||||
if (item.wait > 0) {
|
if (item.wait > 0) {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ struct behavior_hold_tap_data {
|
||||||
// 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;
|
||||||
|
uint8_t layer;
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
uint8_t source;
|
uint8_t source;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -260,6 +261,7 @@ static struct active_hold_tap *store_hold_tap(struct zmk_behavior_binding_event
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
active_hold_taps[i].position = event->position;
|
active_hold_taps[i].position = event->position;
|
||||||
|
active_hold_taps[i].layer = event->layer;
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
active_hold_taps[i].source = event->source;
|
active_hold_taps[i].source = event->source;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -402,60 +404,72 @@ static inline const char *decision_moment_str(enum decision_moment decision_mome
|
||||||
}
|
}
|
||||||
|
|
||||||
static int press_hold_binding(struct active_hold_tap *hold_tap) {
|
static int press_hold_binding(struct active_hold_tap *hold_tap) {
|
||||||
|
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
||||||
|
.param1 = hold_tap->param_hold};
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = hold_tap->position,
|
.position = hold_tap->position,
|
||||||
.timestamp = hold_tap->timestamp,
|
.timestamp = hold_tap->timestamp,
|
||||||
|
.layer = hold_tap->layer,
|
||||||
|
.type = PRESS,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = hold_tap->source,
|
.source = hold_tap->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
return raise_zmk_behavior_binding_event(event);
|
||||||
.param1 = hold_tap->param_hold};
|
|
||||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int press_tap_binding(struct active_hold_tap *hold_tap) {
|
static int press_tap_binding(struct active_hold_tap *hold_tap) {
|
||||||
|
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
||||||
|
.param1 = hold_tap->param_tap};
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = hold_tap->position,
|
.position = hold_tap->position,
|
||||||
.timestamp = hold_tap->timestamp,
|
.timestamp = hold_tap->timestamp,
|
||||||
|
.layer = hold_tap->layer,
|
||||||
|
.type = PRESS,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = hold_tap->source,
|
.source = hold_tap->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
LOG_DBG("tapping on layer%d", hold_tap->layer);
|
||||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
|
||||||
.param1 = hold_tap->param_tap};
|
|
||||||
store_last_hold_tapped(hold_tap);
|
store_last_hold_tapped(hold_tap);
|
||||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int release_hold_binding(struct active_hold_tap *hold_tap) {
|
static int release_hold_binding(struct active_hold_tap *hold_tap) {
|
||||||
|
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
||||||
|
.param1 = hold_tap->param_hold};
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = hold_tap->position,
|
.position = hold_tap->position,
|
||||||
.timestamp = hold_tap->timestamp,
|
.timestamp = hold_tap->timestamp,
|
||||||
|
.layer = hold_tap->layer,
|
||||||
|
.type = RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = hold_tap->source,
|
.source = hold_tap->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
|
return raise_zmk_behavior_binding_event(event);
|
||||||
.param1 = hold_tap->param_hold};
|
|
||||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int release_tap_binding(struct active_hold_tap *hold_tap) {
|
static int release_tap_binding(struct active_hold_tap *hold_tap) {
|
||||||
|
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
||||||
|
.param1 = hold_tap->param_tap};
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = hold_tap->position,
|
.position = hold_tap->position,
|
||||||
.timestamp = hold_tap->timestamp,
|
.timestamp = hold_tap->timestamp,
|
||||||
|
.layer = hold_tap->layer,
|
||||||
|
.type = RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = hold_tap->source,
|
.source = hold_tap->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
|
return raise_zmk_behavior_binding_event(event);
|
||||||
.param1 = hold_tap->param_tap};
|
|
||||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int press_binding(struct active_hold_tap *hold_tap) {
|
static int press_binding(struct active_hold_tap *hold_tap) {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
} else {
|
} else {
|
||||||
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding;
|
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding;
|
||||||
}
|
}
|
||||||
return zmk_behavior_invoke_binding(data->pressed_binding, event, true);
|
event.binding = data->pressed_binding;
|
||||||
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
|
static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
|
||||||
|
|
@ -67,7 +68,8 @@ static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding *pressed_binding = data->pressed_binding;
|
struct zmk_behavior_binding *pressed_binding = data->pressed_binding;
|
||||||
data->pressed_binding = NULL;
|
data->pressed_binding = NULL;
|
||||||
int err;
|
int err;
|
||||||
err = zmk_behavior_invoke_binding(pressed_binding, event, false);
|
event.binding = pressed_binding;
|
||||||
|
err = raise_zmk_behavior_binding_event(event);
|
||||||
zmk_hid_masked_modifiers_clear();
|
zmk_hid_masked_modifiers_clear();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
#include "behavior_sensor_rotate_common.h"
|
#include "behavior_sensor_rotate_common.h"
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
||||||
.sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data,
|
|
||||||
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
||||||
|
|
||||||
#define _TRANSFORM_ENTRY(idx, node) \
|
#define _TRANSFORM_ENTRY(idx, node) \
|
||||||
|
|
@ -32,9 +31,8 @@ static const struct behavior_driver_api behavior_sensor_rotate_driver_api = {
|
||||||
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
|
.tap_ms = DT_INST_PROP_OR(n, tap_ms, 5), \
|
||||||
.override_params = false, \
|
.override_params = false, \
|
||||||
}; \
|
}; \
|
||||||
static struct behavior_sensor_rotate_data behavior_sensor_rotate_data_##n = {}; \
|
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_sensor_rotate_config_##n, POST_KERNEL, \
|
||||||
BEHAVIOR_DT_INST_DEFINE( \
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||||
n, NULL, NULL, &behavior_sensor_rotate_data_##n, &behavior_sensor_rotate_config_##n, \
|
&behavior_sensor_rotate_driver_api);
|
||||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_driver_api);
|
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
|
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_INST)
|
||||||
|
|
|
||||||
|
|
@ -4,73 +4,23 @@
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#include <zmk/sensors.h>
|
||||||
#include <zmk/behavior_queue.h>
|
#include <zmk/behavior_queue.h>
|
||||||
#include <zmk/virtual_key_position.h>
|
#include <zmk/virtual_key_position.h>
|
||||||
#include <zmk/events/position_state_changed.h>
|
#include <zmk/events/position_state_changed.h>
|
||||||
|
|
||||||
#include "behavior_sensor_rotate_common.h"
|
#include "behavior_sensor_rotate_common.h"
|
||||||
|
|
||||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
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 = zmk_behavior_get_binding(binding->behavior_dev);
|
|
||||||
struct behavior_sensor_rotate_data *data = dev->data;
|
|
||||||
|
|
||||||
const struct sensor_value value = channel_data[0].value;
|
|
||||||
int triggers;
|
|
||||||
int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
|
||||||
|
|
||||||
// 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][event.layer];
|
|
||||||
|
|
||||||
remainder.val1 += value.val1;
|
|
||||||
remainder.val2 += value.val2;
|
|
||||||
|
|
||||||
if (abs(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][event.layer] = 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][event.layer].val1,
|
|
||||||
data->remainder[sensor_index][event.layer].val2, triggers, binding->param1,
|
|
||||||
binding->param2);
|
|
||||||
|
|
||||||
data->triggers[sensor_index][event.layer] = triggers;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event,
|
struct zmk_behavior_binding_event event) {
|
||||||
enum behavior_sensor_binding_process_mode mode) {
|
|
||||||
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev);
|
||||||
const struct behavior_sensor_rotate_config *cfg = dev->config;
|
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);
|
const int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(event.position);
|
||||||
|
|
||||||
if (mode != BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER) {
|
struct zmk_sensor_data *data = zmk_sensor_get_data(sensor_index);
|
||||||
data->triggers[sensor_index][event.layer] = 0;
|
int triggers = data->num_triggers;
|
||||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
int triggers = data->triggers[sensor_index][event.layer];
|
|
||||||
|
|
||||||
struct zmk_behavior_binding triggered_binding;
|
struct zmk_behavior_binding triggered_binding;
|
||||||
if (triggers > 0) {
|
if (triggers > 0) {
|
||||||
|
|
@ -85,7 +35,7 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
|
||||||
triggered_binding.param1 = binding->param2;
|
triggered_binding.param1 = binding->param2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
|
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
|
||||||
|
|
@ -99,6 +49,5 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
|
||||||
zmk_behavior_queue_add(&event, triggered_binding, true, cfg->tap_ms);
|
zmk_behavior_queue_add(&event, triggered_binding, true, cfg->tap_ms);
|
||||||
zmk_behavior_queue_add(&event, triggered_binding, false, 0);
|
zmk_behavior_queue_add(&event, triggered_binding, false, 0);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
return ZMK_BEHAVIOR_OPAQUE;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
#include <drivers/behavior.h>
|
#include <drivers/behavior.h>
|
||||||
#include <zmk/behavior.h>
|
#include <zmk/behavior.h>
|
||||||
#include <zmk/keymap.h>
|
|
||||||
#include <zmk/sensors.h>
|
|
||||||
|
|
||||||
struct behavior_sensor_rotate_config {
|
struct behavior_sensor_rotate_config {
|
||||||
struct zmk_behavior_binding cw_binding;
|
struct zmk_behavior_binding cw_binding;
|
||||||
|
|
@ -16,15 +14,5 @@ struct behavior_sensor_rotate_config {
|
||||||
bool override_params;
|
bool override_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct behavior_sensor_rotate_data {
|
|
||||||
struct sensor_value remainder[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_LEN];
|
|
||||||
int triggers[ZMK_KEYMAP_SENSORS_LEN][ZMK_KEYMAP_LAYERS_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,
|
int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event,
|
struct zmk_behavior_binding_event event);
|
||||||
enum behavior_sensor_binding_process_mode mode);
|
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
#include "behavior_sensor_rotate_common.h"
|
#include "behavior_sensor_rotate_common.h"
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = {
|
static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api = {
|
||||||
.sensor_binding_accept_data = zmk_behavior_sensor_rotate_common_accept_data,
|
|
||||||
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
.sensor_binding_process = zmk_behavior_sensor_rotate_common_process};
|
||||||
|
|
||||||
#define SENSOR_ROTATE_VAR_INST(n) \
|
#define SENSOR_ROTATE_VAR_INST(n) \
|
||||||
|
|
@ -23,10 +22,8 @@ static const struct behavior_driver_api behavior_sensor_rotate_var_driver_api =
|
||||||
.tap_ms = DT_INST_PROP(n, tap_ms), \
|
.tap_ms = DT_INST_PROP(n, tap_ms), \
|
||||||
.override_params = true, \
|
.override_params = true, \
|
||||||
}; \
|
}; \
|
||||||
static struct behavior_sensor_rotate_data behavior_sensor_rotate_var_data_##n = {}; \
|
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, NULL, &behavior_sensor_rotate_var_config_##n, \
|
||||||
BEHAVIOR_DT_INST_DEFINE(n, NULL, NULL, &behavior_sensor_rotate_var_data_##n, \
|
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
||||||
&behavior_sensor_rotate_var_config_##n, POST_KERNEL, \
|
|
||||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
|
|
||||||
&behavior_sensor_rotate_var_driver_api);
|
&behavior_sensor_rotate_var_driver_api);
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)
|
DT_INST_FOREACH_STATUS_OKAY(SENSOR_ROTATE_VAR_INST)
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ struct behavior_sticky_key_config {
|
||||||
|
|
||||||
struct active_sticky_key {
|
struct active_sticky_key {
|
||||||
uint32_t position;
|
uint32_t position;
|
||||||
|
uint8_t layer;
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
uint8_t source;
|
uint8_t source;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -67,6 +68,7 @@ static struct active_sticky_key *store_sticky_key(struct zmk_behavior_binding_ev
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sticky_key->position = event->position;
|
sticky_key->position = event->position;
|
||||||
|
sticky_key->layer = event->layer;
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
sticky_key->source = event->source;
|
sticky_key->source = event->source;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -108,13 +110,16 @@ static inline int press_sticky_key_behavior(struct active_sticky_key *sticky_key
|
||||||
.param1 = sticky_key->param1,
|
.param1 = sticky_key->param1,
|
||||||
};
|
};
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = sticky_key->position,
|
.position = sticky_key->position,
|
||||||
|
.layer = sticky_key->layer,
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
|
.type = PRESS,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = sticky_key->source,
|
.source = sticky_key->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key,
|
static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_key,
|
||||||
|
|
@ -124,15 +129,18 @@ static inline int release_sticky_key_behavior(struct active_sticky_key *sticky_k
|
||||||
.param1 = sticky_key->param1,
|
.param1 = sticky_key->param1,
|
||||||
};
|
};
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = sticky_key->position,
|
.position = sticky_key->position,
|
||||||
|
.layer = sticky_key->layer,
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
|
.type = RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = sticky_key->source,
|
.source = sticky_key->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
clear_sticky_key(sticky_key);
|
clear_sticky_key(sticky_key);
|
||||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void on_sticky_key_timeout(struct active_sticky_key *sticky_key) {
|
static inline void on_sticky_key_timeout(struct active_sticky_key *sticky_key) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ struct active_tap_dance {
|
||||||
// Tap Dance Data
|
// Tap Dance Data
|
||||||
int counter;
|
int counter;
|
||||||
uint32_t position;
|
uint32_t position;
|
||||||
|
uint8_t layer;
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
uint8_t source;
|
uint8_t source;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -70,6 +71,7 @@ static int new_tap_dance(struct zmk_behavior_binding_event *event,
|
||||||
if (ref_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) {
|
if (ref_dance->position == ZMK_BHV_TAP_DANCE_POSITION_FREE) {
|
||||||
ref_dance->counter = 0;
|
ref_dance->counter = 0;
|
||||||
ref_dance->position = event->position;
|
ref_dance->position = event->position;
|
||||||
|
ref_dance->layer = event->layer;
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
ref_dance->source = event->source;
|
ref_dance->source = event->source;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -113,27 +115,34 @@ static inline int press_tap_dance_behavior(struct active_tap_dance *tap_dance, i
|
||||||
tap_dance->tap_dance_decided = true;
|
tap_dance->tap_dance_decided = true;
|
||||||
struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1];
|
struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1];
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = tap_dance->position,
|
.position = tap_dance->position,
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
|
.layer = tap_dance->layer,
|
||||||
|
.type = PRESS,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = tap_dance->source,
|
.source = tap_dance->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
return zmk_behavior_invoke_binding(&binding, event, true);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance,
|
static inline int release_tap_dance_behavior(struct active_tap_dance *tap_dance,
|
||||||
int64_t timestamp) {
|
int64_t timestamp) {
|
||||||
struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1];
|
struct zmk_behavior_binding binding = tap_dance->config->behaviors[tap_dance->counter - 1];
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &binding,
|
||||||
.position = tap_dance->position,
|
.position = tap_dance->position,
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
|
.layer = tap_dance->layer,
|
||||||
|
.type = RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = tap_dance->source,
|
.source = tap_dance->source,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
clear_tap_dance(tap_dance);
|
clear_tap_dance(tap_dance);
|
||||||
return zmk_behavior_invoke_binding(&binding, event, false);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding,
|
static int on_tap_dance_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <zephyr/device.h>
|
#include <zephyr/device.h>
|
||||||
#include <drivers/behavior.h>
|
#include <drivers/behavior.h>
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zmk/keymap.h>
|
||||||
|
|
||||||
#include <zmk/behavior.h>
|
#include <zmk/behavior.h>
|
||||||
|
|
||||||
|
|
@ -16,19 +17,20 @@ 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)
|
||||||
|
|
||||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
static int on_keymap_binding_trigger(struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event) {
|
struct zmk_behavior_binding_event event) {
|
||||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
// Avoid uint8_t overflow resulting in an infinite loop
|
||||||
}
|
if (LAYER_ID_TO_INDEX(event.layer) == 0) {
|
||||||
|
return 0;
|
||||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
}
|
||||||
struct zmk_behavior_binding_event event) {
|
return zmk_keymap_raise_binding_event_at_layer_index(LAYER_ID_TO_INDEX(event.layer) - 1,
|
||||||
return ZMK_BEHAVIOR_TRANSPARENT;
|
event.source, event.position, event.type,
|
||||||
|
event.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct behavior_driver_api behavior_transparent_driver_api = {
|
static const struct behavior_driver_api behavior_transparent_driver_api = {
|
||||||
.binding_pressed = on_keymap_binding_pressed,
|
.binding_pressed = on_keymap_binding_trigger,
|
||||||
.binding_released = on_keymap_binding_released,
|
.binding_released = on_keymap_binding_trigger,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
.get_parameter_metadata = zmk_behavior_get_empty_param_metadata,
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
#endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
|
||||||
|
|
|
||||||
|
|
@ -281,8 +281,11 @@ static int release_pressed_keys() {
|
||||||
static inline int press_combo_behavior(int combo_idx, const struct combo_cfg *combo,
|
static inline int press_combo_behavior(int combo_idx, const struct combo_cfg *combo,
|
||||||
int32_t timestamp) {
|
int32_t timestamp) {
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &combo->behavior,
|
||||||
|
.layer = 0, // Combos don't have layers, so their layer is set to be the base layer.
|
||||||
.position = ZMK_VIRTUAL_KEY_POSITION_COMBO(combo_idx),
|
.position = ZMK_VIRTUAL_KEY_POSITION_COMBO(combo_idx),
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
|
.type = PRESS,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -290,20 +293,23 @@ static inline int press_combo_behavior(int combo_idx, const struct combo_cfg *co
|
||||||
|
|
||||||
last_combo_timestamp = timestamp;
|
last_combo_timestamp = timestamp;
|
||||||
|
|
||||||
return zmk_behavior_invoke_binding(&combo->behavior, event, true);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int release_combo_behavior(int combo_idx, const struct combo_cfg *combo,
|
static inline int release_combo_behavior(int combo_idx, const struct combo_cfg *combo,
|
||||||
int32_t timestamp) {
|
int32_t timestamp) {
|
||||||
struct zmk_behavior_binding_event event = {
|
struct zmk_behavior_binding_event event = {
|
||||||
|
.binding = &combo->behavior,
|
||||||
|
.layer = 0, // Combos don't have layers, so their layer is set to be the base layer.
|
||||||
.position = ZMK_VIRTUAL_KEY_POSITION_COMBO(combo_idx),
|
.position = ZMK_VIRTUAL_KEY_POSITION_COMBO(combo_idx),
|
||||||
.timestamp = timestamp,
|
.timestamp = timestamp,
|
||||||
|
.type = RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
return zmk_behavior_invoke_binding(&combo->behavior, event, false);
|
return raise_zmk_behavior_binding_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void move_pressed_keys_to_active_combo(struct active_combo *active_combo) {
|
static void move_pressed_keys_to_active_combo(struct active_combo *active_combo) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zmk/events/behavior_binding_event.h>
|
||||||
|
|
||||||
|
ZMK_EVENT_IMPL(zmk_behavior_binding_event);
|
||||||
167
app/src/keymap.c
167
app/src/keymap.c
|
|
@ -22,6 +22,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#include <zmk/events/position_state_changed.h>
|
#include <zmk/events/position_state_changed.h>
|
||||||
#include <zmk/events/layer_state_changed.h>
|
#include <zmk/events/layer_state_changed.h>
|
||||||
#include <zmk/events/sensor_event.h>
|
#include <zmk/events/sensor_event.h>
|
||||||
|
#include <zmk/events/behavior_binding_event.h>
|
||||||
|
|
||||||
static zmk_keymap_layers_state_t _zmk_keymap_layer_locks = 0;
|
static zmk_keymap_layers_state_t _zmk_keymap_layer_locks = 0;
|
||||||
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
static zmk_keymap_layers_state_t _zmk_keymap_layer_state = 0;
|
||||||
|
|
@ -111,7 +112,7 @@ static struct zmk_behavior_binding
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
uint8_t zmk_keymap_map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
||||||
for (uint8_t i = 0; i < ZMK_KEYMAP_LAYERS_LEN; i++) {
|
for (uint8_t i = 0; i < ZMK_KEYMAP_LAYERS_LEN; i++) {
|
||||||
if (keymap_layer_orders[i] == layer_id) {
|
if (keymap_layer_orders[i] == layer_id) {
|
||||||
return i;
|
return i;
|
||||||
|
|
@ -122,12 +123,10 @@ uint8_t map_layer_id_to_index(zmk_keymap_layer_id_t layer_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LAYER_INDEX_TO_ID(_layer) keymap_layer_orders[_layer]
|
#define LAYER_INDEX_TO_ID(_layer) keymap_layer_orders[_layer]
|
||||||
#define LAYER_ID_TO_INDEX(_layer) map_layer_id_to_index(_layer)
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define LAYER_INDEX_TO_ID(_layer) _layer
|
#define LAYER_INDEX_TO_ID(_layer) _layer
|
||||||
#define LAYER_ID_TO_INDEX(_layer) _layer
|
|
||||||
|
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_LAYER_REORDERING)
|
||||||
|
|
||||||
|
|
@ -699,146 +698,82 @@ int zmk_keymap_reset_settings(void) { return -ENOTSUP; }
|
||||||
|
|
||||||
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
#endif // IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
int zmk_keymap_apply_position_state(uint8_t source, zmk_keymap_layer_id_t layer_id,
|
int zmk_keymap_raise_binding_event_at_layer_index(zmk_keymap_layer_id_t layer_index, uint8_t source,
|
||||||
uint32_t position, bool pressed, int64_t timestamp) {
|
uint32_t position, enum trigger_type type,
|
||||||
const struct zmk_behavior_binding *binding =
|
int64_t timestamp) {
|
||||||
zmk_keymap_get_layer_binding_at_idx(layer_id, position);
|
|
||||||
struct zmk_behavior_binding_event event = {
|
|
||||||
.layer = layer_id,
|
|
||||||
.position = position,
|
|
||||||
.timestamp = timestamp,
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
|
||||||
.source = source,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
LOG_DBG("layer_id: %d position: %d, binding name: %s", layer_id, position,
|
|
||||||
binding->behavior_dev);
|
|
||||||
|
|
||||||
return zmk_behavior_invoke_binding(binding, event, pressed);
|
|
||||||
}
|
|
||||||
|
|
||||||
int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
|
||||||
int64_t timestamp) {
|
|
||||||
if (pressed) {
|
|
||||||
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use int here to be sure we don't loop layer_idx back to UINT8_MAX
|
// We use int here to be sure we don't loop layer_idx back to UINT8_MAX
|
||||||
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1;
|
for (int layer_idx = layer_index; layer_idx >= 0; layer_idx--) {
|
||||||
layer_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default); layer_idx--) {
|
zmk_keymap_layer_id_t candidate_layer = LAYER_INDEX_TO_ID(layer_idx);
|
||||||
zmk_keymap_layer_id_t layer_id = LAYER_INDEX_TO_ID(layer_idx);
|
|
||||||
|
|
||||||
if (layer_id == ZMK_KEYMAP_LAYER_ID_INVAL) {
|
if (candidate_layer >= ZMK_KEYMAP_LAYERS_LEN) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (zmk_keymap_layer_active_with_state(layer_id,
|
if (zmk_keymap_layer_active_with_state(candidate_layer,
|
||||||
zmk_keymap_active_behavior_layer[position])) {
|
zmk_keymap_active_behavior_layer[position]) ||
|
||||||
int ret =
|
(zmk_keymap_layer_active(candidate_layer) && (position >= ZMK_KEYMAP_LEN))) {
|
||||||
zmk_keymap_apply_position_state(source, layer_id, position, pressed, timestamp);
|
const struct zmk_behavior_binding *binding;
|
||||||
if (ret > 0) {
|
if (position >= ZMK_KEYMAP_LEN) {
|
||||||
LOG_DBG("behavior processing to continue to next layer");
|
#if ZMK_KEYMAP_HAS_SENSORS
|
||||||
continue;
|
int sensor_index = ZMK_SENSOR_POSITION_FROM_VIRTUAL_KEY_POSITION(position);
|
||||||
} else if (ret < 0) {
|
binding = &zmk_sensor_keymap[candidate_layer][sensor_index];
|
||||||
LOG_DBG("Behavior returned error: %d", ret);
|
if (!zmk_behavior_get_binding(binding->behavior_dev)) {
|
||||||
return ret;
|
LOG_DBG("No behavior assigned to sensor index %d on layer %d", sensor_index,
|
||||||
|
candidate_layer);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LOG_DBG("layer_id: %d sensor_index: %d, binding name: %s", candidate_layer,
|
||||||
|
sensor_index, binding->behavior_dev);
|
||||||
|
#else
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
return ret;
|
binding = zmk_keymap_get_layer_binding_at_idx(candidate_layer, position);
|
||||||
|
LOG_DBG("layer_id: %d position: %d, binding name: %s", candidate_layer, position,
|
||||||
|
binding->behavior_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return raise_zmk_behavior_binding_event((struct zmk_behavior_binding_event){
|
||||||
|
.binding = binding,
|
||||||
|
.layer = candidate_layer,
|
||||||
|
.position = position,
|
||||||
|
.timestamp = timestamp,
|
||||||
|
.type = type,
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
|
.source = source,
|
||||||
|
#endif
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ZMK_KEYMAP_HAS_SENSORS
|
static int zmk_keymap_position_state_changed(uint8_t source, uint32_t position, bool pressed,
|
||||||
int zmk_keymap_sensor_event(uint8_t sensor_index,
|
int64_t timestamp) {
|
||||||
const struct zmk_sensor_channel_data *channel_data,
|
if (pressed) {
|
||||||
size_t channel_data_size, int64_t timestamp) {
|
zmk_keymap_active_behavior_layer[position] = _zmk_keymap_layer_state;
|
||||||
bool opaque_response = false;
|
|
||||||
|
|
||||||
for (int layer_idx = ZMK_KEYMAP_LAYERS_LEN - 1; layer_idx >= 0; layer_idx--) {
|
|
||||||
uint8_t layer_id = LAYER_INDEX_TO_ID(layer_idx);
|
|
||||||
|
|
||||||
if (layer_id >= ZMK_KEYMAP_LAYERS_LEN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer_id][sensor_index];
|
|
||||||
|
|
||||||
LOG_DBG("layer idx: %d, layer id: %d sensor_index: %d, binding name: %s", layer_idx,
|
|
||||||
layer_id, sensor_index, binding->behavior_dev);
|
|
||||||
|
|
||||||
const struct device *behavior = zmk_behavior_get_binding(binding->behavior_dev);
|
|
||||||
if (!behavior) {
|
|
||||||
LOG_DBG("No behavior assigned to %d on layer %d", sensor_index, layer_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct zmk_behavior_binding_event event = {
|
|
||||||
.layer = layer_id,
|
|
||||||
.position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index),
|
|
||||||
.timestamp = timestamp,
|
|
||||||
};
|
|
||||||
|
|
||||||
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_idx >= LAYER_ID_TO_INDEX(_zmk_keymap_layer_default) &&
|
|
||||||
zmk_keymap_layer_active(layer_id))
|
|
||||||
? 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
enum trigger_type type = pressed ? PRESS : RELEASE;
|
||||||
|
|
||||||
return 0;
|
int ret = zmk_keymap_raise_binding_event_at_layer_index(ZMK_KEYMAP_LAYERS_LEN - 1, source,
|
||||||
|
position, type, timestamp);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_DBG("Behavior returned error: %d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
|
||||||
|
|
||||||
int keymap_listener(const zmk_event_t *eh) {
|
int keymap_listener(const zmk_event_t *eh) {
|
||||||
const struct zmk_position_state_changed *pos_ev;
|
const struct zmk_position_state_changed *pos_ev;
|
||||||
if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) {
|
if ((pos_ev = as_zmk_position_state_changed(eh)) != NULL) {
|
||||||
return zmk_keymap_position_state_changed(pos_ev->source, pos_ev->position, pos_ev->state,
|
return zmk_keymap_position_state_changed(pos_ev->source, pos_ev->position, pos_ev->state,
|
||||||
pos_ev->timestamp);
|
pos_ev->timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#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_event(sensor_ev->sensor_index, sensor_ev->channel_data,
|
|
||||||
sensor_ev->channel_data_size, sensor_ev->timestamp);
|
|
||||||
}
|
|
||||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
|
||||||
|
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZMK_LISTENER(keymap, keymap_listener);
|
ZMK_LISTENER(keymap, keymap_listener);
|
||||||
ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed);
|
ZMK_SUBSCRIPTION(keymap, zmk_position_state_changed);
|
||||||
|
|
||||||
#if ZMK_KEYMAP_HAS_SENSORS
|
|
||||||
ZMK_SUBSCRIPTION(keymap, zmk_sensor_event);
|
|
||||||
#endif /* ZMK_KEYMAP_HAS_SENSORS */
|
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
#if IS_ENABLED(CONFIG_ZMK_KEYMAP_SETTINGS_STORAGE)
|
||||||
|
|
||||||
static int keymap_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
static int keymap_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,11 @@ static int ip_behaviors_handle_event(const struct device *dev, struct input_even
|
||||||
for (size_t i = 0; i < cfg->size; i++) {
|
for (size_t i = 0; i < cfg->size; i++) {
|
||||||
if (cfg->codes[i] == event->code) {
|
if (cfg->codes[i] == event->code) {
|
||||||
struct zmk_behavior_binding_event behavior_event = {
|
struct zmk_behavior_binding_event behavior_event = {
|
||||||
|
.binding = &cfg->bindings[i],
|
||||||
.position = ZMK_VIRTUAL_KEY_POSITION_BEHAVIOR_INPUT_PROCESSOR(
|
.position = ZMK_VIRTUAL_KEY_POSITION_BEHAVIOR_INPUT_PROCESSOR(
|
||||||
state->input_device_index, cfg->index),
|
state->input_device_index, cfg->index),
|
||||||
.timestamp = k_uptime_get(),
|
.timestamp = k_uptime_get(),
|
||||||
|
.type = event->value ? PRESS : RELEASE,
|
||||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||||
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
.source = ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -52,7 +54,7 @@ static int ip_behaviors_handle_event(const struct device *dev, struct input_even
|
||||||
LOG_DBG("FOUND A MATCHING CODE, invoke %s for position %d with %d listeners",
|
LOG_DBG("FOUND A MATCHING CODE, invoke %s for position %d with %d listeners",
|
||||||
cfg->bindings[i].behavior_dev, behavior_event.position,
|
cfg->bindings[i].behavior_dev, behavior_event.position,
|
||||||
ZMK_INPUT_LISTENERS_LEN);
|
ZMK_INPUT_LISTENERS_LEN);
|
||||||
int ret = zmk_behavior_invoke_binding(&cfg->bindings[i], behavior_event, event->value);
|
int ret = raise_zmk_behavior_binding_event(behavior_event);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#include <zmk/sensors.h>
|
#include <zmk/sensors.h>
|
||||||
#include <zmk/event_manager.h>
|
#include <zmk/event_manager.h>
|
||||||
#include <zmk/events/sensor_event.h>
|
#include <zmk/events/sensor_event.h>
|
||||||
|
#include <zmk/events/position_state_changed.h>
|
||||||
|
#include <zmk/virtual_key_position.h>
|
||||||
|
#include <zmk/behavior.h>
|
||||||
|
#include <zmk/keymap.h>
|
||||||
|
|
||||||
#if ZMK_KEYMAP_HAS_SENSORS
|
#if ZMK_KEYMAP_HAS_SENSORS
|
||||||
|
|
||||||
|
|
@ -52,6 +56,26 @@ static struct zmk_sensor_config configs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sensors_item_cfg sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
|
static struct sensors_item_cfg sensors[] = {LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, (, ), 0)};
|
||||||
|
struct zmk_sensor_data sensor_data[ZMK_KEYMAP_SENSORS_LEN] = {};
|
||||||
|
|
||||||
|
struct zmk_sensor_data *zmk_sensor_get_data(uint32_t sensor_idx) {
|
||||||
|
if (sensor_idx >= ZMK_KEYMAP_SENSORS_LEN) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return &sensor_data[sensor_idx];
|
||||||
|
};
|
||||||
|
|
||||||
|
void zmk_sensor_set_num_triggers(uint32_t sensor_idx, int num_triggers) {
|
||||||
|
if (sensor_idx < ZMK_KEYMAP_SENSORS_LEN) {
|
||||||
|
sensor_data[sensor_idx].num_triggers = num_triggers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void zmk_sensor_set_remainder(uint32_t sensor_idx, struct sensor_value remainder) {
|
||||||
|
if (sensor_idx < ZMK_KEYMAP_SENSORS_LEN) {
|
||||||
|
sensor_data[sensor_idx].remainder = remainder;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static ATOMIC_DEFINE(pending_sensors, ZMK_KEYMAP_SENSORS_LEN);
|
static ATOMIC_DEFINE(pending_sensors, ZMK_KEYMAP_SENSORS_LEN);
|
||||||
|
|
||||||
|
|
@ -118,6 +142,49 @@ static void zmk_sensors_trigger_handler(const struct device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (!IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL))
|
||||||
|
|
||||||
|
int sensor_listener(const zmk_event_t *eh) {
|
||||||
|
const struct zmk_sensor_event *sensor_ev = as_zmk_sensor_event(eh);
|
||||||
|
if (sensor_ev == NULL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
uint32_t sensor_index = sensor_ev->sensor_index;
|
||||||
|
const struct sensor_value value = sensor_ev->channel_data[0].value;
|
||||||
|
struct zmk_sensor_data *data = zmk_sensor_get_data(sensor_index);
|
||||||
|
const struct zmk_sensor_config *sensor_config = zmk_sensors_get_config_at_index(sensor_index);
|
||||||
|
data->remainder.val1 += value.val1;
|
||||||
|
data->remainder.val2 += value.val2;
|
||||||
|
|
||||||
|
if (data->remainder.val2 >= 1000000 || data->remainder.val2 <= 1000000) {
|
||||||
|
data->remainder.val1 += data->remainder.val2 / 1000000;
|
||||||
|
data->remainder.val2 %= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int trigger_degrees = 360 / sensor_config->triggers_per_rotation;
|
||||||
|
int triggers = data->remainder.val1 / trigger_degrees;
|
||||||
|
data->remainder.val1 %= trigger_degrees;
|
||||||
|
zmk_sensor_set_remainder(sensor_index, data->remainder);
|
||||||
|
zmk_sensor_set_num_triggers(sensor_index, triggers);
|
||||||
|
|
||||||
|
LOG_DBG("val1: %d, val2: %d, remainder: %d/%d triggers: %d", value.val1, value.val2,
|
||||||
|
data->remainder.val1, data->remainder.val2, triggers);
|
||||||
|
|
||||||
|
int position = ZMK_VIRTUAL_KEY_POSITION_SENSOR(sensor_index);
|
||||||
|
// Source is set to local for the time being, to be improved in the future
|
||||||
|
int ret = zmk_keymap_raise_binding_event_at_layer_index(ZMK_KEYMAP_LAYERS_LEN - 1,
|
||||||
|
ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL,
|
||||||
|
position, SENSOR, sensor_ev->timestamp);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_DBG("Behavior returned error: %d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZMK_LISTENER(sensors, sensor_listener);
|
||||||
|
ZMK_SUBSCRIPTION(sensors, zmk_sensor_event);
|
||||||
|
#endif
|
||||||
|
|
||||||
static void zmk_sensors_init_item(uint8_t i) {
|
static void zmk_sensors_init_item(uint8_t i) {
|
||||||
LOG_DBG("Init sensor at index %d", i);
|
LOG_DBG("Init sensor at index %d", i);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ int zmk_split_transport_central_peripheral_event_handler(
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
|
int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_binding *binding,
|
||||||
struct zmk_behavior_binding_event event, bool state) {
|
struct zmk_behavior_binding_event *event) {
|
||||||
if (!active_transport || !active_transport->api || !active_transport->api->send_command) {
|
if (!active_transport || !active_transport->api || !active_transport->api->send_command) {
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
@ -93,12 +93,22 @@ int zmk_split_central_invoke_behavior(uint8_t source, struct zmk_behavior_bindin
|
||||||
{
|
{
|
||||||
.param1 = binding->param1,
|
.param1 = binding->param1,
|
||||||
.param2 = binding->param2,
|
.param2 = binding->param2,
|
||||||
.position = event.position,
|
.position = event->position,
|
||||||
.event_source = event.source,
|
.event_source = event->source,
|
||||||
.state = state ? 1 : 0,
|
.state = (event->type == PRESS) ? 1 : 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
switch (event->type) {
|
||||||
|
case PRESS:
|
||||||
|
command.data.invoke_behavior.state = 1;
|
||||||
|
break;
|
||||||
|
case RELEASE:
|
||||||
|
command.data.invoke_behavior.state = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
const size_t payload_dev_size = sizeof(command.data.invoke_behavior.behavior_dev);
|
const size_t payload_dev_size = sizeof(command.data.invoke_behavior.behavior_dev);
|
||||||
if (strlcpy(command.data.invoke_behavior.behavior_dev, binding->behavior_dev,
|
if (strlcpy(command.data.invoke_behavior.behavior_dev, binding->behavior_dev,
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
s/.*hid_listener_keycode/kp/p
|
s/.*hid_listener_keycode/kp/p
|
||||||
s/.*keymap_apply_position_state/pos_state/p
|
s/.*raise_binding_event_at_layer_index/binding_ev/p
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
pos_state: layer_id: 0 position: 0, binding name: abc_macro
|
binding_ev: layer_id: 0 position: 0, binding name: abc_macro
|
||||||
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
kp_pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||||
pos_state: layer_id: 0 position: 0, binding name: abc_macro
|
binding_ev: layer_id: 0 position: 0, binding name: abc_macro
|
||||||
pos_state: layer_id: 0 position: 1, binding name: momentary_layer
|
binding_ev: layer_id: 0 position: 1, binding name: momentary_layer
|
||||||
pos_state: layer_id: 0 position: 1, binding name: momentary_layer
|
binding_ev: layer_id: 0 position: 1, binding name: momentary_layer
|
||||||
kp_released: 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 0x05 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_released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,28 @@
|
||||||
#include <dt-bindings/zmk/kscan_mock.h>
|
#include <dt-bindings/zmk/kscan_mock.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
|
behaviors {
|
||||||
|
ht_bal: behavior_hold_tap_balanced {
|
||||||
|
compatible = "zmk,behavior-hold-tap";
|
||||||
|
#binding-cells = <2>;
|
||||||
|
flavor = "balanced";
|
||||||
|
tapping-term-ms = <300>;
|
||||||
|
bindings = <&kp>, <&trans>;
|
||||||
|
};
|
||||||
|
};
|
||||||
keymap {
|
keymap {
|
||||||
compatible = "zmk,keymap";
|
compatible = "zmk,keymap";
|
||||||
|
|
||||||
default_layer {
|
default_layer {
|
||||||
bindings = <
|
bindings = <
|
||||||
&trans &mo 1
|
&trans &mo 1
|
||||||
&kp A &none>;
|
&kp A &kp B>;
|
||||||
};
|
};
|
||||||
|
|
||||||
lower_layer {
|
lower_layer {
|
||||||
bindings = <
|
bindings = <
|
||||||
&trans &trans
|
&trans &trans
|
||||||
&trans &kp A>;
|
&trans &ht_bal C 0>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
s/.*hid_listener_keycode/kp/p
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
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 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
kp_released: usage_page 0x07 keycode 0x06 implicit_mods 0x00 explicit_mods 0x00
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <dt-bindings/zmk/keys.h>
|
||||||
|
#include <behaviors.dtsi>
|
||||||
|
#include <dt-bindings/zmk/kscan_mock.h>
|
||||||
|
#include "../behavior_keymap.dtsi"
|
||||||
|
|
||||||
|
&kscan {
|
||||||
|
events = <
|
||||||
|
ZMK_MOCK_PRESS(0,1,10)
|
||||||
|
ZMK_MOCK_PRESS(1,1,10)
|
||||||
|
ZMK_MOCK_RELEASE(1,1,10)
|
||||||
|
ZMK_MOCK_PRESS(1,1,400)
|
||||||
|
ZMK_MOCK_RELEASE(1,1,400)
|
||||||
|
ZMK_MOCK_RELEASE(0,1,10)
|
||||||
|
>;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue