diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index f8fec493b99f..916455bf9776 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -26,7 +26,6 @@ target_sources(app PRIVATE src/activity.c) target_sources(app PRIVATE src/behavior.c) target_sources(app PRIVATE src/kscan.c) target_sources(app PRIVATE src/matrix_transform.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/input_config.c) target_sources(app PRIVATE src/sensors.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c) target_sources(app PRIVATE src/event_manager.c) @@ -40,7 +39,7 @@ target_sources(app PRIVATE src/behaviors/behavior_reset.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources(app PRIVATE src/hid.c) - target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/hid_input_listener.c) + target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/input_listener.c) target_sources(app PRIVATE src/behaviors/behavior_key_press.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c) target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 8a8d023d7b98..34adbe335dbf 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -20,6 +20,4 @@ #include #include #include -#include -#include #include diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index 0bfc87d04fd6..c43455c3953a 100644 --- a/app/dts/behaviors/mouse_move.dtsi +++ b/app/dts/behaviors/mouse_move.dtsi @@ -11,4 +11,9 @@ acceleration-exponent = <1>; }; }; + + mmv_input_listener { + compatible = "zmk,input-listener"; + device = <&mmv>; + }; }; diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi index 69c48feeea34..27b6aafe1d85 100644 --- a/app/dts/behaviors/mouse_scroll.dtsi +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -11,4 +11,9 @@ acceleration-exponent = <0>; }; }; + + msc_input_listener { + compatible = "zmk,input-listener"; + device = <&msc>; + }; }; diff --git a/app/dts/bindings/zmk,input-configs.yaml b/app/dts/bindings/zmk,input-configs.yaml deleted file mode 100644 index 83bd4a1939df..000000000000 --- a/app/dts/bindings/zmk,input-configs.yaml +++ /dev/null @@ -1,24 +0,0 @@ -description: | - Allows post-processing of input events based on the configuration - -compatible: "zmk,input-configs" - -child-binding: - description: "A configuration for a given input device" - - properties: - device: - type: phandle - required: true - xy-swap: - type: boolean - x-invert: - type: boolean - y-invert: - type: boolean - scale-multiplier: - type: int - default: 1 - scale-divisor: - type: int - default: 1 diff --git a/app/dts/bindings/zmk,input-listener.yaml b/app/dts/bindings/zmk,input-listener.yaml new file mode 100644 index 000000000000..a883557db396 --- /dev/null +++ b/app/dts/bindings/zmk,input-listener.yaml @@ -0,0 +1,21 @@ +description: | + Listener to subscribe to input events and send HID updates after processing + +compatible: "zmk,input-listener" + +properties: + device: + type: phandle + required: true + xy-swap: + type: boolean + x-invert: + type: boolean + y-invert: + type: boolean + scale-multiplier: + type: int + default: 1 + scale-divisor: + type: int + default: 1 diff --git a/app/include/zmk/mouse/input_config.h b/app/include/zmk/mouse/input_config.h deleted file mode 100644 index 0a37b346cafe..000000000000 --- a/app/include/zmk/mouse/input_config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (c) 2023 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#pragma once - -#include -#include - -struct zmk_input_config { - const struct device *dev; - bool xy_swap; - bool x_invert; - bool y_invert; - uint16_t scale_multiplier; - uint16_t scale_divisor; -}; - -const struct zmk_input_config *zmk_input_config_get_for_device(const struct device *dev); \ No newline at end of file diff --git a/app/src/mouse/hid_input_listener.c b/app/src/mouse/hid_input_listener.c deleted file mode 100644 index 712bb5675c21..000000000000 --- a/app/src/mouse/hid_input_listener.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include -#include - -#include -#include -#include -#include - -void handle_rel_code(struct input_event *evt) { - switch (evt->code) { - case INPUT_REL_X: - zmk_hid_mouse_movement_update(evt->value, 0); - break; - case INPUT_REL_Y: - zmk_hid_mouse_movement_update(0, evt->value); - break; - case INPUT_REL_WHEEL: - zmk_hid_mouse_scroll_update(0, evt->value); - break; - case INPUT_REL_HWHEEL: - zmk_hid_mouse_scroll_update(evt->value, 0); - break; - default: - break; - } -} - -void handle_key_code(struct input_event *evt) { - int8_t btn; - - switch (evt->code) { - case INPUT_BTN_0: - case INPUT_BTN_1: - case INPUT_BTN_2: - case INPUT_BTN_3: - case INPUT_BTN_4: - btn = evt->code - INPUT_BTN_0; - if (evt->value > 0) { - zmk_hid_mouse_button_press(btn); - } else { - zmk_hid_mouse_button_release(btn); - } - break; - default: - break; - } -} - -static void swap_xy(struct input_event *evt) { - switch (evt->code) { - case INPUT_REL_X: - evt->code = INPUT_REL_Y; - break; - case INPUT_REL_Y: - evt->code = INPUT_REL_X; - break; - } -} - -static void filter_with_input_config(struct input_event *evt) { - if (!evt->dev) { - return; - } - - const struct zmk_input_config *cfg = zmk_input_config_get_for_device(evt->dev); - - if (!cfg) { - return; - } - - if (cfg->xy_swap) { - swap_xy(evt); - } - - if ((cfg->x_invert && evt->code == INPUT_REL_X) || - (cfg->y_invert && evt->code == INPUT_REL_Y)) { - evt->value = -(evt->value); - } - - evt->value = (int16_t)((evt->value * cfg->scale_multiplier) / cfg->scale_divisor); -} - -void input_handler(struct input_event *evt) { - // First, filter to update the event data as needed. - filter_with_input_config(evt); - - switch (evt->type) { - case INPUT_EV_REL: - handle_rel_code(evt); - break; - case INPUT_EV_KEY: - handle_key_code(evt); - break; - } - - if (evt->sync) { - zmk_endpoints_send_mouse_report(); - zmk_hid_mouse_scroll_set(0, 0); - zmk_hid_mouse_movement_set(0, 0); - } -} - -INPUT_CALLBACK_DEFINE(NULL, input_handler); diff --git a/app/src/mouse/input_config.c b/app/src/mouse/input_config.c deleted file mode 100644 index 745fb49bac5e..000000000000 --- a/app/src/mouse/input_config.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2023 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -#define DT_DRV_COMPAT zmk_input_configs - -#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) - -#define CHILD_CONFIG(inst) \ - { \ - .dev = DEVICE_DT_GET(DT_PHANDLE(inst, device)), \ - .xy_swap = DT_PROP(inst, xy_swap), \ - .x_invert = DT_PROP(inst, x_invert), \ - .y_invert = DT_PROP(inst, y_invert), \ - .scale_multiplier = DT_PROP(inst, scale_multiplier), \ - .scale_divisor = DT_PROP(inst, scale_divisor), \ - }, - -const struct zmk_input_config configs[] = {DT_INST_FOREACH_CHILD(0, CHILD_CONFIG)}; - -const struct zmk_input_config *zmk_input_config_get_for_device(const struct device *dev) { - for (int i = 0; i < ARRAY_SIZE(configs); i++) { - if (configs[i].dev == dev) { - return &configs[i]; - } - } - - return NULL; -} - -#else - -const struct zmk_input_config *zmk_input_config_get_for_device(const struct device *dev) { - return NULL; -} - -#endif \ No newline at end of file diff --git a/app/src/mouse/input_listener.c b/app/src/mouse/input_listener.c new file mode 100644 index 000000000000..a00455bc9aa2 --- /dev/null +++ b/app/src/mouse/input_listener.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_input_listener + +#include +#include +#include +#include + +#include +#include +#include + +enum input_listener_xy_data_mode { + INPUT_LISTENER_XY_DATA_MODE_NONE, + INPUT_LISTENER_XY_DATA_MODE_REL, + INPUT_LISTENER_XY_DATA_MODE_ABS, +}; + +struct input_listener_xy_data { + enum input_listener_xy_data_mode mode; + int16_t x; + 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 { + bool xy_swap; + bool x_invert; + bool y_invert; + uint16_t scale_multiplier; + uint16_t scale_divisor; +}; + +static void handle_rel_code(struct input_listener_data *data, struct input_event *evt) { + switch (evt->code) { + case INPUT_REL_X: + data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->data.x += evt->value; + break; + case INPUT_REL_Y: + data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->data.y += evt->value; + break; + case INPUT_REL_WHEEL: + data->wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->wheel_data.y += evt->value; + break; + case INPUT_REL_HWHEEL: + data->wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->wheel_data.x += evt->value; + break; + default: + break; + } +} + +static void handle_key_code(struct input_listener_data *data, struct input_event *evt) { + int8_t btn; + + switch (evt->code) { + case INPUT_BTN_0: + case INPUT_BTN_1: + case INPUT_BTN_2: + case INPUT_BTN_3: + case INPUT_BTN_4: + btn = evt->code - INPUT_BTN_0; + if (evt->value > 0) { + WRITE_BIT(data->button_set, btn, 1); + } else { + WRITE_BIT(data->button_clear, btn, 1); + } + break; + default: + break; + } +} + +static void swap_xy(struct input_event *evt) { + switch (evt->code) { + case INPUT_REL_X: + evt->code = INPUT_REL_Y; + break; + case INPUT_REL_Y: + evt->code = INPUT_REL_X; + break; + } +} + +static void filter_with_input_config(const struct input_listener_config *cfg, + struct input_event *evt) { + if (!evt->dev) { + return; + } + + if (cfg->xy_swap) { + swap_xy(evt); + } + + if ((cfg->x_invert && evt->code == INPUT_REL_X) || + (cfg->y_invert && evt->code == INPUT_REL_Y)) { + evt->value = -(evt->value); + } + + evt->value = (int16_t)((evt->value * cfg->scale_multiplier) / cfg->scale_divisor); +} + +static void clear_xy_data(struct input_listener_xy_data *data) { + data->x = data->y = 0; + data->mode = INPUT_LISTENER_XY_DATA_MODE_NONE; +} + +static void input_handler(const struct input_listener_config *config, + struct input_listener_data *data, struct input_event *evt) { + // First, filter to update the event data as needed. + filter_with_input_config(config, evt); + + switch (evt->type) { + case INPUT_EV_REL: + handle_rel_code(data, evt); + break; + case INPUT_EV_KEY: + handle_key_code(data, evt); + break; + } + + if (evt->sync) { + if (data->wheel_data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) { + zmk_hid_mouse_scroll_set(data->wheel_data.x, data->wheel_data.y); + } + + if (data->data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) { + zmk_hid_mouse_movement_set(data->data.x, data->data.y); + } + + if (data->button_set != 0) { + for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { + if ((data->button_set & BIT(i)) != 0) { + zmk_hid_mouse_button_press(i); + } + } + } + + if (data->button_clear != 0) { + for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { + if ((data->button_set & BIT(i)) != 0) { + zmk_hid_mouse_button_release(i); + } + } + } + + zmk_endpoints_send_mouse_report(); + zmk_hid_mouse_scroll_set(0, 0); + zmk_hid_mouse_movement_set(0, 0); + + clear_xy_data(&data->data); + clear_xy_data(&data->wheel_data); + + data->button_set = data->button_clear = 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), \ + }; \ + 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); + +DT_INST_FOREACH_STATUS_OKAY(IL_INST)