[Erez & Jack] Examples for advanced macro stuff
This commit is contained in:
		
							parent
							
								
									aabcfd5b4e
								
							
						
					
					
						commit
						6274a216f8
					
				
					 3 changed files with 1230 additions and 1070 deletions
				
			
		
							
								
								
									
										99
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										99
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -211,6 +211,23 @@ This will clear all keys besides the mods currently pressed.
 | 
			
		|||
 | 
			
		||||
If the user attempts to activate layer 1 AND layer 2 at the same time (for example, by hitting their respective layer keys), layer 3 will be activated. Layers 1 and 2 will _also_ be activated, for the purposes of fallbacks (so a given key will fall back from 3 to 2, to 1 -- and only then to 0).
 | 
			
		||||
 | 
			
		||||
#### Naming your macros
 | 
			
		||||
 | 
			
		||||
If you have a bunch of macros you want to refer to from your keymap, while keeping the keymap easily readable, you can just name them like so:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
#define AUD_OFF M(6)
 | 
			
		||||
#define AUD_ON M(7)
 | 
			
		||||
#define MUS_OFF M(8)
 | 
			
		||||
#define MUS_ON M(9)
 | 
			
		||||
#define VC_IN M(10)
 | 
			
		||||
#define VC_DE M(11)
 | 
			
		||||
#define PLOVER M(12)
 | 
			
		||||
#define EXT_PLV M(13)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
As was done on the [Planck default keymap](/keyboard/planck/keymaps/default/keymap.c#L33-L40)
 | 
			
		||||
 | 
			
		||||
#### Timer functionality
 | 
			
		||||
 | 
			
		||||
It's possible to start timers and read values for time-specific events - here's an example:
 | 
			
		||||
| 
						 | 
				
			
			@ -227,11 +244,91 @@ 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). 
 | 
			
		||||
 | 
			
		||||
#### Example 1: Single-key copy/paste (hold to copy, tap to paste)
 | 
			
		||||
 | 
			
		||||
With QMK, it's easy to make one key do two things, as long as one of those things is being a modifier. :) So if you want a key to act as Ctrl when held and send the letter R when tapped, that's easy: `CTL_T(KC_R)`. But what do you do when you want that key to send Ctrl-V (paste) when tapped, and Ctrl-C (copy) when held?
 | 
			
		||||
 | 
			
		||||
