[Erez & Jack] Documents new Leader key functionality
This commit is contained in:
		
							
								
								
									
										56
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								README.md
									
									
									
									
									
								
							@@ -118,6 +118,42 @@ We've added shortcuts to make common modifier/tap (mod-tap) mappings more compac
 | 
			
		||||
  * `LCAG_T(kc)` - is CtrlAltGui when held and *kc* when tapped
 | 
			
		||||
  * `MEH_T(kc)` - is like Hyper, but not as cool -- does not include the Cmd/Win key, so just sends Alt+Ctrl+Shift.
 | 
			
		||||
 | 
			
		||||
### The Leader key: A new kind of modifier
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
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.
 | 
			
		||||
3. Within your `matrix_scan_user` function, do something like this:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
void matrix_scan_user(void) {
 | 
			
		||||
  LEADER_DICTIONARY() {
 | 
			
		||||
    leading = false;
 | 
			
		||||
    leader_end();
 | 
			
		||||
 | 
			
		||||
    SEQ_ONE_KEY(KC_F) {
 | 
			
		||||
      register_code(KC_S);
 | 
			
		||||
      unregister_code(KC_S);
 | 
			
		||||
    }
 | 
			
		||||
    SEQ_TWO_KEYS(KC_A, KC_S) {
 | 
			
		||||
      register_code(KC_H);
 | 
			
		||||
      unregister_code(KC_H);
 | 
			
		||||
    }
 | 
			
		||||
    SEQ_THREE_KEYS(KC_A, KC_S, KC_D) {
 | 
			
		||||
      register_code(KC_LGUI);
 | 
			
		||||
      register_code(KC_S);
 | 
			
		||||
      unregister_code(KC_S);
 | 
			
		||||
      unregister_code(KC_LGUI);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
As you can see, you have three function. you can use - `SEQ_ONE_KEY` for single-key sequences (Leader followed by just one key), and `SEQ_TWO_KEYS` and `SEQ_THREE_.EYS` 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.
 | 
			
		||||
 | 
			
		||||
### Temporarily setting the default layer
 | 
			
		||||
 | 
			
		||||
`DF(layer)` - sets default layer to *layer*. The default layer is the one at the "bottom" of the layer stack - the ultimate fallback layer. This currently does not persist over power loss. When you plug the keyboard back in, layer 0 will always be the default. It is theoretically possible to work around that, but that's not what `DF` does.
 | 
			
		||||
@@ -258,7 +294,7 @@ if (timer_elapsed(key_timer) < 100) {
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It's best to declare the `static uint16_t key_timer;` outside of the macro block (top of file, etc). 
 | 
			
		||||
It's best to declare the `static uint16_t key_timer;` outside of the macro block (top of file, etc).
 | 
			
		||||
 | 
			
		||||
#### Example 1: Single-key copy/paste (hold to copy, tap to paste)
 | 
			
		||||
 | 
			
		||||
@@ -276,7 +312,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 | 
			
		||||
        case 0: {
 | 
			
		||||
            if (record->event.pressed) {
 | 
			
		||||
                key_timer = timer_read(); // if the key is being pressed, we start the timer.
 | 
			
		||||
            } 
 | 
			
		||||
            }
 | 
			
		||||
            else { // this means the key was just released, so we can figure out how long it was pressed for (tap or "held down").
 | 
			
		||||
                if (timer_elapsed(key_timer) > 150) { // 150 being 150ms, the threshhold we pick for counting something as a tap.
 | 
			
		||||
                    return MACRO( D(LCTL), T(C), U(LCTL), END  );
 | 
			
		||||
@@ -312,7 +348,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 | 
			
		||||
                key_timer = timer_read(); // if the key is being pressed, we start the timer.
 | 
			
		||||
                register_code(KC_LSFT); // we're now holding down Shift.
 | 
			
		||||
            } else { // this means the key was just released, so we can figure out how long it was pressed for (tap or "held down").
 | 
			
		||||
                if (timer_elapsed(key_timer) < 150) { // 150 being 150ms, the threshhold we pick for counting something as a tap. 
 | 
			
		||||
                if (timer_elapsed(key_timer) < 150) { // 150 being 150ms, the threshhold we pick for counting something as a tap.
 | 
			
		||||
                    register_code(KC_9); // sending 9 while Shift is held down gives us an opening paren
 | 
			
		||||
                    unregister_code(KC_9); // now let's let go of that key
 | 
			
		||||
                }
 | 
			
		||||
@@ -323,13 +359,13 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 | 
			
		||||
        case 1: {
 | 
			
		||||
            if (record->event.pressed) {
 | 
			
		||||
                key_timer = timer_read(); // Now we're doing the same thing, only for the right shift/close paren key
 | 
			
		||||
                register_code(KC_RSFT); 
 | 
			
		||||
            } else { 
 | 
			
		||||
                if (timer_elapsed(key_timer) < 150) { 
 | 
			
		||||
                    register_code(KC_0); 
 | 
			
		||||
                    unregister_code(KC_0); 
 | 
			
		||||
                register_code(KC_RSFT);
 | 
			
		||||
            } else {
 | 
			
		||||
                if (timer_elapsed(key_timer) < 150) {
 | 
			
		||||
                    register_code(KC_0);
 | 
			
		||||
                    unregister_code(KC_0);
 | 
			
		||||
                }
 | 
			
		||||
                unregister_code(KC_RSFT); 
 | 
			
		||||
                unregister_code(KC_RSFT);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
@@ -510,4 +546,4 @@ what things are (and likely aren't) too risky.
 | 
			
		||||
- EEPROM has around a 100000 write cycle.  You shouldn't rewrite the
 | 
			
		||||
  firmware repeatedly and continually; that'll burn the EEPROM
 | 
			
		||||
  eventually.
 | 
			
		||||
					
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,9 @@
 | 
			
		||||
#ifndef ERGODOX_EZ_H
 | 
			
		||||
#define ERGODOX_EZ_H
 | 
			
		||||
 | 
			
		||||
#include "matrix.h"
 | 
			
		||||
#include "keymap_common.h"
 | 
			
		||||
#include "backlight.h"
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include "quantum.h"
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <avr/io.h>
 | 
			
		||||
#include "i2cmaster.h"
 | 
			
		||||
#include <util/delay.h>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -9,6 +9,7 @@
 | 
			
		||||
 | 
			
		||||
#define LSFTO M(0) // Left shift, open parens when tapped
 | 
			
		||||
#define RSFTC M(1) // Right shift, close parens when tapped
 | 
			
		||||
#define LEADER_TIMEOUT 300
 | 
			
		||||
 | 
			
		||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
			
		||||
/* Keymap 0: Basic layer
 | 
			
		||||
@@ -27,23 +28,23 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
			
		||||
 *                                        ,-------------.       ,-------------.
 | 
			
		||||
 *                                        | App  | LGui |       | Alt  |Ctrl/Esc|
 | 
			
		||||
 *                                 ,------|------|------|       |------+--------+------.
 | 
			
		||||
 *                                 |      | L1   | Home |       | PgUp |        |      |
 | 
			
		||||
 *                                 | Space| Tap/ |------|       |------| Tab/L1 |Enter |
 | 
			
		||||
 *                                 |      |Toggle| End  |       | PgDn |        |      |
 | 
			
		||||
 *                                 |      |      | Home |       | PgUp |        |      |
 | 
			
		||||
 *                                 | Space|Leader|------|       |------| Tab/L1 |Enter |
 | 
			
		||||
 *                                 |      |      | End  |       | PgDn |        |      |
 | 
			
		||||
 *                                 `--------------------'       `----------------------'
 | 
			
		||||
 */
 | 
			
		||||
// If it accepts an argument (i.e, is a function), it doesn't need KC_.
 | 
			
		||||
// Otherwise, it needs KC_*
 | 
			
		||||
[BASE] = KEYMAP(  // layer 0 : default
 | 
			
		||||
        // left hand
 | 
			
		||||
        KC_EQL,         KC_1,         KC_2,   KC_3,   KC_4,    KC_5,   KC_LEFT,
 | 
			
		||||
        KC_DELT,        KC_Q,         KC_W,   KC_E,   KC_R,    KC_T,   TG(SYMB),
 | 
			
		||||
        KC_BSPC,        KC_A,         KC_S,   KC_D,   KC_F,    KC_G,
 | 
			
		||||
        LSFTO,          CTL_T(KC_Z),  KC_X,   KC_C,   KC_V,    KC_B,   ALL_T(KC_LBRC),
 | 
			
		||||
        LT(SYMB,KC_GRV),KC_QUOT,      LALT(KC_LSFT),  KC_LEFT, KC_RGHT,
 | 
			
		||||
                                              ALT_T(KC_APP),   KC_LGUI,
 | 
			
		||||
                                                               KC_HOME,
 | 
			
		||||
                                                 KC_SPC,KC_FN1,KC_END,
 | 
			
		||||
        KC_EQL,         KC_1,         KC_2,   KC_3,   KC_4,     KC_5,   KC_LEFT,
 | 
			
		||||
        KC_DELT,        KC_Q,         KC_W,   KC_E,   KC_R,     KC_T,   TG(SYMB),
 | 
			
		||||
        KC_BSPC,        KC_A,         KC_S,   KC_D,   KC_F,     KC_G,
 | 
			
		||||
        LSFTO,          CTL_T(KC_Z),  KC_X,   KC_C,   KC_V,     KC_B,   ALL_T(KC_LBRC),
 | 
			
		||||
        LT(SYMB,KC_GRV),KC_QUOT,      LALT(KC_LSFT),  KC_LEFT,  KC_RGHT,
 | 
			
		||||
                                              ALT_T(KC_APP),    KC_LGUI,
 | 
			
		||||
                                                                KC_HOME,
 | 
			
		||||
                                                 KC_SPC,KC_LEAD,KC_END,
 | 
			
		||||
        // right hand
 | 
			
		||||
             KC_RGHT,       KC_6,KC_7,       KC_8,   KC_9,   KC_0,            KC_MINS,
 | 
			
		||||
             TG(SYMB),      KC_Y,KC_U,       KC_I,   KC_O,   KC_P,            KC_BSLS,
 | 
			
		||||
@@ -198,28 +199,50 @@ void matrix_init_user(void) {
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
LEADER_EXTERNS();
 | 
			
		||||
 | 
			
		||||
// Runs constantly in the background, in a loop.
 | 
			
		||||
void matrix_scan_user(void) {
 | 
			
		||||
 | 
			
		||||
    uint8_t layer = biton32(layer_state);
 | 
			
		||||
  uint8_t layer = biton32(layer_state);
 | 
			
		||||
 | 
			
		||||
    ergodox_board_led_off();
 | 
			
		||||
    ergodox_right_led_1_off();
 | 
			
		||||
    ergodox_right_led_2_off();
 | 
			
		||||
    ergodox_right_led_3_off();
 | 
			
		||||
    switch (layer) {
 | 
			
		||||
      // TODO: Make this relevant to the ErgoDox EZ.
 | 
			
		||||
        case 1:
 | 
			
		||||
            ergodox_right_led_1_on();
 | 
			
		||||
            break;
 | 
			
		||||
        case 2:
 | 
			
		||||
            ergodox_right_led_2_on();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            // none
 | 
			
		||||
            break;
 | 
			
		||||
  ergodox_board_led_off();
 | 
			
		||||
  ergodox_right_led_1_off();
 | 
			
		||||
  ergodox_right_led_2_off();
 | 
			
		||||
  ergodox_right_led_3_off();
 | 
			
		||||
  switch (layer) {
 | 
			
		||||
    // TODO: Make this relevant to the ErgoDox EZ.
 | 
			
		||||
    case 1:
 | 
			
		||||
      ergodox_right_led_1_on();
 | 
			
		||||
      break;
 | 
			
		||||
    case 2:
 | 
			
		||||
      ergodox_right_led_2_on();
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      // none
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  LEADER_DICTIONARY() {
 | 
			
		||||
    leading = false;
 | 
			
		||||
    leader_end();
 | 
			
		||||
 | 
			
		||||
    SEQ_ONE_KEY(KC_W) {
 | 
			
		||||
      register_code(KC_LALT);
 | 
			
		||||
      register_code(KC_F4);
 | 
			
		||||
      unregister_code(KC_F4);
 | 
			
		||||
      unregister_code(KC_LALT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SEQ_ONE_KEY(KC_O) {
 | 
			
		||||
      register_code(KC_LCTL);
 | 
			
		||||
      register_code(KC_LSFT);
 | 
			
		||||
      register_code(KC_O);
 | 
			
		||||
      unregister_code(KC_O);
 | 
			
		||||
      unregister_code(KC_LSFT);
 | 
			
		||||
      unregister_code(KC_LCTL);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,12 @@ This is my personal layout which I use to test out ideas which may or may not ma
 | 
			
		||||
 | 
			
		||||
Changelog:
 | 
			
		||||
 | 
			
		||||
## May 24, 2016:
 | 
			
		||||
 | 
			
		||||
* Implements Leader key example
 | 
			
		||||
  * Leader, W sends Alt-F4
 | 
			
		||||
  * Leader, O sends Ctrl-shift-o (a shortcut I use in FrontApp) 
 | 
			
		||||
 | 
			
		||||
## May 8, 2016:
 | 
			
		||||
 | 
			
		||||
* Makes bottom-right key send minus/underscore when tapped, L1 temporary toggle when held
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user