Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(split): Make locality work for nested behaviors #2409

Merged
merged 5 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/include/zmk/behavior.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ struct zmk_behavior_binding_event {
int layer;
uint32_t position;
int64_t timestamp;
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
uint8_t source;
caksoylar marked this conversation as resolved.
Show resolved Hide resolved
#endif
};

/**
Expand All @@ -42,6 +45,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(const struct zmk_behavior_binding_event *event,
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;
caksoylar marked this conversation as resolved.
Show resolved Hide resolved
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
petejohanson marked this conversation as resolved.
Show resolved Hide resolved
#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 // source is a member of event because CONFIG_ZMK_SPLIT is enabled
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
31 changes: 24 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,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

struct q_item {
uint32_t position;
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
uint8_t source;
#endif
struct zmk_behavior_binding binding;
bool press : 1;
uint32_t wait : 31;
Expand All @@ -31,13 +35,18 @@ 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(),
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
.source = item.source
#endif
};

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 +58,17 @@ 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(const struct zmk_behavior_binding_event *event,
const struct zmk_behavior_binding binding, bool press, uint32_t wait) {
struct q_item item = {
.press = press,
.binding = binding,
.wait = wait,
.position = event->position,
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
.source = event->source,
#endif
};

const int ret = k_msgq_put(&zmk_behavior_queue_msgq, &item, K_NO_WAIT);
if (ret < 0) {
Expand Down
38 changes: 28 additions & 10 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,9 @@ struct behavior_hold_tap_data {
// this data is specific for each hold-tap
struct active_hold_tap {
int32_t position;
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
uint8_t source;
caksoylar marked this conversation as resolved.
Show resolved Hide resolved
#endif
uint32_t param_hold;
uint32_t param_tap;
int64_t timestamp;
Expand Down Expand Up @@ -250,19 +252,22 @@ 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(struct zmk_behavior_binding_event *event,
uint32_t param_hold, uint32_t param_tap,
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].position = event->position;
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
active_hold_taps[i].source = event->source;
#endif
active_hold_taps[i].status = STATUS_UNDECIDED;
active_hold_taps[i].config = config;
active_hold_taps[i].param_hold = param_hold;
active_hold_taps[i].param_tap = param_tap;
active_hold_taps[i].timestamp = timestamp;
active_hold_taps[i].timestamp = event->timestamp;
active_hold_taps[i].position_of_first_other_key_pressed = -1;
return &active_hold_taps[i];
}
Expand Down Expand Up @@ -400,45 +405,57 @@ 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,
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
.source = hold_tap->source,
#endif
};

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,
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
.source = hold_tap->source,
#endif
};

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,
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
.source = hold_tap->source,
#endif
};

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,
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
.source = hold_tap->source,
#endif
};

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 @@ -598,7 +615,8 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
}

struct active_hold_tap *hold_tap =
store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg);
store_hold_tap(&event, binding->param1, binding->param2, 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(struct zmk_behavior_binding_event *event,
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(event, binding, true, state.tap_ms);
zmk_behavior_queue_add(event, binding, false, state.wait_ms);
break;
case MACRO_MODE_PRESS:
zmk_behavior_queue_add(position, binding, true, state.wait_ms);
zmk_behavior_queue_add(event, binding, true, state.wait_ms);
break;
case MACRO_MODE_RELEASE:
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
zmk_behavior_queue_add(event, 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, 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, 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
Loading