forked from kofal.net/zmk
feat(endpoints): add preferred endpoint setting
Added a new setting to remember the user's preferred endpoint. When both USB and
BLE are connected, the preferred endpoint will be used.
Added a new behavior to control this setting. It supports commands:
&end END_USB - Prefer USB output
&end END_BLE - Prefer BLE output
&end END_TOG - Toggle between USB and BLE
This commit is contained in:
44
app/src/behaviors/behavior_endpoints.c
Normal file
44
app/src/behaviors/behavior_endpoints.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_endpoints
|
||||
|
||||
#include <device.h>
|
||||
#include <devicetree.h>
|
||||
#include <drivers/behavior.h>
|
||||
|
||||
#include <dt-bindings/zmk/endpoints.h>
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/endpoints.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
switch (binding->param1) {
|
||||
case ENDPOINT_TOGGLE_CMD:
|
||||
return zmk_endpoints_toggle();
|
||||
case ENDPOINT_USB_CMD:
|
||||
return zmk_endpoints_select(ZMK_ENDPOINT_USB);
|
||||
case ENDPOINT_BLE_CMD:
|
||||
return zmk_endpoints_select(ZMK_ENDPOINT_BLE);
|
||||
default:
|
||||
LOG_ERR("Unknown endpoints command: %d", binding->param1);
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int behavior_ep_init(struct device *dev) { return 0; }
|
||||
|
||||
static const struct behavior_driver_api behavior_endpoints_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(behavior_end, DT_INST_LABEL(0), behavior_ep_init, NULL, NULL, APPLICATION,
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_endpoints_driver_api);
|
||||
@@ -4,6 +4,9 @@
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <init.h>
|
||||
#include <settings/settings.h>
|
||||
|
||||
#include <zmk/ble.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/hid.h>
|
||||
@@ -16,21 +19,45 @@
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
enum endpoint {
|
||||
ENDPOINT_USB,
|
||||
ENDPOINT_BLE,
|
||||
};
|
||||
#define DEFAULT_ENDPOINT \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ZMK_ENDPOINT_BLE), (ZMK_ENDPOINT_USB))
|
||||
|
||||
#define DEFAULT_ENDPOINT COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BLE), (ENDPOINT_BLE), (ENDPOINT_USB))
|
||||
static enum zmk_endpoint current_endpoint = DEFAULT_ENDPOINT;
|
||||
static enum zmk_endpoint preferred_endpoint =
|
||||
ZMK_ENDPOINT_USB; /* Used if multiple endpoints are ready */
|
||||
|
||||
static enum endpoint current_endpoint = DEFAULT_ENDPOINT;
|
||||
static void update_current_endpoint();
|
||||
|
||||
int zmk_endpoints_select(enum zmk_endpoint endpoint) {
|
||||
LOG_DBG("Selected endpoint %d", endpoint);
|
||||
|
||||
if (preferred_endpoint == endpoint) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
preferred_endpoint = endpoint;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
settings_save_one("endpoints/preferred", &preferred_endpoint, sizeof(preferred_endpoint));
|
||||
#endif
|
||||
|
||||
update_current_endpoint();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_endpoints_toggle() {
|
||||
enum zmk_endpoint new_endpoint =
|
||||
(preferred_endpoint == ZMK_ENDPOINT_USB) ? ZMK_ENDPOINT_BLE : ZMK_ENDPOINT_USB;
|
||||
return zmk_endpoints_select(new_endpoint);
|
||||
}
|
||||
|
||||
static int send_keypad_report() {
|
||||
struct zmk_hid_keypad_report *keypad_report = zmk_hid_get_keypad_report();
|
||||
|
||||
switch (current_endpoint) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB)
|
||||
case ENDPOINT_USB: {
|
||||
case ZMK_ENDPOINT_USB: {
|
||||
int err = zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(*keypad_report));
|
||||
if (err) {
|
||||
LOG_ERR("FAILED TO SEND OVER USB: %d", err);
|
||||
@@ -40,7 +67,7 @@ static int send_keypad_report() {
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
||||
case ENDPOINT_BLE: {
|
||||
case ZMK_ENDPOINT_BLE: {
|
||||
int err = zmk_hog_send_keypad_report(&keypad_report->body);
|
||||
if (err) {
|
||||
LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
|
||||
@@ -60,7 +87,7 @@ static int send_consumer_report() {
|
||||
|
||||
switch (current_endpoint) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB)
|
||||
case ENDPOINT_USB: {
|
||||
case ZMK_ENDPOINT_USB: {
|
||||
int err = zmk_usb_hid_send_report((u8_t *)consumer_report, sizeof(*consumer_report));
|
||||
if (err) {
|
||||
LOG_ERR("FAILED TO SEND OVER USB: %d", err);
|
||||
@@ -70,7 +97,7 @@ static int send_consumer_report() {
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
||||
case 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);
|
||||
@@ -99,6 +126,49 @@ int zmk_endpoints_send_report(u8_t usage_page) {
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
|
||||
static int endpoints_handle_set(const char *name, size_t len, settings_read_cb read_cb,
|
||||
void *cb_arg) {
|
||||
LOG_DBG("Setting endpoint value %s", log_strdup(name));
|
||||
|
||||
if (settings_name_steq(name, "preferred", NULL)) {
|
||||
if (len != sizeof(enum zmk_endpoint)) {
|
||||
LOG_ERR("Invalid endpoint size (got %d expected %d)", len, sizeof(enum zmk_endpoint));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int err = read_cb(cb_arg, &preferred_endpoint, sizeof(enum zmk_endpoint));
|
||||
if (err <= 0) {
|
||||
LOG_ERR("Failed to read preferred endpoint from settings (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
update_current_endpoint();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct settings_handler endpoints_handler = {.name = "endpoints", .h_set = endpoints_handle_set};
|
||||
#endif /* IS_ENABLED(CONFIG_SETTINGS) */
|
||||
|
||||
static int zmk_endpoints_init(struct device *_arg) {
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
settings_subsys_init();
|
||||
|
||||
int err = settings_register(&endpoints_handler);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to register the endpoints settings handler (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
settings_load();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_usb_ready() {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB)
|
||||
return zmk_usb_is_hid_ready();
|
||||
@@ -115,21 +185,20 @@ static bool is_ble_ready() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static enum endpoint get_selected_endpoint() {
|
||||
static enum zmk_endpoint get_selected_endpoint() {
|
||||
if (is_ble_ready()) {
|
||||
if (is_usb_ready()) {
|
||||
LOG_DBG("Both endpoints are ready.");
|
||||
// TODO: add user setting to control this
|
||||
return ENDPOINT_USB;
|
||||
LOG_DBG("Both endpoints are ready. Using %d", preferred_endpoint);
|
||||
return preferred_endpoint;
|
||||
}
|
||||
|
||||
LOG_DBG("Only BLE is ready.");
|
||||
return ENDPOINT_BLE;
|
||||
return ZMK_ENDPOINT_BLE;
|
||||
}
|
||||
|
||||
if (is_usb_ready()) {
|
||||
LOG_DBG("Only USB is ready.");
|
||||
return ENDPOINT_USB;
|
||||
return ZMK_ENDPOINT_USB;
|
||||
}
|
||||
|
||||
LOG_DBG("No endpoints are ready.");
|
||||
@@ -144,8 +213,8 @@ static void disconnect_current_endpoint() {
|
||||
zmk_endpoints_send_report(USAGE_CONSUMER);
|
||||
}
|
||||
|
||||
static int endpoint_listener(const struct zmk_event_header *eh) {
|
||||
enum endpoint new_endpoint = get_selected_endpoint();
|
||||
static void update_current_endpoint() {
|
||||
enum zmk_endpoint new_endpoint = get_selected_endpoint();
|
||||
|
||||
if (new_endpoint != current_endpoint) {
|
||||
/* Cancel all current keypresses so keys don't stay held on the old endpoint. */
|
||||
@@ -154,7 +223,10 @@ static int endpoint_listener(const struct zmk_event_header *eh) {
|
||||
current_endpoint = new_endpoint;
|
||||
LOG_INF("Endpoint changed: %d", current_endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
static int endpoint_listener(const struct zmk_event_header *eh) {
|
||||
update_current_endpoint();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -164,4 +236,6 @@ ZMK_SUBSCRIPTION(endpoint_listener, usb_conn_state_changed);
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
||||
ZMK_SUBSCRIPTION(endpoint_listener, ble_active_profile_changed);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SYS_INIT(zmk_endpoints_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||
|
||||
Reference in New Issue
Block a user