fix(hid): Implicit mods on non-key page events
* Properly send the KEY usage page report for modifier changes when there are state changes to other usages pages that include implicit modifiers.
This commit is contained in:
parent
c4ad3bc5dc
commit
6ef1e7034f
2 changed files with 48 additions and 18 deletions
|
@ -26,14 +26,17 @@ static zmk_mod_flags_t explicit_modifiers = 0;
|
||||||
LOG_DBG("Modifiers set to 0x%02X", keyboard_report.body.modifiers); \
|
LOG_DBG("Modifiers set to 0x%02X", keyboard_report.body.modifiers); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GET_MODIFIERS (keyboard_report.body.modifiers)
|
||||||
|
|
||||||
zmk_mod_flags_t zmk_hid_get_explicit_mods() { return explicit_modifiers; }
|
zmk_mod_flags_t zmk_hid_get_explicit_mods() { return explicit_modifiers; }
|
||||||
|
|
||||||
int zmk_hid_register_mod(zmk_mod_t modifier) {
|
int zmk_hid_register_mod(zmk_mod_t modifier) {
|
||||||
explicit_modifier_counts[modifier]++;
|
explicit_modifier_counts[modifier]++;
|
||||||
LOG_DBG("Modifier %d count %d", modifier, explicit_modifier_counts[modifier]);
|
LOG_DBG("Modifier %d count %d", modifier, explicit_modifier_counts[modifier]);
|
||||||
WRITE_BIT(explicit_modifiers, modifier, true);
|
WRITE_BIT(explicit_modifiers, modifier, true);
|
||||||
|
zmk_mod_flags_t current = GET_MODIFIERS;
|
||||||
SET_MODIFIERS(explicit_modifiers);
|
SET_MODIFIERS(explicit_modifiers);
|
||||||
return 0;
|
return current == GET_MODIFIERS ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_hid_unregister_mod(zmk_mod_t modifier) {
|
int zmk_hid_unregister_mod(zmk_mod_t modifier) {
|
||||||
|
@ -47,26 +50,30 @@ int zmk_hid_unregister_mod(zmk_mod_t modifier) {
|
||||||
LOG_DBG("Modifier %d released", modifier);
|
LOG_DBG("Modifier %d released", modifier);
|
||||||
WRITE_BIT(explicit_modifiers, modifier, false);
|
WRITE_BIT(explicit_modifiers, modifier, false);
|
||||||
}
|
}
|
||||||
|
zmk_mod_flags_t current = GET_MODIFIERS;
|
||||||
SET_MODIFIERS(explicit_modifiers);
|
SET_MODIFIERS(explicit_modifiers);
|
||||||
return 0;
|
return current == GET_MODIFIERS ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_hid_register_mods(zmk_mod_flags_t modifiers) {
|
int zmk_hid_register_mods(zmk_mod_flags_t modifiers) {
|
||||||
|
int ret = 0;
|
||||||
for (zmk_mod_t i = 0; i < 8; i++) {
|
for (zmk_mod_t i = 0; i < 8; i++) {
|
||||||
if (modifiers & (1 << i)) {
|
if (modifiers & (1 << i)) {
|
||||||
zmk_hid_register_mod(i);
|
ret += zmk_hid_register_mod(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_hid_unregister_mods(zmk_mod_flags_t modifiers) {
|
int zmk_hid_unregister_mods(zmk_mod_flags_t modifiers) {
|
||||||
|
int ret = 0;
|
||||||
for (zmk_mod_t i = 0; i < 8; i++) {
|
for (zmk_mod_t i = 0; i < 8; i++) {
|
||||||
if (modifiers & (1 << i)) {
|
if (modifiers & (1 << i)) {
|
||||||
zmk_hid_unregister_mod(i);
|
ret += zmk_hid_unregister_mod(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO)
|
#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO)
|
||||||
|
@ -130,13 +137,15 @@ static inline int deselect_keyboard_usage(zmk_key_t usage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t implicit_modifiers) {
|
int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t implicit_modifiers) {
|
||||||
|
zmk_mod_flags_t current = GET_MODIFIERS;
|
||||||
SET_MODIFIERS(explicit_modifiers | implicit_modifiers);
|
SET_MODIFIERS(explicit_modifiers | implicit_modifiers);
|
||||||
return 0;
|
return current == GET_MODIFIERS ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_hid_implicit_modifiers_release() {
|
int zmk_hid_implicit_modifiers_release() {
|
||||||
|
zmk_mod_flags_t current = GET_MODIFIERS;
|
||||||
SET_MODIFIERS(explicit_modifiers);
|
SET_MODIFIERS(explicit_modifiers);
|
||||||
return 0;
|
return current == GET_MODIFIERS ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmk_hid_keyboard_press(zmk_key_t code) {
|
int zmk_hid_keyboard_press(zmk_key_t code) {
|
||||||
|
|
|
@ -17,56 +17,77 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
#include <zmk/endpoints.h>
|
#include <zmk/endpoints.h>
|
||||||
|
|
||||||
static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed *ev) {
|
static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed *ev) {
|
||||||
int err;
|
int err, explicit_mods_changed, implicit_mods_changed;
|
||||||
|
|
||||||
LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X",
|
LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X",
|
||||||
ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers);
|
ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers);
|
||||||
switch (ev->usage_page) {
|
switch (ev->usage_page) {
|
||||||
case HID_USAGE_KEY:
|
case HID_USAGE_KEY:
|
||||||
err = zmk_hid_keyboard_press(ev->keycode);
|
err = zmk_hid_keyboard_press(ev->keycode);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
LOG_ERR("Unable to press keycode");
|
LOG_ERR("Unable to press keycode");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HID_USAGE_CONSUMER:
|
case HID_USAGE_CONSUMER:
|
||||||
err = zmk_hid_consumer_press(ev->keycode);
|
err = zmk_hid_consumer_press(ev->keycode);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
LOG_ERR("Unable to press keycode");
|
LOG_ERR("Unable to press keycode");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
zmk_hid_register_mods(ev->explicit_modifiers);
|
explicit_mods_changed = zmk_hid_register_mods(ev->explicit_modifiers);
|
||||||
zmk_hid_implicit_modifiers_press(ev->implicit_modifiers);
|
implicit_mods_changed = zmk_hid_implicit_modifiers_press(ev->implicit_modifiers);
|
||||||
|
if (ev->usage_page != HID_USAGE_KEY &&
|
||||||
|
(explicit_mods_changed > 0 || implicit_mods_changed > 0)) {
|
||||||
|
err = zmk_endpoints_send_report(HID_USAGE_KEY);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_ERR("Failed to send key report for changed mofifiers for consumer page event (%d)",
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return zmk_endpoints_send_report(ev->usage_page);
|
return zmk_endpoints_send_report(ev->usage_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hid_listener_keycode_released(const struct zmk_keycode_state_changed *ev) {
|
static int hid_listener_keycode_released(const struct zmk_keycode_state_changed *ev) {
|
||||||
int err;
|
int err, explicit_mods_changed, implicit_mods_changed;
|
||||||
|
|
||||||
LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X",
|
LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X",
|
||||||
ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers);
|
ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers);
|
||||||
switch (ev->usage_page) {
|
switch (ev->usage_page) {
|
||||||
case HID_USAGE_KEY:
|
case HID_USAGE_KEY:
|
||||||
err = zmk_hid_keyboard_release(ev->keycode);
|
err = zmk_hid_keyboard_release(ev->keycode);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
LOG_ERR("Unable to release keycode");
|
LOG_ERR("Unable to release keycode");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HID_USAGE_CONSUMER:
|
case HID_USAGE_CONSUMER:
|
||||||
err = zmk_hid_consumer_release(ev->keycode);
|
err = zmk_hid_consumer_release(ev->keycode);
|
||||||
if (err) {
|
if (err < 0) {
|
||||||
LOG_ERR("Unable to release keycode");
|
LOG_ERR("Unable to release keycode");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zmk_hid_unregister_mods(ev->explicit_modifiers);
|
|
||||||
|
explicit_mods_changed = zmk_hid_unregister_mods(ev->explicit_modifiers);
|
||||||
// There is a minor issue with this code.
|
// There is a minor issue with this code.
|
||||||
// If LC(A) is pressed, then LS(B), then LC(A) is released, the shift for B will be released
|
// If LC(A) is pressed, then LS(B), then LC(A) is released, the shift for B will be released
|
||||||
// prematurely. This causes if LS(B) to repeat like Bbbbbbbb when pressed for a long time.
|
// prematurely. This causes if LS(B) to repeat like Bbbbbbbb when pressed for a long time.
|
||||||
// Solving this would require keeping track of which key's implicit modifiers are currently
|
// Solving this would require keeping track of which key's implicit modifiers are currently
|
||||||
// active and only releasing modifiers at that time.
|
// active and only releasing modifiers at that time.
|
||||||
zmk_hid_implicit_modifiers_release();
|
implicit_mods_changed = zmk_hid_implicit_modifiers_release();
|
||||||
|
;
|
||||||
|
if (ev->usage_page != HID_USAGE_KEY &&
|
||||||
|
(explicit_mods_changed > 0 || implicit_mods_changed > 0)) {
|
||||||
|
err = zmk_endpoints_send_report(HID_USAGE_KEY);
|
||||||
|
if (err < 0) {
|
||||||
|
LOG_ERR("Failed to send key report for changed mofifiers for consumer page event (%d)",
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
}
|
||||||
return zmk_endpoints_send_report(ev->usage_page);
|
return zmk_endpoints_send_report(ev->usage_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue