Real-world Macros

I’m working on a major redesign of the Macros plugin (among others) that should make it more straightforward and accessible to use, but which has some potential backwards-incompatibility. I’d like to collect examples of people’s current Macros to better anticipate the problems that might arise, and to help write a guide to upgrading the code. If you’ve got any Macros function(s) that you’re willing to share, please let me know. Even a general description of non-obvious use cases would be helpful.

Thanks in advance!

1 Like

Hello @merlin

I use both Macros.type and the regular MACRO with examples below.

case FULLSCREEN: if (keyToggledOn(key_state)) { return MACRO(D(LeftGui),D(LeftControl),T(F),U(LeftControl),U(LeftGui));}; break ; // fullscreen osx

case USR: if (keyToggledOn(key_state)) { return Macros.type(PSTR(“DUMMY”));} break;

1 Like

Just so you know, you don’t need a macro to do this; merely putting LCTRL(LGUI(Key_F)) in your keymap gives you the same result.

I was sure I did this for a reason as I am aware of the other way : Macro String being UpperCased Unintentionally (Arduino Boards Update)

I think the issue was resolved long ago, but I also remember having some timing issues in the past. I found that when using macros for shortcuts this way was more consistent. From memory it was for my tmux shortcuts ( I use backtick over the default Ctrl-B ).

Why do I need a macro to LayerActivate() or as a Key_LEDEffecNext key? I’m just complicated I guess. No really it’s because there just aren’t enough keys and I’ve got so many layers too.

 case rtSngAnQ:
    return MACRODOWN(
      D(LeftShift), T(Comma), U(LeftShift));
  break;
  

  }
  return MACRO_NONE;
}

static void leaderLED(uint8_t seq_index) {
  Macros.play(MACRO(
    Dr(Key_LEDEffectNext)));
}

static void leaderPUNCTU(uint8_t seq_index) {
  Layer.activate(PUNCTU);
}

static void leaderSID(uint8_t seq_index) {
  Macros.type(PSTR("yu7816dd"));
}

…but substituting a Macros key for Key_LEDEffectNext or LockLayer(PUNCTU) or LSHIFT(Key_Comma) doesn’t actually get you any more keys on each layer, does it?

Lol I’m actually using leader sequences for those two particular things—they don’t have M(macro name) calls in the keymap. The layer.activate sequence is something I put in my sketch over a year ago to use for testing the punctuation layer because I didn’t want to try to find a place for a LockLayer key when I normally only use shiftToLayer for the punctuation layer. I just rediscovered and removed it today after posting that comment here. And as for LedEffectNext I really don’t have any place in the keymap to put it but I do want to be able to do cycle through the led effects (to show off to other people) so the leader sequence idea made sense to me.

I pasted that block in because it had every sort of thing I use macros for in a very short block.

I have a leader sequence btw that:

  1. switches my Macintosh input source to Unicode hex Iinput
  2. Switches to a Unicode layer that contains a bunch of unicode symbol macros plus a hexadecimal keypad for other unicode symbols.
    and a key on that layer that has a macro that switches back to my normal US international input source and sends me back to the layer I came from.

It is that thing, the Unicode entry layer, that I am using Syster to replace.

I’m confused. You’re saying that the code block you posted was mostly not Macros code, and was therefore off topic?

Is it? When a leader sequence uses something like Macros.play(), Macros.type(), MACRO(), for example, isn’t that Macros code? I probably only assumed those things were from the Macros plug in because they have “macro” in them. I have obviously proven the adage “when I assume I make an ass out of u and me.”

I was trying to help by providing examples of my current macros, and I didn’t mean to do anything wrong. I really did think those things were macros. I am sorry for my stupidity. I am not a programmer and don’t know all the terminology and rules I just like the Model and like to use macros and macro like things to make it do things for me.

Man I’m really sorry. I’m not really stupid I’m just naive about some things and don’t know all the things that you know.

merlin:

