Skip to content

Commit

Permalink
feat(mouse): Added auto-layer-toggle
Browse files Browse the repository at this point in the history
Input Listener: Added logging

Auto Layer Toggle: Added initial version

Auto Layer Toggle: Changed how config is retrieved

Auto Layer Toggle: Adjust logging
  • Loading branch information
infused-kim committed Feb 26, 2024
1 parent 60d4bfe commit d818f96
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 9 deletions.
15 changes: 15 additions & 0 deletions app/dts/bindings/zmk,input-listener.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
149 changes: 140 additions & 9 deletions app/src/mouse/input_listener.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include <zmk/mouse.h>
#include <zmk/endpoints.h>
#include <zmk/hid.h>
#include <zmk/keymap.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

enum input_listener_xy_data_mode {
INPUT_LISTENER_XY_DATA_MODE_NONE,
Expand All @@ -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:
Expand All @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -171,18 +216,104 @@ 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), \
.x_invert = DT_INST_PROP(n, x_invert), \
.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)

0 comments on commit d818f96

Please sign in to comment.