feat(mouse): Added auto-layer-toggle

Input Listener: Added logging

Auto Layer Toggle: Added initial version

Auto Layer Toggle: Changed how config is retrieved

Auto Layer Toggle: Adjust logging
This commit is contained in:
Kim Streich 2024-02-25 18:19:36 -06:00
parent 01221695e5
commit a81da31d6a
2 changed files with 156 additions and 10 deletions

View file

@ -19,3 +19,18 @@ properties:
scale-divisor: scale-divisor:
type: int type: int
default: 1 default: 1
layer-toggle:
type: int
default: -1
required: false
description: The layer that should be toggled when the mouse is moved.
layer-toggle-delay-ms:
type: int
default: 250
required: false
description: How many miliseconds of mouse activity are required before the layer is toggled on.
layer-toggle-timeout-ms:
type: int
default: 250
required: false
description: How many miliseconds of mouse inactivity are required before the layer is toggled off again.

View file

@ -14,6 +14,9 @@
#include <zmk/mouse.h> #include <zmk/mouse.h>
#include <zmk/endpoints.h> #include <zmk/endpoints.h>
#include <zmk/hid.h> #include <zmk/hid.h>
#include <zmk/keymap.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
enum input_listener_xy_data_mode { enum input_listener_xy_data_mode {
INPUT_LISTENER_XY_DATA_MODE_NONE, INPUT_LISTENER_XY_DATA_MODE_NONE,
@ -27,22 +30,35 @@ struct input_listener_xy_data {
int16_t y; int16_t y;
}; };
struct input_listener_data {
struct input_listener_xy_data data;
struct input_listener_xy_data wheel_data;
uint8_t button_set;
uint8_t button_clear;
};
struct input_listener_config { struct input_listener_config {
bool xy_swap; bool xy_swap;
bool x_invert; bool x_invert;
bool y_invert; bool y_invert;
uint16_t scale_multiplier; uint16_t scale_multiplier;
uint16_t scale_divisor; uint16_t scale_divisor;
int layer_toggle;
int layer_toggle_delay_ms;
int layer_toggle_timeout_ms;
}; };
struct input_listener_data {
const struct device *dev;
struct input_listener_xy_data data;
struct input_listener_xy_data wheel_data;
uint8_t button_set;
uint8_t button_clear;
bool layer_toggle_layer_enabled;
int64_t layer_toggle_last_mouse_package_time;
struct k_work_delayable layer_toggle_activation_delay;
struct k_work_delayable layer_toggle_deactivation_delay;
};
void zmk_input_listener_layer_toggle_input_rel_received(const struct input_listener_config *config,
struct input_listener_data *data);
static void handle_rel_code(struct input_listener_data *data, struct input_event *evt) { static void handle_rel_code(struct input_listener_data *data, struct input_event *evt) {
switch (evt->code) { switch (evt->code) {
case INPUT_REL_X: case INPUT_REL_X:
@ -66,6 +82,31 @@ static void handle_rel_code(struct input_listener_data *data, struct input_event
} }
} }
static char *get_input_code_name(struct input_event *evt) {
switch (evt->code) {
case INPUT_REL_X:
return "INPUT_REL_X";
case INPUT_REL_Y:
return "INPUT_REL_Y";
case INPUT_REL_WHEEL:
return "INPUT_REL_WHEEL";
case INPUT_REL_HWHEEL:
return "INPUT_REL_HWHEEL";
case INPUT_BTN_0:
return "INPUT_BTN_0";
case INPUT_BTN_1:
return "INPUT_BTN_1";
case INPUT_BTN_2:
return "INPUT_BTN_2";
case INPUT_BTN_3:
return "INPUT_BTN_3";
case INPUT_BTN_4:
return "INPUT_BTN_4";
default:
return "UNKNOWN";
}
}
static void handle_key_code(struct input_listener_data *data, struct input_event *evt) { static void handle_key_code(struct input_listener_data *data, struct input_event *evt) {
int8_t btn; int8_t btn;
@ -126,6 +167,10 @@ static void input_handler(const struct input_listener_config *config,
// First, filter to update the event data as needed. // First, filter to update the event data as needed.
filter_with_input_config(config, evt); filter_with_input_config(config, evt);
LOG_DBG("Got input_handler event: %s with value 0x%x", get_input_code_name(evt), evt->value);
zmk_input_listener_layer_toggle_input_rel_received(config, data);
switch (evt->type) { switch (evt->type) {
case INPUT_EV_REL: case INPUT_EV_REL:
handle_rel_code(data, evt); handle_rel_code(data, evt);
@ -171,6 +216,72 @@ static void input_handler(const struct input_listener_config *config,
} }
} }
void zmk_input_listener_layer_toggle_input_rel_received(const struct input_listener_config *config,
struct input_listener_data *data) {
if (config->layer_toggle == -1) {
return;
}
data->layer_toggle_last_mouse_package_time = k_uptime_get();
if (data->layer_toggle_layer_enabled == false) {
k_work_schedule(&data->layer_toggle_activation_delay,
K_MSEC(config->layer_toggle_delay_ms));
} else {
// Deactivate the layer if no further movement within
// layer_toggle_timeout_ms
k_work_reschedule(&data->layer_toggle_deactivation_delay,
K_MSEC(config->layer_toggle_timeout_ms));
}
}
void zmk_input_listener_layer_toggle_activate_layer(struct k_work *item) {
struct k_work_delayable *d_work = k_work_delayable_from_work(item);
struct input_listener_data *data =
CONTAINER_OF(d_work, struct input_listener_data, layer_toggle_activation_delay);
const struct input_listener_config *config = data->dev->config;
int64_t current_time = k_uptime_get();
int64_t last_mv_within_ms = current_time - data->layer_toggle_last_mouse_package_time;
if (last_mv_within_ms <= config->layer_toggle_timeout_ms * 0.1) {
LOG_INF("Activating layer %d due to mouse activity...", config->layer_toggle);
zmk_keymap_layer_activate(config->layer_toggle, false);
data->layer_toggle_layer_enabled = true;
} else {
LOG_INF("Not activating mouse layer %d, because last mouse activity was %lldms ago",
config->layer_toggle, last_mv_within_ms);
}
}
void zmk_input_listener_layer_toggle_deactivate_layer(struct k_work *item) {
struct k_work_delayable *d_work = k_work_delayable_from_work(item);
struct input_listener_data *data =
CONTAINER_OF(d_work, struct input_listener_data, layer_toggle_deactivation_delay);
const struct input_listener_config *config = data->dev->config;
LOG_INF("Deactivating layer %d due to mouse activity...", config->layer_toggle);
if (zmk_keymap_layer_active(config->layer_toggle)) {
zmk_keymap_layer_deactivate(config->layer_toggle);
}
data->layer_toggle_layer_enabled = false;
}
static int zmk_input_listener_layer_toggle_init(const struct input_listener_config *config,
struct input_listener_data *data) {
k_work_init_delayable(&data->layer_toggle_activation_delay,
zmk_input_listener_layer_toggle_activate_layer);
k_work_init_delayable(&data->layer_toggle_deactivation_delay,
zmk_input_listener_layer_toggle_deactivate_layer);
return 0;
}
#define IL_INST(n) \ #define IL_INST(n) \
static const struct input_listener_config config_##n = { \ static const struct input_listener_config config_##n = { \
.xy_swap = DT_INST_PROP(n, xy_swap), \ .xy_swap = DT_INST_PROP(n, xy_swap), \
@ -178,11 +289,31 @@ static void input_handler(const struct input_listener_config *config,
.y_invert = DT_INST_PROP(n, y_invert), \ .y_invert = DT_INST_PROP(n, y_invert), \
.scale_multiplier = DT_INST_PROP(n, scale_multiplier), \ .scale_multiplier = DT_INST_PROP(n, scale_multiplier), \
.scale_divisor = DT_INST_PROP(n, scale_divisor), \ .scale_divisor = DT_INST_PROP(n, scale_divisor), \
.layer_toggle = DT_INST_PROP(n, layer_toggle), \
.layer_toggle_delay_ms = DT_INST_PROP(n, layer_toggle_delay_ms), \
.layer_toggle_timeout_ms = DT_INST_PROP(n, layer_toggle_timeout_ms), \
}; \
static struct input_listener_data data_##n = { \
.dev = DEVICE_DT_INST_GET(n), \
.layer_toggle_layer_enabled = false, \
.layer_toggle_last_mouse_package_time = 0, \
}; \ }; \
static struct input_listener_data data_##n = {}; \
void input_handler_##n(struct input_event *evt) { \ void input_handler_##n(struct input_event *evt) { \
input_handler(&config_##n, &data_##n, evt); \ input_handler(&config_##n, &data_##n, evt); \
} \ } \
INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_INST_PHANDLE(n, device)), input_handler_##n); INPUT_CALLBACK_DEFINE(DEVICE_DT_GET(DT_INST_PHANDLE(n, device)), input_handler_##n); \
\
static int zmk_input_listener_init_##n(const struct device *dev) { \
\
struct input_listener_data *data = dev->data; \
const struct input_listener_config *config = dev->config; \
\
zmk_input_listener_layer_toggle_init(config, data); \
\
return 0; \
} \
\
DEVICE_DT_INST_DEFINE(n, &zmk_input_listener_init_##n, NULL, &data_##n, &config_##n, \
POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, NULL);
DT_INST_FOREACH_STATUS_OKAY(IL_INST) DT_INST_FOREACH_STATUS_OKAY(IL_INST)