I think I can redeem myself and thereby be totally responsive to your request. I reread the Macros section in the users manual to make sure I’m being on topic. I do use the macroAction(macroIndex, keyState) method a lot, and the things that I do are really just the same sorts of things exactly that were in the Leader examples I posted, but within the macroAction method and activated from the keymap.

In addition, a lot of my macros use Unicode.type()
Also I use both MACRO() and MACRODOWN() a lot and I do need MACRO(0). I use delays too!

Again, I apologize for the off-topic aspects and bringing in other plugins unnecessarily.

Oh, no! Don’t feel that way. I was trying to ask for code that is triggered by the Macros plugin processing Macros Key events, but I guess I wasn’t specific enough. I’m the one who assumed that “Macros functions” would only be interpreted in one way. I didn’t see the start of a macroAction() function in your code snippet, and, wanting to understand what your code was about, I worded my clarification question poorly.

You should not, in my opinion, consider yourself “not a programmer” if you’ve tinkered with a Kaleidoscope sketch and made it do what you intended.

1 Like

As a head’s up: when PR 1024 gets merged, MACRODOWN() will be deprecated. Macros (i.e. macroAction()) will generally be called only when a Macros key toggle on or off, not every cycle while held, making MACRODOWN() much less relevant.

Thank you. Here is my macroAction() function. It’s astoundingly long, I think. Also I use preprocessor code and a quick search and replace to deal with which Keyboard I’m flashing. (I’m using Kaleidoscope with the same basic sketch with both my Keyboardios and my ErgoDox). That “one sketch for all” concept is why I’m using Macros when they wouldn’t seem to be necessary.

const macro_t *macroAction(uint8_t macroIndex, uint8_t keyState) {
  switch (macroIndex) {

  case cents: 
    return MACRODOWN(
      T(C), T(T), T(Period));
  break;
  
  case copyright: 
    return MACRODOWN(
      D(LeftShift), T(9), T(C), T(0), U(LeftShift));
  break;
  
  case doubleComma:
    return MACRODOWN(
      D(Comma), D(Comma));
  break;
  
  case doubleDash: 
    return MACRODOWN(
      T(Minus), T(Minus));
  break;
  
  case lDAQ: 
    return MACRODOWN(
      D(LeftShift), T(Period), T(Period), U(LeftShift));
  break;
  
  case plusminus: 
    return MACRODOWN(
      D(LeftShift), T(Equals), U(LeftShift), T(Slash), T(Minus));
  break;
  
  case pounds: 
    return MACRODOWN(
      T(L), T(B), T(Period));
  break;
  
  case rDAQ: 
    return MACRODOWN(
      D(LeftShift), T(Comma), T(Comma), U(LeftShift));
  break;
  
  case Registered: 
    return MACRODOWN(
      D(LeftShift), T(9), T(R), T(0), U(LeftShift));
  break;
  
  case triplePeriod: 
    return MACRODOWN(
      T(Period), T(Period), T(Period));
  break;
  
  
#if INTERNATIONAL_KEYBOARD > 0
  case apostroUSN: 
    return MACRODOWN(
      T(Quote), T(Spacebar));
  break;

  case incUSN: 
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(Spacebar));
  break;

  case libra: 
    return MACRODOWN(
      D(RightAlt), D(LeftShift), T(4), U(LeftShift), T(Spacebar), U(RightAlt));
  break;

  case yen: 
    return MACRODOWN(
      D(RightAlt), T(Minus), D(RightAlt));
  break;
  
  case yDiaUSN: 
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(Y));
  break;
  
#else
  case apostroUSN:
    return MACRODOWN(
      T(Quote));
  break;

  case incUSN:
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift));
  break;

  case libra: 
    return MACRODOWN(
      D(RightAlt), D(LeftShift), T(4), U(LeftShift), T(Spacebar), U(RightAlt));
  break;

  case yen:
    return MACRODOWN(
      T(Y), T(E), T(N));
  break;
  
  case yDiaUSN: 
    return MACRODOWN(
      T(I), T(J));
  break;
  
  
#endif
  
