forked from zmkfirmware/zmk
-
Notifications
You must be signed in to change notification settings - Fork 51
/
input_processor_temp_layer.c
280 lines (220 loc) · 8.98 KB
/
input_processor_temp_layer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT zmk_input_processor_temp_layer
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <drivers/input_processor.h>
#include <zephyr/logging/log.h>
#include <zmk/keymap.h>
#include <zmk/behavior.h>
#include <zmk/events/position_state_changed.h>
#include <zmk/events/keycode_state_changed.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
/* Constants and Types */
#define MAX_LAYERS ZMK_KEYMAP_LAYERS_LEN
struct temp_layer_config {
int16_t require_prior_idle_ms;
const uint16_t *excluded_positions;
size_t num_positions;
};
struct temp_layer_state {
uint8_t toggle_layer;
bool is_active;
int64_t last_tapped_timestamp;
};
struct temp_layer_data {
const struct device *dev;
struct k_mutex lock;
struct temp_layer_state state;
};
/* Static Work Queue Items */
static struct k_work_delayable layer_disable_works[MAX_LAYERS];
/* Position Search */
static bool position_is_excluded(const struct temp_layer_config *config, uint32_t position) {
if (!config->excluded_positions || !config->num_positions) {
return false;
}
const uint16_t *end = config->excluded_positions + config->num_positions;
for (const uint16_t *pos = config->excluded_positions; pos < end; pos++) {
if (*pos == position) {
return true;
}
}
return false;
}
/* Timing Check */
static bool should_quick_tap(const struct temp_layer_config *config, int64_t last_tapped,
int64_t current_time) {
return (last_tapped + config->require_prior_idle_ms) > current_time;
}
/* Layer State Management */
static void update_layer_state(struct temp_layer_state *state, bool activate) {
if (state->is_active == activate) {
return;
}
state->is_active = activate;
if (activate) {
zmk_keymap_layer_activate(state->toggle_layer);
LOG_DBG("Layer %d activated", state->toggle_layer);
} else {
zmk_keymap_layer_deactivate(state->toggle_layer);
LOG_DBG("Layer %d deactivated", state->toggle_layer);
}
}
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);
struct layer_state_action action = {.layer = layer_index, .activate = 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) {
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) {
if (!position_is_excluded(cfg, ev->position)) {
LOG_DBG("Position not excluded, deactivating layer");
update_layer_state(&data->state, false);
}
}
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) {
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) {
LOG_DBG("Dispatching handle_position_state_changed");
return handle_position_state_changed(eh);
} else if (as_zmk_keycode_state_changed(eh) != NULL) {
LOG_DBG("Dispatching handle_keycode_state_changed");
return handle_keycode_state_changed(eh);
}
return ZMK_EV_EVENT_BUBBLE;
}
/* Driver Implementation */
static int temp_layer_handle_event(const struct device *dev, struct input_event *event,
uint32_t param1, uint32_t param2,
struct zmk_input_processor_state *state) {
if (param1 >= MAX_LAYERS) {
LOG_ERR("Invalid layer index: %d", param1);
return -EINVAL;
}
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())) {
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);
}
return 0;
}
/* Driver API */
static const struct zmk_input_processor_driver_api temp_layer_driver_api = {
.handle_event = temp_layer_handle_event,
};
/* Event Listeners Conditions */
#define NEEDS_POSITION_HANDLERS(n, ...) DT_INST_PROP_HAS_IDX(n, excluded_positions, 0)
#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
/* Individual Subscriptions */
#if DT_INST_FOREACH_STATUS_OKAY_VARGS(NEEDS_POSITION_HANDLERS, ||)
ZMK_SUBSCRIPTION(processor_temp_layer, zmk_position_state_changed);
#endif
#if DT_INST_FOREACH_STATUS_OKAY_VARGS(NEEDS_KEYCODE_HANDLERS, ||)
ZMK_SUBSCRIPTION(processor_temp_layer, zmk_keycode_state_changed);
#endif
/* Device Instantiation */
#define TEMP_LAYER_INST(n) \
static struct temp_layer_data processor_temp_layer_data_##n = {}; \
static const uint16_t excluded_positions_##n[] = DT_INST_PROP(n, excluded_positions); \
static const struct temp_layer_config processor_temp_layer_config_##n = { \
.require_prior_idle_ms = DT_INST_PROP_OR(n, require_prior_idle_ms, 0), \
.excluded_positions = excluded_positions_##n, \
.num_positions = DT_INST_PROP_LEN(n, excluded_positions), \
}; \
DEVICE_DT_INST_DEFINE(n, temp_layer_init, NULL, &processor_temp_layer_data_##n, \
&processor_temp_layer_config_##n, POST_KERNEL, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &temp_layer_driver_api);
DT_INST_FOREACH_STATUS_OKAY(TEMP_LAYER_INST)