From 94c17d6f88ba48a0d96065789b966e0603f6d9f5 Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Wed, 15 Nov 2023 21:11:41 -0800 Subject: [PATCH 01/14] feat(mouse): Add mouse move and scroll support [WIP] Co-authored-by: Alexander Krikun Co-authored-by: Robert U Co-authored-by: Shawn Meier --- app/CMakeLists.txt | 10 +- app/Kconfig | 8 +- app/dts/behaviors.dtsi | 3 + app/dts/behaviors/mouse_move.dtsi | 12 ++ app/dts/behaviors/mouse_scroll.dtsi | 12 ++ .../behaviors/zmk,behavior-mouse-move.yaml | 13 ++ .../behaviors/zmk,behavior-mouse-scroll.yaml | 13 ++ app/include/dt-bindings/zmk/mouse.h | 36 +++- .../zmk/events/mouse_move_state_changed.h | 33 ++++ .../zmk/events/mouse_scroll_state_changed.h | 34 ++++ app/include/zmk/events/mouse_tick.h | 39 +++++ app/include/zmk/hid.h | 28 ++- app/include/zmk/mouse.h | 19 +- app/src/behaviors/behavior_mouse_move.c | 57 ++++++ app/src/behaviors/behavior_mouse_scroll.c | 58 +++++++ app/src/events/mouse_move_state_changed.c | 10 ++ app/src/events/mouse_scroll_state_changed.c | 10 ++ app/src/events/mouse_tick.c | 10 ++ app/src/hid.c | 33 +++- app/src/hog.c | 1 - app/src/main.c | 7 + app/src/mouse.c | 43 ----- app/src/mouse/Kconfig | 38 ++++ app/src/mouse/key_listener.c | 163 ++++++++++++++++++ app/src/mouse/main.c | 30 ++++ app/src/mouse/tick_listener.c | 106 ++++++++++++ app/tests/mouse-keys/mmv/events.patterns | 1 + .../mouse-keys/mmv/keycode_events.snapshot | 2 + app/tests/mouse-keys/mmv/native_posix.keymap | 26 +++ docs/docs/intro.md | 2 +- 30 files changed, 794 insertions(+), 63 deletions(-) create mode 100644 app/dts/behaviors/mouse_move.dtsi create mode 100644 app/dts/behaviors/mouse_scroll.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml create mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml create mode 100644 app/include/zmk/events/mouse_move_state_changed.h create mode 100644 app/include/zmk/events/mouse_scroll_state_changed.h create mode 100644 app/include/zmk/events/mouse_tick.h create mode 100644 app/src/behaviors/behavior_mouse_move.c create mode 100644 app/src/behaviors/behavior_mouse_scroll.c create mode 100644 app/src/events/mouse_move_state_changed.c create mode 100644 app/src/events/mouse_scroll_state_changed.c create mode 100644 app/src/events/mouse_tick.c delete mode 100644 app/src/mouse.c create mode 100644 app/src/mouse/Kconfig create mode 100644 app/src/mouse/key_listener.c create mode 100644 app/src/mouse/main.c create mode 100644 app/src/mouse/tick_listener.c create mode 100644 app/tests/mouse-keys/mmv/events.patterns create mode 100644 app/tests/mouse-keys/mmv/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mmv/native_posix.keymap diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index ab2e1502..b3218ff0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -27,6 +27,9 @@ target_sources(app PRIVATE src/behavior.c) target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_sideband_behaviors.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/physical_layouts.c) +target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/key_listener.c) +target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.c) +target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/tick_listener.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) @@ -37,6 +40,9 @@ target_sources(app PRIVATE src/events/activity_state_changed.c) target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) target_sources(app PRIVATE src/events/mouse_button_state_changed.c) +target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_move_state_changed.c) +target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_tick.c) +target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_scroll_state_changed.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c) target_sources(app PRIVATE src/behaviors/behavior_reset.c) @@ -44,7 +50,7 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/behavior_soft_off.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.c) + target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.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) @@ -63,6 +69,8 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c) + target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/behaviors/behavior_mouse_move.c) + target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/behaviors/behavior_mouse_scroll.c) target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) target_sources(app PRIVATE src/behavior_queue.c) diff --git a/app/Kconfig b/app/Kconfig index a45f2dc2..7250fcfc 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -373,13 +373,7 @@ endif #Display/LED Options endmenu -menu "Mouse Options" - -config ZMK_MOUSE - bool "Enable ZMK mouse emulation" - -#Mouse Options -endmenu +rsource "src/mouse/Kconfig" menu "Power Management" diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index fde75271..27bc78a6 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -21,3 +21,6 @@ #include #include #include +#include +#include +#include diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi new file mode 100644 index 00000000..2e165f3a --- /dev/null +++ b/app/dts/behaviors/mouse_move.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + /omit-if-no-ref/ mmv: behavior_mouse_move { + compatible = "zmk,behavior-mouse-move"; + label = "MOUSE_MOVE"; + #binding-cells = <1>; + delay-ms = <0>; + time-to-max-speed-ms = <300>; + acceleration-exponent = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi new file mode 100644 index 00000000..f2cb86f6 --- /dev/null +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + /omit-if-no-ref/ msc: behavior_mouse_scroll { + compatible = "zmk,behavior-mouse-scroll"; + label = "MOUSE_SCROLL"; + #binding-cells = <1>; + delay-ms = <0>; + time-to-max-speed-ms = <300>; + acceleration-exponent = <0>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml new file mode 100644 index 00000000..73ec34ec --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml @@ -0,0 +1,13 @@ +description: Mouse move + +compatible: "zmk,behavior-mouse-move" + +include: one_param.yaml + +properties: + delay-ms: + type: int + time-to-max-speed-ms: + type: int + acceleration-exponent: + type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml new file mode 100644 index 00000000..5a932bc5 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml @@ -0,0 +1,13 @@ +description: Mouse scroll + +compatible: "zmk,behavior-mouse-scroll" + +include: one_param.yaml + +properties: + delay-ms: + type: int + time-to-max-speed-ms: + type: int + acceleration-exponent: + type: int diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 582518af..861f9a90 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2023 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -22,3 +22,37 @@ #define MB4 BIT(3) #define MB5 BIT(4) + +#ifndef ZMK_MOUSE_DEFAULT_MOVE_VAL +#define ZMK_MOUSE_DEFAULT_MOVE_VAL 600 +#endif + +#ifndef ZMK_MOUSE_DEFAULT_SCRL_VAL +#define ZMK_MOUSE_DEFAULT_SCRL_VAL 10 +#endif + +/* Mouse move behavior */ +#define MOVE_Y(vert) ((vert)&0xFFFF) +#define MOVE_Y_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) +#define MOVE_X(hor) (((hor)&0xFFFF) << 16) +#define MOVE_X_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) + +#define MOVE(hor, vert) (MOVE_X(hor) + MOVE_Y(vert)) + +#define MOVE_UP MOVE_Y(-ZMK_MOUSE_DEFAULT_MOVE_VAL) +#define MOVE_DOWN MOVE_Y(ZMK_MOUSE_DEFAULT_MOVE_VAL) +#define MOVE_LEFT MOVE_X(-ZMK_MOUSE_DEFAULT_MOVE_VAL) +#define MOVE_RIGHT MOVE_X(ZMK_MOUSE_DEFAULT_MOVE_VAL) + +/* Mouse scroll behavior */ +#define SCRL_Y(vert) ((vert)&0xFFFF) +#define SCRL_Y_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) +#define SCRL_X(hor) (((hor)&0xFFFF) << 16) +#define SCRL_X_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) + +#define SCROLL(hor, vert) (SCRL_X(hor) + SCRL_Y(vert)) + +#define SCRL_UP SCRL_Y(ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_DOWN SCRL_Y(-ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_LEFT SCRL_X(-ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_RIGHT SCRL_X(ZMK_MOUSE_DEFAULT_SCRL_VAL) diff --git a/app/include/zmk/events/mouse_move_state_changed.h b/app/include/zmk/events/mouse_move_state_changed.h new file mode 100644 index 00000000..d1ebad87 --- /dev/null +++ b/app/include/zmk/events/mouse_move_state_changed.h @@ -0,0 +1,33 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_mouse_move_state_changed { + struct vector2d max_speed; + struct mouse_config config; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_move_state_changed); + +static inline struct zmk_mouse_move_state_changed_event * +zmk_mouse_move_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, + bool pressed, int64_t timestamp) { + struct vector2d max_speed = (struct vector2d){ + .x = MOVE_X_DECODE(encoded), + .y = MOVE_Y_DECODE(encoded), + }; + + return new_zmk_mouse_move_state_changed((struct zmk_mouse_move_state_changed){ + .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_scroll_state_changed.h b/app/include/zmk/events/mouse_scroll_state_changed.h new file mode 100644 index 00000000..bf03308f --- /dev/null +++ b/app/include/zmk/events/mouse_scroll_state_changed.h @@ -0,0 +1,34 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +struct zmk_mouse_scroll_state_changed { + struct vector2d max_speed; + struct mouse_config config; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_scroll_state_changed); + +static inline struct zmk_mouse_scroll_state_changed_event * +zmk_mouse_scroll_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, + bool pressed, int64_t timestamp) { + struct vector2d max_speed = (struct vector2d){ + .x = SCRL_X_DECODE(encoded), + .y = SCRL_Y_DECODE(encoded), + }; + + return new_zmk_mouse_scroll_state_changed((struct zmk_mouse_scroll_state_changed){ + .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h new file mode 100644 index 00000000..2f69b045 --- /dev/null +++ b/app/include/zmk/events/mouse_tick.h @@ -0,0 +1,39 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +struct zmk_mouse_tick { + struct vector2d max_move; + struct vector2d max_scroll; + struct mouse_config move_config; + struct mouse_config scroll_config; + int64_t *start_time; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_tick); + +static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move, + struct vector2d max_scroll, + struct mouse_config move_config, + struct mouse_config scroll_config, + int64_t *movement_start) { + return new_zmk_mouse_tick((struct zmk_mouse_tick){ + .max_move = max_move, + .max_scroll = max_scroll, + .move_config = move_config, + .scroll_config = scroll_config, + .start_time = movement_start, + .timestamp = k_uptime_get(), + }); +} diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index 41f559b5..aa59f369 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -61,6 +61,10 @@ #define ZMK_HID_REPORT_ID_CONSUMER 0x02 #define ZMK_HID_REPORT_ID_MOUSE 0x03 +// Needed until Zephyr offers a 2 byte usage macro +#define HID_USAGE16(idx) \ + HID_ITEM(HID_ITEM_TAG_USAGE, HID_ITEM_TYPE_LOCAL, 2), (idx & 0xFF), (idx >> 8 & 0xFF) + static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), HID_USAGE(HID_USAGE_GD_KEYBOARD), @@ -169,11 +173,18 @@ static const uint8_t zmk_hid_report_desc[] = { HID_USAGE(HID_USAGE_GD_X), HID_USAGE(HID_USAGE_GD_Y), HID_USAGE(HID_USAGE_GD_WHEEL), - HID_LOGICAL_MIN8(-0x7F), - HID_LOGICAL_MAX8(0x7F), - HID_REPORT_SIZE(0x08), + HID_LOGICAL_MIN16(0xFF, -0x7F), + HID_LOGICAL_MAX16(0xFF, 0x7F), + HID_REPORT_SIZE(0x10), HID_REPORT_COUNT(0x03), HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), + HID_USAGE_PAGE(HID_USAGE_CONSUMER), + HID_USAGE16(HID_USAGE_CONSUMER_AC_PAN), + HID_LOGICAL_MIN16(0xFF, -0x7F), + HID_LOGICAL_MAX16(0xFF, 0x7F), + HID_REPORT_SIZE(0x08), + HID_REPORT_COUNT(0x01), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), HID_END_COLLECTION, HID_END_COLLECTION, #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) @@ -242,9 +253,10 @@ struct zmk_hid_consumer_report { #if IS_ENABLED(CONFIG_ZMK_MOUSE) struct zmk_hid_mouse_report_body { zmk_mouse_button_flags_t buttons; - int8_t d_x; - int8_t d_y; - int8_t d_wheel; + int16_t d_x; + int16_t d_y; + int16_t d_scroll_y; + int16_t d_scroll_x; } __packed; struct zmk_hid_mouse_report { @@ -285,6 +297,10 @@ int zmk_hid_mouse_button_press(zmk_mouse_button_t button); int zmk_hid_mouse_button_release(zmk_mouse_button_t button); int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); +void zmk_hid_mouse_movement_set(int16_t x, int16_t y); +void zmk_hid_mouse_scroll_set(int8_t x, int8_t y); +void zmk_hid_mouse_movement_update(int16_t x, int16_t y); +void zmk_hid_mouse_scroll_update(int8_t x, int8_t y); void zmk_hid_mouse_clear(void); #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index d873f156..1944ea47 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 The ZMK Contributors + * Copyright (c) 2023 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -10,3 +10,20 @@ typedef uint8_t zmk_mouse_button_flags_t; typedef uint16_t zmk_mouse_button_t; + +struct mouse_config { + int delay_ms; + int time_to_max_speed_ms; + // acceleration exponent 0: uniform speed + // acceleration exponent 1: uniform acceleration + // acceleration exponent 2: uniform jerk + int acceleration_exponent; +}; + +struct vector2d { + float x; + float y; +}; + +struct k_work_q *zmk_mouse_work_q(); +int zmk_mouse_init(); diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c new file mode 100644 index 00000000..0d591f00 --- /dev/null +++ b/app/src/behaviors/behavior_mouse_move.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_move + +#include +#include +#include + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_mouse_move_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE( + zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, + false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_mouse_move_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + static struct mouse_config behavior_mouse_move_config_##n = { \ + .delay_ms = DT_INST_PROP(n, delay_ms), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_mouse_move_init, NULL, NULL, \ + &behavior_mouse_move_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_mouse_scroll.c b/app/src/behaviors/behavior_mouse_scroll.c new file mode 100644 index 00000000..d7167172 --- /dev/null +++ b/app/src/behaviors/behavior_mouse_scroll.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_scroll + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_mouse_scroll_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, + true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, + false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_mouse_scroll_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + static struct mouse_config behavior_mouse_scroll_config_##n = { \ + .delay_ms = DT_INST_PROP(n, delay_ms), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ + }; \ + DEVICE_DT_INST_DEFINE(n, behavior_mouse_scroll_init, NULL, NULL, \ + &behavior_mouse_scroll_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/events/mouse_move_state_changed.c b/app/src/events/mouse_move_state_changed.c new file mode 100644 index 00000000..07a789b2 --- /dev/null +++ b/app/src/events/mouse_move_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_move_state_changed); diff --git a/app/src/events/mouse_scroll_state_changed.c b/app/src/events/mouse_scroll_state_changed.c new file mode 100644 index 00000000..f6216d39 --- /dev/null +++ b/app/src/events/mouse_scroll_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_scroll_state_changed); diff --git a/app/src/events/mouse_tick.c b/app/src/events/mouse_tick.c new file mode 100644 index 00000000..846b3fae --- /dev/null +++ b/app/src/events/mouse_tick.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_tick); diff --git a/app/src/hid.c b/app/src/hid.c index 582db676..cfa8fb7b 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -27,8 +27,9 @@ static uint8_t keys_held = 0; #if IS_ENABLED(CONFIG_ZMK_MOUSE) -static struct zmk_hid_mouse_report mouse_report = {.report_id = ZMK_HID_REPORT_ID_MOUSE, - .body = {.buttons = 0}}; +static struct zmk_hid_mouse_report mouse_report = { + .report_id = ZMK_HID_REPORT_ID_MOUSE, + .body = {.buttons = 0, .d_x = 0, .d_y = 0, .d_scroll_y = 0}}; #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) @@ -430,6 +431,34 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { } return 0; } + +void zmk_hid_mouse_movement_set(int16_t x, int16_t y) { + mouse_report.body.d_x = x; + mouse_report.body.d_y = y; + LOG_DBG("Mouse movement set to 0x%02X 0x%02X ", mouse_report.body.d_x, mouse_report.body.d_y); +} + +void zmk_hid_mouse_movement_update(int16_t x, int16_t y) { + mouse_report.body.d_x += x; + mouse_report.body.d_y += y; + LOG_DBG("Mouse movement updated to 0x%02X 0x%02X ", mouse_report.body.d_x, + mouse_report.body.d_y); +} + +void zmk_hid_mouse_scroll_set(int8_t x, int8_t y) { + mouse_report.body.d_scroll_x = x; + mouse_report.body.d_scroll_y = y; + LOG_DBG("Mouse scroll set to X: 0x%02X Y: 0x%02X", mouse_report.body.d_scroll_x, + mouse_report.body.d_scroll_y); +} + +void zmk_hid_mouse_scroll_update(int8_t x, int8_t y) { + mouse_report.body.d_scroll_x += x; + mouse_report.body.d_scroll_y += y; + LOG_DBG("Mouse scroll updated to X: 0x%02X Y: 0x%02X", mouse_report.body.d_scroll_x, + mouse_report.body.d_scroll_y); +} + void zmk_hid_mouse_clear(void) { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) diff --git a/app/src/hog.c b/app/src/hog.c index 82fafc29..f5d4377a 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -380,7 +380,6 @@ int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) { return 0; }; - #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) static int zmk_hog_init(void) { diff --git a/app/src/main.c b/app/src/main.c index 60df1a45..a6ea2abd 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -14,6 +14,10 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #include +#ifdef CONFIG_ZMK_MOUSE +#include +#endif /* CONFIG_ZMK_MOUSE */ + int main(void) { LOG_INF("Welcome to ZMK!\n"); @@ -26,5 +30,8 @@ int main(void) { zmk_display_init(); #endif /* CONFIG_ZMK_DISPLAY */ +#ifdef CONFIG_ZMK_MOUSE + zmk_mouse_init(); +#endif /* CONFIG_ZMK_MOUSE */ return 0; } diff --git a/app/src/mouse.c b/app/src/mouse.c deleted file mode 100644 index c1b9ac02..00000000 --- a/app/src/mouse.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#include -#include -#include -#include - -static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { - LOG_DBG("buttons: 0x%02X", ev->buttons); - zmk_hid_mouse_buttons_press(ev->buttons); - zmk_endpoints_send_mouse_report(); -} - -static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) { - LOG_DBG("buttons: 0x%02X", ev->buttons); - zmk_hid_mouse_buttons_release(ev->buttons); - zmk_endpoints_send_mouse_report(); -} - -int mouse_listener(const zmk_event_t *eh) { - const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh); - if (mbt_ev) { - if (mbt_ev->state) { - listener_mouse_button_pressed(mbt_ev); - } else { - listener_mouse_button_released(mbt_ev); - } - return 0; - } - return 0; -} - -ZMK_LISTENER(mouse_listener, mouse_listener); -ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed); diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig new file mode 100644 index 00000000..0b299844 --- /dev/null +++ b/app/src/mouse/Kconfig @@ -0,0 +1,38 @@ +# Copyright (c) 2023 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig ZMK_MOUSE + bool "Mouse Emulation" + +if ZMK_MOUSE + +config ZMK_MOUSE_TICK_DURATION + int "Mouse tick duration in ms" + default 8 + + +choice ZMK_MOUSE_WORK_QUEUE + prompt "Work queue selection for mouse events" + default ZMK_MOUSE_WORK_QUEUE_DEDICATED + +config ZMK_MOUSE_WORK_QUEUE_SYSTEM + bool "Use default system work queue for mouse events" + +config ZMK_MOUSE_WORK_QUEUE_DEDICATED + bool "Use dedicated work queue for mouse events" + +endchoice + +if ZMK_MOUSE_WORK_QUEUE_DEDICATED + +config ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE + int "Stack size for dedicated mouse thread/queue" + default 2048 + +config ZMK_MOUSE_DEDICATED_THREAD_PRIORITY + int "Thread priority for dedicated mouse thread/queue" + default 3 + +endif # ZMK_MOUSE_WORK_QUEUE_DEDICATED + +endif diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c new file mode 100644 index 00000000..91c4c5ce --- /dev/null +++ b/app/src/mouse/key_listener.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) +static struct vector2d move_speed = {0}; +static struct vector2d scroll_speed = {0}; +static struct mouse_config move_config = (struct mouse_config){0}; +static struct mouse_config scroll_config = (struct mouse_config){0}; +static int64_t start_time = 0; + +bool equals(const struct mouse_config *one, const struct mouse_config *other) { + return one->delay_ms == other->delay_ms && + one->time_to_max_speed_ms == other->time_to_max_speed_ms && + one->acceleration_exponent == other->acceleration_exponent; +} + +static void clear_mouse_state(struct k_work *work) { + move_speed = (struct vector2d){0}; + scroll_speed = (struct vector2d){0}; + start_time = 0; + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + LOG_DBG("Clearing state"); +} + +K_WORK_DEFINE(mouse_clear, &clear_mouse_state); + +void mouse_clear_cb(struct k_timer *dummy) { + k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_clear); +} + +static void mouse_tick_timer_handler(struct k_work *work) { + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + LOG_DBG("Raising mouse tick event"); + ZMK_EVENT_RAISE( + zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time)); + zmk_endpoints_send_mouse_report(); +} + +K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler); + +void mouse_timer_cb(struct k_timer *dummy) { + LOG_DBG("Submitting mouse work to queue"); + k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); +} + +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb); + +static int mouse_timer_ref_count = 0; + +void mouse_timer_ref() { + if (mouse_timer_ref_count == 0) { + start_time = k_uptime_get(); + k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); + } + mouse_timer_ref_count += 1; +} + +void mouse_timer_unref() { + if (mouse_timer_ref_count > 0) { + mouse_timer_ref_count--; + } + if (mouse_timer_ref_count == 0) { + k_timer_stop(&mouse_timer); + } +} + +static void listener_mouse_move_pressed(const struct zmk_mouse_move_state_changed *ev) { + move_speed.x += ev->max_speed.x; + move_speed.y += ev->max_speed.y; + mouse_timer_ref(); +} + +static void listener_mouse_move_released(const struct zmk_mouse_move_state_changed *ev) { + move_speed.x -= ev->max_speed.x; + move_speed.y -= ev->max_speed.y; + mouse_timer_unref(); +} + +static void listener_mouse_scroll_pressed(const struct zmk_mouse_scroll_state_changed *ev) { + scroll_speed.x += ev->max_speed.x; + scroll_speed.y += ev->max_speed.y; + mouse_timer_ref(); +} + +static void listener_mouse_scroll_released(const struct zmk_mouse_scroll_state_changed *ev) { + scroll_speed.x -= ev->max_speed.x; + scroll_speed.y -= ev->max_speed.y; + mouse_timer_unref(); +} + +static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_press(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_release(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +int mouse_listener(const zmk_event_t *eh) { + const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh); + if (mmv_ev) { + if (!equals(&move_config, &(mmv_ev->config))) + move_config = mmv_ev->config; + + if (mmv_ev->state) { + listener_mouse_move_pressed(mmv_ev); + } else { + listener_mouse_move_released(mmv_ev); + } + return 0; + } + const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh); + if (msc_ev) { + if (!equals(&scroll_config, &(msc_ev->config))) + scroll_config = msc_ev->config; + if (msc_ev->state) { + listener_mouse_scroll_pressed(msc_ev); + } else { + listener_mouse_scroll_released(msc_ev); + } + return 0; + } + const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh); + if (mbt_ev) { + if (mbt_ev->state) { + listener_mouse_button_pressed(mbt_ev); + } else { + listener_mouse_button_released(mbt_ev); + } + return 0; + } + return 0; +} + +ZMK_LISTENER(mouse_listener, mouse_listener); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_move_state_changed); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_scroll_state_changed); + +#endif /*!defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c new file mode 100644 index 00000000..e5b5252f --- /dev/null +++ b/app/src/mouse/main.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) +K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE); +static struct k_work_q mouse_work_q; +#endif + +struct k_work_q *zmk_mouse_work_q() { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + return &mouse_work_q; +#else + return &k_sys_work_q; +#endif +} + +int zmk_mouse_init() { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + k_work_queue_start(&mouse_work_q, mouse_work_stack_area, + K_THREAD_STACK_SIZEOF(mouse_work_stack_area), + CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY, NULL); +#endif + return 0; +} \ No newline at end of file diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c new file mode 100644 index 00000000..f84b29f7 --- /dev/null +++ b/app/src/mouse/tick_listener.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include // CLAMP + +#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) +#if CONFIG_MINIMAL_LIBC +static float powf(float base, float exponent) { + // poor man's power implementation rounds the exponent down to the nearest integer. + float power = 1.0f; + for (; exponent >= 1.0f; exponent--) { + power = power * base; + } + return power; +} +#else +#include +#endif + +struct vector2d move_remainder = {0}; +struct vector2d scroll_remainder = {0}; + +static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) { + int64_t move_duration = now - (start + delay); + // start can be in the future if there's a delay + if (move_duration < 0) { + move_duration = 0; + } + return move_duration; +} + +static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) { + // Calculate the speed based on MouseKeysAccel + // See https://en.wikipedia.org/wiki/Mouse_keys + if (duration_ms > config->time_to_max_speed_ms || config->time_to_max_speed_ms == 0 || + config->acceleration_exponent == 0) { + return max_speed; + } + float time_fraction = (float)duration_ms / config->time_to_max_speed_ms; + return max_speed * powf(time_fraction, config->acceleration_exponent); +} + +static void track_remainder(float *move, float *remainder) { + float new_move = *move + *remainder; + *remainder = new_move - (int)new_move; + *move = (int)new_move; +} + +static struct vector2d update_movement(struct vector2d *remainder, + const struct mouse_config *config, struct vector2d max_speed, + int64_t now, int64_t *start_time) { + struct vector2d move = {0}; + if (max_speed.x == 0 && max_speed.y == 0) { + *remainder = (struct vector2d){0}; + return move; + } + + int64_t move_duration = ms_since_start(*start_time, now, config->delay_ms); + move = (struct vector2d){ + .x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + .y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + }; + + track_remainder(&(move.x), &(remainder->x)); + track_remainder(&(move.y), &(remainder->y)); + + return move; +} + +static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { + struct vector2d move = update_movement(&move_remainder, &(tick->move_config), tick->max_move, + tick->timestamp, tick->start_time); + zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), + (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); + struct vector2d scroll = update_movement(&scroll_remainder, &(tick->scroll_config), + tick->max_scroll, tick->timestamp, tick->start_time); + zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), + (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); +} + +int zmk_mouse_tick_listener(const zmk_event_t *eh) { + const struct zmk_mouse_tick *tick = as_zmk_mouse_tick(eh); + if (tick) { + mouse_tick_handler(tick); + return 0; + } + return 0; +} + +ZMK_LISTENER(zmk_mouse_tick_listener, zmk_mouse_tick_listener); +ZMK_SUBSCRIPTION(zmk_mouse_tick_listener, zmk_mouse_tick); + +#endif /* !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/tests/mouse-keys/mmv/events.patterns b/app/tests/mouse-keys/mmv/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/mouse-keys/mmv/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mmv/keycode_events.snapshot b/app/tests/mouse-keys/mmv/keycode_events.snapshot new file mode 100644 index 00000000..259501ba --- /dev/null +++ b/app/tests/mouse-keys/mmv/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/mouse-keys/mmv/native_posix.keymap b/app/tests/mouse-keys/mmv/native_posix.keymap new file mode 100644 index 00000000..dbb3f014 --- /dev/null +++ b/app/tests/mouse-keys/mmv/native_posix.keymap @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &none + &none &none + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/docs/docs/intro.md b/docs/docs/intro.md index e11eda71..c0c70ab0 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -33,7 +33,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | One Shot Keys | ✅ | ✅ | ✅ | | [Combo Keys](features/combos.md) | ✅ | | ✅ | | [Macros](behaviors/macros.md) | ✅ | ✅ | ✅ | -| Mouse Keys | 🚧 | ✅ | ✅ | +| Mouse Keys | ✅ | ✅ | ✅ | | Low Active Power Usage | ✅ | | | | Low Power Sleep States | ✅ | ✅ | | | [Low Power Mode (VCC Shutoff)](behaviors/power.md) | ✅ | ✅ | | From 04022d24858026a1e0c6b80baed2a31bb3a5fe4e Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Sun, 15 Oct 2023 23:27:45 -0700 Subject: [PATCH 02/14] feat(mouse): Split move/scroll & x/y acceleration --- app/include/zmk/events/mouse_tick.h | 6 +-- app/include/zmk/mouse.h | 7 +++ app/src/mouse/key_listener.c | 70 ++++++++++++++++++++++------- app/src/mouse/tick_listener.c | 21 +++++---- 4 files changed, 77 insertions(+), 27 deletions(-) diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h index 2f69b045..75a041e9 100644 --- a/app/include/zmk/events/mouse_tick.h +++ b/app/include/zmk/events/mouse_tick.h @@ -17,7 +17,7 @@ struct zmk_mouse_tick { struct vector2d max_scroll; struct mouse_config move_config; struct mouse_config scroll_config; - int64_t *start_time; + struct mouse_times start_times; int64_t timestamp; }; @@ -27,13 +27,13 @@ static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_mo struct vector2d max_scroll, struct mouse_config move_config, struct mouse_config scroll_config, - int64_t *movement_start) { + struct mouse_times movement_start) { return new_zmk_mouse_tick((struct zmk_mouse_tick){ .max_move = max_move, .max_scroll = max_scroll, .move_config = move_config, .scroll_config = scroll_config, - .start_time = movement_start, + .start_times = movement_start, .timestamp = k_uptime_get(), }); } diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index 1944ea47..c2ae6252 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -25,5 +25,12 @@ struct vector2d { float y; }; +struct mouse_times { + uint64_t m_x; + uint64_t m_y; + uint64_t s_x; + uint64_t s_y; +}; + struct k_work_q *zmk_mouse_work_q(); int zmk_mouse_init(); diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c index 91c4c5ce..bd06efeb 100644 --- a/app/src/mouse/key_listener.c +++ b/app/src/mouse/key_listener.c @@ -23,7 +23,7 @@ static struct vector2d move_speed = {0}; static struct vector2d scroll_speed = {0}; static struct mouse_config move_config = (struct mouse_config){0}; static struct mouse_config scroll_config = (struct mouse_config){0}; -static int64_t start_time = 0; +static struct mouse_times start_times = (struct mouse_times){0}; bool equals(const struct mouse_config *one, const struct mouse_config *other) { return one->delay_ms == other->delay_ms && @@ -34,7 +34,7 @@ bool equals(const struct mouse_config *one, const struct mouse_config *other) { static void clear_mouse_state(struct k_work *work) { move_speed = (struct vector2d){0}; scroll_speed = (struct vector2d){0}; - start_time = 0; + start_times = (struct mouse_times){0}; zmk_hid_mouse_movement_set(0, 0); zmk_hid_mouse_scroll_set(0, 0); LOG_DBG("Clearing state"); @@ -51,7 +51,7 @@ static void mouse_tick_timer_handler(struct k_work *work) { zmk_hid_mouse_scroll_set(0, 0); LOG_DBG("Raising mouse tick event"); ZMK_EVENT_RAISE( - zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time)); + zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, start_times)); zmk_endpoints_send_mouse_report(); } @@ -64,21 +64,59 @@ void mouse_timer_cb(struct k_timer *dummy) { K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb); -static int mouse_timer_ref_count = 0; +static struct { + int m_x; + int m_y; + int s_x; + int s_y; +} mouse_timer_ref_counts = {0, 0, 0, 0}; -void mouse_timer_ref() { - if (mouse_timer_ref_count == 0) { - start_time = k_uptime_get(); +void mouse_timer_ref(bool m_x, bool m_y, bool s_x, bool s_y) { + if (m_x && mouse_timer_ref_counts.m_x == 0) { + start_times.m_x = k_uptime_get(); + } + if (m_y && mouse_timer_ref_counts.m_y == 0) { + start_times.m_y = k_uptime_get(); + } + if (s_x && mouse_timer_ref_counts.s_x == 0) { + start_times.s_x = k_uptime_get(); + } + if (s_y && mouse_timer_ref_counts.s_y == 0) { + start_times.s_y = k_uptime_get(); + } + if (mouse_timer_ref_counts.m_x == 0 && mouse_timer_ref_counts.m_y == 0 && + mouse_timer_ref_counts.s_x == 0 && mouse_timer_ref_counts.s_y == 0) { k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); } - mouse_timer_ref_count += 1; + if (m_x) { + mouse_timer_ref_counts.m_x++; + } + if (m_y) { + mouse_timer_ref_counts.m_y++; + } + if (s_x) { + mouse_timer_ref_counts.s_x++; + } + if (s_y) { + mouse_timer_ref_counts.s_y++; + } } -void mouse_timer_unref() { - if (mouse_timer_ref_count > 0) { - mouse_timer_ref_count--; +void mouse_timer_unref(bool m_x, bool m_y, bool s_x, bool s_y) { + if (m_x && mouse_timer_ref_counts.m_x > 0) { + mouse_timer_ref_counts.m_x--; } - if (mouse_timer_ref_count == 0) { + if (m_y && mouse_timer_ref_counts.m_y > 0) { + mouse_timer_ref_counts.m_y--; + } + if (s_x && mouse_timer_ref_counts.s_x > 0) { + mouse_timer_ref_counts.s_x--; + } + if (s_y && mouse_timer_ref_counts.s_y > 0) { + mouse_timer_ref_counts.s_y--; + } + if (mouse_timer_ref_counts.m_x == 0 && mouse_timer_ref_counts.m_y == 0 && + mouse_timer_ref_counts.s_x == 0 && mouse_timer_ref_counts.s_y == 0) { k_timer_stop(&mouse_timer); } } @@ -86,25 +124,25 @@ void mouse_timer_unref() { static void listener_mouse_move_pressed(const struct zmk_mouse_move_state_changed *ev) { move_speed.x += ev->max_speed.x; move_speed.y += ev->max_speed.y; - mouse_timer_ref(); + mouse_timer_ref(ev->max_speed.x != 0, ev->max_speed.y != 0, false, false); } static void listener_mouse_move_released(const struct zmk_mouse_move_state_changed *ev) { move_speed.x -= ev->max_speed.x; move_speed.y -= ev->max_speed.y; - mouse_timer_unref(); + mouse_timer_unref(ev->max_speed.x != 0, ev->max_speed.y != 0, false, false); } static void listener_mouse_scroll_pressed(const struct zmk_mouse_scroll_state_changed *ev) { scroll_speed.x += ev->max_speed.x; scroll_speed.y += ev->max_speed.y; - mouse_timer_ref(); + mouse_timer_ref(false, false, ev->max_speed.x != 0, ev->max_speed.y != 0); } static void listener_mouse_scroll_released(const struct zmk_mouse_scroll_state_changed *ev) { scroll_speed.x -= ev->max_speed.x; scroll_speed.y -= ev->max_speed.y; - mouse_timer_unref(); + mouse_timer_unref(false, false, ev->max_speed.x != 0, ev->max_speed.y != 0); } static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c index f84b29f7..90aaf111 100644 --- a/app/src/mouse/tick_listener.c +++ b/app/src/mouse/tick_listener.c @@ -61,17 +61,18 @@ static void track_remainder(float *move, float *remainder) { static struct vector2d update_movement(struct vector2d *remainder, const struct mouse_config *config, struct vector2d max_speed, - int64_t now, int64_t *start_time) { + int64_t now, int64_t start_time_x, int64_t start_time_y) { struct vector2d move = {0}; if (max_speed.x == 0 && max_speed.y == 0) { *remainder = (struct vector2d){0}; return move; } - int64_t move_duration = ms_since_start(*start_time, now, config->delay_ms); + int64_t move_duration_x = ms_since_start(start_time_x, now, config->delay_ms); + int64_t move_duration_y = ms_since_start(start_time_y, now, config->delay_ms); move = (struct vector2d){ - .x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, - .y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + .x = speed(config, max_speed.x, move_duration_x) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + .y = speed(config, max_speed.y, move_duration_y) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, }; track_remainder(&(move.x), &(remainder->x)); @@ -81,12 +82,16 @@ static struct vector2d update_movement(struct vector2d *remainder, } static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { - struct vector2d move = update_movement(&move_remainder, &(tick->move_config), tick->max_move, - tick->timestamp, tick->start_time); + LOG_INF("tick start times: %lld %lld %lld %lld", tick->start_times.m_x, tick->start_times.m_y, + tick->start_times.s_x, tick->start_times.s_y); + struct vector2d move = + update_movement(&move_remainder, &(tick->move_config), tick->max_move, tick->timestamp, + tick->start_times.m_x, tick->start_times.m_y); zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); - struct vector2d scroll = update_movement(&scroll_remainder, &(tick->scroll_config), - tick->max_scroll, tick->timestamp, tick->start_time); + struct vector2d scroll = + update_movement(&scroll_remainder, &(tick->scroll_config), tick->max_scroll, + tick->timestamp, tick->start_times.s_x, tick->start_times.s_y); zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); } From c26b4817b16648f660925ac717145e1dd8af8c77 Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Wed, 15 Nov 2023 23:41:26 -0800 Subject: [PATCH 03/14] fix(mouse): Bump up default mouse tick duration to prevent crashes --- app/src/mouse/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig index 0b299844..f44d2d1d 100644 --- a/app/src/mouse/Kconfig +++ b/app/src/mouse/Kconfig @@ -8,7 +8,7 @@ if ZMK_MOUSE config ZMK_MOUSE_TICK_DURATION int "Mouse tick duration in ms" - default 8 + default 16 choice ZMK_MOUSE_WORK_QUEUE From e38fd7887842f8085849828eebe0d7262c6618ec Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Tue, 21 Nov 2023 00:30:25 +0000 Subject: [PATCH 04/14] refactor: Use input system for pointer events. --- app/CMakeLists.txt | 10 +- app/Kconfig.behaviors | 6 + app/dts/behaviors/mouse_move.dtsi | 10 +- app/dts/behaviors/mouse_scroll.dtsi | 10 +- .../zmk,behavior-input-two-axis.yaml | 21 ++ .../behaviors/zmk,behavior-mouse-move.yaml | 13 - .../behaviors/zmk,behavior-mouse-scroll.yaml | 13 - app/include/dt-bindings/zmk/mouse.h | 16 +- .../zmk/events/mouse_move_state_changed.h | 33 --- .../zmk/events/mouse_scroll_state_changed.h | 34 --- app/include/zmk/events/mouse_tick.h | 39 --- app/include/zmk/mouse.h | 24 +- app/src/behaviors/behavior_input_two_axis.c | 270 ++++++++++++++++++ app/src/behaviors/behavior_mouse_key_press.c | 25 +- app/src/behaviors/behavior_mouse_move.c | 57 ---- app/src/behaviors/behavior_mouse_scroll.c | 58 ---- app/src/events/mouse_move_state_changed.c | 10 - app/src/events/mouse_scroll_state_changed.c | 10 - app/src/events/mouse_tick.c | 10 - app/src/hid.c | 14 +- app/src/mouse/Kconfig | 2 + app/src/mouse/hid_input_listener.c | 72 +++++ app/src/mouse/key_listener.c | 201 ------------- app/src/mouse/main.c | 2 +- app/src/mouse/tick_listener.c | 111 ------- app/tests/mouse-keys/mmv/events.patterns | 1 - .../mouse-keys/mmv/keycode_events.snapshot | 2 - .../mouse-move/move_diagonal/events.patterns | 1 + .../move_diagonal/keycode_events.snapshot | 22 ++ .../move_diagonal/native_posix_64.keymap | 28 ++ .../mouse-move/move_x/events.patterns | 1 + .../mouse-move/move_x/keycode_events.snapshot | 27 ++ .../mouse-move/move_x/native_posix_64.keymap | 28 ++ .../mouse-move/move_y/events.patterns | 1 + .../mouse-move/move_y/keycode_events.snapshot | 27 ++ .../move_y/native_posix_64.keymap} | 4 +- 36 files changed, 556 insertions(+), 657 deletions(-) create mode 100644 app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml delete mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml delete mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml delete mode 100644 app/include/zmk/events/mouse_move_state_changed.h delete mode 100644 app/include/zmk/events/mouse_scroll_state_changed.h delete mode 100644 app/include/zmk/events/mouse_tick.h create mode 100644 app/src/behaviors/behavior_input_two_axis.c delete mode 100644 app/src/behaviors/behavior_mouse_move.c delete mode 100644 app/src/behaviors/behavior_mouse_scroll.c delete mode 100644 app/src/events/mouse_move_state_changed.c delete mode 100644 app/src/events/mouse_scroll_state_changed.c delete mode 100644 app/src/events/mouse_tick.c create mode 100644 app/src/mouse/hid_input_listener.c delete mode 100644 app/src/mouse/key_listener.c delete mode 100644 app/src/mouse/tick_listener.c delete mode 100644 app/tests/mouse-keys/mmv/events.patterns delete mode 100644 app/tests/mouse-keys/mmv/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mouse-move/move_diagonal/events.patterns create mode 100644 app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap create mode 100644 app/tests/mouse-keys/mouse-move/move_x/events.patterns create mode 100644 app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap create mode 100644 app/tests/mouse-keys/mouse-move/move_y/events.patterns create mode 100644 app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot rename app/tests/mouse-keys/{mmv/native_posix.keymap => mouse-move/move_y/native_posix_64.keymap} (79%) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b3218ff0..822383d2 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -27,9 +27,7 @@ target_sources(app PRIVATE src/behavior.c) target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_sideband_behaviors.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/physical_layouts.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/key_listener.c) target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/tick_listener.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) @@ -39,10 +37,6 @@ target_sources_ifdef(CONFIG_ZMK_GPIO_KEY_WAKEUP_TRIGGER app PRIVATE src/gpio_key target_sources(app PRIVATE src/events/activity_state_changed.c) target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) -target_sources(app PRIVATE src/events/mouse_button_state_changed.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_move_state_changed.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_tick.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/events/mouse_scroll_state_changed.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c) target_sources(app PRIVATE src/behaviors/behavior_reset.c) @@ -51,6 +45,7 @@ target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/beha 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/main.c) + target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/hid_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) @@ -69,8 +64,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c) target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c) - target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/behaviors/behavior_mouse_move.c) - target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/behaviors/behavior_mouse_scroll.c) + target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_INPUT_TWO_AXIS app PRIVATE src/behaviors/behavior_input_two_axis.c) target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c) target_sources(app PRIVATE src/behavior_queue.c) diff --git a/app/Kconfig.behaviors b/app/Kconfig.behaviors index d3f4537e..3aa256a9 100644 --- a/app/Kconfig.behaviors +++ b/app/Kconfig.behaviors @@ -56,6 +56,12 @@ config ZMK_BEHAVIOR_SOFT_OFF default y depends on DT_HAS_ZMK_BEHAVIOR_SOFT_OFF_ENABLED && ZMK_PM_SOFT_OFF +config ZMK_BEHAVIOR_INPUT_TWO_AXIS + bool + default y + depends on DT_HAS_ZMK_BEHAVIOR_INPUT_TWO_AXIS_ENABLED + imply ZMK_MOUSE + config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON bool diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index 2e165f3a..0bfc87d0 100644 --- a/app/dts/behaviors/mouse_move.dtsi +++ b/app/dts/behaviors/mouse_move.dtsi @@ -1,10 +1,12 @@ +#include + / { behaviors { - /omit-if-no-ref/ mmv: behavior_mouse_move { - compatible = "zmk,behavior-mouse-move"; - label = "MOUSE_MOVE"; + /omit-if-no-ref/ mmv: mouse_move { + compatible = "zmk,behavior-input-two-axis"; #binding-cells = <1>; - delay-ms = <0>; + x-input-code = ; + y-input-code = ; time-to-max-speed-ms = <300>; acceleration-exponent = <1>; }; diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi index f2cb86f6..69c48fee 100644 --- a/app/dts/behaviors/mouse_scroll.dtsi +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -1,10 +1,12 @@ +#include + / { behaviors { - /omit-if-no-ref/ msc: behavior_mouse_scroll { - compatible = "zmk,behavior-mouse-scroll"; - label = "MOUSE_SCROLL"; + /omit-if-no-ref/ msc: mouse_scroll { + compatible = "zmk,behavior-input-two-axis"; #binding-cells = <1>; - delay-ms = <0>; + x-input-code = ; + y-input-code = ; time-to-max-speed-ms = <300>; acceleration-exponent = <0>; }; diff --git a/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml b/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml new file mode 100644 index 00000000..820ee703 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml @@ -0,0 +1,21 @@ +description: Two axis input behavior + +compatible: "zmk,behavior-input-two-axis" + +include: one_param.yaml + +properties: + x-input-code: + type: int + required: true + y-input-code: + type: int + required: true + delay-ms: + type: int + time-to-max-speed-ms: + type: int + required: true + acceleration-exponent: + type: int + default: 1 diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml deleted file mode 100644 index 73ec34ec..00000000 --- a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Mouse move - -compatible: "zmk,behavior-mouse-move" - -include: one_param.yaml - -properties: - delay-ms: - type: int - time-to-max-speed-ms: - type: int - acceleration-exponent: - type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml deleted file mode 100644 index 5a932bc5..00000000 --- a/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Mouse scroll - -compatible: "zmk,behavior-mouse-scroll" - -include: one_param.yaml - -properties: - delay-ms: - type: int - time-to-max-speed-ms: - type: int - acceleration-exponent: - type: int diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 861f9a90..ea34e124 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -44,15 +44,7 @@ #define MOVE_LEFT MOVE_X(-ZMK_MOUSE_DEFAULT_MOVE_VAL) #define MOVE_RIGHT MOVE_X(ZMK_MOUSE_DEFAULT_MOVE_VAL) -/* Mouse scroll behavior */ -#define SCRL_Y(vert) ((vert)&0xFFFF) -#define SCRL_Y_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) -#define SCRL_X(hor) (((hor)&0xFFFF) << 16) -#define SCRL_X_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) - -#define SCROLL(hor, vert) (SCRL_X(hor) + SCRL_Y(vert)) - -#define SCRL_UP SCRL_Y(ZMK_MOUSE_DEFAULT_SCRL_VAL) -#define SCRL_DOWN SCRL_Y(-ZMK_MOUSE_DEFAULT_SCRL_VAL) -#define SCRL_LEFT SCRL_X(-ZMK_MOUSE_DEFAULT_SCRL_VAL) -#define SCRL_RIGHT SCRL_X(ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_UP MOVE_Y(ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_DOWN MOVE_Y(-ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_LEFT MOVE_X(-ZMK_MOUSE_DEFAULT_SCRL_VAL) +#define SCRL_RIGHT MOVE_X(ZMK_MOUSE_DEFAULT_SCRL_VAL) diff --git a/app/include/zmk/events/mouse_move_state_changed.h b/app/include/zmk/events/mouse_move_state_changed.h deleted file mode 100644 index d1ebad87..00000000 --- a/app/include/zmk/events/mouse_move_state_changed.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#pragma once - -#include -#include -#include - -struct zmk_mouse_move_state_changed { - struct vector2d max_speed; - struct mouse_config config; - bool state; - int64_t timestamp; -}; - -ZMK_EVENT_DECLARE(zmk_mouse_move_state_changed); - -static inline struct zmk_mouse_move_state_changed_event * -zmk_mouse_move_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, - bool pressed, int64_t timestamp) { - struct vector2d max_speed = (struct vector2d){ - .x = MOVE_X_DECODE(encoded), - .y = MOVE_Y_DECODE(encoded), - }; - - return new_zmk_mouse_move_state_changed((struct zmk_mouse_move_state_changed){ - .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); -} diff --git a/app/include/zmk/events/mouse_scroll_state_changed.h b/app/include/zmk/events/mouse_scroll_state_changed.h deleted file mode 100644 index bf03308f..00000000 --- a/app/include/zmk/events/mouse_scroll_state_changed.h +++ /dev/null @@ -1,34 +0,0 @@ - -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#pragma once - -#include -#include -#include -#include - -struct zmk_mouse_scroll_state_changed { - struct vector2d max_speed; - struct mouse_config config; - bool state; - int64_t timestamp; -}; - -ZMK_EVENT_DECLARE(zmk_mouse_scroll_state_changed); - -static inline struct zmk_mouse_scroll_state_changed_event * -zmk_mouse_scroll_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, - bool pressed, int64_t timestamp) { - struct vector2d max_speed = (struct vector2d){ - .x = SCRL_X_DECODE(encoded), - .y = SCRL_Y_DECODE(encoded), - }; - - return new_zmk_mouse_scroll_state_changed((struct zmk_mouse_scroll_state_changed){ - .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); -} diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h deleted file mode 100644 index 75a041e9..00000000 --- a/app/include/zmk/events/mouse_tick.h +++ /dev/null @@ -1,39 +0,0 @@ - -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#pragma once - -#include -#include -#include -#include - -struct zmk_mouse_tick { - struct vector2d max_move; - struct vector2d max_scroll; - struct mouse_config move_config; - struct mouse_config scroll_config; - struct mouse_times start_times; - int64_t timestamp; -}; - -ZMK_EVENT_DECLARE(zmk_mouse_tick); - -static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move, - struct vector2d max_scroll, - struct mouse_config move_config, - struct mouse_config scroll_config, - struct mouse_times movement_start) { - return new_zmk_mouse_tick((struct zmk_mouse_tick){ - .max_move = max_move, - .max_scroll = max_scroll, - .move_config = move_config, - .scroll_config = scroll_config, - .start_times = movement_start, - .timestamp = k_uptime_get(), - }); -} diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index c2ae6252..28dab60d 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -11,26 +11,4 @@ typedef uint8_t zmk_mouse_button_flags_t; typedef uint16_t zmk_mouse_button_t; -struct mouse_config { - int delay_ms; - int time_to_max_speed_ms; - // acceleration exponent 0: uniform speed - // acceleration exponent 1: uniform acceleration - // acceleration exponent 2: uniform jerk - int acceleration_exponent; -}; - -struct vector2d { - float x; - float y; -}; - -struct mouse_times { - uint64_t m_x; - uint64_t m_y; - uint64_t s_x; - uint64_t s_y; -}; - -struct k_work_q *zmk_mouse_work_q(); -int zmk_mouse_init(); +int zmk_mouse_init(void); diff --git a/app/src/behaviors/behavior_input_two_axis.c b/app/src/behaviors/behavior_input_two_axis.c new file mode 100644 index 00000000..5a94895e --- /dev/null +++ b/app/src/behaviors/behavior_input_two_axis.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_input_two_axis + +#include +#include +#include +#include +#include // CLAMP + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct vector2d { + float x; + float y; +}; + +struct movement_state_1d { + float remainder; + int16_t speed; + uint64_t start_time; +}; + +struct movement_state_2d { + struct movement_state_1d x; + struct movement_state_1d y; +}; + +struct behavior_input_two_axis_data { + struct k_work_delayable tick_work; + const struct device *dev; + + struct movement_state_2d state; +}; + +struct behavior_input_two_axis_config { + int16_t x_code; + int16_t y_code; + int delay_ms; + int time_to_max_speed_ms; + // acceleration exponent 0: uniform speed + // acceleration exponent 1: uniform acceleration + // acceleration exponent 2: uniform jerk + int acceleration_exponent; +}; + +#if CONFIG_MINIMAL_LIBC +static float powf(float base, float exponent) { + // poor man's power implementation rounds the exponent down to the nearest integer. + float power = 1.0f; + for (; exponent >= 1.0f; exponent--) { + power = power * base; + } + return power; +} +#else +#include +#endif + +static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) { + if (start == 0) { + return 0; + } + int64_t move_duration = now - (start + delay); + // start can be in the future if there's a delay + if (move_duration < 0) { + move_duration = 0; + } + return move_duration; +} + +static float speed(const struct behavior_input_two_axis_config *config, float max_speed, + int64_t duration_ms) { + // Calculate the speed based on MouseKeysAccel + // See https://en.wikipedia.org/wiki/Mouse_keys + if (duration_ms == 0) { + return 0; + } + + if (duration_ms > config->time_to_max_speed_ms || config->time_to_max_speed_ms == 0 || + config->acceleration_exponent == 0) { + return max_speed; + } + float time_fraction = (float)duration_ms / config->time_to_max_speed_ms; + return max_speed * powf(time_fraction, config->acceleration_exponent); +} + +static void track_remainder(float *move, float *remainder) { + float new_move = *move + *remainder; + *remainder = new_move - (int)new_move; + *move = (int)new_move; +} + +static float update_movement_1d(const struct behavior_input_two_axis_config *config, + struct movement_state_1d *state, int64_t now) { + float move = 0; + if (state->speed == 0) { + state->remainder = 0; + return move; + } + + int64_t move_duration = ms_since_start(state->start_time, now, config->delay_ms); + move = + (move_duration > 0) + ? (speed(config, state->speed, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000) + : 0; + + track_remainder(&(move), &(state->remainder)); + + return move; +} +static struct vector2d update_movement_2d(const struct behavior_input_two_axis_config *config, + struct movement_state_2d *state, int64_t now) { + struct vector2d move = {0}; + + move = (struct vector2d){ + .x = update_movement_1d(config, &state->x, now), + .y = update_movement_1d(config, &state->y, now), + }; + + return move; +} + +static bool is_non_zero_1d_movement(int16_t speed) { return speed != 0; } + +static bool is_non_zero_2d_movement(struct movement_state_2d *state) { + return is_non_zero_1d_movement(state->x.speed) || is_non_zero_1d_movement(state->y.speed); +} + +static bool should_be_working(struct behavior_input_two_axis_data *data) { + return is_non_zero_2d_movement(&data->state); +} + +static void tick_work_cb(struct k_work *work) { + struct k_work_delayable *d_work = k_work_delayable_from_work(work); + struct behavior_input_two_axis_data *data = + CONTAINER_OF(d_work, struct behavior_input_two_axis_data, tick_work); + const struct device *dev = data->dev; + const struct behavior_input_two_axis_config *cfg = dev->config; + + uint32_t timestamp = k_uptime_get(); + + LOG_INF("tick start times: %lld %lld %lld", data->state.x.start_time, data->state.y.start_time, + timestamp); + + struct vector2d move = update_movement_2d(cfg, &data->state, timestamp); + + int ret = 0; + bool have_x = is_non_zero_1d_movement(move.x); + bool have_y = is_non_zero_1d_movement(move.y); + if (have_x) { + ret = input_report_rel(dev, cfg->x_code, (int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), + !have_y, K_NO_WAIT); + } + if (have_y) { + ret = input_report_rel(dev, cfg->y_code, (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX), true, + K_NO_WAIT); + } + + if (should_be_working(data)) { + k_work_schedule(&data->tick_work, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); + } +} + +static void set_start_times_for_activity(struct movement_state_2d *state) { + if (state->x.speed != 0 && state->x.start_time == 0) { + state->x.start_time = k_uptime_get(); + } + + if (state->y.speed != 0 && state->y.start_time == 0) { + state->y.start_time = k_uptime_get(); + } +} + +static void update_work_scheduling(const struct device *dev) { + struct behavior_input_two_axis_data *data = dev->data; + + set_start_times_for_activity(&data->state); + + if (should_be_working(data)) { + k_work_schedule(&data->tick_work, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); + } else { + k_work_cancel_delayable(&data->tick_work); + } +} + +int zmk_input_synth_pointer_adjust_speed(const struct device *dev, int16_t dx, int16_t dy) { + struct behavior_input_two_axis_data *data = dev->data; + + LOG_DBG("Adjusting: %d %d", dx, dy); + data->state.x.speed += dx; + data->state.y.speed += dy; + + LOG_DBG("After: %d %d", data->state.x.speed, data->state.y.speed); + + update_work_scheduling(dev); + + return 0; +} + +// static void process_key_state(const struct device *dev, int32_t val, bool pressed) { +// for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { +// if (val & BIT(i)) { +// WRITE_BIT(val, i, 0); +// input_report_key(dev, INPUT_BTN_0 + i, pressed ? 1 : 0, val == 0, K_FOREVER); +// } +// } +// } + +static int behavior_input_two_axis_init(const struct device *dev) { + struct behavior_input_two_axis_data *data = dev->data; + + data->dev = dev; + k_work_init_delayable(&data->tick_work, tick_work_cb); + + return 0; +}; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + + const struct device *behavior_dev = zmk_behavior_get_binding(binding->behavior_dev); + + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + + int16_t x = MOVE_X_DECODE(binding->param1); + int16_t y = MOVE_Y_DECODE(binding->param1); + + zmk_input_synth_pointer_adjust_speed(behavior_dev, x, y); + return 0; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *behavior_dev = zmk_behavior_get_binding(binding->behavior_dev); + + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + + int16_t x = MOVE_X_DECODE(binding->param1); + int16_t y = MOVE_Y_DECODE(binding->param1); + + zmk_input_synth_pointer_adjust_speed(behavior_dev, -x, -y); + return 0; +} + +static const struct behavior_driver_api behavior_input_two_axis_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define ITA_INST(n) \ + static struct behavior_input_two_axis_data behavior_input_two_axis_data_##n = {}; \ + static struct behavior_input_two_axis_config behavior_input_two_axis_config_##n = { \ + .x_code = DT_INST_PROP(n, x_input_code), \ + .y_code = DT_INST_PROP(n, y_input_code), \ + .delay_ms = DT_INST_PROP_OR(n, delay_ms, 0), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = DT_INST_PROP_OR(n, acceleration_exponent, 1), \ + }; \ + BEHAVIOR_DT_INST_DEFINE( \ + n, behavior_input_two_axis_init, NULL, &behavior_input_two_axis_data_##n, \ + &behavior_input_two_axis_config_##n, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_input_two_axis_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(ITA_INST) diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c index 9064a1aa..66b54fce 100644 --- a/app/src/behaviors/behavior_mouse_key_press.c +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -11,8 +11,9 @@ #include #include -#include -#include +#include +#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -20,19 +21,31 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_mouse_key_press_init(const struct device *dev) { return 0; }; +static void process_key_state(const struct device *dev, int32_t val, bool pressed) { + for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { + if (val & BIT(i)) { + WRITE_BIT(val, i, 0); + input_report_key(dev, INPUT_BTN_0 + i, pressed ? 1 : 0, val == 0, K_FOREVER); + } + } +} + static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, true, - event.timestamp); + process_key_state(zmk_behavior_get_binding(binding->behavior_dev), binding->param1, true); + + return 0; } static int on_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - return raise_zmk_mouse_button_state_changed_from_encoded(binding->param1, false, - event.timestamp); + + process_key_state(zmk_behavior_get_binding(binding->behavior_dev), binding->param1, false); + + return 0; } static const struct behavior_driver_api behavior_mouse_key_press_driver_api = { diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c deleted file mode 100644 index 0d591f00..00000000 --- a/app/src/behaviors/behavior_mouse_move.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#define DT_DRV_COMPAT zmk_behavior_mouse_move - -#include -#include -#include - -#include -#include -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) - -static int behavior_mouse_move_init(const struct device *dev) { return 0; }; - -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - const struct device *dev = device_get_binding(binding->behavior_dev); - const struct mouse_config *config = dev->config; - return ZMK_EVENT_RAISE( - zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, true, event.timestamp)); -} - -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - const struct device *dev = device_get_binding(binding->behavior_dev); - const struct mouse_config *config = dev->config; - return ZMK_EVENT_RAISE(zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, - false, event.timestamp)); -} - -static const struct behavior_driver_api behavior_mouse_move_driver_api = { - .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; - -#define KP_INST(n) \ - static struct mouse_config behavior_mouse_move_config_##n = { \ - .delay_ms = DT_INST_PROP(n, delay_ms), \ - .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ - .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ - }; \ - DEVICE_DT_INST_DEFINE(n, behavior_mouse_move_init, NULL, NULL, \ - &behavior_mouse_move_config_##n, APPLICATION, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(KP_INST) - -#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_mouse_scroll.c b/app/src/behaviors/behavior_mouse_scroll.c deleted file mode 100644 index d7167172..00000000 --- a/app/src/behaviors/behavior_mouse_scroll.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2021 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#define DT_DRV_COMPAT zmk_behavior_mouse_scroll - -#include -#include -#include - -#include -#include -#include -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) - -static int behavior_mouse_scroll_init(const struct device *dev) { return 0; }; - -static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - const struct device *dev = device_get_binding(binding->behavior_dev); - const struct mouse_config *config = dev->config; - return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, - true, event.timestamp)); -} - -static int on_keymap_binding_released(struct zmk_behavior_binding *binding, - struct zmk_behavior_binding_event event) { - LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - const struct device *dev = device_get_binding(binding->behavior_dev); - const struct mouse_config *config = dev->config; - return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, - false, event.timestamp)); -} - -static const struct behavior_driver_api behavior_mouse_scroll_driver_api = { - .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; - -#define KP_INST(n) \ - static struct mouse_config behavior_mouse_scroll_config_##n = { \ - .delay_ms = DT_INST_PROP(n, delay_ms), \ - .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ - .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ - }; \ - DEVICE_DT_INST_DEFINE(n, behavior_mouse_scroll_init, NULL, NULL, \ - &behavior_mouse_scroll_config_##n, APPLICATION, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(KP_INST) - -#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/events/mouse_move_state_changed.c b/app/src/events/mouse_move_state_changed.c deleted file mode 100644 index 07a789b2..00000000 --- a/app/src/events/mouse_move_state_changed.c +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -ZMK_EVENT_IMPL(zmk_mouse_move_state_changed); diff --git a/app/src/events/mouse_scroll_state_changed.c b/app/src/events/mouse_scroll_state_changed.c deleted file mode 100644 index f6216d39..00000000 --- a/app/src/events/mouse_scroll_state_changed.c +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -ZMK_EVENT_IMPL(zmk_mouse_scroll_state_changed); diff --git a/app/src/events/mouse_tick.c b/app/src/events/mouse_tick.c deleted file mode 100644 index 846b3fae..00000000 --- a/app/src/events/mouse_tick.c +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -ZMK_EVENT_IMPL(zmk_mouse_tick); diff --git a/app/src/hid.c b/app/src/hid.c index cfa8fb7b..d6b2344c 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -435,31 +435,33 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { void zmk_hid_mouse_movement_set(int16_t x, int16_t y) { mouse_report.body.d_x = x; mouse_report.body.d_y = y; - LOG_DBG("Mouse movement set to 0x%02X 0x%02X ", mouse_report.body.d_x, mouse_report.body.d_y); + LOG_DBG("Mouse movement set to %d/%d", mouse_report.body.d_x, mouse_report.body.d_y); } void zmk_hid_mouse_movement_update(int16_t x, int16_t y) { mouse_report.body.d_x += x; mouse_report.body.d_y += y; - LOG_DBG("Mouse movement updated to 0x%02X 0x%02X ", mouse_report.body.d_x, - mouse_report.body.d_y); + LOG_DBG("Mouse movement updated to %d/%d", mouse_report.body.d_x, mouse_report.body.d_y); } void zmk_hid_mouse_scroll_set(int8_t x, int8_t y) { mouse_report.body.d_scroll_x = x; mouse_report.body.d_scroll_y = y; - LOG_DBG("Mouse scroll set to X: 0x%02X Y: 0x%02X", mouse_report.body.d_scroll_x, + LOG_DBG("Mouse scroll set to %d/%d", mouse_report.body.d_scroll_x, mouse_report.body.d_scroll_y); } void zmk_hid_mouse_scroll_update(int8_t x, int8_t y) { mouse_report.body.d_scroll_x += x; mouse_report.body.d_scroll_y += y; - LOG_DBG("Mouse scroll updated to X: 0x%02X Y: 0x%02X", mouse_report.body.d_scroll_x, + LOG_DBG("Mouse scroll updated to X: %d/%d", mouse_report.body.d_scroll_x, mouse_report.body.d_scroll_y); } -void zmk_hid_mouse_clear(void) { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } +void zmk_hid_mouse_clear(void) { + LOG_DBG("Mouse report cleared"); + memset(&mouse_report.body, 0, sizeof(mouse_report.body)); +} #endif // IS_ENABLED(CONFIG_ZMK_MOUSE) diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig index f44d2d1d..972c0c6f 100644 --- a/app/src/mouse/Kconfig +++ b/app/src/mouse/Kconfig @@ -3,6 +3,8 @@ menuconfig ZMK_MOUSE bool "Mouse Emulation" + select INPUT + select INPUT_THREAD_PRIORITY_OVERRIDE if ZMK_MOUSE diff --git a/app/src/mouse/hid_input_listener.c b/app/src/mouse/hid_input_listener.c new file mode 100644 index 00000000..6c053755 --- /dev/null +++ b/app/src/mouse/hid_input_listener.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#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; + } +} + +void input_handler(struct input_event *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/key_listener.c b/app/src/mouse/key_listener.c deleted file mode 100644 index bd06efeb..00000000 --- a/app/src/mouse/key_listener.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2021 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) -static struct vector2d move_speed = {0}; -static struct vector2d scroll_speed = {0}; -static struct mouse_config move_config = (struct mouse_config){0}; -static struct mouse_config scroll_config = (struct mouse_config){0}; -static struct mouse_times start_times = (struct mouse_times){0}; - -bool equals(const struct mouse_config *one, const struct mouse_config *other) { - return one->delay_ms == other->delay_ms && - one->time_to_max_speed_ms == other->time_to_max_speed_ms && - one->acceleration_exponent == other->acceleration_exponent; -} - -static void clear_mouse_state(struct k_work *work) { - move_speed = (struct vector2d){0}; - scroll_speed = (struct vector2d){0}; - start_times = (struct mouse_times){0}; - zmk_hid_mouse_movement_set(0, 0); - zmk_hid_mouse_scroll_set(0, 0); - LOG_DBG("Clearing state"); -} - -K_WORK_DEFINE(mouse_clear, &clear_mouse_state); - -void mouse_clear_cb(struct k_timer *dummy) { - k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_clear); -} - -static void mouse_tick_timer_handler(struct k_work *work) { - zmk_hid_mouse_movement_set(0, 0); - zmk_hid_mouse_scroll_set(0, 0); - LOG_DBG("Raising mouse tick event"); - ZMK_EVENT_RAISE( - zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, start_times)); - zmk_endpoints_send_mouse_report(); -} - -K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler); - -void mouse_timer_cb(struct k_timer *dummy) { - LOG_DBG("Submitting mouse work to queue"); - k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); -} - -K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb); - -static struct { - int m_x; - int m_y; - int s_x; - int s_y; -} mouse_timer_ref_counts = {0, 0, 0, 0}; - -void mouse_timer_ref(bool m_x, bool m_y, bool s_x, bool s_y) { - if (m_x && mouse_timer_ref_counts.m_x == 0) { - start_times.m_x = k_uptime_get(); - } - if (m_y && mouse_timer_ref_counts.m_y == 0) { - start_times.m_y = k_uptime_get(); - } - if (s_x && mouse_timer_ref_counts.s_x == 0) { - start_times.s_x = k_uptime_get(); - } - if (s_y && mouse_timer_ref_counts.s_y == 0) { - start_times.s_y = k_uptime_get(); - } - if (mouse_timer_ref_counts.m_x == 0 && mouse_timer_ref_counts.m_y == 0 && - mouse_timer_ref_counts.s_x == 0 && mouse_timer_ref_counts.s_y == 0) { - k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); - } - if (m_x) { - mouse_timer_ref_counts.m_x++; - } - if (m_y) { - mouse_timer_ref_counts.m_y++; - } - if (s_x) { - mouse_timer_ref_counts.s_x++; - } - if (s_y) { - mouse_timer_ref_counts.s_y++; - } -} - -void mouse_timer_unref(bool m_x, bool m_y, bool s_x, bool s_y) { - if (m_x && mouse_timer_ref_counts.m_x > 0) { - mouse_timer_ref_counts.m_x--; - } - if (m_y && mouse_timer_ref_counts.m_y > 0) { - mouse_timer_ref_counts.m_y--; - } - if (s_x && mouse_timer_ref_counts.s_x > 0) { - mouse_timer_ref_counts.s_x--; - } - if (s_y && mouse_timer_ref_counts.s_y > 0) { - mouse_timer_ref_counts.s_y--; - } - if (mouse_timer_ref_counts.m_x == 0 && mouse_timer_ref_counts.m_y == 0 && - mouse_timer_ref_counts.s_x == 0 && mouse_timer_ref_counts.s_y == 0) { - k_timer_stop(&mouse_timer); - } -} - -static void listener_mouse_move_pressed(const struct zmk_mouse_move_state_changed *ev) { - move_speed.x += ev->max_speed.x; - move_speed.y += ev->max_speed.y; - mouse_timer_ref(ev->max_speed.x != 0, ev->max_speed.y != 0, false, false); -} - -static void listener_mouse_move_released(const struct zmk_mouse_move_state_changed *ev) { - move_speed.x -= ev->max_speed.x; - move_speed.y -= ev->max_speed.y; - mouse_timer_unref(ev->max_speed.x != 0, ev->max_speed.y != 0, false, false); -} - -static void listener_mouse_scroll_pressed(const struct zmk_mouse_scroll_state_changed *ev) { - scroll_speed.x += ev->max_speed.x; - scroll_speed.y += ev->max_speed.y; - mouse_timer_ref(false, false, ev->max_speed.x != 0, ev->max_speed.y != 0); -} - -static void listener_mouse_scroll_released(const struct zmk_mouse_scroll_state_changed *ev) { - scroll_speed.x -= ev->max_speed.x; - scroll_speed.y -= ev->max_speed.y; - mouse_timer_unref(false, false, ev->max_speed.x != 0, ev->max_speed.y != 0); -} - -static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { - LOG_DBG("buttons: 0x%02X", ev->buttons); - zmk_hid_mouse_buttons_press(ev->buttons); - zmk_endpoints_send_mouse_report(); -} - -static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) { - LOG_DBG("buttons: 0x%02X", ev->buttons); - zmk_hid_mouse_buttons_release(ev->buttons); - zmk_endpoints_send_mouse_report(); -} - -int mouse_listener(const zmk_event_t *eh) { - const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh); - if (mmv_ev) { - if (!equals(&move_config, &(mmv_ev->config))) - move_config = mmv_ev->config; - - if (mmv_ev->state) { - listener_mouse_move_pressed(mmv_ev); - } else { - listener_mouse_move_released(mmv_ev); - } - return 0; - } - const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh); - if (msc_ev) { - if (!equals(&scroll_config, &(msc_ev->config))) - scroll_config = msc_ev->config; - if (msc_ev->state) { - listener_mouse_scroll_pressed(msc_ev); - } else { - listener_mouse_scroll_released(msc_ev); - } - return 0; - } - const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh); - if (mbt_ev) { - if (mbt_ev->state) { - listener_mouse_button_pressed(mbt_ev); - } else { - listener_mouse_button_released(mbt_ev); - } - return 0; - } - return 0; -} - -ZMK_LISTENER(mouse_listener, mouse_listener); -ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed); -ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_move_state_changed); -ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_scroll_state_changed); - -#endif /*!defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c index e5b5252f..e1227425 100644 --- a/app/src/mouse/main.c +++ b/app/src/mouse/main.c @@ -20,7 +20,7 @@ struct k_work_q *zmk_mouse_work_q() { #endif } -int zmk_mouse_init() { +int zmk_mouse_init(void) { #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) k_work_queue_start(&mouse_work_q, mouse_work_stack_area, K_THREAD_STACK_SIZEOF(mouse_work_stack_area), diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c deleted file mode 100644 index 90aaf111..00000000 --- a/app/src/mouse/tick_listener.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#include -#include -#include -#include -#include - -#include // CLAMP - -#if !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) -#if CONFIG_MINIMAL_LIBC -static float powf(float base, float exponent) { - // poor man's power implementation rounds the exponent down to the nearest integer. - float power = 1.0f; - for (; exponent >= 1.0f; exponent--) { - power = power * base; - } - return power; -} -#else -#include -#endif - -struct vector2d move_remainder = {0}; -struct vector2d scroll_remainder = {0}; - -static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) { - int64_t move_duration = now - (start + delay); - // start can be in the future if there's a delay - if (move_duration < 0) { - move_duration = 0; - } - return move_duration; -} - -static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) { - // Calculate the speed based on MouseKeysAccel - // See https://en.wikipedia.org/wiki/Mouse_keys - if (duration_ms > config->time_to_max_speed_ms || config->time_to_max_speed_ms == 0 || - config->acceleration_exponent == 0) { - return max_speed; - } - float time_fraction = (float)duration_ms / config->time_to_max_speed_ms; - return max_speed * powf(time_fraction, config->acceleration_exponent); -} - -static void track_remainder(float *move, float *remainder) { - float new_move = *move + *remainder; - *remainder = new_move - (int)new_move; - *move = (int)new_move; -} - -static struct vector2d update_movement(struct vector2d *remainder, - const struct mouse_config *config, struct vector2d max_speed, - int64_t now, int64_t start_time_x, int64_t start_time_y) { - struct vector2d move = {0}; - if (max_speed.x == 0 && max_speed.y == 0) { - *remainder = (struct vector2d){0}; - return move; - } - - int64_t move_duration_x = ms_since_start(start_time_x, now, config->delay_ms); - int64_t move_duration_y = ms_since_start(start_time_y, now, config->delay_ms); - move = (struct vector2d){ - .x = speed(config, max_speed.x, move_duration_x) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, - .y = speed(config, max_speed.y, move_duration_y) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, - }; - - track_remainder(&(move.x), &(remainder->x)); - track_remainder(&(move.y), &(remainder->y)); - - return move; -} - -static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { - LOG_INF("tick start times: %lld %lld %lld %lld", tick->start_times.m_x, tick->start_times.m_y, - tick->start_times.s_x, tick->start_times.s_y); - struct vector2d move = - update_movement(&move_remainder, &(tick->move_config), tick->max_move, tick->timestamp, - tick->start_times.m_x, tick->start_times.m_y); - zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), - (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); - struct vector2d scroll = - update_movement(&scroll_remainder, &(tick->scroll_config), tick->max_scroll, - tick->timestamp, tick->start_times.s_x, tick->start_times.s_y); - zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), - (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); -} - -int zmk_mouse_tick_listener(const zmk_event_t *eh) { - const struct zmk_mouse_tick *tick = as_zmk_mouse_tick(eh); - if (tick) { - mouse_tick_handler(tick); - return 0; - } - return 0; -} - -ZMK_LISTENER(zmk_mouse_tick_listener, zmk_mouse_tick_listener); -ZMK_SUBSCRIPTION(zmk_mouse_tick_listener, zmk_mouse_tick); - -#endif /* !defined(CONFIG_ZMK_SPLIT) || defined(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */ diff --git a/app/tests/mouse-keys/mmv/events.patterns b/app/tests/mouse-keys/mmv/events.patterns deleted file mode 100644 index 833100f6..00000000 --- a/app/tests/mouse-keys/mmv/events.patterns +++ /dev/null @@ -1 +0,0 @@ -s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mmv/keycode_events.snapshot b/app/tests/mouse-keys/mmv/keycode_events.snapshot deleted file mode 100644 index 259501ba..00000000 --- a/app/tests/mouse-keys/mmv/keycode_events.snapshot +++ /dev/null @@ -1,2 +0,0 @@ -pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 -released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/mouse-keys/mouse-move/move_diagonal/events.patterns b/app/tests/mouse-keys/mouse-move/move_diagonal/events.patterns new file mode 100644 index 00000000..812126fb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_diagonal/events.patterns @@ -0,0 +1 @@ +s/.*hid_mouse_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot new file mode 100644 index 00000000..91c4f16b --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot @@ -0,0 +1,22 @@ +movement_update: Mouse movement updated to -1/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -2/0 +movement_update: Mouse movement updated to -2/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -2/0 +movement_update: Mouse movement updated to -2/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -3/0 +movement_update: Mouse movement updated to -3/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -3/0 +movement_update: Mouse movement updated to -3/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap new file mode 100644 index 00000000..9dfa5b2a --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &mmv MOVE_UP + &none &none + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_x/events.patterns b/app/tests/mouse-keys/mouse-move/move_x/events.patterns new file mode 100644 index 00000000..812126fb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_x/events.patterns @@ -0,0 +1 @@ +s/.*hid_mouse_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot new file mode 100644 index 00000000..027e83e9 --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot @@ -0,0 +1,27 @@ +movement_update: Mouse movement updated to -1/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -2/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -2/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -3/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 3/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 5/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 5/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 6/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 6/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap new file mode 100644 index 00000000..aacacebb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &mmv MOVE_RIGHT + &none &none + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_y/events.patterns b/app/tests/mouse-keys/mouse-move/move_y/events.patterns new file mode 100644 index 00000000..812126fb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_y/events.patterns @@ -0,0 +1 @@ +s/.*hid_mouse_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot new file mode 100644 index 00000000..178d5e74 --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot @@ -0,0 +1,27 @@ +movement_update: Mouse movement updated to 0/-1 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/5 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/5 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/6 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/6 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mmv/native_posix.keymap b/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap similarity index 79% rename from app/tests/mouse-keys/mmv/native_posix.keymap rename to app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap index dbb3f014..1d914136 100644 --- a/app/tests/mouse-keys/mmv/native_posix.keymap +++ b/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap @@ -10,7 +10,7 @@ default_layer { bindings = < - &mmv MOVE_LEFT &none + &mmv MOVE_UP &mmv MOVE_DOWN &none &none >; }; @@ -22,5 +22,7 @@ events = < ZMK_MOCK_PRESS(0,0,100) ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,1,10) >; }; \ No newline at end of file From b2f61631884c15bff8a8c67e648197ee3f450ff4 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Thu, 23 Nov 2023 22:23:13 +0000 Subject: [PATCH 05/14] feat(mouse): Add input configs for data mods. * Add ability to swap X/Y, invert X and Y values, and apply a scalar multiplier/divisor. --- app/CMakeLists.txt | 1 + app/dts/bindings/zmk,input-configs.yaml | 24 +++++++++++ app/include/zmk/mouse/input_config.h | 21 ++++++++++ app/src/behaviors/behavior_input_two_axis.c | 16 +++---- app/src/mouse/hid_input_listener.c | 38 +++++++++++++++++ app/src/mouse/input_config.c | 42 +++++++++++++++++++ .../move_diagonal_scaling/events.patterns | 1 + .../keycode_events.snapshot | 22 ++++++++++ .../native_posix_64.keymap | 38 +++++++++++++++++ .../move_diagonal_xy_invert/events.patterns | 1 + .../keycode_events.snapshot | 22 ++++++++++ .../native_posix_64.keymap | 38 +++++++++++++++++ .../move_diagonal_xy_swap/events.patterns | 1 + .../keycode_events.snapshot | 22 ++++++++++ .../native_posix_64.keymap | 37 ++++++++++++++++ .../mouse-move/move_x/keycode_events.snapshot | 21 ++++------ .../mouse-move/move_y/keycode_events.snapshot | 21 ++++------ 17 files changed, 335 insertions(+), 31 deletions(-) create mode 100644 app/dts/bindings/zmk,input-configs.yaml create mode 100644 app/include/zmk/mouse/input_config.h create mode 100644 app/src/mouse/input_config.c create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/events.patterns create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/events.patterns create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/events.patterns create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 822383d2..e3a16537 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -28,6 +28,7 @@ target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_s target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/physical_layouts.c) target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.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) diff --git a/app/dts/bindings/zmk,input-configs.yaml b/app/dts/bindings/zmk,input-configs.yaml new file mode 100644 index 00000000..83bd4a19 --- /dev/null +++ b/app/dts/bindings/zmk,input-configs.yaml @@ -0,0 +1,24 @@ +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/include/zmk/mouse/input_config.h b/app/include/zmk/mouse/input_config.h new file mode 100644 index 00000000..0a37b346 --- /dev/null +++ b/app/include/zmk/mouse/input_config.h @@ -0,0 +1,21 @@ +/* + * 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/behaviors/behavior_input_two_axis.c b/app/src/behaviors/behavior_input_two_axis.c index 5a94895e..5a6afe63 100644 --- a/app/src/behaviors/behavior_input_two_axis.c +++ b/app/src/behaviors/behavior_input_two_axis.c @@ -169,14 +169,16 @@ static void tick_work_cb(struct k_work *work) { } } +static void set_start_times_for_activity_1d(struct movement_state_1d *state) { + if (state->speed != 0 && state->start_time == 0) { + state->start_time = k_uptime_get(); + } else if (state->speed == 0) { + state->start_time = 0; + } +} static void set_start_times_for_activity(struct movement_state_2d *state) { - if (state->x.speed != 0 && state->x.start_time == 0) { - state->x.start_time = k_uptime_get(); - } - - if (state->y.speed != 0 && state->y.start_time == 0) { - state->y.start_time = k_uptime_get(); - } + set_start_times_for_activity_1d(&state->x); + set_start_times_for_activity_1d(&state->y); } static void update_work_scheduling(const struct device *dev) { diff --git a/app/src/mouse/hid_input_listener.c b/app/src/mouse/hid_input_listener.c index 6c053755..712bb567 100644 --- a/app/src/mouse/hid_input_listener.c +++ b/app/src/mouse/hid_input_listener.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -52,7 +53,44 @@ void handle_key_code(struct input_event *evt) { } } +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); diff --git a/app/src/mouse/input_config.c b/app/src/mouse/input_config.c new file mode 100644 index 00000000..745fb49b --- /dev/null +++ b/app/src/mouse/input_config.c @@ -0,0 +1,42 @@ +/* + * 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/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/events.patterns b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/events.patterns new file mode 100644 index 00000000..812126fb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/events.patterns @@ -0,0 +1 @@ +s/.*hid_mouse_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot new file mode 100644 index 00000000..99fa1488 --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot @@ -0,0 +1,22 @@ +movement_update: Mouse movement updated to -1/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -3/0 +movement_update: Mouse movement updated to -3/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -3/0 +movement_update: Mouse movement updated to -3/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -5/0 +movement_update: Mouse movement updated to -5/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -5/0 +movement_update: Mouse movement updated to -5/-5 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-5 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap new file mode 100644 index 00000000..b1ddbc1d --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &mmv MOVE_UP + &none &none + >; + }; + }; + + input_configs { + compatible = "zmk,input-configs"; + + mmv { + device = <&mmv>; + scale-multiplier = <5>; + scale-divisor = <3>; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/events.patterns b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/events.patterns new file mode 100644 index 00000000..812126fb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/events.patterns @@ -0,0 +1 @@ +s/.*hid_mouse_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot new file mode 100644 index 00000000..94faacce --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot @@ -0,0 +1,22 @@ +movement_update: Mouse movement updated to 1/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 2/0 +movement_update: Mouse movement updated to 2/2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 2/0 +movement_update: Mouse movement updated to 2/2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 3/0 +movement_update: Mouse movement updated to 3/2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 3/0 +movement_update: Mouse movement updated to 3/3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap new file mode 100644 index 00000000..4767e0ac --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &mmv MOVE_UP + &none &none + >; + }; + }; + + input_configs { + compatible = "zmk,input-configs"; + + mmv { + device = <&mmv>; + x-invert; + y-invert; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/events.patterns b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/events.patterns new file mode 100644 index 00000000..812126fb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/events.patterns @@ -0,0 +1 @@ +s/.*hid_mouse_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot new file mode 100644 index 00000000..5ca5300c --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot @@ -0,0 +1,22 @@ +movement_update: Mouse movement updated to 0/-1 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-2 +movement_update: Mouse movement updated to -2/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-2 +movement_update: Mouse movement updated to -2/-2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-3 +movement_update: Mouse movement updated to -2/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/-3 +movement_update: Mouse movement updated to -3/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to -3/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap new file mode 100644 index 00000000..15327023 --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &mmv MOVE_UP + &none &none + >; + }; + }; + + input_configs { + compatible = "zmk,input-configs"; + + mmv { + device = <&mmv>; + xy-swap; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,10) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_RELEASE(0,0,10) + ZMK_MOCK_RELEASE(0,1,10) + >; +}; \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot index 027e83e9..dfbc4a76 100644 --- a/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot @@ -10,18 +10,15 @@ movement_set: Mouse movement set to 0/0 movement_update: Mouse movement updated to -3/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 1/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 2/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 2/0 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 movement_update: Mouse movement updated to 3/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 5/0 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 5/0 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 6/0 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 6/0 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 \ No newline at end of file diff --git a/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot index 178d5e74..4fd9a252 100644 --- a/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot @@ -10,18 +10,15 @@ movement_set: Mouse movement set to 0/0 movement_update: Mouse movement updated to 0/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/1 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_update: Mouse movement updated to 0/2 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 movement_update: Mouse movement updated to 0/3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/5 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/5 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/6 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/6 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 From 4e53004502b8ec58da238365c148b906547bc7d6 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 11 Dec 2023 15:45:50 -0800 Subject: [PATCH 06/14] refactor(mouse): Remove mouse work queue, Kconfig * Remove now-unused mouse work queue and related mouse main file. * Move ticks config into a DTS property on the two axis input behavior. --- app/CMakeLists.txt | 2 -- .../zmk,behavior-input-two-axis.yaml | 4 +++ app/include/zmk/mouse.h | 2 -- app/src/behaviors/behavior_input_two_axis.c | 20 ++++++----- app/src/main.c | 3 -- app/src/mouse/Kconfig | 34 +------------------ app/src/mouse/main.c | 30 ---------------- 7 files changed, 16 insertions(+), 79 deletions(-) delete mode 100644 app/src/mouse/main.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e3a16537..e8ff7293 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -27,7 +27,6 @@ target_sources(app PRIVATE src/behavior.c) target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_sideband_behaviors.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/physical_layouts.c) -target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/main.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) @@ -45,7 +44,6 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/behavior_soft_off.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/main.c) target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse/hid_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) diff --git a/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml b/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml index 820ee703..0c138e03 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml @@ -11,6 +11,10 @@ properties: y-input-code: type: int required: true + trigger-period-ms: + type: int + default: 16 + description: The time (in ms) between generated inputs when an input has non-zero speed. delay-ms: type: int time-to-max-speed-ms: diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index 28dab60d..c898f001 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -10,5 +10,3 @@ typedef uint8_t zmk_mouse_button_flags_t; typedef uint16_t zmk_mouse_button_t; - -int zmk_mouse_init(void); diff --git a/app/src/behaviors/behavior_input_two_axis.c b/app/src/behaviors/behavior_input_two_axis.c index 5a6afe63..0146df86 100644 --- a/app/src/behaviors/behavior_input_two_axis.c +++ b/app/src/behaviors/behavior_input_two_axis.c @@ -43,12 +43,13 @@ struct behavior_input_two_axis_data { struct behavior_input_two_axis_config { int16_t x_code; int16_t y_code; - int delay_ms; - int time_to_max_speed_ms; + uint16_t delay_ms; + uint16_t time_to_max_speed_ms; + uint8_t trigger_period_ms; // acceleration exponent 0: uniform speed // acceleration exponent 1: uniform acceleration // acceleration exponent 2: uniform jerk - int acceleration_exponent; + uint8_t acceleration_exponent; }; #if CONFIG_MINIMAL_LIBC @@ -107,10 +108,9 @@ static float update_movement_1d(const struct behavior_input_two_axis_config *con } int64_t move_duration = ms_since_start(state->start_time, now, config->delay_ms); - move = - (move_duration > 0) - ? (speed(config, state->speed, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000) - : 0; + move = (move_duration > 0) + ? (speed(config, state->speed, move_duration) * config->trigger_period_ms / 1000) + : 0; track_remainder(&(move), &(state->remainder)); @@ -165,7 +165,7 @@ static void tick_work_cb(struct k_work *work) { } if (should_be_working(data)) { - k_work_schedule(&data->tick_work, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); + k_work_schedule(&data->tick_work, K_MSEC(cfg->trigger_period_ms)); } } @@ -183,11 +183,12 @@ static void set_start_times_for_activity(struct movement_state_2d *state) { static void update_work_scheduling(const struct device *dev) { struct behavior_input_two_axis_data *data = dev->data; + const struct behavior_input_two_axis_config *cfg = dev->config; set_start_times_for_activity(&data->state); if (should_be_working(data)) { - k_work_schedule(&data->tick_work, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); + k_work_schedule(&data->tick_work, K_MSEC(cfg->trigger_period_ms)); } else { k_work_cancel_delayable(&data->tick_work); } @@ -260,6 +261,7 @@ static const struct behavior_driver_api behavior_input_two_axis_driver_api = { static struct behavior_input_two_axis_config behavior_input_two_axis_config_##n = { \ .x_code = DT_INST_PROP(n, x_input_code), \ .y_code = DT_INST_PROP(n, y_input_code), \ + .trigger_period_ms = DT_INST_PROP(n, trigger_period_ms), \ .delay_ms = DT_INST_PROP_OR(n, delay_ms, 0), \ .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ .acceleration_exponent = DT_INST_PROP_OR(n, acceleration_exponent, 1), \ diff --git a/app/src/main.c b/app/src/main.c index a6ea2abd..fcf1d115 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -30,8 +30,5 @@ int main(void) { zmk_display_init(); #endif /* CONFIG_ZMK_DISPLAY */ -#ifdef CONFIG_ZMK_MOUSE - zmk_mouse_init(); -#endif /* CONFIG_ZMK_MOUSE */ return 0; } diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig index 972c0c6f..2dbbf90c 100644 --- a/app/src/mouse/Kconfig +++ b/app/src/mouse/Kconfig @@ -1,40 +1,8 @@ # Copyright (c) 2023 The ZMK Contributors # SPDX-License-Identifier: MIT -menuconfig ZMK_MOUSE +config ZMK_MOUSE bool "Mouse Emulation" select INPUT select INPUT_THREAD_PRIORITY_OVERRIDE -if ZMK_MOUSE - -config ZMK_MOUSE_TICK_DURATION - int "Mouse tick duration in ms" - default 16 - - -choice ZMK_MOUSE_WORK_QUEUE - prompt "Work queue selection for mouse events" - default ZMK_MOUSE_WORK_QUEUE_DEDICATED - -config ZMK_MOUSE_WORK_QUEUE_SYSTEM - bool "Use default system work queue for mouse events" - -config ZMK_MOUSE_WORK_QUEUE_DEDICATED - bool "Use dedicated work queue for mouse events" - -endchoice - -if ZMK_MOUSE_WORK_QUEUE_DEDICATED - -config ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE - int "Stack size for dedicated mouse thread/queue" - default 2048 - -config ZMK_MOUSE_DEDICATED_THREAD_PRIORITY - int "Thread priority for dedicated mouse thread/queue" - default 3 - -endif # ZMK_MOUSE_WORK_QUEUE_DEDICATED - -endif diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c deleted file mode 100644 index e1227425..00000000 --- a/app/src/mouse/main.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#include -#include - -#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) -K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE); -static struct k_work_q mouse_work_q; -#endif - -struct k_work_q *zmk_mouse_work_q() { -#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) - return &mouse_work_q; -#else - return &k_sys_work_q; -#endif -} - -int zmk_mouse_init(void) { -#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) - k_work_queue_start(&mouse_work_q, mouse_work_stack_area, - K_THREAD_STACK_SIZEOF(mouse_work_stack_area), - CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY, NULL); -#endif - return 0; -} \ No newline at end of file From 77acca1981f7e33eb424e787ed4c3e65311fcbbf Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 11 Dec 2023 16:28:31 -0800 Subject: [PATCH 07/14] fix(mouse): Fixes for logging. * Corrected logging for two-axis input timestamps. --- app/src/behaviors/behavior_input_two_axis.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/behaviors/behavior_input_two_axis.c b/app/src/behaviors/behavior_input_two_axis.c index 0146df86..028373c2 100644 --- a/app/src/behaviors/behavior_input_two_axis.c +++ b/app/src/behaviors/behavior_input_two_axis.c @@ -145,10 +145,10 @@ static void tick_work_cb(struct k_work *work) { const struct device *dev = data->dev; const struct behavior_input_two_axis_config *cfg = dev->config; - uint32_t timestamp = k_uptime_get(); + uint64_t timestamp = k_uptime_get(); - LOG_INF("tick start times: %lld %lld %lld", data->state.x.start_time, data->state.y.start_time, - timestamp); + LOG_INF("x start: %llu, y start: %llu, current timestamp: %llu", data->state.x.start_time, + data->state.y.start_time, timestamp); struct vector2d move = update_movement_2d(cfg, &data->state, timestamp); From 5513584a4871941f15ebc80bd6c0e4a6ac43c9eb Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 12 Feb 2024 20:12:34 +0000 Subject: [PATCH 08/14] refactor: Proper per-device input listeners. * Buffer data from input devices and only surface to HID once synd'd. --- app/CMakeLists.txt | 3 +- app/dts/behaviors.dtsi | 2 - app/dts/behaviors/mouse_move.dtsi | 5 + app/dts/behaviors/mouse_scroll.dtsi | 5 + app/dts/bindings/zmk,input-configs.yaml | 24 --- app/dts/bindings/zmk,input-listener.yaml | 21 +++ app/include/zmk/mouse/input_config.h | 21 --- app/src/mouse/hid_input_listener.c | 110 ------------- app/src/mouse/input_config.c | 42 ----- app/src/mouse/input_listener.c | 188 +++++++++++++++++++++++ 10 files changed, 220 insertions(+), 201 deletions(-) delete mode 100644 app/dts/bindings/zmk,input-configs.yaml create mode 100644 app/dts/bindings/zmk,input-listener.yaml delete mode 100644 app/include/zmk/mouse/input_config.h delete mode 100644 app/src/mouse/hid_input_listener.c delete mode 100644 app/src/mouse/input_config.c create mode 100644 app/src/mouse/input_listener.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e8ff7293..9edbe9c3 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -27,7 +27,6 @@ target_sources(app PRIVATE src/behavior.c) target_sources_ifdef(CONFIG_ZMK_KSCAN_SIDEBAND_BEHAVIORS app PRIVATE src/kscan_sideband_behaviors.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/physical_layouts.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) @@ -44,7 +43,7 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/behavior_soft_off.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 27bc78a6..6695af40 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -21,6 +21,4 @@ #include #include #include -#include -#include #include diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index 0bfc87d0..c43455c3 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 69c48fee..27b6aafe 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 83bd4a19..00000000 --- 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 00000000..a883557d --- /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 0a37b346..00000000 --- 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 712bb567..00000000 --- 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 745fb49b..00000000 --- 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 00000000..a00455bc --- /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) From f8fa8aa1b9bf4b229c1a3784fe585c0c53b13cc6 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 19 Feb 2024 01:55:06 -0800 Subject: [PATCH 09/14] chore: Minor input behavior clean-up. --- app/src/behaviors/behavior_input_two_axis.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/app/src/behaviors/behavior_input_two_axis.c b/app/src/behaviors/behavior_input_two_axis.c index 028373c2..eaf84a76 100644 --- a/app/src/behaviors/behavior_input_two_axis.c +++ b/app/src/behaviors/behavior_input_two_axis.c @@ -194,7 +194,7 @@ static void update_work_scheduling(const struct device *dev) { } } -int zmk_input_synth_pointer_adjust_speed(const struct device *dev, int16_t dx, int16_t dy) { +int behavior_input_two_axis_adjust_speed(const struct device *dev, int16_t dx, int16_t dy) { struct behavior_input_two_axis_data *data = dev->data; LOG_DBG("Adjusting: %d %d", dx, dy); @@ -208,15 +208,6 @@ int zmk_input_synth_pointer_adjust_speed(const struct device *dev, int16_t dx, i return 0; } -// static void process_key_state(const struct device *dev, int32_t val, bool pressed) { -// for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { -// if (val & BIT(i)) { -// WRITE_BIT(val, i, 0); -// input_report_key(dev, INPUT_BTN_0 + i, pressed ? 1 : 0, val == 0, K_FOREVER); -// } -// } -// } - static int behavior_input_two_axis_init(const struct device *dev) { struct behavior_input_two_axis_data *data = dev->data; @@ -236,7 +227,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, int16_t x = MOVE_X_DECODE(binding->param1); int16_t y = MOVE_Y_DECODE(binding->param1); - zmk_input_synth_pointer_adjust_speed(behavior_dev, x, y); + behavior_input_two_axis_adjust_speed(behavior_dev, x, y); return 0; } @@ -249,7 +240,7 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, int16_t x = MOVE_X_DECODE(binding->param1); int16_t y = MOVE_Y_DECODE(binding->param1); - zmk_input_synth_pointer_adjust_speed(behavior_dev, -x, -y); + behavior_input_two_axis_adjust_speed(behavior_dev, -x, -y); return 0; } From dad5926fd0a88980de3969b7d8db1682e0bd8514 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 19 Feb 2024 10:23:16 +0000 Subject: [PATCH 10/14] fix: Testing fixes for listener refactor. --- app/dts/behaviors.dtsi | 8 ++++++-- app/dts/behaviors/mouse_key_press.dtsi | 5 +++++ app/dts/behaviors/mouse_keys.dtsi | 9 +++++++++ app/dts/behaviors/mouse_move.dtsi | 6 ++++++ app/dts/behaviors/mouse_scroll.dtsi | 6 ++++++ app/src/mouse/input_listener.c | 2 +- app/tests/mouse-keys/mkp/native_posix_64.keymap | 1 + .../keycode_events.snapshot | 16 ++++++---------- .../move_diagonal_scaling/native_posix_64.keymap | 1 + .../keycode_events.snapshot | 16 ++++++---------- .../native_posix_64.keymap | 1 + .../keycode_events.snapshot | 16 ++++++---------- .../move_diagonal_xy_swap/native_posix_64.keymap | 1 + .../move_diagonal/keycode_events.snapshot | 16 ++++++---------- .../move_diagonal/native_posix_64.keymap | 1 + .../mouse-move/move_x/keycode_events.snapshot | 16 ++++++++-------- .../mouse-move/move_x/native_posix_64.keymap | 1 + .../mouse-move/move_y/keycode_events.snapshot | 16 ++++++++-------- .../mouse-move/move_y/native_posix_64.keymap | 1 + 19 files changed, 80 insertions(+), 59 deletions(-) create mode 100644 app/dts/behaviors/mouse_keys.dtsi diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 6695af40..6ff4b69c 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include #include @@ -19,6 +25,4 @@ #include #include #include -#include #include -#include diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi index 975c24aa..729166ea 100644 --- a/app/dts/behaviors/mouse_key_press.dtsi +++ b/app/dts/behaviors/mouse_key_press.dtsi @@ -5,4 +5,9 @@ #binding-cells = <1>; }; }; + + mkp_input_listener { + compatible = "zmk,input-listener"; + device = <&mkp>; + }; }; diff --git a/app/dts/behaviors/mouse_keys.dtsi b/app/dts/behaviors/mouse_keys.dtsi new file mode 100644 index 00000000..f9a99fed --- /dev/null +++ b/app/dts/behaviors/mouse_keys.dtsi @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "mouse_key_press.dtsi" +#include "mouse_move.dtsi" +#include "mouse_scroll.dtsi" \ No newline at end of file diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index c43455c3..47dc6cec 100644 --- a/app/dts/behaviors/mouse_move.dtsi +++ b/app/dts/behaviors/mouse_move.dtsi @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include / { diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi index 27b6aafe..e9d141f8 100644 --- a/app/dts/behaviors/mouse_scroll.dtsi +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include / { diff --git a/app/src/mouse/input_listener.c b/app/src/mouse/input_listener.c index a00455bc..0acc4349 100644 --- a/app/src/mouse/input_listener.c +++ b/app/src/mouse/input_listener.c @@ -154,7 +154,7 @@ static void input_handler(const struct input_listener_config *config, if (data->button_clear != 0) { for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { - if ((data->button_set & BIT(i)) != 0) { + if ((data->button_clear & BIT(i)) != 0) { zmk_hid_mouse_button_release(i); } } diff --git a/app/tests/mouse-keys/mkp/native_posix_64.keymap b/app/tests/mouse-keys/mkp/native_posix_64.keymap index 8e3071d4..8b955846 100644 --- a/app/tests/mouse-keys/mkp/native_posix_64.keymap +++ b/app/tests/mouse-keys/mkp/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot index 99fa1488..6b9fa770 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot @@ -1,22 +1,18 @@ -movement_update: Mouse movement updated to -1/0 +movement_set: Mouse movement set to -1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -3/0 -movement_update: Mouse movement updated to -3/-3 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -3/0 -movement_update: Mouse movement updated to -3/-3 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -5/0 -movement_update: Mouse movement updated to -5/-3 +movement_set: Mouse movement set to -3/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -5/0 -movement_update: Mouse movement updated to -5/-5 +movement_set: Mouse movement set to -3/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-5 +movement_set: Mouse movement set to 0/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap index b1ddbc1d..6351799b 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot index 94faacce..6b9fa770 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot @@ -1,22 +1,18 @@ -movement_update: Mouse movement updated to 1/0 +movement_set: Mouse movement set to -1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 2/0 -movement_update: Mouse movement updated to 2/2 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 2/0 -movement_update: Mouse movement updated to 2/2 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 3/0 -movement_update: Mouse movement updated to 3/2 +movement_set: Mouse movement set to -3/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 3/0 -movement_update: Mouse movement updated to 3/3 +movement_set: Mouse movement set to -3/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/3 +movement_set: Mouse movement set to 0/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap index 4767e0ac..3392dd0d 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot index 5ca5300c..6b9fa770 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot @@ -1,22 +1,18 @@ -movement_update: Mouse movement updated to 0/-1 +movement_set: Mouse movement set to -1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-2 -movement_update: Mouse movement updated to -2/-2 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-2 -movement_update: Mouse movement updated to -2/-2 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-3 -movement_update: Mouse movement updated to -2/-3 +movement_set: Mouse movement set to -3/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-3 -movement_update: Mouse movement updated to -3/-3 +movement_set: Mouse movement set to -3/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -3/0 +movement_set: Mouse movement set to 0/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap index 15327023..d4cf5031 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot index 91c4f16b..6b9fa770 100644 --- a/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/move_diagonal/keycode_events.snapshot @@ -1,22 +1,18 @@ -movement_update: Mouse movement updated to -1/0 +movement_set: Mouse movement set to -1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -2/0 -movement_update: Mouse movement updated to -2/-2 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -2/0 -movement_update: Mouse movement updated to -2/-2 +movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -3/0 -movement_update: Mouse movement updated to -3/-2 +movement_set: Mouse movement set to -3/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -3/0 -movement_update: Mouse movement updated to -3/-3 +movement_set: Mouse movement set to -3/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-3 +movement_set: Mouse movement set to 0/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap index 9dfa5b2a..7e4d7af2 100644 --- a/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot index dfbc4a76..678f71c9 100644 --- a/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/move_x/keycode_events.snapshot @@ -1,24 +1,24 @@ -movement_update: Mouse movement updated to -1/0 +movement_set: Mouse movement set to -1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -2/0 +movement_set: Mouse movement set to -2/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -2/0 +movement_set: Mouse movement set to -2/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to -3/0 +movement_set: Mouse movement set to -3/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 1/0 +movement_set: Mouse movement set to 1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 2/0 +movement_set: Mouse movement set to 2/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 2/0 +movement_set: Mouse movement set to 2/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 3/0 +movement_set: Mouse movement set to 3/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap index aacacebb..89d50e2b 100644 --- a/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot index 4fd9a252..d20154d5 100644 --- a/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/move_y/keycode_events.snapshot @@ -1,24 +1,24 @@ -movement_update: Mouse movement updated to 0/-1 +movement_set: Mouse movement set to 0/-1 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-2 +movement_set: Mouse movement set to 0/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-2 +movement_set: Mouse movement set to 0/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/-3 +movement_set: Mouse movement set to 0/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/1 +movement_set: Mouse movement set to 0/1 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/2 +movement_set: Mouse movement set to 0/2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/2 +movement_set: Mouse movement set to 0/2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_update: Mouse movement updated to 0/3 +movement_set: Mouse movement set to 0/3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap index 1d914136..5b02246b 100644 --- a/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.keymap @@ -1,4 +1,5 @@ #include +#include #include #include #include From 0c3536cfc7c5a6d6c328ec17938b66a54a88fcf5 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Wed, 10 Apr 2024 02:13:51 +0000 Subject: [PATCH 11/14] refactor(mouse): Tweak behavior inclusion, listener code * Always import mouse keys behavior and their associated listeners. * Tweak listener code to only add listener nodes when listener and the associated input device are enabled. --- app/dts/behaviors.dtsi | 1 + app/dts/behaviors/mouse_key_press.dtsi | 2 +- app/dts/behaviors/mouse_move.dtsi | 2 +- app/dts/behaviors/mouse_scroll.dtsi | 3 ++- app/src/mouse/input_listener.c | 36 +++++++++++++++++--------- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 6ff4b69c..7009d2ff 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -26,3 +26,4 @@ #include #include #include +#include diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi index 729166ea..66e327e8 100644 --- a/app/dts/behaviors/mouse_key_press.dtsi +++ b/app/dts/behaviors/mouse_key_press.dtsi @@ -6,7 +6,7 @@ }; }; - mkp_input_listener { + mkp_input_listener: mkp_input_listener { compatible = "zmk,input-listener"; device = <&mkp>; }; diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index 47dc6cec..09b93520 100644 --- a/app/dts/behaviors/mouse_move.dtsi +++ b/app/dts/behaviors/mouse_move.dtsi @@ -18,7 +18,7 @@ }; }; - mmv_input_listener { + mmv_input_listener: 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 e9d141f8..b482efde 100644 --- a/app/dts/behaviors/mouse_scroll.dtsi +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -1,3 +1,4 @@ + /* * Copyright (c) 2024 The ZMK Contributors * @@ -18,7 +19,7 @@ }; }; - msc_input_listener { + msc_input_listener: msc_input_listener { compatible = "zmk,input-listener"; device = <&msc>; }; diff --git a/app/src/mouse/input_listener.c b/app/src/mouse/input_listener.c index 0acc4349..6863e00e 100644 --- a/app/src/mouse/input_listener.c +++ b/app/src/mouse/input_listener.c @@ -15,6 +15,13 @@ #include #include +#define ONE_IF_DEV_OK(n) \ + COND_CODE_1(DT_NODE_HAS_STATUS(DT_INST_PHANDLE(n, device), okay), (1 +), (0 +)) + +#define VALID_LISTENER_COUNT (DT_INST_FOREACH_STATUS_OKAY(ONE_IF_DEV_OK) 0) + +#if VALID_LISTENER_COUNT > 0 + enum input_listener_xy_data_mode { INPUT_LISTENER_XY_DATA_MODE_NONE, INPUT_LISTENER_XY_DATA_MODE_REL, @@ -171,18 +178,23 @@ static void input_handler(const struct input_listener_config *config, } } +#endif // VALID_LISTENER_COUNT > 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); + COND_CODE_1( \ + DT_NODE_HAS_STATUS(DT_INST_PHANDLE(n, device), okay), \ + (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) From 37ba9eb527d842f98abfc27ea56e86050ffe8dc7 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Tue, 9 Apr 2024 21:43:07 -0700 Subject: [PATCH 12/14] fix(mouse): Fix up tests and make ZMK_MOUSE explicit. --- app/Kconfig.behaviors | 6 ++---- app/include/zmk/hid.h | 4 ---- app/tests/mouse-keys/mkp/native_posix_64.conf | 6 ++++++ .../mouse-keys/mkp/native_posix_64.keymap | 1 - .../keycode_events.snapshot | 20 +++++++++---------- .../native_posix_64.conf | 6 ++++++ .../native_posix_64.keymap | 16 +++++---------- .../keycode_events.snapshot | 12 +++++------ .../native_posix_64.conf | 6 ++++++ .../native_posix_64.keymap | 16 +++++---------- .../keycode_events.snapshot | 6 +++--- .../native_posix_64.conf | 6 ++++++ .../native_posix_64.keymap | 14 ++++--------- .../move_diagonal/native_posix_64.conf | 6 ++++++ .../mouse-move/move_x/native_posix_64.conf | 6 ++++++ .../mouse-move/move_y/native_posix_64.conf | 6 ++++++ 16 files changed, 77 insertions(+), 60 deletions(-) create mode 100644 app/tests/mouse-keys/mkp/native_posix_64.conf create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.conf create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.conf create mode 100644 app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.conf create mode 100644 app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.conf create mode 100644 app/tests/mouse-keys/mouse-move/move_x/native_posix_64.conf create mode 100644 app/tests/mouse-keys/mouse-move/move_y/native_posix_64.conf diff --git a/app/Kconfig.behaviors b/app/Kconfig.behaviors index 3aa256a9..ebc388c9 100644 --- a/app/Kconfig.behaviors +++ b/app/Kconfig.behaviors @@ -48,8 +48,7 @@ config ZMK_BEHAVIOR_KEY_TOGGLE config ZMK_BEHAVIOR_MOUSE_KEY_PRESS bool default y - depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED - imply ZMK_MOUSE + depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED && ZMK_MOUSE config ZMK_BEHAVIOR_SOFT_OFF bool @@ -59,8 +58,7 @@ config ZMK_BEHAVIOR_SOFT_OFF config ZMK_BEHAVIOR_INPUT_TWO_AXIS bool default y - depends on DT_HAS_ZMK_BEHAVIOR_INPUT_TWO_AXIS_ENABLED - imply ZMK_MOUSE + depends on DT_HAS_ZMK_BEHAVIOR_INPUT_TWO_AXIS_ENABLED && ZMK_MOUSE config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON bool diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index aa59f369..efc6664e 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -61,10 +61,6 @@ #define ZMK_HID_REPORT_ID_CONSUMER 0x02 #define ZMK_HID_REPORT_ID_MOUSE 0x03 -// Needed until Zephyr offers a 2 byte usage macro -#define HID_USAGE16(idx) \ - HID_ITEM(HID_ITEM_TAG_USAGE, HID_ITEM_TYPE_LOCAL, 2), (idx & 0xFF), (idx >> 8 & 0xFF) - static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), HID_USAGE(HID_USAGE_GD_KEYBOARD), diff --git a/app/tests/mouse-keys/mkp/native_posix_64.conf b/app/tests/mouse-keys/mkp/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mkp/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y diff --git a/app/tests/mouse-keys/mkp/native_posix_64.keymap b/app/tests/mouse-keys/mkp/native_posix_64.keymap index 8b955846..8e3071d4 100644 --- a/app/tests/mouse-keys/mkp/native_posix_64.keymap +++ b/app/tests/mouse-keys/mkp/native_posix_64.keymap @@ -1,5 +1,4 @@ #include -#include #include #include #include diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot index 6b9fa770..15d31600 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/keycode_events.snapshot @@ -1,18 +1,18 @@ movement_set: Mouse movement set to -1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -2/-2 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -2/-2 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -3/-2 -scroll_set: Mouse scroll set to 0/0 -movement_set: Mouse movement set to 0/0 movement_set: Mouse movement set to -3/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to 0/-3 +movement_set: Mouse movement set to -3/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_set: Mouse movement set to -5/-3 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_set: Mouse movement set to -5/-5 +scroll_set: Mouse scroll set to 0/0 +movement_set: Mouse movement set to 0/0 +movement_set: Mouse movement set to 0/-5 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.conf b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap index 6351799b..df8cda8c 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_scaling/native_posix_64.keymap @@ -1,9 +1,13 @@ #include -#include #include #include #include +&mmv_input_listener { + scale-multiplier = <5>; + scale-divisor = <3>; +}; + / { keymap { compatible = "zmk,keymap"; @@ -16,16 +20,6 @@ >; }; }; - - input_configs { - compatible = "zmk,input-configs"; - - mmv { - device = <&mmv>; - scale-multiplier = <5>; - scale-divisor = <3>; - }; - }; }; diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot index 6b9fa770..33bb267b 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/keycode_events.snapshot @@ -1,18 +1,18 @@ -movement_set: Mouse movement set to -1/0 +movement_set: Mouse movement set to 1/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -2/-2 +movement_set: Mouse movement set to 2/2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -2/-2 +movement_set: Mouse movement set to 2/2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -3/-2 +movement_set: Mouse movement set to 3/2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -3/-3 +movement_set: Mouse movement set to 3/3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to 0/-3 +movement_set: Mouse movement set to 0/3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.conf b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap index 3392dd0d..9b07e1b9 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_invert/native_posix_64.keymap @@ -1,9 +1,13 @@ #include -#include #include #include #include +&mmv_input_listener { + x-invert; + y-invert; +}; + / { keymap { compatible = "zmk,keymap"; @@ -16,16 +20,6 @@ >; }; }; - - input_configs { - compatible = "zmk,input-configs"; - - mmv { - device = <&mmv>; - x-invert; - y-invert; - }; - }; }; diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot index 6b9fa770..40daa64f 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/keycode_events.snapshot @@ -1,4 +1,4 @@ -movement_set: Mouse movement set to -1/0 +movement_set: Mouse movement set to 0/-1 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 movement_set: Mouse movement set to -2/-2 @@ -7,12 +7,12 @@ movement_set: Mouse movement set to 0/0 movement_set: Mouse movement set to -2/-2 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to -3/-2 +movement_set: Mouse movement set to -2/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 movement_set: Mouse movement set to -3/-3 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 -movement_set: Mouse movement set to 0/-3 +movement_set: Mouse movement set to -3/0 scroll_set: Mouse scroll set to 0/0 movement_set: Mouse movement set to 0/0 diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.conf b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y diff --git a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap index d4cf5031..719bca98 100644 --- a/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap +++ b/app/tests/mouse-keys/mouse-move/input-configs/move_diagonal_xy_swap/native_posix_64.keymap @@ -1,9 +1,12 @@ #include -#include #include #include #include +&mmv_input_listener { + xy-swap; +}; + / { keymap { compatible = "zmk,keymap"; @@ -16,15 +19,6 @@ >; }; }; - - input_configs { - compatible = "zmk,input-configs"; - - mmv { - device = <&mmv>; - xy-swap; - }; - }; }; diff --git a/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.conf b/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_diagonal/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y diff --git a/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.conf b/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_x/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y diff --git a/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.conf b/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.conf new file mode 100644 index 00000000..65ed54bb --- /dev/null +++ b/app/tests/mouse-keys/mouse-move/move_y/native_posix_64.conf @@ -0,0 +1,6 @@ +CONFIG_GPIO=n +CONFIG_ZMK_BLE=n +CONFIG_LOG=y +CONFIG_LOG_BACKEND_SHOW_COLOR=n +CONFIG_ZMK_LOG_LEVEL_DBG=y +CONFIG_ZMK_MOUSE=y From d45cb3c26fc113357dfc035965e51c84e13e218d Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Wed, 10 Apr 2024 04:55:14 +0000 Subject: [PATCH 13/14] feat(mouse): Updated mouse keys docs. --- docs/docs/behaviors/index.mdx | 2 + docs/docs/behaviors/mouse-emulation.md | 71 ++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/docs/docs/behaviors/index.mdx b/docs/docs/behaviors/index.mdx index bdacc209..64bbea79 100644 --- a/docs/docs/behaviors/index.mdx +++ b/docs/docs/behaviors/index.mdx @@ -43,6 +43,8 @@ Below is a summary of pre-defined behavior bindings and user-definable behaviors | Binding | Behavior | Description | | ------- | ----------------------------------------------------------- | ------------------------------- | | `&mkp` | [Mouse Button Press](mouse-emulation.md#mouse-button-press) | Emulates pressing mouse buttons | +| `&mmv` | [Mouse Button Press](mouse-emulation.md#mouse-move) | Emulates mouse movement | +| `&msc` | [Mouse Button Press](mouse-emulation.md#mouse-scroll) | Emulates mouse scrolling | ## Reset Behaviors diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md index 7b80bae6..db149252 100644 --- a/docs/docs/behaviors/mouse-emulation.md +++ b/docs/docs/behaviors/mouse-emulation.md @@ -5,8 +5,7 @@ sidebar_label: Mouse Emulation ## Summary -Mouse emulation behaviors send mouse events. Currently, only mouse button presses are supported, but movement -and scroll action support is planned for the future. +Mouse emulation behaviors send mouse events, including mouse button presses, cursor movement and scrolling. :::warning[Refreshing the HID descriptor] @@ -17,14 +16,12 @@ The mouse functionality will not work over BLE until that is done. ## Configuration Option -This feature can be enabled or disabled explicitly via a config option: +To use any of the behaviors documented here, the ZMK mouse feature must be enabled explicitly via a config option: ``` CONFIG_ZMK_MOUSE=y ``` -If you use the mouse key press behavior in your keymap, the feature will automatically be enabled for you. - ## Mouse Button Defines To make it easier to encode the HID mouse button numeric values, include @@ -69,3 +66,67 @@ This example will send press of the fourth mouse button when the binding is trig ``` &mkp MB4 ``` + +## Mouse Move + +This behavior sends mouse X/Y movement events to the connected host. + +### Behavior Binding + +- Reference: `&mmv` +- Parameter: A `uint32` with 16-bits each used for vertical and horizontal velocity. + +The following defines can be passed for the parameter: + +| Define | Action | +| :----------- | :--------- | +| `MOVE_UP` | Move up | +| `MOVE_DOWN` | Move down | +| `MOVE_LEFT` | Move left | +| `MOVE_RIGHT` | Move right | + +### Examples + +The following will send a scroll down event to the host when pressed/held: + +``` +&mmv MOVE_DOWN +``` + +The following will send a scroll left event to the host when pressed/held: + +``` +&mmv MOVE_LEFT +``` + +## Mouse Scroll + +This behavior sends vertical and horizontal scroll events to the connected host. + +### Behavior Binding + +- Reference: `&msc` +- Parameter: A `uint32` with 16-bits each used for vertical and horizontal velocity. + +The following defines can be passed for the parameter: + +| Define | Action | +| :----------- | :--------- | +| `MOVE_UP` | Move up | +| `MOVE_DOWN` | Move down | +| `MOVE_LEFT` | Move left | +| `MOVE_RIGHT` | Move right | + +### Examples + +The following will send a scroll down event to the host when pressed/held: + +``` +&msc MOVE_DOWN +``` + +The following will send a scroll left event to the host when pressed/held: + +``` +&msc MOVE_LEFT +``` From bc75de59f74e9913c810ab358e4d26cdfebfb157 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Sat, 3 Aug 2024 17:09:40 -0600 Subject: [PATCH 14/14] fix: Various fixes for building. --- app/include/zmk/hid.h | 6 ++- app/src/mouse/input_listener.c | 82 +++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index efc6664e..3c4a3a91 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -61,6 +61,10 @@ #define ZMK_HID_REPORT_ID_CONSUMER 0x02 #define ZMK_HID_REPORT_ID_MOUSE 0x03 +#define HID_USAGE16(a, b) HID_ITEM(HID_ITEM_TAG_USAGE, HID_ITEM_TYPE_LOCAL, 2), a, b + +#define HID_USAGE16_SINGLE(a) HID_USAGE16((a & 0xFF), ((a >> 8) & 0xFF)) + static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), HID_USAGE(HID_USAGE_GD_KEYBOARD), @@ -175,7 +179,7 @@ static const uint8_t zmk_hid_report_desc[] = { HID_REPORT_COUNT(0x03), HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_REL), HID_USAGE_PAGE(HID_USAGE_CONSUMER), - HID_USAGE16(HID_USAGE_CONSUMER_AC_PAN), + HID_USAGE16_SINGLE(HID_USAGE_CONSUMER_AC_PAN), HID_LOGICAL_MIN16(0xFF, -0x7F), HID_LOGICAL_MAX16(0xFF, 0x7F), HID_REPORT_SIZE(0x08), diff --git a/app/src/mouse/input_listener.c b/app/src/mouse/input_listener.c index 6863e00e..6f6e07cd 100644 --- a/app/src/mouse/input_listener.c +++ b/app/src/mouse/input_listener.c @@ -9,10 +9,14 @@ #include #include #include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + #include -#include #include +#include #include #define ONE_IF_DEV_OK(n) \ @@ -35,11 +39,15 @@ struct input_listener_xy_data { }; struct input_listener_data { - struct input_listener_xy_data data; - struct input_listener_xy_data wheel_data; + union { + struct { + struct input_listener_xy_data data; + struct input_listener_xy_data wheel_data; - uint8_t button_set; - uint8_t button_clear; + uint8_t button_set; + uint8_t button_clear; + } mouse; + }; }; struct input_listener_config { @@ -53,27 +61,31 @@ struct input_listener_config { 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; + data->mouse.data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->mouse.data.x += evt->value; break; case INPUT_REL_Y: - data->data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; - data->data.y += evt->value; + data->mouse.data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->mouse.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; + data->mouse.wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->mouse.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; + data->mouse.wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL; + data->mouse.wheel_data.x += evt->value; break; default: break; } } -static void handle_key_code(struct input_listener_data *data, struct input_event *evt) { +static void handle_abs_code(const struct input_listener_config *config, + struct input_listener_data *data, struct input_event *evt) {} + +static void handle_key_code(const struct input_listener_config *config, + struct input_listener_data *data, struct input_event *evt) { int8_t btn; switch (evt->code) { @@ -84,9 +96,9 @@ static void handle_key_code(struct input_listener_data *data, struct input_event case INPUT_BTN_4: btn = evt->code - INPUT_BTN_0; if (evt->value > 0) { - WRITE_BIT(data->button_set, btn, 1); + WRITE_BIT(data->mouse.button_set, btn, 1); } else { - WRITE_BIT(data->button_clear, btn, 1); + WRITE_BIT(data->mouse.button_clear, btn, 1); } break; default: @@ -105,6 +117,14 @@ static void swap_xy(struct input_event *evt) { } } +static inline bool is_x_data(const struct input_event *evt) { + return evt->type == INPUT_EV_REL && evt->code == INPUT_REL_X; +} + +static inline bool is_y_data(const struct input_event *evt) { + return evt->type == INPUT_EV_REL && evt->code == INPUT_REL_Y; +} + static void filter_with_input_config(const struct input_listener_config *cfg, struct input_event *evt) { if (!evt->dev) { @@ -115,8 +135,7 @@ static void filter_with_input_config(const struct input_listener_config *cfg, swap_xy(evt); } - if ((cfg->x_invert && evt->code == INPUT_REL_X) || - (cfg->y_invert && evt->code == INPUT_REL_Y)) { + if ((cfg->x_invert && is_x_data(evt)) || (cfg->y_invert && is_y_data(evt))) { evt->value = -(evt->value); } @@ -137,31 +156,34 @@ static void input_handler(const struct input_listener_config *config, case INPUT_EV_REL: handle_rel_code(data, evt); break; + case INPUT_EV_ABS: + handle_abs_code(config, data, evt); + break; case INPUT_EV_KEY: - handle_key_code(data, evt); + handle_key_code(config, 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->mouse.wheel_data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) { + zmk_hid_mouse_scroll_set(data->mouse.wheel_data.x, data->mouse.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->mouse.data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) { + zmk_hid_mouse_movement_set(data->mouse.data.x, data->mouse.data.y); } - if (data->button_set != 0) { + if (data->mouse.button_set != 0) { for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { - if ((data->button_set & BIT(i)) != 0) { + if ((data->mouse.button_set & BIT(i)) != 0) { zmk_hid_mouse_button_press(i); } } } - if (data->button_clear != 0) { + if (data->mouse.button_clear != 0) { for (int i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) { - if ((data->button_clear & BIT(i)) != 0) { + if ((data->mouse.button_clear & BIT(i)) != 0) { zmk_hid_mouse_button_release(i); } } @@ -171,10 +193,10 @@ static void input_handler(const struct input_listener_config *config, 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); + clear_xy_data(&data->mouse.data); + clear_xy_data(&data->mouse.wheel_data); - data->button_set = data->button_clear = 0; + data->mouse.button_set = data->mouse.button_clear = 0; } }