Skip to content

Commit

Permalink
feat(mouse): Add mouse move and scroll support
Browse files Browse the repository at this point in the history
* Use Zephyr input subsystem for all pointers.
* Input processors for modifying events, e.g. scaling, swapping
  codes, temporary (mouse) layers, etc.
* Mouse move/scroll behaviors.
* Infrastructure in place for physical pointer input devices.

Co-authored-by: Alexander Krikun <[email protected]>
Co-authored-by: Robert U <[email protected]>
Co-authored-by: Shawn Meier <[email protected]>
  • Loading branch information
4 people authored and petejohanson committed Oct 22, 2024
1 parent 369a009 commit c9fede9
Show file tree
Hide file tree
Showing 70 changed files with 2,175 additions and 117 deletions.
5 changes: 3 additions & 2 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ if(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS)
endif()

zephyr_syscall_header(${APPLICATION_SOURCE_DIR}/include/drivers/behavior.h)
zephyr_syscall_header(${APPLICATION_SOURCE_DIR}/include/drivers/input_processor.h)
zephyr_syscall_header(${APPLICATION_SOURCE_DIR}/include/drivers/ext_power.h)

# Add your source file to the "app" target. This must come after
Expand All @@ -36,15 +37,14 @@ 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_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)
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
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)
add_subdirectory_ifdef(CONFIG_ZMK_MOUSE src/mouse/)
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_ifdef(CONFIG_ZMK_BEHAVIOR_HOLD_TAP app PRIVATE src/behaviors/behavior_hold_tap.c)
Expand All @@ -64,6 +64,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
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_BEHAVIOR_STUDIO_UNLOCK app PRIVATE src/behaviors/behavior_studio_unlock.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)
Expand Down
8 changes: 1 addition & 7 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,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"

Expand Down
8 changes: 6 additions & 2 deletions app/Kconfig.behaviors
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,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_STICKY_KEY
bool
Expand All @@ -94,6 +93,11 @@ 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 && ZMK_MOUSE

config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
bool

Expand Down
8 changes: 7 additions & 1 deletion app/dts/behaviors.dtsi
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <behaviors/key_press.dtsi>
#include <behaviors/key_toggle.dtsi>
#include <behaviors/transparent.dtsi>
Expand All @@ -19,6 +25,6 @@
#include <behaviors/key_repeat.dtsi>
#include <behaviors/backlight.dtsi>
#include <behaviors/macros.dtsi>
#include <behaviors/mouse_key_press.dtsi>
#include <behaviors/soft_off.dtsi>
#include <behaviors/studio_unlock.dtsi>
#include <behaviors/mouse_keys.dtsi>
5 changes: 5 additions & 0 deletions app/dts/behaviors/mouse_key_press.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@
#binding-cells = <1>;
};
};

mkp_input_listener: mkp_input_listener {
compatible = "zmk,input-listener";
device = <&mkp>;
};
};
9 changes: 9 additions & 0 deletions app/dts/behaviors/mouse_keys.dtsi
Original file line number Diff line number Diff line change
@@ -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"
26 changes: 26 additions & 0 deletions app/dts/behaviors/mouse_move.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <zephyr/dt-bindings/input/input-event-codes.h>

/ {
behaviors {
/omit-if-no-ref/ mmv: mouse_move {
compatible = "zmk,behavior-input-two-axis";
#binding-cells = <1>;
trigger-period-ms = <3>;
x-input-code = <INPUT_REL_X>;
y-input-code = <INPUT_REL_Y>;
time-to-max-speed-ms = <300>;
acceleration-exponent = <1>;
};
};

mmv_input_listener: mmv_input_listener {
compatible = "zmk,input-listener";
device = <&mmv>;
};
};
27 changes: 27 additions & 0 deletions app/dts/behaviors/mouse_scroll.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