#if INTERNATIONAL_KEYBOARD > 3
  case aDiaUSN: 
    return MACRODOWN(
      Dr(Key_RightAlt), T(Q), Ur(Key_RightAlt));
  break;

  case agMCN:
    return MACRODOWN(
      Dr(Key_RightAlt), T(G), Ur(Key_RightAlt));
  break;
  
  case backtick:
    return MACRODOWN(
      Dr(Key_RightAlt), D(Backtick), Ur(Key_RightAlt));
  break;
  
  case caUSN: 
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(6), U(LeftShift), Ur(Key_RightAlt));
  break;

  case e_diares:
    return MACRODOWN(
      Dr(Key_RightAlt), D(V), Ur(Key_RightAlt));
  break;
  
  case eshMCN: 
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(Slash), U(LeftShift), Ur(Key_RightAlt), T(S));
  break;
  
  case ezhMCN:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(7), U(LeftShift), Ur(Key_RightAlt), T(Z));
  break;
  
  case gBrev_MN: 
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(Backslash), U(LeftShift), Ur(Key_RightAlt), T(G));
  break;
  
  case lowDQuot:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), D(B), U(LeftShift), Ur(Key_RightAlt));
  break;
  
  case IPAepsilon: 
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(7), U(LeftShift), Ur(Key_RightAlt), T(3));
  break;

  case IPAturnedC:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(7), U(LeftShift), Ur(Key_RightAlt), T(C));
  break;

  case lange_ij:
    return MACRODOWN(
      Dr(Key_RightAlt), D(J), Ur(Key_RightAlt));
  break;
  
  case leftHighDDQu:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(0), U(LeftShift), Ur(Key_RightAlt));
  break;
  
  case lowQuote:
    return MACRODOWN(
      Dr(Key_RightAlt), D(B), Ur(Key_RightAlt));
  break;
  
  case mid_dot:
    return MACRODOWN(
      Dr(Key_RightAlt), D(X), Ur(Key_RightAlt));
  break;
  
  case not_sign:
    return MACRODOWN(
      Dr(Key_RightAlt), D(Backslash), Ur(Key_RightAlt));
  break;
  
  case oe_ligat:
    return MACRODOWN(
      Dr(Key_RightAlt), D(K), Ur(Key_RightAlt));
  break;
  
  case rightHighDoubQu:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(9), U(LeftShift), Ur(Key_RightAlt));
  break;
  
  case sCar_MN:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(Period), U(LeftShift), Ur(Key_RightAlt), T(S));
  break;
  
  case schwaMCN:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(7), U(LeftShift), Ur(Key_RightAlt), T(E));
  break;
  
  case smUDOmMCN:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(7), U(LeftShift), Ur(Key_RightAlt), T(U));
  break;
  
  case softHyph:
    return MACRODOWN(
      Dr(Key_RightAlt), D(7), Ur(Key_RightAlt));
  break;
  
  case yogh_MN:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(7), U(LeftShift), Ur(Key_RightAlt), T(Y));
  break;
  
  case zCar_MN:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(Period), U(LeftShift), Ur(Key_RightAlt), T(Z));
  break;

  
#elif INTERNATIONAL_KEYBOARD > 0
  case aDiaUSN: 
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(A));
  break;

  case backtick:
    return MACRODOWN(
      D(Backtick), T(Spacebar));
  break;
  
  case caUSN: 
    return MACRODOWN(
      D(LeftShift), T(6), U(LeftShift), T(Spacebar));
  break;

  case e_diares:
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(E));
  break;
  
  case gBrev_MN: 
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(Y));
  break;
  
  case lowDQuot:
    return MACRODOWN(
      D(Comma), D(Comma));
  break;
  
  case lange_ij: 
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(Y));
  break;
  
  case leftHighDDQu:
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), U(Space));
  break;
  
  case lowQuote:
    return MACRODOWN(
      D(Comma));
  break;
  
  case oe_ligat:
    return MACRODOWN(
      D(O), D(E));
  break;
  
  case mid_dot:
    return MACRODOWN(
      T(Period));
  break;
  
  case not_sign:
    return MACRODOWN(
      Dr(Key_RightAlt), D(1), Ur(Key_RightAlt));
  break;
  
  case rightHighDoubQu:
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift), T(Space));
  break;
  
  case sCar_MN:
    return MACRODOWN(
      T(S), T(H));
  break;
  
  case softHyph:
    return MACRODOWN(
      D(Minus));
  break;
  
  case yogh_MN:
    return MACRODOWN(
      T(G), T(H));
  break;
  
  case zCar_MN:
    return MACRODOWN(
      T(Z), T(H));
  break;

  
