Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointer Core: HID, mouse keys behavior, etc. #1991

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
target_sources(app PRIVATE src/events/activity_state_changed.c)
target_sources(app PRIVATE src/events/position_state_changed.c)
target_sources(app PRIVATE src/events/sensor_event.c)
target_sources(app PRIVATE src/events/mouse_button_state_changed.c)
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
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(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)
Expand All @@ -54,6 +56,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE app PRIVATE src/behaviors/behavior_sensor_rotate.c)
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(app PRIVATE src/combo.c)
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
target_sources(app PRIVATE src/behavior_queue.c)
Expand Down
13 changes: 13 additions & 0 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ config ZMK_BLE_CONSUMER_REPORT_QUEUE_SIZE
int "Max number of consumer HID reports to queue for sending over BLE"
default 5

config ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE
int "Max number of mouse HID reports to queue for sending over BLE"
default 20

config ZMK_BLE_CLEAR_BONDS_ON_START
bool "Configuration that clears all bond information from the keyboard on startup."
default n
Expand Down Expand Up @@ -316,6 +320,15 @@ endif
#Display/LED Options
endmenu

menu "Mouse Options"

config ZMK_MOUSE
bool "Enable ZMK mouse emulation"
default n

#Mouse Options
endmenu

menu "Power Management"

config ZMK_BATTERY_REPORTING
Expand Down
5 changes: 5 additions & 0 deletions app/Kconfig.behaviors
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ config ZMK_BEHAVIOR_KEY_TOGGLE
default y
depends on DT_HAS_ZMK_BEHAVIOR_KEY_TOGGLE_ENABLED

config ZMK_BEHAVIOR_MOUSE_KEY_PRESS
bool
default y
depends on DT_HAS_ZMK_BEHAVIOR_MOUSE_KEY_PRESS_ENABLED
imply ZMK_MOUSE

config ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON
bool
Expand Down
3 changes: 2 additions & 1 deletion app/dts/behaviors.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
#include <behaviors/caps_word.dtsi>
#include <behaviors/key_repeat.dtsi>
#include <behaviors/backlight.dtsi>
#include <behaviors/macros.dtsi>
#include <behaviors/macros.dtsi>
#include <behaviors/mouse_key_press.dtsi>
9 changes: 9 additions & 0 deletions app/dts/behaviors/mouse_key_press.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/ {
behaviors {
/omit-if-no-ref/ mkp: behavior_mouse_key_press {
compatible = "zmk,behavior-mouse-key-press";
label = "MOUSE_KEY_PRESS";
#binding-cells = <1>;
};
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description: Mouse key press/release behavior

compatible: "zmk,behavior-mouse-key-press"

include: one_param.yaml
1 change: 1 addition & 0 deletions app/include/dt-bindings/zmk/hid_usage_pages.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define HID_USAGE_GDV (0x06) // Generic Device Controls
#define HID_USAGE_KEY (0x07) // Keyboard/Keypad
#define HID_USAGE_LED (0x08) // LED
#define HID_USAGE_BUTTON (0x09) // Button
#define HID_USAGE_TELEPHONY (0x0B) // Telephony Device
#define HID_USAGE_CONSUMER (0x0C) // Consumer
#define HID_USAGE_DIGITIZERS (0x0D) // Digitizers
Expand Down
24 changes: 24 additions & 0 deletions app/include/dt-bindings/zmk/mouse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#pragma once

#include <zephyr/dt-bindings/dt-util.h>

/* Mouse press behavior */
/* Left click */
#define MB1 BIT(0)
#define LCLK (MB1)

/* Right click */
#define MB2 BIT(1)
#define RCLK (MB2)

/* Middle click */
#define MB3 BIT(2)
#define MCLK (MB3)

#define MB4 BIT(3)
#define MB5 BIT(4)
4 changes: 4 additions & 0 deletions app/include/zmk/endpoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@ int zmk_endpoints_toggle_transport(void);
struct zmk_endpoint_instance zmk_endpoints_selected(void);

int zmk_endpoints_send_report(uint16_t usage_page);

#if IS_ENABLED(CONFIG_ZMK_MOUSE)
int zmk_endpoints_send_mouse_report();
petejohanson marked this conversation as resolved.
Show resolved Hide resolved
#endif // IS_ENABLE(CONFIG_ZMK_MOUSE)
26 changes: 26 additions & 0 deletions app/include/zmk/events/mouse_button_state_changed.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

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

#pragma once

#include <zmk/hid.h>
#include <zmk/event_manager.h>
#include <zmk/mouse.h>

struct zmk_mouse_button_state_changed {
zmk_mouse_button_t buttons;
bool state;
int64_t timestamp;
};

ZMK_EVENT_DECLARE(zmk_mouse_button_state_changed);

static inline struct zmk_mouse_button_state_changed_event *
zmk_mouse_button_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) {
return new_zmk_mouse_button_state_changed((struct zmk_mouse_button_state_changed){
.buttons = ZMK_HID_USAGE_ID(encoded), .state = pressed, .timestamp = timestamp});
}
66 changes: 66 additions & 0 deletions app/include/zmk/hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@
#include <zephyr/usb/class/usb_hid.h>

#include <zmk/keys.h>
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
#include <zmk/mouse.h>
petejohanson marked this conversation as resolved.
Show resolved Hide resolved
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

#include <dt-bindings/zmk/hid_usage.h>
#include <dt-bindings/zmk/hid_usage_pages.h>

#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL
#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

Expand Down Expand Up @@ -46,6 +51,7 @@

#define ZMK_HID_REPORT_ID_KEYBOARD 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),
Expand Down Expand Up @@ -114,6 +120,39 @@ static const uint8_t zmk_hid_report_desc[] = {
HID_REPORT_COUNT(CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE),
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)
Expand Down Expand Up @@ -163,6 +202,21 @@ 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();
int zmk_hid_register_mod(zmk_mod_t modifier);
int zmk_hid_unregister_mod(zmk_mod_t modifier);
Expand All @@ -189,9 +243,21 @@ 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();
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report();
struct zmk_hid_consumer_report *zmk_hid_get_consumer_report();

#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)
4 changes: 4 additions & 0 deletions app/include/zmk/hog.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ int zmk_hog_init();

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)
12 changes: 12 additions & 0 deletions app/include/zmk/mouse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#pragma once

