# On the use of INJECTED…

**URL:** <https://community.keyboard.io/t/on-the-use-of-injected/1930>\
**Category:** Programming\
**Created:** [August 15, 2018, 6:33am UTC](https://community.keyboard.io/t/on-the-use-of-injected/1930 "2018-08-15T06:33:37Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jamadagni](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/jamadagni/32/2030_2.png) [@jamadagni](https://community.keyboard.io/u/jamadagni)\
**Post date:** [August 15, 2018, 6:33am UTC](https://community.keyboard.io/t/on-the-use-of-injected/1930/1 "2018-08-15T06:33:37Z")

</div>

Hello. In the current code, almost (but not) all calls to _handleKeyswitchEvent_ use **INJECTED** , and these are (obviously) the only locations where **INJECTED** is produced:

```auto
./Kaleidoscope/examples/AppSwitcher/Macros.cpp: handleKeyswitchEvent(mod, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED);
./Kaleidoscope/src/Kaleidoscope.cpp: handleKeyswitchEvent(Key_NoKey, 255, 255, 0);
./Kaleidoscope-Cycle/src/Kaleidoscope/Cycle.cpp: handleKeyswitchEvent(Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED | INJECTED);
./Kaleidoscope-Cycle/src/Kaleidoscope/Cycle.cpp: handleKeyswitchEvent(Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED | INJECTED);
./Kaleidoscope-Cycle/src/Kaleidoscope/Cycle.cpp: handleKeyswitchEvent(key, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED | INJECTED);
./Kaleidoscope-Cycle/src/Kaleidoscope/Cycle.cpp: handleKeyswitchEvent(key, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED | INJECTED);
./Kaleidoscope-GhostInTheFirmware/src/Kaleidoscope/GhostInTheFirmware.cpp: handleKeyswitchEvent(Key_NoKey, row, col, WAS_PRESSED);
./Kaleidoscope-GhostInTheFirmware/src/Kaleidoscope/GhostInTheFirmware.cpp: handleKeyswitchEvent(Key_NoKey, row, col, IS_PRESSED);
./Kaleidoscope-Hardware-EZ-ErgoDox/src/kaleidoscope/hardware/ErgoDox.cpp: handleKeyswitchEvent(Key_NoKey, row, col, keyState);
./Kaleidoscope-Hardware-Model01/src/Kaleidoscope-Hardware-Model01.cpp: handleKeyswitchEvent(Key_NoKey, row, startPos - col, keyState);
./Kaleidoscope-Macros/src/Kaleidoscope-Macros.cpp: handleKeyswitchEvent(key, UNKNOWN_KEYSWITCH_LOCATION, INJECTED | flags);
./Kaleidoscope-OneShot/src/Kaleidoscope/OneShot.cpp: handleKeyswitchEvent(key, row, col, key_state | INJECTED);
./Kaleidoscope-Qukeys/src/Kaleidoscope/Qukeys.cpp: handleKeyswitchEvent(keycode, row, col, IS_PRESSED);
./Kaleidoscope-Qukeys/src/Kaleidoscope/Qukeys.cpp: handleKeyswitchEvent(keycode, row, col, IS_PRESSED | WAS_PRESSED);
./Kaleidoscope-SpaceCadet/src/Kaleidoscope/SpaceCadet.cpp: handleKeyswitchEvent(map[i].input, row, col, IS_PRESSED | INJECTED);
./Kaleidoscope-SpaceCadet/src/Kaleidoscope/SpaceCadet.cpp: handleKeyswitchEvent(alternate_key, row, col, IS_PRESSED | INJECTED);
./Kaleidoscope-Syster/README.md: handleKeyswitchEvent (Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED | INJECTED);
./Kaleidoscope-Syster/README.md: handleKeyswitchEvent (Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED | INJECTED);
./Kaleidoscope-Syster/examples/Syster/Syster.ino: handleKeyswitchEvent(Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED | INJECTED);
./Kaleidoscope-Syster/examples/Syster/Syster.ino: handleKeyswitchEvent(Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED | INJECTED);
./Kaleidoscope-Syster/src/Kaleidoscope/Syster.cpp: handleKeyswitchEvent(Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, IS_PRESSED | INJECTED);
./Kaleidoscope-Syster/src/Kaleidoscope/Syster.cpp: handleKeyswitchEvent(Key_Backspace, UNKNOWN_KEYSWITCH_LOCATION, WAS_PRESSED | INJECTED);
./Kaleidoscope-TapDance/src/Kaleidoscope/TapDance.cpp: handleKeyswitchEvent(key, last_tap_dance_row_, last_tap_dance_col_, IS_PRESSED | INJECTED);
./Kaleidoscope-TapDance/src/Kaleidoscope/TapDance.cpp: handleKeyswitchEvent(key, last_tap_dance_row_, last_tap_dance_col_, IS_PRESSED | WAS_PRESSED | INJECTED);
./Kaleidoscope-TapDance/src/Kaleidoscope/TapDance.cpp: handleKeyswitchEvent(key, last_tap_dance_row_, last_tap_dance_col_, WAS_PRESSED | INJECTED);
./Kaleidoscope-TopsyTurvy/src/Kaleidoscope/TopsyTurvy.cpp: handleKeyswitchEvent(new_key, row, col, key_state | TOPSYTURVY | INJECTED);
./Kaleidoscope-TopsyTurvy/src/Kaleidoscope/TopsyTurvy.cpp: handleKeyswitchEvent(new_key, row, col, key_state | TOPSYTURVY | INJECTED);
./Kaleidoscope-Hardware-Virtual/src/Kaleidoscope-Hardware-Virtual.cpp: handleKeyswitchEvent(Key_NoKey, row, col, keyState);
./Kaleidoscope-Hardware-Virtual/src/Kaleidoscope-Hardware-Virtual.cpp: handleKeyswitchEvent(Key_NoKey, row, col, keyState);

```

… and the locations that **INJECTED** is consumed are:

```auto
./Kaleidoscope/src/key_events.cpp: } else if (keyToggledOff(keyState) && (keyState & INJECTED)) {
./Kaleidoscope/src/key_events.cpp- kaleidoscope::hid::releaseKey(mappedKey);
--
./Kaleidoscope-Cycle/src/Kaleidoscope/Cycle.cpp: if (key_state & INJECTED)
./Kaleidoscope-Cycle/src/Kaleidoscope/Cycle.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-Heatmap/src/Kaleidoscope/Heatmap.cpp: if (key_state & INJECTED)
./Kaleidoscope-Heatmap/src/Kaleidoscope/Heatmap.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-LED-AlphaSquare/src/Kaleidoscope/AlphaSquare-Effect.cpp: if (keyState & INJECTED)
./Kaleidoscope-LED-AlphaSquare/src/Kaleidoscope/AlphaSquare-Effect.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-Leader/src/Kaleidoscope/Leader.cpp: if (keyState & INJECTED)
./Kaleidoscope-Leader/src/Kaleidoscope/Leader.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-OneShot/src/Kaleidoscope/OneShot.cpp: if (keyState & INJECTED)
./Kaleidoscope-OneShot/src/Kaleidoscope/OneShot.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-Qukeys/src/Kaleidoscope/Qukeys.cpp: if (row >= ROWS || col >= COLS || (key_state & INJECTED) != 0)
./Kaleidoscope-Qukeys/src/Kaleidoscope/Qukeys.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-Syster/src/Kaleidoscope/Syster.cpp: if (keyState & INJECTED)
./Kaleidoscope-Syster/src/Kaleidoscope/Syster.cpp- return EventHandlerResult::OK;
--
./Kaleidoscope-TapDance/src/Kaleidoscope/TapDance.cpp: if (keyState & INJECTED)
./Kaleidoscope-TapDance/src/Kaleidoscope/TapDance.cpp- return EventHandlerResult::OK;

```

where mostly the result of being injected seems to be “getting ignored”.

Is this then mainly used to ignore injected keypresses when one seeks to handle only real ones? This would mean that for all practical purposes, calls to _handleKeyswitchEvent_ should use **INJECTED**?

I’d also like to know about that one case in key\_events.cpp where only the injected key is released when toggled off – why is this line needed?

---

<div class="post-metadata">

**Author:** ![algernon](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/algernon/32/4404_2.png) [@algernon](https://community.keyboard.io/u/algernon)\
**Post date:** [August 15, 2018, 8:02am UTC](https://community.keyboard.io/t/on-the-use-of-injected/1930/2 "2018-08-15T08:02:46Z")

</div>

> [@jamadagni](#):
>
> Is this then mainly used to ignore injected keypresses when one seeks to handle only real ones?

The primary purpose of `INJECTED` is to prevent infinite recursion. When you inject a key from a plugin, or macro, or anywhere, via `handleKeyswitchEvent`, that runs the key event handlers for all plugins. Including the one that injected the key. In most cases, we’d like these to just go through - but not always. This is why we use a flag instead of using `kaleidoscope::hid::pressKey()` or similar directly. If we didn’t have the flag, there would be cases where you press a key, the firmware injects another, and a plugin triggers an action for both, injecting perhaps a third key, calling `handleKeyswitchEvent` again, and that new key triggering another key, and so on 'till the end of time. This is what `INJECTED` is meant to prevent.

It may not be the best interface, mind you. It’s been at the back of my mind to figure out something better, but didn’t get around to it yet.

> [@jamadagni](#):
>
> I’d also like to know about that one case in key\_events.cpp where only the injected key is released when toggled off – why is this line needed?

Keys are normally “released” by not registering them in the next cycle (since we clear the report each cycle). With injected keys, we can have cases where we press and release the same key multiple times in the same cycle. For the release event to work, we release those keys. We can’t clear the report in these cases, so explicit release is the next best thing.

---

<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:** [August 15, 2018, 12:33pm UTC](https://community.keyboard.io/t/on-the-use-of-injected/1930/3 "2018-08-15T12:33:03Z")

</div>

> [@algernon](#):
>
> It may not be the best interface, mind you. It’s been at the back of my mind to figure out something better, but didn’t get around to it yet.

The problem with `INJECTED` being used to prevent infinite loops is that it prevents one plugin from sending an event that a different plugin should handle (if both plugins ignore `INJECTED` events). Unlike most other plugins, Qukeys was designed to send events with arbitrary `Key` objects, which could be intended for other plugins (e.g. Macros) to handle. It couldn’t work if it set the `INJECTED` flag, so it uses a different method — it sets a `static` boolean to let itself know when it’s sending an event that Qukeys itself should ignore, but which other plugins should not, and clears it after the call to `handleKeyswitchEvent()` returns.

[Kaleidoglyph has an even better system for this, which doesn’t require plugins to manage that tracking themselves, and also partially solves the problem of plugin-order dependence, but that’s slightly off-topic.]

---

<div class="post-metadata">

**Author:** ![jamadagni](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/jamadagni/32/2030_2.png) [@jamadagni](https://community.keyboard.io/u/jamadagni)\
**Post date:** [August 15, 2018, 1:07pm UTC](https://community.keyboard.io/t/on-the-use-of-injected/1930/4 "2018-08-15T13:07:02Z")

</div>

> [@algernon](#):
>
> The primary purpose of `INJECTED` is to prevent infinite recursion. When you inject a key from a plugin, or macro, or anywhere, via `handleKeyswitchEvent` , that runs the key event handlers for all plugins. Including the one that injected the key. In most cases, we’d like these to just go through - but not always.

So in [the thread about Ctrl+wheel for zooming](https://community.keyboard.io/t/ctrl-scroll-for-zoom-not-working-from-keyboard-but-working-from-mouse/1649/2) when you recommended a call to `handleKeyswitchEvent` but _without_ `INJECTED` that was intentional, so that MouseKeys should handle it?

I mean, is it recommended to:

1. normally use `INJECTED` in calls to `handleKeyswitchEvent` and omit it only in the case where one specifically wants other plugins to not ignore it as @merlin kindly explained for the Qukeys exception,

or

1. you normally don’t need to bother with `INJECTED` and you need to use it only in the case when you specifically need it to be ignored?

And on the side of plugins, likewise should they normally contain an `if` check to ignore injected keys or only if there will be a problem if they handle them?

(I hope I’m being clear?)

---

<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:** [August 15, 2018, 4:00pm UTC](https://community.keyboard.io/t/on-the-use-of-injected/1930/5 "2018-08-15T16:00:31Z")

</div>

Only plugins that call `handleKeyswitchEvent()` themselves (directly or indirectly) need to do something to prevent unbounded recursion (from those events). The simplest way to do so is to ignore events generated by the plugin, and the simplest way to accomplish that is to only generate events with the `INJECTED` flag set, and ignore any events with that flag set.

So, if a plugin never calls `handleKeyswitchEvent()` from its event handler, it should not be necessary to check for and ignore `INJECTED` events.