#else
  case backtick:
    return MACRODOWN(
      D(Backtick));
  break;
  
  case caUSN: 
    return MACRODOWN(
      D(LeftShift), T(6), U(LeftShift));
  break;

  case e_diares:
    return MACRODOWN(
      T(E));
  break;
  
  case gBrev_MN: 
    return MACRODOWN(
      T(Y));
  break;
  
  case lowDQuot:
    return MACRODOWN(
      D(Comma), D(Comma));
  break;
  
  case lange_ij:
    return MACRODOWN(
      D(I), D(J));
  break;
  
  case leftHighDDQu:
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift));
  break;
  
  case lowQuote:
    return MACRODOWN(
      D(Comma));
  break;
  
  case oe_ligat:
    return MACRODOWN(
      D(O), D(E));
  break;
  
  case mid_dot:
    return MACRODOWN(
      T(Period));
  break;
  
  case rightHighDoubQu:
    return MACRODOWN(
      D(LeftShift), T(Quote), U(LeftShift));
  break;
  
  case sCar_MN:
    return MACRODOWN(
      T(S), T(H));
  break;
  
  case softHyph:
    return MACRODOWN(
      D(Minus));
  break;
  
  case yogh_MN:
    return MACRODOWN(
      T(G), T(H));
  break;
  
  case zCar_MN:
    return MACRODOWN(
      T(Z), T(H));
  break;

  
#endif
  
#if WITH_UNICODE > 0
  case a0250:
    unicode(0x0250, keyState);
  break;
  
  case asp02b0:
    unicode(0x02b0, keyState);
  break;  
  
  case beta03b2:
    unicode(0x03b2, keyState);
  break;
  
  case blank_UN:
    unicode(0x2205, keyState);
  break;
  
  case brokenBar:
    unicode(0x00a6, keyState);
  break;
  
  case dotlessI0131:
    unicode(0x0131, keyState);
  break;
  
  case em_DashUN:
    unicode(0x2014, keyState);     
  break;
  
  case en_DashUN:
    unicode(0x2013, keyState);
  break;
  
  case enye272:
    unicode(0x0272, keyState);
  break;
  
  case horEllipse:
    unicode(0x2026, keyState);
  break;
  
  case IPAg263:
    unicode(0x263, keyState);
  break;
  
  case IPAr0279:
    unicode(0x279, keyState);
  break;
  
  case longS_UN:
    unicode(0x017f, keyState);
  break;
  
  case longum02d0:
    unicode(0x02d0, keyState);
  break;
  
  case lfSngAnQ:
    unicode(0x203a, keyState);
  break;
  
  case plusminusUN:
    unicode(0x00B1, keyState);
  break;
  
  case rtSngAnQ:
    unicode(0x2039, keyState);
  break;
  
  case smCapI026a:
    unicode(0x026a, keyState);
  break;
  
  case startUnicode:
    return MACRODOWN(
      D(LeftAlt), D(LeftGui), T(Spacebar), U(LeftGui), U(LeftAlt), Dr(Key_RightAlt));
  break;

  case stopUnicode:
    return MACRODOWN(
      Ur(Key_RightAlt), D(LeftAlt), D(LeftGui), T(Spacebar), U(LeftGui), U(LeftAlt));
  break;

  case theta3B8: 
    unicode(0x03b8, keyState);
  break;


