parent
d10350cd2c
commit
bbf7a20b33
@ -1,165 +1,297 @@ |
||||
# The Leader Key: A New Kind of Modifier |
||||
# The Leader Key: A New Kind of Modifier :id=the-leader-key |
||||
|
||||
If you've ever used Vim, you know what a Leader key is. If not, you're about to discover a wonderful concept. :) Instead of hitting Alt+Shift+W for example (holding down three keys at the same time), what if you could hit a _sequence_ of keys instead? So you'd hit our special modifier (the Leader key), followed by W and then C (just a rapid succession of keys), and something would happen. |
||||
If you're a Vim user, you probably know what a Leader key is. In contrast to [Combos](feature_combo.md), the Leader key allows you to hit a *sequence* of up to five keys instead, which triggers some custom functionality once complete. |
||||
|
||||
That's what `QK_LEAD` does. Here's an example: |
||||
## Usage :id=usage |
||||
|
||||
1. Pick a key on your keyboard you want to use as the Leader key. Assign it the keycode `QK_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`. This sets the timeout for the `QK_LEAD` key. Specifically, when you press the `QK_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 `QK_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: |
||||
Add the following to your `rules.mk`: |
||||
|
||||
```c |
||||
LEADER_EXTERNS(); |
||||
|
||||
void matrix_scan_user(void) { |
||||
LEADER_DICTIONARY() { |
||||
leading = false; |
||||
leader_end(); |
||||
|
||||
SEQ_ONE_KEY(KC_F) { |
||||
// Anything you can do in a macro. |
||||
SEND_STRING("QMK is awesome."); |
||||
} |
||||
SEQ_TWO_KEYS(KC_D, KC_D) { |
||||
SEND_STRING(SS_LCTL("a") SS_LCTL("c")); |
||||
} |
||||
SEQ_THREE_KEYS(KC_D, KC_D, KC_S) { |
||||
SEND_STRING("https://start.duckduckgo.com\n"); |
||||
} |
||||
SEQ_TWO_KEYS(KC_A, KC_S) { |
||||
register_code(KC_LGUI); |
||||
register_code(KC_S); |
||||
unregister_code(KC_S); |
||||
unregister_code(KC_LGUI); |
||||
} |
||||
} |
||||
} |
||||
```make |
||||
LEADER_ENABLE = yes |
||||
``` |
||||
|
||||
As you can see, you have a few functions. 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. |
||||
Then add the `QK_LEAD` keycode to your keymap. |
||||
|
||||
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. |
||||
## Callbacks :id=callbacks |
||||
|
||||
## Adding Leader Key Support |
||||
These callbacks are invoked when the leader sequence begins and ends. In the latter you can implement your custom functionality based on the contents of the sequence buffer. |
||||
|
||||
To enable Leader Key, add the following line to your keymap's `rules.mk`: |
||||
```c |
||||
void leader_start_user(void) { |
||||
// Do something when the leader key is pressed |
||||
} |
||||
|
||||
```make |
||||
LEADER_ENABLE = yes |
||||
void leader_end_user(void) { |
||||
if (leader_sequence_one_key(KC_F)) { |
||||
// Leader, f => Types the below string |
||||
SEND_STRING("QMK is awesome."); |
||||
} else if (leader_sequence_two_keys(KC_D, KC_D)) { |
||||
// Leader, d, d => Ctrl+A, Ctrl+C |
||||
SEND_STRING(SS_LCTL("a") SS_LCTL("c")); |
||||
} else if (leader_sequence_three_keys(KC_D, KC_D, KC_S)) { |
||||
// Leader, d, d, s => Types the below string |
||||
SEND_STRING("https://start.duckduckgo.com\n"); |
||||
} else if (leader_sequence_two_keys(KC_A, KC_S)) { |
||||
// Leader, a, s => GUI+S |
||||
tap_code16(LGUI(KC_S)); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
Place the following macro in your `keymap.c` or user space source file, before any functional code. It handles declaration of external variables that will be referenced by Leader Key codes that follows: |
||||
## Basic Configuration :id=basic-configuration |
||||
|
||||
### Timeout :id=timeout |
||||
|
||||
This is the amount of time you have to complete a sequence once the leader key has been pressed. The default value is 300 milliseconds, but you can change this by adding the following to your `config.h`: |
||||
|
||||
```c |
||||
LEADER_EXTERNS(); |
||||
#define LEADER_TIMEOUT 350 |
||||
``` |
||||
|
||||
## Per Key Timing on Leader keys |
||||
### Per-Key Timeout :id=per-key-timeout |
||||
|
||||
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). |
||||
Rather than relying on an incredibly high timeout for long leader key strings or those of us without 200 wpm typing skills, you can enable per-key timing to ensure that each key pressed provides you with more time to finish the sequence. This is incredibly helpful with leader key emulation of tap dance (such as multiple taps of the same key like C, C, C). |
||||
|
||||
To enable this, add the following to your `config.h`: |
||||
|
||||
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. |
||||
After this, it's recommended that you lower your timeout below 300 ms: |
||||
|
||||
```c |
||||
#define LEADER_TIMEOUT 250 |
||||
``` |
||||
|
||||
Now, something like this won't seem impossible to do without a 1000MS leader key timeout: |
||||
Now, something like this won't seem impossible to do without a 1000 millisecond timeout: |
||||
|
||||
```c |
||||
SEQ_THREE_KEYS(KC_C, KC_C, KC_C) { |
||||
SEND_STRING("Per key timing is great!!!"); |
||||
if (leader_sequence_three_keys(KC_C, KC_C, KC_C)) { |
||||
SEND_STRING("Per key timing is great!!!"); |
||||
} |
||||
``` |
||||
|
||||
## Infinite Leader key timeout |
||||
### Disabling Initial Timeout :id=disabling-initial-timeout |
||||
|
||||
Sometimes your leader key may be too far away from the rest of the keys in the sequence. Imagine that your leader key is one of your outer top right keys - you may need to reposition your hand just to reach your leader key. This can make typing the entire sequence on time hard difficult if you are able to type most of the sequence fast. For example, if your sequence is `Leader + asd`, typing `asd` fast is very easy once you have your hands in your home row, but starting the sequence in time after moving your hand out of the home row to reach the leader key and back is not. |
||||
|
||||
Sometimes your leader key is not on a comfortable place as the rest of keys on your sequence. Imagine that your leader key is one of your outer top right keys, you may need to reposition your hand just to reach your leader key. |
||||
This can make typing the entire sequence on time hard even if you are able to type most of the sequence fast. For example, if your sequence is `Leader + asd` typing `asd` fast is very easy once you have your hands in your home row. However starting the sequence in time after moving your hand out of the home row to reach the leader key and back is not. |
||||
To remove the stress this situation produces to your hands you can enable an infinite timeout just for the leader key. This means that after you hit the leader key you will have an infinite amount of time to start the rest of the sequence, allowing you to proper position your hands on the best position to type the rest of the sequence comfortably. |
||||
This infinite timeout only affects the leader key, so in our previous example of `Leader + asd` you will have an infinite amount of time between `Leader` and `a`, but once you start the sequence the timeout you have configured (global or per key) will work normally. |
||||
This way you can configure a very short `LEADER_TIMEOUT` but still have plenty of time to position your hands. |
||||
To remove the stress this situation produces to your hands, you can disable the timeout just for the leader key. Add the following to your `config.h`: |
||||
|
||||
In order to enable this, place this in your `config.h`: |
||||
```c |
||||
#define LEADER_NO_TIMEOUT |
||||
``` |
||||
|
||||
## Strict Key Processing |
||||
|
||||
By default, the Leader Key feature will filter the keycode out of [`Mod-Tap`](mod_tap.md) and [`Layer Tap`](feature_layers.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. |
||||
Now, after you hit the leader key, you will have an infinite amount of time to start the rest of the sequence, allowing you to properly position your hands to type the rest of the sequence comfortably. This way you can configure a very short `LEADER_TIMEOUT`, but still have plenty of time to position your hands. |
||||
|
||||
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 adding `#define LEADER_KEY_STRICT_KEY_PROCESSING` to your `config.h` file. This will then disable the filtering, and you'll need to specify the whole keycode. |
||||
### Strict Key Processing :id=strict-key-processing |
||||
|
||||
## Customization |
||||
By default, only the "tap keycode" portions of [Mod-Taps](mod_tap.md) and [Layer Taps](feature_layers.md#switching-and-toggling-layers) are added to the sequence buffer. This means if you press eg. `LT(3, KC_A)` as part of a sequence, `KC_A` will be added to the buffer, rather than the entire `LT(3, KC_A)` keycode. |
||||
|
||||
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_user()` and `leader_end_user()`. |
||||
This gives a more expected behaviour for most users, however you may want to change this. |
||||
|
||||
The `leader_start_user()` function is called when you tap the `QK_LEAD` key, and the `leader_end_user()` 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). |
||||
To enable this, add the following to your `config.h`: |
||||
|
||||
```c |
||||
void leader_start_user(void) { |
||||
// sequence started |
||||
} |
||||
|
||||
void leader_end_user(void) { |
||||
// sequence ended (no success/failure detection) |
||||
} |
||||
#define LEADER_KEY_STRICT_KEY_PROCESSING |
||||
``` |
||||
|
||||
### Example |
||||
## Example :id=example |
||||
|
||||
This example will play the Mario "One Up" sound when you hit `QK_LEAD` to start the Leader Sequence, and will play "All Star" if it completes successfully or "Rick Roll" you if it fails. |
||||
This example will play the Mario "One Up" sound when you hit `QK_LEAD` to start the leader sequence. When the sequence ends, it will play "All Star" if it completes successfully or "Rick Roll" you if it fails (in other words, no sequence matched). |
||||
|
||||
```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); |
||||
float leader_start_song[][2] = SONG(ONE_UP_SOUND); |
||||
float leader_succeed_song[][2] = SONG(ALL_STAR); |
||||
float leader_fail_song[][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_LCTL(SS_LSFT("t"))); |
||||
did_leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_E, KC_D) { |
||||
SEND_STRING(SS_LGUI("r") "cmd\n" SS_LCTL("c")); |
||||
did_leader_succeed = true; |
||||
} |
||||
leader_end(); |
||||
} |
||||
} |
||||
|
||||
void leader_start_user(void) { |
||||
#ifdef AUDIO_ENABLE |
||||
PLAY_SONG(leader_start); |
||||
PLAY_SONG(leader_start_song); |
||||
#endif |
||||
} |
||||
|
||||
void leader_end_user(void) { |
||||
if (did_leader_succeed) { |
||||
#ifdef AUDIO_ENABLE |
||||
PLAY_SONG(leader_succeed); |
||||
#endif |
||||
} else { |
||||
bool did_leader_succeed = false; |
||||
|
||||
if (leader_sequence_one_key(KC_E)) { |
||||
SEND_STRING(SS_LCTL(SS_LSFT("t"))); |
||||
did_leader_succeed = true; |
||||
} else if (leader_sequence_two_keys(KC_E, KC_D)) { |
||||
SEND_STRING(SS_LGUI("r") "cmd\n" SS_LCTL("c")); |
||||
did_leader_succeed = true; |
||||
} |
||||
|
||||
#ifdef AUDIO_ENABLE |
||||
PLAY_SONG(leader_fail); |
||||
if (did_leader_succeed) { |
||||
PLAY_SONG(leader_succeed_song); |
||||
} else { |
||||
PLAY_SONG(leader_fail_song); |
||||
} |
||||
#endif |
||||
} |
||||
} |
||||
``` |
||||
|
||||
## Keycodes :id=keycodes |
||||
|
||||
|Key |Aliases |Description | |
||||
|-----------------------|---------|-------------------------| |
||||
|`QK_LEADER` |`QK_LEAD`|Begin the leader sequence| |
||||
|
||||
## API :id=api |
||||
|
||||
### `void leader_start_user(void)` :id=api-leader-start-user |
||||
|
||||
User callback, invoked when the leader sequence begins. |
||||
|
||||
--- |
||||
|
||||
### `void leader_end_user(void)` :id=api-leader-end-user |
||||
|
||||
User callback, invoked when the leader sequence ends. |
||||
|
||||
--- |
||||
|
||||
### `void leader_start(void)` :id=api-leader-start |
||||
|
||||
Begin the leader sequence, resetting the buffer and timer. |
||||
|
||||
--- |
||||
|
||||
### `void leader_end(void)` :id=api-leader-end |
||||
|
||||
End the leader sequence. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_active(void)` :id=api-leader-sequence-active |
||||
|
||||
Whether the leader sequence is active. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_add(uint16_t keycode)` :id=api-leader-sequence-add |
||||
|
||||
Add the given keycode to the sequence buffer. |
||||
|
||||
If `LEADER_NO_TIMEOUT` is defined, the timer is reset if the buffer is empty. |
||||
|
||||
#### Arguments :id=api-leader-sequence-add-arguments |
||||
|
||||
- `uint16_t keycode` |
||||
The keycode to add. |
||||
|
||||
#### Return Value :id=api-leader-sequence-add-return |
||||
|
||||
`true` if the keycode was added, `false` if the buffer is full. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_timed_out(void)` :id=api-leader-sequence-timed-out |
||||
|
||||
Whether the leader sequence has reached the timeout. |
||||
|
||||
If `LEADER_NO_TIMEOUT` is defined, the buffer must also contain at least one key. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_reset_timer(void)` :id=api-leader-reset-timer |
||||
|
||||
Reset the leader sequence timer. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_one_key(uint16_t kc)` :id=api-leader-sequence-one-key |
||||
|
||||
Check the sequence buffer for the given keycode. |
||||
|
||||
#### Arguments :id=api-leader-sequence-one-key-arguments |
||||
|
||||
- `uint16_t kc` |
||||
The keycode to check. |
||||
|
||||
#### Return Value :id=api-leader-sequence-one-key-return |
||||
|
||||
`true` if the sequence buffer matches. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_two_keys(uint16_t kc1, uint16_t kc2)` :id=api-leader-sequence-two-keys |
||||
|
||||
Check the sequence buffer for the given keycodes. |
||||
|
||||
#### Arguments :id=api-leader-sequence-two-keys-arguments |
||||
|
||||
- `uint16_t kc1` |
||||
The first keycode to check. |
||||
- `uint16_t kc2` |
||||
The second keycode to check. |
||||
|
||||
#### Return Value :id=api-leader-sequence-two-keys-return |
||||
|
||||
`true` if the sequence buffer matches. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_three_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3)` :id=api-leader-sequence-three-keys |
||||
|
||||
Check the sequence buffer for the given keycodes. |
||||
|
||||
#### Arguments :id=api-leader-sequence-three-keys-arguments |
||||
|
||||
- `uint16_t kc1` |
||||
The first keycode to check. |
||||
- `uint16_t kc2` |
||||
The second keycode to check. |
||||
- `uint16_t kc3` |
||||
The third keycode to check. |
||||
|
||||
#### Return Value :id=api-leader-sequence-three-keys-return |
||||
|
||||
`true` if the sequence buffer matches. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_four_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4)` :id=api-leader-sequence-four-keys |
||||
|
||||
Check the sequence buffer for the given keycodes. |
||||
|
||||
#### Arguments :id=api-leader-sequence-four-keys-arguments |
||||
|
||||
- `uint16_t kc1` |
||||
The first keycode to check. |
||||
- `uint16_t kc2` |
||||
The second keycode to check. |
||||
- `uint16_t kc3` |
||||
The third keycode to check. |
||||
- `uint16_t kc4` |
||||
The fourth keycode to check. |
||||
|
||||
#### Return Value :id=api-leader-sequence-four-keys-return |
||||
|
||||
`true` if the sequence buffer matches. |
||||
|
||||
--- |
||||
|
||||
### `bool leader_sequence_five_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4, uint16_t kc5)` :id=api-leader-sequence-five-keys |
||||
|
||||
Check the sequence buffer for the given keycodes. |
||||
|
||||
#### Arguments :id=api-leader-sequence-five-keys-arguments |
||||
|
||||
- `uint16_t kc1` |
||||
The first keycode to check. |
||||
- `uint16_t kc2` |
||||
The second keycode to check. |
||||
- `uint16_t kc3` |
||||
The third keycode to check. |
||||
- `uint16_t kc4` |
||||
The fourth keycode to check. |
||||
- `uint16_t kc5` |
||||
The fifth keycode to check. |
||||
|
||||
#### Return Value :id=api-leader-sequence-five-keys-return |
||||
|
||||
`true` if the sequence buffer matches. |
||||
|
@ -1,14 +0,0 @@ |
||||
LEADER_DICTIONARY() { |
||||
leading = false; |
||||
leader_end(); |
||||
|
||||
SEQ_ONE_KEY(TD(APMR_PIPE)) { |
||||
register_code(KC_LCTL); |
||||
register_code(KC_LSFT); |
||||
register_code(KC_U); |
||||
|
||||
unregister_code(KC_U); |
||||
unregister_code(KC_LSFT); |
||||
unregister_code(KC_LCTL); |
||||
} |
||||
} |
@ -1 +0,0 @@ |
||||
LEADER_EXTERNS(); |
@ -0,0 +1,101 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "leader.h" |
||||
#include "timer.h" |
||||
#include "util.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#ifndef LEADER_TIMEOUT |
||||
# define LEADER_TIMEOUT 300 |
||||
#endif |
||||
|
||||
// Leader key stuff
|
||||
bool leading = false; |
||||
uint16_t leader_time = 0; |
||||
uint16_t leader_sequence[5] = {0, 0, 0, 0, 0}; |
||||
uint8_t leader_sequence_size = 0; |
||||
|
||||
__attribute__((weak)) void leader_start_user(void) {} |
||||
|
||||
__attribute__((weak)) void leader_end_user(void) {} |
||||
|
||||
void leader_start(void) { |
||||
if (leading) { |
||||
return; |
||||
} |
||||
leader_start_user(); |
||||
leading = true; |
||||
leader_time = timer_read(); |
||||
leader_sequence_size = 0; |
||||
memset(leader_sequence, 0, sizeof(leader_sequence)); |
||||
} |
||||
|
||||
void leader_end(void) { |
||||
leading = false; |
||||
leader_end_user(); |
||||
} |
||||
|
||||
void leader_task(void) { |
||||
if (leader_sequence_active() && leader_sequence_timed_out()) { |
||||
leader_end(); |
||||
} |
||||
} |
||||
|
||||
bool leader_sequence_active(void) { |
||||
return leading; |
||||
} |
||||
|
||||
bool leader_sequence_add(uint16_t keycode) { |
||||
if (leader_sequence_size >= ARRAY_SIZE(leader_sequence)) { |
||||
return false; |
||||
} |
||||
|
||||
#if defined(LEADER_NO_TIMEOUT) |
||||
if (leader_sequence_size == 0) { |
||||
leader_reset_timer(); |
||||
} |
||||
#endif |
||||
|
||||
leader_sequence[leader_sequence_size] = keycode; |
||||
leader_sequence_size++; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool leader_sequence_timed_out(void) { |
||||
#if defined(LEADER_NO_TIMEOUT) |
||||
return leader_sequence_size > 0 && timer_elapsed(leader_time) > LEADER_TIMEOUT; |
||||
#else |
||||
return timer_elapsed(leader_time) > LEADER_TIMEOUT; |
||||
#endif |
||||
} |
||||
|
||||
void leader_reset_timer(void) { |
||||
leader_time = timer_read(); |
||||
} |
||||
|
||||
bool leader_sequence_is(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4, uint16_t kc5) { |
||||
return leader_sequence[0] == kc1 && leader_sequence[1] == kc2 && leader_sequence[2] == kc3 && leader_sequence[3] == kc4 && leader_sequence[4] == kc5; |
||||
} |
||||
|
||||
bool leader_sequence_one_key(uint16_t kc) { |
||||
return leader_sequence_is(kc, 0, 0, 0, 0); |
||||
} |
||||
|
||||
bool leader_sequence_two_keys(uint16_t kc1, uint16_t kc2) { |
||||
return leader_sequence_is(kc1, kc2, 0, 0, 0); |
||||
} |
||||
|
||||
bool leader_sequence_three_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3) { |
||||
return leader_sequence_is(kc1, kc2, kc3, 0, 0); |
||||
} |
||||
|
||||
bool leader_sequence_four_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4) { |
||||
return leader_sequence_is(kc1, kc2, kc3, kc4, 0); |
||||
} |
||||
|
||||
bool leader_sequence_five_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4, uint16_t kc5) { |
||||
return leader_sequence_is(kc1, kc2, kc3, kc4, kc5); |
||||
} |
@ -0,0 +1,119 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <stdbool.h> |
||||
#include <stdint.h> |
||||
|
||||
/**
|
||||
* \defgroup leader |
||||
* |
||||
* Leader Key |
||||
* \{ |
||||
*/ |
||||
|
||||
/**
|
||||
* \brief User callback, invoked when the leader sequence begins. |
||||
*/ |
||||
void leader_start_user(void); |
||||
|
||||
/**
|
||||
* \brief User callback, invoked when the leader sequence ends. |
||||
*/ |
||||
void leader_end_user(void); |
||||
|
||||
/**
|
||||
* Begin the leader sequence, resetting the buffer and timer. |
||||
*/ |
||||
void leader_start(void); |
||||
|
||||
/**
|
||||
* End the leader sequence. |
||||
*/ |
||||
void leader_end(void); |
||||
|
||||
void leader_task(void); |
||||
|
||||
/**
|
||||
* Whether the leader sequence is active. |
||||
*/ |
||||
bool leader_sequence_active(void); |
||||
|
||||
/**
|
||||
* Add the given keycode to the sequence buffer. |
||||
* |
||||
* If `LEADER_NO_TIMEOUT` is defined, the timer is reset if the buffer is empty. |
||||
* |
||||
* \param keycode The keycode to add. |
||||
* |
||||
* \return `true` if the keycode was added, `false` if the buffer is full. |
||||
*/ |
||||
bool leader_sequence_add(uint16_t keycode); |
||||
|
||||
/**
|
||||
* Whether the leader sequence has reached the timeout. |
||||
* |
||||
* If `LEADER_NO_TIMEOUT` is defined, the buffer must also contain at least one key. |
||||
*/ |
||||
bool leader_sequence_timed_out(void); |
||||
|
||||
/**
|
||||
* Reset the leader sequence timer. |
||||
*/ |
||||
void leader_reset_timer(void); |
||||
|
||||
/**
|
||||
* Check the sequence buffer for the given keycode. |
||||
* |
||||
* \param kc The keycode to check. |
||||
* |
||||
* \return `true` if the sequence buffer matches. |
||||
*/ |
||||
bool leader_sequence_one_key(uint16_t kc); |
||||
|
||||
/**
|
||||
* Check the sequence buffer for the given keycodes. |
||||
* |
||||
* \param kc1 The first keycode to check. |
||||
* \param kc2 The second keycode to check. |
||||
* |
||||
* \return `true` if the sequence buffer matches. |
||||
*/ |
||||
bool leader_sequence_two_keys(uint16_t kc1, uint16_t kc2); |
||||
|
||||
/**
|
||||
* Check the sequence buffer for the given keycodes. |
||||
* |
||||
* \param kc1 The first keycode to check. |
||||
* \param kc2 The second keycode to check. |
||||
* \param kc3 The third keycode to check. |
||||
* |
||||
* \return `true` if the sequence buffer matches. |
||||
*/ |
||||
bool leader_sequence_three_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3); |
||||
|
||||
/**
|
||||
* Check the sequence buffer for the given keycodes. |
||||
* |
||||
* \param kc1 The first keycode to check. |
||||
* \param kc2 The second keycode to check. |
||||
* \param kc3 The third keycode to check. |
||||
* \param kc4 The fourth keycode to check. |
||||
* |
||||
* \return `true` if the sequence buffer matches. |
||||
*/ |
||||
bool leader_sequence_four_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4); |
||||
|
||||
/**
|
||||
* Check the sequence buffer for the given keycodes. |
||||
* |
||||
* \param kc1 The first keycode to check. |
||||
* \param kc2 The second keycode to check. |
||||
* \param kc3 The third keycode to check. |
||||
* \param kc4 The fourth keycode to check. |
||||
* \param kc5 The fifth keycode to check. |
||||
* |
||||
* \return `true` if the sequence buffer matches. |
||||
*/ |
||||
bool leader_sequence_five_keys(uint16_t kc1, uint16_t kc2, uint16_t kc3, uint16_t kc4, uint16_t kc5); |
||||
|
||||
/** \} */ |
@ -0,0 +1,6 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once |
||||
|
||||
#include "test_common.h" |
@ -0,0 +1,8 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once |
||||
|
||||
#include "test_common.h" |
||||
|
||||
#define LEADER_NO_TIMEOUT |
@ -0,0 +1,7 @@ |
||||
# --------------------------------------------------------------------------------
|
||||
# Keep this file, even if it is empty, as a marker that this folder contains tests
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
LEADER_ENABLE = yes
|
||||
|
||||
SRC += ../leader_sequences.c
|
@ -0,0 +1,48 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "keyboard_report_util.hpp" |
||||
#include "keycode.h" |
||||
#include "test_common.hpp" |
||||
#include "test_keymap_key.hpp" |
||||
|
||||
using testing::_; |
||||
|
||||
class Leader : public TestFixture {}; |
||||
|
||||
TEST_F(Leader, does_not_timeout_until_next_key_pressed) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
|
||||
set_keymap({key_leader, key_a}); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
|
||||
idle_for(1000); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
EXPECT_REPORT(driver, (KC_1)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
idle_for(300); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
EXPECT_EQ(leader_sequence_timed_out(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_A)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
} |
@ -0,0 +1,5 @@ |
||||
#pragma once |
||||
|
||||
#include "test_common.h" |
||||
|
||||
#define LEADER_PER_KEY_TIMING |
@ -0,0 +1,7 @@ |
||||
# --------------------------------------------------------------------------------
|
||||
# Keep this file, even if it is empty, as a marker that this folder contains tests
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
LEADER_ENABLE = yes
|
||||
|
||||
SRC += ../leader_sequences.c
|
@ -0,0 +1,40 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "keyboard_report_util.hpp" |
||||
#include "keycode.h" |
||||
#include "test_common.hpp" |
||||
#include "test_keymap_key.hpp" |
||||
|
||||
using testing::_; |
||||
|
||||
class Leader : public TestFixture {}; |
||||
|
||||
TEST_F(Leader, does_not_timeout_during_sequence) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
auto key_b = KeymapKey(0, 2, 0, KC_B); |
||||
auto key_c = KeymapKey(0, 3, 0, KC_C); |
||||
|
||||
set_keymap({key_leader, key_a, key_b, key_c}); |
||||
|
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_a); |
||||
|
||||
idle_for(150); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_b); |
||||
|
||||
idle_for(150); |
||||
|
||||
EXPECT_REPORT(driver, (KC_3)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_c); |
||||
|
||||
idle_for(300); |
||||
} |
@ -0,0 +1,26 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "quantum.h" |
||||
|
||||
void leader_end_user(void) { |
||||
if (leader_sequence_one_key(KC_A)) { |
||||
tap_code(KC_1); |
||||
} |
||||
|
||||
if (leader_sequence_two_keys(KC_A, KC_B)) { |
||||
tap_code(KC_2); |
||||
} |
||||
|
||||
if (leader_sequence_three_keys(KC_A, KC_B, KC_C)) { |
||||
tap_code(KC_3); |
||||
} |
||||
|
||||
if (leader_sequence_four_keys(KC_A, KC_B, KC_C, KC_D)) { |
||||
tap_code(KC_4); |
||||
} |
||||
|
||||
if (leader_sequence_five_keys(KC_A, KC_B, KC_C, KC_D, KC_E)) { |
||||
tap_code(KC_5); |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once |
||||
|
||||
#include "test_common.h" |
||||
|
||||
#define LEADER_KEY_STRICT_KEY_PROCESSING |
@ -0,0 +1,7 @@ |
||||
# --------------------------------------------------------------------------------
|
||||
# Keep this file, even if it is empty, as a marker that this folder contains tests
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
LEADER_ENABLE = yes
|
||||
|
||||
SRC += ../leader_sequences.c
|
@ -0,0 +1,45 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "keyboard_report_util.hpp" |
||||
#include "keycode.h" |
||||
#include "test_common.hpp" |
||||
#include "test_keymap_key.hpp" |
||||
|
||||
using testing::_; |
||||
|
||||
class Leader : public TestFixture {}; |
||||
|
||||
TEST_F(Leader, does_not_extract_mod_tap_keycode) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_mt = KeymapKey(0, 1, 0, LSFT_T(KC_A)); |
||||
|
||||
set_keymap({key_leader, key_mt}); |
||||
|
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_mt); |
||||
|
||||
EXPECT_EQ(leader_sequence_one_key(KC_A), false); |
||||
EXPECT_EQ(leader_sequence_one_key(LSFT_T(KC_A)), true); |
||||
} |
||||
|
||||
TEST_F(Leader, does_not_extract_layer_tap_keycode) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_lt = KeymapKey(0, 1, 0, LT(1, KC_A)); |
||||
|
||||
set_keymap({key_leader, key_lt}); |
||||
|
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_lt); |
||||
|
||||
EXPECT_EQ(leader_sequence_one_key(KC_A), false); |
||||
EXPECT_EQ(leader_sequence_one_key(LT(1, KC_A)), true); |
||||
} |
@ -0,0 +1,7 @@ |
||||
# --------------------------------------------------------------------------------
|
||||
# Keep this file, even if it is empty, as a marker that this folder contains tests
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
LEADER_ENABLE = yes
|
||||
|
||||
SRC += leader_sequences.c
|
@ -0,0 +1,224 @@ |
||||
// Copyright 2023 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "keyboard_report_util.hpp" |
||||
#include "keycode.h" |
||||
#include "test_common.hpp" |
||||
#include "test_keymap_key.hpp" |
||||
|
||||
using testing::_; |
||||
|
||||
class Leader : public TestFixture {}; |
||||
|
||||
TEST_F(Leader, triggers_one_key_sequence) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
|
||||
set_keymap({key_leader, key_a}); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_1)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
|
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
idle_for(300); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
EXPECT_EQ(leader_sequence_timed_out(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_A)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
} |
||||
|
||||
TEST_F(Leader, triggers_two_key_sequence) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
auto key_b = KeymapKey(0, 2, 0, KC_B); |
||||
|
||||
set_keymap({key_leader, key_a, key_b}); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_2)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
tap_key(key_b); |
||||
|
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
idle_for(300); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
EXPECT_EQ(leader_sequence_timed_out(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_A)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
} |
||||
|
||||
TEST_F(Leader, triggers_three_key_sequence) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
auto key_b = KeymapKey(0, 2, 0, KC_B); |
||||
auto key_c = KeymapKey(0, 3, 0, KC_C); |
||||
|
||||
set_keymap({key_leader, key_a, key_b, key_c}); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_3)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
tap_key(key_b); |
||||
tap_key(key_c); |
||||
|
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
idle_for(300); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
EXPECT_EQ(leader_sequence_timed_out(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_A)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
} |
||||
|
||||
TEST_F(Leader, triggers_four_key_sequence) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
auto key_b = KeymapKey(0, 2, 0, KC_B); |
||||
auto key_c = KeymapKey(0, 3, 0, KC_C); |
||||
auto key_d = KeymapKey(0, 4, 0, KC_D); |
||||
|
||||
set_keymap({key_leader, key_a, key_b, key_c, key_d}); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_4)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
tap_key(key_b); |
||||
tap_key(key_c); |
||||
tap_key(key_d); |
||||
|
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
idle_for(300); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
EXPECT_EQ(leader_sequence_timed_out(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_A)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
} |
||||
|
||||
TEST_F(Leader, triggers_five_key_sequence) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_a = KeymapKey(0, 1, 0, KC_A); |
||||
auto key_b = KeymapKey(0, 2, 0, KC_B); |
||||
auto key_c = KeymapKey(0, 3, 0, KC_C); |
||||
auto key_d = KeymapKey(0, 4, 0, KC_D); |
||||
auto key_e = KeymapKey(0, 5, 0, KC_E); |
||||
|
||||
set_keymap({key_leader, key_a, key_b, key_c, key_d, key_e}); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
|
||||
EXPECT_NO_REPORT(driver); |
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_5)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
tap_key(key_b); |
||||
tap_key(key_c); |
||||
tap_key(key_d); |
||||
tap_key(key_e); |
||||
|
||||
EXPECT_EQ(leader_sequence_timed_out(), false); |
||||
|
||||
idle_for(300); |
||||
|
||||
EXPECT_EQ(leader_sequence_active(), false); |
||||
EXPECT_EQ(leader_sequence_timed_out(), true); |
||||
|
||||
EXPECT_REPORT(driver, (KC_A)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_a); |
||||
} |
||||
|
||||
TEST_F(Leader, extracts_mod_tap_keycode) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_mt = KeymapKey(0, 1, 0, LSFT_T(KC_A)); |
||||
|
||||
set_keymap({key_leader, key_mt}); |
||||
|
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_REPORT(driver, (KC_1)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_mt); |
||||
|
||||
EXPECT_EQ(leader_sequence_one_key(KC_A), true); |
||||
|
||||
idle_for(300); |
||||
} |
||||
|
||||
TEST_F(Leader, extracts_layer_tap_keycode) { |
||||
TestDriver driver; |
||||
|
||||
auto key_leader = KeymapKey(0, 0, 0, QK_LEADER); |
||||
auto key_lt = KeymapKey(0, 1, 0, LT(1, KC_A)); |
||||
|
||||
set_keymap({key_leader, key_lt}); |
||||
|
||||
tap_key(key_leader); |
||||
|
||||
EXPECT_REPORT(driver, (KC_1)); |
||||
EXPECT_EMPTY_REPORT(driver); |
||||
tap_key(key_lt); |
||||
|
||||
EXPECT_EQ(leader_sequence_one_key(KC_A), true); |
||||
|
||||
idle_for(300); |
||||
} |
@ -1,24 +0,0 @@ |
||||
#include "curry.h" |
||||
#include "leader.h" |
||||
|
||||
LEADER_EXTERNS(); |
||||
|
||||
void matrix_scan_user(void) { |
||||
static bool has_ran_yet; |
||||
if (!has_ran_yet) { |
||||
has_ran_yet = true; |
||||
startup_user(); |
||||
} |
||||
|
||||
#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE) |
||||
matrix_scan_rgb(); |
||||
#endif // RGBLIGHT_ENABLE
|
||||
LEADER_DICTIONARY() { |
||||
leading = false; |
||||
leader_end(); |
||||
SEQ_ONE_KEY(KC_F) { SEND_STRING(SS_LCTL("akf")); } // Select all and format
|
||||
SEQ_ONE_KEY(KC_P) { SEND_STRING(SS_LCTL(SS_LSFT("4"))); } // Screenshot region
|
||||
SEQ_TWO_KEYS(KC_D, KC_D) { SEND_STRING(SS_LCTL("ac")); } // Copy all
|
||||
} |
||||
matrix_scan_keymap(); |
||||
} |
@ -0,0 +1,31 @@ |
||||
#include "curry.h" |
||||
#include "leader_user.h" |
||||
|
||||
void leader_end_user(void) { |
||||
if (leader_sequence_one_key(KC_F)) { |
||||
// Select all and format
|
||||
SEND_STRING(SS_LCTL("akf")); |
||||
} |
||||
if (leader_sequence_one_key(KC_P)) { |
||||
// Screenshot region
|
||||
SEND_STRING(SS_LCTL(SS_LSFT("4"))); |
||||
} |
||||
if (leader_sequence_two_keys(KC_D, KC_D)) { |
||||
// Copy all
|
||||
SEND_STRING(SS_LCTL("ac")); |
||||
} |
||||
} |
||||
|
||||
void matrix_scan_user(void) { |
||||
static bool has_ran_yet; |
||||
if (!has_ran_yet) { |
||||
has_ran_yet = true; |
||||
startup_user(); |
||||
} |
||||
|
||||
#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE) |
||||
matrix_scan_rgb(); |
||||
#endif // RGBLIGHT_ENABLE
|
||||
|
||||
matrix_scan_keymap(); |
||||
} |
@ -1,116 +0,0 @@ |
||||
#include "leader.h" |
||||
#ifdef RGBLIGHT_ENABLE |
||||
extern rgblight_config_t rgblight_config; |
||||
#endif |
||||
bool leader_succeed; |
||||
|
||||
LEADER_EXTERNS(); |
||||
|
||||
void matrix_scan_user(void) { |
||||
static bool has_ran_yet; |
||||
if (!has_ran_yet) { |
||||
has_ran_yet = true; |
||||
startup_user(); |
||||
} |
||||
#ifdef TAP_DANCE_ENABLE // Run Diablo 3 macro checking code.
|
||||
// run_diablo_macro_check();
|
||||
#endif |
||||
#ifdef RGBLIGHT_ENABLE |
||||
matrix_scan_rgb(); |
||||
#endif |
||||
LEADER_DICTIONARY() { |
||||
leader_succeed = leading = false; |
||||
|
||||
SEQ_ONE_KEY(KC_W) { |
||||
// vim/tmux: Use in command mode in vim: write to file, switch tmux pane in the current session window and repeat the last command
|
||||
SEND_STRING(":w" SS_TAP(X_ENTER)); |
||||
tmux_pane_switch_repeat(); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_ONE_KEY(KC_T) { |
||||
// Send the Tmux Prefix
|
||||
tmux_prefix(); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_ONE_KEY(KC_A) { |
||||
// tmux: Send the prefix and press 'right' arrow
|
||||
tmux_prefix(); |
||||
tap_code(KC_RIGHT); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_T, KC_T) { |
||||
// tmux: Send the prefix to a nested session
|
||||
tmux_prefix(); |
||||
tmux_prefix(); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_T, KC_R) { |
||||
// tmux: Switch pane and repeat last action
|
||||
tmux_pane_switch_repeat(); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_V, KC_Z){ |
||||
// vim: Zoom pane
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_BSLS)); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_V, KC_R) { |
||||
// vim: Substitute and place cursor
|
||||
SEND_STRING(":%s///g" SS_TAP(X_LEFT)); |
||||
tap_code(KC_LEFT); |
||||
tap_code(KC_LEFT); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_V, KC_T) { |
||||
// vim: move current pane to new tab
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_T)); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_ONE_KEY(KC_R){ |
||||
// Toggle RGB Layer indicator
|
||||
tap_code16(KC_RGB_T); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_ONE_KEY(KC_SPC){ |
||||
// One Shot Unicode layer
|
||||
//TODO tap_code16(OS_UNI);
|
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_TWO_KEYS(KC_SPC, KC_SPC){ |
||||
// Toggle _MODS
|
||||
tap_code16(TG_MODS); |
||||
leader_succeed = true; |
||||
} else |
||||
SEQ_THREE_KEYS(KC_BSPC, KC_BSPC, KC_BSPC){ |
||||
// Reset the keyboard
|
||||
reset_keyboard(); |
||||
leader_succeed = true; |
||||
} |
||||
leader_end(); |
||||
} |
||||
// matrix_scan_keymap();
|
||||
} |
||||
|
||||
void leader_start_user(void) { |
||||
#ifdef RGBLIGHT_ENABLE |
||||
rgblight_savebase(); |
||||
rgblight_mode_noeeprom(1); |
||||
rgblight_sethsv_noeeprom(HSV_GOLDENROD); |
||||
#endif |
||||
} |
||||
|
||||
void leader_end_user(void) { |
||||
// pick color depending of success /fail
|
||||
// fade leader_start from 100 to 0
|
||||
// fade new color from 0 to 100 to 0
|
||||
// fade old color from 0 to 100
|
||||
#ifdef RGBLIGHT_ENABLE |
||||
if (leader_succeed) { |
||||
fadeflash_leds(HSV_GREEN); |
||||
} else { |
||||
fadeflash_leds(HSV_RED); |
||||
} |
||||
#endif |
||||
} |
@ -0,0 +1,113 @@ |
||||
#include "leader_user.h" |
||||
#ifdef RGBLIGHT_ENABLE |
||||
extern rgblight_config_t rgblight_config; |
||||
#endif |
||||
bool leader_succeed; |
||||
|
||||
void matrix_scan_user(void) { |
||||
static bool has_ran_yet; |
||||
if (!has_ran_yet) { |
||||
has_ran_yet = true; |
||||
startup_user(); |
||||
} |
||||
#ifdef TAP_DANCE_ENABLE // Run Diablo 3 macro checking code.
|
||||
// run_diablo_macro_check();
|
||||
#endif |
||||
#ifdef RGBLIGHT_ENABLE |
||||
matrix_scan_rgb(); |
||||
#endif |
||||
|
||||
// matrix_scan_keymap();
|
||||
} |
||||
|
||||
void leader_start_user(void) { |
||||
#ifdef RGBLIGHT_ENABLE |
||||
rgblight_savebase(); |
||||
rgblight_mode_noeeprom(1); |
||||
rgblight_sethsv_noeeprom(HSV_GOLDENROD); |
||||
#endif |
||||
} |
||||
|
||||
void leader_end_user(void) { |
||||
leader_succeed = false; |
||||
|
||||
if (leader_sequence_one_key(KC_W)) { |
||||
// vim/tmux: Use in command mode in vim: write to file, switch tmux pane in the current session window and repeat the last command
|
||||
SEND_STRING(":w" SS_TAP(X_ENTER)); |
||||
tmux_pane_switch_repeat(); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_one_key(KC_T)) { |
||||
// Send the Tmux Prefix
|
||||
tmux_prefix(); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_one_key(KC_A)) { |
||||
// tmux: Send the prefix and press 'right' arrow
|
||||
tmux_prefix(); |
||||
tap_code(KC_RIGHT); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_two_keys(KC_T, KC_T)) { |
||||
// tmux: Send the prefix to a nested session
|
||||
tmux_prefix(); |
||||
tmux_prefix(); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_two_keys(KC_T, KC_R)) { |
||||
// tmux: Switch pane and repeat last action
|
||||
tmux_pane_switch_repeat(); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_two_keys(KC_V, KC_Z)){ |
||||
// vim: Zoom pane
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_BSLS)); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_two_keys(KC_V, KC_R)) { |
||||
// vim: Substitute and place cursor
|
||||
SEND_STRING(":%s///g" SS_TAP(X_LEFT)); |
||||
tap_code(KC_LEFT); |
||||
tap_code(KC_LEFT); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_two_keys(KC_V, KC_T)) { |
||||
// vim: move current pane to new tab
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_T)); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_one_key(KC_R)){ |
||||
// Toggle RGB Layer indicator
|
||||
tap_code16(KC_RGB_T); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_one_key(KC_SPC)){ |
||||
// One Shot Unicode layer
|
||||
//TODO tap_code16(OS_UNI);
|
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_two_keys(KC_SPC, KC_SPC)){ |
||||
// Toggle _MODS
|
||||
tap_code16(TG_MODS); |
||||
leader_succeed = true; |
||||
} else |
||||
if (leader_sequence_three_keys(KC_BSPC, KC_BSPC, KC_BSPC)){ |
||||
// Reset the keyboard
|
||||
reset_keyboard(); |
||||
leader_succeed = true; |
||||
} |
||||
|
||||
// pick color depending of success /fail
|
||||
// fade leader_start from 100 to 0
|
||||
// fade new color from 0 to 100 to 0
|
||||
// fade old color from 0 to 100
|
||||
#ifdef RGBLIGHT_ENABLE |
||||
if (leader_succeed) { |
||||
fadeflash_leds(HSV_GREEN); |
||||
} else { |
||||
fadeflash_leds(HSV_RED); |
||||
} |
||||
#endif |
||||
} |
@ -1,6 +1,6 @@ |
||||
#pragma once |
||||
#include "kuchosauronad0.h" |
||||
|
||||
#include "leader.h" |
||||
#include "leader_user.h" |
||||
|
||||
void matrix_scan_user(void); |
@ -1,46 +0,0 @@ |
||||
#include "leader.h" |
||||
|
||||
LEADER_EXTERNS(); |
||||
|
||||
// Runs constantly in the background, in a loop.
|
||||
void matrix_scan_user(void){ |
||||
|
||||
#ifdef TAP_DANCE_ENABLE // Run Diablo 3 macro checking code.
|
||||
// run_diablo_macro_check();
|
||||
#endif // TAP_DANCE_ENABLE
|
||||
|
||||
#ifdef RGBLIGHT_ENABLE |
||||
matrix_scan_rgb(); |
||||
#endif // RGBLIGHT_ENABLE
|
||||
|
||||
LEADER_DICTIONARY() { |
||||
leading = false; |
||||
leader_end(); |
||||
|
||||
SEQ_TWO_KEYS(KC_V, KC_Z){ |
||||
// vim: Zoom pane
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_BSLS)); |
||||
} |
||||
|
||||
SEQ_TWO_KEYS(KC_V, KC_R) { |
||||
// vim: Substitute and place cursor
|
||||
SEND_STRING(":%s///g" SS_TAP(X_LEFT)); |
||||
tap_code(KC_LEFT); |
||||
tap_code(KC_LEFT); |
||||
} |
||||
|
||||
SEQ_TWO_KEYS(KC_V, KC_T) { |
||||
// vim: move current pane to new tab
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_T)); |
||||
} |
||||
|
||||
SEQ_THREE_KEYS(KC_BSPC, KC_BSPC, KC_BSPC){ |
||||
// Reset the keyboard
|
||||
reset_keyboard(); |
||||
} |
||||
} |
||||
|
||||
matrix_scan_keymap(); |
||||
} |
@ -0,0 +1,41 @@ |
||||
#include "leader_user.h" |
||||
|
||||
void leader_end_user(void) { |
||||
if (leader_sequence_two_keys(KC_V, KC_Z)){ |
||||
// vim: Zoom pane
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_BSLS)); |
||||
} |
||||
|
||||
if (leader_sequence_two_keys(KC_V, KC_R)) { |
||||
// vim: Substitute and place cursor
|
||||
SEND_STRING(":%s///g" SS_TAP(X_LEFT)); |
||||
tap_code(KC_LEFT); |
||||
tap_code(KC_LEFT); |
||||
} |
||||
|
||||
if (leader_sequence_two_keys(KC_V, KC_T)) { |
||||
// vim: move current pane to new tab
|
||||
tap_code16(LCTL(KC_W)); |
||||
tap_code16(LSFT(KC_T)); |
||||
} |
||||
|
||||
if (leader_sequence_three_keys(KC_BSPC, KC_BSPC, KC_BSPC)){ |
||||
// Reset the keyboard
|
||||
reset_keyboard(); |
||||
} |
||||
} |
||||
|
||||
// Runs constantly in the background, in a loop.
|
||||
void matrix_scan_user(void){ |
||||
|
||||
#ifdef TAP_DANCE_ENABLE // Run Diablo 3 macro checking code.
|
||||
// run_diablo_macro_check();
|
||||
#endif // TAP_DANCE_ENABLE
|
||||
|
||||
#ifdef RGBLIGHT_ENABLE |
||||
matrix_scan_rgb(); |
||||
#endif // RGBLIGHT_ENABLE
|
||||
|
||||
matrix_scan_keymap(); |
||||
} |
@ -1,6 +1,6 @@ |
||||
#pragma once |
||||
#include "yet-another-developer.h" |
||||
|
||||
#include "leader.h" |
||||
#include "leader_user.h" |
||||
|
||||
void matrix_scan_user(void); |
Loading…
Reference in new issue