From 0a4b1a6533f434e6bdb7f7f5c336aa3096a90ad7 Mon Sep 17 00:00:00 2001 From: Chris Andreae Date: Tue, 21 Nov 2023 05:00:10 +0900 Subject: [PATCH] feat(ble): add behavior to disconnect from BLE profile Adds new functionality and a behavior to disconnect an active BLE connection. The motivation for this is that for some devices like phones, the presence of an active BLE connection results in the onscreen keyboard being selected. --- app/include/dt-bindings/zmk/bt.h | 2 ++ app/include/zmk/ble.h | 1 + app/src/behaviors/behavior_bt.c | 2 ++ app/src/ble.c | 21 +++++++++++++++++++++ docs/docs/behaviors/bluetooth.md | 21 +++++++++++++++------ 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index 8ca10606942..7af89ddb011 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -9,6 +9,7 @@ #define BT_PRV_CMD 2 #define BT_SEL_CMD 3 // #define BT_FULL_RESET_CMD 4 +#define BT_DISC_CMD 5 /* Note: Some future commands will include additional parameters, so we @@ -19,3 +20,4 @@ defines these aliases up front. #define BT_NXT BT_NXT_CMD 0 #define BT_PRV BT_PRV_CMD 0 #define BT_SEL BT_SEL_CMD +#define BT_DISC BT_DISC_CMD diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index 435fde49654..92fd595fbcb 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -24,6 +24,7 @@ int zmk_ble_clear_bonds(); int zmk_ble_prof_next(); int zmk_ble_prof_prev(); int zmk_ble_prof_select(uint8_t index); +int zmk_ble_prof_disconnect(uint8_t index); int zmk_ble_active_profile_index(); bt_addr_le_t *zmk_ble_active_profile_addr(); diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 6d44b5f5e9f..bf98532ce93 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -31,6 +31,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, return zmk_ble_prof_prev(); case BT_SEL_CMD: return zmk_ble_prof_select(binding->param2); + case BT_DISC_CMD: + return zmk_ble_prof_disconnect(binding->param2); default: LOG_ERR("Unknown BT command: %d", binding->param1); } diff --git a/app/src/ble.c b/app/src/ble.c index 483bc9d79c1..8c991c54b80 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -271,6 +271,27 @@ int zmk_ble_prof_prev() { ZMK_BLE_PROFILE_COUNT); }; +int zmk_ble_prof_disconnect(uint8_t index) { + if (index >= ZMK_BLE_PROFILE_COUNT) + return -ERANGE; + + bt_addr_le_t *addr = &profiles[index].peer; + struct bt_conn *conn; + int result; + + if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { + return -ENODEV; + } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + return -ENODEV; + } + + result = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + LOG_DBG("Disconnected from profile %d: %d", index, result); + + bt_conn_unref(conn); + return result; +} + bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; } char *zmk_ble_active_profile_name() { return profiles[active_profile].name; } diff --git a/docs/docs/behaviors/bluetooth.md b/docs/docs/behaviors/bluetooth.md index 1d461722f5c..ef1cc4666f1 100644 --- a/docs/docs/behaviors/bluetooth.md +++ b/docs/docs/behaviors/bluetooth.md @@ -13,6 +13,13 @@ computer/laptop/keyboard should receive the keyboard input; many of the commands When pairing to a host device ZMK saves bond information to the selected profile. It will not replace this when you initiate pairing with another device. To pair with a new device select an unused profile with `BT_SEL`, `BT_NXT` or `BT_PRV` bindings, or by clearing an existing profile using `BT_CLR`. A ZMK device may show as "connected" on multiple hosts at the same time. This is working as intended, and only the host associated with the active profile will receive keystrokes. + +An _inactive_ connected profile can be explicitly disconnected using the `BT_DISC` behavior. This can be helpful in +cases when host devices behave differently when a bluetooth keyboard is connected, for example by hiding their on-screen +keyboard. Note that at present the active bluetooth profile will immediately reconnect if disconnected. This is true +even if OUT_USB is selected. To remain disconnected, another bluetooth profile must be first selected using (e.g.) +`BT_SEL`. + ::: ## Bluetooth Command Defines @@ -28,12 +35,14 @@ This will allow you to reference the actions defined in this header such as `BT_ Here is a table describing the command for each define: -| Define | Action | -| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile. | -| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end is reached. | -| `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | -| `BT_SEL` | Select the 0-indexed profile by number. Please note: this definition must include a number as an argument in the keymap to work correctly. eg. `BT_SEL 0` | +| Define | Action | +| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `BT_CLR` | Clear bond information between the keyboard and host for the selected profile. | +| `BT_NXT` | Switch to the next profile, cycling through to the first one when the end is reached. | +| `BT_PRV` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | +| `BT_SEL` | Select the 0-indexed profile by number. Please note: this definition must include a number as an argument in the keymap to work correctly. eg. `BT_SEL 0` | +| `BT_DISC` | Disconnect from the 0-indexed profile by number, if it's currently connected and inactive. Please note: this definition must include a number as an | +| | argument in the keymap to work correctly. eg. `BT_DISC 0` | :::note Selected profile persistence The profile that is selected by the `BT_SEL`/`BT_PRV`/`BT_NXT` actions will be saved to flash storage and hence persist across restarts and firmware flashes.