Merge d3065d7325
into 7bd74a6b0f
This commit is contained in:
commit
ca07831381
18 changed files with 416 additions and 0 deletions
|
@ -37,6 +37,7 @@ target_sources(app PRIVATE src/events/activity_state_changed.c)
|
|||
target_sources(app PRIVATE src/events/position_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/sensor_event.c)
|
||||
target_sources(app PRIVATE src/events/mouse_button_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_PROGRAMMABLE_BUTTONS app PRIVATE src/events/programmable_button_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
|
||||
|
@ -45,6 +46,7 @@ target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SOFT_OFF app PRIVATE src/behaviors/beha
|
|||
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE src/hid.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_MOUSE app PRIVATE src/mouse.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_PROGRAMMABLE_BUTTONS app PRIVATE src/programmable_buttons.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||
|
@ -63,6 +65,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_VAR app PRIVATE src/behaviors/behavior_sensor_rotate_var.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_SENSOR_ROTATE_COMMON app PRIVATE src/behaviors/behavior_sensor_rotate_common.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_MOUSE_KEY_PRESS app PRIVATE src/behaviors/behavior_mouse_key_press.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_PROGRAMMABLE_BUTTONS app PRIVATE src/behaviors/behavior_programmable_buttons.c)
|
||||
target_sources(app PRIVATE src/combo.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_tap_dance.c)
|
||||
target_sources(app PRIVATE src/behavior_queue.c)
|
||||
|
|
13
app/Kconfig
13
app/Kconfig
|
@ -219,6 +219,10 @@ config ZMK_BLE_MOUSE_REPORT_QUEUE_SIZE
|
|||
int "Max number of mouse HID reports to queue for sending over BLE"
|
||||
default 20
|
||||
|
||||
config ZMK_BLE_PROGRAMMABLE_BUTTONS_REPORT_QUEUE_SIZE
|
||||
int "Max number of programmable buttons HID reports to queue for sending over BLE"
|
||||
default 20
|
||||
|
||||
config ZMK_BLE_CLEAR_BONDS_ON_START
|
||||
bool "Configuration that clears all bond information from the keyboard on startup."
|
||||
|
||||
|
@ -373,6 +377,15 @@ endif
|
|||
#Display/LED Options
|
||||
endmenu
|
||||
|
||||
menu "Programmable Buttons"
|
||||
|
||||
config ZMK_PROGRAMMABLE_BUTTONS
|
||||
bool "Enable programmable buttons"
|
||||
default n
|
||||
|
||||
#Mouse Options
|
||||
endmenu
|
||||
|
||||
menu "Mouse Options"
|
||||
|
||||
config ZMK_MOUSE
|
||||
|
|
|
@ -21,3 +21,4 @@
|
|||
#include <behaviors/macros.dtsi>
|
||||
#include <behaviors/mouse_key_press.dtsi>
|
||||
#include <behaviors/soft_off.dtsi>
|
||||
#include <behaviors/programmable_buttons.dtsi>
|
||||
|
|
14
app/dts/behaviors/programmable_buttons.dtsi
Normal file
14
app/dts/behaviors/programmable_buttons.dtsi
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
/omit-if-no-ref/ pb: programmable_buttons {
|
||||
compatible = "zmk,behavior-programmable-buttons";
|
||||
#binding-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2020 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Programmable buttons press/release behavior
|
||||
|
||||
compatible: "zmk,behavior-programmable-buttons"
|
||||
|
||||
include: one_param.yaml
|
|
@ -70,6 +70,11 @@ struct zmk_endpoint_instance zmk_endpoints_selected(void);
|
|||
|
||||
int zmk_endpoints_send_report(uint16_t usage_page);
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
int zmk_endpoints_send_programmable_buttons_report();
|
||||
#endif // IS_ENABLE(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_endpoints_send_mouse_report();
|
||||
#endif // IS_ENABLE(CONFIG_ZMK_MOUSE)
|
||||
|
|
24
app/include/zmk/events/programmable_button_state_changed.h
Normal file
24
app/include/zmk/events/programmable_button_state_changed.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/event_manager.h>
|
||||
|
||||
struct zmk_programmable_button_state_changed {
|
||||
uint8_t index;
|
||||
bool state;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_programmable_button_state_changed);
|
||||
|
||||
static inline int raise_zmk_programmable_button_state_changed_from_encoded(uint8_t index, bool pressed,
|
||||
int64_t timestamp) {
|
||||
return raise_zmk_programmable_button_state_changed((struct zmk_programmable_button_state_changed){
|
||||
.index = index, .state = pressed, .timestamp = timestamp});
|
||||
}
|
|
@ -60,6 +60,7 @@
|
|||
#define ZMK_HID_REPORT_ID_LEDS 0x01
|
||||
#define ZMK_HID_REPORT_ID_CONSUMER 0x02
|
||||
#define ZMK_HID_REPORT_ID_MOUSE 0x03
|
||||
#define ZMK_HID_REPORT_ID_PROGRAMMABLE_BUTTONS 0x04
|
||||
|
||||
static const uint8_t zmk_hid_report_desc[] = {
|
||||
HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP),
|
||||
|
@ -145,6 +146,25 @@ static const uint8_t zmk_hid_report_desc[] = {
|
|||
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS),
|
||||
HID_END_COLLECTION,
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
HID_USAGE_PAGE(HID_USAGE_CONSUMER),
|
||||
HID_USAGE(HID_USAGE_CONSUMER_CONSUMER_CONTROL),
|
||||
HID_COLLECTION(HID_COLLECTION_APPLICATION),
|
||||
HID_REPORT_ID(ZMK_HID_REPORT_ID_PROGRAMMABLE_BUTTONS),
|
||||
HID_USAGE(HID_USAGE_CONSUMER_PROGRAMMABLE_BUTTONS),
|
||||
HID_COLLECTION(HID_COLLECTION_NAMED_ARRAY),
|
||||
HID_USAGE_PAGE(HID_USAGE_BUTTON),
|
||||
HID_USAGE_MIN8(0x1),
|
||||
HID_USAGE_MAX8(0x20),
|
||||
HID_LOGICAL_MIN8(0x00),
|
||||
HID_LOGICAL_MAX8(0x01),
|
||||
HID_REPORT_SIZE(0x01),
|
||||
HID_REPORT_COUNT(0x20),
|
||||
HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS),
|
||||
HID_END_COLLECTION,
|
||||
HID_END_COLLECTION,
|
||||
#endif //IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
HID_USAGE_PAGE(HID_USAGE_GD),
|
||||
HID_USAGE(HID_USAGE_GD_MOUSE),
|
||||
|
@ -239,6 +259,13 @@ struct zmk_hid_consumer_report {
|
|||
struct zmk_hid_consumer_report_body body;
|
||||
} __packed;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
struct zmk_hid_programmable_buttons_report {
|
||||
uint8_t report_id;
|
||||
uint32_t body;
|
||||
} __packed;
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
struct zmk_hid_mouse_report_body {
|
||||
zmk_mouse_button_flags_t buttons;
|
||||
|
@ -280,6 +307,12 @@ int zmk_hid_press(uint32_t usage);
|
|||
int zmk_hid_release(uint32_t usage);
|
||||
bool zmk_hid_is_pressed(uint32_t usage);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
int zmk_hid_programmable_button_press(uint8_t index);
|
||||
int zmk_hid_programmable_button_release(uint8_t index);
|
||||
void zmk_hid_programmable_buttons_clear(void);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_hid_mouse_button_press(zmk_mouse_button_t button);
|
||||
int zmk_hid_mouse_button_release(zmk_mouse_button_t button);
|
||||
|
@ -295,6 +328,10 @@ struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(void);
|
|||
zmk_hid_boot_report_t *zmk_hid_get_boot_report();
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
struct zmk_hid_programmable_buttons_report *zmk_hid_get_programmable_buttons_report(void);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
struct zmk_hid_mouse_report *zmk_hid_get_mouse_report();
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
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);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
int zmk_hog_send_programmable_buttons_report(uint32_t body);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_hog_send_mouse_report(struct zmk_hid_mouse_report_body *body);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
int zmk_usb_hid_send_keyboard_report(void);
|
||||
int zmk_usb_hid_send_consumer_report(void);
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
int zmk_usb_hid_send_programmable_buttons_report(void);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_usb_hid_send_mouse_report(void);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
52
app/src/behaviors/behavior_programmable_buttons.c
Normal file
52
app/src/behaviors/behavior_programmable_buttons.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_programmable_buttons
|
||||
|
||||
// Dependencies
|
||||
#include <zephyr/device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/programmable_button_state_changed.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("programmable button : position %d keycode 0x%02X", event.position, binding->param1);
|
||||
|
||||
return raise_zmk_programmable_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("programmable button : position %d keycode 0x%02X", event.position, binding->param1);
|
||||
return raise_zmk_programmable_button_state_changed_from_encoded(binding->param1, false,
|
||||
event.timestamp);
|
||||
}
|
||||
|
||||
// Initialization Function
|
||||
static int behavior_programmable_button_init(const struct device *dev) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// API Structure
|
||||
static const struct behavior_driver_api behavior_programmable_button_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released};
|
||||
|
||||
#define KP_INST(n) \
|
||||
BEHAVIOR_DT_INST_DEFINE(n, behavior_programmable_button_init, NULL, NULL, NULL, POST_KERNEL, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_programmable_button_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KP_INST)
|
||||
|
||||
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */
|
|
@ -203,6 +203,37 @@ int zmk_endpoints_send_report(uint16_t usage_page) {
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
int zmk_endpoints_send_programmable_buttons_report() {
|
||||
switch (current_instance.transport) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB)
|
||||
case ZMK_TRANSPORT_USB: {
|
||||
int err = zmk_usb_hid_send_programmable_buttons_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_TRANSPORT_BLE: {
|
||||
struct zmk_hid_programmable_buttons_report *programmable_buttons_report = zmk_hid_get_programmable_buttons_report();
|
||||
int err = zmk_hog_send_programmable_buttons_report(programmable_buttons_report->body);
|
||||
if (err) {
|
||||
LOG_ERR("FAILED TO SEND OVER HOG: %d", err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_BLE) */
|
||||
}
|
||||
|
||||
LOG_ERR("Unsupported endpoint transport %d", current_instance.transport);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_endpoints_send_mouse_report() {
|
||||
switch (current_instance.transport) {
|
||||
|
@ -334,6 +365,9 @@ static int zmk_endpoints_init(void) {
|
|||
void zmk_endpoints_clear_current(void) {
|
||||
zmk_hid_keyboard_clear();
|
||||
zmk_hid_consumer_clear();
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
zmk_hid_programmable_buttons_clear();
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
zmk_hid_mouse_clear();
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
|
9
app/src/events/programmable_button_state_changed.c
Normal file
9
app/src/events/programmable_button_state_changed.c
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zmk/events/programmable_button_state_changed.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_programmable_button_state_changed);
|
|
@ -18,6 +18,11 @@ static struct zmk_hid_keyboard_report keyboard_report = {
|
|||
static struct zmk_hid_consumer_report consumer_report = {.report_id = ZMK_HID_REPORT_ID_CONSUMER,
|
||||
.body = {.keys = {0}}};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
static struct zmk_hid_programmable_buttons_report programmable_buttons_report = {.report_id = ZMK_HID_REPORT_ID_PROGRAMMABLE_BUTTONS,
|
||||
.body = 0};
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
|
||||
static zmk_hid_boot_report_t boot_report = {.modifiers = 0, ._reserved = 0, .keys = {0}};
|
||||
|
@ -369,6 +374,27 @@ bool zmk_hid_is_pressed(uint32_t usage) {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
int zmk_hid_programmable_button_press(uint8_t index){
|
||||
if (index < 1 || index > 32) {
|
||||
return -EINVAL;
|
||||
}
|
||||
WRITE_BIT(programmable_buttons_report.body, index - 1, true);
|
||||
return 0;
|
||||
}
|
||||
int zmk_hid_programmable_button_release(uint8_t index){
|
||||
if (index < 1 || index > 32) {
|
||||
return -EINVAL;
|
||||
}
|
||||
WRITE_BIT(programmable_buttons_report.body, index -1, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zmk_hid_programmable_buttons_clear(void) { programmable_buttons_report.body = 0; }
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
// Keep track of how often a button was pressed.
|
||||
|
@ -442,6 +468,12 @@ struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(void) {
|
|||
return &consumer_report;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
struct zmk_hid_programmable_buttons_report *zmk_hid_get_programmable_buttons_report(void) {
|
||||
return &programmable_buttons_report;
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
struct zmk_hid_mouse_report *zmk_hid_get_mouse_report(void) {
|
||||
|
|
|
@ -69,6 +69,15 @@ static struct hids_report consumer_input = {
|
|||
.type = HIDS_INPUT,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
static struct hids_report programmable_buttons_input = {
|
||||
.id = ZMK_HID_REPORT_ID_PROGRAMMABLE_BUTTONS,
|
||||
.type = HIDS_INPUT,
|
||||
};
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
static struct hids_report mouse_input = {
|
||||
|
@ -143,6 +152,15 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn,
|
|||
sizeof(struct zmk_hid_consumer_report_body));
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
static ssize_t read_hids_programmable_buttons_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
void *buf, uint16_t len, uint16_t offset) {
|
||||
uint32_t report_body = zmk_hid_get_programmable_buttons_report()->body;
|
||||
return bt_gatt_attr_read(conn, attr, buf, len, offset, &report_body,
|
||||
sizeof(uint32_t));
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
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) {
|
||||
|
@ -200,6 +218,14 @@ BT_GATT_SERVICE_DEFINE(
|
|||
BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ_ENCRYPT, read_hids_report_ref,
|
||||
NULL, &consumer_input),
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
|
||||
BT_GATT_PERM_READ_ENCRYPT, read_hids_programmable_buttons_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, &programmable_buttons_input),
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
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),
|
||||
|
@ -328,6 +354,60 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
K_MSGQ_DEFINE(zmk_hog_programmable_buttons_msgq, sizeof(uint32_t),
|
||||
CONFIG_ZMK_BLE_PROGRAMMABLE_BUTTONS_REPORT_QUEUE_SIZE, 4);
|
||||
|
||||
void send_programmable_buttons_report_callback(struct k_work *work) {
|
||||
uint32_t report;
|
||||
while (k_msgq_get(&zmk_hog_programmable_buttons_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[13],
|
||||
.data = &report,
|
||||
.len = sizeof(report),
|
||||
};
|
||||
|
||||
int err = bt_gatt_notify_cb(conn, ¬ify_params);
|
||||
if (err == -EPERM) {
|
||||
bt_conn_set_security(conn, BT_SECURITY_L2);
|
||||
} else if (err) {
|
||||
LOG_DBG("Error notifying %d", err);
|
||||
}
|
||||
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
};
|
||||
|
||||
K_WORK_DEFINE(hog_programmable_buttons_work, send_programmable_buttons_report_callback);
|
||||
|
||||
int zmk_hog_send_programmable_buttons_report(uint32_t report) {
|
||||
int err = k_msgq_put(&zmk_hog_programmable_buttons_msgq, &report, K_MSEC(100));
|
||||
if (err) {
|
||||
switch (err) {
|
||||
case -EAGAIN: {
|
||||
LOG_WRN("Consumer message queue full, popping first message and queueing again");
|
||||
uint32_t discarded_report;
|
||||
k_msgq_get(&zmk_hog_programmable_buttons_msgq, &discarded_report, K_NO_WAIT);
|
||||
return zmk_hog_send_programmable_buttons_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_programmable_buttons_work);
|
||||
|
||||
return 0;
|
||||
};
|
||||
#endif //IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
|
||||
K_MSGQ_DEFINE(zmk_hog_mouse_msgq, sizeof(struct zmk_hid_mouse_report_body),
|
||||
|
|
42
app/src/programmable_buttons.c
Normal file
42
app/src/programmable_buttons.c
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/events/programmable_button_state_changed.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/endpoints.h>
|
||||
|
||||
static void listener_programmable_button_pressed(const struct zmk_programmable_button_state_changed *ev) {
|
||||
LOG_DBG("programmable button event press: 0x%02X", ev->index);
|
||||
zmk_hid_programmable_button_press(ev->index);
|
||||
zmk_endpoints_send_programmable_buttons_report();
|
||||
}
|
||||
|
||||
static void listener_programmable_button_released(const struct zmk_programmable_button_state_changed *ev) {
|
||||
LOG_DBG("programmable button event released: 0x%02X", ev->index);
|
||||
zmk_hid_programmable_button_release(ev->index);
|
||||
zmk_endpoints_send_programmable_buttons_report();
|
||||
}
|
||||
|
||||
int programmable_buttons_listener(const zmk_event_t *eh) {
|
||||
const struct zmk_programmable_button_state_changed *pb_ev = as_zmk_programmable_button_state_changed(eh);
|
||||
if (pb_ev) {
|
||||
if (pb_ev->state) {
|
||||
listener_programmable_button_pressed(pb_ev);
|
||||
} else {
|
||||
listener_programmable_button_released(pb_ev);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(programmable_buttons_listener, programmable_buttons_listener);
|
||||
ZMK_SUBSCRIPTION(programmable_buttons_listener, zmk_programmable_button_state_changed);
|
|
@ -164,6 +164,19 @@ int zmk_usb_hid_send_consumer_report(void) {
|
|||
return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report));
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
int zmk_usb_hid_send_programmable_buttons_report(void) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
if (hid_protocol == HID_PROTOCOL_BOOT) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */
|
||||
|
||||
struct zmk_hid_programmable_buttons_report *report = zmk_hid_get_programmable_buttons_report();
|
||||
return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report));
|
||||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_PROGRAMMABLE_BUTTONS)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_MOUSE)
|
||||
int zmk_usb_hid_send_mouse_report() {
|
||||
#if IS_ENABLED(CONFIG_ZMK_USB_BOOT)
|
||||
|
|
42
docs/docs/behaviors/programmable-buttons.md
Normal file
42
docs/docs/behaviors/programmable-buttons.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
title: Programmable Buttons Behaviors
|
||||
sidebar_label: Programmable Buttons
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
TODO: Programmable Buttons can be used to configure shortcuts that will not overlap with other softwares inputs. As per hid specification they are typically used to
|
||||
control software applications or GUI objects.
|
||||
|
||||
:::warning[OS Compatibility]
|
||||
|
||||
Only Linux is known to have programmable buttons compatibility
|
||||
|
||||
:::
|
||||
|
||||
## Configuration Option
|
||||
|
||||
This feature can be enabled or disabled explicitly via a config option:
|
||||
|
||||
```
|
||||
CONFIG_ZMK_PROGRAMMABLE_BUTTONS=y
|
||||
```
|
||||
|
||||
## Programmable Button Press
|
||||
|
||||
This behavior can press/release up to 32 programmable buttons.
|
||||
|
||||
### Behavior Binding
|
||||
|
||||
- Reference: `&pb`
|
||||
- Parameter: A `uint8` from 1 up to 32
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
The following will send the programmable button 1
|
||||
|
||||
```
|
||||
&pb 1
|
||||
```
|
||||
|
Loading…
Add table
Reference in a new issue