Skip to content

Commit 9e36ebd

Browse files
caksoylartokazio
authored andcommitted
feat(split): Make locality work nested behavior invocations
Co-authored-by: Tokazio <[email protected]>
1 parent 11f600d commit 9e36ebd

13 files changed

Lines changed: 146 additions & 105 deletions

app/include/zmk/behavior.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct zmk_behavior_binding_event {
2626
int layer;
2727
uint32_t position;
2828
int64_t timestamp;
29+
uint8_t source;
2930
};
3031

3132
/**
@@ -42,6 +43,19 @@ struct zmk_behavior_binding_event {
4243
*/
4344
const struct device *zmk_behavior_get_binding(const char *name);
4445

46+
/**
47+
* @brief Invoke a behavior given its binding and invoking event details.
48+
*
49+
* @param src_binding Behavior binding to invoke.
50+
* @param event The binding event struct containing details of the event that invoked it.
51+
* @param pressed Whether the binding is pressed or released.
52+
*
53+
* @retval 0 If successful.
54+
* @retval Negative errno code if failure.
55+
*/
56+
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
57+
struct zmk_behavior_binding_event event, bool pressed);
58+
4559
/**
4660
* @brief Get a local ID for a behavior from its @p name field.
4761
*

app/include/zmk/behavior_queue.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
#include <stdint.h>
1111
#include <zmk/behavior.h>
1212

13-
int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding behavior,
14-
bool press, uint32_t wait);
13+
int zmk_behavior_queue_add(uint32_t position, uint8_t source,
14+
const struct zmk_behavior_binding behavior, bool press, uint32_t wait);

app/include/zmk/split/bluetooth/service.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct sensor_event {
2020

2121
struct zmk_split_run_behavior_data {
2222
uint8_t position;
23+
uint8_t source;
2324
uint8_t state;
2425
uint32_t param1;
2526
uint32_t param2;

app/src/behavior.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@
1717

1818
#endif
1919

20+
#include <zmk/ble.h>
21+
#if ZMK_BLE_IS_CENTRAL
22+
#include <zmk/split/bluetooth/central.h>
23+
#endif
24+
2025
#include <drivers/behavior.h>
2126
#include <zmk/behavior.h>
2227
#include <zmk/hid.h>
2328
#include <zmk/matrix.h>
2429

30+
#include <zmk/events/position_state_changed.h>
31+
2532
#include <zephyr/logging/log.h>
2633
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
2734

@@ -49,6 +56,66 @@ const struct device *z_impl_behavior_get_binding(const char *name) {
4956
return NULL;
5057
}
5158

59+
static int invoke_locally(struct zmk_behavior_binding *binding,
60+
struct zmk_behavior_binding_event event, bool pressed) {
61+
if (pressed) {
62+
return behavior_keymap_binding_pressed(binding, event);
63+
} else {
64+
return behavior_keymap_binding_released(binding, event);
65+
}
66+
}
67+
68+
int zmk_behavior_invoke_binding(const struct zmk_behavior_binding *src_binding,
69+
struct zmk_behavior_binding_event event, bool pressed) {
70+
// We want to make a copy of this, since it may be converted from
71+
// relative to absolute before being invoked
72+
struct zmk_behavior_binding binding = *src_binding;
73+
74+
const struct device *behavior = zmk_behavior_get_binding(binding.behavior_dev);
75+
76+
if (!behavior) {
77+
LOG_WRN("No behavior assigned to %d on layer %d", event.position, event.layer);
78+
return 1;
79+
}
80+
81+
int err = behavior_keymap_binding_convert_central_state_dependent_params(&binding, event);
82+
if (err) {
83+
LOG_ERR("Failed to convert relative to absolute behavior binding (err %d)", err);
84+
return err;
85+
}
86+
87+
enum behavior_locality locality = BEHAVIOR_LOCALITY_CENTRAL;
88+
err = behavior_get_locality(behavior, &locality);
89+
if (err) {
90+
LOG_ERR("Failed to get behavior locality %d", err);
91+
return err;
92+
}
93+
94+
switch (locality) {
95+
case BEHAVIOR_LOCALITY_CENTRAL:
96+
return invoke_locally(&binding, event, pressed);
97+
case BEHAVIOR_LOCALITY_EVENT_SOURCE:
98+
#if ZMK_BLE_IS_CENTRAL
99+
if (event.source == ZMK_POSITION_STATE_CHANGE_SOURCE_LOCAL) {
100+
return invoke_locally(&binding, event, pressed);
101+
} else {
102+
return zmk_split_bt_invoke_behavior(event.source, &binding, event, pressed);
103+
}
104+
#else
105+
return invoke_locally(&binding, event, pressed);
106+
#endif
107+
case BEHAVIOR_LOCALITY_GLOBAL:
108+
#if ZMK_BLE_IS_CENTRAL
109+
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
110+
zmk_split_bt_invoke_behavior(i, &binding, event, pressed);
111+
}
112+
#endif
113+
return invoke_locally(&binding, event, pressed);
114+
}
115+
116+
return -ENOTSUP;
117+
}
118+
52119
#if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA)
53120

54121
int zmk_behavior_get_empty_param_metadata(const struct device *dev,

app/src/behavior_queue.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include <zmk/behavior_queue.h>
8+
#include <zmk/behavior.h>
89

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

1516
struct q_item {
1617
uint32_t position;
18+
uint8_t source;
1719
struct zmk_behavior_binding binding;
1820
bool press : 1;
1921
uint32_t wait : 31;
@@ -31,13 +33,13 @@ static void behavior_queue_process_next(struct k_work *work) {
3133
LOG_DBG("Invoking %s: 0x%02x 0x%02x", item.binding.behavior_dev, item.binding.param1,
3234
item.binding.param2);
3335

34-
struct zmk_behavior_binding_event event = {.position = item.position,
35-
.timestamp = k_uptime_get()};
36+
struct zmk_behavior_binding_event event = {
37+
.position = item.position, .timestamp = k_uptime_get(), .source = item.source};
3638

3739
if (item.press) {
38-
behavior_keymap_binding_pressed(&item.binding, event);
40+
zmk_behavior_invoke_binding(&item.binding, event, true);
3941
} else {
40-
behavior_keymap_binding_released(&item.binding, event);
42+
zmk_behavior_invoke_binding(&item.binding, event, false);
4143
}
4244

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

52-
int zmk_behavior_queue_add(uint32_t position, const struct zmk_behavior_binding binding, bool press,
53-
uint32_t wait) {
54-
struct q_item item = {.press = press, .binding = binding, .wait = wait};
54+
int zmk_behavior_queue_add(uint32_t position, uint8_t source,
55+
const struct zmk_behavior_binding binding, bool press, uint32_t wait) {
56+
struct q_item item = {
57+
.press = press, .binding = binding, .wait = wait, .position = position, .source = source};
5558

5659
const int ret = k_msgq_put(&zmk_behavior_queue_msgq, &item, K_NO_WAIT);
5760
if (ret < 0) {

app/src/behaviors/behavior_hold_tap.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include <zmk/events/position_state_changed.h>
1919
#include <zmk/events/keycode_state_changed.h>
2020
#include <zmk/behavior.h>
21-
#include <zmk/keymap.h>
2221

2322
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
2423

@@ -77,6 +76,7 @@ struct behavior_hold_tap_data {
7776
// this data is specific for each hold-tap
7877
struct active_hold_tap {
7978
int32_t position;
79+
uint8_t source;
8080
uint32_t param_hold;
8181
uint32_t param_tap;
8282
int64_t timestamp;
@@ -250,14 +250,16 @@ static struct active_hold_tap *find_hold_tap(uint32_t position) {
250250
return NULL;
251251
}
252252

253-
static struct active_hold_tap *store_hold_tap(uint32_t position, uint32_t param_hold,
254-
uint32_t param_tap, int64_t timestamp,
253+
static struct active_hold_tap *store_hold_tap(uint32_t position, uint8_t source,
254+
uint32_t param_hold, uint32_t param_tap,
255+
int64_t timestamp,
255256
const struct behavior_hold_tap_config *config) {
256257
for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) {
257258
if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) {
258259
continue;
259260
}
260261
active_hold_taps[i].position = position;
262+
active_hold_taps[i].source = source;
261263
active_hold_taps[i].status = STATUS_UNDECIDED;
262264
active_hold_taps[i].config = config;
263265
active_hold_taps[i].param_hold = param_hold;
@@ -400,45 +402,49 @@ static int press_hold_binding(struct active_hold_tap *hold_tap) {
400402
struct zmk_behavior_binding_event event = {
401403
.position = hold_tap->position,
402404
.timestamp = hold_tap->timestamp,
405+
.source = hold_tap->source,
403406
};
404407

405408
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
406409
.param1 = hold_tap->param_hold};
407-
return behavior_keymap_binding_pressed(&binding, event);
410+
return zmk_behavior_invoke_binding(&binding, event, true);
408411
}
409412

410413
static int press_tap_binding(struct active_hold_tap *hold_tap) {
411414
struct zmk_behavior_binding_event event = {
412415
.position = hold_tap->position,
413416
.timestamp = hold_tap->timestamp,
417+
.source = hold_tap->source,
414418
};
415419

416420
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
417421
.param1 = hold_tap->param_tap};
418422
store_last_hold_tapped(hold_tap);
419-
return behavior_keymap_binding_pressed(&binding, event);
423+
return zmk_behavior_invoke_binding(&binding, event, true);
420424
}
421425

422426
static int release_hold_binding(struct active_hold_tap *hold_tap) {
423427
struct zmk_behavior_binding_event event = {
424428
.position = hold_tap->position,
425429
.timestamp = hold_tap->timestamp,
430+
.source = hold_tap->source,
426431
};
427432

428433
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->hold_behavior_dev,
429434
.param1 = hold_tap->param_hold};
430-
return behavior_keymap_binding_released(&binding, event);
435+
return zmk_behavior_invoke_binding(&binding, event, false);
431436
}
432437

433438
static int release_tap_binding(struct active_hold_tap *hold_tap) {
434439
struct zmk_behavior_binding_event event = {
435440
.position = hold_tap->position,
436441
.timestamp = hold_tap->timestamp,
442+
.source = hold_tap->source,
437443
};
438444

439445
struct zmk_behavior_binding binding = {.behavior_dev = hold_tap->config->tap_behavior_dev,
440446
.param1 = hold_tap->param_tap};
441-
return behavior_keymap_binding_released(&binding, event);
447+
return zmk_behavior_invoke_binding(&binding, event, false);
442448
}
443449

444450
static int press_binding(struct active_hold_tap *hold_tap) {
@@ -597,8 +603,8 @@ static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding,
597603
return ZMK_BEHAVIOR_OPAQUE;
598604
}
599605

600-
struct active_hold_tap *hold_tap =
601-
store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg);
606+
struct active_hold_tap *hold_tap = store_hold_tap(event.position, event.source, binding->param1,
607+
binding->param2, event.timestamp, cfg);
602608
if (hold_tap == NULL) {
603609
LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?",
604610
ZMK_BHV_HOLD_TAP_MAX_HELD);

app/src/behaviors/behavior_macro.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ static void replace_params(struct behavior_macro_trigger_state *state,
158158
state->param2_source = PARAM_SOURCE_BINDING;
159159
}
160160

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

170171
switch (state.mode) {
171172
case MACRO_MODE_TAP:
172-
zmk_behavior_queue_add(position, binding, true, state.tap_ms);
173-
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
173+
zmk_behavior_queue_add(position, source, binding, true, state.tap_ms);
174+
zmk_behavior_queue_add(position, source, binding, false, state.wait_ms);
174175
break;
175176
case MACRO_MODE_PRESS:
176-
zmk_behavior_queue_add(position, binding, true, state.wait_ms);
177+
zmk_behavior_queue_add(position, source, binding, true, state.wait_ms);
177178
break;
178179
case MACRO_MODE_RELEASE:
179-
zmk_behavior_queue_add(position, binding, false, state.wait_ms);
180+
zmk_behavior_queue_add(position, source, binding, false, state.wait_ms);
180181
break;
181182
default:
182183
LOG_ERR("Unknown macro mode: %d", state.mode);
@@ -197,7 +198,7 @@ static int on_macro_binding_pressed(struct zmk_behavior_binding *binding,
197198
.start_index = 0,
198199
.count = state->press_bindings_count};
199200

200-
queue_macro(event.position, cfg->bindings, trigger_state, binding);
201+
queue_macro(event.position, event.source, cfg->bindings, trigger_state, binding);
201202

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

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

213214
return ZMK_BEHAVIOR_OPAQUE;
214215
}

app/src/behaviors/behavior_mod_morph.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ static int on_mod_morph_binding_pressed(struct zmk_behavior_binding *binding,
5151
} else {
5252
data->pressed_binding = (struct zmk_behavior_binding *)&cfg->normal_binding;
5353
}
54-
return behavior_keymap_binding_pressed(data->pressed_binding, event);
54+
return zmk_behavior_invoke_binding(data->pressed_binding, event, true);
5555
}
5656

5757
static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
@@ -67,7 +67,7 @@ static int on_mod_morph_binding_released(struct zmk_behavior_binding *binding,
6767
struct zmk_behavior_binding *pressed_binding = data->pressed_binding;
6868
data->pressed_binding = NULL;
6969
int err;
70-
err = behavior_keymap_binding_released(pressed_binding, event);
70+
err = zmk_behavior_invoke_binding(pressed_binding, event, false);
7171
zmk_hid_masked_modifiers_clear();
7272
return err;
7373
}

app/src/behaviors/behavior_sensor_rotate_common.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ int zmk_behavior_sensor_rotate_common_process(struct zmk_behavior_binding *bindi
9090
LOG_DBG("Sensor binding: %s", binding->behavior_dev);
9191

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

9797
return ZMK_BEHAVIOR_OPAQUE;

0 commit comments

Comments
 (0)