Skip to content

Commit

Permalink
core: Fix for stuck key problem #441
Browse files Browse the repository at this point in the history
- Idea form qmk/qmk_firmware#182
- Define NO_TRACK_KEY_PRESS to get old behaviour
- This should resolve #105, #248, #397, #441 and FAQ entry: https://github.com/tmk/tmk_keyboard/wiki/FAQ-Keymap#modifierlayer-stuck
  • Loading branch information
tmk committed May 30, 2017
1 parent cf9f157 commit ba2883f
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 16 deletions.
8 changes: 8 additions & 0 deletions tmk_core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ Source code is available here: <https://github.com/tmk/tmk_keyboard/tree/core>

Updates
-------
#### 2017/05/30
Fixed **Modifier/Layer key stuck** problem. See this wiki entry. <https://github.com/tmk/tmk_keyboard/wiki/FAQ-Keymap#modifierlayer-stuck> If you need old keymap behaviour for some reason define `NO_TRACK_KEY_PRESS` in your `config.h`.

This is virtually equivalent to QMK `PREVENT_STUCK_MODIFIERS`. <https://github.com/qmk/qmk_firmware/pull/182>

#### 2017/01/11
Changed action code for `ACTION_LAYER_MODS` and this may cause incompatibility with existent shared URL and downloaded firmwware of keymap editor. If you are using the action you just have to redefine it on keymap editor. Existent keymap code should not suffer.

#### 2016/06/26
Keymap framework was updated. `fn_actions[]` should be defined as `action_t` instead of `uint16_t`. And default code for keymap handling is now included in core you just need define `uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS]` and `action_t fn_actions[]`.

Expand Down
6 changes: 3 additions & 3 deletions tmk_core/common/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void process_action(keyrecord_t *record)

if (IS_NOEVENT(event)) { return; }

action_t action = layer_switch_get_action(event.key);
action_t action = layer_switch_get_action(event);
dprint("ACTION: "); debug_action(action);
#ifndef NO_ACTION_LAYER
dprint(" layer_state: "); layer_debug();
Expand Down Expand Up @@ -529,9 +529,9 @@ void clear_keyboard_but_mods(void)
#endif
}

bool is_tap_key(keypos_t key)
bool is_tap_key(keyevent_t event)
{
action_t action = layer_switch_get_action(key);
action_t action = layer_switch_get_action(event);

switch (action.kind.id) {
case ACT_LMODS_TAP:
Expand Down
2 changes: 1 addition & 1 deletion tmk_core/common/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ void unregister_mods(uint8_t mods);
void clear_keyboard(void);
void clear_keyboard_but_mods(void);
void layer_switch(uint8_t new_layer);
bool is_tap_key(keypos_t key);
bool is_tap_key(keyevent_t event);

/* debug */
void debug_event(keyevent_t event);
Expand Down
36 changes: 30 additions & 6 deletions tmk_core/common/action_layer.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ static void default_layer_state_set(uint32_t state)
default_layer_state = state;
hook_default_layer_change(default_layer_state);
default_layer_debug(); debug("\n");
#ifdef NO_TRACK_KEY_PRESS
clear_keyboard_but_mods(); // To avoid stuck keys
#endif
}

void default_layer_debug(void)
Expand Down Expand Up @@ -66,7 +68,9 @@ static void layer_state_set(uint32_t state)
layer_state = state;
hook_layer_change(layer_state);
layer_debug(); dprintln();
#ifdef NO_TRACK_KEY_PRESS
clear_keyboard_but_mods(); // To avoid stuck keys
#endif
}

void layer_clear(void)
Expand Down Expand Up @@ -115,7 +119,8 @@ void layer_debug(void)



action_t layer_switch_get_action(keypos_t key)
/* return layer effective for key at this time */
static uint8_t current_layer_for_key(keypos_t key)
{
action_t action = ACTION_TRANSPARENT;

Expand All @@ -126,15 +131,34 @@ action_t layer_switch_get_action(keypos_t key)
if (layers & (1UL<<i)) {
action = action_for_key(i, key);
if (action.code != (action_t)ACTION_TRANSPARENT.code) {
return action;
return i;
}
}
}
/* fall back to layer 0 */
action = action_for_key(0, key);
return action;
return 0;
#else
return biton32(default_layer_state);
#endif
}


#ifndef NO_TRACK_KEY_PRESS
/* record layer on where key is pressed */
static uint8_t layer_pressed[MATRIX_ROWS][MATRIX_COLS] = {};
#endif
action_t layer_switch_get_action(keyevent_t event)
{
uint8_t layer = 0;
#ifndef NO_TRACK_KEY_PRESS
if (event.pressed) {
layer = current_layer_for_key(event.key);
layer_pressed[event.key.row][event.key.col] = layer;
} else {
layer = layer_pressed[event.key.row][event.key.col];
}
#else
action = action_for_key(biton32(default_layer_state), key);
return action;
layer = current_layer_for_key(event.key);
#endif
return action_for_key(layer, event.key);
}
2 changes: 1 addition & 1 deletion tmk_core/common/action_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ void layer_xor(uint32_t state);


/* return action depending on current layer status */
action_t layer_switch_get_action(keypos_t key);
action_t layer_switch_get_action(keyevent_t key);

#endif
10 changes: 5 additions & 5 deletions tmk_core/common/action_tapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ bool process_tapping(keyrecord_t *keyp)
*/
else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) {
// Modifier should be retained till end of this tapping.
action_t action = layer_switch_get_action(event.key);
action_t action = layer_switch_get_action(event);
switch (action.kind.id) {
case ACT_LMODS:
case ACT_RMODS:
Expand Down Expand Up @@ -152,7 +152,7 @@ bool process_tapping(keyrecord_t *keyp)
debug_tapping_key();
return true;
}
else if (is_tap_key(event.key) && event.pressed) {
else if (is_tap_key(event) && event.pressed) {
if (tapping_key.tap.count > 1) {
debug("Tapping: Start new tap with releasing last tap(>1).\n");
// unregister key
Expand Down Expand Up @@ -196,7 +196,7 @@ bool process_tapping(keyrecord_t *keyp)
tapping_key = (keyrecord_t){};
return true;
}
else if (is_tap_key(event.key) && event.pressed) {
else if (is_tap_key(event) && event.pressed) {
if (tapping_key.tap.count > 1) {
debug("Tapping: Start new tap with releasing last timeout tap(>1).\n");
// unregister key
Expand Down Expand Up @@ -241,7 +241,7 @@ bool process_tapping(keyrecord_t *keyp)
tapping_key = *keyp;
return true;
}
} else if (is_tap_key(event.key)) {
} else if (is_tap_key(event)) {
// Sequential tap can be interfered with other tap key.
debug("Tapping: Start with interfering other tap.\n");
tapping_key = *keyp;
Expand Down Expand Up @@ -272,7 +272,7 @@ bool process_tapping(keyrecord_t *keyp)
}
// not tapping state
else {
if (event.pressed && is_tap_key(event.key)) {
if (event.pressed && is_tap_key(event)) {
debug("Tapping: Start(Press tap key).\n");
tapping_key = *keyp;
waiting_buffer_scan_tap();
Expand Down

0 comments on commit ba2883f

Please sign in to comment.