From d8d8b96992c509408ed305a427265f7d0759288b Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Tue, 27 Apr 2021 18:24:11 +0300 Subject: [PATCH 01/35] Preliminary work for mouse click --- app/Kconfig | 4 ++ app/include/dt-bindings/zmk/mouse.h | 9 ++++ app/include/zmk/hid.h | 46 +++++++++++++++++++ app/include/zmk/hog.h | 1 + app/include/zmk/mouse.h | 13 ++++++ app/src/endpoints.c | 38 ++++++++++++++- app/src/hid.c | 62 +++++++++++++++++++++++++ app/src/hid_listener.c | 15 ++++++ app/src/hog.c | 71 +++++++++++++++++++++++++++++ 9 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 app/include/dt-bindings/zmk/mouse.h create mode 100644 app/include/zmk/mouse.h diff --git a/app/Kconfig b/app/Kconfig index 8817d506..60423891 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -124,6 +124,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 5 + config ZMK_BLE_CLEAR_BONDS_ON_START bool "Configuration that clears all bond information from the keyboard on startup." default n diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h new file mode 100644 index 00000000..0e0e6341 --- /dev/null +++ b/app/include/dt-bindings/zmk/mouse.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#pragma once + +#include +#include \ No newline at end of file diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index 95b82d46..65836d28 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -183,6 +184,33 @@ static const uint8_t zmk_hid_report_desc[] = { 0x00, /* END COLLECTION */ HID_MI_COLLECTION_END, + + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xA1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (0x01) */ + 0x29, 0x03, /* Usage Maximum (0x03) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x03, /* Report Count (3) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */ + 0x95, 0x01, /* Report Count (1) */ + 0x75, 0x05, /* Report Size (5) */ + 0x81, 0x03, /* Input (Const,Var,Abs,No Wrap,Linear,...) */ + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x15, 0x81, /* Logical Minimum (129) */ + 0x25, 0x7F, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Size (8) */ + 0x95, 0x02, /* Report Count (2) */ + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ + 0xC0, /* End Collection */ + 0xC0, /* End Collection */ }; // struct zmk_hid_boot_report @@ -220,6 +248,17 @@ struct zmk_hid_consumer_report { struct zmk_hid_consumer_report_body body; } __packed; +struct zmk_hid_mouse_report_body { + zmk_mouse_button_flags_t buttons; + int8_t x; + int8_t y; +} __packed; + +struct zmk_hid_mouse_report { + uint8_t report_id; + struct zmk_hid_mouse_report_body body; +} __packed; + 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); @@ -235,5 +274,12 @@ int zmk_hid_consumer_press(zmk_key_t key); int zmk_hid_consumer_release(zmk_key_t key); void zmk_hid_consumer_clear(); +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(); + struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(); +struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(); diff --git a/app/include/zmk/hog.h b/app/include/zmk/hog.h index 7523fb66..9debc3ff 100644 --- a/app/include/zmk/hog.h +++ b/app/include/zmk/hog.h @@ -13,3 +13,4 @@ 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); +int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body); diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h new file mode 100644 index 00000000..0d4bcb61 --- /dev/null +++ b/app/include/zmk/mouse.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +typedef uint8_t zmk_mouse_button_flags_t; +typedef uint8_t zmk_mouse_button_t; \ No newline at end of file diff --git a/app/src/endpoints.c b/app/src/endpoints.c index c15aad87..c4b4e235 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -106,7 +106,7 @@ static int send_consumer_report() { switch (current_endpoint) { #if IS_ENABLED(CONFIG_ZMK_USB) - case ZMK_ENDPOINT_USB: { + case ZMK_ENDPOINT_USB: { int err = zmk_usb_hid_send_report((uint8_t *)consumer_report, sizeof(*consumer_report)); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); @@ -116,7 +116,7 @@ static int send_consumer_report() { #endif /* IS_ENABLED(CONFIG_ZMK_USB) */ #if IS_ENABLED(CONFIG_ZMK_BLE) - case ZMK_ENDPOINT_BLE: { + case ZMK_ENDPOINT_BLE: { int err = zmk_hog_send_consumer_report(&consumer_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); @@ -131,6 +131,36 @@ static int send_consumer_report() { } } +static int send_mouse_report() { + struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); + + switch (current_endpoint) { +#if IS_ENABLED(CONFIG_ZMK_USB) + case ZMK_ENDPOINT_USB: { + int err = zmk_usb_hid_send_report((uint8_t *)mouse_report, sizeof(*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_ENDPOINT_BLE: { + 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) */ + + default: + LOG_ERR("Unsupported endpoint %d", current_endpoint); + return -ENOTSUP; + } +} + int zmk_endpoints_send_report(uint16_t usage_page) { LOG_DBG("usage page 0x%02X", usage_page); @@ -139,6 +169,8 @@ int zmk_endpoints_send_report(uint16_t usage_page) { return send_keyboard_report(); case HID_USAGE_CONSUMER: return send_consumer_report(); + case HID_USAGE_GD: + return send_mouse_report(); default: LOG_ERR("Unsupported usage page %d", usage_page); return -ENOTSUP; @@ -229,9 +261,11 @@ static enum zmk_endpoint get_selected_endpoint() { static void disconnect_current_endpoint() { zmk_hid_keyboard_clear(); zmk_hid_consumer_clear(); + zmk_hid_mouse_clear(); zmk_endpoints_send_report(HID_USAGE_KEY); zmk_endpoints_send_report(HID_USAGE_CONSUMER); + zmk_endpoints_send_report(HID_USAGE_GD); } static void update_current_endpoint() { diff --git a/app/src/hid.c b/app/src/hid.c index b524b09f..4a2f2b3d 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -15,6 +15,9 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; +static struct zmk_hid_mouse_report mouse_report = {.report_id = 3, .body = { + .buttons = 0, .x = 0, .y = 0}}; + // 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}; @@ -169,6 +172,61 @@ int zmk_hid_consumer_release(zmk_key_t code) { void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer_report.body)); } + +// Keep track of how often a button was pressed. +// Only release the button if the count is 0. +static int explicit_button_counts[3] = {0, 0, 0}; +static zmk_mod_flags_t explicit_buttons = 0; + +#define SET_MOUSE_BUTTONS(butts) \ + { \ + mouse_report.body.buttons = butts; \ + LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \ + } + +int zmk_hid_mouse_button_press(zmk_mouse_button_t button) { + explicit_button_counts[button-5]++; + LOG_DBG("Button %d count %d", button, explicit_button_counts[button-5]); + 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 (explicit_button_counts[button-5] <= 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-5]); + if (explicit_button_counts[button-5] == 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_mod_t i = 5; i < 8; i++) { + if (buttons & (1 << i)) { + zmk_hid_mouse_button_press(i); + } + } + return 0; +} + +int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { + for (zmk_mod_t i = 5; i < 8; i++) { + if (buttons & (1 << i)) { + zmk_hid_mouse_button_release(i); + } + } + return 0; +} + +void zmk_hid_mouse_clear() { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } + struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { return &keyboard_report; } @@ -176,3 +234,7 @@ struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { struct zmk_hid_consumer_report *zmk_hid_get_consumer_report() { return &consumer_report; } + +struct zmk_hid_mouse_report *zmk_hid_get_mouse_report() { + return &mouse_report; +} diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index d582c169..e3c91215 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -35,6 +35,13 @@ static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed * return err; } break; + case HID_USAGE_GD: + err = zmk_hid_mouse_buttons_press(ev->keycode); + if (err) { + LOG_ERR("Unable to press button"); + return err; + } + break; } zmk_hid_register_mods(ev->explicit_modifiers); zmk_hid_implicit_modifiers_press(ev->implicit_modifiers); @@ -59,6 +66,14 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed LOG_ERR("Unable to release keycode"); return err; } + break; + case HID_USAGE_GD: + err = zmk_hid_mouse_buttons_release(ev->keycode); + if (err) { + LOG_ERR("Unable to release button"); + return err; + } + break; } zmk_hid_unregister_mods(ev->explicit_modifiers); // There is a minor issue with this code. diff --git a/app/src/hog.c b/app/src/hog.c index e8aceca3..8b285bf1 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -56,6 +56,11 @@ static struct hids_report consumer_input = { .type = HIDS_INPUT, }; +static struct hids_report mouse_input = { + .id = 0x03, + .type = HIDS_INPUT, +}; + static bool host_requests_notification = false; static uint8_t ctrl_point; // static uint8_t proto_mode; @@ -93,6 +98,14 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, sizeof(struct zmk_hid_consumer_report_body)); } +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)); +} + // 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, @@ -139,6 +152,13 @@ BT_GATT_SERVICE_DEFINE( 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, &consumer_input), + + 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_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point)); @@ -261,6 +281,57 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { return 0; }; +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[10], + .data = &report, + .len = sizeof(report), + }; + + int err = bt_gatt_notify_cb(conn, ¬ify_params); + 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("Mouse 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; +}; + int zmk_hog_init(const struct device *_arg) { k_work_q_start(&hog_work_q, hog_q_stack, K_THREAD_STACK_SIZEOF(hog_q_stack), CONFIG_ZMK_BLE_THREAD_PRIORITY); From 9b0997473472bbd9de32508191e19b98020cbda3 Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Wed, 28 Apr 2021 15:07:54 +0300 Subject: [PATCH 02/35] Fine-tuning report, 16 buttons --- app/include/zmk/hid.h | 20 +++++++++----------- app/include/zmk/mouse.h | 4 ++-- app/src/hid.c | 23 +++++++++++++---------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index 65836d28..eaf267cc 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -188,26 +188,24 @@ static const uint8_t zmk_hid_report_desc[] = { 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ 0x09, 0x02, /* Usage (Mouse) */ 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x04, /* Report ID (4) */ 0x09, 0x01, /* Usage (Pointer) */ 0xA1, 0x00, /* Collection (Physical) */ 0x05, 0x09, /* Usage Page (Button) */ 0x19, 0x01, /* Usage Minimum (0x01) */ - 0x29, 0x03, /* Usage Maximum (0x03) */ + 0x29, 0x10, /* Usage Maximum (0x10) */ 0x15, 0x00, /* Logical Minimum (0) */ 0x25, 0x01, /* Logical Maximum (1) */ - 0x95, 0x03, /* Report Count (3) */ + 0x95, 0x10, /* Report Count (16) */ 0x75, 0x01, /* Report Size (1) */ 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */ - 0x95, 0x01, /* Report Count (1) */ - 0x75, 0x05, /* Report Size (5) */ - 0x81, 0x03, /* Input (Const,Var,Abs,No Wrap,Linear,...) */ 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x16, 0x01, 0x80, /* Logical Minimum (-32767) */ + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */ + 0x75, 0x10, /* Report Size (8) */ + 0x95, 0x02, /* Report Count (2) */ 0x09, 0x30, /* Usage (X) */ 0x09, 0x31, /* Usage (Y) */ - 0x15, 0x81, /* Logical Minimum (129) */ - 0x25, 0x7F, /* Logical Maximum (127) */ - 0x75, 0x08, /* Report Size (8) */ - 0x95, 0x02, /* Report Count (2) */ 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ 0xC0, /* End Collection */ 0xC0, /* End Collection */ @@ -250,8 +248,8 @@ struct zmk_hid_consumer_report { struct zmk_hid_mouse_report_body { zmk_mouse_button_flags_t buttons; - int8_t x; - int8_t y; + int16_t x; + int16_t y; } __packed; struct zmk_hid_mouse_report { diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index 0d4bcb61..32d3d03e 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -9,5 +9,5 @@ #include #include -typedef uint8_t zmk_mouse_button_flags_t; -typedef uint8_t zmk_mouse_button_t; \ No newline at end of file +typedef uint16_t zmk_mouse_button_flags_t; +typedef uint16_t zmk_mouse_button_t; \ No newline at end of file diff --git a/app/src/hid.c b/app/src/hid.c index 4a2f2b3d..26ad29b8 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -15,7 +15,7 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; -static struct zmk_hid_mouse_report mouse_report = {.report_id = 3, .body = { +static struct zmk_hid_mouse_report mouse_report = {.report_id = 4, .body = { .buttons = 0, .x = 0, .y = 0}}; // Keep track of how often a modifier was pressed. @@ -175,7 +175,7 @@ void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer // Keep track of how often a button was pressed. // Only release the button if the count is 0. -static int explicit_button_counts[3] = {0, 0, 0}; +static int explicit_button_counts[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static zmk_mod_flags_t explicit_buttons = 0; #define SET_MOUSE_BUTTONS(butts) \ @@ -185,21 +185,21 @@ static zmk_mod_flags_t explicit_buttons = 0; } int zmk_hid_mouse_button_press(zmk_mouse_button_t button) { - explicit_button_counts[button-5]++; - LOG_DBG("Button %d count %d", button, explicit_button_counts[button-5]); + 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 (explicit_button_counts[button-5] <= 0) { + 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-5]); - if (explicit_button_counts[button-5] == 0) { + 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); } @@ -208,7 +208,7 @@ int zmk_hid_mouse_button_release(zmk_mouse_button_t button) { } int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) { - for (zmk_mod_t i = 5; i < 8; i++) { + for (zmk_mod_t i = 0; i < 16; i++) { if (buttons & (1 << i)) { zmk_hid_mouse_button_press(i); } @@ -217,7 +217,7 @@ int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons) { } int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { - for (zmk_mod_t i = 5; i < 8; i++) { + for (zmk_mod_t i = 0; i < 16; i++) { if (buttons & (1 << i)) { zmk_hid_mouse_button_release(i); } @@ -225,7 +225,10 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { return 0; } -void zmk_hid_mouse_clear() { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } +void zmk_hid_mouse_clear() { + memset(&mouse_report.body, 0, sizeof(mouse_report.body)); + mouse_report.body.buffer = 1; +} struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { return &keyboard_report; From e585af2aa139282685a4985221c6051e34e1be1f Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Thu, 29 Apr 2021 11:29:53 +0300 Subject: [PATCH 03/35] Bluetooth tuning, mouse wheel and movement backend --- app/include/zmk/endpoints.h | 1 + app/include/zmk/hid.h | 22 +++++++++++++-- app/src/endpoints.c | 33 +++++++++++------------ app/src/hid.c | 53 ++++++++++++++++++++++++++++++++++--- app/src/hog.c | 10 +++++-- 5 files changed, 94 insertions(+), 25 deletions(-) diff --git a/app/include/zmk/endpoints.h b/app/include/zmk/endpoints.h index c8860533..450d7ea3 100644 --- a/app/include/zmk/endpoints.h +++ b/app/include/zmk/endpoints.h @@ -13,3 +13,4 @@ int zmk_endpoints_toggle(); enum zmk_endpoint zmk_endpoints_selected(); int zmk_endpoints_send_report(uint16_t usage_page); +int zmk_endpoints_send_mouse_report(); diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index eaf267cc..ec0cb626 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -207,6 +207,18 @@ static const uint8_t zmk_hid_report_desc[] = { 0x09, 0x30, /* Usage (X) */ 0x09, 0x31, /* Usage (Y) */ 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7F, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Count (8) */ + 0x95, 0x01, /* Report Size (1) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ + 0x05, 0x0C, /* Usage Page (Consumer) */ // Horizontal wheel + 0x0A, 0x38, 0x02, /* Usage (AC Pan) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7f, /* Logical Maximum (127) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ 0xC0, /* End Collection */ 0xC0, /* End Collection */ }; @@ -248,8 +260,10 @@ struct zmk_hid_consumer_report { struct zmk_hid_mouse_report_body { zmk_mouse_button_flags_t buttons; - int16_t x; - int16_t y; + uint16_t x; + uint16_t y; + uint8_t wheel_vert; + uint8_t wheel_hor; } __packed; struct zmk_hid_mouse_report { @@ -276,6 +290,10 @@ int zmk_hid_mouse_button_press(zmk_mouse_button_t button); int zmk_hid_mouse_button_release(zmk_mouse_button_t button); int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); +int zmk_hid_mouse_movement_press(uint16_t x, uint16_t y); +int zmk_hid_mouse_movement_release(uint16_t x, uint16_t y); +int zmk_hid_mouse_wheel_press(uint8_t hor, uint8_t vert); +int zmk_hid_mouse_wheel_release(uint8_t hor, uint8_t vert); void zmk_hid_mouse_clear(); struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); diff --git a/app/src/endpoints.c b/app/src/endpoints.c index c4b4e235..ff6d5ad3 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -131,7 +131,22 @@ static int send_consumer_report() { } } -static int send_mouse_report() { +int zmk_endpoints_send_report(uint16_t usage_page) { + + LOG_DBG("usage page 0x%02X", usage_page); + switch (usage_page) { + case HID_USAGE_KEY: + return send_keyboard_report(); + case HID_USAGE_CONSUMER: + return send_consumer_report(); + default: + LOG_ERR("Unsupported usage page %d", usage_page); + return -ENOTSUP; + } +} + +int zmk_endpoints_send_mouse_report() { + LOG_ERR("SENDING MOUSE REPORT"); struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); switch (current_endpoint) { @@ -161,22 +176,6 @@ static int send_mouse_report() { } } -int zmk_endpoints_send_report(uint16_t usage_page) { - - LOG_DBG("usage page 0x%02X", usage_page); - switch (usage_page) { - case HID_USAGE_KEY: - return send_keyboard_report(); - case HID_USAGE_CONSUMER: - return send_consumer_report(); - case HID_USAGE_GD: - return send_mouse_report(); - default: - LOG_ERR("Unsupported usage page %d", usage_page); - return -ENOTSUP; - } -} - #if IS_ENABLED(CONFIG_SETTINGS) static int endpoints_handle_set(const char *name, size_t len, settings_read_cb read_cb, diff --git a/app/src/hid.c b/app/src/hid.c index 26ad29b8..75e0f45a 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -16,7 +16,7 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; static struct zmk_hid_mouse_report mouse_report = {.report_id = 4, .body = { - .buttons = 0, .x = 0, .y = 0}}; + .buttons = 0, .x = 0, .y = 0, .wheel_hor = 0, .wheel_vert = 0}}; // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. @@ -177,6 +177,10 @@ void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer // Only release the button if the count is 0. static int explicit_button_counts[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static zmk_mod_flags_t explicit_buttons = 0; +static int16_t curr_x = 0; +static int16_t curr_y = 0; +static int8_t curr_hor = 0; +static int8_t curr_vert = 0; #define SET_MOUSE_BUTTONS(butts) \ { \ @@ -225,11 +229,52 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { return 0; } -void zmk_hid_mouse_clear() { - memset(&mouse_report.body, 0, sizeof(mouse_report.body)); - mouse_report.body.buffer = 1; +#define SET_MOUSE_MOVEMENT(coor_x, coor_y) \ + { \ + mouse_report.body.x = coor_x; \ + LOG_DBG("Mouse movement x set to 0x%02X", mouse_report.body.x); \ + mouse_report.body.y = coor_y; \ + LOG_DBG("Mouse movement y set to 0x%02X", mouse_report.body.y); \ + } + +int zmk_hid_mouse_movement_press(uint16_t x, uint16_t y) { + curr_x += x; + curr_y += y; + SET_MOUSE_MOVEMENT(curr_x, curr_y); + return 0; } +int zmk_hid_mouse_movement_release(uint16_t x, uint16_t y) { + curr_x -= x; + curr_y -= y; + SET_MOUSE_MOVEMENT(curr_x, curr_y); + return 0; +} + +#define SET_MOUSE_WHEEL(horiz, vertic) \ + { \ + mouse_report.body.wheel_hor = horiz; \ + LOG_DBG("Mouse wheel hor set to 0x%02X", mouse_report.body.wheel_hor); \ + mouse_report.body.wheel_vert = vertic; \ + LOG_DBG("Mouse wheel vert set to 0x%02X", mouse_report.body.wheel_vert); \ + } + +int zmk_hid_mouse_wheel_press(uint8_t hor, uint8_t vert) { + curr_hor += hor; + curr_vert += vert; + SET_MOUSE_WHEEL(curr_hor, curr_vert); + return 0; +} + +int zmk_hid_mouse_wheel_release(uint8_t hor, uint8_t vert) { + curr_hor -= hor; + curr_vert -= vert; + SET_MOUSE_WHEEL(curr_hor, curr_vert); + return 0; +} + +void zmk_hid_mouse_clear() { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } + struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { return &keyboard_report; } diff --git a/app/src/hog.c b/app/src/hog.c index 8b285bf1..2bbf874f 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -57,7 +57,7 @@ static struct hids_report consumer_input = { }; static struct hids_report mouse_input = { - .id = 0x03, + .id = 0x04, .type = HIDS_INPUT, }; @@ -187,6 +187,8 @@ K_MSGQ_DEFINE(zmk_hog_keyboard_msgq, sizeof(struct zmk_hid_keyboard_report_body) void send_keyboard_report_callback(struct k_work *work) { struct zmk_hid_keyboard_report_body report; + LOG_ERR("Sending keyboard callback"); + while (k_msgq_get(&zmk_hog_keyboard_msgq, &report, K_NO_WAIT) == 0) { struct bt_conn *conn = destination_connection(); if (conn == NULL) { @@ -212,6 +214,7 @@ K_WORK_DEFINE(hog_keyboard_work, send_keyboard_report_callback); int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *report) { int err = k_msgq_put(&zmk_hog_keyboard_msgq, report, K_MSEC(100)); + LOG_ERR("Sending keyboard report"); if (err) { switch (err) { case -EAGAIN: { @@ -288,6 +291,8 @@ CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); void send_mouse_report_callback(struct k_work *work) { struct zmk_hid_mouse_report_body report; + LOG_ERR("Sending mouse callback"); + while (k_msgq_get(&zmk_hog_mouse_msgq, &report, K_NO_WAIT) == 0) { struct bt_conn *conn = destination_connection(); if (conn == NULL) { @@ -295,7 +300,7 @@ void send_mouse_report_callback(struct k_work *work) { } struct bt_gatt_notify_params notify_params = { - .attr = &hog_svc.attrs[10], + .attr = &hog_svc.attrs[13], .data = &report, .len = sizeof(report), }; @@ -313,6 +318,7 @@ 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)); + LOG_ERR("Sending mouse report"); if (err) { switch (err) { case -EAGAIN: { From aefbd5edc993f6e28776dddc20ff14567af79e83 Mon Sep 17 00:00:00 2001 From: Dmitry Tsykunov <> Date: Thu, 29 Apr 2021 04:49:04 +0300 Subject: [PATCH 04/35] Mouse-related behaviours --- app/CMakeLists.txt | 3 ++ app/dts/behaviors.dtsi | 3 ++ app/dts/behaviors/mouse_key_press.dtsi | 9 ++++ app/dts/behaviors/mouse_move.dtsi | 9 ++++ app/dts/behaviors/mouse_wheel.dtsi | 9 ++++ .../zmk,behavior-mouse-key-press.yaml | 5 ++ .../behaviors/zmk,behavior-mouse-move.yaml | 5 ++ .../behaviors/zmk,behavior-mouse-wheel.yaml | 5 ++ app/include/dt-bindings/zmk/mouse.h | 39 ++++++++++++++- app/src/behaviors/behavior_mouse_key_press.c | 45 +++++++++++++++++ app/src/behaviors/behavior_mouse_move.c | 49 ++++++++++++++++++ app/src/behaviors/behavior_mouse_wheel.c | 50 +++++++++++++++++++ 12 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 app/dts/behaviors/mouse_key_press.dtsi create mode 100644 app/dts/behaviors/mouse_move.dtsi create mode 100644 app/dts/behaviors/mouse_wheel.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml create mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml create mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml create mode 100644 app/src/behaviors/behavior_mouse_key_press.c create mode 100644 app/src/behaviors/behavior_mouse_move.c create mode 100644 app/src/behaviors/behavior_mouse_wheel.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5092deff..27b68957 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -55,6 +55,9 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_key_press.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_move.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_wheel.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/keymap.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 4333ceea..9aa5bf57 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -14,3 +14,6 @@ #include #include #include +#include +#include +#include diff --git a/app/dts/behaviors/mouse_key_press.dtsi b/app/dts/behaviors/mouse_key_press.dtsi new file mode 100644 index 00000000..8b2aacb3 --- /dev/null +++ b/app/dts/behaviors/mouse_key_press.dtsi @@ -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>; + }; + }; +}; diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi new file mode 100644 index 00000000..e442c501 --- /dev/null +++ b/app/dts/behaviors/mouse_move.dtsi @@ -0,0 +1,9 @@ +/ { + behaviors { + /omit-if-no-ref/ mmv: behavior_mouse_move { + compatible = "zmk,behavior-mouse-move"; + label = "MOUSE_MOVE"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/behaviors/mouse_wheel.dtsi b/app/dts/behaviors/mouse_wheel.dtsi new file mode 100644 index 00000000..2a7527ab --- /dev/null +++ b/app/dts/behaviors/mouse_wheel.dtsi @@ -0,0 +1,9 @@ +/ { + behaviors { + /omit-if-no-ref/ mwh: behavior_mouse_wheel { + compatible = "zmk,behavior-mouse-wheel"; + label = "MOUSE_WHEEL"; + #binding-cells = <1>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml new file mode 100644 index 00000000..8540916b --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-key-press.yaml @@ -0,0 +1,5 @@ +description: Mouse key press/release behavior + +compatible: "zmk,behavior-mouse-key-press" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml new file mode 100644 index 00000000..f18d78a7 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml @@ -0,0 +1,5 @@ +description: Mouse move + +compatible: "zmk,behavior-mouse-move" + +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml new file mode 100644 index 00000000..89021172 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml @@ -0,0 +1,5 @@ +description: Mouse wheel + +compatible: "zmk,behavior-mouse-wheel" + +include: one_param.yaml diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 0e0e6341..bd7b395e 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -5,5 +5,40 @@ */ #pragma once -#include -#include \ No newline at end of file +/* Left click */ +#define MB1 (0x01) +#define LCLK (MB1) + +/* Right click */ +#define MB2 (0x02) +#define RCLK (MB2) + +/* Middle click */ +#define MB3 (0x04) +#define MCLK (MB3) + +#define MB4 (0x08) + +#define MB5 (0x10) + +#define MB6 (0x20) + +#define MB7 (0x40) + +#define MB8 (0x80) + +#define MOVE_UP (0x0000FFFF) + +#define MOVE_DOWN (0x00000001) + +#define MOVE_LEFT (0xFFFF0000) + +#define MOVE_RIGHT (0x00010000) + +#define WHEEL_UP (0x0001) + +#define WHEEL_DOWN (0x00FF) + +#define WHEEL_LEFT (0xFF00) + +#define WHEEL_RIGHT (0x0100) diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c new file mode 100644 index 00000000..43754f6e --- /dev/null +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_key_press + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +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); + zmk_hid_mouse_buttons_press(HID_USAGE_ID(binding->param1)); + return zmk_endpoints_send_mouse_report(); +} + +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); + zmk_hid_mouse_buttons_release(HID_USAGE_ID(binding->param1)); + return zmk_endpoints_send_mouse_report(); +} + +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 KP_INST(n) \ + DEVICE_AND_API_INIT(behavior_mouse_key_press_##n, DT_INST_LABEL(n), behavior_mouse_key_press_init, NULL, \ + NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_mouse_key_press_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c new file mode 100644 index 00000000..0fd2cd52 --- /dev/null +++ b/app/src/behaviors/behavior_mouse_move.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_move + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static int behavior_mouse_move_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + uint32_t x = (binding->param1 & 0xFFFF0000) >> 16; + uint32_t y = binding->param1 & 0x0000FFFF; + zmk_hid_mouse_movement_press(x, y); + return zmk_endpoints_send_mouse_report(); +} + +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); + uint32_t x = (binding->param1 & 0xFFFF0000) >> 16; + uint32_t y = binding->param1 & 0x0000FFFF; + zmk_hid_mouse_movement_release(x, y); + return zmk_endpoints_send_mouse_report(); +} + +static const struct behavior_driver_api behavior_mouse_move_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + DEVICE_AND_API_INIT(behavior_mouse_move_##n, DT_INST_LABEL(n), behavior_mouse_move_init, NULL, \ + NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_mouse_move_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/behaviors/behavior_mouse_wheel.c b/app/src/behaviors/behavior_mouse_wheel.c new file mode 100644 index 00000000..4f99876f --- /dev/null +++ b/app/src/behaviors/behavior_mouse_wheel.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_wheel + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +static int behavior_mouse_wheel_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); + int32_t x = (binding->param1 & 0xFF00) >> 8; + int32_t y = binding->param1 & 0x00FF; + zmk_hid_mouse_wheel_press(x, y); + return zmk_endpoints_send_mouse_report(); +} + +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); + int32_t x = (binding->param1 & 0xFF00) >> 8; + int32_t y = binding->param1 & 0x00FF; + zmk_hid_mouse_wheel_release(x, y); + return zmk_endpoints_send_mouse_report(); +} + +static const struct behavior_driver_api behavior_mouse_wheel_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + + +#define KP_INST(n) \ + DEVICE_AND_API_INIT(behavior_mouse_wheel_##n, DT_INST_LABEL(n), behavior_mouse_wheel_init, NULL, \ + NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_mouse_wheel_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) From 400e24608bdd154a1547e1a6e2c4ba828eda0224 Mon Sep 17 00:00:00 2001 From: Dmitry Tsykunov <> Date: Thu, 29 Apr 2021 17:52:22 +0300 Subject: [PATCH 05/35] Add mouse movement event --- app/CMakeLists.txt | 1 + app/include/zmk/events/mouse_state_changed.h | 33 +++++++++++++++++++ app/src/behaviors/behavior_mouse_move.c | 17 ++++------ app/src/events/mouse_state_changed.c | 10 ++++++ app/src/hid_listener.c | 34 +++++++++++++++++++- 5 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 app/include/zmk/events/mouse_state_changed.h create mode 100644 app/src/events/mouse_state_changed.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 27b68957..e7c55330 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -38,6 +38,7 @@ target_sources(app PRIVATE src/events/keycode_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/endpoint_selection_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) +target_sources(app PRIVATE src/events/mouse_state_changed.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c) diff --git a/app/include/zmk/events/mouse_state_changed.h b/app/include/zmk/events/mouse_state_changed.h new file mode 100644 index 00000000..10d4a02f --- /dev/null +++ b/app/include/zmk/events/mouse_state_changed.h @@ -0,0 +1,33 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include + +struct zmk_mouse_state_changed { + uint32_t x; + uint32_t y; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_state_changed); + +static inline struct zmk_mouse_state_changed_event * +zmk_mouse_state_changed_from_encoded(uint32_t encoded, bool pressed, + int64_t timestamp) { + + uint32_t x = (binding->param1 & 0xFFFF0000) >> 16; + uint32_t y = binding->param1 & 0x0000FFFF; + LOG_DBG("x: 0x%02X y: 0x%02X", x, y); + zmk_hid_mouse_movement_release(x, y); + + return new_zmk_mouse_state_changed((struct zmk_mouse_state_changed){ + .x = x, .y = y, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c index 0fd2cd52..d1aeb314 100644 --- a/app/src/behaviors/behavior_mouse_move.c +++ b/app/src/behaviors/behavior_mouse_move.c @@ -13,29 +13,26 @@ #include #include #include -#include -#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +ZMK_EVENT_DECLARE(zmk_mouse_move); + static int behavior_mouse_move_init(const struct device *dev) { return 0; }; static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - uint32_t x = (binding->param1 & 0xFFFF0000) >> 16; - uint32_t y = binding->param1 & 0x0000FFFF; - zmk_hid_mouse_movement_press(x, y); - return zmk_endpoints_send_mouse_report(); + return ZMK_EVENT_RAISE(zmk_mouse_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); - uint32_t x = (binding->param1 & 0xFFFF0000) >> 16; - uint32_t y = binding->param1 & 0x0000FFFF; - zmk_hid_mouse_movement_release(x, y); - return zmk_endpoints_send_mouse_report(); + return ZMK_EVENT_RAISE(zmk_mouse_state_changed_from_encoded(binding->param1, false, + event.timestamp); } static const struct behavior_driver_api behavior_mouse_move_driver_api = { diff --git a/app/src/events/mouse_state_changed.c b/app/src/events/mouse_state_changed.c new file mode 100644 index 00000000..0d46ccf3 --- /dev/null +++ b/app/src/events/mouse_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_state_changed); diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index e3c91215..c32b95d9 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -85,6 +85,28 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed return zmk_endpoints_send_report(ev->usage_page); } +static int hid_listener_mouse_pressed(const struct zmk_mouse_state_changed *ev) { + int err; + LOG_DBG("x: 0x%02X, y: 0x%02X", ev->x, ev->y); + err = zmk_hid_mouse_movement_press(ev->x, ev->y); + if (err) { + LOG_ERR("Unable press button"); + return err; + } + return zmk_endpoints_send_mouse_report(); +} + +static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) { + int err; + LOG_DBG("x: 0x%02X, y: 0x%02X", ev->x, ev->y); + err = zmk_hid_mouse_movement_release(ev->x, ev->y); + if (err) { + LOG_ERR("Unable to release button"); + return err; + } + return zmk_endpoints_send_mouse_report(); +} + int hid_listener(const zmk_event_t *eh) { const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); if (ev) { @@ -93,9 +115,19 @@ int hid_listener(const zmk_event_t *eh) { } else { hid_listener_keycode_released(ev); } + } else { + const struct zmk_mouse_state_changed *ev = as_zmk_mouse_state_changed(eh); + if (ev) { + if (ev->state) { + hid_listener_mouse_pressed(ev); + } else { + hid_listener_mouse_released(ev); + } + } } return 0; } ZMK_LISTENER(hid_listener, hid_listener); -ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed); \ No newline at end of file +ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed); +ZMK_SUBSCRIPTION(hid_listener, zmk_mouse_state_changed); From 3eebe8657b8f53bf15f6a14624674da895c7026c Mon Sep 17 00:00:00 2001 From: Dmitry Tsykunov <> Date: Thu, 29 Apr 2021 18:11:28 +0300 Subject: [PATCH 06/35] Continuous mouse movement prototype --- app/include/zmk/events/mouse_state_changed.h | 7 +++---- app/src/behaviors/behavior_mouse_move.c | 13 ++++++------ app/src/hid_listener.c | 22 +++++++++++++++++++- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/app/include/zmk/events/mouse_state_changed.h b/app/include/zmk/events/mouse_state_changed.h index 10d4a02f..46eb06b8 100644 --- a/app/include/zmk/events/mouse_state_changed.h +++ b/app/include/zmk/events/mouse_state_changed.h @@ -10,6 +10,7 @@ #include #include + struct zmk_mouse_state_changed { uint32_t x; uint32_t y; @@ -23,10 +24,8 @@ static inline struct zmk_mouse_state_changed_event * zmk_mouse_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { - uint32_t x = (binding->param1 & 0xFFFF0000) >> 16; - uint32_t y = binding->param1 & 0x0000FFFF; - LOG_DBG("x: 0x%02X y: 0x%02X", x, y); - zmk_hid_mouse_movement_release(x, y); + uint32_t x = (encoded & 0xFFFF0000) >> 16; + uint32_t y = encoded & 0x0000FFFF; return new_zmk_mouse_state_changed((struct zmk_mouse_state_changed){ .x = x, .y = y, .state = pressed, .timestamp = timestamp}); diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c index d1aeb314..33edbd08 100644 --- a/app/src/behaviors/behavior_mouse_move.c +++ b/app/src/behaviors/behavior_mouse_move.c @@ -17,29 +17,30 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -ZMK_EVENT_DECLARE(zmk_mouse_move); - static int behavior_mouse_move_init(const struct device *dev) { return 0; }; + static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - return ZMK_EVENT_RAISE(zmk_mouse_state_changed_from_encoded(binding->param1, true, - event.timestamp); + int res = ZMK_EVENT_RAISE(zmk_mouse_state_changed_from_encoded(binding->param1, true, + event.timestamp)); + return res; } 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_state_changed_from_encoded(binding->param1, false, - event.timestamp); + event.timestamp)); } static const struct behavior_driver_api behavior_mouse_move_driver_api = { .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; #define KP_INST(n) \ - DEVICE_AND_API_INIT(behavior_mouse_move_##n, DT_INST_LABEL(n), behavior_mouse_move_init, NULL, \ + DEVICE_AND_API_INIT(behavior_mouse_move_##n, DT_INST_LABEL(n), behavior_mouse_move_init, NULL, \ NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ &behavior_mouse_move_driver_api); diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index c32b95d9..5cef4281 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -11,6 +11,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#include #include #include #include @@ -85,14 +86,31 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed return zmk_endpoints_send_report(ev->usage_page); } +static int mouse_is_moving_counter = 0; + +void mouse_timer_cb(struct k_timer *dummy); + +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, NULL); + +void mouse_timer_cb(struct k_timer *dummy) +{ + if (mouse_is_moving_counter != 0) { + zmk_endpoints_send_mouse_report(); + k_timer_start(&mouse_timer, K_MSEC(10), K_NO_WAIT); + } +} + static int hid_listener_mouse_pressed(const struct zmk_mouse_state_changed *ev) { int err; LOG_DBG("x: 0x%02X, y: 0x%02X", ev->x, ev->y); err = zmk_hid_mouse_movement_press(ev->x, ev->y); if (err) { - LOG_ERR("Unable press button"); + LOG_ERR("Unable to press button"); return err; } + // race condition? + mouse_is_moving_counter += 1; + k_timer_start(&mouse_timer, K_MSEC(10), K_NO_WAIT); return zmk_endpoints_send_mouse_report(); } @@ -104,6 +122,8 @@ static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) LOG_ERR("Unable to release button"); return err; } + // race condition? + mouse_is_moving_counter -= 1; return zmk_endpoints_send_mouse_report(); } From 5083b312965b7bbd9e541034506e345de2a0f57d Mon Sep 17 00:00:00 2001 From: Dmitry Tsykunov <> Date: Sat, 1 May 2021 09:38:57 +0300 Subject: [PATCH 07/35] Add mouse behaviour documentation --- app/include/dt-bindings/zmk/mouse.h | 5 ++++ docs/docs/behaviors/mouse-move.md | 37 +++++++++++++++++++++++++++++ docs/docs/behaviors/mouse-press.md | 37 +++++++++++++++++++++++++++++ docs/docs/behaviors/mouse-wheel.md | 35 +++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 docs/docs/behaviors/mouse-move.md create mode 100644 docs/docs/behaviors/mouse-press.md create mode 100644 docs/docs/behaviors/mouse-wheel.md diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index bd7b395e..16766ac1 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -5,6 +5,7 @@ */ #pragma once +/* Mouse press behavior */ /* Left click */ #define MB1 (0x01) #define LCLK (MB1) @@ -27,6 +28,8 @@ #define MB8 (0x80) +/* Mouse move behavior */ + #define MOVE_UP (0x0000FFFF) #define MOVE_DOWN (0x00000001) @@ -35,6 +38,8 @@ #define MOVE_RIGHT (0x00010000) +/* Mouse wheel behavior */ + #define WHEEL_UP (0x0001) #define WHEEL_DOWN (0x00FF) diff --git a/docs/docs/behaviors/mouse-move.md b/docs/docs/behaviors/mouse-move.md new file mode 100644 index 00000000..91ef666f --- /dev/null +++ b/docs/docs/behaviors/mouse-move.md @@ -0,0 +1,37 @@ +--- +title: Mouse Move Behavior +sidebar_label: Mouse Move +--- + +## Summary + +Mouse move behavior allows to send keycode signals of mouse movement. + +Please visit view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list of signals. + +## Keycode Defines + +To make it easier to encode the HID keycode numeric values, most keymaps include +the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header +provided by ZMK near the top: + +``` +#include +``` + +Doing so makes a set of defines such as `MOVE_UP`, `MOVE_DOWN`, `MOVE_LEFT` and `MOVE_RIGHT` available for use with these behaviors. + +## Mouse press + +The "mouse move" behavior sends standard keycodes on press/release. + +### Behavior Binding + +- Reference: `&mmv` +- Parameter: The keycode usage ID. + +Example: + +``` +&mmv MOVE_UP +``` diff --git a/docs/docs/behaviors/mouse-press.md b/docs/docs/behaviors/mouse-press.md new file mode 100644 index 00000000..3fad8e5d --- /dev/null +++ b/docs/docs/behaviors/mouse-press.md @@ -0,0 +1,37 @@ +--- +title: Mouse Press Behavior +sidebar_label: Mouse Press +--- + +## Summary + +Mouse press behavior allows to send keycode presses and releases of mouse buttons. + +Please visit view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list. + +## Keycode Defines + +To make it easier to encode the HID keycode numeric values, most keymaps include +the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header +provided by ZMK near the top: + +``` +#include +``` + +Doing so makes a set of defines such as `LCLK`, `RCLK`, etc. available for use with these behaviors + +## Mouse press + +The "mouse press" behavior sends standard keycodes on press/release. + +### Behavior Binding + +- Reference: `&mp` +- Parameter: The keycode usage ID. + +Example: + +``` +&mp LCLK +``` diff --git a/docs/docs/behaviors/mouse-wheel.md b/docs/docs/behaviors/mouse-wheel.md new file mode 100644 index 00000000..5bf21e4c --- /dev/null +++ b/docs/docs/behaviors/mouse-wheel.md @@ -0,0 +1,35 @@ +--- +title: Mouse Wheel Behavior +sidebar_label: Mouse Wheel +--- + +## Summary + +Mouse wheel behavior allows to send keycode signals of mouse wheel scrolling. + +## Keycode Defines + +To make it easier to encode the HID keycode numeric values, most keymaps include +the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header +provided by ZMK near the top: + +``` +#include +``` + +Doing so makes a set of defines such as `WHEEL_UP`, `WHEEL_DOWN`, `WHEEL_LEFT` and `WHEEL_RIGHT` available for use with these behaviors. + +## Mouse wheel + +The "mouse wheel" behavior sends standard keycodes on press/release. + +### Behavior Binding + +- Reference: `&mwh` +- Parameter: The keycode usage ID. + +Example: + +``` +&mwh WHEEL_UP +``` From c36ec0c717cc8616b72c772835d869e1b113af28 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Sun, 2 May 2021 13:30:57 +0300 Subject: [PATCH 08/35] Cleaning out prototype traces --- app/src/endpoints.c | 5 ++--- app/src/hid.c | 2 +- app/src/hid_listener.c | 15 --------------- app/src/hog.c | 10 +--------- 4 files changed, 4 insertions(+), 28 deletions(-) diff --git a/app/src/endpoints.c b/app/src/endpoints.c index ff6d5ad3..3e04186b 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -106,7 +106,7 @@ static int send_consumer_report() { switch (current_endpoint) { #if IS_ENABLED(CONFIG_ZMK_USB) - case ZMK_ENDPOINT_USB: { + case ZMK_ENDPOINT_USB: { int err = zmk_usb_hid_send_report((uint8_t *)consumer_report, sizeof(*consumer_report)); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); @@ -116,7 +116,7 @@ static int send_consumer_report() { #endif /* IS_ENABLED(CONFIG_ZMK_USB) */ #if IS_ENABLED(CONFIG_ZMK_BLE) - case ZMK_ENDPOINT_BLE: { + case ZMK_ENDPOINT_BLE: { int err = zmk_hog_send_consumer_report(&consumer_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); @@ -264,7 +264,6 @@ static void disconnect_current_endpoint() { zmk_endpoints_send_report(HID_USAGE_KEY); zmk_endpoints_send_report(HID_USAGE_CONSUMER); - zmk_endpoints_send_report(HID_USAGE_GD); } static void update_current_endpoint() { diff --git a/app/src/hid.c b/app/src/hid.c index 75e0f45a..9ef57ea0 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -16,7 +16,7 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; static struct zmk_hid_mouse_report mouse_report = {.report_id = 4, .body = { - .buttons = 0, .x = 0, .y = 0, .wheel_hor = 0, .wheel_vert = 0}}; + .buttons = 0, .x = 0, .y = 0, .wheel_vert = 0, .wheel_hor = 0}}; // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 5cef4281..6a0afc38 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -36,13 +36,6 @@ static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed * return err; } break; - case HID_USAGE_GD: - err = zmk_hid_mouse_buttons_press(ev->keycode); - if (err) { - LOG_ERR("Unable to press button"); - return err; - } - break; } zmk_hid_register_mods(ev->explicit_modifiers); zmk_hid_implicit_modifiers_press(ev->implicit_modifiers); @@ -67,14 +60,6 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed LOG_ERR("Unable to release keycode"); return err; } - break; - case HID_USAGE_GD: - err = zmk_hid_mouse_buttons_release(ev->keycode); - if (err) { - LOG_ERR("Unable to release button"); - return err; - } - break; } zmk_hid_unregister_mods(ev->explicit_modifiers); // There is a minor issue with this code. diff --git a/app/src/hog.c b/app/src/hog.c index 2bbf874f..a3208eba 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -187,8 +187,6 @@ K_MSGQ_DEFINE(zmk_hog_keyboard_msgq, sizeof(struct zmk_hid_keyboard_report_body) void send_keyboard_report_callback(struct k_work *work) { struct zmk_hid_keyboard_report_body report; - LOG_ERR("Sending keyboard callback"); - while (k_msgq_get(&zmk_hog_keyboard_msgq, &report, K_NO_WAIT) == 0) { struct bt_conn *conn = destination_connection(); if (conn == NULL) { @@ -214,7 +212,6 @@ K_WORK_DEFINE(hog_keyboard_work, send_keyboard_report_callback); int zmk_hog_send_keyboard_report(struct zmk_hid_keyboard_report_body *report) { int err = k_msgq_put(&zmk_hog_keyboard_msgq, report, K_MSEC(100)); - LOG_ERR("Sending keyboard report"); if (err) { switch (err) { case -EAGAIN: { @@ -285,14 +282,10 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { }; K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body), -CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); - + CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); void send_mouse_report_callback(struct k_work *work) { struct zmk_hid_mouse_report_body report; - - LOG_ERR("Sending mouse callback"); - while (k_msgq_get(&zmk_hog_mouse_msgq, &report, K_NO_WAIT) == 0) { struct bt_conn *conn = destination_connection(); if (conn == NULL) { @@ -318,7 +311,6 @@ 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)); - LOG_ERR("Sending mouse report"); if (err) { switch (err) { case -EAGAIN: { From b27b8e35ec87c92bc71519ece664e8fb4b6f833c Mon Sep 17 00:00:00 2001 From: krikun98 Date: Sun, 2 May 2021 13:52:23 +0300 Subject: [PATCH 09/35] clang-format --- app/include/zmk/events/mouse_state_changed.h | 20 ++- app/include/zmk/hid.h | 155 ++++++++----------- app/src/behaviors/behavior_mouse_key_press.c | 6 +- app/src/behaviors/behavior_mouse_move.c | 9 +- app/src/behaviors/behavior_mouse_wheel.c | 5 +- app/src/endpoints.c | 4 +- app/src/hid.c | 35 ++--- app/src/hid_listener.c | 17 +- app/src/hog.c | 9 +- 9 files changed, 111 insertions(+), 149 deletions(-) diff --git a/app/include/zmk/events/mouse_state_changed.h b/app/include/zmk/events/mouse_state_changed.h index 46eb06b8..0264ea4a 100644 --- a/app/include/zmk/events/mouse_state_changed.h +++ b/app/include/zmk/events/mouse_state_changed.h @@ -10,23 +10,21 @@ #include #include - struct zmk_mouse_state_changed { - uint32_t x; - uint32_t y; - bool state; - int64_t timestamp; + uint32_t x; + uint32_t y; + bool state; + int64_t timestamp; }; ZMK_EVENT_DECLARE(zmk_mouse_state_changed); static inline struct zmk_mouse_state_changed_event * -zmk_mouse_state_changed_from_encoded(uint32_t encoded, bool pressed, - int64_t timestamp) { +zmk_mouse_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { - uint32_t x = (encoded & 0xFFFF0000) >> 16; - uint32_t y = encoded & 0x0000FFFF; + uint32_t x = (encoded & 0xFFFF0000) >> 16; + uint32_t y = encoded & 0x0000FFFF; - return new_zmk_mouse_state_changed((struct zmk_mouse_state_changed){ - .x = x, .y = y, .state = pressed, .timestamp = timestamp}); + return new_zmk_mouse_state_changed( + (struct zmk_mouse_state_changed){.x = x, .y = y, .state = pressed, .timestamp = timestamp}); } diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index ec0cb626..fb9705a1 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -20,55 +20,39 @@ static const uint8_t zmk_hid_report_desc[] = { /* USAGE_PAGE (Generic Desktop) */ - HID_GI_USAGE_PAGE, - HID_USAGE_GD, + HID_GI_USAGE_PAGE, HID_USAGE_GD, /* USAGE (Keyboard) */ - HID_LI_USAGE, - HID_USAGE_GD_KEYBOARD, + HID_LI_USAGE, HID_USAGE_GD_KEYBOARD, /* COLLECTION (Application) */ - HID_MI_COLLECTION, - COLLECTION_APPLICATION, + HID_MI_COLLECTION, COLLECTION_APPLICATION, /* REPORT ID (1) */ - HID_GI_REPORT_ID, - 0x01, + HID_GI_REPORT_ID, 0x01, /* USAGE_PAGE (Keyboard/Keypad) */ - HID_GI_USAGE_PAGE, - HID_USAGE_KEY, + HID_GI_USAGE_PAGE, HID_USAGE_KEY, /* USAGE_MINIMUM (Keyboard LeftControl) */ - HID_LI_USAGE_MIN(1), - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL, + HID_LI_USAGE_MIN(1), HID_USAGE_KEY_KEYBOARD_LEFTCONTROL, /* USAGE_MAXIMUM (Keyboard Right GUI) */ - HID_LI_USAGE_MAX(1), - HID_USAGE_KEY_KEYBOARD_RIGHT_GUI, + HID_LI_USAGE_MAX(1), HID_USAGE_KEY_KEYBOARD_RIGHT_GUI, /* LOGICAL_MINIMUM (0) */ - HID_GI_LOGICAL_MIN(1), - 0x00, + HID_GI_LOGICAL_MIN(1), 0x00, /* LOGICAL_MAXIMUM (1) */ - HID_GI_LOGICAL_MAX(1), - 0x01, + HID_GI_LOGICAL_MAX(1), 0x01, /* REPORT_SIZE (1) */ - HID_GI_REPORT_SIZE, - 0x01, + HID_GI_REPORT_SIZE, 0x01, /* REPORT_COUNT (8) */ - HID_GI_REPORT_COUNT, - 0x08, + HID_GI_REPORT_COUNT, 0x08, /* INPUT (Data,Var,Abs) */ - HID_MI_INPUT, - 0x02, + HID_MI_INPUT, 0x02, /* USAGE_PAGE (Keyboard/Keypad) */ - HID_GI_USAGE_PAGE, - HID_USAGE_KEY, + HID_GI_USAGE_PAGE, HID_USAGE_KEY, /* REPORT_SIZE (8) */ - HID_GI_REPORT_SIZE, - 0x08, + HID_GI_REPORT_SIZE, 0x08, /* REPORT_COUNT (1) */ - HID_GI_REPORT_COUNT, - 0x01, + HID_GI_REPORT_COUNT, 0x01, /* INPUT (Cnst,Var,Abs) */ - HID_MI_INPUT, - 0x03, + HID_MI_INPUT, 0x03, /* USAGE_PAGE (Keyboard/Keypad) */ HID_GI_USAGE_PAGE, @@ -98,17 +82,13 @@ static const uint8_t zmk_hid_report_desc[] = { 0x02, #elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) /* LOGICAL_MINIMUM (0) */ - HID_GI_LOGICAL_MIN(1), - 0x00, + HID_GI_LOGICAL_MIN(1), 0x00, /* LOGICAL_MAXIMUM (0xFF) */ - HID_GI_LOGICAL_MAX(1), - 0xFF, + HID_GI_LOGICAL_MAX(1), 0xFF, /* USAGE_MINIMUM (Reserved) */ - HID_LI_USAGE_MIN(1), - 0x00, + HID_LI_USAGE_MIN(1), 0x00, /* USAGE_MAXIMUM (Keyboard Application) */ - HID_LI_USAGE_MAX(1), - 0xFF, + HID_LI_USAGE_MAX(1), 0xFF, /* REPORT_SIZE (1) */ HID_GI_REPORT_SIZE, 0x08, @@ -125,17 +105,13 @@ static const uint8_t zmk_hid_report_desc[] = { /* END_COLLECTION */ HID_MI_COLLECTION_END, /* USAGE_PAGE (Consumer) */ - HID_GI_USAGE_PAGE, - HID_USAGE_CONSUMER, + HID_GI_USAGE_PAGE, HID_USAGE_CONSUMER, /* USAGE (Consumer Control) */ - HID_LI_USAGE, - HID_USAGE_CONSUMER_CONSUMER_CONTROL, + HID_LI_USAGE, HID_USAGE_CONSUMER_CONSUMER_CONTROL, /* Consumer Page */ - HID_MI_COLLECTION, - COLLECTION_APPLICATION, + HID_MI_COLLECTION, COLLECTION_APPLICATION, /* REPORT ID (1) */ - HID_GI_REPORT_ID, - 0x02, + HID_GI_REPORT_ID, 0x02, /* USAGE_PAGE (Consumer) */ HID_GI_USAGE_PAGE, HID_USAGE_CONSUMER, @@ -158,18 +134,11 @@ static const uint8_t zmk_hid_report_desc[] = { 0x08, #elif IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_FULL) /* LOGICAL_MINIMUM (0) */ - HID_GI_LOGICAL_MIN(1), - 0x00, + HID_GI_LOGICAL_MIN(1), 0x00, /* LOGICAL_MAXIMUM (0xFFFF) */ - HID_GI_LOGICAL_MAX(2), - 0xFF, - 0xFF, - HID_LI_USAGE_MIN(1), - 0x00, + HID_GI_LOGICAL_MAX(2), 0xFF, 0xFF, HID_LI_USAGE_MIN(1), 0x00, /* USAGE_MAXIMUM (0xFFFF) */ - HID_LI_USAGE_MAX(2), - 0xFF, - 0xFF, + HID_LI_USAGE_MAX(2), 0xFF, 0xFF, /* INPUT (Data,Ary,Abs) */ /* REPORT_SIZE (16) */ HID_GI_REPORT_SIZE, @@ -185,42 +154,42 @@ static const uint8_t zmk_hid_report_desc[] = { /* END COLLECTION */ HID_MI_COLLECTION_END, - 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ - 0x09, 0x02, /* Usage (Mouse) */ - 0xA1, 0x01, /* Collection (Application) */ - 0x85, 0x04, /* Report ID (4) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xA1, 0x00, /* Collection (Physical) */ - 0x05, 0x09, /* Usage Page (Button) */ - 0x19, 0x01, /* Usage Minimum (0x01) */ - 0x29, 0x10, /* Usage Maximum (0x10) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x95, 0x10, /* Report Count (16) */ - 0x75, 0x01, /* Report Size (1) */ - 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */ - 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ - 0x16, 0x01, 0x80, /* Logical Minimum (-32767) */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */ - 0x75, 0x10, /* Report Size (8) */ - 0x95, 0x02, /* Report Count (2) */ - 0x09, 0x30, /* Usage (X) */ - 0x09, 0x31, /* Usage (Y) */ - 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ - 0x15, 0x81, /* Logical Minimum (-127) */ - 0x25, 0x7F, /* Logical Maximum (127) */ - 0x75, 0x08, /* Report Count (8) */ - 0x95, 0x01, /* Report Size (1) */ - 0x09, 0x38, /* Usage (Wheel) */ - 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x09, 0x02, /* Usage (Mouse) */ + 0xA1, 0x01, /* Collection (Application) */ + 0x85, 0x04, /* Report ID (4) */ + 0x09, 0x01, /* Usage (Pointer) */ + 0xA1, 0x00, /* Collection (Physical) */ + 0x05, 0x09, /* Usage Page (Button) */ + 0x19, 0x01, /* Usage Minimum (0x01) */ + 0x29, 0x10, /* Usage Maximum (0x10) */ + 0x15, 0x00, /* Logical Minimum (0) */ + 0x25, 0x01, /* Logical Maximum (1) */ + 0x95, 0x10, /* Report Count (16) */ + 0x75, 0x01, /* Report Size (1) */ + 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */ + 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ + 0x16, 0x01, 0x80, /* Logical Minimum (-32767) */ + 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */ + 0x75, 0x10, /* Report Size (8) */ + 0x95, 0x02, /* Report Count (2) */ + 0x09, 0x30, /* Usage (X) */ + 0x09, 0x31, /* Usage (Y) */ + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7F, /* Logical Maximum (127) */ + 0x75, 0x08, /* Report Count (8) */ + 0x95, 0x01, /* Report Size (1) */ + 0x09, 0x38, /* Usage (Wheel) */ + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ 0x05, 0x0C, /* Usage Page (Consumer) */ // Horizontal wheel - 0x0A, 0x38, 0x02, /* Usage (AC Pan) */ - 0x15, 0x81, /* Logical Minimum (-127) */ - 0x25, 0x7f, /* Logical Maximum (127) */ - 0x95, 0x01, /* Report Count (1) */ - 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ - 0xC0, /* End Collection */ - 0xC0, /* End Collection */ + 0x0A, 0x38, 0x02, /* Usage (AC Pan) */ + 0x15, 0x81, /* Logical Minimum (-127) */ + 0x25, 0x7f, /* Logical Maximum (127) */ + 0x95, 0x01, /* Report Count (1) */ + 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ + 0xC0, /* End Collection */ + 0xC0, /* End Collection */ }; // struct zmk_hid_boot_report diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c index 43754f6e..3dc5ce79 100644 --- a/app/src/behaviors/behavior_mouse_key_press.c +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -38,8 +38,8 @@ 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 KP_INST(n) \ - DEVICE_AND_API_INIT(behavior_mouse_key_press_##n, DT_INST_LABEL(n), behavior_mouse_key_press_init, NULL, \ - NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_mouse_key_press_driver_api); + DEVICE_AND_API_INIT( \ + behavior_mouse_key_press_##n, DT_INST_LABEL(n), behavior_mouse_key_press_init, NULL, NULL, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_key_press_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c index 33edbd08..cc51129d 100644 --- a/app/src/behaviors/behavior_mouse_move.c +++ b/app/src/behaviors/behavior_mouse_move.c @@ -19,12 +19,11 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_mouse_move_init(const struct device *dev) { return 0; }; - static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - int res = ZMK_EVENT_RAISE(zmk_mouse_state_changed_from_encoded(binding->param1, true, - event.timestamp)); + int res = ZMK_EVENT_RAISE( + zmk_mouse_state_changed_from_encoded(binding->param1, true, event.timestamp)); return res; } @@ -32,8 +31,8 @@ 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_state_changed_from_encoded(binding->param1, false, - event.timestamp)); + return ZMK_EVENT_RAISE( + zmk_mouse_state_changed_from_encoded(binding->param1, false, event.timestamp)); } static const struct behavior_driver_api behavior_mouse_move_driver_api = { diff --git a/app/src/behaviors/behavior_mouse_wheel.c b/app/src/behaviors/behavior_mouse_wheel.c index 4f99876f..1794a5c4 100644 --- a/app/src/behaviors/behavior_mouse_wheel.c +++ b/app/src/behaviors/behavior_mouse_wheel.c @@ -41,10 +41,9 @@ static int on_keymap_binding_released(struct zmk_behavior_binding *binding, static const struct behavior_driver_api behavior_mouse_wheel_driver_api = { .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; - #define KP_INST(n) \ - DEVICE_AND_API_INIT(behavior_mouse_wheel_##n, DT_INST_LABEL(n), behavior_mouse_wheel_init, NULL, \ - NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + DEVICE_AND_API_INIT(behavior_mouse_wheel_##n, DT_INST_LABEL(n), behavior_mouse_wheel_init, \ + NULL, NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ &behavior_mouse_wheel_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 3e04186b..59d9f74e 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -151,7 +151,7 @@ int zmk_endpoints_send_mouse_report() { switch (current_endpoint) { #if IS_ENABLED(CONFIG_ZMK_USB) - case ZMK_ENDPOINT_USB: { + case ZMK_ENDPOINT_USB: { int err = zmk_usb_hid_send_report((uint8_t *)mouse_report, sizeof(*mouse_report)); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); @@ -161,7 +161,7 @@ int zmk_endpoints_send_mouse_report() { #endif /* IS_ENABLED(CONFIG_ZMK_USB) */ #if IS_ENABLED(CONFIG_ZMK_BLE) - case ZMK_ENDPOINT_BLE: { + case ZMK_ENDPOINT_BLE: { int err = zmk_hog_send_mouse_report(&mouse_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); diff --git a/app/src/hid.c b/app/src/hid.c index 9ef57ea0..55b39b74 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -15,8 +15,8 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; -static struct zmk_hid_mouse_report mouse_report = {.report_id = 4, .body = { - .buttons = 0, .x = 0, .y = 0, .wheel_vert = 0, .wheel_hor = 0}}; +static struct zmk_hid_mouse_report mouse_report = { + .report_id = 4, .body = {.buttons = 0, .x = 0, .y = 0, .wheel_vert = 0, .wheel_hor = 0}}; // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. @@ -172,7 +172,6 @@ int zmk_hid_consumer_release(zmk_key_t code) { void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer_report.body)); } - // Keep track of how often a button was pressed. // Only release the button if the count is 0. static int explicit_button_counts[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -182,10 +181,10 @@ static int16_t curr_y = 0; static int8_t curr_hor = 0; static int8_t curr_vert = 0; -#define SET_MOUSE_BUTTONS(butts) \ - { \ - mouse_report.body.buttons = butts; \ - LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \ +#define SET_MOUSE_BUTTONS(butts) \ + { \ + mouse_report.body.buttons = butts; \ + LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \ } int zmk_hid_mouse_button_press(zmk_mouse_button_t button) { @@ -229,12 +228,12 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { return 0; } -#define SET_MOUSE_MOVEMENT(coor_x, coor_y) \ - { \ - mouse_report.body.x = coor_x; \ - LOG_DBG("Mouse movement x set to 0x%02X", mouse_report.body.x); \ - mouse_report.body.y = coor_y; \ - LOG_DBG("Mouse movement y set to 0x%02X", mouse_report.body.y); \ +#define SET_MOUSE_MOVEMENT(coor_x, coor_y) \ + { \ + mouse_report.body.x = coor_x; \ + LOG_DBG("Mouse movement x set to 0x%02X", mouse_report.body.x); \ + mouse_report.body.y = coor_y; \ + LOG_DBG("Mouse movement y set to 0x%02X", mouse_report.body.y); \ } int zmk_hid_mouse_movement_press(uint16_t x, uint16_t y) { @@ -251,12 +250,12 @@ int zmk_hid_mouse_movement_release(uint16_t x, uint16_t y) { return 0; } -#define SET_MOUSE_WHEEL(horiz, vertic) \ - { \ - mouse_report.body.wheel_hor = horiz; \ - LOG_DBG("Mouse wheel hor set to 0x%02X", mouse_report.body.wheel_hor); \ +#define SET_MOUSE_WHEEL(horiz, vertic) \ + { \ + mouse_report.body.wheel_hor = horiz; \ + LOG_DBG("Mouse wheel hor set to 0x%02X", mouse_report.body.wheel_hor); \ mouse_report.body.wheel_vert = vertic; \ - LOG_DBG("Mouse wheel vert set to 0x%02X", mouse_report.body.wheel_vert); \ + LOG_DBG("Mouse wheel vert set to 0x%02X", mouse_report.body.wheel_vert); \ } int zmk_hid_mouse_wheel_press(uint8_t hor, uint8_t vert) { diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 6a0afc38..755d1860 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -77,8 +77,7 @@ void mouse_timer_cb(struct k_timer *dummy); K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, NULL); -void mouse_timer_cb(struct k_timer *dummy) -{ +void mouse_timer_cb(struct k_timer *dummy) { if (mouse_is_moving_counter != 0) { zmk_endpoints_send_mouse_report(); k_timer_start(&mouse_timer, K_MSEC(10), K_NO_WAIT); @@ -121,14 +120,14 @@ int hid_listener(const zmk_event_t *eh) { hid_listener_keycode_released(ev); } } else { - const struct zmk_mouse_state_changed *ev = as_zmk_mouse_state_changed(eh); - if (ev) { - if (ev->state) { - hid_listener_mouse_pressed(ev); - } else { - hid_listener_mouse_released(ev); + const struct zmk_mouse_state_changed *ev = as_zmk_mouse_state_changed(eh); + if (ev) { + if (ev->state) { + hid_listener_mouse_pressed(ev); + } else { + hid_listener_mouse_released(ev); + } } - } } return 0; } diff --git a/app/src/hog.c b/app/src/hog.c index a3208eba..6b71c98f 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -98,9 +98,8 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, sizeof(struct zmk_hid_consumer_report_body)); } -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) { +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)); @@ -154,7 +153,7 @@ BT_GATT_SERVICE_DEFINE( NULL, &consumer_input), 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_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), @@ -282,7 +281,7 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { }; K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body), - CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); + CONFIG_ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE, 4); void send_mouse_report_callback(struct k_work *work) { struct zmk_hid_mouse_report_body report; From 2d2a8bd60d64f133537ad319d68785a4434a254a Mon Sep 17 00:00:00 2001 From: Dmitry Tsykunov <73191463+dtsykunov@users.noreply.github.com> Date: Sun, 2 May 2021 16:18:41 +0300 Subject: [PATCH 10/35] Implemented Rinh's suggestion to remove deadlocks --- app/src/hid_listener.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 755d1860..921d68e7 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -71,16 +71,32 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed return zmk_endpoints_send_report(ev->usage_page); } -static int mouse_is_moving_counter = 0; +static void zmk_mouse_work(struct k_work *work) { + int rc = zmk_endpoints_send_mouse_report(); + if (rc != 0) { + LOG_ERR("Failed to send mouse report, error: %d", rc); + } +} -void mouse_timer_cb(struct k_timer *dummy); +K_WORK_DEFINE(mouse_work, &zmk_mouse_work); -K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, NULL); +void mouse_timer_cb(struct k_timer *dummy) { k_work_submit(&mouse_work); } -void mouse_timer_cb(struct k_timer *dummy) { - if (mouse_is_moving_counter != 0) { - zmk_endpoints_send_mouse_report(); - k_timer_start(&mouse_timer, K_MSEC(10), K_NO_WAIT); +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_timer_cb); + +static int mouse_timer_ref_count = 0; + +void mouse_timer_ref() { + if (mouse_timer_ref_count == 0) { + k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(10)); + } + mouse_timer_ref_count += 1; +} + +void mouse_timer_unref() { + mouse_timer_ref_count -= 1; + if (mouse_timer_ref_count == 0) { + k_timer_stop(&mouse_timer); } } @@ -92,10 +108,8 @@ static int hid_listener_mouse_pressed(const struct zmk_mouse_state_changed *ev) LOG_ERR("Unable to press button"); return err; } - // race condition? - mouse_is_moving_counter += 1; - k_timer_start(&mouse_timer, K_MSEC(10), K_NO_WAIT); - return zmk_endpoints_send_mouse_report(); + mouse_timer_ref(); + return 0; } static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) { @@ -106,9 +120,8 @@ static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) LOG_ERR("Unable to release button"); return err; } - // race condition? - mouse_is_moving_counter -= 1; - return zmk_endpoints_send_mouse_report(); + mouse_timer_unref(); + return 0; } int hid_listener(const zmk_event_t *eh) { From c76935d90aca8aadde15346b8c488dfe7d3374fd Mon Sep 17 00:00:00 2001 From: krikun98 Date: Sun, 2 May 2021 16:47:30 +0300 Subject: [PATCH 11/35] Raised BLE mouse report queue size --- app/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Kconfig b/app/Kconfig index 60423891..44259149 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -126,7 +126,7 @@ config ZMK_BLE_CONSUMER_REPORT_QUEUE_SIZE config ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE int "Max number of mouse HID reports to queue for sending over BLE" - default 5 + default 20 config ZMK_BLE_CLEAR_BONDS_ON_START bool "Configuration that clears all bond information from the keyboard on startup." From fbd6110cd96d68672e005b1a7c7b3b59b3280c56 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Sun, 2 May 2021 17:08:12 +0300 Subject: [PATCH 12/35] Documentation refactor --- docs/docs/behaviors/mouse-emulation.md | 69 ++++++++++++++++++++++++++ docs/docs/behaviors/mouse-move.md | 37 -------------- docs/docs/behaviors/mouse-press.md | 37 -------------- docs/docs/behaviors/mouse-wheel.md | 35 ------------- 4 files changed, 69 insertions(+), 109 deletions(-) create mode 100644 docs/docs/behaviors/mouse-emulation.md delete mode 100644 docs/docs/behaviors/mouse-move.md delete mode 100644 docs/docs/behaviors/mouse-press.md delete mode 100644 docs/docs/behaviors/mouse-wheel.md diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md new file mode 100644 index 00000000..e3b74048 --- /dev/null +++ b/docs/docs/behaviors/mouse-emulation.md @@ -0,0 +1,69 @@ +--- +title: Mouse Emulation Behaviors +sidebar_label: Mouse Emulation +--- + +## Summary + +Mouse emulation behaviors send mouse movements, button presses or wheel actions. + +Please view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list of signals. + +## Keycode Defines + +To make it easier to encode the HID keycode numeric values, most keymaps include +the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header +provided by ZMK near the top: + +``` +#include +``` + +Doing so allows using a set of defines such as `MOVE_UP`, `MOVE_DOWN`, `LCLK` and `WHEEL_UP` with these behaviors. + +## Mouse Button Press + +This behavior can press/release up to 16 mouse buttons. + +### Behavior Binding + +- Reference: `&mkp` +- Parameter: A `uint16` with each bit referring to a button. + +Example: + +``` +&mkp LCLK +``` + +## Mouse Movement + +This behavior is used to manipulate the cursor. + +### Behavior Binding + +- Reference: `&mmv` +- Parameter: A `uint32` with the first 16 bits relating to horizontal movement + and the last 16 - to vertical movement. + +Example: + +``` +&mmv MOVE_UP +``` + +## Mouse Wheel + +This behaviour is used to scroll, both horizontally and vertically. + +### Behavior Binding + +- Reference: `&mwh` +- Parameter: A `uint16` with the first 8 bits relating to horizontal movement + and the last 8 - to vertical movement. + +Example: + +``` +&mwh WHEEL_UP +``` diff --git a/docs/docs/behaviors/mouse-move.md b/docs/docs/behaviors/mouse-move.md deleted file mode 100644 index 91ef666f..00000000 --- a/docs/docs/behaviors/mouse-move.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Mouse Move Behavior -sidebar_label: Mouse Move ---- - -## Summary - -Mouse move behavior allows to send keycode signals of mouse movement. - -Please visit view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list of signals. - -## Keycode Defines - -To make it easier to encode the HID keycode numeric values, most keymaps include -the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header -provided by ZMK near the top: - -``` -#include -``` - -Doing so makes a set of defines such as `MOVE_UP`, `MOVE_DOWN`, `MOVE_LEFT` and `MOVE_RIGHT` available for use with these behaviors. - -## Mouse press - -The "mouse move" behavior sends standard keycodes on press/release. - -### Behavior Binding - -- Reference: `&mmv` -- Parameter: The keycode usage ID. - -Example: - -``` -&mmv MOVE_UP -``` diff --git a/docs/docs/behaviors/mouse-press.md b/docs/docs/behaviors/mouse-press.md deleted file mode 100644 index 3fad8e5d..00000000 --- a/docs/docs/behaviors/mouse-press.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Mouse Press Behavior -sidebar_label: Mouse Press ---- - -## Summary - -Mouse press behavior allows to send keycode presses and releases of mouse buttons. - -Please visit view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list. - -## Keycode Defines - -To make it easier to encode the HID keycode numeric values, most keymaps include -the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header -provided by ZMK near the top: - -``` -#include -``` - -Doing so makes a set of defines such as `LCLK`, `RCLK`, etc. available for use with these behaviors - -## Mouse press - -The "mouse press" behavior sends standard keycodes on press/release. - -### Behavior Binding - -- Reference: `&mp` -- Parameter: The keycode usage ID. - -Example: - -``` -&mp LCLK -``` diff --git a/docs/docs/behaviors/mouse-wheel.md b/docs/docs/behaviors/mouse-wheel.md deleted file mode 100644 index 5bf21e4c..00000000 --- a/docs/docs/behaviors/mouse-wheel.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Mouse Wheel Behavior -sidebar_label: Mouse Wheel ---- - -## Summary - -Mouse wheel behavior allows to send keycode signals of mouse wheel scrolling. - -## Keycode Defines - -To make it easier to encode the HID keycode numeric values, most keymaps include -the [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) header -provided by ZMK near the top: - -``` -#include -``` - -Doing so makes a set of defines such as `WHEEL_UP`, `WHEEL_DOWN`, `WHEEL_LEFT` and `WHEEL_RIGHT` available for use with these behaviors. - -## Mouse wheel - -The "mouse wheel" behavior sends standard keycodes on press/release. - -### Behavior Binding - -- Reference: `&mwh` -- Parameter: The keycode usage ID. - -Example: - -``` -&mwh WHEEL_UP -``` From 848f32c957fc74fcb551a466750509b56da9983a Mon Sep 17 00:00:00 2001 From: krikun98 Date: Sun, 2 May 2021 18:36:09 +0300 Subject: [PATCH 13/35] Add the doc page to the sidebar --- docs/docs/intro.md | 52 +++++++++++++++++++++++----------------------- docs/sidebars.js | 1 + 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 39a52c6c..e1983c93 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -14,32 +14,32 @@ ZMK is currently missing some features found in other popular firmware. This tab | Legend: | ✅ Supported | 🚧 Under Development | 💡 Planned | | :------ | :----------- | :------------------- | :--------- | -| **Feature** | ZMK | BlueMicro | QMK | -| ---------------------------------------------------------------------------------------------------------------------------------- | :-: | :-------: | :-: | -| Low Latency BLE Support | ✅ | ✅ | | -| Multi-Device BLE Support | ✅ | | | -| [USB Connectivity](behaviors/outputs.md) | ✅ | ✅ | ✅ | -| User Configuration Repositories | ✅ | | | -| Split Keyboard Support | ✅ | ✅ | ✅ | -| [Keymaps and Layers](behaviors/layers.md) | ✅ | ✅ | ✅ | -| [Hold-Tap](behaviors/hold-tap.md) (which includes [Mod-Tap](behaviors/mod-tap.md) and [Layer-Tap](behaviors/layers.md/#layer-tap)) | ✅ | ✅ | ✅ | -| [Keyboard Codes](codes/index.mdx#keyboard) | ✅ | ✅ | ✅ | -| [Media](codes/index.mdx#media-controls) & [Consumer](codes/index.mdx#consumer-controls) Codes | ✅ | ✅ | ✅ | -| [Encoders](features/encoders.md)[^1] | ✅ | ✅ | ✅ | -| [Display Support](features/displays.md)[^2] | 🚧 | 🚧 | ✅ | -| [RGB Underglow](features/underglow.md) | ✅ | ✅ | ✅ | -| One Shot Keys | ✅ | ✅ | ✅ | -| [Combo Keys](features/combos.md) | ✅ | | ✅ | -| Macros | 🚧 | ✅ | ✅ | -| Mouse Keys | 🚧 | ✅ | ✅ | -| Low Active Power Usage | ✅ | | | -| Low Power Sleep States | ✅ | ✅ | | -| [Low Power Mode (VCC Shutoff)](behaviors/power.md) | ✅ | ✅ | | -| Battery Reporting | ✅ | ✅ | | -| Shell over BLE | 💡 | | | -| Realtime Keymap Updating | 💡 | | ✅ | -| AVR/8 Bit | | | ✅ | -| [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | +| **Feature** | ZMK | BlueMicro | QMK | +| ------------------------------------------------------------------------------------------------------------------------- | :-: | :-------: | :-: | +| Low Latency BLE Support | ✅ | ✅ | | +| Multi-Device BLE Support | ✅ | | | +| [USB Connectivity](behaviors/outputs) | ✅ | ✅ | ✅ | +| User Configuration Repositories | ✅ | | | +| Split Keyboard Support | ✅ | ✅ | ✅ | +| [Keymaps and Layers](behaviors/layers) | ✅ | ✅ | ✅ | +| [Hold-Tap](behaviors/hold-tap) (which includes [Mod-Tap](behaviors/mod-tap) and [Layer-Tap](behaviors/layers/#layer-tap)) | ✅ | ✅ | ✅ | +| [Keyboard Codes](codes/#keyboard) | ✅ | ✅ | ✅ | +| [Media](codes/#media-controls) & [Consumer](codes/#consumer-controls) Codes | ✅ | ✅ | ✅ | +| [Encoders](features/encoders)[^1] | ✅ | ✅ | ✅ | +| [Display Support](features/displays)[^2] | 🚧 | 🚧 | ✅ | +| [RGB Underglow](features/underglow) | ✅ | ✅ | ✅ | +| One Shot Keys | ✅ | ✅ | ✅ | +| [Combo Keys](features/combos) | ✅ | | ✅ | +| Macros | 🚧 | ✅ | ✅ | +| Mouse Keys | ✅ | ✅ | ✅ | +| Low Active Power Usage | ✅ | | | +| Low Power Sleep States | ✅ | ✅ | | +| [Low Power Mode (VCC Shutoff)](behaviors/power) | ✅ | ✅ | | +| Battery Reporting | ✅ | ✅ | | +| Shell over BLE | 💡 | | | +| Realtime Keymap Updating | 💡 | | ✅ | +| AVR/8 Bit | | | ✅ | +| [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | [^2]: Encoders are not currently supported on peripheral side splits. [^1]: OLEDs are currently proof of concept in ZMK. diff --git a/docs/sidebars.js b/docs/sidebars.js index 2a406589..545df5b3 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -26,6 +26,7 @@ module.exports = { "behaviors/mod-morph", "behaviors/sticky-key", "behaviors/sticky-layer", + "behaviors/mouse-emulation", "behaviors/reset", "behaviors/bluetooth", "behaviors/outputs", From a29ee0033a3723643e3723d88c28155c664ed921 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Mon, 3 May 2021 09:54:35 +0300 Subject: [PATCH 14/35] Added new mouse movement macros --- app/include/dt-bindings/zmk/mouse.h | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 16766ac1..007fe128 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -28,6 +28,22 @@ #define MB8 (0x80) +#define MB9 (0x0100) + +#define MB10 (0x0200) + +#define MB11 (0x0400) + +#define MB12 (0x0800) + +#define MB13 (0x1000) + +#define MB14 (0x2000) + +#define MB15 (0x4000) + +#define MB16 (0x8000) + /* Mouse move behavior */ #define MOVE_UP (0x0000FFFF) @@ -38,6 +54,13 @@ #define MOVE_RIGHT (0x00010000) +/* -32767 to 32767, barely usable beyond about 50 (probably depends on screen resolution) */ +#define MOVE_VERT(vert) ((vert) < 0 ? -(vert) : (1 << 16) - (vert)) + +#define MOVE_HOR(hor) (((hor) > 0 ? (hor) : (1 << 16) + (hor)) << 16) + +#define MOVE(hor, vert) (MOVE_HOR(hor) + MOVE_VERT(vert)) + /* Mouse wheel behavior */ #define WHEEL_UP (0x0001) @@ -47,3 +70,10 @@ #define WHEEL_LEFT (0xFF00) #define WHEEL_RIGHT (0x0100) + +/* -127 to 127, barely usable beyond about 10 */ +#define WHEEL_VERT(vert) ((vert) < 0 ? (1 << 8) + (vert) : vert) + +#define WHEEL_HOR(hor) (((hor) < 0 ? (1 << 8) + (hor) : hor) << 8) + +#define WHEEL(hor, vert) (WHEEL_HOR(hor) + WHEEL_VERT(vert)) From 33518ef5c9cf4c6c5b2708017d70d6e12e4cdf9a Mon Sep 17 00:00:00 2001 From: krikun98 Date: Mon, 3 May 2021 11:13:33 +0300 Subject: [PATCH 15/35] Review edits: macro, event override fix, cosmetics --- app/include/zmk/mouse.h | 2 +- app/src/behaviors/behavior_mouse_wheel.c | 11 ++++++---- app/src/hid.c | 4 ++-- app/src/hid_listener.c | 27 ++++++++++++------------ 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index 32d3d03e..e749ac5d 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -10,4 +10,4 @@ #include typedef uint16_t zmk_mouse_button_flags_t; -typedef uint16_t zmk_mouse_button_t; \ No newline at end of file +typedef uint16_t zmk_mouse_button_t; diff --git a/app/src/behaviors/behavior_mouse_wheel.c b/app/src/behaviors/behavior_mouse_wheel.c index 1794a5c4..bd2cd29b 100644 --- a/app/src/behaviors/behavior_mouse_wheel.c +++ b/app/src/behaviors/behavior_mouse_wheel.c @@ -18,13 +18,16 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#define WHEEL_HORIZONTAL(encoded) (((encoded)&0xFF00) >> 8) +#define WHEEL_VERTICAL(encoded) ((encoded)&0x00FF) + static int behavior_mouse_wheel_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); - int32_t x = (binding->param1 & 0xFF00) >> 8; - int32_t y = binding->param1 & 0x00FF; + int32_t x = WHEEL_HORIZONTAL(binding->param1); + int32_t y = WHEEL_VERTICAL(binding->param1); zmk_hid_mouse_wheel_press(x, y); return zmk_endpoints_send_mouse_report(); } @@ -32,8 +35,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, 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); - int32_t x = (binding->param1 & 0xFF00) >> 8; - int32_t y = binding->param1 & 0x00FF; + int32_t x = WHEEL_HORIZONTAL(binding->param1); + int32_t y = WHEEL_VERTICAL(binding->param1); zmk_hid_mouse_wheel_release(x, y); return zmk_endpoints_send_mouse_report(); } diff --git a/app/src/hid.c b/app/src/hid.c index 55b39b74..7c5c8b1d 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -181,9 +181,9 @@ static int16_t curr_y = 0; static int8_t curr_hor = 0; static int8_t curr_vert = 0; -#define SET_MOUSE_BUTTONS(butts) \ +#define SET_MOUSE_BUTTONS(btns) \ { \ - mouse_report.body.buttons = butts; \ + mouse_report.body.buttons = btns; \ LOG_DBG("Mouse buttons set to 0x%02X", mouse_report.body.buttons); \ } diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 921d68e7..eab48091 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -125,22 +125,23 @@ static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) } int hid_listener(const zmk_event_t *eh) { - const struct zmk_keycode_state_changed *ev = as_zmk_keycode_state_changed(eh); - if (ev) { - if (ev->state) { - hid_listener_keycode_pressed(ev); + const struct zmk_keycode_state_changed *kc_ev = as_zmk_keycode_state_changed(eh); + if (kc_ev) { + if (kc_ev->state) { + hid_listener_keycode_pressed(kc_ev); } else { - hid_listener_keycode_released(ev); + hid_listener_keycode_released(kc_ev); } - } else { - const struct zmk_mouse_state_changed *ev = as_zmk_mouse_state_changed(eh); - if (ev) { - if (ev->state) { - hid_listener_mouse_pressed(ev); - } else { - hid_listener_mouse_released(ev); - } + return 0; + } + const struct zmk_mouse_state_changed *ms_ev = as_zmk_mouse_state_changed(eh); + if (ms_ev) { + if (ms_ev->state) { + hid_listener_mouse_pressed(ms_ev); + } else { + hid_listener_mouse_released(ms_ev); } + return 0; } return 0; } From fdcd7241e34ff496236c811429c93d362331a972 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Mon, 3 May 2021 11:14:00 +0300 Subject: [PATCH 16/35] Mouse movement coordinate signedness consistency --- app/include/zmk/events/mouse_state_changed.h | 8 ++++---- app/include/zmk/hid.h | 16 ++++++++-------- app/src/hid.c | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/include/zmk/events/mouse_state_changed.h b/app/include/zmk/events/mouse_state_changed.h index 0264ea4a..d19d091a 100644 --- a/app/include/zmk/events/mouse_state_changed.h +++ b/app/include/zmk/events/mouse_state_changed.h @@ -11,8 +11,8 @@ #include struct zmk_mouse_state_changed { - uint32_t x; - uint32_t y; + int32_t x; + int32_t y; bool state; int64_t timestamp; }; @@ -22,8 +22,8 @@ ZMK_EVENT_DECLARE(zmk_mouse_state_changed); static inline struct zmk_mouse_state_changed_event * zmk_mouse_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { - uint32_t x = (encoded & 0xFFFF0000) >> 16; - uint32_t y = encoded & 0x0000FFFF; + int32_t x = (encoded & 0xFFFF0000) >> 16; + int32_t y = encoded & 0x0000FFFF; return new_zmk_mouse_state_changed( (struct zmk_mouse_state_changed){.x = x, .y = y, .state = pressed, .timestamp = timestamp}); diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index fb9705a1..c18c8463 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -229,10 +229,10 @@ struct zmk_hid_consumer_report { struct zmk_hid_mouse_report_body { zmk_mouse_button_flags_t buttons; - uint16_t x; - uint16_t y; - uint8_t wheel_vert; - uint8_t wheel_hor; + int16_t x; + int16_t y; + int8_t wheel_vert; + int8_t wheel_hor; } __packed; struct zmk_hid_mouse_report { @@ -259,10 +259,10 @@ int zmk_hid_mouse_button_press(zmk_mouse_button_t button); int zmk_hid_mouse_button_release(zmk_mouse_button_t button); int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); -int zmk_hid_mouse_movement_press(uint16_t x, uint16_t y); -int zmk_hid_mouse_movement_release(uint16_t x, uint16_t y); -int zmk_hid_mouse_wheel_press(uint8_t hor, uint8_t vert); -int zmk_hid_mouse_wheel_release(uint8_t hor, uint8_t vert); +int zmk_hid_mouse_movement_press(int16_t x, int16_t y); +int zmk_hid_mouse_movement_release(int16_t x, int16_t y); +int zmk_hid_mouse_wheel_press(int8_t hor, int8_t vert); +int zmk_hid_mouse_wheel_release(int8_t hor, int8_t vert); void zmk_hid_mouse_clear(); struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); diff --git a/app/src/hid.c b/app/src/hid.c index 7c5c8b1d..85d87de1 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -236,14 +236,14 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { LOG_DBG("Mouse movement y set to 0x%02X", mouse_report.body.y); \ } -int zmk_hid_mouse_movement_press(uint16_t x, uint16_t y) { +int zmk_hid_mouse_movement_press(int16_t x, int16_t y) { curr_x += x; curr_y += y; SET_MOUSE_MOVEMENT(curr_x, curr_y); return 0; } -int zmk_hid_mouse_movement_release(uint16_t x, uint16_t y) { +int zmk_hid_mouse_movement_release(int16_t x, int16_t y) { curr_x -= x; curr_y -= y; SET_MOUSE_MOVEMENT(curr_x, curr_y); @@ -258,14 +258,14 @@ int zmk_hid_mouse_movement_release(uint16_t x, uint16_t y) { LOG_DBG("Mouse wheel vert set to 0x%02X", mouse_report.body.wheel_vert); \ } -int zmk_hid_mouse_wheel_press(uint8_t hor, uint8_t vert) { +int zmk_hid_mouse_wheel_press(int8_t hor, int8_t vert) { curr_hor += hor; curr_vert += vert; SET_MOUSE_WHEEL(curr_hor, curr_vert); return 0; } -int zmk_hid_mouse_wheel_release(uint8_t hor, uint8_t vert) { +int zmk_hid_mouse_wheel_release(int8_t hor, int8_t vert) { curr_hor -= hor; curr_vert -= vert; SET_MOUSE_WHEEL(curr_hor, curr_vert); From 8e6fbdcc2540c21d011fa692a3ba63ed44c3937f Mon Sep 17 00:00:00 2001 From: krikun98 Date: Mon, 3 May 2021 11:48:19 +0300 Subject: [PATCH 17/35] Reverted mouse buttons 9-16 --- app/include/dt-bindings/zmk/mouse.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 007fe128..a1021a45 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -28,22 +28,6 @@ #define MB8 (0x80) -#define MB9 (0x0100) - -#define MB10 (0x0200) - -#define MB11 (0x0400) - -#define MB12 (0x0800) - -#define MB13 (0x1000) - -#define MB14 (0x2000) - -#define MB15 (0x4000) - -#define MB16 (0x8000) - /* Mouse move behavior */ #define MOVE_UP (0x0000FFFF) From 2d3f0e1d92588d46e8f91dea79b20a7508559e32 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Mon, 3 May 2021 12:32:36 +0300 Subject: [PATCH 18/35] Report refactor (added macros) --- app/include/dt-bindings/zmk/hid_usage_pages.h | 1 + app/include/zmk/hid.h | 232 +++++++++++++----- 2 files changed, 168 insertions(+), 65 deletions(-) diff --git a/app/include/dt-bindings/zmk/hid_usage_pages.h b/app/include/dt-bindings/zmk/hid_usage_pages.h index f38f4fd3..e3946867 100644 --- a/app/include/dt-bindings/zmk/hid_usage_pages.h +++ b/app/include/dt-bindings/zmk/hid_usage_pages.h @@ -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 diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index c18c8463..b293aaa6 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -14,45 +14,59 @@ #include #include -#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL - #define COLLECTION_REPORT 0x03 static const uint8_t zmk_hid_report_desc[] = { /* USAGE_PAGE (Generic Desktop) */ - HID_GI_USAGE_PAGE, HID_USAGE_GD, + HID_GI_USAGE_PAGE, + HID_USAGE_GD, /* USAGE (Keyboard) */ - HID_LI_USAGE, HID_USAGE_GD_KEYBOARD, + HID_LI_USAGE, + HID_USAGE_GD_KEYBOARD, /* COLLECTION (Application) */ - HID_MI_COLLECTION, COLLECTION_APPLICATION, + HID_MI_COLLECTION, + COLLECTION_APPLICATION, /* REPORT ID (1) */ - HID_GI_REPORT_ID, 0x01, + HID_GI_REPORT_ID, + 0x01, /* USAGE_PAGE (Keyboard/Keypad) */ - HID_GI_USAGE_PAGE, HID_USAGE_KEY, + HID_GI_USAGE_PAGE, + HID_USAGE_KEY, /* USAGE_MINIMUM (Keyboard LeftControl) */ - HID_LI_USAGE_MIN(1), HID_USAGE_KEY_KEYBOARD_LEFTCONTROL, + HID_LI_USAGE_MIN(1), + HID_USAGE_KEY_KEYBOARD_LEFTCONTROL, /* USAGE_MAXIMUM (Keyboard Right GUI) */ - HID_LI_USAGE_MAX(1), HID_USAGE_KEY_KEYBOARD_RIGHT_GUI, + HID_LI_USAGE_MAX(1), + HID_USAGE_KEY_KEYBOARD_RIGHT_GUI, /* LOGICAL_MINIMUM (0) */ - HID_GI_LOGICAL_MIN(1), 0x00, + HID_GI_LOGICAL_MIN(1), + 0x00, /* LOGICAL_MAXIMUM (1) */ - HID_GI_LOGICAL_MAX(1), 0x01, + HID_GI_LOGICAL_MAX(1), + 0x01, /* REPORT_SIZE (1) */ - HID_GI_REPORT_SIZE, 0x01, + HID_GI_REPORT_SIZE, + 0x01, /* REPORT_COUNT (8) */ - HID_GI_REPORT_COUNT, 0x08, + HID_GI_REPORT_COUNT, + 0x08, /* INPUT (Data,Var,Abs) */ - HID_MI_INPUT, 0x02, + HID_MI_INPUT, + 0x02, /* USAGE_PAGE (Keyboard/Keypad) */ - HID_GI_USAGE_PAGE, HID_USAGE_KEY, + HID_GI_USAGE_PAGE, + HID_USAGE_KEY, /* REPORT_SIZE (8) */ - HID_GI_REPORT_SIZE, 0x08, + HID_GI_REPORT_SIZE, + 0x08, /* REPORT_COUNT (1) */ - HID_GI_REPORT_COUNT, 0x01, + HID_GI_REPORT_COUNT, + 0x01, /* INPUT (Cnst,Var,Abs) */ - HID_MI_INPUT, 0x03, + HID_MI_INPUT, + 0x03, /* USAGE_PAGE (Keyboard/Keypad) */ HID_GI_USAGE_PAGE, @@ -82,13 +96,17 @@ static const uint8_t zmk_hid_report_desc[] = { 0x02, #elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) /* LOGICAL_MINIMUM (0) */ - HID_GI_LOGICAL_MIN(1), 0x00, + HID_GI_LOGICAL_MIN(1), + 0x00, /* LOGICAL_MAXIMUM (0xFF) */ - HID_GI_LOGICAL_MAX(1), 0xFF, + HID_GI_LOGICAL_MAX(1), + 0xFF, /* USAGE_MINIMUM (Reserved) */ - HID_LI_USAGE_MIN(1), 0x00, + HID_LI_USAGE_MIN(1), + 0x00, /* USAGE_MAXIMUM (Keyboard Application) */ - HID_LI_USAGE_MAX(1), 0xFF, + HID_LI_USAGE_MAX(1), + 0xFF, /* REPORT_SIZE (1) */ HID_GI_REPORT_SIZE, 0x08, @@ -105,13 +123,17 @@ static const uint8_t zmk_hid_report_desc[] = { /* END_COLLECTION */ HID_MI_COLLECTION_END, /* USAGE_PAGE (Consumer) */ - HID_GI_USAGE_PAGE, HID_USAGE_CONSUMER, + HID_GI_USAGE_PAGE, + HID_USAGE_CONSUMER, /* USAGE (Consumer Control) */ - HID_LI_USAGE, HID_USAGE_CONSUMER_CONSUMER_CONTROL, + HID_LI_USAGE, + HID_USAGE_CONSUMER_CONSUMER_CONTROL, /* Consumer Page */ - HID_MI_COLLECTION, COLLECTION_APPLICATION, + HID_MI_COLLECTION, + COLLECTION_APPLICATION, /* REPORT ID (1) */ - HID_GI_REPORT_ID, 0x02, + HID_GI_REPORT_ID, + 0x02, /* USAGE_PAGE (Consumer) */ HID_GI_USAGE_PAGE, HID_USAGE_CONSUMER, @@ -134,11 +156,18 @@ static const uint8_t zmk_hid_report_desc[] = { 0x08, #elif IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_FULL) /* LOGICAL_MINIMUM (0) */ - HID_GI_LOGICAL_MIN(1), 0x00, + HID_GI_LOGICAL_MIN(1), + 0x00, /* LOGICAL_MAXIMUM (0xFFFF) */ - HID_GI_LOGICAL_MAX(2), 0xFF, 0xFF, HID_LI_USAGE_MIN(1), 0x00, + HID_GI_LOGICAL_MAX(2), + 0xFF, + 0xFF, + HID_LI_USAGE_MIN(1), + 0x00, /* USAGE_MAXIMUM (0xFFFF) */ - HID_LI_USAGE_MAX(2), 0xFF, 0xFF, + HID_LI_USAGE_MAX(2), + 0xFF, + 0xFF, /* INPUT (Data,Ary,Abs) */ /* REPORT_SIZE (16) */ HID_GI_REPORT_SIZE, @@ -154,42 +183,115 @@ static const uint8_t zmk_hid_report_desc[] = { /* END COLLECTION */ HID_MI_COLLECTION_END, - 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ - 0x09, 0x02, /* Usage (Mouse) */ - 0xA1, 0x01, /* Collection (Application) */ - 0x85, 0x04, /* Report ID (4) */ - 0x09, 0x01, /* Usage (Pointer) */ - 0xA1, 0x00, /* Collection (Physical) */ - 0x05, 0x09, /* Usage Page (Button) */ - 0x19, 0x01, /* Usage Minimum (0x01) */ - 0x29, 0x10, /* Usage Maximum (0x10) */ - 0x15, 0x00, /* Logical Minimum (0) */ - 0x25, 0x01, /* Logical Maximum (1) */ - 0x95, 0x10, /* Report Count (16) */ - 0x75, 0x01, /* Report Size (1) */ - 0x81, 0x02, /* Input (Data,Var,Abs,No Wrap,Linear,...) */ - 0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */ - 0x16, 0x01, 0x80, /* Logical Minimum (-32767) */ - 0x26, 0xFF, 0x7F, /* Logical Maximum (32767) */ - 0x75, 0x10, /* Report Size (8) */ - 0x95, 0x02, /* Report Count (2) */ - 0x09, 0x30, /* Usage (X) */ - 0x09, 0x31, /* Usage (Y) */ - 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ - 0x15, 0x81, /* Logical Minimum (-127) */ - 0x25, 0x7F, /* Logical Maximum (127) */ - 0x75, 0x08, /* Report Count (8) */ - 0x95, 0x01, /* Report Size (1) */ - 0x09, 0x38, /* Usage (Wheel) */ - 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ - 0x05, 0x0C, /* Usage Page (Consumer) */ // Horizontal wheel - 0x0A, 0x38, 0x02, /* Usage (AC Pan) */ - 0x15, 0x81, /* Logical Minimum (-127) */ - 0x25, 0x7f, /* Logical Maximum (127) */ - 0x95, 0x01, /* Report Count (1) */ - 0x81, 0x06, /* Input (Data,Var,Rel,No Wrap,Linear,...) */ - 0xC0, /* End Collection */ - 0xC0, /* End Collection */ + /* USAGE_PAGE (Generic Desktop) */ + HID_GI_USAGE_PAGE, + HID_USAGE_GD, + /* USAGE (Mouse) */ + HID_LI_USAGE, + HID_USAGE_GD_MOUSE, + /* COLLECTION (Application) */ + HID_MI_COLLECTION, + COLLECTION_APPLICATION, + /* REPORT ID (4) */ + HID_GI_REPORT_ID, + 0x04, + /* USAGE (Pointer) */ + HID_LI_USAGE, + HID_USAGE_GD_POINTER, + /* COLLECTION (Physical) */ + HID_MI_COLLECTION, + COLLECTION_PHYSICAL, + /* USAGE_PAGE (Button) */ + HID_GI_USAGE_PAGE, + HID_USAGE_BUTTON, + /* USAGE_MINIMUM (0x1) (button 1?) */ + HID_LI_USAGE_MIN(1), + 0x1, + /* USAGE_MAXIMUM (0x10) (button 5? Buttons up to 8 still work) */ + HID_LI_USAGE_MAX(1), + 0x10, + /* LOGICAL_MINIMUM (0) */ + HID_GI_LOGICAL_MIN(1), + 0x00, + /* LOGICAL_MAXIMUM (1) */ + HID_GI_LOGICAL_MAX(1), + 0x01, + /* REPORT_SIZE (1) */ + HID_GI_REPORT_SIZE, + 0x01, + /* REPORT_COUNT (16) */ + HID_GI_REPORT_COUNT, + 0x10, + /* INPUT (Data,Var,Abs) */ + HID_MI_INPUT, + 0x02, + /* USAGE_PAGE (Generic Desktop) */ + HID_GI_USAGE_PAGE, + HID_USAGE_GD, + /* LOGICAL_MINIMUM (-32767) */ + HID_GI_LOGICAL_MIN(2), + 0x01, + 0x80, + /* LOGICAL_MAXIMUM (32767) */ + HID_GI_LOGICAL_MAX(2), + 0xFF, + 0x7F, + /* REPORT_SIZE (16) */ + HID_GI_REPORT_SIZE, + 0x10, + /* REPORT_COUNT (2) */ + HID_GI_REPORT_COUNT, + 0x02, + /* USAGE (X) */ + HID_LI_USAGE, + HID_USAGE_GD_X, + /* USAGE (Y) */ + HID_LI_USAGE, + HID_USAGE_GD_Y, + /* Input (Data,Var,Rel) */ + HID_MI_INPUT, + 0x06, + /* LOGICAL_MINIMUM (-127) */ + HID_GI_LOGICAL_MIN(1), + 0x81, + /* LOGICAL_MAXIMUM (127) */ + HID_GI_LOGICAL_MAX(1), + 0x7F, + /* REPORT_SIZE (8) */ + HID_GI_REPORT_SIZE, + 0x08, + /* REPORT_COUNT (1) */ + HID_GI_REPORT_COUNT, + 0x01, + /* USAGE (Wheel) */ + HID_LI_USAGE, + HID_USAGE_GD_WHEEL, + /* Input (Data,Var,Rel) */ + HID_MI_INPUT, + 0x06, + /* USAGE_PAGE (Consumer) */ // Horizontal wheel + HID_GI_USAGE_PAGE, + HID_USAGE_CONSUMER, + /* USAGE (AC Pan) */ + 0x0A, + 0x38, + 0x02, + /* LOGICAL_MINIMUM (-127) */ + HID_GI_LOGICAL_MIN(1), + 0x81, + /* LOGICAL_MAXIMUM (127) */ + HID_GI_LOGICAL_MAX(1), + 0x7F, + /* REPORT_COUNT (1) */ + HID_GI_REPORT_COUNT, + 0x01, + /* Input (Data,Var,Rel) */ + HID_MI_INPUT, + 0x06, + /* END COLLECTION */ + HID_MI_COLLECTION_END, + /* END COLLECTION */ + HID_MI_COLLECTION_END, }; // struct zmk_hid_boot_report From c55bd0fa276d43f5e1f8c5d84c290c38afb2ce03 Mon Sep 17 00:00:00 2001 From: Okke Formsma Date: Fri, 14 May 2021 13:29:55 +0200 Subject: [PATCH 19/35] Simplify binary arithmetic --- app/include/dt-bindings/zmk/mouse.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index a1021a45..418afc28 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -30,34 +30,34 @@ /* Mouse move behavior */ -#define MOVE_UP (0x0000FFFF) +#define MOVE_UP MOVE_VERT(1) -#define MOVE_DOWN (0x00000001) +#define MOVE_DOWN MOVE_VERT(-1) -#define MOVE_LEFT (0xFFFF0000) +#define MOVE_LEFT MOVE_HOR(-1) -#define MOVE_RIGHT (0x00010000) +#define MOVE_RIGHT MOVE_HOR(1) /* -32767 to 32767, barely usable beyond about 50 (probably depends on screen resolution) */ -#define MOVE_VERT(vert) ((vert) < 0 ? -(vert) : (1 << 16) - (vert)) +#define MOVE_VERT(vert) ((-(vert)) & 0xFFFF) -#define MOVE_HOR(hor) (((hor) > 0 ? (hor) : (1 << 16) + (hor)) << 16) +#define MOVE_HOR(hor) (((hor)&0xFFFF) << 16) #define MOVE(hor, vert) (MOVE_HOR(hor) + MOVE_VERT(vert)) /* Mouse wheel behavior */ -#define WHEEL_UP (0x0001) +#define WHEEL_UP WHEEL_VERT(1) -#define WHEEL_DOWN (0x00FF) +#define WHEEL_DOWN WHEEL_VERT(-1) -#define WHEEL_LEFT (0xFF00) +#define WHEEL_LEFT WHEEL_HOR(-1) -#define WHEEL_RIGHT (0x0100) +#define WHEEL_RIGHT WHEEL_HOR(1) /* -127 to 127, barely usable beyond about 10 */ -#define WHEEL_VERT(vert) ((vert) < 0 ? (1 << 8) + (vert) : vert) +#define WHEEL_VERT(vert) ((vert)&0xFF) -#define WHEEL_HOR(hor) (((hor) < 0 ? (1 << 8) + (hor) : hor) << 8) +#define WHEEL_HOR(hor) (((hor)&0xFF) << 8) #define WHEEL(hor, vert) (WHEEL_HOR(hor) + WHEEL_VERT(vert)) From 1815820716d46baac3ddcc7b31e2b8f07f23ff4b Mon Sep 17 00:00:00 2001 From: krikun98 Date: Sat, 15 May 2021 00:42:29 +0300 Subject: [PATCH 20/35] Modified mouse_timer_unref to account for errors --- app/src/hid_listener.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index eab48091..a6877244 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -94,7 +94,9 @@ void mouse_timer_ref() { } void mouse_timer_unref() { - mouse_timer_ref_count -= 1; + if (mouse_timer_ref_count > 0) { + mouse_timer_ref_count -= 1; + } if (mouse_timer_ref_count == 0) { k_timer_stop(&mouse_timer); } @@ -118,6 +120,7 @@ static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) err = zmk_hid_mouse_movement_release(ev->x, ev->y); if (err) { LOG_ERR("Unable to release button"); + mouse_timer_unref(); return err; } mouse_timer_unref(); From 35eef63fa9a9813a73cedb4c01cd67f50c63d1d1 Mon Sep 17 00:00:00 2001 From: Okke Formsma Date: Fri, 14 May 2021 20:32:14 +0200 Subject: [PATCH 21/35] feat(mouse keys): add events, smoothing and acceleration --- app/CMakeLists.txt | 9 +- app/dts/behaviors.dtsi | 2 +- app/dts/behaviors/mouse_move.dtsi | 3 + app/dts/behaviors/mouse_scroll.dtsi | 12 ++ app/dts/behaviors/mouse_wheel.dtsi | 9 -- .../behaviors/zmk,behavior-mouse-move.yaml | 8 ++ .../behaviors/zmk,behavior-mouse-scroll.yaml | 13 ++ .../behaviors/zmk,behavior-mouse-wheel.yaml | 5 - app/include/dt-bindings/zmk/mouse.h | 42 +++--- .../zmk/events/mouse_button_state_changed.h | 27 ++++ .../zmk/events/mouse_move_state_changed.h | 33 +++++ .../zmk/events/mouse_scroll_state_changed.h | 34 +++++ app/include/zmk/events/mouse_state_changed.h | 30 ---- app/include/zmk/events/mouse_tick.h | 36 +++++ app/include/zmk/hid.h | 16 +-- app/include/zmk/mouse.h | 14 ++ app/src/behaviors/behavior_mouse_key_press.c | 19 +-- app/src/behaviors/behavior_mouse_move.c | 33 +++-- app/src/behaviors/behavior_mouse_scroll.c | 58 ++++++++ app/src/behaviors/behavior_mouse_wheel.c | 52 ------- app/src/endpoints.c | 2 +- app/src/events/mouse_button_state_changed.c | 10 ++ app/src/events/mouse_move_state_changed.c | 10 ++ app/src/events/mouse_scroll_state_changed.c | 10 ++ .../{mouse_state_changed.c => mouse_tick.c} | 4 +- app/src/hid.c | 61 +++----- app/src/hid_listener.c | 70 +-------- app/src/mouse/key_listener.c | 135 ++++++++++++++++++ app/src/mouse/tick_listener.c | 129 +++++++++++++++++ app/tests/mouse-keys/mmv/events.patterns | 1 + .../mouse-keys/mmv/keycode_events.snapshot | 2 + app/tests/mouse-keys/mmv/native_posix.keymap | 26 ++++ docs/docs/behaviors/mouse-emulation.md | 6 +- 33 files changed, 653 insertions(+), 268 deletions(-) create mode 100644 app/dts/behaviors/mouse_scroll.dtsi delete mode 100644 app/dts/behaviors/mouse_wheel.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml delete mode 100644 app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml create mode 100644 app/include/zmk/events/mouse_button_state_changed.h create mode 100644 app/include/zmk/events/mouse_move_state_changed.h create mode 100644 app/include/zmk/events/mouse_scroll_state_changed.h delete mode 100644 app/include/zmk/events/mouse_state_changed.h create mode 100644 app/include/zmk/events/mouse_tick.h create mode 100644 app/src/behaviors/behavior_mouse_scroll.c delete mode 100644 app/src/behaviors/behavior_mouse_wheel.c create mode 100644 app/src/events/mouse_button_state_changed.c create mode 100644 app/src/events/mouse_move_state_changed.c create mode 100644 app/src/events/mouse_scroll_state_changed.c rename app/src/events/{mouse_state_changed.c => mouse_tick.c} (55%) create mode 100644 app/src/mouse/key_listener.c create mode 100644 app/src/mouse/tick_listener.c create mode 100644 app/tests/mouse-keys/mmv/events.patterns create mode 100644 app/tests/mouse-keys/mmv/keycode_events.snapshot create mode 100644 app/tests/mouse-keys/mmv/native_posix.keymap diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index e7c55330..b08fd637 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -27,6 +27,8 @@ target_sources(app PRIVATE src/activity.c) target_sources(app PRIVATE src/kscan.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/hid.c) +target_sources(app PRIVATE src/mouse/key_listener.c) +target_sources(app PRIVATE src/mouse/tick_listener.c) target_sources(app PRIVATE src/sensors.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c) target_sources(app PRIVATE src/event_manager.c) @@ -38,7 +40,10 @@ target_sources(app PRIVATE src/events/keycode_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/endpoint_selection_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) -target_sources(app PRIVATE src/events/mouse_state_changed.c) +target_sources(app PRIVATE src/events/mouse_button_state_changed.c) +target_sources(app PRIVATE src/events/mouse_move_state_changed.c) +target_sources(app PRIVATE src/events/mouse_tick.c) +target_sources(app PRIVATE src/events/mouse_scroll_state_changed.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c) @@ -58,7 +63,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) target_sources(app PRIVATE src/behaviors/behavior_mouse_key_press.c) target_sources(app PRIVATE src/behaviors/behavior_mouse_move.c) - target_sources(app PRIVATE src/behaviors/behavior_mouse_wheel.c) + target_sources(app PRIVATE src/behaviors/behavior_mouse_scroll.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/keymap.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 9aa5bf57..3edaa1c1 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -16,4 +16,4 @@ #include #include #include -#include +#include diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index e442c501..858c5617 100644 --- a/app/dts/behaviors/mouse_move.dtsi +++ b/app/dts/behaviors/mouse_move.dtsi @@ -4,6 +4,9 @@ compatible = "zmk,behavior-mouse-move"; label = "MOUSE_MOVE"; #binding-cells = <1>; + delay-ms = <100>; + time-to-max-speed-ms = <1000>; + acceleration-exponent = <2000>; }; }; }; diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi new file mode 100644 index 00000000..931124ce --- /dev/null +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -0,0 +1,12 @@ +/ { + behaviors { + /omit-if-no-ref/ mwh: msc: behavior_mouse_scroll { + compatible = "zmk,behavior-mouse-scroll"; + label = "MOUSE_SCROLL"; + #binding-cells = <1>; + delay-ms = <0>; + time-to-max-speed-ms = <1000>; + acceleration-exponent = <0>; + }; + }; +}; diff --git a/app/dts/behaviors/mouse_wheel.dtsi b/app/dts/behaviors/mouse_wheel.dtsi deleted file mode 100644 index 2a7527ab..00000000 --- a/app/dts/behaviors/mouse_wheel.dtsi +++ /dev/null @@ -1,9 +0,0 @@ -/ { - behaviors { - /omit-if-no-ref/ mwh: behavior_mouse_wheel { - compatible = "zmk,behavior-mouse-wheel"; - label = "MOUSE_WHEEL"; - #binding-cells = <1>; - }; - }; -}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml index f18d78a7..73ec34ec 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-move.yaml @@ -3,3 +3,11 @@ description: Mouse move compatible: "zmk,behavior-mouse-move" include: one_param.yaml + +properties: + delay-ms: + type: int + time-to-max-speed-ms: + type: int + acceleration-exponent: + type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml new file mode 100644 index 00000000..5a932bc5 --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-mouse-scroll.yaml @@ -0,0 +1,13 @@ +description: Mouse scroll + +compatible: "zmk,behavior-mouse-scroll" + +include: one_param.yaml + +properties: + delay-ms: + type: int + time-to-max-speed-ms: + type: int + acceleration-exponent: + type: int diff --git a/app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml b/app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml deleted file mode 100644 index 89021172..00000000 --- a/app/dts/bindings/behaviors/zmk,behavior-mouse-wheel.yaml +++ /dev/null @@ -1,5 +0,0 @@ -description: Mouse wheel - -compatible: "zmk,behavior-mouse-wheel" - -include: one_param.yaml diff --git a/app/include/dt-bindings/zmk/mouse.h b/app/include/dt-bindings/zmk/mouse.h index 418afc28..cf0415c9 100644 --- a/app/include/dt-bindings/zmk/mouse.h +++ b/app/include/dt-bindings/zmk/mouse.h @@ -29,35 +29,27 @@ #define MB8 (0x80) /* Mouse move behavior */ - -#define MOVE_UP MOVE_VERT(1) - -#define MOVE_DOWN MOVE_VERT(-1) - -#define MOVE_LEFT MOVE_HOR(-1) - -#define MOVE_RIGHT MOVE_HOR(1) - -/* -32767 to 32767, barely usable beyond about 50 (probably depends on screen resolution) */ -#define MOVE_VERT(vert) ((-(vert)) & 0xFFFF) - +#define MOVE_VERT(vert) ((vert)&0xFFFF) +#define MOVE_VERT_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) #define MOVE_HOR(hor) (((hor)&0xFFFF) << 16) +#define MOVE_HOR_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) #define MOVE(hor, vert) (MOVE_HOR(hor) + MOVE_VERT(vert)) -/* Mouse wheel behavior */ +#define MOVE_UP MOVE_VERT(-600) +#define MOVE_DOWN MOVE_VERT(600) +#define MOVE_LEFT MOVE_HOR(-600) +#define MOVE_RIGHT MOVE_HOR(600) -#define WHEEL_UP WHEEL_VERT(1) +/* Mouse scroll behavior */ +#define SCROLL_VERT(vert) ((vert)&0xFFFF) +#define SCROLL_VERT_DECODE(encoded) (int16_t)((encoded)&0x0000FFFF) +#define SCROLL_HOR(hor) (((hor)&0xFFFF) << 16) +#define SCROLL_HOR_DECODE(encoded) (int16_t)(((encoded)&0xFFFF0000) >> 16) -#define WHEEL_DOWN WHEEL_VERT(-1) +#define SCROLL(hor, vert) (SCROLL_HOR(hor) + SCROLL_VERT(vert)) -#define WHEEL_LEFT WHEEL_HOR(-1) - -#define WHEEL_RIGHT WHEEL_HOR(1) - -/* -127 to 127, barely usable beyond about 10 */ -#define WHEEL_VERT(vert) ((vert)&0xFF) - -#define WHEEL_HOR(hor) (((hor)&0xFF) << 8) - -#define WHEEL(hor, vert) (WHEEL_HOR(hor) + WHEEL_VERT(vert)) +#define SCROLL_UP SCROLL_VERT(10) +#define SCROLL_DOWN SCROLL_VERT(-10) +#define SCROLL_LEFT SCROLL_HOR(-10) +#define SCROLL_RIGHT SCROLL_HOR(10) diff --git a/app/include/zmk/events/mouse_button_state_changed.h b/app/include/zmk/events/mouse_button_state_changed.h new file mode 100644 index 00000000..7ec4d208 --- /dev/null +++ b/app/include/zmk/events/mouse_button_state_changed.h @@ -0,0 +1,27 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +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 = HID_USAGE_ID(encoded), .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_move_state_changed.h b/app/include/zmk/events/mouse_move_state_changed.h new file mode 100644 index 00000000..8866f81d --- /dev/null +++ b/app/include/zmk/events/mouse_move_state_changed.h @@ -0,0 +1,33 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +struct zmk_mouse_move_state_changed { + struct vector2d max_speed; + struct mouse_config config; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_move_state_changed); + +static inline struct zmk_mouse_move_state_changed_event * +zmk_mouse_move_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, + bool pressed, int64_t timestamp) { + struct vector2d max_speed = (struct vector2d){ + .x = MOVE_HOR_DECODE(encoded), + .y = MOVE_VERT_DECODE(encoded), + }; + + return new_zmk_mouse_move_state_changed((struct zmk_mouse_move_state_changed){ + .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_scroll_state_changed.h b/app/include/zmk/events/mouse_scroll_state_changed.h new file mode 100644 index 00000000..fa60e8a7 --- /dev/null +++ b/app/include/zmk/events/mouse_scroll_state_changed.h @@ -0,0 +1,34 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +struct zmk_mouse_scroll_state_changed { + struct vector2d max_speed; + struct mouse_config config; + bool state; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_scroll_state_changed); + +static inline struct zmk_mouse_scroll_state_changed_event * +zmk_mouse_scroll_state_changed_from_encoded(uint32_t encoded, struct mouse_config config, + bool pressed, int64_t timestamp) { + struct vector2d max_speed = (struct vector2d){ + .x = SCROLL_HOR_DECODE(encoded), + .y = SCROLL_VERT_DECODE(encoded), + }; + + return new_zmk_mouse_scroll_state_changed((struct zmk_mouse_scroll_state_changed){ + .max_speed = max_speed, .config = config, .state = pressed, .timestamp = timestamp}); +} diff --git a/app/include/zmk/events/mouse_state_changed.h b/app/include/zmk/events/mouse_state_changed.h deleted file mode 100644 index d19d091a..00000000 --- a/app/include/zmk/events/mouse_state_changed.h +++ /dev/null @@ -1,30 +0,0 @@ - -/* - * Copyright (c) 2020 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#pragma once - -#include -#include - -struct zmk_mouse_state_changed { - int32_t x; - int32_t y; - bool state; - int64_t timestamp; -}; - -ZMK_EVENT_DECLARE(zmk_mouse_state_changed); - -static inline struct zmk_mouse_state_changed_event * -zmk_mouse_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) { - - int32_t x = (encoded & 0xFFFF0000) >> 16; - int32_t y = encoded & 0x0000FFFF; - - return new_zmk_mouse_state_changed( - (struct zmk_mouse_state_changed){.x = x, .y = y, .state = pressed, .timestamp = timestamp}); -} diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h new file mode 100644 index 00000000..6307b5eb --- /dev/null +++ b/app/include/zmk/events/mouse_tick.h @@ -0,0 +1,36 @@ + +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include +#include + +struct zmk_mouse_tick { + struct vector2d max_move; + struct vector2d max_scroll; + struct mouse_config move_config; + struct mouse_config scroll_config; + int64_t timestamp; +}; + +ZMK_EVENT_DECLARE(zmk_mouse_tick); + +static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move, + struct vector2d max_scroll, + struct mouse_config move_config, + struct mouse_config scroll_config) { + return new_zmk_mouse_tick((struct zmk_mouse_tick){ + .max_move = max_move, + .max_scroll = max_scroll, + .move_config = move_config, + .scroll_config = scroll_config, + .timestamp = k_uptime_get(), + }); +} diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index b293aaa6..d6edac2c 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -242,7 +242,7 @@ static const uint8_t zmk_hid_report_desc[] = { /* REPORT_COUNT (2) */ HID_GI_REPORT_COUNT, 0x02, - /* USAGE (X) */ + /* USAGE (X) */ // Vertical scroll HID_LI_USAGE, HID_USAGE_GD_X, /* USAGE (Y) */ @@ -269,7 +269,7 @@ static const uint8_t zmk_hid_report_desc[] = { /* Input (Data,Var,Rel) */ HID_MI_INPUT, 0x06, - /* USAGE_PAGE (Consumer) */ // Horizontal wheel + /* USAGE_PAGE (Consumer) */ // Horizontal scroll HID_GI_USAGE_PAGE, HID_USAGE_CONSUMER, /* USAGE (AC Pan) */ @@ -333,8 +333,8 @@ struct zmk_hid_mouse_report_body { zmk_mouse_button_flags_t buttons; int16_t x; int16_t y; - int8_t wheel_vert; - int8_t wheel_hor; + int8_t scroll_y; + int8_t scroll_x; } __packed; struct zmk_hid_mouse_report { @@ -361,10 +361,10 @@ int zmk_hid_mouse_button_press(zmk_mouse_button_t button); int zmk_hid_mouse_button_release(zmk_mouse_button_t button); int zmk_hid_mouse_buttons_press(zmk_mouse_button_flags_t buttons); int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons); -int zmk_hid_mouse_movement_press(int16_t x, int16_t y); -int zmk_hid_mouse_movement_release(int16_t x, int16_t y); -int zmk_hid_mouse_wheel_press(int8_t hor, int8_t vert); -int zmk_hid_mouse_wheel_release(int8_t hor, int8_t vert); +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(); struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index e749ac5d..93d96df9 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -11,3 +11,17 @@ typedef uint16_t zmk_mouse_button_flags_t; typedef uint16_t zmk_mouse_button_t; + +struct mouse_config { + int delay_ms; + int time_to_max_speed_ms; + // acceleration exponent 0: uniform speed + // acceleration exponent 1: uniform acceleration + // acceleration exponent 2: uniform jerk + float acceleration_exponent; +}; + +struct vector2d { + float x; + float y; +}; diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c index 3dc5ce79..6da2a8c4 100644 --- a/app/src/behaviors/behavior_mouse_key_press.c +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -10,28 +10,29 @@ #include #include -#include -#include #include -#include -#include +#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + static int behavior_mouse_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); - zmk_hid_mouse_buttons_press(HID_USAGE_ID(binding->param1)); - return zmk_endpoints_send_mouse_report(); + + 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); - zmk_hid_mouse_buttons_release(HID_USAGE_ID(binding->param1)); - return zmk_endpoints_send_mouse_report(); + 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 = { @@ -43,3 +44,5 @@ static const struct behavior_driver_api behavior_mouse_key_press_driver_api = { APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_key_press_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ \ No newline at end of file diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c index cc51129d..92ea3d86 100644 --- a/app/src/behaviors/behavior_mouse_move.c +++ b/app/src/behaviors/behavior_mouse_move.c @@ -10,37 +10,48 @@ #include #include -#include -#include #include -#include +#include +#include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + static int behavior_mouse_move_init(const struct device *dev) { return 0; }; static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - int res = ZMK_EVENT_RAISE( - zmk_mouse_state_changed_from_encoded(binding->param1, true, event.timestamp)); - return res; + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE( + zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, true, event.timestamp)); } static int on_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); - - return ZMK_EVENT_RAISE( - zmk_mouse_state_changed_from_encoded(binding->param1, false, event.timestamp)); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_move_state_changed_from_encoded(binding->param1, *config, + false, event.timestamp)); } static const struct behavior_driver_api behavior_mouse_move_driver_api = { .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; #define KP_INST(n) \ + static struct mouse_config behavior_mouse_move_config_##n = { \ + .delay_ms = DT_INST_PROP(n, delay_ms), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = (float)DT_INST_PROP(n, acceleration_exponent) / 1000.0f, \ + }; \ DEVICE_AND_API_INIT(behavior_mouse_move_##n, DT_INST_LABEL(n), behavior_mouse_move_init, NULL, \ - NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_mouse_move_driver_api); + &behavior_mouse_move_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_mouse_scroll.c b/app/src/behaviors/behavior_mouse_scroll.c new file mode 100644 index 00000000..e347d8af --- /dev/null +++ b/app/src/behaviors/behavior_mouse_scroll.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_mouse_scroll + +#include +#include +#include + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +static int behavior_mouse_scroll_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, + true, event.timestamp)); +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1); + const struct device *dev = device_get_binding(binding->behavior_dev); + const struct mouse_config *config = dev->config; + return ZMK_EVENT_RAISE(zmk_mouse_scroll_state_changed_from_encoded(binding->param1, *config, + false, event.timestamp)); +} + +static const struct behavior_driver_api behavior_mouse_scroll_driver_api = { + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; + +#define KP_INST(n) \ + static struct mouse_config behavior_mouse_scroll_config_##n = { \ + .delay_ms = DT_INST_PROP(n, delay_ms), \ + .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ + .acceleration_exponent = (float)DT_INST_PROP(n, acceleration_exponent) / 1000.0f, \ + }; \ + DEVICE_AND_API_INIT(behavior_mouse_scroll_##n, DT_INST_LABEL(n), behavior_mouse_scroll_init, \ + NULL, &behavior_mouse_scroll_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(KP_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/behaviors/behavior_mouse_wheel.c b/app/src/behaviors/behavior_mouse_wheel.c deleted file mode 100644 index bd2cd29b..00000000 --- a/app/src/behaviors/behavior_mouse_wheel.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2021 The ZMK Contributors - * - * SPDX-License-Identifier: MIT - */ - -#define DT_DRV_COMPAT zmk_behavior_mouse_wheel - -#include -#include -#include - -#include -#include -#include -#include -#include - -LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); - -#define WHEEL_HORIZONTAL(encoded) (((encoded)&0xFF00) >> 8) -#define WHEEL_VERTICAL(encoded) ((encoded)&0x00FF) - -static int behavior_mouse_wheel_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); - int32_t x = WHEEL_HORIZONTAL(binding->param1); - int32_t y = WHEEL_VERTICAL(binding->param1); - zmk_hid_mouse_wheel_press(x, y); - return zmk_endpoints_send_mouse_report(); -} - -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); - int32_t x = WHEEL_HORIZONTAL(binding->param1); - int32_t y = WHEEL_VERTICAL(binding->param1); - zmk_hid_mouse_wheel_release(x, y); - return zmk_endpoints_send_mouse_report(); -} - -static const struct behavior_driver_api behavior_mouse_wheel_driver_api = { - .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; - -#define KP_INST(n) \ - DEVICE_AND_API_INIT(behavior_mouse_wheel_##n, DT_INST_LABEL(n), behavior_mouse_wheel_init, \ - NULL, NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_mouse_wheel_driver_api); - -DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 59d9f74e..d40396c8 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -146,7 +146,7 @@ int zmk_endpoints_send_report(uint16_t usage_page) { } int zmk_endpoints_send_mouse_report() { - LOG_ERR("SENDING MOUSE REPORT"); + LOG_DBG("SENDING MOUSE REPORT"); struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); switch (current_endpoint) { diff --git a/app/src/events/mouse_button_state_changed.c b/app/src/events/mouse_button_state_changed.c new file mode 100644 index 00000000..e1ede414 --- /dev/null +++ b/app/src/events/mouse_button_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_button_state_changed); diff --git a/app/src/events/mouse_move_state_changed.c b/app/src/events/mouse_move_state_changed.c new file mode 100644 index 00000000..faf89cb8 --- /dev/null +++ b/app/src/events/mouse_move_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_move_state_changed); diff --git a/app/src/events/mouse_scroll_state_changed.c b/app/src/events/mouse_scroll_state_changed.c new file mode 100644 index 00000000..4b4170fe --- /dev/null +++ b/app/src/events/mouse_scroll_state_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(zmk_mouse_scroll_state_changed); diff --git a/app/src/events/mouse_state_changed.c b/app/src/events/mouse_tick.c similarity index 55% rename from app/src/events/mouse_state_changed.c rename to app/src/events/mouse_tick.c index 0d46ccf3..0930b9fb 100644 --- a/app/src/events/mouse_state_changed.c +++ b/app/src/events/mouse_tick.c @@ -5,6 +5,6 @@ */ #include -#include +#include -ZMK_EVENT_IMPL(zmk_mouse_state_changed); +ZMK_EVENT_IMPL(zmk_mouse_tick); diff --git a/app/src/hid.c b/app/src/hid.c index 85d87de1..9cdceac9 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -16,7 +16,7 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; static struct zmk_hid_mouse_report mouse_report = { - .report_id = 4, .body = {.buttons = 0, .x = 0, .y = 0, .wheel_vert = 0, .wheel_hor = 0}}; + .report_id = 4, .body = {.buttons = 0, .x = 0, .y = 0, .scroll_x = 0, .scroll_y = 0}}; // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. @@ -176,10 +176,6 @@ void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer // Only release the button if the count is 0. static int explicit_button_counts[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static zmk_mod_flags_t explicit_buttons = 0; -static int16_t curr_x = 0; -static int16_t curr_y = 0; -static int8_t curr_hor = 0; -static int8_t curr_vert = 0; #define SET_MOUSE_BUTTONS(btns) \ { \ @@ -228,50 +224,31 @@ int zmk_hid_mouse_buttons_release(zmk_mouse_button_flags_t buttons) { return 0; } -#define SET_MOUSE_MOVEMENT(coor_x, coor_y) \ - { \ - mouse_report.body.x = coor_x; \ - LOG_DBG("Mouse movement x set to 0x%02X", mouse_report.body.x); \ - mouse_report.body.y = coor_y; \ - LOG_DBG("Mouse movement y set to 0x%02X", mouse_report.body.y); \ - } - -int zmk_hid_mouse_movement_press(int16_t x, int16_t y) { - curr_x += x; - curr_y += y; - SET_MOUSE_MOVEMENT(curr_x, curr_y); - return 0; +void zmk_hid_mouse_movement_set(int16_t x, int16_t y) { + mouse_report.body.x = x; + mouse_report.body.y = y; + LOG_DBG("Mouse movement set to 0x%02X 0x%02X ", mouse_report.body.x, mouse_report.body.y); } -int zmk_hid_mouse_movement_release(int16_t x, int16_t y) { - curr_x -= x; - curr_y -= y; - SET_MOUSE_MOVEMENT(curr_x, curr_y); - return 0; +void zmk_hid_mouse_movement_update(int16_t x, int16_t y) { + mouse_report.body.x += x; + mouse_report.body.y += y; + LOG_DBG("Mouse movement updated to 0x%02X 0x%02X ", mouse_report.body.x, mouse_report.body.y); } -#define SET_MOUSE_WHEEL(horiz, vertic) \ - { \ - mouse_report.body.wheel_hor = horiz; \ - LOG_DBG("Mouse wheel hor set to 0x%02X", mouse_report.body.wheel_hor); \ - mouse_report.body.wheel_vert = vertic; \ - LOG_DBG("Mouse wheel vert set to 0x%02X", mouse_report.body.wheel_vert); \ - } - -int zmk_hid_mouse_wheel_press(int8_t hor, int8_t vert) { - curr_hor += hor; - curr_vert += vert; - SET_MOUSE_WHEEL(curr_hor, curr_vert); - return 0; +void zmk_hid_mouse_scroll_set(int8_t x, int8_t y) { + mouse_report.body.scroll_x = x; + mouse_report.body.scroll_y = y; + LOG_DBG("Mouse scroll set to 0x%02X 0x%02X ", mouse_report.body.scroll_x, + mouse_report.body.scroll_y); } -int zmk_hid_mouse_wheel_release(int8_t hor, int8_t vert) { - curr_hor -= hor; - curr_vert -= vert; - SET_MOUSE_WHEEL(curr_hor, curr_vert); - return 0; +void zmk_hid_mouse_scroll_update(int8_t x, int8_t y) { + mouse_report.body.scroll_x += x; + mouse_report.body.scroll_y += y; + LOG_DBG("Mouse scroll updated to 0x%02X 0x%02X ", mouse_report.body.scroll_x, + mouse_report.body.scroll_y); } - void zmk_hid_mouse_clear() { memset(&mouse_report.body, 0, sizeof(mouse_report.body)); } struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() { diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index a6877244..af7c38d8 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -11,8 +11,6 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include -#include -#include #include #include #include @@ -71,62 +69,6 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed return zmk_endpoints_send_report(ev->usage_page); } -static void zmk_mouse_work(struct k_work *work) { - int rc = zmk_endpoints_send_mouse_report(); - if (rc != 0) { - LOG_ERR("Failed to send mouse report, error: %d", rc); - } -} - -K_WORK_DEFINE(mouse_work, &zmk_mouse_work); - -void mouse_timer_cb(struct k_timer *dummy) { k_work_submit(&mouse_work); } - -K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_timer_cb); - -static int mouse_timer_ref_count = 0; - -void mouse_timer_ref() { - if (mouse_timer_ref_count == 0) { - k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(10)); - } - mouse_timer_ref_count += 1; -} - -void mouse_timer_unref() { - if (mouse_timer_ref_count > 0) { - mouse_timer_ref_count -= 1; - } - if (mouse_timer_ref_count == 0) { - k_timer_stop(&mouse_timer); - } -} - -static int hid_listener_mouse_pressed(const struct zmk_mouse_state_changed *ev) { - int err; - LOG_DBG("x: 0x%02X, y: 0x%02X", ev->x, ev->y); - err = zmk_hid_mouse_movement_press(ev->x, ev->y); - if (err) { - LOG_ERR("Unable to press button"); - return err; - } - mouse_timer_ref(); - return 0; -} - -static int hid_listener_mouse_released(const struct zmk_mouse_state_changed *ev) { - int err; - LOG_DBG("x: 0x%02X, y: 0x%02X", ev->x, ev->y); - err = zmk_hid_mouse_movement_release(ev->x, ev->y); - if (err) { - LOG_ERR("Unable to release button"); - mouse_timer_unref(); - return err; - } - mouse_timer_unref(); - return 0; -} - int hid_listener(const zmk_event_t *eh) { const struct zmk_keycode_state_changed *kc_ev = as_zmk_keycode_state_changed(eh); if (kc_ev) { @@ -137,18 +79,8 @@ int hid_listener(const zmk_event_t *eh) { } return 0; } - const struct zmk_mouse_state_changed *ms_ev = as_zmk_mouse_state_changed(eh); - if (ms_ev) { - if (ms_ev->state) { - hid_listener_mouse_pressed(ms_ev); - } else { - hid_listener_mouse_released(ms_ev); - } - return 0; - } return 0; } ZMK_LISTENER(hid_listener, hid_listener); -ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed); -ZMK_SUBSCRIPTION(hid_listener, zmk_mouse_state_changed); +ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed); \ No newline at end of file diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c new file mode 100644 index 00000000..6a96fbaa --- /dev/null +++ b/app/src/mouse/key_listener.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct vector2d move_speed = {0}; +static struct vector2d scroll_speed = {0}; +static struct mouse_config move_config = {0}; +static struct mouse_config scroll_config = {0}; + +static void clear_mouse_state() { + move_speed = (struct vector2d){0}; + scroll_speed = (struct vector2d){0}; +} + +static void mouse_tick_timer_handler(struct k_work *work) { + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + ZMK_EVENT_RAISE(zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config)); + zmk_endpoints_send_mouse_report(); +} + +K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler); + +void mouse_timer_cb(struct k_timer *dummy) { k_work_submit(&mouse_tick); } + +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_timer_cb); + +static int mouse_timer_ref_count = 0; + +void mouse_timer_ref() { + if (mouse_timer_ref_count == 0) { + k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(10)); + } + mouse_timer_ref_count += 1; + // trigger the first mouse tick event immediately + mouse_tick_timer_handler(NULL); +} + +void mouse_timer_unref() { + if (mouse_timer_ref_count > 0) { + mouse_timer_ref_count--; + } + if (mouse_timer_ref_count == 0) { + k_timer_stop(&mouse_timer); + clear_mouse_state(); + } +} + +static void listener_mouse_move_pressed(const struct zmk_mouse_move_state_changed *ev) { + move_speed.x += ev->max_speed.x; + move_speed.y += ev->max_speed.y; + mouse_timer_ref(); +} + +static void listener_mouse_move_released(const struct zmk_mouse_move_state_changed *ev) { + move_speed.x -= ev->max_speed.x; + move_speed.y -= ev->max_speed.y; + mouse_timer_unref(); +} + +static void listener_mouse_scroll_pressed(const struct zmk_mouse_scroll_state_changed *ev) { + scroll_speed.x += ev->max_speed.x; + scroll_speed.y += ev->max_speed.y; + mouse_timer_ref(); +} + +static void listener_mouse_scroll_released(const struct zmk_mouse_scroll_state_changed *ev) { + scroll_speed.x -= ev->max_speed.x; + scroll_speed.y -= ev->max_speed.y; + mouse_timer_unref(); +} + +static void listener_mouse_button_pressed(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_press(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +static void listener_mouse_button_released(const struct zmk_mouse_button_state_changed *ev) { + LOG_DBG("buttons: 0x%02X", ev->buttons); + zmk_hid_mouse_buttons_release(ev->buttons); + zmk_endpoints_send_mouse_report(); +} + +int mouse_listener(const zmk_event_t *eh) { + const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh); + if (mmv_ev) { + if (mmv_ev->state) { + listener_mouse_move_pressed(mmv_ev); + } else { + listener_mouse_move_released(mmv_ev); + } + return 0; + } + const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh); + if (msc_ev) { + if (msc_ev->state) { + listener_mouse_scroll_pressed(msc_ev); + } else { + listener_mouse_scroll_released(msc_ev); + } + return 0; + } + const struct zmk_mouse_button_state_changed *mbt_ev = as_zmk_mouse_button_state_changed(eh); + if (mbt_ev) { + if (mbt_ev->state) { + listener_mouse_button_pressed(mbt_ev); + } else { + listener_mouse_button_released(mbt_ev); + } + return 0; + } + return 0; +} + +ZMK_LISTENER(mouse_listener, mouse_listener); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_button_state_changed); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_move_state_changed); +ZMK_SUBSCRIPTION(mouse_listener, zmk_mouse_scroll_state_changed); diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c new file mode 100644 index 00000000..a80b6069 --- /dev/null +++ b/app/src/mouse/tick_listener.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include + +#include + +// CLAMP will be provided by sys/util.h from zephyr 2.6 onward +#define CLAMP(x, min, max) MIN(MAX(x, min), max) + +#if CONFIG_MINIMAL_LIBC +static float powf(float base, float exponent) { + // poor man's power implementation rounds the exponent down to the nearest integer. + LOG_DBG("falling back to integer exponent %d instead of %f", (int)exponent, exponent); + float power = 1.0f; + for (; exponent < 1.0f; exponent--) { + power = power * base; + } + return power; +} +#else +#include +#endif + +struct movement_state { + int64_t start; + int64_t last_tick; + struct vector2d fractional_remainder; +}; + +struct movement_state move_state = {0}; +static struct mouse_config move_config = (struct mouse_config){ + .delay_ms = 0, + .time_to_max_speed_ms = 300, + .acceleration_exponent = 2.0, +}; + +struct movement_state scroll_state = {0}; +static struct mouse_config scroll_config = (struct mouse_config){ + .delay_ms = 0, + .time_to_max_speed_ms = 300, + .acceleration_exponent = 2.0, +}; + +static int64_t ms_since_last_tick(int64_t last_tick, int64_t now) { return now - last_tick; } + +static int64_t ms_since_start(int64_t start, int64_t now) { + int64_t move_duration = now - start; + // start can be in the future if there's a delay + if (move_duration < 0) { + move_duration = 0; + } + return move_duration; +} + +static float speed(struct mouse_config *config, float max_speed, int64_t duration_ms) { + // Calculate the speed based on MouseKeysAccel + // See https://en.wikipedia.org/wiki/Mouse_keys + if (duration_ms > config->time_to_max_speed_ms) { + return max_speed; + } + float time_fraction = (float)duration_ms / config->time_to_max_speed_ms; + return max_speed * powf(time_fraction, config->acceleration_exponent); +} + +static void track_remainder(float *move, float *remainder) { + float new_move = *move + *remainder; + *remainder = new_move - (int)new_move; + *move = (int)new_move; +} + +static struct vector2d update_movement(struct movement_state *state, struct mouse_config *config, + struct vector2d max_speed, int64_t now) { + struct vector2d move = {0}; + if (max_speed.x == 0 && max_speed.y == 0) { + *state = (struct movement_state){0}; + return move; + } + if (state->start == 0) { + state->start = now + config->delay_ms; + state->last_tick = now; + } + + int64_t tick_duration = ms_since_last_tick(state->last_tick, now); + int64_t move_duration = ms_since_start(state->start, now); + move = (struct vector2d){ + .x = speed(config, max_speed.x, move_duration) * tick_duration / 1000, + .y = speed(config, max_speed.y, move_duration) * tick_duration / 1000, + }; + + track_remainder(&(move.x), &state->fractional_remainder.x); + track_remainder(&(move.y), &state->fractional_remainder.y); + + state->last_tick = now; + return move; +} + +static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { + struct vector2d move = + update_movement(&move_state, &move_config, tick->max_move, tick->timestamp); + zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), + (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); + struct vector2d scroll = + update_movement(&scroll_state, &scroll_config, tick->max_scroll, tick->timestamp); + zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), + (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); +} + +int zmk_mouse_tick_listener(const zmk_event_t *eh) { + const struct zmk_mouse_tick *tick = as_zmk_mouse_tick(eh); + if (tick) { + mouse_tick_handler(tick); + return 0; + } + return 0; +} + +ZMK_LISTENER(zmk_mouse_tick_listener, zmk_mouse_tick_listener); +ZMK_SUBSCRIPTION(zmk_mouse_tick_listener, zmk_mouse_tick); \ No newline at end of file diff --git a/app/tests/mouse-keys/mmv/events.patterns b/app/tests/mouse-keys/mmv/events.patterns new file mode 100644 index 00000000..833100f6 --- /dev/null +++ b/app/tests/mouse-keys/mmv/events.patterns @@ -0,0 +1 @@ +s/.*hid_listener_keycode_//p \ No newline at end of file diff --git a/app/tests/mouse-keys/mmv/keycode_events.snapshot b/app/tests/mouse-keys/mmv/keycode_events.snapshot new file mode 100644 index 00000000..259501ba --- /dev/null +++ b/app/tests/mouse-keys/mmv/keycode_events.snapshot @@ -0,0 +1,2 @@ +pressed: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 +released: usage_page 0x07 keycode 0x05 implicit_mods 0x00 explicit_mods 0x00 diff --git a/app/tests/mouse-keys/mmv/native_posix.keymap b/app/tests/mouse-keys/mmv/native_posix.keymap new file mode 100644 index 00000000..ecf06601 --- /dev/null +++ b/app/tests/mouse-keys/mmv/native_posix.keymap @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &mmv MOVE_LEFT &none + &none &none + >; + }; + }; +}; + + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_RELEASE(0,0,10) + >; +}; \ No newline at end of file diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md index e3b74048..fec7e2c6 100644 --- a/docs/docs/behaviors/mouse-emulation.md +++ b/docs/docs/behaviors/mouse-emulation.md @@ -5,7 +5,7 @@ sidebar_label: Mouse Emulation ## Summary -Mouse emulation behaviors send mouse movements, button presses or wheel actions. +Mouse emulation behaviors send mouse movements, button presses or scroll actions. Please view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list of signals. @@ -19,7 +19,7 @@ provided by ZMK near the top: #include ``` -Doing so allows using a set of defines such as `MOVE_UP`, `MOVE_DOWN`, `LCLK` and `WHEEL_UP` with these behaviors. +Doing so allows using a set of defines such as `MOVE_UP`, `MOVE_DOWN`, `LCLK` and `SCROLL_UP` with these behaviors. ## Mouse Button Press @@ -65,5 +65,5 @@ This behaviour is used to scroll, both horizontally and vertically. Example: ``` -&mwh WHEEL_UP +&mwh SCROLL_UP ``` From 30581f720761852d2ad71d1d0f34a641f64184dc Mon Sep 17 00:00:00 2001 From: krikun98 Date: Fri, 27 Aug 2021 01:31:30 +0300 Subject: [PATCH 22/35] Added dedicated mouse work queue option --- app/CMakeLists.txt | 1 + app/Kconfig | 7 +++++++ app/include/zmk/mouse.h | 3 +++ app/src/main.c | 4 ++++ app/src/mouse/Kconfig | 34 +++++++++++++++++++++++++++++++++ app/src/mouse/key_listener.c | 6 ++++-- app/src/mouse/main.c | 37 ++++++++++++++++++++++++++++++++++++ 7 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 app/src/mouse/Kconfig create mode 100644 app/src/mouse/main.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b08fd637..b70ba2f0 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -28,6 +28,7 @@ target_sources(app PRIVATE src/kscan.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/hid.c) target_sources(app PRIVATE src/mouse/key_listener.c) +target_sources(app PRIVATE src/mouse/main.c) target_sources(app PRIVATE src/mouse/tick_listener.c) target_sources(app PRIVATE src/sensors.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c) diff --git a/app/Kconfig b/app/Kconfig index 44259149..db3d8bfc 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -326,6 +326,13 @@ endif #Display/LED Options endmenu +menu "Mouse Options" + +rsource "src/mouse/Kconfig" + +#Mouse Options +endmenu + menu "Power Management" config ZMK_IDLE_TIMEOUT diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index 93d96df9..1e974f4b 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -25,3 +25,6 @@ struct vector2d { float x; float y; }; + +struct k_work_q *zmk_mouse_work_q(); +int zmk_mouse_init(); \ No newline at end of file diff --git a/app/src/main.c b/app/src/main.c index ae604a7b..62c71437 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -29,4 +29,8 @@ void main(void) { #ifdef CONFIG_ZMK_DISPLAY zmk_display_init(); #endif /* CONFIG_ZMK_DISPLAY */ + +#ifdef CONFIG_ZMK_MOUSE + zmk_mouse_init(); +#endif /* CONFIG_ZMK_MOUSE */ } diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig new file mode 100644 index 00000000..c440de58 --- /dev/null +++ b/app/src/mouse/Kconfig @@ -0,0 +1,34 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +menuconfig ZMK_MOUSE + bool "Enable ZMK mouse emulation" + default n + +if ZMK_MOUSE + +choice ZMK_MOUSE_WORK_QUEUE + prompt "Work queue selection for mouse events" + default ZMK_MOUSE_WORK_QUEUE_DEDICATED + +config ZMK_MOUSE_WORK_QUEUE_SYSTEM + bool "Use default system work queue for mouse events" + +config ZMK_MOUSE_WORK_QUEUE_DEDICATED + bool "Use dedicated work queue for mouse events" + +endchoice + +if ZMK_MOUSE_WORK_QUEUE_DEDICATED + +config ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE + int "Stack size for dedicated mouse thread/queue" + default 2048 + +config ZMK_MOUSE_DEDICATED_THREAD_PRIORITY + int "Thread priority for dedicated mouse thread/queue" + default 5 + +endif # ZMK_MOUSE_WORK_QUEUE_DEDICATED + +endif diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c index 6a96fbaa..d522ca9e 100644 --- a/app/src/mouse/key_listener.c +++ b/app/src/mouse/key_listener.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2021 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -37,7 +37,9 @@ static void mouse_tick_timer_handler(struct k_work *work) { K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler); -void mouse_timer_cb(struct k_timer *dummy) { k_work_submit(&mouse_tick); } +void mouse_timer_cb(struct k_timer *dummy) { + k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); +} K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_timer_cb); diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c new file mode 100644 index 00000000..7ba27c39 --- /dev/null +++ b/app/src/mouse/main.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + +K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE); + +static struct k_work_q mouse_work_q; + +struct k_work_q *zmk_mouse_work_q() { + return &mouse_work_q; +} + +#else + +struct k_work_q *zmk_mouse_work_q() { + return &k_sys_work_q; +} + +#endif + +int zmk_mouse_init() { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + k_work_q_start(&mouse_work_q, mouse_work_stack_area, + K_THREAD_STACK_SIZEOF(mouse_work_stack_area), + CONFIG_ZMK_MOUSE_DEDICATED_THREAD_PRIORITY); +#endif + return 0; +} \ No newline at end of file From c2c2961bfc5e1c6941012e94e6863d64bc062141 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Fri, 27 Aug 2021 03:19:57 +0300 Subject: [PATCH 23/35] Simplified tick rate and made it configurable --- app/src/mouse/Kconfig | 4 ++++ app/src/mouse/key_listener.c | 2 +- app/src/mouse/main.c | 3 --- app/src/mouse/tick_listener.c | 10 ++-------- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig index c440de58..213b305a 100644 --- a/app/src/mouse/Kconfig +++ b/app/src/mouse/Kconfig @@ -7,6 +7,10 @@ menuconfig ZMK_MOUSE if ZMK_MOUSE +config ZMK_MOUSE_TICK_DURATION + int "Mouse tick duration in ms" + default 8 + choice ZMK_MOUSE_WORK_QUEUE prompt "Work queue selection for mouse events" default ZMK_MOUSE_WORK_QUEUE_DEDICATED diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c index d522ca9e..4b8443f7 100644 --- a/app/src/mouse/key_listener.c +++ b/app/src/mouse/key_listener.c @@ -47,7 +47,7 @@ static int mouse_timer_ref_count = 0; void mouse_timer_ref() { if (mouse_timer_ref_count == 0) { - k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(10)); + k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); } mouse_timer_ref_count += 1; // trigger the first mouse tick event immediately diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c index 7ba27c39..a36b0047 100644 --- a/app/src/mouse/main.c +++ b/app/src/mouse/main.c @@ -5,9 +5,6 @@ */ #include -#include -#include -#include #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c index a80b6069..4aec26f4 100644 --- a/app/src/mouse/tick_listener.c +++ b/app/src/mouse/tick_listener.c @@ -34,7 +34,6 @@ static float powf(float base, float exponent) { struct movement_state { int64_t start; - int64_t last_tick; struct vector2d fractional_remainder; }; @@ -52,8 +51,6 @@ static struct mouse_config scroll_config = (struct mouse_config){ .acceleration_exponent = 2.0, }; -static int64_t ms_since_last_tick(int64_t last_tick, int64_t now) { return now - last_tick; } - static int64_t ms_since_start(int64_t start, int64_t now) { int64_t move_duration = now - start; // start can be in the future if there's a delay @@ -88,20 +85,17 @@ static struct vector2d update_movement(struct movement_state *state, struct mous } if (state->start == 0) { state->start = now + config->delay_ms; - state->last_tick = now; } - int64_t tick_duration = ms_since_last_tick(state->last_tick, now); int64_t move_duration = ms_since_start(state->start, now); move = (struct vector2d){ - .x = speed(config, max_speed.x, move_duration) * tick_duration / 1000, - .y = speed(config, max_speed.y, move_duration) * tick_duration / 1000, + .x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, + .y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, }; track_remainder(&(move.x), &state->fractional_remainder.x); track_remainder(&(move.y), &state->fractional_remainder.y); - state->last_tick = now; return move; } From a6d5ed15c9829b42e602d12c098e14ec9a1337c5 Mon Sep 17 00:00:00 2001 From: krikun98 Date: Tue, 31 Aug 2021 01:49:28 +0300 Subject: [PATCH 24/35] Add messages to BLE queue without a waiting interval --- app/src/hog.c | 8 +++----- app/src/mouse/key_listener.c | 4 +--- app/src/mouse/main.c | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/app/src/hog.c b/app/src/hog.c index 6b71c98f..259ab744 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -309,14 +309,12 @@ void send_mouse_report_callback(struct k_work *work) { 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)); + int err = k_msgq_put(&zmk_hog_mouse_msgq, report, K_NO_WAIT); if (err) { switch (err) { case -EAGAIN: { - LOG_WRN("Mouse 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); + LOG_WRN("Mouse message queue full, dropping report"); + return err; } default: LOG_WRN("Failed to queue mouse report to send (%d)", err); diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c index 4b8443f7..37fb3551 100644 --- a/app/src/mouse/key_listener.c +++ b/app/src/mouse/key_listener.c @@ -41,7 +41,7 @@ void mouse_timer_cb(struct k_timer *dummy) { k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); } -K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_timer_cb); +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, NULL); static int mouse_timer_ref_count = 0; @@ -50,8 +50,6 @@ void mouse_timer_ref() { k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); } mouse_timer_ref_count += 1; - // trigger the first mouse tick event immediately - mouse_tick_timer_handler(NULL); } void mouse_timer_unref() { diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c index a36b0047..271417c1 100644 --- a/app/src/mouse/main.c +++ b/app/src/mouse/main.c @@ -5,6 +5,7 @@ */ #include +#include #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) From 775117d590f701094722c1df8df0ab970c114b2b Mon Sep 17 00:00:00 2001 From: krikun98 Date: Thu, 2 Sep 2021 04:09:07 +0300 Subject: [PATCH 25/35] Cleanup and acceleration fixes --- app/dts/behaviors/mouse_move.dtsi | 6 +- app/dts/behaviors/mouse_scroll.dtsi | 2 +- app/include/zmk/events/mouse_tick.h | 5 +- app/include/zmk/mouse.h | 2 +- app/src/behaviors/behavior_mouse_key_press.c | 6 +- app/src/behaviors/behavior_mouse_move.c | 8 +-- app/src/behaviors/behavior_mouse_scroll.c | 8 +-- app/src/endpoints.c | 1 - app/src/main.c | 4 ++ app/src/mouse/key_listener.c | 35 ++++++++++-- app/src/mouse/main.c | 21 +++---- app/src/mouse/tick_listener.c | 58 +++++++------------- 12 files changed, 80 insertions(+), 76 deletions(-) diff --git a/app/dts/behaviors/mouse_move.dtsi b/app/dts/behaviors/mouse_move.dtsi index 858c5617..d34329c8 100644 --- a/app/dts/behaviors/mouse_move.dtsi +++ b/app/dts/behaviors/mouse_move.dtsi @@ -4,9 +4,9 @@ compatible = "zmk,behavior-mouse-move"; label = "MOUSE_MOVE"; #binding-cells = <1>; - delay-ms = <100>; - time-to-max-speed-ms = <1000>; - acceleration-exponent = <2000>; + delay-ms = <0>; + time-to-max-speed-ms = <300>; + acceleration-exponent = <1>; }; }; }; diff --git a/app/dts/behaviors/mouse_scroll.dtsi b/app/dts/behaviors/mouse_scroll.dtsi index 931124ce..fb54886d 100644 --- a/app/dts/behaviors/mouse_scroll.dtsi +++ b/app/dts/behaviors/mouse_scroll.dtsi @@ -5,7 +5,7 @@ label = "MOUSE_SCROLL"; #binding-cells = <1>; delay-ms = <0>; - time-to-max-speed-ms = <1000>; + time-to-max-speed-ms = <300>; acceleration-exponent = <0>; }; }; diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h index 6307b5eb..1c78dc8c 100644 --- a/app/include/zmk/events/mouse_tick.h +++ b/app/include/zmk/events/mouse_tick.h @@ -17,6 +17,7 @@ struct zmk_mouse_tick { struct vector2d max_scroll; struct mouse_config move_config; struct mouse_config scroll_config; + int64_t* start_time; int64_t timestamp; }; @@ -25,12 +26,14 @@ ZMK_EVENT_DECLARE(zmk_mouse_tick); static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_move, struct vector2d max_scroll, struct mouse_config move_config, - struct mouse_config scroll_config) { + struct mouse_config scroll_config, + int64_t* movement_start) { return new_zmk_mouse_tick((struct zmk_mouse_tick){ .max_move = max_move, .max_scroll = max_scroll, .move_config = move_config, .scroll_config = scroll_config, + .start_time = movement_start, .timestamp = k_uptime_get(), }); } diff --git a/app/include/zmk/mouse.h b/app/include/zmk/mouse.h index 1e974f4b..f8f85744 100644 --- a/app/include/zmk/mouse.h +++ b/app/include/zmk/mouse.h @@ -18,7 +18,7 @@ struct mouse_config { // acceleration exponent 0: uniform speed // acceleration exponent 1: uniform acceleration // acceleration exponent 2: uniform jerk - float acceleration_exponent; + int acceleration_exponent; }; struct vector2d { diff --git a/app/src/behaviors/behavior_mouse_key_press.c b/app/src/behaviors/behavior_mouse_key_press.c index 6da2a8c4..e5f2709c 100644 --- a/app/src/behaviors/behavior_mouse_key_press.c +++ b/app/src/behaviors/behavior_mouse_key_press.c @@ -39,9 +39,9 @@ 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 KP_INST(n) \ - DEVICE_AND_API_INIT( \ - behavior_mouse_key_press_##n, DT_INST_LABEL(n), behavior_mouse_key_press_init, NULL, NULL, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_key_press_driver_api); + DEVICE_DT_INST_DEFINE(n, behavior_mouse_key_press_init, device_pm_control_nop, NULL, NULL, \ + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &behavior_mouse_key_press_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/behaviors/behavior_mouse_move.c b/app/src/behaviors/behavior_mouse_move.c index 92ea3d86..5977a039 100644 --- a/app/src/behaviors/behavior_mouse_move.c +++ b/app/src/behaviors/behavior_mouse_move.c @@ -46,11 +46,11 @@ static const struct behavior_driver_api behavior_mouse_move_driver_api = { static struct mouse_config behavior_mouse_move_config_##n = { \ .delay_ms = DT_INST_PROP(n, delay_ms), \ .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ - .acceleration_exponent = (float)DT_INST_PROP(n, acceleration_exponent) / 1000.0f, \ + .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ }; \ - DEVICE_AND_API_INIT(behavior_mouse_move_##n, DT_INST_LABEL(n), behavior_mouse_move_init, NULL, \ - &behavior_mouse_move_config_##n, APPLICATION, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); + DEVICE_DT_INST_DEFINE(n, behavior_mouse_move_init, device_pm_control_nop, NULL, \ + &behavior_mouse_move_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_move_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/behaviors/behavior_mouse_scroll.c b/app/src/behaviors/behavior_mouse_scroll.c index e347d8af..64162352 100644 --- a/app/src/behaviors/behavior_mouse_scroll.c +++ b/app/src/behaviors/behavior_mouse_scroll.c @@ -47,11 +47,11 @@ static const struct behavior_driver_api behavior_mouse_scroll_driver_api = { static struct mouse_config behavior_mouse_scroll_config_##n = { \ .delay_ms = DT_INST_PROP(n, delay_ms), \ .time_to_max_speed_ms = DT_INST_PROP(n, time_to_max_speed_ms), \ - .acceleration_exponent = (float)DT_INST_PROP(n, acceleration_exponent) / 1000.0f, \ + .acceleration_exponent = DT_INST_PROP(n, acceleration_exponent), \ }; \ - DEVICE_AND_API_INIT(behavior_mouse_scroll_##n, DT_INST_LABEL(n), behavior_mouse_scroll_init, \ - NULL, &behavior_mouse_scroll_config_##n, APPLICATION, \ - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); + DEVICE_DT_INST_DEFINE(n, behavior_mouse_scroll_init, device_pm_control_nop, NULL, \ + &behavior_mouse_scroll_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mouse_scroll_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) diff --git a/app/src/endpoints.c b/app/src/endpoints.c index d40396c8..3e025291 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -146,7 +146,6 @@ int zmk_endpoints_send_report(uint16_t usage_page) { } int zmk_endpoints_send_mouse_report() { - LOG_DBG("SENDING MOUSE REPORT"); struct zmk_hid_mouse_report *mouse_report = zmk_hid_get_mouse_report(); switch (current_endpoint) { diff --git a/app/src/main.c b/app/src/main.c index 62c71437..d3b3e578 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -17,6 +17,10 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#ifdef CONFIG_ZMK_MOUSE +#include +#endif /* CONFIG_ZMK_MOUSE */ + #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) void main(void) { diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c index 37fb3551..56a84b45 100644 --- a/app/src/mouse/key_listener.c +++ b/app/src/mouse/key_listener.c @@ -20,18 +20,36 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static struct vector2d move_speed = {0}; static struct vector2d scroll_speed = {0}; -static struct mouse_config move_config = {0}; -static struct mouse_config scroll_config = {0}; +static struct mouse_config move_config = (struct mouse_config){0}; +static struct mouse_config scroll_config = (struct mouse_config){0}; +static int64_t start_time = 0; -static void clear_mouse_state() { +bool equals(const struct mouse_config *one, const struct mouse_config *other) { + return one->delay_ms == other->delay_ms && + one->time_to_max_speed_ms == other->time_to_max_speed_ms && + one->acceleration_exponent == other->acceleration_exponent; +} + +static void clear_mouse_state(struct k_work *work) { move_speed = (struct vector2d){0}; scroll_speed = (struct vector2d){0}; + start_time = 0; + zmk_hid_mouse_movement_set(0, 0); + zmk_hid_mouse_scroll_set(0, 0); + LOG_DBG("Clearing state"); +} + +K_WORK_DEFINE(mouse_clear, &clear_mouse_state); + +void mouse_clear_cb(struct k_timer *dummy) { + k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_clear); } static void mouse_tick_timer_handler(struct k_work *work) { zmk_hid_mouse_movement_set(0, 0); zmk_hid_mouse_scroll_set(0, 0); - ZMK_EVENT_RAISE(zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config)); + LOG_DBG("Raising mouse tick event"); + ZMK_EVENT_RAISE(zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time)); zmk_endpoints_send_mouse_report(); } @@ -41,12 +59,13 @@ void mouse_timer_cb(struct k_timer *dummy) { k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); } -K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, NULL); +K_TIMER_DEFINE(mouse_timer, mouse_timer_cb, mouse_clear_cb); static int mouse_timer_ref_count = 0; void mouse_timer_ref() { if (mouse_timer_ref_count == 0) { + start_time = k_uptime_get(); k_timer_start(&mouse_timer, K_NO_WAIT, K_MSEC(CONFIG_ZMK_MOUSE_TICK_DURATION)); } mouse_timer_ref_count += 1; @@ -58,7 +77,6 @@ void mouse_timer_unref() { } if (mouse_timer_ref_count == 0) { k_timer_stop(&mouse_timer); - clear_mouse_state(); } } @@ -101,6 +119,9 @@ static void listener_mouse_button_released(const struct zmk_mouse_button_state_c int mouse_listener(const zmk_event_t *eh) { const struct zmk_mouse_move_state_changed *mmv_ev = as_zmk_mouse_move_state_changed(eh); if (mmv_ev) { + if (!equals(&move_config, &(mmv_ev->config))) + move_config = mmv_ev->config; + if (mmv_ev->state) { listener_mouse_move_pressed(mmv_ev); } else { @@ -110,6 +131,8 @@ int mouse_listener(const zmk_event_t *eh) { } const struct zmk_mouse_scroll_state_changed *msc_ev = as_zmk_mouse_scroll_state_changed(eh); if (msc_ev) { + if (!equals(&scroll_config, &(msc_ev->config))) + scroll_config = msc_ev->config; if (msc_ev->state) { listener_mouse_scroll_pressed(msc_ev); } else { diff --git a/app/src/mouse/main.c b/app/src/mouse/main.c index 271417c1..49208a76 100644 --- a/app/src/mouse/main.c +++ b/app/src/mouse/main.c @@ -8,23 +8,18 @@ #include #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) - K_THREAD_STACK_DEFINE(mouse_work_stack_area, CONFIG_ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE); - static struct k_work_q mouse_work_q; - -struct k_work_q *zmk_mouse_work_q() { - return &mouse_work_q; -} - -#else - -struct k_work_q *zmk_mouse_work_q() { - return &k_sys_work_q; -} - #endif +struct k_work_q *zmk_mouse_work_q() { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + return &mouse_work_q; +#else + return &k_sys_work_q; +#endif +} + int zmk_mouse_init() { #if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) k_work_q_start(&mouse_work_q, mouse_work_stack_area, diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c index 4aec26f4..a1459384 100644 --- a/app/src/mouse/tick_listener.c +++ b/app/src/mouse/tick_listener.c @@ -13,17 +13,13 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include -#include - -// CLAMP will be provided by sys/util.h from zephyr 2.6 onward -#define CLAMP(x, min, max) MIN(MAX(x, min), max) +#include // CLAMP #if CONFIG_MINIMAL_LIBC static float powf(float base, float exponent) { // poor man's power implementation rounds the exponent down to the nearest integer. - LOG_DBG("falling back to integer exponent %d instead of %f", (int)exponent, exponent); float power = 1.0f; - for (; exponent < 1.0f; exponent--) { + for (; exponent >= 1.0f; exponent--) { power = power * base; } return power; @@ -32,27 +28,11 @@ static float powf(float base, float exponent) { #include #endif -struct movement_state { - int64_t start; - struct vector2d fractional_remainder; -}; +struct vector2d move_remainder = {0}; +struct vector2d scroll_remainder = {0}; -struct movement_state move_state = {0}; -static struct mouse_config move_config = (struct mouse_config){ - .delay_ms = 0, - .time_to_max_speed_ms = 300, - .acceleration_exponent = 2.0, -}; - -struct movement_state scroll_state = {0}; -static struct mouse_config scroll_config = (struct mouse_config){ - .delay_ms = 0, - .time_to_max_speed_ms = 300, - .acceleration_exponent = 2.0, -}; - -static int64_t ms_since_start(int64_t start, int64_t now) { - int64_t move_duration = now - start; +static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) { + int64_t move_duration = now - (start + delay); // start can be in the future if there's a delay if (move_duration < 0) { move_duration = 0; @@ -60,10 +40,12 @@ static int64_t ms_since_start(int64_t start, int64_t now) { return move_duration; } -static float speed(struct mouse_config *config, float max_speed, int64_t duration_ms) { +static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) { // Calculate the speed based on MouseKeysAccel // See https://en.wikipedia.org/wiki/Mouse_keys - if (duration_ms > config->time_to_max_speed_ms) { + 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; @@ -76,36 +58,34 @@ static void track_remainder(float *move, float *remainder) { *move = (int)new_move; } -static struct vector2d update_movement(struct movement_state *state, struct mouse_config *config, - struct vector2d max_speed, int64_t now) { +static struct vector2d update_movement(struct vector2d *remainder, + const struct mouse_config *config, struct vector2d max_speed, + int64_t now, int64_t *start_time) { struct vector2d move = {0}; if (max_speed.x == 0 && max_speed.y == 0) { - *state = (struct movement_state){0}; + *remainder = (struct vector2d){0}; return move; } - if (state->start == 0) { - state->start = now + config->delay_ms; - } - int64_t move_duration = ms_since_start(state->start, now); + int64_t move_duration = ms_since_start(*start_time, now, config->delay_ms); move = (struct vector2d){ .x = speed(config, max_speed.x, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, .y = speed(config, max_speed.y, move_duration) * CONFIG_ZMK_MOUSE_TICK_DURATION / 1000, }; - track_remainder(&(move.x), &state->fractional_remainder.x); - track_remainder(&(move.y), &state->fractional_remainder.y); + track_remainder(&(move.x), &(remainder->x)); + track_remainder(&(move.y), &(remainder->y)); return move; } static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { struct vector2d move = - update_movement(&move_state, &move_config, tick->max_move, tick->timestamp); + update_movement(&move_remainder, &(tick->move_config), tick->max_move, tick->timestamp, tick->start_time); zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); struct vector2d scroll = - update_movement(&scroll_state, &scroll_config, tick->max_scroll, tick->timestamp); + update_movement(&scroll_remainder, &(tick->scroll_config), tick->max_scroll, tick->timestamp, tick->start_time); zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); } From c6c4e9b53105e07547c241615bfbf52a478df10d Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Wed, 22 Sep 2021 00:27:52 +0300 Subject: [PATCH 26/35] Send mouse messages from dedicated thread --- app/src/endpoints.c | 4 ++++ app/src/hog.c | 23 +++++++++++++++++++++++ app/src/mouse/Kconfig | 2 +- app/src/mouse/key_listener.c | 4 +++- app/src/mouse/tick_listener.c | 13 ++++++------- 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 3e025291..7aabc5d4 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -161,7 +161,11 @@ int zmk_endpoints_send_mouse_report() { #if IS_ENABLED(CONFIG_ZMK_BLE) case ZMK_ENDPOINT_BLE: { +#if IS_ENABLED(CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED) + int err = zmk_hog_send_mouse_report_direct(&mouse_report->body); +#else int err = zmk_hog_send_mouse_report(&mouse_report->body); +#endif if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); } diff --git a/app/src/hog.c b/app/src/hog.c index 259ab744..e607e8c4 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -327,6 +327,29 @@ int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *report) { return 0; }; +int zmk_hog_send_mouse_report_direct(struct zmk_hid_mouse_report_body *report) { + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return 1; + } + + 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) { + LOG_DBG("Error notifying %d", err); + return err; + } + + bt_conn_unref(conn); + + return 0; +}; + int zmk_hog_init(const struct device *_arg) { k_work_q_start(&hog_work_q, hog_q_stack, K_THREAD_STACK_SIZEOF(hog_q_stack), CONFIG_ZMK_BLE_THREAD_PRIORITY); diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig index 213b305a..57c57a4f 100644 --- a/app/src/mouse/Kconfig +++ b/app/src/mouse/Kconfig @@ -31,7 +31,7 @@ config ZMK_MOUSE_DEDICATED_THREAD_STACK_SIZE config ZMK_MOUSE_DEDICATED_THREAD_PRIORITY int "Thread priority for dedicated mouse thread/queue" - default 5 + default 3 endif # ZMK_MOUSE_WORK_QUEUE_DEDICATED diff --git a/app/src/mouse/key_listener.c b/app/src/mouse/key_listener.c index 56a84b45..713d0323 100644 --- a/app/src/mouse/key_listener.c +++ b/app/src/mouse/key_listener.c @@ -49,13 +49,15 @@ static void mouse_tick_timer_handler(struct k_work *work) { zmk_hid_mouse_movement_set(0, 0); zmk_hid_mouse_scroll_set(0, 0); LOG_DBG("Raising mouse tick event"); - ZMK_EVENT_RAISE(zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time)); + ZMK_EVENT_RAISE( + zmk_mouse_tick(move_speed, scroll_speed, move_config, scroll_config, &start_time)); zmk_endpoints_send_mouse_report(); } K_WORK_DEFINE(mouse_tick, &mouse_tick_timer_handler); void mouse_timer_cb(struct k_timer *dummy) { + LOG_DBG("Submitting mouse work to queue"); k_work_submit_to_queue(zmk_mouse_work_q(), &mouse_tick); } diff --git a/app/src/mouse/tick_listener.c b/app/src/mouse/tick_listener.c index a1459384..9c76bd5d 100644 --- a/app/src/mouse/tick_listener.c +++ b/app/src/mouse/tick_listener.c @@ -43,9 +43,8 @@ static int64_t ms_since_start(int64_t start, int64_t now, int64_t delay) { static float speed(const struct mouse_config *config, float max_speed, int64_t duration_ms) { // Calculate the speed based on MouseKeysAccel // See https://en.wikipedia.org/wiki/Mouse_keys - if (duration_ms > config->time_to_max_speed_ms - || config->time_to_max_speed_ms == 0 - || config->acceleration_exponent == 0) { + 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; @@ -80,12 +79,12 @@ static struct vector2d update_movement(struct vector2d *remainder, } static void mouse_tick_handler(const struct zmk_mouse_tick *tick) { - struct vector2d move = - update_movement(&move_remainder, &(tick->move_config), tick->max_move, tick->timestamp, tick->start_time); + struct vector2d move = update_movement(&move_remainder, &(tick->move_config), tick->max_move, + tick->timestamp, tick->start_time); zmk_hid_mouse_movement_update((int16_t)CLAMP(move.x, INT16_MIN, INT16_MAX), (int16_t)CLAMP(move.y, INT16_MIN, INT16_MAX)); - struct vector2d scroll = - update_movement(&scroll_remainder, &(tick->scroll_config), tick->max_scroll, tick->timestamp, tick->start_time); + struct vector2d scroll = update_movement(&scroll_remainder, &(tick->scroll_config), + tick->max_scroll, tick->timestamp, tick->start_time); zmk_hid_mouse_scroll_update((int8_t)CLAMP(scroll.x, INT8_MIN, INT8_MAX), (int8_t)CLAMP(scroll.y, INT8_MIN, INT8_MAX)); } From 7580668d970df8162683c42e80e4ad8c2b23ae49 Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Thu, 23 Sep 2021 21:04:47 +0300 Subject: [PATCH 27/35] Added documentation for new features --- docs/docs/behaviors/mouse-emulation.md | 39 +++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md index fec7e2c6..a2364656 100644 --- a/docs/docs/behaviors/mouse-emulation.md +++ b/docs/docs/behaviors/mouse-emulation.md @@ -9,6 +9,20 @@ Mouse emulation behaviors send mouse movements, button presses or scroll actions Please view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/mouse.h) for a comprehensive list of signals. +## Configuration options + +This feature should be enabled via a config option: +``` +CONFIG_ZMK_MOUSE=y +``` +This option enables several others. + +### Dedicated thread processing +`CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED` is enabled by default and separates the processing of mouse signals into a dedicated thread, significantly improving performance. + +### Tick rate configuration +`CONFIG_ZMK_MOUSE_TICK_DURATION` sets the tick rate for mouse polling. It is set to 8 ms. by default. + ## Keycode Defines To make it easier to encode the HID keycode numeric values, most keymaps include @@ -52,7 +66,7 @@ Example: &mmv MOVE_UP ``` -## Mouse Wheel +## Mouse Scrolling This behaviour is used to scroll, both horizontally and vertically. @@ -67,3 +81,26 @@ Example: ``` &mwh SCROLL_UP ``` + +## Acceleration + +Both mouse movement and scrolling have independently configurable acceleration profiles with three parameters: delay before movement, time to max speed and the acceleration exponent. +The exponent is usually set to 0 for constant speed, 1 for uniform acceleration or 2 for uniform jerk. + +These profiles can be configured inside your keymap: + +``` +&mmv { + time-to-max-speed-ms = <500>; +}; + +&mwh { + acceleration-exponent=<1>; +}; + +/ { + keymap { + ... + }; +}; +``` From 37ba47c20c3ee9b4873fd395e099fda3f192d7f5 Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Thu, 23 Sep 2021 21:30:43 +0300 Subject: [PATCH 28/35] Moved tick duration --- app/src/mouse/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/mouse/Kconfig b/app/src/mouse/Kconfig index 57c57a4f..1161b86b 100644 --- a/app/src/mouse/Kconfig +++ b/app/src/mouse/Kconfig @@ -5,12 +5,12 @@ menuconfig ZMK_MOUSE bool "Enable ZMK mouse emulation" default n -if ZMK_MOUSE - config ZMK_MOUSE_TICK_DURATION int "Mouse tick duration in ms" default 8 +if ZMK_MOUSE + choice ZMK_MOUSE_WORK_QUEUE prompt "Work queue selection for mouse events" default ZMK_MOUSE_WORK_QUEUE_DEDICATED From 5021a842cdd80802d0b5d6ba2cb622007b6452bd Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Thu, 23 Sep 2021 21:31:41 +0300 Subject: [PATCH 29/35] clang-format --- app/include/zmk/events/mouse_tick.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/include/zmk/events/mouse_tick.h b/app/include/zmk/events/mouse_tick.h index 1c78dc8c..c75b9b4f 100644 --- a/app/include/zmk/events/mouse_tick.h +++ b/app/include/zmk/events/mouse_tick.h @@ -17,7 +17,7 @@ struct zmk_mouse_tick { struct vector2d max_scroll; struct mouse_config move_config; struct mouse_config scroll_config; - int64_t* start_time; + int64_t *start_time; int64_t timestamp; }; @@ -27,7 +27,7 @@ static inline struct zmk_mouse_tick_event *zmk_mouse_tick(struct vector2d max_mo struct vector2d max_scroll, struct mouse_config move_config, struct mouse_config scroll_config, - int64_t* movement_start) { + int64_t *movement_start) { return new_zmk_mouse_tick((struct zmk_mouse_tick){ .max_move = max_move, .max_scroll = max_scroll, From 621ecc54503851383736477360d6c8faac4d5cbe Mon Sep 17 00:00:00 2001 From: Alexander Krikun Date: Thu, 23 Sep 2021 22:00:07 +0300 Subject: [PATCH 30/35] prettier --- docs/docs/behaviors/mouse-emulation.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/docs/behaviors/mouse-emulation.md b/docs/docs/behaviors/mouse-emulation.md index a2364656..efe095e7 100644 --- a/docs/docs/behaviors/mouse-emulation.md +++ b/docs/docs/behaviors/mouse-emulation.md @@ -12,16 +12,20 @@ Please view [`dt-bindings/zmk/mouse.h`](https://github.com/zmkfirmware/zmk/blob/ ## Configuration options This feature should be enabled via a config option: + ``` CONFIG_ZMK_MOUSE=y ``` + This option enables several others. ### Dedicated thread processing + `CONFIG_ZMK_MOUSE_WORK_QUEUE_DEDICATED` is enabled by default and separates the processing of mouse signals into a dedicated thread, significantly improving performance. ### Tick rate configuration -`CONFIG_ZMK_MOUSE_TICK_DURATION` sets the tick rate for mouse polling. It is set to 8 ms. by default. + +`CONFIG_ZMK_MOUSE_TICK_DURATION` sets the tick rate for mouse polling. It is set to 8 ms. by default. ## Keycode Defines From b9f900faa70920a55a6307ce4a7164e5a1c03a6a Mon Sep 17 00:00:00 2001 From: Cedric Vincent Date: Sat, 25 Sep 2021 12:06:43 +0200 Subject: [PATCH 31/35] feat(sensor): Add Pimoroni PIM447 trackball driver. --- app/drivers/sensor/CMakeLists.txt | 3 +- app/drivers/sensor/Kconfig | 3 +- .../sensor/trackball_pim447/CMakeLists.txt | 4 + app/drivers/sensor/trackball_pim447/Kconfig | 8 + .../trackball_pim447/trackball_pim447.c | 167 ++++++++++++++++++ 5 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 app/drivers/sensor/trackball_pim447/CMakeLists.txt create mode 100644 app/drivers/sensor/trackball_pim447/Kconfig create mode 100644 app/drivers/sensor/trackball_pim447/trackball_pim447.c diff --git a/app/drivers/sensor/CMakeLists.txt b/app/drivers/sensor/CMakeLists.txt index b549320f..d5e35e75 100644 --- a/app/drivers/sensor/CMakeLists.txt +++ b/app/drivers/sensor/CMakeLists.txt @@ -2,4 +2,5 @@ # SPDX-License-Identifier: MIT add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery) -add_subdirectory_ifdef(CONFIG_EC11 ec11) \ No newline at end of file +add_subdirectory_ifdef(CONFIG_EC11 ec11) +add_subdirectory_ifdef(CONFIG_ZMK_TRACKBALL_PIM447 trackball_pim447) diff --git a/app/drivers/sensor/Kconfig b/app/drivers/sensor/Kconfig index a828f6c6..fcf451a1 100644 --- a/app/drivers/sensor/Kconfig +++ b/app/drivers/sensor/Kconfig @@ -2,4 +2,5 @@ # SPDX-License-Identifier: MIT rsource "battery/Kconfig" -rsource "ec11/Kconfig" \ No newline at end of file +rsource "ec11/Kconfig" +rsource "trackball_pim447/Kconfig" diff --git a/app/drivers/sensor/trackball_pim447/CMakeLists.txt b/app/drivers/sensor/trackball_pim447/CMakeLists.txt new file mode 100644 index 00000000..03e20c65 --- /dev/null +++ b/app/drivers/sensor/trackball_pim447/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(trackball_pim447.c) diff --git a/app/drivers/sensor/trackball_pim447/Kconfig b/app/drivers/sensor/trackball_pim447/Kconfig new file mode 100644 index 00000000..ac837b93 --- /dev/null +++ b/app/drivers/sensor/trackball_pim447/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config ZMK_TRACKBALL_PIM447 + bool "ZMK PIM447 trackball" + depends on I2C + help + Enable I2C-based driver for Pimoroni PIM447 trackball. diff --git a/app/drivers/sensor/trackball_pim447/trackball_pim447.c b/app/drivers/sensor/trackball_pim447/trackball_pim447.c new file mode 100644 index 00000000..6efb1ef8 --- /dev/null +++ b/app/drivers/sensor/trackball_pim447/trackball_pim447.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT pimoroni_trackball_pim447 + +#include +#include + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +#include +LOG_MODULE_REGISTER(trackball_pim447); + +#define TRACKBALL_PIM447_REG_LEFT 0x04 +#define TRACKBALL_PIM447_REG_RIGHT 0x05 +#define TRACKBALL_PIM447_REG_UP 0x06 +#define TRACKBALL_PIM447_REG_DOWN 0x07 +#define TRACKBALL_PIM447_REG_SWITCH 0x08 + +#define TRACKBALL_PIM447_REG_MIN TRACKBALL_PIM447_REG_LEFT +#define TRACKBALL_PIM447_REG_MAX TRACKBALL_PIM447_REG_SWITCH + +struct trackball_pim447_data { + const struct device *i2c_dev; + int32_t dx; + int32_t dy; + int32_t dz; +}; + +static int trackball_pim447_read_reg(const struct device *dev, + uint8_t reg, uint8_t *value) +{ + struct trackball_pim447_data *data = dev->data; + + if (reg < TRACKBALL_PIM447_REG_MIN || reg > TRACKBALL_PIM447_REG_MAX) { + return -ENOTSUP; + } + + int status = i2c_reg_read_byte(data->i2c_dev, DT_INST_REG_ADDR(0), + reg, value); + if (status < 0) { + LOG_ERR("Sensor reg read byte failed"); + return status; + } + + return 0; +} + +static int trackball_pim447_read_axis(const struct device *dev, + uint8_t reg_negative, + uint8_t reg_positive, + int32_t *value) +{ + uint8_t value_negative; + uint8_t value_positive; + int status; + + status = trackball_pim447_read_reg(dev, reg_negative, &value_negative); + if (status < 0) { + return status; + } + + status = trackball_pim447_read_reg(dev, reg_positive, &value_positive); + if (status < 0) { + return status; + } + + *value = value_positive - value_negative; + + return 0; +} + +static int trackball_pim447_sample_fetch(const struct device *dev, + enum sensor_channel chan) +{ + struct trackball_pim447_data *data = dev->data; + int status; + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DX) { + status = trackball_pim447_read_axis(dev, + TRACKBALL_PIM447_REG_LEFT, + TRACKBALL_PIM447_REG_RIGHT, + &data->dx); + if (status < 0) { + return status; + } + } + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DY) { + status = trackball_pim447_read_axis(dev, + TRACKBALL_PIM447_REG_UP, + TRACKBALL_PIM447_REG_DOWN, + &data->dy); + if (status < 0) { + return status; + } + } + + if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DZ) { + uint8_t value; + status = trackball_pim447_read_reg(dev, + TRACKBALL_PIM447_REG_SWITCH, + &value); + if (status < 0) { + return status; + } + + data->dz = value; + } + + return 0; +} + +static int trackball_pim447_channel_get(const struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct trackball_pim447_data *data = dev->data; + + /* Not used. */ + val->val2 = 0; + + switch (chan) { + case SENSOR_CHAN_POS_DX: + val->val1 = data->dx; + break; + + case SENSOR_CHAN_POS_DY: + val->val1 = data->dy; + break; + + case SENSOR_CHAN_POS_DZ: + val->val1 = data->dz; + break; + + default: + return -ENOTSUP; + } + + return 0; +} + +static int trackball_pim447_init(const struct device *dev) +{ + struct trackball_pim447_data *data = dev->data; + + data->i2c_dev = device_get_binding(DT_INST_BUS_LABEL(0)); + if (data->i2c_dev == NULL) { + LOG_ERR("Failed to get I2C device"); + return -EINVAL; + } + + return 0; +} + +static struct trackball_pim447_data trackball_pim447_data; + +static const struct sensor_driver_api trackball_pim447_api = { + .sample_fetch = trackball_pim447_sample_fetch, + .channel_get = trackball_pim447_channel_get, +}; + +DEVICE_DT_INST_DEFINE(0, &trackball_pim447_init, device_pm_control_nop, + &trackball_pim447_data, NULL, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &trackball_pim447_api); From 7b45f80c7205279c0b9c40e4263ffb876130a847 Mon Sep 17 00:00:00 2001 From: Cedric Vincent Date: Tue, 28 Sep 2021 17:44:14 +0200 Subject: [PATCH 32/35] feat(mouse): Add support for PIM447 trackball. --- app/CMakeLists.txt | 1 + app/src/mouse/trackball_pim447.c | 132 +++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 app/src/mouse/trackball_pim447.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index b70ba2f0..f7c5e963 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -30,6 +30,7 @@ target_sources(app PRIVATE src/hid.c) target_sources(app PRIVATE src/mouse/key_listener.c) target_sources(app PRIVATE src/mouse/main.c) target_sources(app PRIVATE src/mouse/tick_listener.c) +target_sources_ifdef(CONFIG_ZMK_TRACKBALL_PIM447 app PRIVATE src/mouse/trackball_pim447.c) target_sources(app PRIVATE src/sensors.c) target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c) target_sources(app PRIVATE src/event_manager.c) diff --git a/app/src/mouse/trackball_pim447.c b/app/src/mouse/trackball_pim447.c new file mode 100644 index 00000000..ece68892 --- /dev/null +++ b/app/src/mouse/trackball_pim447.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021 Cedric VINCENT + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(PIM447, CONFIG_SENSOR_LOG_LEVEL); + +/* + * It feels more natural and more confortable to convert the speed + * reported by the PIM447 trackball. + */ +static int16_t convert_speed(int32_t value) +{ + bool negative = (value < 0); + + if (negative) { + value = -value; + } + + switch (value) { + case 0: value = 0; break; + case 1: value = 1; break; + case 2: value = 4; break; + case 3: value = 8; break; + case 4: value = 18; break; + case 5: value = 32; break; + case 6: value = 50; break; + case 7: value = 72; break; + case 8: value = 98; break; + default: value = 127; break; + } + + if (negative) { + value = -value; + } + + return value; +} + +static void thread_code(void *p1, void *p2, void *p3) +{ + const struct device *dev; + int result; + + /* PIM447 trackball initialization. */ + + const char *label = DT_LABEL(DT_INST(0, pimoroni_trackball_pim447)); + dev = device_get_binding(label); + if (dev == NULL) { + LOG_ERR("Cannot get TRACKBALL_PIM447 device"); + return; + } + + /* Event loop. */ + + bool button_press_sent = false; + bool button_release_sent = false; + + while (true) { + struct sensor_value pos_dx, pos_dy, pos_dz; + bool send_report = false; + + result = sensor_sample_fetch(dev); + if (result < 0) { + LOG_ERR("Failed to fetch TRACKBALL_PIM447 sample"); + return; + } + + result = sensor_channel_get(dev, SENSOR_CHAN_POS_DX, &pos_dx); + if (result < 0) { + LOG_ERR("Failed to get TRACKBALL_PIM447 pos_dx channel value"); + return; + } + + result = sensor_channel_get(dev, SENSOR_CHAN_POS_DY, &pos_dy); + if (result < 0) { + LOG_ERR("Failed to get TRACKBALL_PIM447 pos_dy channel value"); + return; + } + + result = sensor_channel_get(dev, SENSOR_CHAN_POS_DZ, &pos_dz); + if (result < 0) { + LOG_ERR("Failed to get TRACKBALL_PIM447 pos_dz channel value"); + return; + } + + if (pos_dx.val1 != 0 || pos_dy.val1 != 0) { + zmk_hid_mouse_movement_update(convert_speed(pos_dx.val1), + convert_speed(pos_dy.val1)); + send_report = true; + } + + if (pos_dz.val1 == 0x80 && button_press_sent == false) { + zmk_hid_mouse_button_press(0); + button_press_sent = true; + button_release_sent = false; + send_report = true; + } else if (pos_dz.val1 == 0x01 && button_release_sent == false) { + zmk_hid_mouse_button_release(0); + button_press_sent = false; + button_release_sent = true; + send_report = true; + } + + if (send_report) { + zmk_endpoints_send_mouse_report(); + zmk_hid_mouse_clear(); + } + + k_sleep(K_MSEC(10)); + } +} + +#define STACK_SIZE 1024 + +static K_THREAD_STACK_DEFINE(thread_stack, STACK_SIZE); +static struct k_thread thread; + +int zmk_trackball_pim447_init() +{ + k_thread_create(&thread, thread_stack, STACK_SIZE, thread_code, + NULL, NULL, NULL, K_PRIO_PREEMPT(8), 0, K_NO_WAIT); + return 0; +} + +SYS_INIT(zmk_trackball_pim447_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); From e907e032713de8fa44788040fc00513c0f72c64a Mon Sep 17 00:00:00 2001 From: Cedric VINCENT Date: Sun, 14 Nov 2021 18:52:11 +0100 Subject: [PATCH 33/35] feat(pim447): Add support for a lot of new driver properties. --- .../sensor/pimoroni,trackball_pim447.yaml | 58 ++++++++++++++ .../dt-bindings/zmk/trackball_pim447.h | 11 +++ app/include/zmk/trackball_pim447.h | 10 +++ app/src/mouse/trackball_pim447.c | 78 +++++++++++++++++-- 4 files changed, 151 insertions(+), 6 deletions(-) create mode 100644 app/drivers/zephyr/dts/bindings/sensor/pimoroni,trackball_pim447.yaml create mode 100644 app/include/dt-bindings/zmk/trackball_pim447.h create mode 100644 app/include/zmk/trackball_pim447.h diff --git a/app/drivers/zephyr/dts/bindings/sensor/pimoroni,trackball_pim447.yaml b/app/drivers/zephyr/dts/bindings/sensor/pimoroni,trackball_pim447.yaml new file mode 100644 index 00000000..2e1796e7 --- /dev/null +++ b/app/drivers/zephyr/dts/bindings/sensor/pimoroni,trackball_pim447.yaml @@ -0,0 +1,58 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Trackball PIM447 + +compatible: "pimoroni,trackball_pim447" + +properties: + label: + type: string + required: true + + reg: + type: int + required: true + + move-factor: + type: int + required: false + default: 1 + + invert-move-x: + type: boolean + required: false + + invert-move-y: + type: boolean + required: false + + button: + type: int + required: false + default: 0 + + swap-axes: + type: boolean + required: false + + scroll-divisor: + type: int + required: false + default: 2 + + invert-scroll-x: + type: boolean + required: false + + invert-scroll-y: + type: boolean + required: false + + mode: + type: int + required: false + default: 1 + enum: + - 1 + - 2 diff --git a/app/include/dt-bindings/zmk/trackball_pim447.h b/app/include/dt-bindings/zmk/trackball_pim447.h new file mode 100644 index 00000000..a5ebc86d --- /dev/null +++ b/app/include/dt-bindings/zmk/trackball_pim447.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#pragma once + +#define PIM447_NONE 0 +#define PIM447_MOVE 1 +#define PIM447_SCROLL 2 +#define PIM447_TOGGLE 3 diff --git a/app/include/zmk/trackball_pim447.h b/app/include/zmk/trackball_pim447.h new file mode 100644 index 00000000..08620821 --- /dev/null +++ b/app/include/zmk/trackball_pim447.h @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#pragma once + +#include + +extern void zmk_trackball_pim447_set_mode(int mode); diff --git a/app/src/mouse/trackball_pim447.c b/app/src/mouse/trackball_pim447.c index ece68892..36374be9 100644 --- a/app/src/mouse/trackball_pim447.c +++ b/app/src/mouse/trackball_pim447.c @@ -8,9 +8,46 @@ #include #include #include +#include LOG_MODULE_REGISTER(PIM447, CONFIG_SENSOR_LOG_LEVEL); +#define MOVE_FACTOR DT_PROP(DT_INST(0, pimoroni_trackball_pim447), move_factor) +#define MOVE_X_INVERT DT_PROP(DT_INST(0, pimoroni_trackball_pim447), invert_move_x) +#define MOVE_Y_INVERT DT_PROP(DT_INST(0, pimoroni_trackball_pim447), invert_move_y) +#define MOVE_X_FACTOR (MOVE_FACTOR * (MOVE_X_INVERT ? -1 : 1)) +#define MOVE_Y_FACTOR (MOVE_FACTOR * (MOVE_Y_INVERT ? -1 : 1)) + +#define SCROLL_DIVISOR DT_PROP(DT_INST(0, pimoroni_trackball_pim447), scroll_divisor) +#define SCROLL_X_INVERT DT_PROP(DT_INST(0, pimoroni_trackball_pim447), invert_scroll_x) +#define SCROLL_Y_INVERT DT_PROP(DT_INST(0, pimoroni_trackball_pim447), invert_scroll_y) +#define SCROLL_X_DIVISOR (SCROLL_DIVISOR * (SCROLL_X_INVERT ? -1 : 1)) +#define SCROLL_Y_DIVISOR (SCROLL_DIVISOR * (SCROLL_Y_INVERT ? 1 : -1)) + +#define BUTTON DT_PROP(DT_INST(0, pimoroni_trackball_pim447), button) +#define SWAP_AXES DT_PROP(DT_INST(0, pimoroni_trackball_pim447), swap_axes) + +static int mode = DT_PROP(DT_INST(0, pimoroni_trackball_pim447), mode); + +void zmk_trackball_pim447_set_mode(int new_mode) +{ + switch (new_mode) { + case PIM447_MOVE: + case PIM447_SCROLL: + mode = new_mode; + break; + + case PIM447_TOGGLE: + mode = mode == PIM447_MOVE + ? PIM447_SCROLL + : PIM447_MOVE; + break; + + default: + break; + } +} + /* * It feels more natural and more confortable to convert the speed * reported by the PIM447 trackball. @@ -65,6 +102,7 @@ static void thread_code(void *p1, void *p2, void *p3) while (true) { struct sensor_value pos_dx, pos_dy, pos_dz; bool send_report = false; + int clear = PIM447_NONE; result = sensor_sample_fetch(dev); if (result < 0) { @@ -91,18 +129,41 @@ static void thread_code(void *p1, void *p2, void *p3) } if (pos_dx.val1 != 0 || pos_dy.val1 != 0) { - zmk_hid_mouse_movement_update(convert_speed(pos_dx.val1), - convert_speed(pos_dy.val1)); - send_report = true; + if (SWAP_AXES) { + int32_t tmp = pos_dx.val1; + pos_dx.val1 = pos_dy.val1; + pos_dy.val1 = tmp; + } + + switch(mode) { + default: + case PIM447_MOVE: { + int dx = convert_speed(pos_dx.val1) * MOVE_X_FACTOR; + int dy = convert_speed(pos_dy.val1) * MOVE_Y_FACTOR; + zmk_hid_mouse_movement_set(dx, dy); + send_report = true; + clear = PIM447_MOVE; + break; + } + + case PIM447_SCROLL: { + int dx = pos_dx.val1 / SCROLL_X_DIVISOR; + int dy = pos_dy.val1 / SCROLL_Y_DIVISOR; + zmk_hid_mouse_scroll_set(dx, dy); + send_report = true; + clear = PIM447_SCROLL; + break; + } + } } if (pos_dz.val1 == 0x80 && button_press_sent == false) { - zmk_hid_mouse_button_press(0); + zmk_hid_mouse_button_press(BUTTON); button_press_sent = true; button_release_sent = false; send_report = true; } else if (pos_dz.val1 == 0x01 && button_release_sent == false) { - zmk_hid_mouse_button_release(0); + zmk_hid_mouse_button_release(BUTTON); button_press_sent = false; button_release_sent = true; send_report = true; @@ -110,7 +171,12 @@ static void thread_code(void *p1, void *p2, void *p3) if (send_report) { zmk_endpoints_send_mouse_report(); - zmk_hid_mouse_clear(); + + switch (clear) { + case PIM447_MOVE: zmk_hid_mouse_movement_set(0, 0); break; + case PIM447_SCROLL: zmk_hid_mouse_scroll_set(0, 0); break; + default: break; + } } k_sleep(K_MSEC(10)); From d081ac7a76864a7b6979576cdb69c5e73f75691a Mon Sep 17 00:00:00 2001 From: Cedric VINCENT Date: Sun, 14 Nov 2021 18:55:22 +0100 Subject: [PATCH 34/35] feat(behaviors): Add &pim447_to and &pim447_mo behaviors. --- app/CMakeLists.txt | 1 + app/dts/behaviors.dtsi | 1 + app/dts/behaviors/trackball_pim447.dtsi | 56 +++++++++++++++++ .../zmk,behavior-trackball_pim447.yaml | 15 +++++ app/src/behaviors/behavior_trackball_pim447.c | 61 +++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 app/dts/behaviors/trackball_pim447.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-trackball_pim447.yaml create mode 100644 app/src/behaviors/behavior_trackball_pim447.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index f7c5e963..bb615b2c 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -66,6 +66,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) target_sources(app PRIVATE src/behaviors/behavior_mouse_key_press.c) target_sources(app PRIVATE src/behaviors/behavior_mouse_move.c) target_sources(app PRIVATE src/behaviors/behavior_mouse_scroll.c) + target_sources(app PRIVATE src/behaviors/behavior_trackball_pim447.c) target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) target_sources(app PRIVATE src/combo.c) target_sources(app PRIVATE src/keymap.c) diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 3edaa1c1..878d5cbb 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -17,3 +17,4 @@ #include #include #include +#include diff --git a/app/dts/behaviors/trackball_pim447.dtsi b/app/dts/behaviors/trackball_pim447.dtsi new file mode 100644 index 00000000..dc95c692 --- /dev/null +++ b/app/dts/behaviors/trackball_pim447.dtsi @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + behaviors { + /omit-if-no-ref/ pim447_move: behavior_trackball_pim447_move { + compatible = "zmk,behavior-trackball-pim447"; + label = "PIM447_MOVE"; + mode = ; + #binding-cells = <0>; + }; + + /omit-if-no-ref/ pim447_scroll: behavior_trackball_pim447_scroll { + compatible = "zmk,behavior-trackball-pim447"; + label = "PIM447_SCROLL"; + mode = ; + #binding-cells = <0>; + }; + + /omit-if-no-ref/ pim447_toggle: behavior_trackball_pim447_toggle { + compatible = "zmk,behavior-trackball-pim447"; + label = "PIM447_TOGGLE"; + mode = ; + #binding-cells = <0>; + }; + + /omit-if-no-ref/ pim447_move_scroll: behavior_trackball_pim447_move_scroll { + compatible = "zmk,behavior-trackball-pim447"; + label = "PIM447_MOVE_SCROLL"; + mode = ; + momentary; + #binding-cells = <0>; + }; + + /omit-if-no-ref/ pim447_scroll_move: behavior_trackball_pim447_scroll_move { + compatible = "zmk,behavior-trackball-pim447"; + label = "PIM447_SCROLL_MOVE"; + mode = ; + momentary; + #binding-cells = <0>; + }; + + /omit-if-no-ref/ pim447_toggle_toggle: behavior_trackball_pim447_toggle_toggle { + compatible = "zmk,behavior-trackball-pim447"; + label = "PIM447_TOGGLE_TOGGLE"; + mode = ; + momentary; + #binding-cells = <0>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-trackball_pim447.yaml b/app/dts/bindings/behaviors/zmk,behavior-trackball_pim447.yaml new file mode 100644 index 00000000..0c34117b --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-trackball_pim447.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +description: Trackball PIM447 behavior + +compatible: "zmk,behavior-trackball-pim447" + +include: zero_param.yaml + +properties: + mode: + type: int + required: true + momentary: + type: boolean diff --git a/app/src/behaviors/behavior_trackball_pim447.c b/app/src/behaviors/behavior_trackball_pim447.c new file mode 100644 index 00000000..d2eec9bc --- /dev/null +++ b/app/src/behaviors/behavior_trackball_pim447.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_trackball_pim447 + +#include +#include +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +struct config { + int mode; + bool momentary; +}; + +static int behavior_trackball_pim447_init(const struct device *dev) { return 0; }; + +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *device = device_get_binding(binding->behavior_dev); + const struct config *config = device->config; + + zmk_trackball_pim447_set_mode(config->mode); + + return ZMK_BEHAVIOR_OPAQUE; +} + +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + const struct device *device = device_get_binding(binding->behavior_dev); + const struct config *config = device->config; + + if (config->momentary) { + zmk_trackball_pim447_set_mode(PIM447_TOGGLE); + } + + return ZMK_BEHAVIOR_OPAQUE; +} + +static const struct behavior_driver_api behavior_trackball_pim447_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +#define PIM447_INST(n) \ + static const struct config config_##n = { \ + .mode = DT_INST_PROP(n, mode), \ + .momentary = DT_INST_PROP(n, momentary) \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, behavior_trackball_pim447_init, device_pm_control_nop, \ + NULL, &config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_trackball_pim447_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(PIM447_INST) + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ From eb8889883d1e91f58a42f0babc17a10fa3fa1b4a Mon Sep 17 00:00:00 2001 From: Cedric VINCENT Date: Sun, 14 Nov 2021 19:46:57 +0100 Subject: [PATCH 35/35] feat(docs): Add documentation about PIM447 trackball driver. --- docs/docs/behaviors/trackball-pim447.md | 33 ++++++++++++ docs/docs/features/trackballs.md | 71 +++++++++++++++++++++++++ docs/docs/intro.md | 1 + docs/sidebars.js | 2 + 4 files changed, 107 insertions(+) create mode 100644 docs/docs/behaviors/trackball-pim447.md create mode 100644 docs/docs/features/trackballs.md diff --git a/docs/docs/behaviors/trackball-pim447.md b/docs/docs/behaviors/trackball-pim447.md new file mode 100644 index 00000000..af28eb23 --- /dev/null +++ b/docs/docs/behaviors/trackball-pim447.md @@ -0,0 +1,33 @@ +--- +title: Trackball PIM447 Behaviors +sidebar_label: Trackball PIM447 +--- + +The mode of the trackball PIM447 driver can be changed using the +following key behaviors. + +- `&pim447_move`: set trackball mode to "move" . +- `&pim447_scroll`: set trackball mode to "scroll" . +- `&pim447_toggle`: toggle trackball mode (from "scroll" to "move", or vice versa). +- `&pim447_move_scroll`: set trackball mode to "move" when pressed, then to "scroll" when released. +- `&pim447_scroll_move`: set trackball mode to "scroll" when pressed, then to "move" when released. +- `&pim447_toggle_toggle`: toggle trackball mode when pressed, then toggle again when released. + +Example: + +``` +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + a_layer { + bindings = <&kp a + &kp b + &kp c + &pim447_toggle>; + }; + }; +}; +``` diff --git a/docs/docs/features/trackballs.md b/docs/docs/features/trackballs.md new file mode 100644 index 00000000..e489c090 --- /dev/null +++ b/docs/docs/features/trackballs.md @@ -0,0 +1,71 @@ +--- +title: Trackballs +sidebar_label: Trackballs +--- + +Only the [Pimoroni PIM447](https://shop.pimoroni.com/products/trackball-breakout) +trackball is supported in ZMK so far. + +## Enable Trackball Support + +To enable support for PIM447 trackball — and to make it acts like a +mouse — add the two following lines to the shield `.config` file: + +```ini +CONFIG_ZMK_MOUSE=y +CONFIG_ZMK_TRACKBALL_PIM447=y +``` + +Assuming the PIM447 trackball is connected to the `pro_micro_i2c` pins +and its bus address hasn't been changed, then the following lines must +be added to the shield `.overlay` file: + +```devicetree +&pro_micro_i2c { + status = "okay"; + + trackball_pim447@a { + compatible = "pimoroni,trackball_pim447"; + reg = <0xa>; + label = "TRACKBALL_PIM447"; + }; +}; +``` + +## Customize Trackball Driver Properties + +The PIM447 trackball driver can be configured according to a lot of +different properties that are listed in the shield `.overlay` sample +below: + +```devicetree +#include // for PIM447_MOVE and PIM447_SCROLL constants. + +&pro_micro_i2c { + status = "okay"; + + trackball_pim447@a { + compatible = "pimoroni,trackball_pim447"; + reg = <0xa>; + label = "TRACKBALL_PIM447"; + + move-factor = <2>; // Increase pointer velocity (default: 1) + invert-move-x; // Invert pointer X axis (left is right, and vice versa) + invert-move-y; // Invert pointer Y axis (up is down, and vice versa) + button = <1>; // Send right-click when pressing the ball (default: 0, ie. left-click) + swap-axes; // Swap X and Y axes (horizontal is vertical, and vice versa) + scroll-divisor = <1>; // Increase wheel velocity (default: 2) + invert-scroll-x; // Invert wheel X axis (left is right, and vice versa) + invert-scroll-y; // Invert wheel Y axis (up is down, and vice versa) + mode = ; // Act as mouse wheels at startup (default: PIM447_MOVE for a pointer) + }; +}; +``` + +## Change Trackball Driver Mode + +As seen at the end of the previous section, the PIM447 trackball +driver can act as a mouse pointer or as mouse wheels according to the +`mode` specified in the shield `.overlay` file. It can also be +changed dynamically using [dedicated key +behaviors](/docs/behaviors/trackball-pim447). diff --git a/docs/docs/intro.md b/docs/docs/intro.md index e1983c93..ad89991e 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -40,6 +40,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | Realtime Keymap Updating | 💡 | | ✅ | | AVR/8 Bit | | | ✅ | | [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | +| [Trackballs](features/trackballs) | ✅ | | ✅ | [^2]: Encoders are not currently supported on peripheral side splits. [^1]: OLEDs are currently proof of concept in ZMK. diff --git a/docs/sidebars.js b/docs/sidebars.js index 545df5b3..54a01901 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -15,6 +15,7 @@ module.exports = { "features/displays", "features/encoders", "features/underglow", + "features/trackballs", "features/beta-testing", ], Behaviors: [ @@ -32,6 +33,7 @@ module.exports = { "behaviors/outputs", "behaviors/lighting", "behaviors/power", + "behaviors/trackball-pim447", ], Codes: [ "codes/index",