# Macro that respects one-shot modifier keys

**URL:** <https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163>\
**Category:** Help and Getting Started\
**Created:** [January 23, 2023, 9:14pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163 "2023-01-23T21:14:51Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![hupfdule](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/hupfdule/32/4046_2.png) [@hupfdule](https://community.keyboard.io/u/hupfdule)\
**Post date:** [January 23, 2023, 9:14pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/1 "2023-01-23T21:14:51Z")

</div>

Hi,

I have a macro defined to enter the two characters “qu”:

```auto
/**
 * Press the Q key and directly afterwards the U key as this is the most
 * used combination in written texts.
 */
static const macro_t *quMacro(KeyEvent &event) {
  if (keyToggledOn(event.state)) {
    return MACRO(T(DE_Q),
                 T(DE_U)
           );
  }
  return MACRO_NONE;
}

```

If I hit the Macro key it enters “qu” as expected. If I am holding shift while hitting the Macro key it enters “QU” as I would expect.

The problem arises when I use a OneShot shift before hitting the Macro key. It enters “QU”, but I would like it to produce “Qu” instead (the OneShot modifier is only applied to the first key in the Macro.

Is that possible with the Macros plugin?

Interestingly if I define that Macro as a DynamicMacro in Chrysalis it works like I want it to! But I did not find a way to configure a DynamicMacro within the .ino file. Is that possible somehow?

---

<div class="post-metadata">

**Author:** ![merlin](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/merlin/32/3416_2.png) [@merlin](https://community.keyboard.io/u/merlin)\
**Post date:** [January 24, 2023, 2:58pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/2 "2023-01-24T14:58:55Z")

</div>

I’m surprised that DynamicMacros is exhibiting that behaviour, since its code is nearly identical to Macros (for playback). Keys in the one-shot state should be (virtually) released after the key-toggled-on event for the next keypress is finished processing, so the one-shot `shift` in your example ought to stay pressed until either macro is finished playing.

You can get your Macros macro to behave the way you want it to, however: take a look at the [`ShiftBlocker`](https://github.com/keyboardio/Kaleidoscope/blob/master/examples/Features/ShiftBlocker/ShiftBlocker.ino) example sketch to see how.

---

<div class="post-metadata">

**Author:** ![hupfdule](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/hupfdule/32/4046_2.png) [@hupfdule](https://community.keyboard.io/u/hupfdule)\
**Post date:** [January 24, 2023, 8:34pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/3 "2023-01-24T20:34:43Z")

</div>

I am sorry, but I need a bit more help here.  
Do you suggest that I actually use that ShiftBlocker and ignore Shift for the „U“ key?

If that is the case, would this be the correct code then?

> [@](#):
>
> ```auto
> static const macro_t *quMacro(KeyEvent &event) {
> if (keyToggledOn(event.state)) {
> Macros.tap(DE_Q);
> ShiftBlocker.enable();
> Macros.tap(DE_U);
> ShiftBlocker.disable();
> }
> return MACRO_NONE;
> }
> 
> ```

Wouldn’t that mean that I am unable to produce „QU“ by holding the shift key then?

What is this line in your example for?

```auto
       // Change the Macros key into a plain `E` key before its press event is
      // processed.
      event.key = Key_E;
```

And what is the actual difference of returning `MACRO(T(DE_U))` as in my first example and just calling `Macros.tap(DE_U)` and returning MACRO\_NONE as in the ShiftBlocker example?

---

<div class="post-metadata">

**Author:** ![merlin](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/merlin/32/3416_2.png) [@merlin](https://community.keyboard.io/u/merlin)\
**Post date:** [January 25, 2023, 5:38pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/4 "2023-01-25T17:38:15Z")

</div>

There’s no way for your macro to distinguish between a one-shot `shift` and a `shift` key that is physically being held. You could, however, modify the `ShiftBlocker` example to ignore (i.e. not block) a `Key_RightShift` (for example), and have your OneShot key use left shift instead.

> [@hupfdule](#):
>
> What is this line in your example for?

That line (`event.key = Key_E` is similar to `Macros.tap(Key_E)`, but instead of using the virtual Macros keys, it simply changes the Macros key that was pressed into that key, and lets its press event finish normally. The main user-visible difference is that if you press and hold the key, it’s possible to get repeating characters.

> [@hupfdule](#):
>
> And what is the actual difference of returning `MACRO(T(DE_U))` as in my first example and just calling `Macros.tap(DE_U)` and returning MACRO\_NONE as in the ShiftBlocker example?

Not a lot. Using the `MACRO()` preprocessor macro calls `Macros.play()`, which calls things like `Macros.tap()` (depending on the arguments to `MACRO()`). The latter is more flexible, because it allows you to make other function calls (e.g. `::ShiftBlocker.enable()`) in between the usual `MACRO()` steps.

---

<div class="post-metadata">

**Author:** ![hupfdule](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/hupfdule/32/4046_2.png) [@hupfdule](https://community.keyboard.io/u/hupfdule)\
**Post date:** [January 25, 2023, 8:33pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/5 "2023-01-25T20:33:25Z")

</div>

> [@merlin](#):
>
> There’s no way for your macro to distinguish between a one-shot `shift` and a `shift` key that is physically being held. You could, however, modify the `ShiftBlocker` example to ignore (i.e. not block) a `Key_RightShift` (for example), and have your OneShot key use left shift instead.

That’s rather unfortunate. It would be better if it could (optionally) behave like the DynamicMacros plugin which is much more appropriate for my use case.

The ShiftBlocker seems like a lot of work that (even in your proposal of differentiating between left and right shift) will not cover all corner cases. The DynamicMacros plugin is more flexible in that regard.

---

<div class="post-metadata">

**Author:** ![merlin](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/merlin/32/3416_2.png) [@merlin](https://community.keyboard.io/u/merlin)\
**Post date:** [January 25, 2023, 8:46pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/6 "2023-01-25T20:46:02Z")

</div>

> [@hupfdule](#):
>
> That’s rather unfortunate. It would be better if it could (optionally) behave like the DynamicMacros plugin which is much more appropriate for my use case.

Honestly, I’m not sure how DynamicMacros could be doing that; it’s definitely a bug.

> [@hupfdule](#):
>
> The ShiftBlocker seems like a lot of work that (even in your proposal of differentiating between left and right shift) will not cover all corner cases.

Since your intent is to use it for one very specific case, it doesn’t need to. Instead of (or in addition to) testing the `event.key` value, you could program it to check `event.addr` to make sure that it only acts on keys that you want it to. This is the reason that it’s an example of a custom plugin, rather than an official core plugin.

There is an alternative approach. You could make a custom plugin that removes the `INJECTED` bit from subsequent events when a Macros key toggles on in its `onKeyEvent()` handler (which would need to come before OneShot in `KALEIDOSCOPE_INIT_PLUGINS()`, and turn that off with a second handler that uses `afterEachCycle()`.

---

<div class="post-metadata">

**Author:** ![hupfdule](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/hupfdule/32/4046_2.png) [@hupfdule](https://community.keyboard.io/u/hupfdule)\
**Post date:** [January 25, 2023, 9:31pm UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/7 "2023-01-25T21:31:32Z")

</div>

> [@merlin](#):
>
> Honestly, I’m not sure how DynamicMacros could be doing that; it’s definitely a bug.

I don’t see it as such. It might be a bug in the sense that it wasn’t the _intended_ behavior, but it is the behavior _I_ want.

Both plugins behave the same when used without a modifier as well as when a modifier key is held. They only differ in their handling of OneShot modifiers. While the Macros plugin applies the modifier to the whole macro, the DynamicMacros plugin lets the first pressed key swallow the modifier (as would be the case if the keys in the macro were pressed manually).  
Either variant may be desirable, depending on the use case. I my case it is the second one.  
Therefore I think it would be best if this was somehow configurable for a given macro.

> [@merlin](#):
>
> Since your intent is to use it for one very specific case, it doesn’t need to. Instead of (or in addition to) testing the `event.key` value, you could program it to check `event.addr` to make sure that it only acts on keys that you want it to. This is the reason that it’s an example of a custom plugin, rather than an official core plugin.

My use case is actually very simple, but not _that_ specific: Apply the modifiers as if I would press the keys manually. That would mean that the OneShot modifier is only applied to the first pressed key in the macro. I don’t want to do this for a specific key. I also don’t want to reduce my choices of which shift key I might use.  
Maybe I will want another macro in the future, e. g. for writing the word “table”. I want to be able to write it in all lowercase (by not applying a shift modifier), write it in all uppercase (by either holding shift or locking a OneShot shift modifier) and only capitalize the first character (by pressing a OneShot shift modifier before pressing the macro key).

Trying to handle specific keys with additional plugins is not only very complicated (at least for someone like me that has no experience in that field), but is actually less flexible.

> [@merlin](#):
>
> There is an alternative approach. You could make a custom plugin that removes the `INJECTED` bit from subsequent events when a Macros key toggles on in its `onKeyEvent()` handler (which would need to come before OneShot in `KALEIDOSCOPE_INIT_PLUGINS()`, and turn that off with a second handler that uses `afterEachCycle()`.

Unfortunately you lost me here. I am more of a user than a developer here. I don’t know anything about writing Kaleisoscope plugins and in fact didn’t even understand what I would have to do here nor what would be the actual outcome of it.

---

<div class="post-metadata">

**Author:** ![merlin](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/merlin/32/3416_2.png) [@merlin](https://community.keyboard.io/u/merlin)\
**Post date:** [January 27, 2023, 2:10am UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/8 "2023-01-27T02:10:32Z")

</div>

> [@hupfdule](#):
>
> I don’t see it as such. It might be a bug in the sense that it wasn’t the _intended_ behavior, but it is the behavior _I_ want.

The definition of a bug is that its behaviour is not as designed. I’m telling you that it’s a bug as a warning that it is likely to get fixed, so that it does work as designed in the future. The one-shot key is designed to stay in effect until the event that triggers its release is done being processed by Kaleidoscope, so if it was behaving as designed, it would not be (virtually) released until after the macro had finished playing.

That’s not the behaviour that you want, and that’s fair. I encourage you to submit an issue to the Kaleidoscope GitHub repository requesting the change, so that it can be discussed by other interested parties. Unsurprisingly, I disagree with you about what it _should_ do (I’m the one who most recently redesigned both the Macros and OneShot plugins), but this is a matter of what is most sensible, not a matter of “right” and “wrong”. Macros can be used for other purposes than just typing, so it really isn’t that clear whether OneShot should apply to _keys_ or _characters_. One downside to the latter is that is substantially complicates the code.

I have now looked into the cause, and can reproduce the bug (or would-be feature, if you will) in the interaction between DynamicMacros and OneShot. While I still haven’t found the cause, I can tell that OneShot is releasing the one-shot modifier key, curiously, after the _release_ event of the first virtual key in the macro sequence. If OneShot was simply treating this as a “normal” key tap, it would release the modifier after the _press_ event, not the release. It’s clear that this bug in plugin-order dependent (there’s no actual salient difference between the two Macros plugins; whether or not it happens depends on whether OneShot comes before or after them in `KALEIDOSCOPE_INIT_PLUGINS()`). For right now, you can just move OneShot after Macros, and you’ll get what you’re looking for. However, I do have a fix for the bug, and once I’ve determined the cause, I’ll be submitting it as a PR, which will cause it to stop working the way you want.

However, it has occurred to me that you do not need to employ a custom ShiftBlocker plugin to get what you want. While OneShot doesn’t know about Macros, or _vice versa_, your sketch knows about both, so you can write your macros like this:

```c++
const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
  if (keyToggledOn(event.state)) {
    switch (macro_id) {
    case MACRO_QU:
      Macros.tap(Key_Q);
      OneShot.cancel();
      event.key = Key_U;
      return MACRO_NONE;
    case MACRO_TABLE:
      Macros.tap(Key_T);
      OneShot.cancel();
      return MACRO(T(A), T(B), T(L), T(E));
    default:
      break;
    }
  }
  return MACRO_NONE;
}

```

This should do exactly what you want, even after the bug gets fixed, and should have been the first thing I suggested.

---

<div class="post-metadata">

**Author:** ![hupfdule](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/hupfdule/32/4046_2.png) [@hupfdule](https://community.keyboard.io/u/hupfdule)\
**Post date:** [January 30, 2023, 11:10am UTC](https://community.keyboard.io/t/macro-that-respects-one-shot-modifier-keys/6163/9 "2023-01-30T11:10:30Z")

</div>

> [@merlin](#):
>
> I encourage you to submit an issue to the Kaleidoscope GitHub repository requesting the change, so that it can be discussed by other interested parties.

I was thinking about that, but the macro definition you described below seems to be good enough to be a general purpose solution to that problem.

To be able to cancel the OneShot modifier inside a macro should solve all these problems. Therefore I think no it would be ok if the macros are always handled as a single key press as it possible with this workaround to get the behaviour I desire here.

Also I hope your example here in this thread is enough for other people searching for the same behaviour to find it.

Many thanks for your help!
