Skip to content

Commit

Permalink
feat(split): Make locality work nested behavior invocations
Browse files Browse the repository at this point in the history
Co-authored-by: Tokazio <[email protected]>
  • Loading branch information
2 people authored and petejohanson committed Sep 23, 2024
1 parent 11f600d commit 9e36ebd
Show file tree
Hide file tree
Showing 13 changed files with 146 additions and 105 deletions.
14 changes: 14 additions & 0 deletions app/include/zmk/behavior.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct zmk_behavior_binding_event {
int layer;
uint32_t position;
int64_t timestamp;
uint8_t source;
};

/**
Expand All @@ -42,6 +43,19 @@ struct zmk_behavior_binding_event {
*/
const struct device *zmk_behavior_get_binding(const char *name);

/**
* @brief Invoke a behavior given its binding and invoking event details.
*
* @param src_binding Behavior binding to invoke.
* @param event The binding event struct containing details of the event that invoked it.
* @param pressed Whether the binding is pressed or released.
*
* @retval 0 If successful.
* @retval Negative errno code if failure.
*/
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
struct zmk_behavior_binding_event event, bool pressed);

/**
* @brief Get a local ID for a behavior from its @p name field.
*
Expand Down
4 changes: 2 additions & 2 deletions app/include/zmk/behavior_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
#include <stdint.h>
#include <zmk/behavior.h>

int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding behavior,
bool press, uint32_t wait);
int zmk_behavior_queue_add(uint32_t position, uint8_t source,
const struct zmk_behavior_binding behavior, bool press, uint32_t wait);
1 change: 1 addition & 0 deletions app/include/zmk/split/bluetooth/service.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct sensor_event {

struct zmk_split_run_behavior_data {
uint8_t position;
uint8_t source;
uint8_t state;
uint32_t param1;
uint32_t param2;
Expand Down
67 changes: 67 additions & 0 deletions app/src/behavior.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@

#endif

#include <zmk/ble.h>
#if ZMK_BLE_IS_CENTRAL
#include <zmk/split/bluetooth/central.h>
#endif

#include <drivers/behavior.h>
#include <zmk/behavior.h>
#include <zmk/hid.h>
#include <zmk/matrix.h>

#include <zmk/events/position_state_changed.h>

#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -49,6 +56,66 @@ const struct device *z_impl_behavior_get_binding(const char *name) {
return NULL;
}

static int invoke_locally(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event, bool pressed) {
if (pressed) {
return behavior_keymap_binding_pressed(binding, event);
} else {
return behavior_keymap_binding_released(binding, event);
}
}

int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
struct zmk_behavior_binding_event event, bool pressed) {
// 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 = *src_binding;

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);
if (err) {
LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err);
return err;
}

enum behavior_locality locality = BEHAVIOR_LOCALITY_CENTRAL;
err = behavior_get_locality(behavior, &locality);
if (err) {
LOG_ERR("Failed to get behavior locality %d", err);
return err;
}

switch (locality) {
case BEHAVIOR_LOCALITY_CENTRAL:
return invoke_locally(&binding, event, pressed);
case BEHAVIOR_LOCALITY_EVENT_SOURCE:
#if ZMK_BLE_IS_CENTRAL
if (event.source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) {
return invoke_locally(&binding, event, pressed);
} else {
return zmk_split_bt_invoke_behavior(event.source, &binding, event, pressed);
}
#else
return invoke_locally(&binding, event, pressed);
#endif
case BEHAVIOR_LOCALITY_GLOBAL:
#if ZMK_BLE_IS_CENTRAL
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
zmk_split_bt_invoke_behavior(i, &binding, event, pressed);
}
#endif
return invoke_locally(&binding, event, pressed);
}

return -ENOTSUP;
}

#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)

int zmk_behavior_get_empty_param_metadata(const struct device *dev,
Expand Down
17 changes: 10 additions & 7 deletions app/src/behavior_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include <zmk/behavior_queue.h>
#include <zmk/behavior.h>

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
Expand All @@ -14,6 +15,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

struct q_item {
uint32_t position;
uint8_t source;
struct zmk_behavior_binding binding;
bool press : 1;
uint32_t wait : 31;
Expand All @@ -31,13 +33,13 @@ static void behavior_queue_process_next(struct k_work *work) {
LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1,
item.binding.param2);

struct zmk_behavior_binding_event event = {.position = item.position,
.timestamp = k_uptime_get()};
struct zmk_behavior_binding_event event = {
.position = item.position, .timestamp = k_uptime_get(), .source = item.source};

if (item.press) {
behavior_keymap_binding_pressed(&item.binding, event);
zmk_behavior_invoke_binding(&item.binding, event, true);
} else {
behavior_keymap_binding_released(&item.binding, event);
zmk_behavior_invoke_binding(&item.binding, event, false);
}

LOG_DBG("Processing next queued behavior in %dms", item.wait);
Expand All @@ -49,9 +51,10 @@ static void behavior_queue_process_next(struct k_work *work) {
}
}

int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding binding, bool press,
uint32_t wait) {
struct q_item item = {.press = press, .binding = binding, .wait = wait};
int zmk_behavior_queue_add(uint32_t position, uint8_t source,
const struct zmk_behavior_binding binding, bool press, uint32_t wait) {
struct q_item item = {
.press = press, .binding = binding, .wait = wait, .position = position, .source = source};

const int ret = k_msgq_put(&zmk_behavior_queue_msgq, &item, K_NO_WAIT);
if (ret < 0) {
Expand Down
24 changes: 15 additions & 9 deletions app/src/behaviors/behavior_hold_tap.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include <zmk/events/position_state_changed.h>
#include <zmk/events/keycode_state_changed.h>
#include <zmk/behavior.h>
#include <zmk/keymap.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

Expand Down Expand Up @@ -77,6 +76,7 @@ struct behavior_hold_tap_data {
// this data is specific for each hold-tap
struct active_hold_tap {
int32_t position;
uint8_t source;
uint32_t param_hold;
uint32_t param_tap;
int64_t timestamp;
Expand Down Expand Up @@ -250,14 +250,16 @@ static struct active_hold_tap *find_hold_tap(uint32_t position) {
return NULL;
}

static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold,
uint32_t param_tap, int64_t timestamp,
static struct active_hold_tap *store_hold_tap(uint32_t position, uint8_t source,
uint32_t param_hold, uint32_t param_tap,
int64_t timestamp,
const struct behavior_hold_tap_config *config) {
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) {
if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) {
continue;
}
active_hold_taps[i].position = position;
active_hold_taps[i].source = source;
active_hold_taps[i].status = STATUS_UNDECIDED;
active_hold_taps[i].config = config;
active_hold_taps[i].param_hold = param_hold;
Expand Down Expand Up @@ -400,45 +402,49 @@ static int press_hold_binding(struct active_hold_tap *hold_tap) {
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
.source = hold_tap->source,
};

struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
.param1 = hold_tap->param_hold};
return behavior_keymap_binding_pressed(&binding, event);
return zmk_behavior_invoke_binding(&binding, event, true);
}

static int press_tap_binding(struct active_hold_tap *hold_tap) {
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
.source = hold_tap->source,
};

struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
.param1 = hold_tap->param_tap};
store_last_hold_tapped(hold_tap);
return behavior_keymap_binding_pressed(&binding, event);
return zmk_behavior_invoke_binding(&binding, event, true);
}

static int release_hold_binding(struct active_hold_tap *hold_tap) {
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
.source = hold_tap->source,
};

struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
.param1 = hold_tap->param_hold};
return behavior_keymap_binding_released(&binding, event);
return zmk_behavior_invoke_binding(&binding, event, false);
}

static int release_tap_binding(struct active_hold_tap *hold_tap) {
struct zmk_behavior_binding_event event = {
.position = hold_tap->position,
.timestamp = hold_tap->timestamp,
.source = hold_tap->source,
};

struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
.param1 = hold_tap->param_tap};
return behavior_keymap_binding_released(&binding, event);
return zmk_behavior_invoke_binding(&binding, event, false);
}

static int press_binding(struct active_hold_tap *hold_tap) {
Expand Down Expand Up @@ -597,8 +603,8 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
return ZMK_BEHAVIOR_OPAQUE;
}

struct active_hold_tap *hold_tap =
store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg);
struct active_hold_tap *hold_tap = store_hold_tap(event.position, event.source, binding->param1,
binding->param2, event.timestamp, cfg);
if (hold_tap == NULL) {
LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?",
ZMK_BHV_HOLD_TAP_MAX_HELD);
Expand Down
15 changes: 8 additions & 7 deletions app/src/behaviors/behavior_macro.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ static void replace_params(struct behavior_macro_trigger_state *state,
state->param2_source = PARAM_SOURCE_BINDING;
}

static void queue_macro(uint32_t position, const struct zmk_behavior_binding bindings[],
static void queue_macro(uint32_t position, uint8_t source,
const struct zmk_behavior_binding bindings[],
struct behavior_macro_trigger_state state,
const struct zmk_behavior_binding *macro_binding) {
LOG_DBG("Iterating macro bindings - starting: %d, count: %d", state.start_index, state.count);
Expand All @@ -169,14 +170,14 @@ static void queue_macro(uint32_t position, const struct zmk_behavior_binding bin

switch (state.mode) {
case MACRO_MODE_TAP:
zmk_behavior_queue_add(position, binding, true, state.tap_ms);
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
zmk_behavior_queue_add(position, source, binding, true, state.tap_ms);
zmk_behavior_queue_add(position, source, binding, false, state.wait_ms);
break;
case MACRO_MODE_PRESS:
zmk_behavior_queue_add(position, binding, true, state.wait_ms);
zmk_behavior_queue_add(position, source, binding, true, state.wait_ms);
break;
case MACRO_MODE_RELEASE:
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
zmk_behavior_queue_add(position, source, binding, false, state.wait_ms);
break;
default:
LOG_ERR("Unknown macro mode: %d", state.mode);
Expand All @@ -197,7 +198,7 @@ static int on_macro_binding_pressed(struct zmk_behavior_binding *binding,
.start_index = 0,
.count = state->press_bindings_count};

queue_macro(event.position, cfg->bindings, trigger_state, binding);
queue_macro(event.position, event.source, cfg->bindings, trigger_state, binding);

return ZMK_BEHAVIOR_OPAQUE;
}
Expand All @@ -208,7 +209,7 @@ static int on_macro_binding_released(struct zmk_behavior_binding *binding,
const struct behavior_macro_config *cfg = dev->config;
struct behavior_macro_state *state = dev->data;

queue_macro(event.position, cfg->bindings, state->release_state, binding);
queue_macro(event.position, event.source, cfg->bindings, state->release_state, binding);

return ZMK_BEHAVIOR_OPAQUE;
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/behaviors/behavior_mod_morph.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
} else {
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding;
}
return behavior_keymap_binding_pressed(data->pressed_binding, event);
return zmk_behavior_invoke_binding(data->pressed_binding, event, true);
}

static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
Expand All @@ -67,7 +67,7 @@ static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding *pressed_binding = data->pressed_binding;
data->pressed_binding = NULL;
int err;
err = behavior_keymap_binding_released(pressed_binding, event);
err = zmk_behavior_invoke_binding(pressed_binding, event, false);
zmk_hid_masked_modifiers_clear();
return err;
}
Expand Down
4 changes: 2 additions & 2 deletions app/src/behaviors/behavior_sensor_rotate_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
LOG_DBG("Sensor binding: %s", binding->behavior_dev);

for (int i = 0; i < triggers; i++) {
zmk_behavior_queue_add(event.position, triggered_binding, true, cfg->tap_ms);
zmk_behavior_queue_add(event.position, triggered_binding, false, 0);
zmk_behavior_queue_add(event.position, event.source, triggered_binding, true, cfg->tap_ms);
zmk_behavior_queue_add(event.position, event.source, triggered_binding, false, 0);
}

return ZMK_BEHAVIOR_OPAQUE;
Expand Down
Loading

0 comments on commit 9e36ebd

Please sign in to comment.