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

Crossover bilateral combinations for dual-hand chords and rolls #54

Closed
Show file tree
Hide file tree
Changes from all commits
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
20 changes: 20 additions & 0 deletions docs/tap_hold.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,26 @@ If `BILATERAL_COMBINATIONS` is defined to a value, hold times greater than that
#define BILATERAL_COMBINATIONS 500
```

To delay the registration of modifiers (such as `KC_LGUI` and `KC_RGUI`, which are considered to be "flashing mods" because they suddenly "flash" or pop up the "Start Menu" in Microsoft Windows) during bilateral combinations:

1. Add the following line to your `config.h` and define a timeout value (measured in milliseconds). Hold times greater than this value will permit modifiers to be registered.

```c
#define BILATERAL_COMBINATIONS_DEFERMODS 100
```

2. Add the following line to your `rules.mk` file to enable QMK's deferred execution facility, which is needed by the `BILATERAL_COMBINATIONS_DEFERMODS` setting mentioned above.

```make
DEFERRED_EXEC_ENABLE = yes
```

To enable *crossover* bilateral combinations (which start on one side of the keyboard and cross over to the other side, such as `RSFT_T(KC_J)` and `LGUI_T(KC_A)` in the word "jam"), add the following line to your `config.h` and define a value: hold times greater than that value will permit crossover bilateral combinations. For example, if you typed `RSFT_T(KC_J)` and `LGUI_T(KC_A)` faster than the defined value, the keys `KC_J` and `KC_A` would be sent to the computer. In contrast, if you typed slower than the defined value, the keys `RSFT(KC_A)` would be sent to the computer.

```c
#define BILATERAL_COMBINATIONS_CROSSOVER 75
```

To monitor activations in the background, enable debugging, enable the console, enable terminal bell, add `#define DEBUG_ACTION` to `config.h`, and use something like the following shell command line:

```sh
Expand Down
49 changes: 44 additions & 5 deletions tmk_core/common/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ int retro_tapping_counter = 0;
# include <fauxclicky.h>
#endif

#if (BILATERAL_COMBINATIONS + 0)
#if (BILATERAL_COMBINATIONS + BILATERAL_COMBINATIONS_CROSSOVER + 0)
# include "quantum.h"
#endif

Expand Down Expand Up @@ -231,9 +231,12 @@ static struct {
uint8_t tap;
uint8_t mods;
bool left;
# if (BILATERAL_COMBINATIONS + 0)
# if (BILATERAL_COMBINATIONS + BILATERAL_COMBINATIONS_CROSSOVER + 0)
uint16_t time;
# endif
# if (BILATERAL_COMBINATIONS_DEFERMODS + 0)
deferred_token defermods;
# endif
} bilateral_combinations = { false };

static bool bilateral_combinations_left(keypos_t key) {
Expand All @@ -248,22 +251,41 @@ static bool bilateral_combinations_left(keypos_t key) {
# endif
}

# if (BILATERAL_COMBINATIONS_DEFERMODS + 0)
static uint32_t bilateral_combinations_defermods(uint32_t trigger_time, void *cb_arg) {
if (bilateral_combinations.active) {
register_mods(bilateral_combinations.mods);
}
return 0;
}
# endif

static void bilateral_combinations_hold(action_t action, keyevent_t event) {
dprint("BILATERAL_COMBINATIONS: hold\n");
bilateral_combinations.active = true;
bilateral_combinations.code = action.key.code;
bilateral_combinations.tap = action.layer_tap.code;
bilateral_combinations.mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods : action.key.mods << 4;
bilateral_combinations.left = bilateral_combinations_left(event.key);
# if (BILATERAL_COMBINATIONS + 0)
# if (BILATERAL_COMBINATIONS + BILATERAL_COMBINATIONS_CROSSOVER + 0)
bilateral_combinations.time = event.time;
# endif
# if (BILATERAL_COMBINATIONS_DEFERMODS + 0)
bilateral_combinations.defermods = defer_exec(BILATERAL_COMBINATIONS_DEFERMODS, bilateral_combinations_defermods, NULL);
# endif
}

static void bilateral_combinations_clear(void) {
bilateral_combinations.active = false;
# if (BILATERAL_COMBINATIONS_DEFERMODS + 0)
cancel_deferred_exec(bilateral_combinations.defermods);
# endif
}

static void bilateral_combinations_release(uint8_t code) {
dprint("BILATERAL_COMBINATIONS: release\n");
if (bilateral_combinations.active && (code == bilateral_combinations.code)) {
bilateral_combinations.active = false;
bilateral_combinations_clear();
}
}

Expand All @@ -274,14 +296,27 @@ static void bilateral_combinations_tap(keyevent_t event) {
# if (BILATERAL_COMBINATIONS + 0)
if (TIMER_DIFF_16(event.time, bilateral_combinations.time) > BILATERAL_COMBINATIONS) {
dprint("BILATERAL_COMBINATIONS: timeout\n");
bilateral_combinations_clear();
return;
}
# endif
dprint("BILATERAL_COMBINATIONS: change\n");
unregister_mods(bilateral_combinations.mods);
tap_code(bilateral_combinations.tap);
}
bilateral_combinations.active = false;
# if (BILATERAL_COMBINATIONS_CROSSOVER + 0)
else {
if (TIMER_DIFF_16(event.time, bilateral_combinations.time) > BILATERAL_COMBINATIONS_CROSSOVER) {
dprint("BILATERAL_COMBINATIONS_CROSSOVER: timeout\n");
bilateral_combinations_clear();
return;
}
dprint("BILATERAL_COMBINATIONS_CROSSOVER: change\n");
unregister_mods(bilateral_combinations.mods);
tap_code(bilateral_combinations.tap);
}
# endif
bilateral_combinations_clear();
}
}
#endif
Expand Down Expand Up @@ -433,7 +468,11 @@ void process_action(keyrecord_t *record, action_t action) {
}
} else {
dprint("MODS_TAP: No tap: add_mods\n");
# if defined(BILATERAL_COMBINATIONS) && (BILATERAL_COMBINATIONS_DEFERMODS + 0)
add_mods(mods);
# else
register_mods(mods);
# endif
# ifdef BILATERAL_COMBINATIONS
// mod-tap hold
bilateral_combinations_hold(action, event);
Expand Down