From 24487bd9744f504724089f0e1cec98431a2d3333 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Wed, 14 Jan 2026 11:17:43 -0700 Subject: [PATCH] feat(pointing): Release pressed keys on disconnect (#3204) Match the behavior for key press release on split peripheral disconnect, and track pressed input keys to release them as needed on disconnect. --- app/include/zmk/pointing/input_split.h | 3 +- app/src/pointing/Kconfig | 5 ++ app/src/pointing/input_split.c | 64 ++++++++++++++++++- app/src/split/bluetooth/central.c | 2 +- .../split/peripheral-input/events.patterns | 1 + .../split/peripheral-input/peripheral.overlay | 1 + .../ble/split/peripheral-input/snapshot.log | 9 +++ 7 files changed, 82 insertions(+), 3 deletions(-) diff --git a/app/include/zmk/pointing/input_split.h b/app/include/zmk/pointing/input_split.h index 812035477..235ea4954 100644 --- a/app/include/zmk/pointing/input_split.h +++ b/app/include/zmk/pointing/input_split.h @@ -7,4 +7,5 @@ #pragma once int zmk_input_split_report_peripheral_event(uint8_t reg, uint8_t type, uint16_t code, int32_t value, - bool sync); \ No newline at end of file + bool sync); +int zmk_input_split_peripheral_disconnected(uint8_t reg); \ No newline at end of file diff --git a/app/src/pointing/Kconfig b/app/src/pointing/Kconfig index 43bc784fa..fc91f1449 100644 --- a/app/src/pointing/Kconfig +++ b/app/src/pointing/Kconfig @@ -78,6 +78,11 @@ config ZMK_INPUT_SPLIT_INIT_PRIORITY int "Input Split initialization priority" default INPUT_INIT_PRIORITY + +config ZMK_INPUT_SPLIT_MAX_TRACKED_KEYS + int "Input Split max tracked keys to release on peripheral disconnect" + default 5 + endif # ZMK_INPUT_SPLIT endif # ZMK_POINTING diff --git a/app/src/pointing/input_split.c b/app/src/pointing/input_split.c index c3bcd4cc2..6662111d6 100644 --- a/app/src/pointing/input_split.c +++ b/app/src/pointing/input_split.c @@ -26,11 +26,42 @@ struct zis_entry { static const struct zis_entry proxy_inputs[] = {DT_INST_FOREACH_STATUS_OKAY(ZIS_ENTRY)}; +static uint16_t proxy_active_keys[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)] + [CONFIG_ZMK_INPUT_SPLIT_MAX_TRACKED_KEYS]; + +static int replace_active_key(size_t input, uint16_t find, uint16_t replace) { + for (size_t k = 0; k < CONFIG_ZMK_INPUT_SPLIT_MAX_TRACKED_KEYS; k++) { + if (proxy_active_keys[input][k] == find) { + proxy_active_keys[input][k] = replace; + return 0; + } + } + + return -ENODEV; +} + int zmk_input_split_report_peripheral_event(uint8_t reg, uint8_t type, uint16_t code, int32_t value, bool sync) { LOG_DBG("Got peripheral event for %d!", reg); for (size_t i = 0; i < ARRAY_SIZE(proxy_inputs); i++) { if (reg == proxy_inputs[i].reg) { + if (type == INPUT_EV_KEY) { + uint16_t find, replace; + + if (value) { + find = 0; + replace = code; + } else { + find = code; + replace = 0; + } + + int ret = replace_active_key(i, find, replace); + if (ret < 0) { + LOG_WRN("Failed to %s key %d", value ? "track pressed" : "untrack released", + ret); + } + } return input_report(proxy_inputs[i].dev, type, code, value, sync, K_NO_WAIT); } } @@ -38,6 +69,37 @@ int zmk_input_split_report_peripheral_event(uint8_t reg, uint8_t type, uint16_t return -ENODEV; } +int zmk_input_split_peripheral_disconnected(uint8_t reg) { + for (size_t i = 0; i < ARRAY_SIZE(proxy_inputs); i++) { + if (reg == proxy_inputs[i].reg) { + uint16_t prev = 0; + for (size_t k = 0; k < CONFIG_ZMK_INPUT_SPLIT_MAX_TRACKED_KEYS; k++) { + if (proxy_active_keys[i][k] != 0) { + if (prev != 0) { + int ret = input_report(proxy_inputs[i].dev, INPUT_EV_KEY, prev, 0, false, + K_NO_WAIT); + if (ret < 0) { + LOG_WRN("Failed to report release event on disconnect (%d)", ret); + } + } + + prev = proxy_active_keys[i][k]; + proxy_active_keys[i][k] = 0; + } + } + + if (prev != 0) { + int ret = input_report(proxy_inputs[i].dev, INPUT_EV_KEY, prev, 0, true, K_NO_WAIT); + if (ret < 0) { + LOG_WRN("Failed to report release event on disconnect (%d)", ret); + } + } + } + } + + return -ENODEV; +} + #define ZIS_INST(n) \ DEVICE_DT_INST_DEFINE(n, NULL, NULL, NULL, NULL, POST_KERNEL, \ CONFIG_ZMK_INPUT_SPLIT_INIT_PRIORITY, NULL); @@ -78,4 +140,4 @@ int zmk_input_split_report_peripheral_event(uint8_t reg, uint8_t type, uint16_t #endif -DT_INST_FOREACH_STATUS_OKAY(ZIS_INST) \ No newline at end of file +DT_INST_FOREACH_STATUS_OKAY(ZIS_INST) diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 1a9fb0e8a..b4b61ce77 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -122,7 +122,7 @@ void release_peripheral_input_subs(struct bt_conn *conn) { for (size_t i = 0; i < ARRAY_SIZE(peripheral_input_slots); i++) { if (peripheral_input_slots[i].conn == conn) { peripheral_input_slots[i].conn = NULL; - // memset(&peripheral_input_slots[i], 0, sizeof(struct peripheral_input_slot)); + zmk_input_split_peripheral_disconnected(peripheral_input_slots[i].reg); } } } diff --git a/app/tests/ble/split/peripheral-input/events.patterns b/app/tests/ble/split/peripheral-input/events.patterns index f8cf363c2..c08c17662 100644 --- a/app/tests/ble/split/peripheral-input/events.patterns +++ b/app/tests/ble/split/peripheral-input/events.patterns @@ -1 +1,2 @@ s/^d_02: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}/profile 0 /p +s/^d_00: @[0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9][0-9][0-9][0-9] .{19}.*zmk_hid_mouse_button_/mouse button /p diff --git a/app/tests/ble/split/peripheral-input/peripheral.overlay b/app/tests/ble/split/peripheral-input/peripheral.overlay index 3c571a4fc..8f403b5e1 100644 --- a/app/tests/ble/split/peripheral-input/peripheral.overlay +++ b/app/tests/ble/split/peripheral-input/peripheral.overlay @@ -21,6 +21,7 @@ , , , + , ; exit-after; }; diff --git a/app/tests/ble/split/peripheral-input/snapshot.log b/app/tests/ble/split/peripheral-input/snapshot.log index cf63c996e..a31d449d5 100644 --- a/app/tests/ble/split/peripheral-input/snapshot.log +++ b/app/tests/ble/split/peripheral-input/snapshot.log @@ -24,3 +24,12 @@ profile 0 ble_central: notify_func: payload profile 0 00 64 00 64 00 00 00 00 00 |.d.d.... . profile 0 ble_central: notify_func: payload profile 0 00 28 00 32 00 00 00 00 00 |.(.2.... . +mouse button press: Button 1 count 1 +mouse button press: Mouse buttons set to 0x02 +profile 0 ble_central: notify_func: payload +profile 0 02 00 00 00 00 00 00 00 00 |........ . +mouse button release: Button 1 count: 0 +mouse button release: Button 1 released +mouse button release: Mouse buttons set to 0x00 +profile 0 ble_central: notify_func: payload +profile 0 00 00 00 00 00 00 00 00 00 |........ .