Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Send a dummy keycode to neutralize flashing modifiers in retro tap and key overrides #20992

Merged
merged 5 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Tap a dummy keycode to prevent modifier flashes in RETRO_TAPPING and
KEY_OVERRIDE
  • Loading branch information
precondition committed May 19, 2023
commit 347135bad9b650470ac554aea21d7640679b6aed
7 changes: 7 additions & 0 deletions quantum/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,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);
}
}
Expand Down
25 changes: 25 additions & 0 deletions quantum/action_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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" phenomen.
*
* \param active_mods 8-bit packed bit-array describing the currenctly 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
11 changes: 11 additions & 0 deletions quantum/action_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ void use_oneshot_swaphands(void);
void clear_oneshot_swaphands(void);
#endif

#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE
# if !(QK_BASIC <= 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
9 changes: 9 additions & 0 deletions quantum/process_keycode/process_key_override.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down