# WIP: AccentLayerPlugin, accented char build onto Unicode plugin

**URL:** <https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248>\
**Category:** Programming\
**Created:** [March 6, 2023, 10:33pm UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248 "2023-03-06T22:33:32Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![dlyr](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/dlyr/32/4667_2.png) [@dlyr](https://community.keyboard.io/u/dlyr)\
**Post date:** [March 6, 2023, 10:33pm UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/1 "2023-03-06T22:33:32Z")

</div>

Hi,

## TL;DR;

I’m seeking feedback on my first plugin code before making it better for sharing, see code sample below

## Long Story

I own a model 100 since a few months, and I discover the world of split keyboards and layer.

Since I type both in english and french (and c++ and other programming languages), I need to have efficient way to type accented characters.

Firstly I setted up macro for compose key combination, within Chrysalis, but while the key to macro id mapping is exported, the macro content is not (I have one kbd at home, another at work and I want to share the configuration).

So I think the solution is to setup my “accent layer” on the firmware side, which I’m currently doing.

To this end I have done a few tests, and I’m writing here to have feedback.

I have developped a plugin that leverage Unicode plugin to type accent char (which seems to be portable accros OSes, not tested yet).

## Sample code

First I define key codes

```auto
constexpr Key Key_A_CIRC{kaleidoscope::ranges::SAFE_START};
constexpr Key Key_A_ACUTE{Key_A_CIRC.getRaw() + 1};
// ...

```

Then I created a table key code to unicode char

```auto

struct KeyToUnicode {
  Key key;
  uint32_t unicode;
};

static const KeyToUnicode keyToUnicodeTable[] = {
  {Key_A_CIRC, U'â'},
  {Key_A_ACUTE, U'á'},
// ...

```

Finally I setted up the plugin as (temporary name, “Weur” inspired by [non-English on QWERTY](https://altgr-weur.eu/altgr-intl.html))

```auto

class WeurPlugin : public Plugin {
 public:
  static constexpr uint32_t upperOffset = 0x00E0 - 0x00C0;

  bool isShiftKeyHeld(Key &which) {
    for (Key key : kaleidoscope::live_keys.all()) {
      if (key.isKeyboardShift()) {
        which = key;
        return true;
      }
    }
    return false;
  }

  EventHandlerResult onKeyEvent(KeyEvent &event) {

    uint32_t converted = keyToUnicode(event.key);

    if (converted == 0) return EventHandlerResult::OK;

    if (keyToggledOn(event.state)) {
      Key shiftKey;
      if (isShiftKeyHeld(shiftKey)) {
// I'm not sure if its the right way to do that,
// having shift pressed while using Unicode.type produces strange results
        kaleidoscope::Runtime.hid().keyboard().releaseRawKey(shiftKey);
        kaleidoscope::Runtime.hid().keyboard().sendReport();
        ::Unicode.type(converted - upperOffset);
// upperOffset works most of the time, need better managment
        kaleidoscope::Runtime.hid().keyboard().pressRawKey(shiftKey);
        kaleidoscope::Runtime.hid().keyboard().sendReport();
      } else {
        ::Unicode.type(converted);
      }
    }
    return EventHandlerResult::ABORT;
  }
};

```

In the layer definition, I can use Key\_A\_CIRC where ever I want e.g. as Key\_A  
It supports helded shift to produce uppercase accented character.  
The main drawback is a visual feedback on screen, I can quickly see the typed sequence for unicode char (that was also the case with macro and compose key in chrysalis).

Any comment welcome to improve the approach.

++dlyr

---

<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:** [March 8, 2023, 5:46am UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/2 "2023-03-08T05:46:13Z")

</div>

1. In general, I would advise against directly interacting with HID reports in this way, but the Unicode plugin is already doing it, so I feel like it can be justified in this case. It could also be argued that the existing Unicode plugin should be rewritten.

2. It is possible to hold more than one `shift` key at a time, but your code assumes only one. Perhaps it would be better to use an `onAddToReport()` handler to suppress modifiers (`shift` isn’t the only one that can interfere and cause unexpected output). See the `ShiftBlocker` example for this trick.

---

<div class="post-metadata">

**Author:** ![dlyr](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/dlyr/32/4667_2.png) [@dlyr](https://community.keyboard.io/u/dlyr)\
**Post date:** [March 8, 2023, 7:45am UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/3 "2023-03-08T07:45:59Z")

</div>

Thanks for the feedback.  
Indeed I first try using ShiftBlocker, but as I understand it is closely link to macro behavior and not compatible with Unicode plugin internals.  
I will try to update Unicode plugin using macro key press/release and save/clear/restore modifiers state in the callback.

---

<div class="post-metadata">

**Author:** ![dlyr](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/dlyr/32/4667_2.png) [@dlyr](https://community.keyboard.io/u/dlyr)\
**Post date:** [March 8, 2023, 8:05am UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/4 "2023-03-08T08:05:54Z")

</div>

After a second read, ShiftBlocker seems to remove shift from the current live key to the macro temp key state, but also remove shift keys activated by macro code.  
What I need to achieve is to save modifiers state, then send a sequence for the unicode output, and restore state.  
I’m not sure how to achieve this … any clue welcome.

---

<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:** [March 8, 2023, 3:44pm UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/5 "2023-03-08T15:44:52Z")

</div>

The current version of `Unicode.type()` (which I’m thinking more and more should be rewritten, but that’s a separate issue) just uses the current HID report, modifies it, and sends reports immediately. If you want to guarantee that any `shift` modifier bits are removed from the HID report, you should just unconditionally remove both of them with `releaseRawKey()` rather than recording the first one you find (and note that `isKeyboardShift()` will not return `true` for all keys that cause a `shift` modifier bit to get set) and only unsetting that one. You still need to test for a held `shift` key, but you can drop the `which` parameter because it’s not needed. There’s also no need to restore `shift` bits that you removed from the HID report if you don’t return `ABORT`: they’ll automatically get restored:

```c++
    if (keyToggledOn(event.state)) {
      kaleidoscope::Runtime.hid().keyboard().releaseRawKey(Key_LeftShift);
      kaleidoscope::Runtime.hid().keyboard().releaseRawKey(Key_RightShift);
      kaleidoscope::Runtime.hid().keyboard().sendReport();
      
      if (isShiftKeyHeld()) {
        converted -= upperOffset;
        // upperOffset works most of the time, need better managment
      }
      ::Unicode.type(converted);
    }
    return EventHandlerResult::OK;
  }

```

In fact, you might want to clear all the modifier bits in the HID report, not just the `shift` keys, to prevent shortcuts from being triggered. This simplifies the code even more:

```c++
      kaleidoscope::Runtime.hid().keyboard().clearModifiers();
      kaleidoscope::Runtime.hid().keyboard().sendReport();

```

---

<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:** [March 8, 2023, 3:55pm UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/6 "2023-03-08T15:55:48Z")

</div>

> [@dlyr](#):
>
> Indeed I first try using ShiftBlocker, but as I understand it is closely link to macro behavior and not compatible with Unicode plugin internals.

It’s not really linked to Macros (though it’s _raison d’être_ was a Macro that someone wanted); it’s written to work the way most plugins do. Unicode is exceptional in sending HID reports directly rather than calling `Runtime.handleKeyEvent()`, like most plugins do. Even then, ShiftBlocker could be used to suppress keys before calling `Unicode.type()` by forcing a report to get sent the “normal” way, but calling `Runtime.prepareKeyboardReport()`, then `Runtime.sendKeyboardReport()`.

---

<div class="post-metadata">

**Author:** ![dlyr](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/dlyr/32/4667_2.png) [@dlyr](https://community.keyboard.io/u/dlyr)\
**Post date:** [March 9, 2023, 9:09am UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/7 "2023-03-09T09:09:37Z")

</div>

Thanks for the reply,  
Indeed the new version of `onKeyEvent` works as expected.  
As far as I understand, with the current version of Unicode plugin, I have to use `hid()` to clearModifiers.  
Also my understanding of `shiftBlocker` and how report works is weak. I understand it blocks shifts during `onAddToReport`, which is called for each active key to generate a report, later send to the host.

Since I’m new to hardware and keyboard programming, I surely need to have a “big picture” introduction on how it works, wath is a report, and how they are managed. Any reference welcome.

I also need to figure out tests, my current version is available here [GitHub - dlyr/Kaleidoscope at dlyr](https://github.com/dlyr/Kaleidoscope/tree/dlyr)

++ dlyr.

---

<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:** [March 10, 2023, 5:52pm UTC](https://community.keyboard.io/t/wip-accentlayerplugin-accented-char-build-onto-unicode-plugin/6248/8 "2023-03-10T17:52:24Z")

</div>

Think of the HID report as a set of keycodes that are currently active (“pressed”). Functions like `pressRawKey()` and `clearModifiers()` just add or remove keycodes from that set (setting or unsetting a bit in a bitfield). `sendReport()` actually causes a report to be sent over USB. Your plugin and the Unicode plugin call these functions directly, but for most plugins, Kaleidoscope handles all of the HID reporting functions behind another layer of abstraction. When a key event is received, each plugin’s `onKeyEvent()` handler is called, then Kaleidoscope makes any corresponding updates to the `live_keys` array, and generates a new report from that (calling any `onAddToReport()` handlers in the process).

You might find it helpful to look at the lower level of how HID reports are handled in the KeyboardioHID repository. Kaleidoscope code itself gets impenetrable as there are many layers of redirection to follow.
