# Manipulate modifiers while keeping OS key repeat ability

**URL:** https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016
**Category:** Programming
**Created:** [July 6, 2019, 11:52am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016 "2019-07-06T11:52:38Z")
**Posts on this page:** 17
**Page:** 1

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 6, 2019, 11:52am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/1 "2019-07-06T11:52:38Z")

</div>

I have a feeling I am going into well-discussed territory here.  
There exists a number of posts that discuss how to change modifiers. I think I have read them all by now. You have the ShapeShifter plugin that changes the key typed while holding down shift. Someone made a ModifierLayers plugin that maps a whole layer to e.g. Shift. (I think. It uses the old plugin system, and I am too much a noob to know how to get it to work).

The exact problem I am trying to solve is that, depending on the key, I want AltGr/Right Alt to be held instead of shift.

I want to, when I press Shift + 2, create @ instead of ".

I know this has also been discussed on the forums, but the solution in those cases seemed to be to switch keyboard layouts on the OS level from (in my case) danish to US.

I don’t want to that.

Currently I am using US layout because I like that layout better. But the rest of my family and my coworkers are pretty annoyed every time they need to use my keyboard (which has danish layout). And with my first 100% programmable keyboard (the Keyboardio, duh) I want to switch all my PCs to Danish, but configure the Keyboardio to use the US layout. But that means I have to be able to switch modifier from shift to altgr.

And before you ask: Yes, I will keep both keyboards attached. The normal keyboard for all the normal people, and the Keyboardio for me.

With macros I was able to put one on e.g. the “2” key that produced a @ even with danish keyboard layout when shift was held. But it wouldn’t repeat. Do I need that repeat? Probably not, but out of sheer principle I want the keyboard to behave exactly like normal. Curse my OCD!

I have so far come up with this:

```
EventHandlerResult MyAwesomePlugin::onKeyswitchEvent(Key &mapped_key, byte row,
                                              byte col, uint8_t key_state) {
  uint8_t modifiers = Keyboard.lastKeyReport.modifiers;
  
  if(mapped_key == Key_2) {
    set_key_ = false;

    // Check if only shifts are pressed
    if(!(modifiers & ~SHIFT_KEYS) && (modifiers & SHIFT_KEYS)) {
      if(keyToggledOn(key_state)) {
        // If key was just pressed
        // and set the modifiers to AltGr
        set_key_ = true;
      } else if(keyIsPressed(key_state)) {
        // If key is pressed

        // Have non-shift modifiers been pressed?
        if(modifiers & ~SHIFT_KEYS) {
          return EventHandlerResult::OK;
        }

        // Set modifiers to AltGr
        set_key_ = true;
      } else if(keyToggledOff(key_state)) {
        // Some debugging message I removed.
      }
    }
  }
  return EventHandlerResult::OK;
}

```

At first I had everything in onKeyswitchEvent, but then I read about how the report could be incomplete at just about any stage until it was sent over the wire. So I tried to make the changes as late as possible and used beforeReportingState:

```
EventHandlerResult MyAwesomePlugin::beforeReportingState() {
  if(set_key_) {
    Keyboard.keyReport.modifiers = RIGHT_ALT_KEY;
  }
  if(!memcmp(Keyboard.lastKeyReport.allkeys, 
             Keyboard.keyReport.allkeys, 
             sizeof(Keyboard.keyReport))) {
    // Here we end up if the reports are the same. At this point the keyboard should 
    // not send a new report. That logic is elsewhere in the firmware. When I hold 
    // down shift I never end up here, although the report modifiers have been set to
    // RIGHT_ALT_KEY. I think there is something else going on in the firmware, but I
    // have no idea how to find out.
  }
  return EventHandlerResult::OK;
}

```

I cannot figure out what is happening since the reports are not the same. What goes into allkeys?  
If I just press any other key than 2 and shift I get key repeat, but not with 2 and shift.  
Without knowing anything really about Kaleidoscope my guess is that because I hold down shift the whole time, and I change the modifier to not have shift but right alt instead, the firmware still sees that shift at a time when it needs to figure out if a report should be sent.

Do I make myself clear, or am I just sounding like the noob I am?

---

<div class="post-metadata">

### Author: ![tiltowaitt](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/tiltowaitt/32/4764_2.png) [@tiltowaitt](https://community.keyboard.io/u/tiltowaitt)
#### Post date: [July 6, 2019, 4:12pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/2 "2019-07-06T16:12:20Z")

</div>

So you want to get an `@` when you hit `Shift+2`, even though you’re using the Danish layout? Would something like this work?

```auto
EventHandlerResult MyAwesomePlugin::onKeyswitchEvent(Key &mapped_key, byte row,
                                              byte col, uint8_t key_state) {
  if(mapped_key == Key_2) {
    if(mapped_key.flags == SHIFT_HELD) {
      if(keyIsPressed(key_state)) {
        hid::pressKey(RALT(Key_2));
        return EventHandlerResult::EVENT_CONSUMED;
      }
  }
  return EventHandlerResult::OK;
}

```

