From e8f0612377d2894b80aa3d01a2ec218b44eb9f78 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Wed, 27 Mar 2024 16:33:52 +0000 Subject: [PATCH] fix(mouse): Better batching of MT events. * Handle input events for multiple slots before a sync event triggers a HID report. --- app/include/zmk/mouse/hid.h | 7 +++-- app/src/mouse/hid.c | 56 +++++++++++++++++++++++----------- app/src/mouse/input_listener.c | 48 ++++++++++++++++++----------- 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/app/include/zmk/mouse/hid.h b/app/include/zmk/mouse/hid.h index 51e150f65745..76999705253e 100644 --- a/app/include/zmk/mouse/hid.h +++ b/app/include/zmk/mouse/hid.h @@ -270,7 +270,9 @@ struct zmk_hid_mouse_report { // Report for single finger struct zmk_ptp_finger { // Touch Valid (bit 0) and tip switch (bit 1) - uint8_t valid_tip; + uint8_t touch_valid : 1; + uint8_t tip_switch : 1; + uint8_t padding : 6; // Contact ID uint8_t contact_id; // X @@ -363,7 +365,8 @@ struct zmk_hid_mouse_report *zmk_mouse_hid_get_mouse_report(); int zmk_mouse_hid_set_ptp_finger(struct zmk_ptp_finger finger); void zmk_mouse_hid_ptp_update_scan_time(void); -void zmk_mouse_hid_ptp_clear(void); +void zmk_mouse_hid_ptp_clear_lifted_fingers(void); +// void zmk_mouse_hid_ptp_clear(void); struct zmk_hid_ptp_report *zmk_mouse_hid_get_ptp_report(); diff --git a/app/src/mouse/hid.c b/app/src/mouse/hid.c index e0f4bc10eb49..7219f6c7e9cc 100644 --- a/app/src/mouse/hid.c +++ b/app/src/mouse/hid.c @@ -122,27 +122,14 @@ static struct zmk_hid_ptp_report ptp_report = { }; int zmk_mouse_hid_set_ptp_finger(struct zmk_ptp_finger finger) { - bool finger_removed = false; + // First try to update existing for (int i = 0; i < ptp_report.body.contact_count; i++) { if (ptp_report.body.fingers[i].contact_id == finger.contact_id) { ptp_report.body.fingers[i] = finger; - - if (!finger.valid_tip) { - finger_removed = true; - } else { - return 0; - } - } else if (finger_removed) { - ptp_report.body.fingers[i - 1] = ptp_report.body.fingers[i]; + return 0; } } - if (finger_removed) { - memset(&ptp_report.body.fingers[--ptp_report.body.contact_count], 0, - sizeof(struct zmk_ptp_finger)); - return 0; - } - if (ptp_report.body.contact_count == CONFIG_ZMK_TRACKPAD_FINGERS) { return -ENOMEM; } @@ -152,6 +139,27 @@ int zmk_mouse_hid_set_ptp_finger(struct zmk_ptp_finger finger) { return 0; } +void zmk_mouse_hid_ptp_clear_lifted_fingers(void) { + int valid_count = 0; + for (int i = 0; i < ptp_report.body.contact_count; i++) { + if (!ptp_report.body.fingers[i].tip_switch) { + continue; + } + + ptp_report.body.fingers[valid_count++] = ptp_report.body.fingers[i]; + } + + for (int i = valid_count; i < ptp_report.body.contact_count; i++) { + memset(&ptp_report.body.fingers[i], 0, sizeof(struct zmk_ptp_finger)); + } + + ptp_report.body.contact_count = valid_count; + + if (ptp_report.body.contact_count == 0) { + ptp_report.body.scan_time = 0; + } +} + void zmk_mouse_hid_ptp_update_scan_time(void) { if (ptp_report.body.contact_count > 0) { // scan time is in 100 microsecond units @@ -169,12 +177,24 @@ struct zmk_hid_ptp_report *zmk_mouse_hid_get_ptp_report() { return &ptp_report; } -struct zmk_hid_ptp_feature_selective_report *zmk_mouse_hid_ptp_get_feature_selective_report(); +struct zmk_hid_ptp_feature_selective_report selective_report = { + .report_id = ZMK_MOUSE_HID_REPORT_ID_FEATURE_PTP_SELECTIVE, + .body = + { + .surface_switch = 1, + .button_switch = 1, + }, +}; + +struct zmk_hid_ptp_feature_selective_report *zmk_mouse_hid_ptp_get_feature_selective_report() { + return &selective_report; +} + void zmk_mouse_hid_ptp_set_feature_selective_report(bool surface_switch, bool button_switch); struct zmk_hid_ptp_feature_mode_report mode_report = { .report_id = ZMK_MOUSE_HID_REPORT_ID_FEATURE_PTP_MODE, - .mode = 0, + .mode = 3, }; struct zmk_hid_ptp_feature_mode_report *zmk_mouse_hid_ptp_get_feature_mode_report() { @@ -217,7 +237,7 @@ static struct zmk_hid_ptp_feature_capabilities_report cap_report = { .body = { .max_touches = CONFIG_ZMK_TRACKPAD_FINGERS, - .pad_type = PTP_PAD_TYPE_NON_CLICKABLE, + .pad_type = PTP_PAD_TYPE_DEPRESSIBLE, }, }; diff --git a/app/src/mouse/input_listener.c b/app/src/mouse/input_listener.c index 546e39063d82..b892ec6dbf16 100644 --- a/app/src/mouse/input_listener.c +++ b/app/src/mouse/input_listener.c @@ -48,6 +48,7 @@ struct input_listener_data { } mouse; struct { + bool pending_data; struct input_listener_xy_data data; uint8_t finger_idx; bool touched; @@ -92,18 +93,41 @@ static void handle_rel_code(struct input_listener_data *data, struct input_event } } +static int send_ptp_finger_to_hid(struct input_listener_data *data) { + struct zmk_ptp_finger finger = {.contact_id = data->ptp.finger_idx}; + finger.x = data->ptp.data.x; + finger.y = data->ptp.data.y; + finger.touch_valid = 1; + finger.tip_switch = data->ptp.touched ? 1 : 0; + + int err = zmk_mouse_hid_set_ptp_finger(finger); + + data->ptp.pending_data = false; + data->ptp.data.y = data->ptp.data.x = 0; + data->ptp.touched = false; + + return err; +} + static void handle_abs_code(const struct input_listener_config *config, struct input_listener_data *data, struct input_event *evt) { if (config->mode == INPUT_LISTENER_MODE_PTP) { switch (evt->code) { case INPUT_ABS_MT_SLOT: + if (data->ptp.pending_data) { + send_ptp_finger_to_hid(data); + } + + data->ptp.pending_data = true; data->ptp.finger_idx = evt->value; break; case INPUT_ABS_X: + data->ptp.pending_data = true; data->ptp.data.mode = INPUT_LISTENER_XY_DATA_MODE_ABS; data->ptp.data.x = evt->value; break; case INPUT_ABS_Y: + data->ptp.pending_data = true; data->ptp.data.mode = INPUT_LISTENER_XY_DATA_MODE_ABS; data->ptp.data.y = evt->value; break; @@ -230,28 +254,16 @@ static void input_handler(const struct input_listener_config *config, break; case INPUT_LISTENER_MODE_PTP: #if IS_ENABLED(CONFIG_ZMK_TRACKPAD) - struct zmk_ptp_finger finger = {.contact_id = data->ptp.finger_idx}; - finger.x = data->ptp.data.x; - finger.y = data->ptp.data.y; - WRITE_BIT(finger.valid_tip, 0, 1); - WRITE_BIT(finger.valid_tip, 1, data->ptp.touched ? 1 : 0); - - zmk_mouse_hid_set_ptp_finger(finger); - zmk_mouse_hid_ptp_update_scan_time(); + if (data->ptp.pending_data) { + send_ptp_finger_to_hid(data); + } // TODO: Button Data - zmk_endpoints_send_ptp_report(); - - if (!data->ptp.touched) { - finger.x = finger.y = 0; - WRITE_BIT(finger.valid_tip, 0, 0); - zmk_mouse_hid_set_ptp_finger(finger); - zmk_mouse_hid_ptp_update_scan_time(); + zmk_mouse_hid_ptp_update_scan_time(); + zmk_endpoints_send_ptp_report(); - // TODO: Button Data - zmk_endpoints_send_ptp_report(); - } + zmk_mouse_hid_ptp_clear_lifted_fingers(); #else LOG_WRN("PTP Mode not supported without CONFIG_ZMK_TRACKPAD=y"); #endif // IS_ENABLED(CONFIG_ZMK_TRACKPAD)