[Feature] Send a dummy keycode to neutralize flashing modifiers in retro tap and key overrides (#20992)
This commit is contained in:
parent
baf2891124
commit
1abf8f3e8b
8 changed files with 311 additions and 1 deletions
|
@ -528,6 +528,13 @@ void process_action(keyrecord_t *record, action_t action) {
|
|||
unregister_code(action.key.code);
|
||||
} else {
|
||||
ac_dprintf("MODS_TAP: No tap: add_mods\n");
|
||||
# if defined(RETRO_TAPPING) && defined(DUMMY_MOD_NEUTRALIZER_KEYCODE)
|
||||
// Send a dummy keycode to neutralize flashing modifiers
|
||||
// if the key was held and then released with no interruptions.
|
||||
if (retro_tapping_counter == 2) {
|
||||
neutralize_flashing_modifiers(get_mods());
|
||||
}
|
||||
# endif
|
||||
unregister_mods(mods);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -500,3 +500,28 @@ __attribute__((weak)) void oneshot_layer_changed_kb(uint8_t layer) {
|
|||
uint8_t has_anymod(void) {
|
||||
return bitpop(real_mods);
|
||||
}
|
||||
|
||||
#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE
|
||||
/** \brief Send a dummy keycode in between the register and unregister event of a modifier key, to neutralize the "flashing modifiers" phenomenon.
|
||||
*
|
||||
* \param active_mods 8-bit packed bit-array describing the currently active modifiers (in the format GASCGASC).
|
||||
*
|
||||
* Certain QMK features like key overrides or retro tap must unregister a previously
|
||||
* registered modifier before sending another keycode but this can trigger undesired
|
||||
* keyboard shortcuts if the clean tap of a single modifier key is bound to an action
|
||||
* on the host OS, as is for example the case for the left GUI key on Windows, which
|
||||
* opens the Start Menu when tapped.
|
||||
*/
|
||||
void neutralize_flashing_modifiers(uint8_t active_mods) {
|
||||
// In most scenarios, the flashing modifiers phenomenon is a problem
|
||||
// only for a subset of modifier masks.
|
||||
const static uint8_t mods_to_neutralize[] = MODS_TO_NEUTRALIZE;
|
||||
const static uint8_t n_mods = ARRAY_SIZE(mods_to_neutralize);
|
||||
for (uint8_t i = 0; i < n_mods; ++i) {
|
||||
if (active_mods == mods_to_neutralize[i]) {
|
||||
tap_code(DUMMY_MOD_NEUTRALIZER_KEYCODE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -102,6 +102,19 @@ void use_oneshot_swaphands(void);
|
|||
void clear_oneshot_swaphands(void);
|
||||
#endif
|
||||
|
||||
#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE
|
||||
// KC_A is used as the lowerbound instead of QK_BASIC because the range QK_BASIC...KC_A includes
|
||||
// internal keycodes like KC_NO and KC_TRANSPARENT which are unsuitable for use with `tap_code(kc)`.
|
||||
# if !(KC_A <= DUMMY_MOD_NEUTRALIZER_KEYCODE && DUMMY_MOD_NEUTRALIZER_KEYCODE <= QK_BASIC_MAX)
|
||||
# error "DUMMY_MOD_NEUTRALIZER_KEYCODE must be a basic, unmodified, HID keycode!"
|
||||
# endif
|
||||
void neutralize_flashing_modifiers(uint8_t active_mods);
|
||||
#endif
|
||||
#ifndef MODS_TO_NEUTRALIZE
|
||||
# define MODS_TO_NEUTRALIZE \
|
||||
{ MOD_BIT(KC_LEFT_ALT), MOD_BIT(KC_LEFT_GUI) }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -322,6 +322,15 @@ static bool try_activating_override(const uint16_t keycode, const uint8_t layer,
|
|||
|
||||
clear_active_override(false);
|
||||
|
||||
#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE
|
||||
// Send a dummy keycode before unregistering the modifier(s)
|
||||
// so that suppressing the modifier(s) doesn't falsely get interpreted
|
||||
// by the host OS as a tap of a modifier key.
|
||||
// For example, unintended activations of the start menu on Windows when
|
||||
// using a GUI+<kc> key override with suppressed mods.
|
||||
neutralize_flashing_modifiers(active_mods);
|
||||
#endif
|
||||
|
||||
active_override = override;
|
||||
active_override_trigger_is_down = true;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue