diff --git a/app/Kconfig b/app/Kconfig index f23930b4..629dfa70 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -25,7 +25,40 @@ config USB_DEVICE_PID config USB_DEVICE_MANUFACTURER default "ZMK Project" -menu "HID Output Types" +menu "HID" + +choice ZMK_HID_REPORT_TYPE + prompt "HID Report Type" + +config ZMK_HID_REPORT_TYPE_HKRO + bool "#-Key Roll Over (HKRO) HID Report" + help + Enable # key roll over for HID report. This selection is "boot keyboard" compatible + but limits the total number of possible keys to report as held to #. + +config ZMK_HID_REPORT_TYPE_NKRO + bool "Full N-Key Roll Over (NKRO) HID Report" + help + Enable full N-Key Roll Over for HID output. This selection will prevent the keyboard + from working with some BIOS/UEFI versions that only support "boot keyboard" support. + This option also prevents using some infrequently used higher range HID usages. + +endchoice + +if ZMK_HID_REPORT_TYPE_HKRO + +config ZMK_HID_KEYBOARD_REPORT_SIZE + int "# Keyboard Keys Reportable" + default 6 + + +endif + +config ZMK_HID_CONSUMER_REPORT_SIZE + int "# Consumer Keys Reportable" + default 6 + +menu "Output Types" config ZMK_USB bool "USB" @@ -92,7 +125,10 @@ config ZMK_BLE_PASSKEY_ENTRY #ZMK_BLE endif -#HID Output Types +#Output Types +endmenu + +# HID endmenu menu "Split Support" diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index 5aa004c2..be88c175 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -13,11 +13,9 @@ #include #include -#define COLLECTION_REPORT 0x03 - -#define ZMK_HID_KEYBOARD_NKRO_SIZE 6 +#define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL -#define ZMK_HID_CONSUMER_NKRO_SIZE 6 +#define COLLECTION_REPORT 0x03 static const uint8_t zmk_hid_report_desc[] = { /* USAGE_PAGE (Generic Desktop) */ @@ -74,6 +72,30 @@ static const uint8_t zmk_hid_report_desc[] = { /* USAGE_PAGE (Keyboard/Keypad) */ HID_GI_USAGE_PAGE, HID_USAGE_KEY, + +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) + /* LOGICAL_MINIMUM (0) */ + HID_GI_LOGICAL_MIN(1), + 0x00, + /* LOGICAL_MAXIMUM (1) */ + HID_GI_LOGICAL_MAX(1), + 0x01, + /* USAGE_MINIMUM (Reserved) */ + HID_LI_USAGE_MIN(1), + 0x00, + /* USAGE_MAXIMUM (Keyboard Application) */ + HID_LI_USAGE_MAX(1), + ZMK_HID_KEYBOARD_NKRO_MAX_USAGE, + /* REPORT_SIZE (8) */ + HID_GI_REPORT_SIZE, + 0x01, + /* REPORT_COUNT (6) */ + HID_GI_REPORT_COUNT, + ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1, + /* INPUT (Data,Ary,Abs) */ + HID_MI_INPUT, + 0x02, +#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) /* LOGICAL_MINIMUM (0) */ HID_GI_LOGICAL_MIN(1), 0x00, @@ -89,12 +111,15 @@ static const uint8_t zmk_hid_report_desc[] = { /* REPORT_SIZE (1) */ HID_GI_REPORT_SIZE, 0x08, - /* REPORT_COUNT (ZMK_HID_KEYBOARD_NKRO_SIZE) */ + /* REPORT_COUNT (CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE) */ HID_GI_REPORT_COUNT, - ZMK_HID_KEYBOARD_NKRO_SIZE, + CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE, /* INPUT (Data,Ary,Abs) */ HID_MI_INPUT, 0x00, +#else +#error "A proper HID report type must be selected" +#endif /* END_COLLECTION */ HID_MI_COLLECTION_END, @@ -130,9 +155,9 @@ static const uint8_t zmk_hid_report_desc[] = { /* REPORT_SIZE (16) */ HID_GI_REPORT_SIZE, 0x10, - /* REPORT_COUNT (ZMK_HID_CONSUMER_NKRO_SIZE) */ + /* REPORT_COUNT (CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE) */ HID_GI_REPORT_COUNT, - ZMK_HID_CONSUMER_NKRO_SIZE, + CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE, HID_MI_INPUT, 0x00, /* END COLLECTION */ @@ -149,7 +174,11 @@ static const uint8_t zmk_hid_report_desc[] = { struct zmk_hid_keyboard_report_body { zmk_mod_flags_t modifiers; uint8_t _reserved; - uint8_t keys[ZMK_HID_KEYBOARD_NKRO_SIZE]; +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) + uint8_t keys[(ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1) / 8]; +#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) + uint8_t keys[CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE]; +#endif } __packed; struct zmk_hid_keyboard_report { @@ -158,7 +187,7 @@ struct zmk_hid_keyboard_report { } __packed; struct zmk_hid_consumer_report_body { - uint16_t keys[ZMK_HID_CONSUMER_NKRO_SIZE]; + uint16_t keys[CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE]; } __packed; struct zmk_hid_consumer_report { diff --git a/app/src/hid.c b/app/src/hid.c index 7ab080e5..756ed900 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -69,8 +69,30 @@ int zmk_hid_unregister_mods(zmk_mod_flags_t modifiers) { return 0; } +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) + +#define TOGGLE_KEYBOARD(code, val) WRITE_BIT(keyboard_report.body.keys[code / 8], code % 8, val) + +static inline int select_keyboard_usage(zmk_key_t usage) { + if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) { + return -EINVAL; + } + TOGGLE_KEYBOARD(usage, 1); + return 0; +} + +static inline int deselect_keyboard_usage(zmk_key_t usage) { + if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) { + return -EINVAL; + } + TOGGLE_KEYBOARD(usage, 0); + return 0; +} + +#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) + #define TOGGLE_KEYBOARD(match, val) \ - for (int idx = 0; idx < ZMK_HID_KEYBOARD_NKRO_SIZE; idx++) { \ + for (int idx = 0; idx < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; idx++) { \ if (keyboard_report.body.keys[idx] != match) { \ continue; \ } \ @@ -80,8 +102,22 @@ int zmk_hid_unregister_mods(zmk_mod_flags_t modifiers) { } \ } +static inline int select_keyboard_usage(zmk_key_t usage) { + TOGGLE_KEYBOARD(0U, usage); + return 0; +} + +static inline int deselect_keyboard_usage(zmk_key_t usage) { + TOGGLE_KEYBOARD(usage, 0U); + return 0; +} + +#else +#error "A proper HID report type must be selected" +#endif + #define TOGGLE_CONSUMER(match, val) \ - for (int idx = 0; idx < ZMK_HID_CONSUMER_NKRO_SIZE; idx++) { \ + for (int idx = 0; idx < CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE; idx++) { \ if (consumer_report.body.keys[idx] != match) { \ continue; \ } \ @@ -105,7 +141,7 @@ int zmk_hid_keyboard_press(zmk_key_t code) { if (code >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && code <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI) { return zmk_hid_register_mod(code - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL); } - TOGGLE_KEYBOARD(0U, code); + select_keyboard_usage(code); return 0; }; @@ -113,7 +149,7 @@ int zmk_hid_keyboard_release(zmk_key_t code) { if (code >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && code <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI) { return zmk_hid_unregister_mod(code - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL); } - TOGGLE_KEYBOARD(code, 0U); + deselect_keyboard_usage(code); return 0; };