Here's what you do:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
static uint16_t key_timer;
 | 
			
		||||
 | 
			
		||||
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 | 
			
		||||
{
 | 
			
		||||
      switch(id) {
 | 
			
		||||
        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  );
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    return MACRO( D(LCTL), T(V), U(LCTL), END  );
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    return MACRO_NONE;
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
And then, to assign this macro to a key on your keyboard layout, you just use `M(0)` on the key you want to press for copy/paste.
 | 
			
		||||
 | 
			
		||||
#### Example 2: Space Cadet Shift (making it easy to send opening and closing parentheses)
 | 
			
		||||
 | 
			
		||||
In the [Modern Space Cadet Keyboard](http://stevelosh.com/blog/2012/10/a-modern-space-cadet/#shift-parentheses), one of cooler features is the Shift Parentheses. To quote Steve Losh:
 | 
			
		||||
 | 
			
		||||
  > When held while pressing other keys, act like Shift.
 | 
			
		||||
  > When pressed and released on their own, type an opening or closing parenthesis (left and right shift respectively).
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
static uint16_t key_timer;
 | 
			
		||||
 | 
			
		||||
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 | 
			
		||||
{
 | 
			
		||||
      switch(id) {
 | 
			
		||||
        case 0: {
 | 
			
		||||
            if (record->event.pressed) {
 | 
			
		||||
                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. 
 | 
			
		||||
                    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
 | 
			
		||||
                }
 | 
			
		||||
                unregister_code(KC_LSFT); // let's release the Shift key now.
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        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); 
 | 
			
		||||
                }
 | 
			
		||||
                unregister_code(KC_RSFT); 
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    return MACRO_NONE;
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
And then, to assign this macro to a key on your keyboard layout, you just use `M(0)` on the key you want to press for left shift/opening parens, and `M(1)` for right shift/closing parens.
 | 
			
		||||
 | 
			
		||||
## Additional keycode aliases for software-implemented layouts (Colemak, Dvorak, etc)
 | 
			
		||||
 | 
			
		||||
Everything is assuming you're in Qwerty (in software) by default, but there is built-in support for using a Colemak or Dvorak layout by including this at the top of your keymap:
 | 
			
		||||
 | 
			
		||||
   #include <keymap_extras/keymap_colemak.h>
 | 
			
		||||
   #include <keymap_colemak.h>
 | 
			
		||||
 | 
			
		||||
If you use Dvorak, use `keymap_dvorak.h` instead of `keymap_colemak.h` for this line. After including this line, you will get access to:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -7,6 +7,9 @@
 | 
			
		|||
#define SYMB 1 // symbols
 | 
			
		||||
#define MDIA 2 // media keys
 | 
			
		||||
 | 
			
		||||
#define LSFTO M(0) // Left shift, open parens when tapped
 | 
			
		||||
#define RSFTC M(1) // Right shift, close parens when tapped
 | 
			
		||||
 | 
			
		||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
			
		||||
/* Keymap 0: Basic layer
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +20,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
			
		|||
 * |--------+------+------+------+------+------|      |           |      |------+------+------+------+------+--------|
 | 
			
		||||
 * | BkSp   |   A  |   S  |   D  |   F  |   G  |------|           |------|   H  | Alt/J|   K  |   L  |; / L2| LGui/' |
 | 
			
		||||
 * |--------+------+------+------+------+------| Hyper|           | Meh  |------+------+------+------+------+--------|
 | 
			
		||||
 * | LShift |Z/Ctrl|   X  |   C  |   V  |   B  |      |           |      |   N  |   M  |   ,  |   .  |//Ctrl| RShift |
 | 
			
		||||
 * |LShift/(|Z/Ctrl|   X  |   C  |   V  |   B  |      |           |      |   N  |   M  |   ,  |   .  |//Ctrl|RShift/)|
 | 
			
		||||
 * `--------+------+------+------+------+-------------'           `-------------+------+------+------+------+--------'
 | 
			
		||||
 *   |Grv/L1|  '"  |AltShf| Left | Right|                                       |  Up  | Down |   [  |   ]  | ~L1  |
 | 
			
		||||
 *   `----------------------------------'                                       `----------------------------------'
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +39,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
			
		|||
        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,
 | 
			
		||||
        KC_LSFT,        CTL_T(KC_Z),  KC_X,   KC_C,   KC_V,    KC_B,   ALL_T(KC_NO),
 | 
			
		||||
        LSFTO,          CTL_T(KC_Z),  KC_X,   KC_C,   KC_V,    KC_B,   ALL_T(KC_NO),
 | 
			
		||||
        LT(SYMB,KC_GRV),KC_QUOT,      LALT(KC_LSFT),  KC_LEFT, KC_RGHT,
 | 
			
		||||
                                              ALT_T(KC_APP),   KC_LGUI,
 | 
			
		||||
                                                               KC_HOME,
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +48,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
 | 
			
		|||
             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,
 | 
			
		||||
                          KC_H,ALT_T(KC_J),KC_K,   KC_L,   LT(MDIA,KC_SCLN),GUI_T(KC_QUOT),
 | 
			
		||||
             MEH_T(KC_NO),KC_N,KC_M,       KC_COMM,KC_DOT, CTL_T(KC_SLSH),  KC_RSFT,
 | 
			
		||||
             MEH_T(KC_NO),KC_N,KC_M,       KC_COMM,KC_DOT, CTL_T(KC_SLSH),  RSFTC,
 | 
			
		||||
                               KC_UP,      KC_DOWN,KC_LBRC,KC_RBRC,         KC_FN1,
 | 
			
		||||
             KC_LALT,        CTL_T(KC_ESC),
 | 
			
		||||
             KC_PGUP,
 | 
			
		||||
| 
						 | 
				
			
			@ -140,17 +143,37 @@ const uint16_t PROGMEM fn_actions[] = {
 | 
			
		|||
    [1] = ACTION_LAYER_TAP_TOGGLE(SYMB)                // FN1 - Momentary Layer 1 (Symbols)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static uint16_t key_timer;
 | 
			
		||||
 | 
			
		||||
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
 | 
			
		||||
{
 | 
			
		||||
  // MACRODOWN only works in this function
 | 
			
		||||
      switch(id) {
 | 
			
		||||
        case 0:
 | 
			
		||||
        if (record->event.pressed) {
 | 
			
		||||
          register_code(KC_RSFT);
 | 
			
		||||
        } else {
 | 
			
		||||
          unregister_code(KC_RSFT);
 | 
			
		||||
        case 0: {
 | 
			
		||||
            if (record->event.pressed) {
 | 
			
		||||
                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. 
 | 
			
		||||
                    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
 | 
			
		||||
                }
 | 
			
		||||
                unregister_code(KC_LSFT); // let's release the Shift key now.
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        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); 
 | 
			
		||||
                }
 | 
			
		||||
                unregister_code(KC_RSFT); 
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    return MACRO_NONE;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -183,3 +206,5 @@ void matrix_scan_user(void) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue