mirror of https://github.com/zmkfirmware/zmk.git
fix(pointing): Temp layer threading protection. (#2729)
fix(pointing): Temp layer threading protection. Ensure all layer operations occur on the system work queue thread. Fixes: #2719 fix(pointing): Handle layer events to disable events Make the temp layer input processor propely handle layers getting deactivated externally before the temp layer timeout. Co-authored-by: Nicolas Munnich <98408764+Nick-Munnich@users.noreply.github.com>
This commit is contained in:
parent
21f54e7238
commit
1e3e62c13d
|
|
@ -40,6 +40,11 @@ config ZMK_INPUT_PROCESSOR_TEMP_LAYER
|
|||
default y
|
||||
depends on DT_HAS_ZMK_INPUT_PROCESSOR_TEMP_LAYER_ENABLED
|
||||
|
||||
config ZMK_INPUT_PROCESSOR_TEMP_LAYER_MAX_ACTION_EVENTS
|
||||
int "Temporary Layer Input Processor Max Action Events"
|
||||
default 4
|
||||
depends on ZMK_INPUT_PROCESSOR_TEMP_LAYER
|
||||
|
||||
endif
|
||||
|
||||
config ZMK_INPUT_PROCESSOR_TRANSFORM
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <zmk/behavior.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/keycode_state_changed.h>
|
||||
#include <zmk/events/layer_state_changed.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ struct temp_layer_state {
|
|||
|
||||
struct temp_layer_data {
|
||||
const struct device *dev;
|
||||
struct k_mutex lock;
|
||||
struct temp_layer_state state;
|
||||
};
|
||||
|
||||
|
|
@ -78,28 +80,88 @@ static void update_layer_state(struct temp_layer_state *state, bool activate) {
|
|||
}
|
||||
}
|
||||
|
||||
struct layer_state_action {
|
||||
uint8_t layer;
|
||||
bool activate;
|
||||
};
|
||||
|
||||
K_MSGQ_DEFINE(temp_layer_action_msgq, sizeof(struct layer_state_action),
|
||||
CONFIG_ZMK_INPUT_PROCESSOR_TEMP_LAYER_MAX_ACTION_EVENTS, 4);
|
||||
|
||||
static void layer_action_work_cb(struct k_work *work) {
|
||||
|
||||
const struct device *dev = DEVICE_DT_INST_GET(0);
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
|
||||
int ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Error locking for updating %d", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
struct layer_state_action action;
|
||||
|
||||
while (k_msgq_get(&temp_layer_action_msgq, &action, K_MSEC(10)) >= 0) {
|
||||
if (!action.activate) {
|
||||
if (zmk_keymap_layer_active(action.layer)) {
|
||||
update_layer_state(&data->state, false);
|
||||
}
|
||||
} else {
|
||||
update_layer_state(&data->state, true);
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
}
|
||||
|
||||
static K_WORK_DEFINE(layer_action_work, layer_action_work_cb);
|
||||
|
||||
/* Work Queue Callback */
|
||||
static void layer_disable_callback(struct k_work *work) {
|
||||
struct k_work_delayable *d_work = k_work_delayable_from_work(work);
|
||||
int layer_index = ARRAY_INDEX(layer_disable_works, d_work);
|
||||
|
||||
const struct device *dev = DEVICE_DT_INST_GET(0);
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
struct layer_state_action action = {.layer = layer_index, .activate = false};
|
||||
|
||||
if (zmk_keymap_layer_active(layer_index)) {
|
||||
update_layer_state(&data->state, false);
|
||||
}
|
||||
int ret = k_msgq_put(&temp_layer_action_msgq, &action, K_MSEC(10));
|
||||
k_work_submit(&layer_action_work);
|
||||
}
|
||||
|
||||
/* Event Handlers */
|
||||
static int handle_position_state_changed(const zmk_event_t *eh) {
|
||||
static int handle_layer_state_changed(const struct device *dev, const zmk_event_t *eh) {
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
int ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (data->state.toggle_layer == 0) {
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
if (!zmk_keymap_layer_active(zmk_keymap_layer_index_to_id(data->state.toggle_layer))) {
|
||||
LOG_DBG("Deactivating layer that was activated by this processor");
|
||||
data->state.is_active = false;
|
||||
k_work_cancel_delayable(&layer_disable_works[data->state.toggle_layer]);
|
||||
}
|
||||
ret = k_mutex_unlock(&data->lock);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
static int handle_position_state_changed(const struct device *dev, const zmk_event_t *eh) {
|
||||
const struct zmk_position_state_changed *ev = as_zmk_position_state_changed(eh);
|
||||
if (!ev->state) {
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
const struct device *dev = DEVICE_DT_INST_GET(0);
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
int ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct temp_layer_config *cfg = dev->config;
|
||||
|
||||
if (data->state.is_active && cfg->excluded_positions && cfg->num_positions > 0) {
|
||||
|
|
@ -110,35 +172,64 @@ static int handle_position_state_changed(const zmk_event_t *eh) {
|
|||
}
|
||||
LOG_DBG("Position excluded, continuing");
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
static int handle_keycode_state_changed(const zmk_event_t *eh) {
|
||||
static int handle_keycode_state_changed(const struct device *dev, const zmk_event_t *eh) {
|
||||
const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh);
|
||||
if (!ev->state) {
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
const struct device *dev = DEVICE_DT_INST_GET(0);
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
|
||||
int ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_DBG("Setting last_tapped_timestamp to: %d", ev->timestamp);
|
||||
data->state.last_tapped_timestamp = ev->timestamp;
|
||||
|
||||
ret = k_mutex_unlock(&data->lock);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
static int handle_state_changed_dispatcher(const zmk_event_t *eh) {
|
||||
if (as_zmk_position_state_changed(eh) != NULL) {
|
||||
static int handle_state_changed_dispatcher(const struct device *dev, const zmk_event_t *eh) {
|
||||
if (as_zmk_layer_state_changed(eh) != NULL) {
|
||||
LOG_DBG("Dispatching handle_layer_state_changed");
|
||||
return handle_layer_state_changed(dev, eh);
|
||||
} else if (as_zmk_position_state_changed(eh) != NULL) {
|
||||
LOG_DBG("Dispatching handle_position_state_changed");
|
||||
return handle_position_state_changed(eh);
|
||||
return handle_position_state_changed(dev, eh);
|
||||
} else if (as_zmk_keycode_state_changed(eh) != NULL) {
|
||||
LOG_DBG("Dispatching handle_keycode_state_changed");
|
||||
return handle_keycode_state_changed(eh);
|
||||
return handle_keycode_state_changed(dev, eh);
|
||||
}
|
||||
|
||||
return ZMK_EV_EVENT_BUBBLE;
|
||||
}
|
||||
|
||||
#define DISPATCH_EVENT(inst) \
|
||||
{ \
|
||||
int err = handle_state_changed_dispatcher(DEVICE_DT_INST_GET(inst), eh); \
|
||||
if (err < 0) { \
|
||||
return err; \
|
||||
} \
|
||||
}
|
||||
|
||||
static int handle_event_dispatcher(const zmk_event_t *eh) {
|
||||
DT_INST_FOREACH_STATUS_OKAY(DISPATCH_EVENT)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Driver Implementation */
|
||||
static int temp_layer_handle_event(const struct device *dev, struct input_event *event,
|
||||
uint32_t param1, uint32_t param2,
|
||||
|
|
@ -149,23 +240,37 @@ static int temp_layer_handle_event(const struct device *dev, struct input_event
|
|||
}
|
||||
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
|
||||
int ret = k_mutex_lock(&data->lock, K_FOREVER);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct temp_layer_config *cfg = dev->config;
|
||||
|
||||
data->state.toggle_layer = param1;
|
||||
|
||||
if (!data->state.is_active &&
|
||||
!should_quick_tap(cfg, data->state.last_tapped_timestamp, k_uptime_get())) {
|
||||
update_layer_state(&data->state, true);
|
||||
struct layer_state_action action = {.layer = param1, .activate = true};
|
||||
|
||||
int ret = k_msgq_put(&temp_layer_action_msgq, &action, K_MSEC(10));
|
||||
k_work_submit(&layer_action_work);
|
||||
}
|
||||
|
||||
if (param2 > 0) {
|
||||
k_work_reschedule(&layer_disable_works[param1], K_MSEC(param2));
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return ZMK_INPUT_PROC_CONTINUE;
|
||||
}
|
||||
|
||||
static int temp_layer_init(const struct device *dev) {
|
||||
struct temp_layer_data *data = (struct temp_layer_data *)dev->data;
|
||||
k_mutex_init(&data->lock);
|
||||
|
||||
for (int i = 0; i < MAX_LAYERS; i++) {
|
||||
k_work_init_delayable(&layer_disable_works[i], layer_disable_callback);
|
||||
}
|
||||
|
|
@ -183,10 +288,8 @@ static const struct zmk_input_processor_driver_api temp_layer_driver_api = {
|
|||
#define NEEDS_KEYCODE_HANDLERS(n, ...) (DT_INST_PROP_OR(n, require_prior_idle_ms, 0) > 0)
|
||||
|
||||
/* Event Handlers Registration */
|
||||
#if DT_INST_FOREACH_STATUS_OKAY_VARGS(NEEDS_POSITION_HANDLERS, ||) || \
|
||||
DT_INST_FOREACH_STATUS_OKAY_VARGS(NEEDS_KEYCODE_HANDLERS, ||)
|
||||
ZMK_LISTENER(processor_temp_layer, handle_state_changed_dispatcher);
|
||||
#endif
|
||||
ZMK_LISTENER(processor_temp_layer, handle_event_dispatcher);
|
||||
ZMK_SUBSCRIPTION(processor_temp_layer, zmk_layer_state_changed);
|
||||
|
||||
/* Individual Subscriptions */
|
||||
#if DT_INST_FOREACH_STATUS_OKAY_VARGS(NEEDS_POSITION_HANDLERS, ||)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
layer_changed: layer 1 state 1
|
||||
Dispatching handle_layer_state_changed
|
||||
movement_set: Mouse movement set to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
|
|
@ -12,3 +13,4 @@ movement_set: Mouse movement set to -3/0
|
|||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
layer_changed: layer 1 state 0
|
||||
Dispatching handle_layer_state_changed
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
Dispatching handle_position_state_changed
|
||||
Position excluded, continuing
|
||||
layer_changed: layer 1 state 1
|
||||
Dispatching handle_layer_state_changed
|
||||
movement_set: Mouse movement set to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
|
|
@ -17,5 +18,6 @@ Dispatching handle_position_state_changed
|
|||
Dispatching handle_position_state_changed
|
||||
Position not excluded, deactivating layer
|
||||
layer_changed: layer 1 state 0
|
||||
Dispatching handle_layer_state_changed
|
||||
Position excluded, continuing
|
||||
Dispatching handle_position_state_changed
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
Dispatching handle_position_state_changed
|
||||
Position excluded, continuing
|
||||
layer_changed: layer 1 state 1
|
||||
Dispatching handle_layer_state_changed
|
||||
movement_set: Mouse movement set to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ movement_set: Mouse movement set to -1/0
|
|||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
layer_changed: layer 1 state 1
|
||||
Dispatching handle_layer_state_changed
|
||||
movement_set: Mouse movement set to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
|
|
@ -146,3 +147,4 @@ movement_set: Mouse movement set to -9/0
|
|||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
layer_changed: layer 1 state 0
|
||||
Dispatching handle_layer_state_changed
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
s/.*hid_mouse_//p
|
||||
s/.*set_layer_state: //p
|
||||
s/.*handle_state_changed_dispatcher: //p
|
||||
s/.*handle_layer_state_changed: //p
|
||||
s/.*handle_position_state_changed: //p
|
||||
s/.*handle_keycode_state_changed: //p
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
layer_changed: layer 1 state 1
|
||||
Dispatching handle_layer_state_changed
|
||||
movement_set: Mouse movement set to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_set: Mouse movement set to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_set: Mouse movement set to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_set: Mouse movement set to -3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
layer_changed: layer 1 state 0
|
||||
Dispatching handle_layer_state_changed
|
||||
Deactivating layer that was activated by this processor
|
||||
layer_changed: layer 1 state 1
|
||||
Dispatching handle_layer_state_changed
|
||||
movement_set: Mouse movement set to -1/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_set: Mouse movement set to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_set: Mouse movement set to -2/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
movement_set: Mouse movement set to -3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
CONFIG_GPIO=n
|
||||
CONFIG_ZMK_BLE=n
|
||||
CONFIG_LOG=y
|
||||
CONFIG_LOG_BACKEND_SHOW_COLOR=n
|
||||
CONFIG_ZMK_LOG_LEVEL_DBG=y
|
||||
CONFIG_ZMK_POINTING=y
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
#include <dt-bindings/zmk/input_transform.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
#include <behaviors.dtsi>
|
||||
#include <input/processors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/pointing.h>
|
||||
|
||||
&mmv_input_listener {
|
||||
input-processors = <&zip_temp_layer 1 500>;
|
||||
};
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&mmv MOVE_LEFT &mmv MOVE_UP
|
||||
&mo 1 &none
|
||||
>;
|
||||
};
|
||||
|
||||
mkp_layer {
|
||||
bindings = <&mkp LCLK &mkp RCLK &trans &trans>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_RELEASE(0,0,150)
|
||||
ZMK_MOCK_PRESS(1,0,100)
|
||||
ZMK_MOCK_RELEASE(1,0,100)
|
||||
ZMK_MOCK_PRESS(0,0,100)
|
||||
ZMK_MOCK_RELEASE(0,0,150)
|
||||
>;
|
||||
};
|
||||
Loading…
Reference in New Issue