/*
* Copyright (c) 2024 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <zephyr/dt-bindings/input/input-event-codes.h>

/ {
behaviors {
/omit-if-no-ref/ msc: mouse_scroll {
compatible = "zmk,behavior-input-two-axis";
#binding-cells = <1>;
trigger-period-ms = <3>;
x-input-code = <INPUT_REL_HWHEEL>;
y-input-code = <INPUT_REL_WHEEL>;
time-to-max-speed-ms = <300>;
acceleration-exponent = <1>;
};
};

msc_input_listener: msc_input_listener {
compatible = "zmk,input-listener";
device = <&msc>;
};
};
25 changes: 25 additions & 0 deletions app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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
trigger-period-ms:
type: int
default: 5
description: The time (in ms) between generated inputs when an input has non-zero speed.
delay-ms:
type: int
time-to-max-speed-ms:
type: int
required: true
acceleration-exponent:
type: int
default: 1
6 changes: 6 additions & 0 deletions app/dts/bindings/input_processors/ip_common.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2024 The ZMK Contributors
# SPDX-License-Identifier: MIT

properties:
track-remainders:
type: boolean
13 changes: 13 additions & 0 deletions app/dts/bindings/input_processors/ip_one_param.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2024 The ZMK Contributors
# SPDX-License-Identifier: MIT

include: ip_common.yaml

properties:
"#input-processor-cells":
type: int
required: true
const: 1

input-processor-cells:
- param1
14 changes: 14 additions & 0 deletions app/dts/bindings/input_processors/ip_two_param.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2024 The ZMK Contributors
# SPDX-License-Identifier: MIT

include: ip_common.yaml

properties:
"#input-processor-cells":
type: int
required: true
const: 2

input-processor-cells:
- param1
- param2
10 changes: 10 additions & 0 deletions app/dts/bindings/input_processors/ip_zero_param.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) 2024 The ZMK Contributors
# SPDX-License-Identifier: MIT

include: ip_common.yaml

properties:
"#input-processor-cells":
type: int
required: true
const: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) 2024, The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Input Processor for remapping certain input codes to other codes

compatible: "zmk,input-processor-code-mapper"

include: ip_zero_param.yaml

properties:
type:
type: int
required: true
map:
type: array
required: true
16 changes: 16 additions & 0 deletions app/dts/bindings/input_processors/zmk,input-processor-scaler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright (c) 2024, The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Input Processor for scaling values

compatible: "zmk,input-processor-scaler"

include: ip_two_param.yaml

properties:
type:
type: int
required: true
codes:
type: array
required: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2024, The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Input Processor for temporarily enabling a layer after input events

compatible: "zmk,input-processor-temp-layer"

include: ip_two_param.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2024, The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Input Processor for transforming values in various ways

compatible: "zmk,input-processor-transform"

include: ip_one_param.yaml

properties:
type:
type: int
x-codes:
type: array
required: true
y-codes:
type: array
required: true
23 changes: 23 additions & 0 deletions app/dts/bindings/zmk,input-listener.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
description: |
Listener to subscribe to input events and send HID updates after processing
compatible: "zmk,input-listener"

properties:
device:
type: phandle
required: true
input-processors:
type: phandle-array

child-binding:
description: "Listener overrides for certain layers"

properties:
layers:
type: array
required: true
inherit:
type: boolean
input-processors:
type: phandle-array
67 changes: 67 additions & 0 deletions app/include/drivers/input_processor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#pragma once

#include <zephyr/types.h>
#include <stddef.h>
#include <zephyr/sys/util.h>
#include <string.h>
#include <zephyr/device.h>
#include <zephyr/input/input.h>

struct zmk_input_processor_entry {
const struct device *dev;
uint32_t param1;
uint32_t param2;
bool track_remainders;
};

#define ZMK_INPUT_PROCESSOR_ENTRY_AT_IDX(idx, n) \
{ \
.dev = DEVICE_DT_GET(DT_PHANDLE_BY_IDX(n, input_processors, idx)), \
.param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(n, input_processors, idx, param1), (0), \
(DT_PHA_BY_IDX(n, input_processors, idx, param1))), \
.param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(n, input_processors, idx, param2), (0), \
(DT_PHA_BY_IDX(n, input_processors, idx, param2))), \
.track_remainders = \
COND_CODE_1(DT_PROP(DT_PHANDLE_BY_IDX(n, input_processors, idx), track_remainders), \
(true), (false)), \
}

struct zmk_input_processor_state {
float *remainder;
};

// TODO: Need the ability to store remainders? Some data passed in?
typedef int (*zmk_input_processor_handle_event_callback_t)(const struct device *dev,
struct input_event *event,
uint32_t param1, uint32_t param2,
struct zmk_input_processor_state *state);

__subsystem struct zmk_input_processor_driver_api {
zmk_input_processor_handle_event_callback_t handle_event;
};

__syscall int zmk_input_processor_handle_event(const struct device *dev, struct input_event *event,
uint32_t param1, uint32_t param2,
struct zmk_input_processor_state *state);

static inline int z_impl_zmk_input_processor_handle_event(const struct device *dev,
struct input_event *event,
uint32_t param1, uint32_t param2,
struct zmk_input_processor_state *state) {
const struct zmk_input_processor_driver_api *api =
(const struct zmk_input_processor_driver_api *)dev->api;

if (api->handle_event == NULL) {
return -ENOTSUP;
}

return api->handle_event(dev, event, param1, param2, state);
}

#include <syscalls/input_processor.h>
Loading

0 comments on commit c9fede9

Please sign in to comment.