2026-04-08 16:32:13 +08:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <app_event_manager.h>
|
|
|
|
|
|
|
|
|
|
#define MODULE keyboard_core_module
|
|
|
|
|
#include <caf/events/button_event.h>
|
|
|
|
|
#include <caf/events/module_state_event.h>
|
|
|
|
|
#include <caf/events/power_event.h>
|
|
|
|
|
|
|
|
|
|
#include <caf/key_id.h>
|
|
|
|
|
#include <zephyr/logging/log.h>
|
|
|
|
|
#include <zephyr/sys/byteorder.h>
|
|
|
|
|
#include <zephyr/sys/util.h>
|
|
|
|
|
|
2026-04-10 13:46:50 +08:00
|
|
|
#include "encoder_event.h"
|
2026-04-15 10:52:01 +08:00
|
|
|
#include "function_bitmap_state_event.h"
|
2026-04-13 11:55:59 +08:00
|
|
|
#include "function_bitmap_update_event.h"
|
2026-04-08 16:32:13 +08:00
|
|
|
#include "keyboard_core.h"
|
|
|
|
|
#include "keyboard_hid_report_event.h"
|
2026-04-17 19:12:57 +08:00
|
|
|
#include "module_lifecycle.h"
|
2026-04-23 15:12:29 +08:00
|
|
|
#include "settings_mode_event.h"
|
2026-04-10 09:06:18 +08:00
|
|
|
#include "set_protocol_event.h"
|
2026-04-23 09:48:06 +08:00
|
|
|
#include "transport_policy_event.h"
|
2026-04-08 16:32:13 +08:00
|
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(MODULE, LOG_LEVEL_INF);
|
|
|
|
|
|
|
|
|
|
#define KEYBOARD_USAGE_FIRST_MODIFIER 0xE0U
|
|
|
|
|
#define KEYBOARD_USAGE_LAST_MODIFIER 0xE7U
|
|
|
|
|
#define KEYBOARD_USAGE_ERROR_ROLLOVER 0x01U
|
|
|
|
|
#define KEYBOARD_BOOT_RESERVED_BYTE 0x00U
|
|
|
|
|
|
|
|
|
|
enum key_usage_type {
|
|
|
|
|
KEY_USAGE_TYPE_KEYBOARD,
|
|
|
|
|
KEY_USAGE_TYPE_CONSUMER,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct keymap_entry {
|
|
|
|
|
uint16_t key_id;
|
|
|
|
|
uint8_t usage_type;
|
|
|
|
|
uint16_t usage_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct keyboard_state {
|
2026-04-13 11:55:59 +08:00
|
|
|
uint8_t pressed_usage_bitmap[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
|
|
|
|
uint8_t function_pressed_bitmap[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
2026-04-08 16:32:13 +08:00
|
|
|
uint32_t consumer_bits;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct keyboard_reports_cache {
|
|
|
|
|
uint8_t boot_report[KEYBOARD_BOOT_REPORT_SIZE];
|
|
|
|
|
uint8_t nkro_report[KEYBOARD_NKRO_REPORT_SIZE];
|
|
|
|
|
uint8_t consumer_report[KEYBOARD_CONSUMER_REPORT_SIZE];
|
|
|
|
|
bool boot_valid;
|
|
|
|
|
bool nkro_valid;
|
|
|
|
|
bool consumer_valid;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct keymap_entry keymap[] = {
|
|
|
|
|
{ KEY_ID(0, 1), KEY_USAGE_TYPE_KEYBOARD, 0x0053 }, /* num lock */
|
|
|
|
|
{ KEY_ID(0, 2), KEY_USAGE_TYPE_KEYBOARD, 0x005F }, /* keypad 7 */
|
|
|
|
|
{ KEY_ID(0, 3), KEY_USAGE_TYPE_KEYBOARD, 0x005C }, /* keypad 4 */
|
|
|
|
|
{ KEY_ID(0, 4), KEY_USAGE_TYPE_KEYBOARD, 0x0059 }, /* keypad 1 */
|
|
|
|
|
{ KEY_ID(0, 5), KEY_USAGE_TYPE_KEYBOARD, 0x0062 }, /* keypad 0 */
|
|
|
|
|
{ KEY_ID(1, 1), KEY_USAGE_TYPE_KEYBOARD, 0x0054 }, /* keypad / */
|
|
|
|
|
{ KEY_ID(1, 2), KEY_USAGE_TYPE_KEYBOARD, 0x0060 }, /* keypad 8 */
|
|
|
|
|
{ KEY_ID(1, 3), KEY_USAGE_TYPE_KEYBOARD, 0x005D }, /* keypad 5 */
|
|
|
|
|
{ KEY_ID(1, 4), KEY_USAGE_TYPE_KEYBOARD, 0x005A }, /* keypad 2 */
|
|
|
|
|
{ KEY_ID(1, 5), KEY_USAGE_TYPE_KEYBOARD, 0x0063 }, /* keypad . */
|
|
|
|
|
{ KEY_ID(2, 1), KEY_USAGE_TYPE_KEYBOARD, 0x0055 }, /* keypad * */
|
|
|
|
|
{ KEY_ID(2, 2), KEY_USAGE_TYPE_KEYBOARD, 0x0061 }, /* keypad 9 */
|
|
|
|
|
{ KEY_ID(2, 3), KEY_USAGE_TYPE_KEYBOARD, 0x005E }, /* keypad 6 */
|
|
|
|
|
{ KEY_ID(2, 4), KEY_USAGE_TYPE_KEYBOARD, 0x005B }, /* keypad 3 */
|
|
|
|
|
{ KEY_ID(3, 0), KEY_USAGE_TYPE_CONSUMER, KEYBOARD_CONSUMER_CTRL_MUTE },
|
|
|
|
|
{ KEY_ID(3, 1), KEY_USAGE_TYPE_KEYBOARD, 0x0056 }, /* keypad - */
|
|
|
|
|
{ KEY_ID(3, 3), KEY_USAGE_TYPE_KEYBOARD, 0x0057 }, /* keypad + */
|
2026-04-10 11:42:19 +08:00
|
|
|
{ KEY_ID(3, 5), KEY_USAGE_TYPE_KEYBOARD, 0x0058 }, /* keypad enter */
|
2026-04-08 16:32:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const uint16_t consumer_usage_map[KEYBOARD_CONSUMER_CTRL_COUNT] = {
|
|
|
|
|
[KEYBOARD_CONSUMER_CTRL_MUTE] = 0x00E2,
|
|
|
|
|
[KEYBOARD_CONSUMER_CTRL_VOLUME_UP] = 0x00E9,
|
|
|
|
|
[KEYBOARD_CONSUMER_CTRL_VOLUME_DOWN] = 0x00EA,
|
|
|
|
|
[KEYBOARD_CONSUMER_CTRL_PLAY_PAUSE] = 0x00CD,
|
|
|
|
|
[KEYBOARD_CONSUMER_CTRL_NEXT_TRACK] = 0x00B5,
|
|
|
|
|
[KEYBOARD_CONSUMER_CTRL_PREV_TRACK] = 0x00B6,
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
struct keyboard_core_module_ctx {
|
|
|
|
|
struct module_lifecycle_ctx lc;
|
|
|
|
|
struct keyboard_state keyboard_state;
|
|
|
|
|
struct keyboard_reports_cache reports_cache;
|
|
|
|
|
uint8_t function_usage_mask[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
|
|
|
|
enum keyboard_protocol_mode transport_protocol_modes[HID_TRANSPORT_COUNT];
|
2026-04-23 09:48:06 +08:00
|
|
|
enum hid_transport_policy current_transport;
|
2026-04-23 15:12:29 +08:00
|
|
|
bool settings_active;
|
2026-04-10 19:28:20 +08:00
|
|
|
};
|
2026-04-17 19:12:57 +08:00
|
|
|
|
|
|
|
|
static int do_init(void);
|
|
|
|
|
static int do_start(void);
|
|
|
|
|
static int do_stop(void);
|
|
|
|
|
|
|
|
|
|
static const struct module_lifecycle_cfg lifecycle_cfg = {
|
|
|
|
|
.mode = ML_MODE_POWER,
|
|
|
|
|
.stopped_state = MODULE_STATE_STANDBY,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct module_lifecycle_ops lifecycle_ops = {
|
|
|
|
|
.do_init = do_init,
|
|
|
|
|
.do_start = do_start,
|
|
|
|
|
.do_stop = do_stop,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct keyboard_core_module_ctx ctx = {
|
|
|
|
|
.lc = {
|
|
|
|
|
.state = LC_UNINIT,
|
|
|
|
|
.cfg = &lifecycle_cfg,
|
|
|
|
|
.ops = &lifecycle_ops,
|
|
|
|
|
},
|
|
|
|
|
.transport_protocol_modes = {
|
|
|
|
|
[HID_TRANSPORT_USB] = KEYBOARD_PROTOCOL_MODE_REPORT,
|
|
|
|
|
[HID_TRANSPORT_BLE] = KEYBOARD_PROTOCOL_MODE_REPORT,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static bool policy_to_transport(enum hid_transport_policy policy,
|
|
|
|
|
enum hid_transport *transport)
|
2026-04-10 19:28:20 +08:00
|
|
|
{
|
2026-04-23 09:48:06 +08:00
|
|
|
switch (policy) {
|
|
|
|
|
case HID_TRANSPORT_POLICY_USB:
|
2026-04-10 19:28:20 +08:00
|
|
|
*transport = HID_TRANSPORT_USB;
|
|
|
|
|
return true;
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
case HID_TRANSPORT_POLICY_BLE:
|
2026-04-10 19:28:20 +08:00
|
|
|
*transport = HID_TRANSPORT_BLE;
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum keyboard_protocol_mode active_protocol_mode_get(void)
|
|
|
|
|
{
|
|
|
|
|
enum hid_transport transport;
|
|
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (policy_to_transport(ctx.current_transport, &transport)) {
|
2026-04-24 10:54:14 +08:00
|
|
|
return ctx.transport_protocol_modes[transport];
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return KEYBOARD_PROTOCOL_MODE_REPORT;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static bool transport_policy_to_mode(enum hid_transport_policy policy,
|
|
|
|
|
enum mode_switch_mode *mode)
|
|
|
|
|
{
|
|
|
|
|
if (mode == NULL) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (policy) {
|
|
|
|
|
case HID_TRANSPORT_POLICY_USB:
|
|
|
|
|
*mode = MODE_SWITCH_USB;
|
|
|
|
|
return true;
|
|
|
|
|
case HID_TRANSPORT_POLICY_BLE:
|
|
|
|
|
*mode = MODE_SWITCH_BLE;
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
static const struct keymap_entry *keymap_get(uint16_t key_id)
|
|
|
|
|
{
|
|
|
|
|
size_t left = 0;
|
|
|
|
|
size_t right = ARRAY_SIZE(keymap);
|
|
|
|
|
|
|
|
|
|
while (left < right) {
|
|
|
|
|
size_t mid = left + ((right - left) / 2U);
|
|
|
|
|
|
|
|
|
|
if (keymap[mid].key_id == key_id) {
|
|
|
|
|
return &keymap[mid];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (keymap[mid].key_id < key_id) {
|
|
|
|
|
left = mid + 1U;
|
|
|
|
|
} else {
|
|
|
|
|
right = mid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 10:52:01 +08:00
|
|
|
static bool usage_to_bitmap_pos(uint16_t usage_id, uint8_t *byte_idx,
|
|
|
|
|
uint8_t *bit_idx)
|
|
|
|
|
{
|
|
|
|
|
if ((byte_idx == NULL) || (bit_idx == NULL)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((usage_id >= KEYBOARD_USAGE_FIRST_MODIFIER) &&
|
|
|
|
|
(usage_id <= KEYBOARD_USAGE_LAST_MODIFIER)) {
|
|
|
|
|
*byte_idx = 0U;
|
|
|
|
|
*bit_idx = (uint8_t)(usage_id - KEYBOARD_USAGE_FIRST_MODIFIER);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (usage_id <= KEYBOARD_NKRO_USAGE_MAX) {
|
|
|
|
|
*byte_idx = (uint8_t)(1U + (usage_id / 8U));
|
|
|
|
|
*bit_idx = (uint8_t)(usage_id % 8U);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
static bool usage_bitmap_test(const uint8_t *bitmap, uint16_t usage_id)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
2026-04-15 10:52:01 +08:00
|
|
|
uint8_t byte_idx;
|
|
|
|
|
uint8_t bit_idx;
|
|
|
|
|
|
|
|
|
|
if ((bitmap == NULL) ||
|
|
|
|
|
!usage_to_bitmap_pos(usage_id, &byte_idx, &bit_idx)) {
|
2026-04-13 11:55:59 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-15 10:52:01 +08:00
|
|
|
return (bitmap[byte_idx] & BIT(bit_idx)) != 0U;
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
static bool usage_bitmap_write(uint8_t *bitmap, uint16_t usage_id, bool pressed)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
2026-04-13 11:55:59 +08:00
|
|
|
uint8_t byte_idx;
|
|
|
|
|
uint8_t bit_idx;
|
|
|
|
|
bool was_pressed;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-15 10:52:01 +08:00
|
|
|
if ((bitmap == NULL) ||
|
|
|
|
|
!usage_to_bitmap_pos(usage_id, &byte_idx, &bit_idx)) {
|
2026-04-08 16:32:13 +08:00
|
|
|
LOG_WRN("Unsupported keyboard usage 0x%04x", usage_id);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
was_pressed = (bitmap[byte_idx] & BIT(bit_idx)) != 0U;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
|
|
|
|
if (was_pressed == pressed) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
WRITE_BIT(bitmap[byte_idx], bit_idx, pressed);
|
2026-04-08 16:32:13 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool consumer_key_update(uint16_t consumer_id, bool pressed)
|
|
|
|
|
{
|
|
|
|
|
if (consumer_id >= KEYBOARD_CONSUMER_CTRL_COUNT) {
|
|
|
|
|
LOG_WRN("Unsupported consumer id %u", consumer_id);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
bool was_pressed =
|
|
|
|
|
(ctx.keyboard_state.consumer_bits & BIT(consumer_id)) != 0U;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
|
|
|
|
if (was_pressed == pressed) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
WRITE_BIT(ctx.keyboard_state.consumer_bits, consumer_id, pressed);
|
2026-04-08 16:32:13 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void keyboard_state_clear(void)
|
|
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
memset(&ctx.keyboard_state, 0, sizeof(ctx.keyboard_state));
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
static void function_usage_mask_clear(void)
|
|
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
memset(ctx.function_usage_mask, 0, sizeof(ctx.function_usage_mask));
|
2026-04-13 11:55:59 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
static void reports_cache_invalidate(void)
|
|
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.reports_cache.boot_valid = false;
|
|
|
|
|
ctx.reports_cache.nkro_valid = false;
|
|
|
|
|
ctx.reports_cache.consumer_valid = false;
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
static void build_effective_hid_bitmap(uint8_t bitmap[KEYBOARD_PROTOCOL_BITMAP_BYTES])
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < KEYBOARD_PROTOCOL_BITMAP_BYTES; i++) {
|
2026-04-24 10:54:14 +08:00
|
|
|
bitmap[i] = ctx.keyboard_state.pressed_usage_bitmap[i] &
|
|
|
|
|
(uint8_t)~ctx.keyboard_state.function_pressed_bitmap[i];
|
2026-04-13 11:55:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
static void build_boot_report(uint8_t report[KEYBOARD_BOOT_REPORT_SIZE])
|
|
|
|
|
{
|
2026-04-13 11:55:59 +08:00
|
|
|
uint8_t effective_hid_bitmap[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
2026-04-08 16:32:13 +08:00
|
|
|
size_t key_count = 0;
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
build_effective_hid_bitmap(effective_hid_bitmap);
|
2026-04-08 16:32:13 +08:00
|
|
|
memset(report, 0, KEYBOARD_BOOT_REPORT_SIZE);
|
2026-04-15 10:52:01 +08:00
|
|
|
report[0] = effective_hid_bitmap[0];
|
2026-04-08 16:32:13 +08:00
|
|
|
report[1] = KEYBOARD_BOOT_RESERVED_BYTE;
|
|
|
|
|
|
|
|
|
|
for (uint16_t usage_id = 0; usage_id <= KEYBOARD_NKRO_USAGE_MAX; usage_id++) {
|
2026-04-15 10:52:01 +08:00
|
|
|
uint8_t byte_idx;
|
|
|
|
|
uint8_t bit_idx;
|
|
|
|
|
|
|
|
|
|
(void)usage_to_bitmap_pos(usage_id, &byte_idx, &bit_idx);
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
if ((effective_hid_bitmap[byte_idx] & BIT(bit_idx)) == 0U) {
|
2026-04-08 16:32:13 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key_count == (KEYBOARD_BOOT_REPORT_SIZE - 2U)) {
|
|
|
|
|
memset(&report[2], KEYBOARD_USAGE_ERROR_ROLLOVER,
|
|
|
|
|
KEYBOARD_BOOT_REPORT_SIZE - 2U);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
report[2U + key_count] = (uint8_t)usage_id;
|
|
|
|
|
key_count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void build_nkro_report(uint8_t report[KEYBOARD_NKRO_REPORT_SIZE])
|
|
|
|
|
{
|
2026-04-13 11:55:59 +08:00
|
|
|
uint8_t effective_hid_bitmap[KEYBOARD_PROTOCOL_BITMAP_BYTES];
|
|
|
|
|
|
|
|
|
|
build_effective_hid_bitmap(effective_hid_bitmap);
|
2026-04-15 10:52:01 +08:00
|
|
|
report[0] = effective_hid_bitmap[0];
|
|
|
|
|
memcpy(&report[1], &effective_hid_bitmap[1], KEYBOARD_NKRO_BITMAP_BYTES);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint16_t active_consumer_usage_get(void)
|
|
|
|
|
{
|
|
|
|
|
for (uint8_t consumer_id = 0; consumer_id < KEYBOARD_CONSUMER_CTRL_COUNT; consumer_id++) {
|
2026-04-24 10:54:14 +08:00
|
|
|
if ((ctx.keyboard_state.consumer_bits & BIT(consumer_id)) != 0U) {
|
2026-04-08 16:32:13 +08:00
|
|
|
return consumer_usage_map[consumer_id];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0U;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void build_consumer_report(uint8_t report[KEYBOARD_CONSUMER_REPORT_SIZE])
|
|
|
|
|
{
|
|
|
|
|
sys_put_le16(active_consumer_usage_get(), report);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 13:46:50 +08:00
|
|
|
static void submit_consumer_fifo_frame(uint16_t usage_id)
|
|
|
|
|
{
|
|
|
|
|
uint8_t report_buf[KEYBOARD_CONSUMER_REPORT_SIZE];
|
2026-04-10 19:28:20 +08:00
|
|
|
enum keyboard_protocol_mode protocol_mode = active_protocol_mode_get();
|
2026-04-23 09:48:06 +08:00
|
|
|
enum mode_switch_mode mode;
|
2026-04-10 13:46:50 +08:00
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc) ||
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.settings_active ||
|
|
|
|
|
!transport_policy_to_mode(ctx.current_transport, &mode) ||
|
2026-04-10 19:28:20 +08:00
|
|
|
(protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT)) {
|
2026-04-10 13:46:50 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sys_put_le16(usage_id, report_buf);
|
2026-04-14 16:42:04 +08:00
|
|
|
(void)submit_keyboard_hid_report_event(
|
2026-04-23 09:48:06 +08:00
|
|
|
mode, KEYBOARD_REPORT_TYPE_CONSUMER, protocol_mode,
|
2026-04-14 16:42:04 +08:00
|
|
|
HID_QUEUE_POLICY_FIFO, report_buf, KEYBOARD_CONSUMER_REPORT_SIZE);
|
2026-04-10 13:46:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void submit_consumer_pulse_frames(enum keyboard_consumer_control control_id,
|
|
|
|
|
uint8_t pulse_count)
|
|
|
|
|
{
|
|
|
|
|
uint16_t usage_id;
|
|
|
|
|
|
2026-04-10 19:28:20 +08:00
|
|
|
if (active_protocol_mode_get() == KEYBOARD_PROTOCOL_MODE_BOOT) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 13:46:50 +08:00
|
|
|
if (control_id >= KEYBOARD_CONSUMER_CTRL_COUNT) {
|
|
|
|
|
LOG_WRN("Unsupported consumer control id %u", control_id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
usage_id = consumer_usage_map[control_id];
|
|
|
|
|
if (usage_id == 0U) {
|
|
|
|
|
LOG_WRN("Unmapped consumer control id %u", control_id);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < pulse_count; i++) {
|
|
|
|
|
submit_consumer_fifo_frame(usage_id);
|
|
|
|
|
submit_consumer_fifo_frame(0U);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
static void emit_keys_report(bool force)
|
|
|
|
|
{
|
|
|
|
|
uint8_t report_buf[KEYBOARD_NKRO_REPORT_SIZE];
|
|
|
|
|
uint8_t report_size;
|
|
|
|
|
uint8_t *cache_buf;
|
|
|
|
|
bool *cache_valid;
|
2026-04-10 19:28:20 +08:00
|
|
|
enum keyboard_protocol_mode protocol_mode = active_protocol_mode_get();
|
2026-04-23 09:48:06 +08:00
|
|
|
enum mode_switch_mode mode;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (!transport_policy_to_mode(ctx.current_transport, &mode)) {
|
2026-04-08 16:32:13 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (ctx.settings_active) {
|
2026-04-23 15:12:29 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
if (protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) {
|
|
|
|
|
build_boot_report(report_buf);
|
|
|
|
|
report_size = KEYBOARD_BOOT_REPORT_SIZE;
|
2026-04-24 10:54:14 +08:00
|
|
|
cache_buf = ctx.reports_cache.boot_report;
|
|
|
|
|
cache_valid = &ctx.reports_cache.boot_valid;
|
2026-04-08 16:32:13 +08:00
|
|
|
} else {
|
|
|
|
|
build_nkro_report(report_buf);
|
|
|
|
|
report_size = KEYBOARD_NKRO_REPORT_SIZE;
|
2026-04-24 10:54:14 +08:00
|
|
|
cache_buf = ctx.reports_cache.nkro_report;
|
|
|
|
|
cache_valid = &ctx.reports_cache.nkro_valid;
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!force && *cache_valid && (memcmp(cache_buf, report_buf, report_size) == 0)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(cache_buf, report_buf, report_size);
|
|
|
|
|
*cache_valid = true;
|
|
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
(void)submit_keyboard_hid_report_event(
|
2026-04-23 09:48:06 +08:00
|
|
|
mode, KEYBOARD_REPORT_TYPE_KEYS, protocol_mode,
|
2026-04-14 16:42:04 +08:00
|
|
|
HID_QUEUE_POLICY_LATEST, report_buf, report_size);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_consumer_report(bool force)
|
|
|
|
|
{
|
|
|
|
|
uint8_t report_buf[KEYBOARD_CONSUMER_REPORT_SIZE];
|
2026-04-10 19:28:20 +08:00
|
|
|
enum keyboard_protocol_mode protocol_mode = active_protocol_mode_get();
|
2026-04-23 09:48:06 +08:00
|
|
|
enum mode_switch_mode mode;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (!transport_policy_to_mode(ctx.current_transport, &mode) ||
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.settings_active ||
|
2026-04-23 09:48:06 +08:00
|
|
|
(protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT)) {
|
2026-04-08 16:32:13 +08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
build_consumer_report(report_buf);
|
2026-04-24 10:54:14 +08:00
|
|
|
if (!force && ctx.reports_cache.consumer_valid &&
|
|
|
|
|
(memcmp(ctx.reports_cache.consumer_report, report_buf,
|
2026-04-08 16:32:13 +08:00
|
|
|
KEYBOARD_CONSUMER_REPORT_SIZE) == 0)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
memcpy(ctx.reports_cache.consumer_report, report_buf,
|
|
|
|
|
KEYBOARD_CONSUMER_REPORT_SIZE);
|
|
|
|
|
ctx.reports_cache.consumer_valid = true;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
(void)submit_keyboard_hid_report_event(
|
2026-04-23 09:48:06 +08:00
|
|
|
mode, KEYBOARD_REPORT_TYPE_CONSUMER, protocol_mode,
|
2026-04-14 16:42:04 +08:00
|
|
|
HID_QUEUE_POLICY_LATEST, report_buf,
|
|
|
|
|
KEYBOARD_CONSUMER_REPORT_SIZE);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void emit_all_reports(bool force)
|
|
|
|
|
{
|
|
|
|
|
emit_keys_report(force);
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
if (active_protocol_mode_get() != KEYBOARD_PROTOCOL_MODE_BOOT) {
|
|
|
|
|
emit_consumer_report(force);
|
|
|
|
|
}
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-15 10:52:01 +08:00
|
|
|
static void emit_function_state_event(void)
|
2026-04-13 11:55:59 +08:00
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
(void)submit_function_bitmap_state_event(
|
|
|
|
|
ctx.keyboard_state.pressed_usage_bitmap);
|
2026-04-13 11:55:59 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static void emit_release_reports(enum hid_transport_policy transport_policy)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
|
|
|
|
uint8_t keys_report[KEYBOARD_NKRO_REPORT_SIZE] = { 0 };
|
|
|
|
|
uint8_t consumer_report[KEYBOARD_CONSUMER_REPORT_SIZE] = { 0 };
|
2026-04-10 19:28:20 +08:00
|
|
|
enum keyboard_protocol_mode protocol_mode = active_protocol_mode_get();
|
2026-04-23 09:48:06 +08:00
|
|
|
enum mode_switch_mode mode;
|
2026-04-08 16:32:13 +08:00
|
|
|
size_t keys_report_size =
|
|
|
|
|
(protocol_mode == KEYBOARD_PROTOCOL_MODE_BOOT) ?
|
|
|
|
|
KEYBOARD_BOOT_REPORT_SIZE : KEYBOARD_NKRO_REPORT_SIZE;
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
switch (transport_policy) {
|
|
|
|
|
case HID_TRANSPORT_POLICY_USB:
|
|
|
|
|
mode = MODE_SWITCH_USB;
|
|
|
|
|
break;
|
|
|
|
|
case HID_TRANSPORT_POLICY_BLE:
|
|
|
|
|
mode = MODE_SWITCH_BLE;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-14 16:42:04 +08:00
|
|
|
(void)submit_keyboard_hid_report_event(
|
|
|
|
|
mode, KEYBOARD_REPORT_TYPE_KEYS, protocol_mode,
|
|
|
|
|
HID_QUEUE_POLICY_LATEST, keys_report, keys_report_size);
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-10 19:28:20 +08:00
|
|
|
if (protocol_mode != KEYBOARD_PROTOCOL_MODE_BOOT) {
|
2026-04-14 16:42:04 +08:00
|
|
|
(void)submit_keyboard_hid_report_event(
|
|
|
|
|
mode, KEYBOARD_REPORT_TYPE_CONSUMER, protocol_mode,
|
|
|
|
|
HID_QUEUE_POLICY_LATEST, consumer_report,
|
|
|
|
|
KEYBOARD_CONSUMER_REPORT_SIZE);
|
2026-04-10 19:28:20 +08:00
|
|
|
}
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_init(void)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
|
|
|
|
keyboard_state_clear();
|
|
|
|
|
reports_cache_invalidate();
|
2026-04-13 11:55:59 +08:00
|
|
|
function_usage_mask_clear();
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.settings_active = false;
|
2026-04-25 15:40:49 +08:00
|
|
|
ctx.current_transport = HID_TRANSPORT_POLICY_USB;
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.transport_protocol_modes[HID_TRANSPORT_USB] =
|
2026-04-10 19:28:20 +08:00
|
|
|
KEYBOARD_PROTOCOL_MODE_REPORT;
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.transport_protocol_modes[HID_TRANSPORT_BLE] =
|
2026-04-10 19:28:20 +08:00
|
|
|
KEYBOARD_PROTOCOL_MODE_REPORT;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_start(void)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
if (module_lifecycle_is_running(&ctx.lc)) {
|
2026-04-08 16:32:13 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 19:12:57 +08:00
|
|
|
static int do_stop(void)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
2026-04-17 19:12:57 +08:00
|
|
|
return 0;
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (ctx.current_transport != HID_TRANSPORT_POLICY_NONE) {
|
2026-04-24 10:54:14 +08:00
|
|
|
emit_release_reports(ctx.current_transport);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
2026-04-15 10:52:01 +08:00
|
|
|
emit_function_state_event();
|
2026-04-08 16:32:13 +08:00
|
|
|
|
|
|
|
|
keyboard_state_clear();
|
|
|
|
|
reports_cache_invalidate();
|
2026-04-17 19:12:57 +08:00
|
|
|
|
|
|
|
|
return 0;
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool handle_button_event(const struct button_event *event)
|
|
|
|
|
{
|
|
|
|
|
const struct keymap_entry *entry;
|
|
|
|
|
bool changed;
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
2026-04-08 16:32:13 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (ctx.settings_active) {
|
2026-04-23 15:12:29 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
entry = keymap_get(event->key_id);
|
|
|
|
|
if (!entry) {
|
|
|
|
|
LOG_WRN("Unmapped key id 0x%04x", event->key_id);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry->usage_type == KEY_USAGE_TYPE_KEYBOARD) {
|
2026-04-13 11:55:59 +08:00
|
|
|
bool routed_to_function;
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
changed = usage_bitmap_write(ctx.keyboard_state.pressed_usage_bitmap,
|
2026-04-13 11:55:59 +08:00
|
|
|
entry->usage_id, event->pressed);
|
|
|
|
|
if (!changed) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (event->pressed) {
|
|
|
|
|
routed_to_function =
|
2026-04-24 10:54:14 +08:00
|
|
|
usage_bitmap_test(ctx.function_usage_mask, entry->usage_id);
|
|
|
|
|
(void)usage_bitmap_write(ctx.keyboard_state.function_pressed_bitmap,
|
2026-04-13 11:55:59 +08:00
|
|
|
entry->usage_id, routed_to_function);
|
|
|
|
|
} else {
|
|
|
|
|
routed_to_function =
|
2026-04-24 10:54:14 +08:00
|
|
|
usage_bitmap_test(ctx.keyboard_state.function_pressed_bitmap,
|
2026-04-13 11:55:59 +08:00
|
|
|
entry->usage_id);
|
2026-04-24 10:54:14 +08:00
|
|
|
(void)usage_bitmap_write(ctx.keyboard_state.function_pressed_bitmap,
|
2026-04-13 11:55:59 +08:00
|
|
|
entry->usage_id, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (routed_to_function) {
|
2026-04-15 10:52:01 +08:00
|
|
|
emit_function_state_event();
|
2026-04-13 11:55:59 +08:00
|
|
|
} else {
|
2026-04-08 16:32:13 +08:00
|
|
|
emit_keys_report(false);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
changed = consumer_key_update(entry->usage_id, event->pressed);
|
|
|
|
|
if (changed) {
|
|
|
|
|
emit_consumer_report(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
static bool handle_transport_policy_event(
|
|
|
|
|
const struct transport_policy_event *event)
|
2026-04-08 16:32:13 +08:00
|
|
|
{
|
2026-04-23 09:48:06 +08:00
|
|
|
bool transport_changed;
|
2026-04-08 16:32:13 +08:00
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc)) {
|
|
|
|
|
ctx.current_transport = event->hid_transport;
|
2026-04-08 16:32:13 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
transport_changed = (ctx.current_transport != HID_TRANSPORT_POLICY_NONE) &&
|
|
|
|
|
(ctx.current_transport != event->hid_transport);
|
2026-04-23 09:48:06 +08:00
|
|
|
if (transport_changed) {
|
2026-04-24 10:54:14 +08:00
|
|
|
emit_release_reports(ctx.current_transport);
|
2026-04-15 10:52:01 +08:00
|
|
|
emit_function_state_event();
|
2026-04-08 16:32:13 +08:00
|
|
|
keyboard_state_clear();
|
|
|
|
|
reports_cache_invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.current_transport = event->hid_transport;
|
2026-04-23 09:48:06 +08:00
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (ctx.current_transport != HID_TRANSPORT_POLICY_NONE) {
|
2026-04-23 09:48:06 +08:00
|
|
|
emit_all_reports(true);
|
|
|
|
|
}
|
2026-04-08 16:32:13 +08:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 13:46:50 +08:00
|
|
|
static bool handle_encoder_event(const struct encoder_event *event)
|
|
|
|
|
{
|
2026-04-25 15:40:49 +08:00
|
|
|
if (!module_lifecycle_is_running(&ctx.lc) ||
|
|
|
|
|
(ctx.current_transport == HID_TRANSPORT_POLICY_NONE)) {
|
2026-04-10 13:46:50 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (ctx.settings_active) {
|
2026-04-23 15:12:29 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 13:46:50 +08:00
|
|
|
if (event->detents > 0) {
|
|
|
|
|
submit_consumer_pulse_frames(KEYBOARD_CONSUMER_CTRL_VOLUME_UP,
|
|
|
|
|
(uint8_t)event->detents);
|
|
|
|
|
} else if (event->detents < 0) {
|
|
|
|
|
submit_consumer_pulse_frames(KEYBOARD_CONSUMER_CTRL_VOLUME_DOWN,
|
|
|
|
|
(uint8_t)(-event->detents));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
static bool handle_function_bitmap_update_event(
|
|
|
|
|
const struct function_bitmap_update_event *event)
|
|
|
|
|
{
|
2026-04-24 10:54:14 +08:00
|
|
|
memcpy(ctx.function_usage_mask, event->bitmap,
|
|
|
|
|
sizeof(ctx.function_usage_mask));
|
2026-04-13 11:55:59 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
static bool app_event_handler(const struct app_event_header *aeh)
|
|
|
|
|
{
|
|
|
|
|
if (is_button_event(aeh)) {
|
|
|
|
|
return handle_button_event(cast_button_event(aeh));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 13:46:50 +08:00
|
|
|
if (is_encoder_event(aeh)) {
|
|
|
|
|
return handle_encoder_event(cast_encoder_event(aeh));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-13 11:55:59 +08:00
|
|
|
if (is_function_bitmap_update_event(aeh)) {
|
|
|
|
|
return handle_function_bitmap_update_event(
|
|
|
|
|
cast_function_bitmap_update_event(aeh));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-10 09:06:18 +08:00
|
|
|
if (is_set_protocol_event(aeh)) {
|
|
|
|
|
const struct set_protocol_event *event = cast_set_protocol_event(aeh);
|
2026-04-10 19:28:20 +08:00
|
|
|
enum hid_transport active_transport;
|
2026-04-10 09:06:18 +08:00
|
|
|
|
2026-04-10 19:28:20 +08:00
|
|
|
if (event->transport >= HID_TRANSPORT_COUNT) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (ctx.transport_protocol_modes[event->transport] !=
|
|
|
|
|
event->protocol_mode) {
|
|
|
|
|
ctx.transport_protocol_modes[event->transport] =
|
|
|
|
|
event->protocol_mode;
|
2026-04-10 09:06:18 +08:00
|
|
|
|
2026-04-25 15:40:49 +08:00
|
|
|
if (module_lifecycle_is_running(&ctx.lc) &&
|
2026-04-24 10:54:14 +08:00
|
|
|
policy_to_transport(ctx.current_transport, &active_transport) &&
|
2026-04-10 19:28:20 +08:00
|
|
|
(active_transport == event->transport)) {
|
|
|
|
|
reports_cache_invalidate();
|
2026-04-10 09:06:18 +08:00
|
|
|
emit_keys_report(true);
|
2026-04-10 19:28:20 +08:00
|
|
|
|
|
|
|
|
if (event->protocol_mode != KEYBOARD_PROTOCOL_MODE_BOOT) {
|
|
|
|
|
emit_consumer_report(true);
|
|
|
|
|
}
|
2026-04-10 09:06:18 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-23 09:48:06 +08:00
|
|
|
if (is_transport_policy_event(aeh)) {
|
|
|
|
|
return handle_transport_policy_event(
|
|
|
|
|
cast_transport_policy_event(aeh));
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-23 15:12:29 +08:00
|
|
|
if (is_settings_mode_event(aeh)) {
|
|
|
|
|
const struct settings_mode_event *event =
|
|
|
|
|
cast_settings_mode_event(aeh);
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
if (ctx.settings_active == event->active) {
|
2026-04-23 15:12:29 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 10:54:14 +08:00
|
|
|
ctx.settings_active = event->active;
|
|
|
|
|
if (ctx.settings_active) {
|
2026-04-25 15:40:49 +08:00
|
|
|
if (ctx.current_transport != HID_TRANSPORT_POLICY_NONE) {
|
2026-04-24 10:54:14 +08:00
|
|
|
emit_release_reports(ctx.current_transport);
|
2026-04-23 15:12:29 +08:00
|
|
|
}
|
|
|
|
|
emit_function_state_event();
|
|
|
|
|
keyboard_state_clear();
|
|
|
|
|
reports_cache_invalidate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-08 16:32:13 +08:00
|
|
|
if (is_module_state_event(aeh)) {
|
|
|
|
|
const struct module_state_event *event = cast_module_state_event(aeh);
|
|
|
|
|
|
|
|
|
|
if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
|
2026-04-24 10:54:14 +08:00
|
|
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_power_down_event(aeh)) {
|
2026-04-24 10:54:14 +08:00
|
|
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
|
|
|
|
(void)module_set_lifecycle(&ctx.lc, LC_STOPPED);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_wake_up_event(aeh)) {
|
2026-04-24 10:54:14 +08:00
|
|
|
if (module_lifecycle_is_initialized(&ctx.lc)) {
|
|
|
|
|
(void)module_set_lifecycle(&ctx.lc, LC_RUNNING);
|
2026-04-08 16:32:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__ASSERT_NO_MSG(false);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
APP_EVENT_LISTENER(MODULE, app_event_handler);
|
|
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, button_event);
|
2026-04-10 13:46:50 +08:00
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, encoder_event);
|
2026-04-13 11:55:59 +08:00
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, function_bitmap_update_event);
|
2026-04-10 09:06:18 +08:00
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, set_protocol_event);
|
2026-04-23 15:12:29 +08:00
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, settings_mode_event);
|
2026-04-23 09:48:06 +08:00
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, transport_policy_event);
|
2026-04-08 16:32:13 +08:00
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, module_state_event);
|
|
|
|
|
APP_EVENT_SUBSCRIBE_EARLY(MODULE, power_down_event);
|
|
|
|
|
APP_EVENT_SUBSCRIBE(MODULE, wake_up_event);
|