Kaleidoscope-CapsLock: turns letter keys red when CAPS LOCK is on

I’ve added a function to my .ino to send a Key_CapsLock press to the host OS when I press fn-shift. I prefer this to OneShot, because OneShot also modifies the number keys, where at least on macOS caps lock only modifies letters (and also stays locked until you hit the caps lock key again).

Based on previous discussion on the subject I added code to my loop() so the letter keys are lit up red (like how the numpad mode works). I also made the fn and shift keys light up the same way the num key does in numpad mode.

I’m happy to break it out into a plugin and contribute it back, if (A) that’s a thing people want, and (2) people will help me make sure it’s idiomatic. C++ is like eleventh or something on my list of programming languages.

So, anybody want that?

Update: I did it and the Kaleidoscope-CapsLock plugin is in my repo.

6 Likes

That sounds neat!
The best way to get something nice and idiomatic is to start with something horrible and let people send patches :wink:

4 Likes

It looks like LED_CAPS_LOCK starts false, becomes true on the first press, but then doesn’t become false again on a second press. I was keeping a separate boolean for the state within the macro when it was that, but in a plugin that seems like a kludge. Am I missing something about how to ensure it gets unset on a second press, is that a bug elsewhere in the firmware, or do I just need to keep track of state within the plugin?

Also, how do I address the fn keys in order to light them up? In my .ino I was doing this:

} else if (k == Key_LeftShift || k == Key_RightShift || k == ShiftToLayer(FUNCTION)) {

In a plugin that ShiftToLayer(FUNCTION) is read literally by the compiler and thus is an error.

In the plugin’s translation unit, FUNCTION won’t be defined, so that’s why it won’t work. If you want to highlight all layer-changing keys, though, there’s a simple test for that:

if (k.flags == (KEY_FLAGS | SYNTHETIC | SWITCH_TO_KEYMAP)) {...}

If you only want ShiftToLayer() keys highlighted, also test for this:

if (k.keyCode >= LAYER_SHIFT_OFFSET) {...}

…and if you only want a specific layer shift highlighted, you’ll have to find a way to pass the layer number to the function and test for:

byte n = <layer number>;
if (k.keyCode == (LAYER_SHIFT_OFFSET + n)) {...}

So there’s no way to address the ‘fn’ keys by name or location and they have to be located by flags? The point for this plugin would be to highlight the combination of keys used to get back out of the mode (so, if caps lock is enabled as fn-shift, light up the ‘fn’ and ‘shift’ keys while caps lock is on).

BTW I’m assuming there doesn’t need to be a layer for this. In macOS at least, caps lock is a momentary key (not a locking key). Tapping it once turns it on (and lights an LED in a supported keyboard); tapping it again turns it off. I’ve found that if I define fn-shift as Key_CapsLock, the OS is properly handling state (first press ON, second press off). The Keyboardio doesn’t seem to be changing its LED_CAPS_LOCK state after the first press, so I end up with the OS caps lock state as off, but the LED still ON.

The macro does what I want:

static void toggleCapsLockMacro(uint8_t keyState) {
static Key lastKey;
lastKey.keyCode = Key_CapsLock.keyCode;
  if (keyToggledOn(keyState)) {
    capsState = !capsState;

    if (!capsState) {
      // Some keys seem to get "stuck" in the painted color. Reset current mode to unstick them.
      LEDControl.set_mode(LEDControl.get_mode_index());
    }
  }
  if (keyIsPressed(keyState)) {
    kaleidoscope::hid::pressKey(lastKey);
  }
}

`
Then the colors are painted within the loop():

 if (capsState) {
    for (uint8_t r = 0; r < ROWS; r++) {
    for (uint8_t c = 0; c < COLS; c++) {
      Key k = Layer.lookupOnActiveLayer(r, c);

      cRGB breathColor = breath_compute();

      if ((k.raw >= Key_A.raw) && (k.raw <= Key_Z.raw)) {
        LEDControl.setCrgbAt(r, c, CRGB(255, 0, 0));
      } else if (k == Key_LeftShift || k == Key_RightShift || k == ShiftToLayer(FUNCTION)) {
        LEDControl.setCrgbAt(r, c, breathColor);
      } else {
        LEDControl.refreshAt(r, c);
      }
    }
  }
}

In that usage I was just using ShiftToLayer(FUNCTION) because I couldn’t figure out how to address the physical ‘fn’ key by itself.

Well, you could use the row & col indexes to identify the fn keys, but that wouldn’t be great for a plugin, since it would be keymap-dependent.

There’s actually a feature request for a plugin like this - see #219

Yes, that’s the discussion @fedward referred to at the beginning of this thread.

That’s what I get for not following the link - my bad.

1 Like

I am confused by that feature request, because it was closed without an actual resolution. I’m new to GitHub so I didn’t know the etiquette of commenting on closed issues.

Anyway, I’ve pushed an initial plugin to my own public repo. Voilà, Kaleidoscope-CapsLock.

1 Like

It was closed by mistake: I answered another question during the discussion, and mistakenly closed the original. If you run into anything similar, or want to comment on a closed issue for whatever reason, go ahead!

1 Like

I have commented on that feature request. Thanks!

New Keyboardio user here, with very little programming experience. I noticed this plugin and installed it per the instructions on fedward’s plugin page, as well as installing the library files.

While the plugin does offer ALL CAPS functionality, I’ve noticed the following:

  1. Many of the default LED effects seem to have been disabled, including the NumPad custom effect that lights up only the number keys when the “num” key is pressed. Only the solid-colors and AlphaSquareEffect LED effects apparently work. How can all the default LED effects be restored, without disabling the plugin?

  2. When pressing the fn + shift keys, the Q and U keys light up red first, before the letter-keys turn red after releasing. Holding down then fn key while Caps Lock is on also causes the Q and U keys to light up red. Is this supposed to happen?

  3. How can the plugin code be modified such that only the letter-keys light up, in a similar manner to the NumPad default LED effect where only the numerical keypad keys turn red upon pressing the “num” key, and all the other keys go dark?

The NumPad issue seems to happen (or at least be fixed) because of the loading order. If you put &CapsLock before &NumPad in your Kaleidoscope.use() both will work. If you put &CapsLock after &NumPad then NumPad stops working. No idea why.

And yes, I can now confirm that the animated effects all stop working for me too. I don’t use the animated effects so I hadn’t noticed that problem. I’ll see if I can figure out why that happens.

Those are transparent keys in the FUNCTION layer. It’s not so much supposed to happen as a strange, temporary side effect of using the fn key as a chorded control to get to the Key_CapsLock key code. I saw this but didn’t think it was worth trying to fix.

On my keyboard it does exactly the same thing as the NumPad function. Only the letter keys in the active keymap turn red, and other keys stay in whatever state they were in before. Is your whole keyboard turning red?

Release 0.0.2 is now up on GitHub to fix the problem overriding other color modes.

  1. Putting &CapsLock before &NumLock fixed the issue.

  2. No comment on this.

  3. No, not the entire keyboard is turning red. Just the keys in the active keymap turn red, while the rest stay as they are in the solid-colors LED effects. Oddly, the default programming has keys in the active keymap turn red, while the other keys go dark in the animated effects when the “num” key is pressed.

  1. With the bug fix in yesterday’s release it shouldn’t actually matter what order they’re loaded in (while testing I had them loading in the order that previously didn’t work) so if you’re bored and want to check it the other way, I’d appreciate confirmation that the bug fix really did what it was supposed to. But I’m also pretty sure it’s good since the animated modes are still working. That said …

Ohhhhh, I didn’t quite understand what you were asking before (because I don’t use the animated modes and I thus wasn’t seeing the difference). Personally I’d argue that NumPad is Doing It Wrong and the behavior of CapsLock is “correct,” but I can see how you might prefer it the other way. Oddly enough the likely fix for this is a partial return to the behavior that was previously broken. To wit, this (removed) line needs to be added back somewhere in Kaleidoscope-CapsLock.cpp:

      ::LEDControl.set_mode(::LEDControl.get_mode_index());

I’m not in a position to test it at the moment but I think the place you’d want to put it is between the current lines 23 and 24:

  if (capsState) {
    capsCleanupDone = false;
    // Reset LED mode, which effectively disables animation
    ::LEDControl.set_mode(::LEDControl.get_mode_index());
    for (uint8_t r = 0; r < ROWS; r++) {
      for (uint8_t c = 0; c < COLS; c++) {

I think that should do what you want. You’d have to make that change to Kaleidoscope-CapsLock.cpp and then rebuild and flash.

THANKS… er, that is, thanks for this plugin, @fedward!

1. I can confirm for you that it does work even if &CapsLock is placed after &NumPad.

3. Your suggestion there does work to turn off animated LED effects for the rest of the keyboard while caps lock is on, though static LED effects are unaffected. (But that’s how it is for num lock too.)

I played with the code a bit, trying to figure out how to turn off all other LED effects while the caps lock is on. Instead I managed to get my keyboard to a state where it wouldn’t display any LED effects at all except the ones for caps lock! At that point I removed almost all of my attempted modifications, keeping just a few minor ones: with caps lock on, now my letter keys are white and my caps lock key is hot pink (since the dull blue of the breathing effect wasn’t standing out in its new location on the E key). I decided I like the current state of things, so I’m no longer looking for a way to turn off other LED effects.

1 Like