---

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 6, 2019, 4:42pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/3 "2019-07-06T16:42:26Z")

</div>

Unfortunately not.  
It seems

```
mapped_key.flags == SHIFT_HELD

```

doesn’t evaluate to true.

---

<div class="post-metadata">

### Author: ![tiltowaitt](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/tiltowaitt/32/4764_2.png) [@tiltowaitt](https://community.keyboard.io/u/tiltowaitt)
#### Post date: [July 6, 2019, 4:50pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/4 "2019-07-06T16:50:26Z")

</div>

Then swap in your modifiers check?

---

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 6, 2019, 5:03pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/5 "2019-07-06T17:03:16Z")

</div>

With this:

```
if(mapped_key == Key_2) {
  Serial.println("Key_2 event");
  if(!(modifiers & ~SHIFT_KEYS) && (modifiers & SHIFT_KEYS)) {
    Serial.println("SHIFT_HELD");
    if(keyIsPressed(key_state)) {
      Serial.println("keyIsPressed");
      hid::pressKey(RALT(Key_2));
      return EventHandlerResult::EVENT_CONSUMED;
    }
  }
}

```

I now get “keyIsPressed” in the console, but nothing is printing with shift down. Neither 2, " nor @.

My guess is that, from Kaleidoscopes point of view, shift is still down (because I am pressing it down physically) and by default shift+right-alt+2 doesn’t produce any characters.

---

<div class="post-metadata">

### Author: ![tiltowaitt](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/tiltowaitt/32/4764_2.png) [@tiltowaitt](https://community.keyboard.io/u/tiltowaitt)
#### Post date: [July 6, 2019, 6:03pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/6 "2019-07-06T18:03:08Z")

</div>

> [@peterpop](#):
>
> My guess is that, from Kaleidoscopes point of view, shift is still down (because I am pressing it down physically) and by default shift+right-alt+2 doesn’t produce any characters.

Per my understanding, that shouldn’t be the case. Try replacing the call to `pressKey` with `hid::pressKey(Key_2);`. You should get a `2`, not `"`.

What happens if you manually type `AltGr+2`?

---

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 6, 2019, 6:29pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/7 "2019-07-06T18:29:23Z")

</div>

If I press Shift+2 I still get ".

But I do notice something funny.

If I first press 2 and keep it down, I can see 2s printed with Windows’ typical speed. But if I then press down shift the "s goes crazy. I think this is because Kaleidoscope is generating the hid::pressKey(Key\_2) events as fast as it can and to Windows they are a bunch of fast incoming keydowns and keyups so it’s Kaleidoscope that determines the speed and not Windows.

If I press AltGr+2 I get @ (I use the AltGr from my normal keyboard)  
If I then also press down Shift I get nothing.

---

<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: [July 7, 2019, 12:22am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/8 "2019-07-07T00:22:03Z")

</div>

I was dissatisfied with the lack of ability to completely dissociate shifted symbols from unshifted symbols in the keyboard firmware, and ended up writing a completely independent firmware as a result. I did this because, at the time it was impossible to implement my Unshifter plugin for Kaleidoscope with its system of tracking keyboard state in the HID report. Unshifter lets me arbitrarily rearrange symbols such that holding shift in combination with a key can produce any arbitrary key value, even ones that aren’t `shift`-modified in the HID report. For example, I have a key in my keymap that’s `,` without shift, but `;` with it.

There have been some changes to Kaleidoscope since I first wrote it, so I might be able to port Unshifter now. I’m not very optimistic, but it’s possible that I could make it work. If so, I’m pretty sure it would solve your problem.

---

<div class="post-metadata">

### Author: ![tiltowaitt](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/tiltowaitt/32/4764_2.png) [@tiltowaitt](https://community.keyboard.io/u/tiltowaitt)
#### Post date: [July 7, 2019, 5:53am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/9 "2019-07-07T05:53:42Z")

</div>

Whoops, I should have had you use something other than `Key_2`, but it doesn’t matter; looking in `hid.cpp`, it seems that `hid::pressKey()` uses the modifiers currently pressed, as well as any modifiers explicitly set in the `Key`'s `flags`.

I did, however, notice another function that might be useful, namely `releaseModifiers()`. In your `if` block, try this:

```auto
hid::releaseModifiers(SHIFT_HELD);
hid::pressKey(RALT(Key_2));
hid::pressModifiers(SHIFT_HELD);

```

I don’t know how to help with the repeat speed, unfortunately. I encountered the same thing with another plugin I wrote, but I was able to skirt around the issue because the plugin called for me to disable repeat altogether.

---

<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: [July 7, 2019, 12:28pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/10 "2019-07-07T12:28:20Z")

</div>

One important thing to understand is that the keyboard doesn’t send key press and release _events_ to the host. Instead, it sends a HID report that contains (effectively) a list of all the keys that are currently pressed at the time. Kaleidoscope starts every scan cycle with an empty report, and adds keycodes as it goes, on key at a time. Once it has processed all the keys, it then sends the complete report to the host.