#include <dt-bindings/zmk/mouse.h>

typedef uint8_t zmk_mouse_button_flags_t;
typedef uint16_t zmk_mouse_button_t;
3 changes: 3 additions & 0 deletions app/include/zmk/usb_hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@

int zmk_usb_hid_send_keyboard_report();
int zmk_usb_hid_send_consumer_report();
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
int zmk_usb_hid_send_mouse_report();
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
void zmk_usb_hid_set_protocol(uint8_t protocol);
48 changes: 48 additions & 0 deletions app/src/behaviors/behavior_mouse_key_press.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#define DT_DRV_COMPAT zmk_behavior_mouse_key_press

#include <zephyr/device.h>
#include <drivers/behavior.h>
#include <zephyr/logging/log.h>

#include <zmk/behavior.h>
#include <zmk/event_manager.h>
#include <zmk/events/mouse_button_state_changed.h>

LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);

#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)

static int behavior_mouse_key_press_init(const struct device *dev) { return 0; };

static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);

return ZMK_EVENT_RAISE(
zmk_mouse_button_state_changed_from_encoded(binding->param1, true, event.timestamp));
}

static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
struct zmk_behavior_binding_event event) {
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
return ZMK_EVENT_RAISE(
zmk_mouse_button_state_changed_from_encoded(binding->param1, false, event.timestamp));
}

static const struct behavior_driver_api behavior_mouse_key_press_driver_api = {
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};

#define MKP_INST(n) \
DEVICE_DT_INST_DEFINE(n, behavior_mouse_key_press_init, NULL, NULL, NULL, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
&behavior_mouse_key_press_driver_api);

DT_INST_FOREACH_STATUS_OKAY(MKP_INST)

#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
33 changes: 33 additions & 0 deletions app/src/endpoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,36 @@ int zmk_endpoints_send_report(uint16_t usage_page) {
return -ENOTSUP;
}

#if IS_ENABLED(CONFIG_ZMK_MOUSE)
int zmk_endpoints_send_mouse_report() {
petejohanson marked this conversation as resolved.
Show resolved Hide resolved
switch (current_instance.transport) {
#if IS_ENABLED(CONFIG_ZMK_USB)
case ZMK_TRANSPORT_USB: {
int err = zmk_usb_hid_send_mouse_report();
if (err) {
LOG_ERR("FAILED TO SEND OVER USB: %d", err);
}
return err;
}
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */

#if IS_ENABLED(CONFIG_ZMK_BLE)
case ZMK_TRANSPORT_BLE: {
struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report();
int err = zmk_hog_send_mouse_report(&mouse_report->body);
if (err) {
LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
}
return err;
}
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
}

LOG_ERR("Unsupported endpoint transport %d", current_instance.transport);
return -ENOTSUP;
}
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

#if IS_ENABLED(CONFIG_SETTINGS)

static int endpoints_handle_set(const char *name, size_t len, settings_read_cb read_cb,
Expand Down Expand Up @@ -295,6 +325,9 @@ static int zmk_endpoints_init(const struct device *_arg) {
static void disconnect_current_endpoint() {
zmk_hid_keyboard_clear();
zmk_hid_consumer_clear();
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
zmk_hid_mouse_clear();
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)

zmk_endpoints_send_report(HID_USAGE_KEY);
zmk_endpoints_send_report(HID_USAGE_CONSUMER);
Expand Down
9 changes: 9 additions & 0 deletions app/src/events/mouse_button_state_changed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <zmk/events/mouse_button_state_changed.h>

ZMK_EVENT_IMPL(zmk_mouse_button_state_changed);
Loading