diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index bc135fd3..2bdffea5 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -27,6 +27,7 @@ typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_bin int64_t timestamp); __subsystem struct behavior_driver_api { + behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params; behavior_keymap_binding_callback_t binding_pressed; behavior_keymap_binding_callback_t binding_released; behavior_sensor_keymap_binding_callback_t sensor_binding_triggered; @@ -35,6 +36,30 @@ __subsystem struct behavior_driver_api { * @endcond */ +/** + * @brief Handle the keymap binding which needs to be converted from relative "toggle" to absolute + * "turn on" + * @param binding Pointer to the details so of the binding + * @param event The event that triggered use of the binding + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int behavior_keymap_binding_convert_central_state_dependent_params( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); + +static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent_params( + struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; + + if (api->binding_convert_central_state_dependent_params == NULL) { + return 0; + } + + return api->binding_convert_central_state_dependent_params(binding, event); +} + /** * @brief Handle the keymap binding being pressed * @param dev Pointer to the device structure for the driver instance. diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index 659cde56..3ce1e747 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -18,6 +18,22 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) +static int +on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *ext_power = device_get_binding("EXT_POWER"); + if (ext_power == NULL) { + LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1); + return -EIO; + } + + if (binding->param1 == EXT_POWER_TOGGLE_CMD) { + binding->param1 = ext_power_get(ext_power) > 0 ? EXT_POWER_OFF_CMD : EXT_POWER_ON_CMD; + } + + return 0; +} + static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *ext_power = device_get_binding("EXT_POWER"); @@ -51,6 +67,8 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static int behavior_ext_power_init(const struct device *dev) { return 0; }; static const struct behavior_driver_api behavior_ext_power_driver_api = { + .binding_convert_central_state_dependent_params = + on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, }; diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index f9eaa136..fe33e04a 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -20,6 +20,27 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_rgb_underglow_init(const struct device *dev) { return 0; } +static int +on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { + case RGB_TOG_CMD: { + bool state; + int err = zmk_rgb_underglow_get_state(&state); + if (err) { + LOG_ERR("Failed to get RGB underglow state (err %d)", err); + return err; + } + + binding->param1 = state ? RGB_OFF_CMD : RGB_ON_CMD; + LOG_DBG("RGB relative toggle convert to absolute %s", state ? "OFF" : "ON"); + return 0; + } + default: + return 0; + } +}; + static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { switch (binding->param1) { @@ -63,6 +84,8 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, } static const struct behavior_driver_api behavior_rgb_underglow_driver_api = { + .binding_convert_central_state_dependent_params = + on_keymap_binding_convert_central_state_dependent_params, .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, }; diff --git a/app/src/keymap.c b/app/src/keymap.c index 75ec6bf4..1643f647 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -153,7 +153,9 @@ const char *zmk_keymap_layer_label(uint8_t layer) { } int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, int64_t timestamp) { - struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; + // We want to make a copy of this, since it may be converted from + // relative to absolute before being invoked + struct zmk_behavior_binding binding = zmk_keymap[layer][position]; const struct device *behavior; struct zmk_behavior_binding_event event = { .layer = layer, @@ -162,19 +164,25 @@ int zmk_keymap_apply_position_state(int layer, uint32_t position, bool pressed, }; LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, - log_strdup(binding->behavior_dev)); + log_strdup(binding.behavior_dev)); - behavior = device_get_binding(binding->behavior_dev); + behavior = device_get_binding(binding.behavior_dev); if (!behavior) { LOG_DBG("No behavior assigned to %d on layer %d", position, layer); return 1; } + int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event); + if (err) { + LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err); + return err; + } + if (pressed) { - return behavior_keymap_binding_pressed(binding, event); + return behavior_keymap_binding_pressed(&binding, event); } else { - return behavior_keymap_binding_released(binding, event); + return behavior_keymap_binding_released(&binding, event); } }