Current equivalent of `useLoopHook` for highlighting single CapsLock LED?

Hello. As I just said here I find the CapsLock plugin problematic to use.

Besides, on ordinary keyboards one doesn’t have the alphabetic keys highlighted nor is it necessary IMO because unlike for NumLock, no keys are being repurposed here.

All I would like for is for the CapsLock key to be highlighted as per standard keyboards. I have seen this closed request, especially @algernon’s advice to do useLoopHook, but it would seem that that function is now deprecated and it is not clear to me what the current equivalent is.

I presume keeping track of the CapsLock status may be accomplished by a simple boolean as shown here. It is the colouring part that I want to know.

Perhaps a NumLock-like breathing effect would require a separate plugin, but it would be sufficient to have a single fixed colour because one is not going to use CapsLock for any extended period of time. Please advise as to how this may be accomplished.

I also note that my CapsLock is a Qukey that doubles to LSHIFT(RightAlt) for XKB fourth level selection. My current sketch.

The current recommended way is to write a small plugin (doesn’t have to be a separate library, and can be in your .ino sketch file):

namespace kaleidoscope {
class LEDCapsLock : public kaleidoscope::Plugin {
public:
  LEDCapsLock() {}

  EventHandlerResult beforeReportingState() {
    // Do the highlighting here

    return EventHandlerResult::OK;
  }
};
}

kaleidoscope::LEDCapsLock LEDCapsLock;

// ...

KALEIDOSCOPE_INIT_PLUGINS(...,
                          LEDCapsLock);

As to how to do the highlighting, that can be done in various ways. If you want to do this for your own sketch only, and not in a generic way, then the easiest thing is to check if the top layer is the base layer, and if the CapsLock key is pressed, and highlight it then. Otherwise just refresh.

The above translated to code (this should be the body of the beforeReportingState method above:

// check capslock state
bool capsState = !!(kaleidoscope::hid::getKeyboardLEDs() & LED_CAPS_LOCK);

if (Layer.top() != LYR_QWERTY || !capsState) {
  // If the top layer is not LYR_QWERTY, or CapsLock is not pressed...
  ::LEDControl.refreshAt(2, 6);
  return EventHandlerResult::OK;
}

::LEDControl.setCrgbAt(2, 6, CRGB(0, 0, 160));
return EventHandlerResult::OK;

If you want to use the breathe effect, then replace the setCrgbAt line with something like this:

::LEDControl.setCrgbAt(2, 6, breath_compute());

Mind you, the above is a specialized solution, not a generic one. A generic one would scan the keymap for the CapsLock key, most likely, instead of hard-coding positions.

1 Like

Yes, the above is… not the most intuitive. Some of the things there, like checking if caps is active could be abstracted away into a more intuitive wrapper.

Seeing use-cases like this is awesome, because we can see which parts of the code need to be improved. Please bear with us 'till we get there!

Hello @algernon! I have noticed this double-not in other similar contexts. Can you explain why it is needed and just & is not sufficient?

The & and the !! serve different purposes. foo & bar does a bit-wise AND, it effectively checks if the bits in bar are set in foo. It’s return value is the same type as foo and bar. But, we want a boolean, a more limited type. So we use !!, double not.

The first not will turn any non-zero value into zero; and any zero value into one. The second not will flip the value. This way, we went from uint8_t to bool in a few easy steps.

It’s not needed, but I find that it makes the code clearer, the intent of it.

2 Likes
bool capsState = bool(kaleidoscope::hid::getKeyboardLEDs() & LED_CAPS_LOCK);

Might be an alternative that may be less confusing for C++ newbies.

FWIW, I remember there was a broken version of either gcc or clang some years ago, that made it necessary to add those !! to suppress spurious compiler diagnostic messages when assigning to bool. That’s why you find it here and there in code that was written by that time.

2 Likes