One problem you may have is that the modifier key you’re testing for might have been _pressed_ before the 2 key, but it might be _scanned_ after it in the scan order. If a modifier needs to be unset, it should be done in the `beforeReportingState()` hook, not in `onKeyswitchEvent()`.

Also, the `hid::press*()` and `hid::release*()` functions don’t send HID reports, they only set and unset keycodes in the report, so calling `hid::releaseModifiers()` followed by `hid::pressModifiers()` with the same argument will only have an effect if a report is sent in between those two calls. And sending extra reports like that tends to cause rapid key repeats, so it’s far better to ensure that the normal end-of-cycle report contains only what it should.

---

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 7, 2019, 10:11pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/11 "2019-07-07T22:11:17Z")

</div>

Hmmm… If I try to use hid::releaseModifiers (in beforeReportingState as per Michaels comment) I get this error in the Arduino IDE:

```
<snip>\MyAwesomePlugin.cpp:108:5: error: 'releaseModifiers'
                                    is not a member of 'kaleidoscope::hid'
```

---

<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: [July 8, 2019, 12:26am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/12 "2019-07-08T00:26:06Z")

</div>

It’s `kaleidoscope::hid::pressKey()` & `kaleidoscope::hid::releaseKey()`. Sorry about not checking the function names first.

---

<div class="post-metadata">

### Author: ![tiltowaitt](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.keyboard.io/tiltowaitt/32/4764_2.png) [@tiltowaitt](https://community.keyboard.io/u/tiltowaitt)
#### Post date: [July 8, 2019, 6:00pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/13 "2019-07-08T18:00:07Z")

</div>

Ah, it turns out that `releaseModifiers` and `pressModifiers` are both in an anonymous namespace, and so are unaccessible. I didn’t notice earlier, because they share the same level of indentation as the rest of the `kaleidoscope::hid` namespace. My bad.

---

<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: [July 8, 2019, 11:01pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/14 "2019-07-08T23:01:30Z")

</div>

Right. I put those functions in that namespace because they’re intended to be helper functions, and shouldn’t be called by plugins directly. Similarly, it’s unwise to directly call functions in KeyboardioHID.

---

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 9, 2019, 7:21am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/15 "2019-07-09T07:21:53Z")

</div>

> [@tiltowaitt](#):
>
> Ah, it turns out that `releaseModifiers` and `pressModifiers` are both in an anonymous namespace, and so are unaccessible.

I was about to ask about the \*Modifiers functions not being accessible, but you cleared it up for me. 🙂

> [@merlin](#):
>
> Similarly, it’s unwise to directly call functions in KeyboardioHID.

Noted. If there are other ways to accomplish this I am all ears.

With this:

```
EventHandlerResult MyAwesomePlugin::beforeReportingState() {
  if(set_key_) { 
    Serial.println("Press AltGr");
    kaleidoscope::hid::releaseKey(Key_LeftShift);
    kaleidoscope::hid::pressKey(Key_RightAlt);
  }
  return EventHandlerResult::OK;
}

```

I, of course, get “Press AltGr” all the time after the first press. I need some way to tell the system to unpress it again. I haven’t found the correct place for “set\_key\_ = false;” yet.  
Is beforeReportingState called before afterEachCycle? And how do the two functions relate?  
I need to somehow check if anything other than “2” and SHIFT is pressed and in that case set set\_key\_ to false - or something equivalent to that. But I need to do it as late in the process (cycle?) as possible.

---

<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: [July 9, 2019, 11:40am UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/16 "2019-07-09T11:40:48Z")

</div>

I think you should use three hooks and two boolean variables (`two_pressed_` & `shift_pressed_`):

`afterEachCycle()` — Set both member variables to `false`. This hook gets called after the report is sent. I don’t recall if it’s before or after the report is cleared, but that doesn’t matter in this case, since we’re doing the equivalent operation.

`onKeyswitchEvent()` — Test each pressed key. If `mappedKey` is `Key_2`, set `two_pressed_` to `true`. Likewise if a `shift` key is pressed, set the other state variable. This hook is called during the scan cycle for each key that’s not idle.

`beforeReportingState()` — If both state variables are `true`, call `kaleidoscope::hid::releaseKey()` on both `shift` keys, and `pressKey()` on `Key_RightAlt`. This function gets called after the scan cycle is finished, but before the report is sent.

Note that it’s never necessary to call `releaseKey(KeyRightAlt)`, because _all_ keycodes get cleared from the report after the report is sent each cycle.

---

<div class="post-metadata">

### Author: ![peterpop](https://avatars.discourse-cdn.com/v4/letter/p/f17d59/32.png) [@peterpop](https://community.keyboard.io/u/peterpop)
#### Post date: [July 9, 2019, 12:32pm UTC](https://community.keyboard.io/t/manipulate-modifiers-while-keeping-os-key-repeat-ability/3016/17 "2019-07-09T12:32:07Z")

</div>

Yes! That is exactly the behavior I want. Thank you 😃

And I even learned a lot at the same time.
