From 743449472e58651ec8111e6f70811103fb0a28bd Mon Sep 17 00:00:00 2001 From: Joe Wasson Date: Mon, 17 Sep 2018 10:48:02 -0700 Subject: Make `PREVENT_STUCK_MODIFIERS` the default (#3107) * Remove chording as it is not documented, not used, and needs work. * Make Leader Key an optional feature. * Switch from `PREVENT_STUCK_MODIFIERS` to `STRICT_LAYER_RELEASE` * Remove `#define PREVENT_STUCK_MODIFIERS` from keymaps. --- docs/feature_leader_key.md | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'docs/feature_leader_key.md') diff --git a/docs/feature_leader_key.md b/docs/feature_leader_key.md index 46633b287..0c3f4a133 100644 --- a/docs/feature_leader_key.md +++ b/docs/feature_leader_key.md @@ -39,3 +39,11 @@ void matrix_scan_user(void) { As you can see, you have a few function. You can use `SEQ_ONE_KEY` for single-key sequences (Leader followed by just one key), and `SEQ_TWO_KEYS`, `SEQ_THREE_KEYS` up to `SEQ_FIVE_KEYS` for longer sequences. Each of these accepts one or more keycodes as arguments. This is an important point: You can use keycodes from **any layer on your keyboard**. That layer would need to be active for the leader macro to fire, obviously. + +## Adding Leader Key Support in the `rules.mk` + +To add support for Leader Key you simply need to add a single line to your keymap's `rules.mk`: + +``` +LEADER_ENABLE = yes +``` -- cgit v1.2.3-70-g09d2 From 244e1c5a57eecd349c7d88e1af42d1b3467aeafe Mon Sep 17 00:00:00 2001 From: dsissitka Date: Sun, 16 Sep 2018 17:49:20 -0400 Subject: Fix LEADER_KEY docs. LEADER_KEY needs to be set in config.h, not keymap.c. Credit goes to @randywallace for figuring this one out: https://github.com/qmk/qmk_firmware/issues/2514#issuecomment-384847485 --- docs/feature_leader_key.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/feature_leader_key.md') diff --git a/docs/feature_leader_key.md b/docs/feature_leader_key.md index 0c3f4a133..92aebd463 100644 --- a/docs/feature_leader_key.md +++ b/docs/feature_leader_key.md @@ -5,7 +5,7 @@ If you've ever used Vim, you know what a Leader key is. If not, you're about to That's what `KC_LEAD` does. Here's an example: 1. Pick a key on your keyboard you want to use as the Leader key. Assign it the keycode `KC_LEAD`. This key would be dedicated just for this -- it's a single action key, can't be used for anything else. -2. Include the line `#define LEADER_TIMEOUT 300` somewhere in your keymap.c file, probably near the top. The 300 there is 300ms -- that's how long you have for the sequence of keys following the leader. You can tweak this value for comfort, of course. +2. Include the line `#define LEADER_TIMEOUT 300` in your config.h. The 300 there is 300ms -- that's how long you have for the sequence of keys following the leader. You can tweak this value for comfort, of course. 3. Within your `matrix_scan_user` function, do something like this: ``` -- cgit v1.2.3-70-g09d2 From 3ec4a00bfc090fc440480336e3273b459074aa18 Mon Sep 17 00:00:00 2001 From: Alexander Kagno Date: Sat, 15 Dec 2018 08:29:24 -0700 Subject: Per Key Leader Timing Option (#4026) * leader changes to enable per key timing option * Changes requested to docs for @drashna * Changes requested by @drashna --- docs/config_options.md | 6 +++++- docs/feature_leader_key.md | 23 +++++++++++++++++++++++ quantum/process_keycode/process_leader.c | 6 ++++++ 3 files changed, 34 insertions(+), 1 deletion(-) (limited to 'docs/feature_leader_key.md') diff --git a/docs/config_options.md b/docs/config_options.md index bea4acb01..fb1655e9a 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -143,6 +143,8 @@ If you define these options you will enable the associated feature, which may in * Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle) * `#define LEADER_TIMEOUT 300` * how long before the leader key times out +* `#define LEADER_PER_KEY_TIMING` + * sets the timer for leader key chords to run on each key press rather than overall * `#define ONESHOT_TIMEOUT 300` * how long before oneshot times out * `#define ONESHOT_TAP_TOGGLE 2` @@ -194,7 +196,7 @@ Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in yo * `#define SPLIT_HAND_PIN B7` * For using high/low pin to determine handedness, low = right hand, high = left hand. Replace 'B7' with the pin you are using. This is optional and you can still use the EEHANDS method or MASTER_LEFT / MASTER_RIGHT defines like the stock Let's Split uses. - + * `#define USE_I2C` * For using I2C instead of Serial (defaults to serial) @@ -252,6 +254,8 @@ Use these to enable or disable building certain features. The more you have enab * Enable the audio subsystem. * `RGBLIGHT_ENABLE` * Enable keyboard underlight functionality +* `LEADER_ENABLE` + * Enable leader key chording * `MIDI_ENABLE` * MIDI controls * `UNICODE_ENABLE` diff --git a/docs/feature_leader_key.md b/docs/feature_leader_key.md index 92aebd463..9b49e0fd9 100644 --- a/docs/feature_leader_key.md +++ b/docs/feature_leader_key.md @@ -47,3 +47,26 @@ To add support for Leader Key you simply need to add a single line to your keyma ``` LEADER_ENABLE = yes ``` + +## Per Key Timing on Leader keys + +Rather than relying on an incredibly high timeout for long leader key strings or those of us without 200wpm typing skills, we can enable per key timing to ensure that each key pressed provides us with more time to finish our stroke. This is incredibly helpful with leader key emulation of tap dance (read: multiple taps of the same key like C, C, C). + +In order to enable this, place this in your `config.h`: +``` +#define LEADER_PER_KEY_TIMING +``` + +After this, it's recommended that you lower your `LEADER_TIMEOUT` to something less that 300ms. + +``` +#define LEADER_TIMEOUT 250 +``` + +Now, something like this won't seem impossible to do without a 1000MS leader key timeout: + +``` +SEQ_THREE_KEYS(KC_C, KC_C, KC_C) { + SEND_STRING("Per key timing is great!!!"); +} +``` diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c index eddbf71f7..b32fc1db6 100644 --- a/quantum/process_keycode/process_leader.c +++ b/quantum/process_keycode/process_leader.c @@ -38,9 +38,15 @@ uint8_t leader_sequence_size = 0; bool process_leader(uint16_t keycode, keyrecord_t *record) { // Leader key set-up if (record->event.pressed) { +#ifdef LEADER_PER_KEY_TIMING + leader_time = timer_read(); +#endif if (!leading && keycode == KC_LEAD) { leader_start(); leading = true; +#ifndef LEADER_PER_KEY_TIMING + leader_time = timer_read(); +#endif leader_time = timer_read(); leader_sequence_size = 0; leader_sequence[0] = 0; -- cgit v1.2.3-70-g09d2 From 639585314863912480c9967fc38bb2d9418a34ab Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Thu, 20 Dec 2018 08:58:12 -0800 Subject: Docs: Add additional clarification to Leader Key documention (#4660) * Add clarification for Leader Timeout * Add additional documentatin to config_options.md * Add leader_start() and leader_end() documentation * Add Examples * Clarify timout * Remove customization * Improve docs based on feedback * Better clarification of features * Fix example * Spelling/grammar issue * Spelling and clarification --- docs/config_options.md | 1 + docs/feature_leader_key.md | 82 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 7 deletions(-) (limited to 'docs/feature_leader_key.md') diff --git a/docs/config_options.md b/docs/config_options.md index fb1655e9a..879761a40 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -143,6 +143,7 @@ If you define these options you will enable the associated feature, which may in * Breaks any Tap Toggle functionality (`TT` or the One Shot Tap Toggle) * `#define LEADER_TIMEOUT 300` * how long before the leader key times out + * If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. * `#define LEADER_PER_KEY_TIMING` * sets the timer for leader key chords to run on each key press rather than overall * `#define ONESHOT_TIMEOUT 300` diff --git a/docs/feature_leader_key.md b/docs/feature_leader_key.md index 9b49e0fd9..168a1fc1c 100644 --- a/docs/feature_leader_key.md +++ b/docs/feature_leader_key.md @@ -5,10 +5,11 @@ If you've ever used Vim, you know what a Leader key is. If not, you're about to That's what `KC_LEAD` does. Here's an example: 1. Pick a key on your keyboard you want to use as the Leader key. Assign it the keycode `KC_LEAD`. This key would be dedicated just for this -- it's a single action key, can't be used for anything else. -2. Include the line `#define LEADER_TIMEOUT 300` in your config.h. The 300 there is 300ms -- that's how long you have for the sequence of keys following the leader. You can tweak this value for comfort, of course. -3. Within your `matrix_scan_user` function, do something like this: +2. Include the line `#define LEADER_TIMEOUT 300` in your `config.h`. This sets the timeout for the `KC_LEAD` key. Specifically, when you press the `KC_LEAD` key, you only have a certain amount of time to complete the Leader Key sequence. The `300` here sets that to 300ms, and you can increase this value to give you more time to hit the sequence. But any keys pressed during this timeout are intercepted and not sent, so you may want to keep this value low. . + * By default, this timeout is how long after pressing `KC_LEAD` to complete your entire sequence. This may be very low for some people. So you may want to increase this timeout. Optionally, you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. This allows you to maintain a low value here, but still be able to use the longer sequences. To enable this option, add `#define LEADER_PER_KEY_TIMING` to your `config.h`. +3. Within your `matrix_scan_user` function, add something like this: -``` +```c LEADER_EXTERNS(); void matrix_scan_user(void) { @@ -44,7 +45,7 @@ Each of these accepts one or more keycodes as arguments. This is an important po To add support for Leader Key you simply need to add a single line to your keymap's `rules.mk`: -``` +```make LEADER_ENABLE = yes ``` @@ -53,20 +54,87 @@ LEADER_ENABLE = yes Rather than relying on an incredibly high timeout for long leader key strings or those of us without 200wpm typing skills, we can enable per key timing to ensure that each key pressed provides us with more time to finish our stroke. This is incredibly helpful with leader key emulation of tap dance (read: multiple taps of the same key like C, C, C). In order to enable this, place this in your `config.h`: -``` +```c #define LEADER_PER_KEY_TIMING ``` After this, it's recommended that you lower your `LEADER_TIMEOUT` to something less that 300ms. -``` +```c #define LEADER_TIMEOUT 250 ``` Now, something like this won't seem impossible to do without a 1000MS leader key timeout: -``` +```c SEQ_THREE_KEYS(KC_C, KC_C, KC_C) { SEND_STRING("Per key timing is great!!!"); } ``` + +## Customization + +The Leader Key feature has some additional customization to how the Leader Key feature works. It has two functions that can be called at certain parts of the process. Namely `leader_start()` and `leader_end()`. + +The `leader_start()` function is called when you tap the `KC_LEAD` key, and the `leader_end()` function is called when either the leader sequence is completed, or the leader timeout is hit. + +You can add these functions to your code (`keymap.c` usually) to add feedback to the Leader sequences (such as beeping or playing music). + +```c +void leader_start(void) { + // sequence started +} + +void leader_end(void) { + // sequence ended (no success/failuer detection) +} +``` + +### Example + +This example will play the Mario "One Up" sound when you hit `KC_LEAD` to start the Leader Sequence, and will play "All Star" if it completes successfully or "Rick Roll" you if it fails. + +```c +bool did_leader_succeed; +#ifdef AUDIO_ENABLE +float leader_start[][2] = SONG(ONE_UP_SOUND ); +float leader_succeed[][2] = SONG(ALL_STAR); +float leader_fail[][2] = SONG(RICK_ROLL); +#endif +LEADER_EXTERNS(); + +void matrix_scan_user(void) { + LEADER_DICTIONARY() { + did_leader_succeed = leading = false; + + SEQ_ONE_KEY(KC_E) { + // Anything you can do in a macro. + SEND_STRING(SS_LCTRL(SS_LSFT("t"))); + did_leader_succeed = true; + } else + SEQ_TWO_KEYS(KC_E, KC_D) { + SEND_STRING(SS_LGUI("r")"cmd"SS_TAP(KC_ENTER)SS_LCTRL("c")); + did_leader_succeed = true; + } + leader_end(); + } +} + +void leader_start(void) { +#ifdef AUDIO_ENABLE + PLAY_SONG(leader_start); +#endif +} + +void leader_end(void) { + if (did_leader_succeed) { +#ifdef AUDIO_ENABLE + PLAY_SONG(leader_succeed); +#endif + } else { +#ifdef AUDIO_ENABLE + PLAY_SONG(leader_fail); +#endif + } +} +``` -- cgit v1.2.3-70-g09d2 From afd5cda4a0d832bacfff319177fe93968f686a11 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Thu, 20 Dec 2018 16:54:06 -0800 Subject: Fix up process_leader to be a bit more optimized (#4662) * Fix up process_leader to be a bit more optimized * Process dual function keys better * Make leader start a callable function * Fix per key timer call location * Add escape if already leading * Return false for KC_LEAD * Add documentation --- docs/config_options.md | 2 ++ docs/feature_leader_key.md | 6 ++++ quantum/process_keycode/process_leader.c | 51 +++++++++++++++++++------------- quantum/process_keycode/process_leader.h | 2 +- 4 files changed, 40 insertions(+), 21 deletions(-) (limited to 'docs/feature_leader_key.md') diff --git a/docs/config_options.md b/docs/config_options.md index 879761a40..4bbc5debd 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -146,6 +146,8 @@ If you define these options you will enable the associated feature, which may in * If you're having issues finishing the sequence before it times out, you may need to increase the timeout setting. Or you may want to enable the `LEADER_PER_KEY_TIMING` option, which resets the timeout after each key is tapped. * `#define LEADER_PER_KEY_TIMING` * sets the timer for leader key chords to run on each key press rather than overall +* `#define LEADER_KEY_STRICT_KEY_PROCESSING` + * Disables keycode filtering for Mod-Tap and Layer-Tap keycodes. Eg, if you enable this, you would need to specify `MT(MOD_CTL, KC_A)` if you want to use `KC_A`. * `#define ONESHOT_TIMEOUT 300` * how long before oneshot times out * `#define ONESHOT_TAP_TOGGLE 2` diff --git a/docs/feature_leader_key.md b/docs/feature_leader_key.md index 168a1fc1c..82cf78901 100644 --- a/docs/feature_leader_key.md +++ b/docs/feature_leader_key.md @@ -72,6 +72,12 @@ SEQ_THREE_KEYS(KC_C, KC_C, KC_C) { } ``` +## Strict Key Processing + +By default, the Leader Key feature will filter the keycode out of [`Mod-Tap`](feature_advanced_keycodes.md#mod-tap) and [`Layer Tap`](feature_advanced_keycodes.md#switching-and-toggling-layers) functions when checking for the Leader sequences. That means if you're using `LT(3, KC_A)`, it will pick this up as `KC_A` for the sequence, rather than `LT(3, KC_A)`, giving a more expected behavior for newer users. + +While, this may be fine for most, if you want to specify the whole keycode (eg, `LT(3, KC_A)` from the example above) in the sequence, you can enable this by added `#define LEADER_KEY_STRICT_KEY_PROCESSING` to your `config.h` file. This well then disable the filtering, and you'll need to specify the whole keycode. + ## Customization The Leader Key feature has some additional customization to how the Leader Key feature works. It has two functions that can be called at certain parts of the process. Namely `leader_start()` and `leader_end()`. diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c index b32fc1db6..57fccdc7e 100644 --- a/quantum/process_keycode/process_leader.c +++ b/quantum/process_keycode/process_leader.c @@ -35,31 +35,42 @@ uint16_t leader_time = 0; uint16_t leader_sequence[5] = {0, 0, 0, 0, 0}; uint8_t leader_sequence_size = 0; +void qk_leader_start(void) { + if (leading) { return; } + leader_start(); + leading = true; + leader_time = timer_read(); + leader_sequence_size = 0; + leader_sequence[0] = 0; + leader_sequence[1] = 0; + leader_sequence[2] = 0; + leader_sequence[3] = 0; + leader_sequence[4] = 0; +} + bool process_leader(uint16_t keycode, keyrecord_t *record) { // Leader key set-up if (record->event.pressed) { + if (leading) { + if (timer_elapsed(leader_time) < LEADER_TIMEOUT) { +#ifndef LEADER_KEY_STRICT_KEY_PROCESSING + if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) { + keycode = keycode & 0xFF; + } +#endif // LEADER_KEY_STRICT_KEY_PROCESSING + leader_sequence[leader_sequence_size] = keycode; + leader_sequence_size++; #ifdef LEADER_PER_KEY_TIMING - leader_time = timer_read(); + leader_time = timer_read(); #endif - if (!leading && keycode == KC_LEAD) { - leader_start(); - leading = true; -#ifndef LEADER_PER_KEY_TIMING - leader_time = timer_read(); -#endif - leader_time = timer_read(); - leader_sequence_size = 0; - leader_sequence[0] = 0; - leader_sequence[1] = 0; - leader_sequence[2] = 0; - leader_sequence[3] = 0; - leader_sequence[4] = 0; - return false; - } - if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) { - leader_sequence[leader_sequence_size] = keycode; - leader_sequence_size++; - return false; + return false; + } + } else { + if (keycode == KC_LEAD) { + qk_leader_start(); + return false; + } + break; } } return true; diff --git a/quantum/process_keycode/process_leader.h b/quantum/process_keycode/process_leader.h index 59c3eed1b..15bccc3f6 100644 --- a/quantum/process_keycode/process_leader.h +++ b/quantum/process_keycode/process_leader.h @@ -24,7 +24,7 @@ bool process_leader(uint16_t keycode, keyrecord_t *record); void leader_start(void); void leader_end(void); - +void qk_leader_start(void); #define SEQ_ONE_KEY(key) if (leader_sequence[0] == (key) && leader_sequence[1] == 0 && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0) #define SEQ_TWO_KEYS(key1, key2) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0) -- cgit v1.2.3-70-g09d2