Merge 8873bf937e
into 49f7275beb
This commit is contained in:
commit
8076b62919
79 changed files with 6776 additions and 318 deletions
|
@ -32,7 +32,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_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)
|
||||
|
@ -40,7 +39,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/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)
|
||||
|
@ -59,6 +58,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_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)
|
||||
|
@ -96,9 +96,12 @@ target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c)
|
|||
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_LOW_PRIORITY_WORK_QUEUE app PRIVATE src/workqueue.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_INPUT_MOUSE_PS2 app PRIVATE src/behaviors/behavior_mouse_setting.c)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
|
||||
add_subdirectory(src/display/)
|
||||
add_subdirectory_ifdef(CONFIG_SETTINGS src/settings/)
|
||||
add_subdirectory(src/mouse/)
|
||||
|
||||
zephyr_cc_option(-Wfatal-errors)
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -15,14 +15,18 @@ 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
|
||||
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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
@ -19,5 +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/mouse_keys.dtsi>
|
||||
#include <behaviors/mouse_setting.dtsi>
|
||||
|
|
|
@ -5,4 +5,9 @@
|
|||
#binding-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mkp_input_listener: mkp_input_listener {
|
||||
compatible = "zmk,input-listener";
|
||||
device = <&mkp>;
|
||||
};
|
||||
};
|
||||
|
|
9
app/dts/behaviors/mouse_keys.dtsi
Normal file
9
app/dts/behaviors/mouse_keys.dtsi
Normal file
|
@ -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"
|
25
app/dts/behaviors/mouse_move.dtsi
Normal file
25
app/dts/behaviors/mouse_move.dtsi
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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>;
|
||||
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>;
|
||||
};
|
||||
};
|
26
app/dts/behaviors/mouse_scroll.dtsi
Normal file
26
app/dts/behaviors/mouse_scroll.dtsi
Normal file
|
@ -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/ msc: mouse_scroll {
|
||||
compatible = "zmk,behavior-input-two-axis";
|
||||
#binding-cells = <1>;
|
||||
x-input-code = <INPUT_REL_HWHEEL>;
|
||||
y-input-code = <INPUT_REL_WHEEL>;
|
||||
time-to-max-speed-ms = <300>;
|
||||
acceleration-exponent = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
msc_input_listener: msc_input_listener {
|
||||
compatible = "zmk,input-listener";
|
||||
device = <&msc>;
|
||||
};
|
||||
};
|
14
app/dts/behaviors/mouse_setting.dtsi
Normal file
14
app/dts/behaviors/mouse_setting.dtsi
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
mms: behavior_mouse_setting {
|
||||
compatible = "zmk,behavior-mouse-setting";
|
||||
#binding-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
25
app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml
Normal file
25
app/dts/bindings/behaviors/zmk,behavior-input-two-axis.yaml
Normal file
|
@ -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: 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:
|
||||
type: int
|
||||
required: true
|
||||
acceleration-exponent:
|
||||
type: int
|
||||
default: 1
|
|
@ -0,0 +1,6 @@
|
|||
description: Mouse Setting
|
||||
|
||||
compatible: "zmk,behavior-mouse-setting"
|
||||
|
||||
include: one_param.yaml
|
||||
|
36
app/dts/bindings/zmk,input-listener.yaml
Normal file
36
app/dts/bindings/zmk,input-listener.yaml
Normal file
|
@ -0,0 +1,36 @@
|
|||
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
|
||||
layer-toggle:
|
||||
type: int
|
||||
default: -1
|
||||
required: false
|
||||
description: The layer that should be toggled when the mouse is moved.
|
||||
layer-toggle-delay-ms:
|
||||
type: int
|
||||
default: 250
|
||||
required: false
|
||||
description: How many miliseconds of mouse activity are required before the layer is toggled on.
|
||||
layer-toggle-timeout-ms:
|
||||
type: int
|
||||
default: 250
|
||||
required: false
|
||||
description: How many miliseconds of mouse inactivity are required before the layer is toggled off again.
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
@ -22,3 +22,29 @@
|
|||
|
||||
#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)
|
||||
|
||||
#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)
|
||||
|
|
21
app/include/dt-bindings/zmk/mouse_settings.h
Normal file
21
app/include/dt-bindings/zmk/mouse_settings.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define MS_LOG 0
|
||||
#define MS_RESET 1
|
||||
|
||||
#define MS_TP_SENSITIVITY_INCR 10
|
||||
#define MS_TP_SENSITIVITY_DECR 11
|
||||
|
||||
#define MS_TP_NEG_INERTIA_INCR 12
|
||||
#define MS_TP_NEG_INERTIA_DECR 13
|
||||
|
||||
#define MS_TP_VALUE6_INCR 14
|
||||
#define MS_TP_VALUE6_DECR 15
|
||||
|
||||
#define MS_TP_PTS_THRESHOLD_INCR 16
|
||||
#define MS_TP_PTS_THRESHOLD_DECR 17
|
|
@ -72,6 +72,6 @@ int zmk_endpoints_send_report(uint16_t usage_page);
|
|||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_endpoints_send_mouse_report();
|
||||
#endif // IS_ENABLE(CONFIG_ZMK_MOUSE)
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
void zmk_endpoints_clear_current(void);
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
#include <zephyr/usb/class/usb_hid.h>
|
||||
|
||||
#include <zmk/keys.h>
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
#include <zmk/mouse.h>
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
#include <dt-bindings/zmk/hid_usage.h>
|
||||
#include <dt-bindings/zmk/hid_usage_pages.h>
|
||||
|
@ -25,8 +22,6 @@
|
|||
#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL
|
||||
#endif
|
||||
|
||||
#define ZMK_HID_MOUSE_NUM_BUTTONS 0x05
|
||||
|
||||
// See https://www.usb.org/sites/default/files/hid1_11.pdf section 6.2.2.4 Main Items
|
||||
|
||||
#define ZMK_HID_MAIN_VAL_DATA (0x00 << 0)
|
||||
|
@ -59,7 +54,6 @@
|
|||
#define ZMK_HID_REPORT_ID_KEYBOARD 0x01
|
||||
#define ZMK_HID_REPORT_ID_LEDS 0x01
|
||||
#define ZMK_HID_REPORT_ID_CONSUMER 0x02
|
||||
#define ZMK_HID_REPORT_ID_MOUSE 0x03
|
||||
|
||||
static const uint8_t zmk_hid_report_desc[] = {
|
||||
HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP),
|
||||
|
@ -145,38 +139,6 @@ static const uint8_t zmk_hid_report_desc[] = {
|
|||
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS),
|
||||
HID_END_COLLECTION,
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
HID_USAGE_PAGE(HID_USAGE_GD),
|
||||
HID_USAGE(HID_USAGE_GD_MOUSE),
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION),
|
||||
HID_REPORT_ID(ZMK_HID_REPORT_ID_MOUSE),
|
||||
HID_USAGE(HID_USAGE_GD_POINTER),
|
||||
HID_COLLECTION(HID_COLLECTION_PHYSICAL),
|
||||
HID_USAGE_PAGE(HID_USAGE_BUTTON),
|
||||
HID_USAGE_MIN8(0x1),
|
||||
HID_USAGE_MAX8(ZMK_HID_MOUSE_NUM_BUTTONS),
|
||||
HID_LOGICAL_MIN8(0x00),
|
||||
HID_LOGICAL_MAX8(0x01),
|
||||
HID_REPORT_SIZE(0x01),
|
||||
HID_REPORT_COUNT(0x5),
|
||||
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
|
||||
// Constant padding for the last 3 bits.
|
||||
HID_REPORT_SIZE(0x03),
|
||||
HID_REPORT_COUNT(0x01),
|
||||
HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
|
||||
// Some OSes ignore pointer devices without X/Y data.
|
||||
HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP),
|
||||
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_REPORT_COUNT(0x03),
|
||||
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)
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
|
@ -239,21 +201,6 @@ struct zmk_hid_consumer_report {
|
|||
struct zmk_hid_consumer_report_body body;
|
||||
} __packed;
|
||||
|
||||
#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;
|
||||
} __packed;
|
||||
|
||||
struct zmk_hid_mouse_report {
|
||||
uint8_t report_id;
|
||||
struct zmk_hid_mouse_report_body body;
|
||||
} __packed;
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
zmk_mod_flags_t zmk_hid_get_explicit_mods(void);
|
||||
int zmk_hid_register_mod(zmk_mod_t modifier);
|
||||
int zmk_hid_unregister_mod(zmk_mod_t modifier);
|
||||
|
@ -280,21 +227,9 @@ int zmk_hid_press(uint32_t usage);
|
|||
int zmk_hid_release(uint32_t usage);
|
||||
bool zmk_hid_is_pressed(uint32_t usage);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
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_clear(void);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(void);
|
||||
struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(void);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
zmk_hid_boot_report_t *zmk_hid_get_boot_report();
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
struct zmk_hid_mouse_report *zmk_hid_get_mouse_report();
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
|
@ -11,7 +11,3 @@
|
|||
|
||||
int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *body);
|
||||
int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *body);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
88
app/include/zmk/mouse/hid.h
Normal file
88
app/include/zmk/mouse/hid.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/usb/usb_device.h>
|
||||
#include <zephyr/usb/class/usb_hid.h>
|
||||
|
||||
#include <zmk/keys.h>
|
||||
#include <zmk/hid.h>
|
||||
|
||||
#include <zmk/mouse/types.h>
|
||||
|
||||
#include <dt-bindings/zmk/hid_usage.h>
|
||||
#include <dt-bindings/zmk/hid_usage_pages.h>
|
||||
|
||||
#define ZMK_MOUSE_HID_NUM_BUTTONS 0x05
|
||||
|
||||
#define ZMK_MOUSE_HID_REPORT_ID_MOUSE 0x01
|
||||
|
||||
// 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_mouse_hid_report_desc[] = {
|
||||
HID_USAGE_PAGE(HID_USAGE_GD),
|
||||
HID_USAGE(HID_USAGE_GD_MOUSE),
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION),
|
||||
HID_REPORT_ID(ZMK_MOUSE_HID_REPORT_ID_MOUSE),
|
||||
HID_USAGE(HID_USAGE_GD_POINTER),
|
||||
HID_COLLECTION(HID_COLLECTION_PHYSICAL),
|
||||
HID_USAGE_PAGE(HID_USAGE_BUTTON),
|
||||
HID_USAGE_MIN8(0x1),
|
||||
HID_USAGE_MAX8(ZMK_MOUSE_HID_NUM_BUTTONS),
|
||||
HID_LOGICAL_MIN8(0x00),
|
||||
HID_LOGICAL_MAX8(0x01),
|
||||
HID_REPORT_SIZE(0x01),
|
||||
HID_REPORT_COUNT(0x5),
|
||||
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
|
||||
// Constant padding for the last 3 bits.
|
||||
HID_REPORT_SIZE(0x03),
|
||||
HID_REPORT_COUNT(0x01),
|
||||
HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
|
||||
// Some OSes ignore pointer devices without X/Y data.
|
||||
HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP),
|
||||
HID_USAGE(HID_USAGE_GD_X),
|
||||
HID_USAGE(HID_USAGE_GD_Y),
|
||||
HID_USAGE(HID_USAGE_GD_WHEEL),
|
||||
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_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,
|
||||
};
|
||||
|
||||
struct zmk_hid_mouse_report_body {
|
||||
zmk_mouse_button_flags_t buttons;
|
||||
int16_t d_x;
|
||||
int16_t d_y;
|
||||
int16_t d_scroll_y;
|
||||
int16_t d_scroll_x;
|
||||
} __packed;
|
||||
|
||||
struct zmk_hid_mouse_report {
|
||||
uint8_t report_id;
|
||||
struct zmk_hid_mouse_report_body body;
|
||||
} __packed;
|
||||
|
||||
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);
|
||||
|
||||
struct zmk_hid_mouse_report *zmk_mouse_hid_get_mouse_report();
|
13
app/include/zmk/mouse/hog.h
Normal file
13
app/include/zmk/mouse/hog.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zmk/mouse/hid.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_mouse_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
* Copyright (c) 2023 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
13
app/include/zmk/mouse/usb_hid.h
Normal file
13
app/include/zmk/mouse/usb_hid.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_mouse_usb_hid_send_mouse_report(void);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
|
@ -5,3 +5,5 @@ add_subdirectory_ifdef(CONFIG_GPIO gpio)
|
|||
add_subdirectory_ifdef(CONFIG_KSCAN kscan)
|
||||
add_subdirectory_ifdef(CONFIG_SENSOR sensor)
|
||||
add_subdirectory_ifdef(CONFIG_DISPLAY display)
|
||||
add_subdirectory_ifdef(CONFIG_PS2 ps2)
|
||||
add_subdirectory_ifdef(CONFIG_INPUT input)
|
||||
|
|
|
@ -5,3 +5,5 @@ rsource "gpio/Kconfig"
|
|||
rsource "kscan/Kconfig"
|
||||
rsource "sensor/Kconfig"
|
||||
rsource "display/Kconfig"
|
||||
rsource "ps2/Kconfig"
|
||||
rsource "input/Kconfig"
|
||||
|
|
6
app/module/drivers/input/CMakeLists.txt
Normal file
6
app/module/drivers/input/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
zephyr_library_amend()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_ZMK_INPUT_MOUSE_PS2 input_mouse_ps2.c)
|
27
app/module/drivers/input/Kconfig
Normal file
27
app/module/drivers/input/Kconfig
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
DT_COMPAT_ZMK_INPUT_PS2_MOUSE := zmk,input-mouse-ps2
|
||||
|
||||
config ZMK_INPUT_MOUSE_PS2
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_INPUT_PS2_MOUSE))
|
||||
depends on (!ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL)
|
||||
select ZMK_MOUSE
|
||||
select PS2
|
||||
|
||||
config ZMK_INPUT_MOUSE_PS2_ENABLE_PS2_RESEND_CALLBACK
|
||||
bool "Get notifications from the underluing PS2 protocol driver when the received data is invalid and when a resend is requested from the peripheral. This helps the mouse driver to re-align its command buffer and prevent unexpected clicks and jerky movements. With the ps2-uart driver this option is not really necessary, but is very useful for the ps2-gpio driver where mis-transmissions are frequent."
|
||||
default n
|
||||
|
||||
if ZMK_INPUT_MOUSE_PS2
|
||||
|
||||
config ZMK_INPUT_MOUSE_PS2_ENABLE_UROB_COMPAT
|
||||
bool "Makes the driver compatible with urob's zmk fork. His fork has commits that change the default zmk function definitions. This option adopts the code to make it compatible with his changes. Only enable it if you are using his fork or it will fail to compile."
|
||||
default n
|
||||
|
||||
config ZMK_INPUT_MOUSE_PS2_ENABLE_ERROR_MITIGATION
|
||||
bool "Tries to mitigate transmission errors. Only useful when using a PS2 driver that is prone to miscommunication like the GPIO bitbanging driver."
|
||||
default n
|
||||
|
||||
endif # ZMK_INPUT_MOUSE_PS2
|
1779
app/module/drivers/input/input_mouse_ps2.c
Normal file
1779
app/module/drivers/input/input_mouse_ps2.c
Normal file
File diff suppressed because it is too large
Load diff
5
app/module/drivers/ps2/CMakeLists.txt
Normal file
5
app/module/drivers/ps2/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_PS2_GPIO ps2_gpio.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_PS2_UART ps2_uart.c)
|
9
app/module/drivers/ps2/Kconfig
Normal file
9
app/module/drivers/ps2/Kconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if PS2
|
||||
|
||||
rsource "Kconfig.gpio"
|
||||
rsource "Kconfig.uart"
|
||||
|
||||
endif # PS2
|
66
app/module/drivers/ps2/Kconfig.gpio
Normal file
66
app/module/drivers/ps2/Kconfig.gpio
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Copyright (c) 2017 Linaro Ltd.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
DT_COMPAT_PS2_GPIO := gpio-ps2
|
||||
|
||||
config PS2_GPIO
|
||||
bool "GPIO bit banging PS/2 support"
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_PS2_GPIO))
|
||||
help
|
||||
Enable software driven (bit banging) PS/2 support using GPIO pins
|
||||
|
||||
if PS2_GPIO
|
||||
|
||||
config PS2_GPIO_ENABLE_PS2_RESEND_CALLBACK
|
||||
bool "Notify the PS2 device driver (mouse driver) when the received data is invalid and a resend is requested from the peripheral. This can help the higher level PS2 device driver handle transmission errors with less side-effects, but it requires a forked zephyr. With the ps2-uart driver this option is not really necessary, but is very useful for the ps2-gpio driver."
|
||||
default n
|
||||
select ZMK_INPUT_MOUSE_PS2_ENABLE_PS2_RESEND_CALLBACK
|
||||
|
||||
# PS/2 events must be processed within 30-50us. Therefore we shift the
|
||||
# BT_CTLR_LLL_PRIO from 0 to 1 and BT_CTLR_ULL_* priorities from 1 to 2.
|
||||
# We then set the gpio priority to 0.
|
||||
#
|
||||
# The following also has to be added to the device tree to set GPIOTE to the
|
||||
# highest priority:
|
||||
# &gpiote {
|
||||
# interrupts = < 0x6 0 >;
|
||||
# };
|
||||
#
|
||||
# On top of that all other interrupts have to be set to priority 3 to prevent
|
||||
# them from delaying the BT interrupts.
|
||||
#
|
||||
# Overrides can be generated using the following script in infused-kim's zmk
|
||||
# fork:
|
||||
# app/scripts/gen_interrupt_priority_overrides.py
|
||||
#
|
||||
# Make sure to do it on a zephyr.dts where the interrupts have not been
|
||||
# adjusted yet (i.e. a config that doesn't have the the following options
|
||||
# enabled).
|
||||
#
|
||||
# If you are building using a toolchain you can find the zephyr.dts in the
|
||||
# build directory, which by default is: `app/build/zephyr/zephyr.dts`
|
||||
#
|
||||
# If you are building using the github actions, copy the output of the build
|
||||
# step `xxxx_right - nice_nano_v2 Devicetree file` into a file and run the
|
||||
# script on it.
|
||||
#
|
||||
# This will increase the probability that the PS/2 interrupts are triggered in
|
||||
# time.
|
||||
|
||||
config BT_CTLR_ADVANCED_FEATURES
|
||||
default y
|
||||
|
||||
config BT_CTLR_LLL_PRIO
|
||||
default 1
|
||||
|
||||
config BT_CTLR_ULL_HIGH_PRIO
|
||||
default 2
|
||||
|
||||
config BT_CTLR_ULL_LOW_PRIO
|
||||
default 2
|
||||
|
||||
config PS2_GPIO_INTERRUPT_LOG_ENABLED
|
||||
bool "Enable extensive interrupt logging."
|
||||
default n
|
||||
|
||||
endif # PS2_GPIO
|
76
app/module/drivers/ps2/Kconfig.uart
Normal file
76
app/module/drivers/ps2/Kconfig.uart
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Copyright (c) 2017 Linaro Ltd.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
DT_COMPAT_PS2_UART := uart-ps2
|
||||
|
||||
config PS2_UART
|
||||
bool "GPIO bit banging PS/2 support through UART"
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_PS2_UART))
|
||||
select SERIAL
|
||||
select UART_ASYNC_API
|
||||
select UART_USE_RUNTIME_CONFIGURE
|
||||
help
|
||||
Enable software driven (bit banging) PS/2 support using UART on GPIO pins
|
||||
|
||||
if PS2_UART
|
||||
|
||||
config PS2_UART_WRITE_MODE_BLOCKING
|
||||
bool "Don't use interrupts for writing data and instead block using timers."
|
||||
default n
|
||||
|
||||
config PS2_UART_ENABLE_PS2_RESEND_CALLBACK
|
||||
bool "Notify the PS2 device driver (mouse driver) when the received data is invalid and a resend is requested from the peripheral. This can help the higher level PS2 device driver handle transmission errors with less side-effects, but it requires a forked zephyr. With the ps2-uart driver this option is not really necessary, but is very useful for the ps2-gpio driver."
|
||||
default n
|
||||
select ZMK_INPUT_MOUSE_PS2_ENABLE_PS2_RESEND_CALLBACK
|
||||
|
||||
# PM_DEVICE is needed, because we use GPIO bitbanging for writing. And to
|
||||
# release the data PIN that is used by the UART device, we use pinctrl to
|
||||
# switch to the sleep state. But the sleep state is only included if PM_DEVICE
|
||||
# is enabled.
|
||||
config PM_DEVICE
|
||||
default y
|
||||
|
||||
# PS/2 events must be processed within 30-50us. Therefore we shift the
|
||||
# BT_CTLR_LLL_PRIO from 0 to 1 and BT_CTLR_ULL_* priorities from 1 to 2.
|
||||
# We then set the gpio priority to 0.
|
||||
#
|
||||
# The following also has to be added to the device tree to set GPIOTE to the
|
||||
# highest priority:
|
||||
# &gpiote {
|
||||
# interrupts = < 0x6 0 >;
|
||||
# };
|
||||
#
|
||||
# On top of that all other interrupts have to be set to priority 3 to prevent
|
||||
# them from delaying the BT interrupts.
|
||||
#
|
||||
# Overrides can be generated using the following script in infused-kim's zmk
|
||||
# fork:
|
||||
# app/scripts/gen_interrupt_priority_overrides.py
|
||||
#
|
||||
# Make sure to do it on a zephyr.dts where the interrupts have not been
|
||||
# adjusted yet (i.e. a config that doesn't have the the following options
|
||||
# enabled).
|
||||
#
|
||||
# If you are building using a toolchain you can find the zephyr.dts in the
|
||||
# build directory, which by default is: `app/build/zephyr/zephyr.dts`
|
||||
#
|
||||
# If you are building using the github actions, copy the output of the build
|
||||
# step `xxxx_right - nice_nano_v2 Devicetree file` into a file and run the
|
||||
# script on it.
|
||||
#
|
||||
# This will increase the probability that the PS/2 interrupts are triggered in
|
||||
# time.
|
||||
|
||||
config BT_CTLR_ADVANCED_FEATURES
|
||||
default y
|
||||
|
||||
config BT_CTLR_LLL_PRIO
|
||||
default 1
|
||||
|
||||
config BT_CTLR_ULL_HIGH_PRIO
|
||||
default 2
|
||||
|
||||
config BT_CTLR_ULL_LOW_PRIO
|
||||
default 2
|
||||
|
||||
endif # PS2_UART
|
1362
app/module/drivers/ps2/ps2_gpio.c
Normal file
1362
app/module/drivers/ps2/ps2_gpio.c
Normal file
File diff suppressed because it is too large
Load diff
1301
app/module/drivers/ps2/ps2_uart.c
Normal file
1301
app/module/drivers/ps2/ps2_uart.c
Normal file
File diff suppressed because it is too large
Load diff
72
app/module/dts/bindings/input/zmk,input-mouse-ps2.yaml
Normal file
72
app/module/dts/bindings/input/zmk,input-mouse-ps2.yaml
Normal file
|
@ -0,0 +1,72 @@
|
|||
description: PS2 mouse configuration
|
||||
|
||||
compatible: "zmk,input-mouse-ps2"
|
||||
|
||||
properties:
|
||||
ps2-device:
|
||||
type: phandle
|
||||
required: true
|
||||
description: |
|
||||
The ps2 device the mouse should use.
|
||||
|
||||
rst-gpios:
|
||||
type: phandle-array
|
||||
required: false
|
||||
description: GPIO to which the RST pin of the device is connected and on which the Power-On-Reset will be performed.
|
||||
|
||||
sampling-rate:
|
||||
type: int
|
||||
description: Adjusts the sensitivity setting on trackpoint devices. The allowed values are 10, 20, 40, 60, 80, 100, 200 and the default is 100.
|
||||
enum:
|
||||
- 10
|
||||
- 20
|
||||
- 40
|
||||
- 60
|
||||
- 80
|
||||
- 100
|
||||
- 200
|
||||
|
||||
scroll-mode:
|
||||
type: boolean
|
||||
description: Enables scroll wheel on mouse devices supporting the Intellimouse extension.
|
||||
|
||||
disable-clicking:
|
||||
type: boolean
|
||||
description: Disables clicking. Useful when using a PS2 driver that is prone to erros in transmissions to reduce accidental clicks.
|
||||
|
||||
tp-press-to-select:
|
||||
type: boolean
|
||||
description: Enables mouse clicking by pressing hard on the trackpoint. Not all trackpoints support this feature.
|
||||
|
||||
tp-press-to-select-threshold:
|
||||
type: int
|
||||
description: Adjusts how sensitive the press-to-select feature is. The range is 0 - 255 and the default is 8. You can also adjust this setting at runtime without recompiling using the &mms behavior. If this setting is enabled, then the runtime behavior won't be saved into the runtime settings.
|
||||
|
||||
tp-sensitivity:
|
||||
type: int
|
||||
description: Adjusts the sensitivity setting on trackpoint devices. The range is 0 - 255 and the default is 128. You can also adjust this setting at runtime without recompiling using the &mms behavior. If this setting is enabled, then the runtime behavior won't be saved into the runtime settings.
|
||||
|
||||
tp-neg-inertia:
|
||||
type: int
|
||||
description: Adjusts the negative inertia setting on trackpoint devices. The range is 0 - 255 and the default is 6. You can also adjust this setting at runtime without recompiling using the &mms behavior. If this setting is enabled, then the runtime behavior won't be saved into the runtime settings.
|
||||
|
||||
tp-val6-upper-speed:
|
||||
type: int
|
||||
description: Adjusts the negative value0 upper plateau speed setting on trackpoint devices. The range is 0 - 255 and the default is 97. You can also adjust this setting at runtime without recompiling using the &mms behavior. If this setting is enabled, then the runtime behavior won't be saved into the runtime settings.
|
||||
|
||||
tp-x-invert:
|
||||
type: boolean
|
||||
description: Enables x axis inversion on the trackpoint. Only works with some trackpoint devices, but is properly considered by the trackpoint's acceleration features (which may or may not have an impact). Alternatively consider achieving the same effect using the `zmk,input-configs` feature.
|
||||
|
||||
tp-y-invert:
|
||||
type: boolean
|
||||
description: Enables y axis inversion on the trackpoint. Only works with some trackpoint devices, but is properly considered by the trackpoint's acceleration features (which may or may not have an impact). Alternatively consider achieving the same effect using the `zmk,input-configs` feature.
|
||||
|
||||
tp-xy-swap:
|
||||
type: boolean
|
||||
description: Swaps the x and y axis on the trackpoint. Only works with some trackpoint devices, but may properly considered by the trackpoint's acceleration features (which may or may not have an impact). Alternatively consider achieving the same effect using the `zmk,input-configs` feature.
|
||||
|
||||
layer-toggle:
|
||||
type: int
|
||||
required: false
|
||||
description: The layer that should be toggled when the mouse is moved.
|
19
app/module/dts/bindings/ps2/gpio-ps2.yaml
Normal file
19
app/module/dts/bindings/ps2/gpio-ps2.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2019, Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: GPIO PS2
|
||||
|
||||
compatible: "gpio-ps2"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
scl-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO to which the SCL pin of the I2C bus is connected.
|
||||
sda-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO to which the SDA pin of the I2C bus is connected.
|
||||
|
18
app/module/dts/bindings/ps2/uart-ps2.yaml
Normal file
18
app/module/dts/bindings/ps2/uart-ps2.yaml
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Copyright (c) 2019, Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: GPIO PS2
|
||||
|
||||
compatible: "uart-ps2"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
scl-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO to which the SCL pin is connected.
|
||||
sda-gpios:
|
||||
type: phandle-array
|
||||
required: true
|
||||
description: GPIO to which the SDA pin is connected.
|
15
app/module/include/zmk/input_mouse_ps2.h
Normal file
15
app/module/include/zmk/input_mouse_ps2.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
int zmk_mouse_ps2_settings_log();
|
||||
int zmk_mouse_ps2_settings_reset();
|
||||
|
||||
int zmk_mouse_ps2_tp_sensitivity_change(int amount);
|
||||
int zmk_mouse_ps2_tp_neg_inertia_change(int amount);
|
||||
int zmk_mouse_ps2_tp_value6_upper_plateau_speed_change(int amount);
|
||||
int zmk_mouse_ps2_tp_pts_threshold_change(int amount);
|
68
app/scripts/gen_interrupt_priority_overrides.py
Executable file
68
app/scripts/gen_interrupt_priority_overrides.py
Executable file
|
@ -0,0 +1,68 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
Script for generating interrupt adjustments for zephyr dts files.
|
||||
|
||||
Requirements:
|
||||
- pip install devicetree
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from devicetree import dtlib
|
||||
|
||||
|
||||
def get_interrupt_nodes(dt):
|
||||
interrupt_nodes = []
|
||||
for node in dt.node_iter():
|
||||
if 'interrupts' in node.props.keys():
|
||||
interrupt_nodes.append(node)
|
||||
|
||||
return interrupt_nodes
|
||||
|
||||
def get_node_label(node):
|
||||
label = node.labels[0]
|
||||
return label
|
||||
|
||||
def gen_interrupt_adjustment_str(node, priority_incr):
|
||||
label = get_node_label(node)
|
||||
interrupt_val1, interrupt_priority = node.props['interrupts'].to_nums()
|
||||
|
||||
if label == 'gpiote':
|
||||
new_priority = 0
|
||||
else:
|
||||
new_priority = interrupt_priority + priority_incr
|
||||
|
||||
adj_str = f'''
|
||||
&{label} {{
|
||||
interrupts = < {interrupt_val1} {new_priority} >;
|
||||
}};
|
||||
'''
|
||||
return adj_str
|
||||
|
||||
|
||||
def gen_interrupt_adjustment(dts_path, priority_incr):
|
||||
dt = dtlib.DT(dts_path)
|
||||
interrupt_nodes = get_interrupt_nodes(dt)
|
||||
|
||||
adjustments = ''
|
||||
for node in interrupt_nodes:
|
||||
adj_str = gen_interrupt_adjustment_str(node, priority_incr)
|
||||
if get_node_label(node) == 'gpiote':
|
||||
adjustments = adj_str + adjustments
|
||||
else:
|
||||
adjustments += adj_str
|
||||
|
||||
return adjustments
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Generate interrupt adjustments for zephyr.dts files.')
|
||||
parser.add_argument('dts_path', metavar='DTS_PATH', type=str, help='Path to the zephyr.dts file')
|
||||
parser.add_argument('-p', '--priority-incr', type=int, default=2, help='By how much to increase the priority (default: 2)')
|
||||
args = parser.parse_args()
|
||||
|
||||
adj = gen_interrupt_adjustment(args.dts_path, args.priority_incr)
|
||||
print(adj)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
265
app/src/behaviors/behavior_input_two_axis.c
Normal file
265
app/src/behaviors/behavior_input_two_axis.c
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_input_two_axis
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/input/input.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h> // CLAMP
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
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;
|
||||
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
|
||||
uint8_t 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 <math.h>
|
||||
#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->trigger_period_ms / 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;
|
||||
|
||||
uint64_t timestamp = k_uptime_get();
|
||||
|
||||
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);
|
||||
|
||||
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(cfg->trigger_period_ms));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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(cfg->trigger_period_ms));
|
||||
} else {
|
||||
k_work_cancel_delayable(&data->tick_work);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 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);
|
||||
|
||||
behavior_input_two_axis_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);
|
||||
|
||||
behavior_input_two_axis_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), \
|
||||
.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), \
|
||||
}; \
|
||||
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)
|
|
@ -11,8 +11,9 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/mouse_button_state_changed.h>
|
||||
#include <zmk/mouse/hid.h>
|
||||
#include <zephyr/input/input.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
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_MOUSE_HID_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 = {
|
||||
|
|
62
app/src/behaviors/behavior_mouse_setting.c
Normal file
62
app/src/behaviors/behavior_mouse_setting.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#define DT_DRV_COMPAT zmk_behavior_mouse_setting
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <dt-bindings/zmk/mouse_settings.h>
|
||||
#include <zmk/input_mouse_ps2.h>
|
||||
|
||||
#define INCREMENT_TP_SENSITIVITY 10
|
||||
#define INCREMENT_TP_NEG_INERTIA 1
|
||||
#define INCREMENT_TP_VALUE6 5
|
||||
#define INCREMENT_TP_PTS_THRESHOLD 1
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
switch (binding->param1) {
|
||||
|
||||
case MS_LOG:
|
||||
return zmk_mouse_ps2_settings_log();
|
||||
case MS_RESET:
|
||||
return zmk_mouse_ps2_settings_reset();
|
||||
case MS_TP_SENSITIVITY_INCR:
|
||||
return zmk_mouse_ps2_tp_sensitivity_change(INCREMENT_TP_SENSITIVITY);
|
||||
case MS_TP_SENSITIVITY_DECR:
|
||||
return zmk_mouse_ps2_tp_sensitivity_change(-INCREMENT_TP_SENSITIVITY);
|
||||
|
||||
case MS_TP_NEG_INERTIA_INCR:
|
||||
return zmk_mouse_ps2_tp_neg_inertia_change(INCREMENT_TP_NEG_INERTIA);
|
||||
case MS_TP_NEG_INERTIA_DECR:
|
||||
return zmk_mouse_ps2_tp_neg_inertia_change(-INCREMENT_TP_NEG_INERTIA);
|
||||
|
||||
case MS_TP_VALUE6_INCR:
|
||||
return zmk_mouse_ps2_tp_value6_upper_plateau_speed_change(INCREMENT_TP_VALUE6);
|
||||
case MS_TP_VALUE6_DECR:
|
||||
return zmk_mouse_ps2_tp_value6_upper_plateau_speed_change(-INCREMENT_TP_VALUE6);
|
||||
|
||||
case MS_TP_PTS_THRESHOLD_INCR:
|
||||
return zmk_mouse_ps2_tp_pts_threshold_change(INCREMENT_TP_PTS_THRESHOLD);
|
||||
case MS_TP_PTS_THRESHOLD_DECR:
|
||||
return zmk_mouse_ps2_tp_pts_threshold_change(-INCREMENT_TP_PTS_THRESHOLD);
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return ZMK_BEHAVIOR_OPAQUE;
|
||||
}
|
||||
|
||||
// Initialization Function
|
||||
static int zmk_behavior_mouse_setting_init(const struct device *dev) { return 0; };
|
||||
|
||||
static const struct behavior_driver_api zmk_behavior_mouse_setting_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, zmk_behavior_mouse_setting_init, NULL, NULL, NULL, POST_KERNEL,
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&zmk_behavior_mouse_setting_driver_api);
|
|
@ -15,6 +15,9 @@
|
|||
#include <dt-bindings/zmk/hid_usage_pages.h>
|
||||
#include <zmk/usb_hid.h>
|
||||
#include <zmk/hog.h>
|
||||
#include <zmk/mouse/hid.h>
|
||||
#include <zmk/mouse/hog.h>
|
||||
#include <zmk/mouse/usb_hid.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/ble_active_profile_changed.h>
|
||||
#include <zmk/events/usb_conn_state_changed.h>
|
||||
|
@ -208,7 +211,7 @@ int zmk_endpoints_send_mouse_report() {
|
|||
switch (current_instance.transport) {
|
||||
case ZMK_TRANSPORT_USB: {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB)
|
||||
int err = zmk_usb_hid_send_mouse_report();
|
||||
int err = zmk_mouse_usb_hid_send_mouse_report();
|
||||
if (err) {
|
||||
LOG_ERR("FAILED TO SEND OVER USB: %d", err);
|
||||
}
|
||||
|
@ -221,8 +224,8 @@ int zmk_endpoints_send_mouse_report() {
|
|||
|
||||
case ZMK_TRANSPORT_BLE: {
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
||||
struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report();
|
||||
int err = zmk_hog_send_mouse_report(&mouse_report->body);
|
||||
struct zmk_hid_mouse_report *mouse_report = zmk_mouse_hid_get_mouse_report();
|
||||
int err = zmk_mouse_hog_send_mouse_report(&mouse_report->body);
|
||||
if (err) {
|
||||
LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
|
||||
}
|
||||
|
|
|
@ -25,13 +25,6 @@ static uint8_t keys_held = 0;
|
|||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static struct zmk_hid_mouse_report mouse_report = {.report_id = ZMK_HID_REPORT_ID_MOUSE,
|
||||
.body = {.buttons = 0}};
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
// Keep track of how often a modifier was pressed.
|
||||
// Only release the modifier if the count is 0.
|
||||
static int explicit_modifier_counts[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
@ -369,71 +362,6 @@ bool zmk_hid_is_pressed(uint32_t usage) {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
// Keep track of how often a button was pressed.
|
||||
// Only release the button if the count is 0.
|
||||
static int explicit_button_counts[5] = {0, 0, 0, 0, 0};
|
||||
static zmk_mod_flags_t explicit_buttons = 0;
|
||||
|
||||
#define SET_MOUSE_BUTTONS(btns) \
|
||||
{ \
|
||||
mouse_report.body.buttons = btns; \
|
||||
LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_button_press(zmk_mouse_button_t button) {
|
||||
if (button >= ZMK_HID_MOUSE_NUM_BUTTONS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
explicit_button_counts[button]++;
|
||||
LOG_DBG("Button %d count %d", button, explicit_button_counts[button]);
|
||||
WRITE_BIT(explicit_buttons, button, true);
|
||||
SET_MOUSE_BUTTONS(explicit_buttons);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_button_release(zmk_mouse_button_t button) {
|
||||
if (button >= ZMK_HID_MOUSE_NUM_BUTTONS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (explicit_button_counts[button] <= 0) {
|
||||
LOG_ERR("Tried to release button %d too often", button);
|
||||
return -EINVAL;
|
||||
}
|
||||
explicit_button_counts[button]--;
|
||||
LOG_DBG("Button %d count: %d", button, explicit_button_counts[button]);
|
||||
if (explicit_button_counts[button] == 0) {
|
||||
LOG_DBG("Button %d released", button);
|
||||
WRITE_BIT(explicit_buttons, button, false);
|
||||
}
|
||||
SET_MOUSE_BUTTONS(explicit_buttons);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) {
|
||||
for (zmk_mouse_button_t i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
|
||||
if (buttons & BIT(i)) {
|
||||
zmk_hid_mouse_button_press(i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) {
|
||||
for (zmk_mouse_button_t i = 0; i < ZMK_HID_MOUSE_NUM_BUTTONS; i++) {
|
||||
if (buttons & BIT(i)) {
|
||||
zmk_hid_mouse_button_release(i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void zmk_hid_mouse_clear(void) { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); }
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(void) {
|
||||
return &keyboard_report;
|
||||
}
|
||||
|
@ -441,11 +369,3 @@ struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(void) {
|
|||
struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(void) {
|
||||
return &consumer_report;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(void) {
|
||||
return &mouse_report;
|
||||
}
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
|
@ -69,15 +69,6 @@ static struct hids_report consumer_input = {
|
|||
.type = HIDS_INPUT,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static struct hids_report mouse_input = {
|
||||
.id = ZMK_HID_REPORT_ID_MOUSE,
|
||||
.type = HIDS_INPUT,
|
||||
};
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static bool host_requests_notification = false;
|
||||
static uint8_t ctrl_point;
|
||||
// static uint8_t proto_mode;
|
||||
|
@ -143,15 +134,6 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn,
|
|||
sizeof(struct zmk_hid_consumer_report_body));
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
static ssize_t read_hids_mouse_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
void *buf, uint16_t len, uint16_t offset) {
|
||||
struct zmk_hid_mouse_report_body *report_body = &zmk_hid_get_mouse_report()->body;
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body,
|
||||
sizeof(struct zmk_hid_mouse_report_body));
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
// static ssize_t write_proto_mode(struct bt_conn *conn,
|
||||
// const struct bt_gatt_attr *attr,
|
||||
// const void *buf, uint16_t len, uint16_t offset,
|
||||
|
@ -200,14 +182,6 @@ BT_GATT_SERVICE_DEFINE(
|
|||
BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
|
||||
NULL, &consumer_input),
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
||||
BT_GATT_PERM_READ_ENCRYPT, read_hids_mouse_input_report, NULL, NULL),
|
||||
BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
|
||||
BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
|
||||
NULL, &mouse_input),
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_HID_INDICATORS)
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT,
|
||||
BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
|
||||
|
@ -220,7 +194,7 @@ BT_GATT_SERVICE_DEFINE(
|
|||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP,
|
||||
BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point));
|
||||
|
||||
struct bt_conn *destination_connection(void) {
|
||||
static struct bt_conn *destination_connection(void) {
|
||||
struct bt_conn *conn;
|
||||
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
|
||||
LOG_DBG("Address pointer %p", addr);
|
||||
|
@ -237,7 +211,7 @@ struct bt_conn *destination_connection(void) {
|
|||
|
||||
K_THREAD_STACK_DEFINE(hog_q_stack, CONFIG_ZMK_BLE_THREAD_STACK_SIZE);
|
||||
|
||||
struct k_work_q hog_work_q;
|
||||
static struct k_work_q hog_work_q;
|
||||
|
||||
K_MSGQ_DEFINE(zmk_hog_keyboard_msgq, sizeof(struct zmk_hid_keyboard_report_body),
|
||||
CONFIG_ZMK_BLE_KEYBOARD_REPORT_QUEUE_SIZE, 4);
|
||||
|
@ -343,61 +317,6 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body),
|
||||
CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4);
|
||||
|
||||
void send_mouse_report_callback(struct k_work *work) {
|
||||
struct zmk_hid_mouse_report_body report;
|
||||
while (k_msgq_get(&zmk_hog_mouse_msgq, &report, K_NO_WAIT) == 0) {
|
||||
struct bt_conn *conn = destination_connection();
|
||||
if (conn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct bt_gatt_notify_params notify_params = {
|
||||
.attr = &hog_svc.attrs[13],
|
||||
.data = &report,
|
||||
.len = sizeof(report),
|
||||
};
|
||||
|
||||
int err = bt_gatt_notify_cb(conn, ¬ify_params);
|
||||
if (err == -EPERM) {
|
||||
bt_conn_set_security(conn, BT_SECURITY_L2);
|
||||
} else if (err) {
|
||||
LOG_DBG("Error notifying %d", err);
|
||||
}
|
||||
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
};
|
||||
|
||||
K_WORK_DEFINE(hog_mouse_work, send_mouse_report_callback);
|
||||
|
||||
int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) {
|
||||
int err = k_msgq_put(&zmk_hog_mouse_msgq, report, K_MSEC(100));
|
||||
if (err) {
|
||||
switch (err) {
|
||||
case -EAGAIN: {
|
||||
LOG_WRN("Consumer message queue full, popping first message and queueing again");
|
||||
struct zmk_hid_mouse_report_body discarded_report;
|
||||
k_msgq_get(&zmk_hog_mouse_msgq, &discarded_report, K_NO_WAIT);
|
||||
return zmk_hog_send_mouse_report(report);
|
||||
}
|
||||
default:
|
||||
LOG_WRN("Failed to queue mouse report to send (%d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
k_work_submit_to_queue(&hog_work_q, &hog_mouse_work);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static int zmk_hog_init(void) {
|
||||
static const struct k_work_queue_config queue_config = {.name = "HID Over GATT Send Work"};
|
||||
k_work_queue_start(&hog_work_q, hog_q_stack, K_THREAD_STACK_SIZEOF(hog_q_stack),
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/events/mouse_button_state_changed.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/mouse.h>
|
||||
|
||||
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);
|
6
app/src/mouse/CMakeLists.txt
Normal file
6
app/src/mouse/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
if(CONFIG_ZMK_MOUSE)
|
||||
target_sources(app PRIVATE hid.c)
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE usb_hid.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE hog.c)
|
||||
endif()
|
19
app/src/mouse/Kconfig
Normal file
19
app/src/mouse/Kconfig
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Copyright (c) 2023 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
menuconfig ZMK_MOUSE
|
||||
bool "Mouse Emulation"
|
||||
select INPUT
|
||||
select INPUT_THREAD_PRIORITY_OVERRIDE
|
||||
select USB_COMPOSITE_DEVICE if ZMK_USB
|
||||
|
||||
if ZMK_MOUSE
|
||||
|
||||
if ZMK_USB
|
||||
|
||||
config USB_HID_DEVICE_COUNT
|
||||
default 2
|
||||
|
||||
endif
|
||||
|
||||
endif # ZMK_MOUSE
|
109
app/src/mouse/hid.c
Normal file
109
app/src/mouse/hid.c
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/mouse/hid.h>
|
||||
|
||||
static struct zmk_hid_mouse_report mouse_report = {
|
||||
.report_id = ZMK_MOUSE_HID_REPORT_ID_MOUSE,
|
||||
.body = {.buttons = 0, .d_x = 0, .d_y = 0, .d_scroll_y = 0}};
|
||||
|
||||
// Keep track of how often a button was pressed.
|
||||
// Only release the button if the count is 0.
|
||||
static int explicit_button_counts[5] = {0, 0, 0, 0, 0};
|
||||
static zmk_mod_flags_t explicit_buttons = 0;
|
||||
|
||||
#define SET_MOUSE_BUTTONS(btns) \
|
||||
{ \
|
||||
mouse_report.body.buttons = btns; \
|
||||
LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_button_press(zmk_mouse_button_t button) {
|
||||
if (button >= ZMK_MOUSE_HID_NUM_BUTTONS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
explicit_button_counts[button]++;
|
||||
LOG_DBG("Button %d count %d", button, explicit_button_counts[button]);
|
||||
WRITE_BIT(explicit_buttons, button, true);
|
||||
SET_MOUSE_BUTTONS(explicit_buttons);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_button_release(zmk_mouse_button_t button) {
|
||||
if (button >= ZMK_MOUSE_HID_NUM_BUTTONS) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (explicit_button_counts[button] <= 0) {
|
||||
LOG_ERR("Tried to release button %d too often", button);
|
||||
return -EINVAL;
|
||||
}
|
||||
explicit_button_counts[button]--;
|
||||
LOG_DBG("Button %d count: %d", button, explicit_button_counts[button]);
|
||||
if (explicit_button_counts[button] == 0) {
|
||||
LOG_DBG("Button %d released", button);
|
||||
WRITE_BIT(explicit_buttons, button, false);
|
||||
}
|
||||
SET_MOUSE_BUTTONS(explicit_buttons);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) {
|
||||
for (zmk_mouse_button_t i = 0; i < ZMK_MOUSE_HID_NUM_BUTTONS; i++) {
|
||||
if (buttons & BIT(i)) {
|
||||
zmk_hid_mouse_button_press(i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) {
|
||||
for (zmk_mouse_button_t i = 0; i < ZMK_MOUSE_HID_NUM_BUTTONS; i++) {
|
||||
if (buttons & BIT(i)) {
|
||||
zmk_hid_mouse_button_release(i);
|
||||
}
|
||||
}
|
||||
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 %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 %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 %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: %d/%d", mouse_report.body.d_scroll_x,
|
||||
mouse_report.body.d_scroll_y);
|
||||
}
|
||||
|
||||
void zmk_hid_mouse_clear(void) {
|
||||
LOG_DBG("Mouse report cleared");
|
||||
memset(&mouse_report.body, 0, sizeof(mouse_report.body));
|
||||
}
|
||||
|
||||
struct zmk_hid_mouse_report *zmk_mouse_hid_get_mouse_report(void) {
|
||||
return &mouse_report;
|
||||
}
|
200
app/src/mouse/hog.c
Normal file
200
app/src/mouse/hog.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/init.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
#include <zmk/ble.h>
|
||||
#include <zmk/endpoints_types.h>
|
||||
#include <zmk/mouse/hog.h>
|
||||
#include <zmk/mouse/hid.h>
|
||||
|
||||
enum {
|
||||
HIDS_REMOTE_WAKE = BIT(0),
|
||||
HIDS_NORMALLY_CONNECTABLE = BIT(1),
|
||||
};
|
||||
|
||||
struct hids_info {
|
||||
uint16_t version; /* version number of base USB HID Specification */
|
||||
uint8_t code; /* country HID Device hardware is localized for. */
|
||||
uint8_t flags;
|
||||
} __packed;
|
||||
|
||||
struct hids_report {
|
||||
uint8_t id; /* report id */
|
||||
uint8_t type; /* report type */
|
||||
} __packed;
|
||||
|
||||
static struct hids_info info = {
|
||||
.version = 0x1101,
|
||||
.code = 0x00,
|
||||
.flags = HIDS_NORMALLY_CONNECTABLE | HIDS_REMOTE_WAKE,
|
||||
};
|
||||
|
||||
enum {
|
||||
HIDS_INPUT = 0x01,
|
||||
HIDS_OUTPUT = 0x02,
|
||||
HIDS_FEATURE = 0x03,
|
||||
};
|
||||
|
||||
static struct hids_report mouse_input = {
|
||||
.id = ZMK_MOUSE_HID_REPORT_ID_MOUSE,
|
||||
.type = HIDS_INPUT,
|
||||
};
|
||||
|
||||
static bool host_requests_notification = false;
|
||||
static uint8_t ctrl_point;
|
||||
|
||||
static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
|
||||
uint16_t len, uint16_t offset) {
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
|
||||
sizeof(struct hids_info));
|
||||
}
|
||||
|
||||
static ssize_t read_hids_report_ref(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
void *buf, uint16_t len, uint16_t offset) {
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
|
||||
sizeof(struct hids_report));
|
||||
}
|
||||
|
||||
static ssize_t read_hids_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
void *buf, uint16_t len, uint16_t offset) {
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, zmk_mouse_hid_report_desc,
|
||||
sizeof(zmk_mouse_hid_report_desc));
|
||||
}
|
||||
|
||||
static ssize_t read_hids_mouse_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
void *buf, uint16_t len, uint16_t offset) {
|
||||
struct zmk_hid_mouse_report_body *report_body = &zmk_mouse_hid_get_mouse_report()->body;
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body,
|
||||
sizeof(struct zmk_hid_mouse_report_body));
|
||||
}
|
||||
|
||||
static void input_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) {
|
||||
LOG_DBG("Input CC changed for %d", attr->handle);
|
||||
host_requests_notification = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
|
||||
}
|
||||
|
||||
static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
const void *buf, uint16_t len, uint16_t offset, uint8_t flags) {
|
||||
uint8_t *value = attr->user_data;
|
||||
|
||||
if (offset + len > sizeof(ctrl_point)) {
|
||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
|
||||
}
|
||||
|
||||
memcpy(value + offset, buf, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* HID Service Declaration */
|
||||
BT_GATT_SERVICE_DEFINE(
|
||||
mouse_hog_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS),
|
||||
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, BT_GATT_PERM_READ_ENCRYPT,
|
||||
read_hids_report_map, NULL, NULL),
|
||||
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
||||
BT_GATT_PERM_READ_ENCRYPT, read_hids_mouse_input_report, NULL, NULL),
|
||||
BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT),
|
||||
BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
|
||||
NULL, &mouse_input),
|
||||
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_hids_info,
|
||||
NULL, &info),
|
||||
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP,
|
||||
BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point));
|
||||
|
||||
static struct bt_conn *destination_connection(void) {
|
||||
struct bt_conn *conn;
|
||||
bt_addr_le_t *addr = zmk_ble_active_profile_addr();
|
||||
|
||||
if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
|
||||
LOG_WRN("Not sending, no active address for current profile");
|
||||
return NULL;
|
||||
} else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
|
||||
LOG_WRN("Not sending, not connected to active profile");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
K_THREAD_STACK_DEFINE(mouse_hog_q_stack, CONFIG_ZMK_BLE_THREAD_STACK_SIZE);
|
||||
|
||||
static struct k_work_q mouse_hog_work_q;
|
||||
|
||||
K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body),
|
||||
CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4);
|
||||
|
||||
void send_mouse_report_callback(struct k_work *work) {
|
||||
struct zmk_hid_mouse_report_body report;
|
||||
while (k_msgq_get(&zmk_hog_mouse_msgq, &report, K_NO_WAIT) == 0) {
|
||||
struct bt_conn *conn = destination_connection();
|
||||
if (conn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct bt_gatt_notify_params notify_params = {
|
||||
.attr = &mouse_hog_svc.attrs[3],
|
||||
.data = &report,
|
||||
.len = sizeof(report),
|
||||
};
|
||||
|
||||
int err = bt_gatt_notify_cb(conn, ¬ify_params);
|
||||
if (err == -EPERM) {
|
||||
bt_conn_set_security(conn, BT_SECURITY_L2);
|
||||
} else if (err) {
|
||||
LOG_DBG("Error notifying %d", err);
|
||||
}
|
||||
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
};
|
||||
|
||||
K_WORK_DEFINE(hog_mouse_work, send_mouse_report_callback);
|
||||
|
||||
int zmk_mouse_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) {
|
||||
int err = k_msgq_put(&zmk_hog_mouse_msgq, report, K_MSEC(100));
|
||||
if (err) {
|
||||
switch (err) {
|
||||
case -EAGAIN: {
|
||||
LOG_WRN("Consumer message queue full, popping first message and queueing again");
|
||||
struct zmk_hid_mouse_report_body discarded_report;
|
||||
k_msgq_get(&zmk_hog_mouse_msgq, &discarded_report, K_NO_WAIT);
|
||||
return zmk_mouse_hog_send_mouse_report(report);
|
||||
}
|
||||
default:
|
||||
LOG_WRN("Failed to queue mouse report to send (%d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
k_work_submit_to_queue(&mouse_hog_work_q, &hog_mouse_work);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int zmk_mouse_hog_init(void) {
|
||||
static const struct k_work_queue_config queue_config = {.name =
|
||||
"Mouse HID Over GATT Send Work"};
|
||||
k_work_queue_start(&mouse_hog_work_q, mouse_hog_q_stack,
|
||||
K_THREAD_STACK_SIZEOF(mouse_hog_q_stack), CONFIG_ZMK_BLE_THREAD_PRIORITY,
|
||||
&queue_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(zmk_mouse_hog_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
|
361
app/src/mouse/input_listener.c
Normal file
361
app/src/mouse/input_listener.c
Normal file
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_input_listener
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/input/input.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/mouse/types.h>
|
||||
#include <zmk/mouse/hid.h>
|
||||
|
||||
#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,
|
||||
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 {
|
||||
const struct device *dev;
|
||||
|
||||
union {
|
||||
struct {
|
||||
struct input_listener_xy_data data;
|
||||
struct input_listener_xy_data wheel_data;
|
||||
|
||||
uint8_t button_set;
|
||||
uint8_t button_clear;
|
||||
} mouse;
|
||||
};
|
||||
|
||||
bool layer_toggle_layer_enabled;
|
||||
int64_t layer_toggle_last_mouse_package_time;
|
||||
struct k_work_delayable layer_toggle_activation_delay;
|
||||
struct k_work_delayable layer_toggle_deactivation_delay;
|
||||
};
|
||||
|
||||
struct input_listener_config {
|
||||
bool xy_swap;
|
||||
bool x_invert;
|
||||
bool y_invert;
|
||||
uint16_t scale_multiplier;
|
||||
uint16_t scale_divisor;
|
||||
int layer_toggle;
|
||||
int layer_toggle_delay_ms;
|
||||
int layer_toggle_timeout_ms;
|
||||
};
|
||||
|
||||
void zmk_input_listener_layer_toggle_input_rel_received(const struct input_listener_config *config,
|
||||
struct input_listener_data *data);
|
||||
|
||||
static char *get_input_code_name(struct input_event *evt) {
|
||||
switch (evt->code) {
|
||||
case INPUT_REL_X:
|
||||
return "INPUT_REL_X";
|
||||
case INPUT_REL_Y:
|
||||
return "INPUT_REL_Y";
|
||||
case INPUT_REL_WHEEL:
|
||||
return "INPUT_REL_WHEEL";
|
||||
case INPUT_REL_HWHEEL:
|
||||
return "INPUT_REL_HWHEEL";
|
||||
case INPUT_BTN_0:
|
||||
return "INPUT_BTN_0";
|
||||
case INPUT_BTN_1:
|
||||
return "INPUT_BTN_1";
|
||||
case INPUT_BTN_2:
|
||||
return "INPUT_BTN_2";
|
||||
case INPUT_BTN_3:
|
||||
return "INPUT_BTN_3";
|
||||
case INPUT_BTN_4:
|
||||
return "INPUT_BTN_4";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_rel_code(struct input_listener_data *data, struct input_event *evt) {
|
||||
switch (evt->code) {
|
||||
case INPUT_REL_X:
|
||||
data->mouse.data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||
data->mouse.data.x += evt->value;
|
||||
break;
|
||||
case INPUT_REL_Y:
|
||||
data->mouse.data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||
data->mouse.data.y += evt->value;
|
||||
break;
|
||||
case INPUT_REL_WHEEL:
|
||||
data->mouse.wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||
data->mouse.wheel_data.y += evt->value;
|
||||
break;
|
||||
case INPUT_REL_HWHEEL:
|
||||
data->mouse.wheel_data.mode = INPUT_LISTENER_XY_DATA_MODE_REL;
|
||||
data->mouse.wheel_data.x += evt->value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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->mouse.button_set, btn, 1);
|
||||
} else {
|
||||
WRITE_BIT(data->mouse.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 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) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cfg->xy_swap) {
|
||||
swap_xy(evt);
|
||||
}
|
||||
|
||||
if ((cfg->x_invert && is_x_data(evt)) || (cfg->y_invert && is_y_data(evt))) {
|
||||
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);
|
||||
|
||||
LOG_DBG("Got input_handler event: %s with value 0x%x", get_input_code_name(evt), evt->value);
|
||||
|
||||
zmk_input_listener_layer_toggle_input_rel_received(config, data);
|
||||
|
||||
switch (evt->type) {
|
||||
case INPUT_EV_REL:
|
||||
handle_rel_code(data, evt);
|
||||
break;
|
||||
case INPUT_EV_ABS:
|
||||
handle_abs_code(config, data, evt);
|
||||
break;
|
||||
case INPUT_EV_KEY:
|
||||
handle_key_code(config, data, evt);
|
||||
break;
|
||||
}
|
||||
|
||||
if (evt->sync) {
|
||||
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->mouse.data.mode == INPUT_LISTENER_XY_DATA_MODE_REL) {
|
||||
zmk_hid_mouse_movement_set(data->mouse.data.x, data->mouse.data.y);
|
||||
}
|
||||
|
||||
if (data->mouse.button_set != 0) {
|
||||
for (int i = 0; i < ZMK_MOUSE_HID_NUM_BUTTONS; i++) {
|
||||
if ((data->mouse.button_set & BIT(i)) != 0) {
|
||||
zmk_hid_mouse_button_press(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data->mouse.button_clear != 0) {
|
||||
for (int i = 0; i < ZMK_MOUSE_HID_NUM_BUTTONS; i++) {
|
||||
if ((data->mouse.button_clear & 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->mouse.data);
|
||||
clear_xy_data(&data->mouse.wheel_data);
|
||||
|
||||
data->mouse.button_set = data->mouse.button_clear = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void zmk_input_listener_layer_toggle_input_rel_received(const struct input_listener_config *config,
|
||||
struct input_listener_data *data) {
|
||||
if (config->layer_toggle == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->layer_toggle_last_mouse_package_time = k_uptime_get();
|
||||
|
||||
if (data->layer_toggle_layer_enabled == false) {
|
||||
k_work_schedule(&data->layer_toggle_activation_delay,
|
||||
K_MSEC(config->layer_toggle_delay_ms));
|
||||
} else {
|
||||
// Deactivate the layer if no further movement within
|
||||
// layer_toggle_timeout_ms
|
||||
k_work_reschedule(&data->layer_toggle_deactivation_delay,
|
||||
K_MSEC(config->layer_toggle_timeout_ms));
|
||||
}
|
||||
}
|
||||
|
||||
void zmk_input_listener_layer_toggle_activate_layer(struct k_work *item) {
|
||||
struct k_work_delayable *d_work = k_work_delayable_from_work(item);
|
||||
|
||||
struct input_listener_data *data =
|
||||
CONTAINER_OF(d_work, struct input_listener_data, layer_toggle_activation_delay);
|
||||
const struct input_listener_config *config = data->dev->config;
|
||||
|
||||
int64_t current_time = k_uptime_get();
|
||||
int64_t last_mv_within_ms = current_time - data->layer_toggle_last_mouse_package_time;
|
||||
|
||||
if (last_mv_within_ms <= config->layer_toggle_timeout_ms * 0.1) {
|
||||
LOG_INF("Activating layer %d due to mouse activity...", config->layer_toggle);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_INPUT_MOUSE_PS2_ENABLE_UROB_COMPAT)
|
||||
|
||||
zmk_keymap_layer_activate(config->layer_toggle, false);
|
||||
|
||||
#else
|
||||
|
||||
zmk_keymap_layer_activate(config->layer_toggle);
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_INPUT_MOUSE_PS2_ENABLE_UROB_COMPAT) */
|
||||
|
||||
data->layer_toggle_layer_enabled = true;
|
||||
} else {
|
||||
LOG_INF("Not activating mouse layer %d, because last mouse activity was %lldms ago",
|
||||
config->layer_toggle, last_mv_within_ms);
|
||||
}
|
||||
}
|
||||
|
||||
void zmk_input_listener_layer_toggle_deactivate_layer(struct k_work *item) {
|
||||
struct k_work_delayable *d_work = k_work_delayable_from_work(item);
|
||||
|
||||
struct input_listener_data *data =
|
||||
CONTAINER_OF(d_work, struct input_listener_data, layer_toggle_deactivation_delay);
|
||||
const struct input_listener_config *config = data->dev->config;
|
||||
|
||||
LOG_INF("Deactivating layer %d due to mouse activity...", config->layer_toggle);
|
||||
|
||||
if (zmk_keymap_layer_active(config->layer_toggle)) {
|
||||
zmk_keymap_layer_deactivate(config->layer_toggle);
|
||||
}
|
||||
|
||||
data->layer_toggle_layer_enabled = false;
|
||||
}
|
||||
|
||||
static int zmk_input_listener_layer_toggle_init(const struct input_listener_config *config,
|
||||
struct input_listener_data *data) {
|
||||
k_work_init_delayable(&data->layer_toggle_activation_delay,
|
||||
zmk_input_listener_layer_toggle_activate_layer);
|
||||
k_work_init_delayable(&data->layer_toggle_deactivation_delay,
|
||||
zmk_input_listener_layer_toggle_deactivate_layer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // VALID_LISTENER_COUNT > 0
|
||||
|
||||
#define IL_INST(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), \
|
||||
.layer_toggle = DT_INST_PROP(n, layer_toggle), \
|
||||
.layer_toggle_delay_ms = DT_INST_PROP(n, layer_toggle_delay_ms), \
|
||||
.layer_toggle_timeout_ms = DT_INST_PROP(n, layer_toggle_timeout_ms), \
|
||||
}; \
|
||||
static struct input_listener_data data_##n = \
|
||||
{ \
|
||||
.dev = DEVICE_DT_INST_GET(n), \
|
||||
.layer_toggle_layer_enabled = false, \
|
||||
.layer_toggle_last_mouse_package_time = 0, \
|
||||
}; \
|
||||
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); \
|
||||
\
|
||||
static int zmk_input_listener_init_##n(const struct device *dev) { \
|
||||
struct input_listener_data *data = dev->data; \
|
||||
const struct input_listener_config *config = dev->config; \
|
||||
\
|
||||
zmk_input_listener_layer_toggle_init(config, data); \
|
||||
\
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, &zmk_input_listener_init_##n, NULL, &data_##n, &config_##n, \
|
||||
POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, NULL);), \
|
||||
())
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(IL_INST)
|
148
app/src/mouse/usb_hid.c
Normal file
148
app/src/mouse/usb_hid.c
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/init.h>
|
||||
|
||||
#include <zephyr/usb/usb_device.h>
|
||||
#include <zephyr/usb/class/usb_hid.h>
|
||||
|
||||
#include <zmk/usb.h>
|
||||
#include <zmk/mouse/hid.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/event_manager.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
static const struct device *hid_dev;
|
||||
|
||||
static K_SEM_DEFINE(hid_sem, 1, 1);
|
||||
|
||||
static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); }
|
||||
|
||||
#define HID_GET_REPORT_TYPE_MASK 0xff00
|
||||
#define HID_GET_REPORT_ID_MASK 0x00ff
|
||||
|
||||
#define HID_REPORT_TYPE_INPUT 0x100
|
||||
#define HID_REPORT_TYPE_OUTPUT 0x200
|
||||
#define HID_REPORT_TYPE_FEATURE 0x300
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
static uint8_t hid_protocol = HID_PROTOCOL_REPORT;
|
||||
|
||||
static void set_proto_cb(const struct device *dev, uint8_t protocol) { hid_protocol = protocol; }
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */
|
||||
|
||||
static int get_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len,
|
||||
uint8_t **data) {
|
||||
|
||||
/*
|
||||
* 7.2.1 of the HID v1.11 spec is unclear about handling requests for reports that do not exist
|
||||
* For requested reports that aren't input reports, return -ENOTSUP like the Zephyr subsys does
|
||||
*/
|
||||
if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_INPUT &&
|
||||
(setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_FEATURE) {
|
||||
LOG_ERR("Get: Unsupported report type %d requested",
|
||||
(setup->wValue & HID_GET_REPORT_TYPE_MASK) >> 8);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
switch (setup->wValue & HID_GET_REPORT_ID_MASK) {
|
||||
case ZMK_MOUSE_HID_REPORT_ID_MOUSE:
|
||||
struct zmk_hid_mouse_report *report = zmk_mouse_hid_get_mouse_report();
|
||||
*data = (uint8_t *)report;
|
||||
*len = sizeof(*report);
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Invalid report ID %d requested", setup->wValue & HID_GET_REPORT_ID_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len,
|
||||
uint8_t **data) {
|
||||
if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_OUTPUT &&
|
||||
(setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_FEATURE) {
|
||||
LOG_ERR("Set: Unsupported report type %d requested",
|
||||
(setup->wValue & HID_GET_REPORT_TYPE_MASK) >> 8);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
switch (setup->wValue & HID_GET_REPORT_ID_MASK) {
|
||||
default:
|
||||
LOG_ERR("Invalid report ID %d requested", setup->wValue & HID_GET_REPORT_ID_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hid_ops ops = {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
.protocol_change = set_proto_cb,
|
||||
#endif
|
||||
.int_in_ready = in_ready_cb,
|
||||
.get_report = get_report_cb,
|
||||
.set_report = set_report_cb,
|
||||
};
|
||||
|
||||
static int zmk_mouse_usb_hid_send_report(const uint8_t *report, size_t len) {
|
||||
switch (zmk_usb_get_status()) {
|
||||
case USB_DC_SUSPEND:
|
||||
return usb_wakeup_request();
|
||||
case USB_DC_ERROR:
|
||||
case USB_DC_RESET:
|
||||
case USB_DC_DISCONNECTED:
|
||||
case USB_DC_UNKNOWN:
|
||||
return -ENODEV;
|
||||
default:
|
||||
k_sem_take(&hid_sem, K_MSEC(30));
|
||||
LOG_HEXDUMP_DBG(report, len, "Mouse HID report");
|
||||
int err = hid_int_ep_write(hid_dev, report, len, NULL);
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Failed to write %d", err);
|
||||
k_sem_give(&hid_sem);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_mouse_usb_hid_send_mouse_report() {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
if (hid_protocol == HID_PROTOCOL_BOOT) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */
|
||||
|
||||
struct zmk_hid_mouse_report *report = zmk_mouse_hid_get_mouse_report();
|
||||
return zmk_mouse_usb_hid_send_report((uint8_t *)report, sizeof(*report));
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static int zmk_mouse_usb_hid_init(void) {
|
||||
hid_dev = device_get_binding("HID_1");
|
||||
if (hid_dev == NULL) {
|
||||
LOG_ERR("Unable to locate HID device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
usb_hid_register_device(hid_dev, zmk_mouse_hid_report_desc, sizeof(zmk_mouse_hid_report_desc),
|
||||
&ops);
|
||||
|
||||
// usb_hid_set_proto_code(hid_dev, HID_BOOT_IFACE_CODE_MOUSE);
|
||||
|
||||
usb_hid_init(hid_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(zmk_mouse_usb_hid_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
|
@ -164,19 +164,6 @@ int zmk_usb_hid_send_consumer_report(void) {
|
|||
return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report));
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_usb_hid_send_mouse_report() {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
if (hid_protocol == HID_PROTOCOL_BOOT) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */
|
||||
|
||||
struct zmk_hid_mouse_report *report = zmk_hid_get_mouse_report();
|
||||
return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report));
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static int zmk_usb_hid_init(void) {
|
||||
hid_dev = device_get_binding("HID_0");
|
||||
if (hid_dev == NULL) {
|
||||
|
|
6
app/tests/mouse-keys/mkp/native_posix_64.conf
Normal file
6
app/tests/mouse-keys/mkp/native_posix_64.conf
Normal file
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +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 -3/-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 -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
|
|
@ -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
|
|
@ -0,0 +1,33 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
&mmv_input_listener {
|
||||
scale-multiplier = <5>;
|
||||
scale-divisor = <3>;
|
||||
};
|
||||
|
||||
/ {
|
||||
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)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +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
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -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
|
|
@ -0,0 +1,33 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
&mmv_input_listener {
|
||||
x-invert;
|
||||
y-invert;
|
||||
};
|
||||
|
||||
/ {
|
||||
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)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +1,18 @@
|
|||
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
|
||||
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/-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 -3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -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
|
|
@ -0,0 +1,32 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
&mmv_input_listener {
|
||||
xy-swap;
|
||||
};
|
||||
|
||||
/ {
|
||||
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)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +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
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -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
|
|
@ -0,0 +1,29 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <behaviors/mouse_move.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
/ {
|
||||
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)
|
||||
>;
|
||||
};
|
1
app/tests/mouse-keys/mouse-move/move_x/events.patterns
Normal file
1
app/tests/mouse-keys/mouse-move/move_x/events.patterns
Normal file
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +1,24 @@
|
|||
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/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/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_set: Mouse movement set to -3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/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/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/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_set: Mouse movement set to 3/0
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -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
|
|
@ -0,0 +1,29 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <behaviors/mouse_move.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
/ {
|
||||
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)
|
||||
>;
|
||||
};
|
1
app/tests/mouse-keys/mouse-move/move_y/events.patterns
Normal file
1
app/tests/mouse-keys/mouse-move/move_y/events.patterns
Normal file
|
@ -0,0 +1 @@
|
|||
s/.*hid_mouse_//p
|
|
@ -0,0 +1,24 @@
|
|||
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 0/-2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
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_set: Mouse movement set to 0/-3
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/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 0/2
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
||||
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_set: Mouse movement set to 0/3
|
||||
scroll_set: Mouse scroll set to 0/0
|
||||
movement_set: Mouse movement set to 0/0
|
|
@ -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
|
|
@ -0,0 +1,29 @@
|
|||
#include <behaviors.dtsi>
|
||||
#include <behaviors/mouse_move.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include <dt-bindings/zmk/mouse.h>
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label ="Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&mmv MOVE_UP &mmv MOVE_DOWN
|
||||
&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)
|
||||
>;
|
||||
};
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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) | ✅ | ✅ | |
|
||||
|
|
Loading…
Add table
Reference in a new issue