From d818f96a55093e8391d0e2de31c78a7aa2f57f6e Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Sun, 25 Feb 2024 18:19:36 -0600 Subject: [PATCH] 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 --- app/dts/bindings/zmk,input-listener.yaml | 15 +++ app/src/mouse/input_listener.c | 149 +++++++++++++++++++++-- 2 files changed, 155 insertions(+), 9 deletions(-) diff --git a/app/dts/bindings/zmk,input-listener.yaml b/app/dts/bindings/zmk,input-listener.yaml index a883557db39..fba83e3b3a6 100644 --- a/app/dts/bindings/zmk,input-listener.yaml +++ b/app/dts/bindings/zmk,input-listener.yaml @@ -19,3 +19,18 @@ properties: scale-divisor: type: int 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. diff --git a/app/src/mouse/input_listener.c b/app/src/mouse/input_listener.c index 0acc434997f..89d7690ae58 100644 --- a/app/src/mouse/input_listener.c +++ b/app/src/mouse/input_listener.c @@ -14,6 +14,9 @@ #include #include #include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); enum input_listener_xy_data_mode { INPUT_LISTENER_XY_DATA_MODE_NONE, @@ -27,22 +30,35 @@ struct input_listener_xy_data { int16_t y; }; +struct input_listener_config { + bool xy_swap; + bool x_invert; + bool y_invert; + uint16_t scale_multiplier; + 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; -}; -struct input_listener_config { - bool xy_swap; - bool x_invert; - bool y_invert; - uint16_t scale_multiplier; - uint16_t scale_divisor; + 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) { switch (evt->code) { 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) { 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. 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) { case INPUT_EV_REL: 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) \ static const struct input_listener_config config_##n = { \ .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), \ .scale_multiplier = DT_INST_PROP(n, scale_multiplier), \ .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) { \ 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)