#elif INTERNATIONAL_KEYBOARD > 0
  case blank_UN:
    return MACRODOWN(
      Dr(Key_RightAlt), T(4), Ur(Key_RightAlt));
  break;
  
  case brokenBar:
    return MACRODOWN(
      Dr(Key_RightAlt), D(LeftShift), T(Backslash), U(LeftShift), Ur(Key_RightAlt));
  break;
  
  case em_DashUN: 
    return MACRODOWN(
      T(Minus), T(Minus));
  break;
  
  case en_DashUN: 
    return MACRODOWN(
      T(Minus), T(Minus));
  break;
  
  case horEllipse: 
    return MACRODOWN(
      T(Period), T(Period), T(Period));
  break;
  
  case lfSngAnQ:
    return MACRODOWN(
      D(LeftShift), T(Period), U(LeftShift));
  break;
  
  case longS_UN: 
    return MACRODOWN(
      T(S), T(S));
  break;
  
  case plusminusUN: 
    return MACRODOWN(
      D(LeftShift), T(Equals), U(LeftShift), T(Slash), T(Minus));
  break;
  
  case rtSngAnQ:
    return MACRODOWN(
      D(LeftShift), T(Comma), U(LeftShift));
  break;
  
  
#else
  case blank_UN:
    return MACRODOWN(
      D(LeftShift), T(X), U(LeftShift));
  break;
  
  case brokenBar:
    return MACRODOWN(
      D(LeftShift), T(Backslash), U(LeftShift));
  break;
  
  case em_DashUN: 
    return MACRODOWN(
      T(Minus), T(Minus));
  break;
  
  case en_DashUN: 
    return MACRODOWN(
      T(Minus), T(Minus));
  break;
  
  case horEllipse: 
    return MACRODOWN(
      T(Period), T(Period), T(Period));
  break;
  
  case lfSngAnQ:
    return MACRODOWN(
      D(LeftShift), T(Period), U(LeftShift));
  break;
  
  case longS_UN: 
    return MACRODOWN(
      T(S), T(S));
  break;
  
  case plusminusUN: 
    return MACRODOWN(
      D(LeftShift), T(Equals), U(LeftShift), T(Slash), T(Minus));
  break;
  
  case rtSngAnQ:
    return MACRODOWN(
      D(LeftShift), T(Comma), U(LeftShift));
  break;
  
#endif
  

  }
  return MACRO_NONE;
}

It’s not at all clear to me what you get out of using a keymap entry of M(yen) instead of RALT(Key_Minus), but as long as you’re not running out of PROGMEM space and you don’t care about key repeat, there’s nothing wrong with doing it. You should be able to do just one check for key state at the top, and replace all the instances of MACRODOWN() with MACRO() in order to make your macroAction() work with the forthcoming version of Macros.

I have one additional efficiency note for you. Many of your macros have a common pattern that can be abbreviated—modifier down, symbol key tap, modifier up. Here’s one example:

The first three items in the sequence can be condensed to just one:

  case plusminus: 
    return MACRODOWN(
      Tr(LSHIFT(Key_Equals)), T(Slash), T(Minus));
  break;

That change reduces the size of the Macros command sequence by six bytes of PROGMEM for each such occurrence.

You’d get a much bigger efficiency gain by using RALT(Key_Minus) directly in the keymap instead of M(yen) coupled with this:

  case yen: 
    return MACRODOWN(
      D(RightAlt), T(Minus), D(RightAlt));
  break;

That’s at least 12 bytes of program memory extra (I’m pretty sure it’s more, but I don’t know by how much. You can save six of those bytes by using a more efficient macro, but it’s both more functional and space and time efficient to put the key value you want directly in the keymap.

1 Like

Oh yeah! Thank you. I’m using that method already for a Key definition. I don’t know why I didn’t think of using it more widely. I glad I mentioned it and I’m grateful for your help.

1 Like

You don’t need to use the Macros plugin to accomplish this (in most cases), though. If I understand correctly, you have different configurations for different operating systems. You could use the preprocessor to define Key_Yen, for example, and based on the OS you’re compiling for, it could be defined as RALT(Key_Minus) or M(yen)—only using Macros keys for the output symbols that actually require more than a simple keypress.

1 Like