LockLayer as a secondary (held) action?

Is this possible?

I would rarely use the numpad layer, so considering moving it to N.

Yes, it is possible, but not yet configurable via Chrysalis. You can set this up by defining a Qukey object in a Kaleidoscope sketch, and compiling custom firmware.

1 Like

Thanks for the reply. My next question is can I also toggle an LED on the key as an indicator?

I’m guessing this would need to be in a macro, with the code toggling the layer & LED state, but I’m not sure how to get the layer state.

If you want the color to override any existing LED effect, the best way to implement this is not a macro, but a custom little plugin, something along these lines:

EventHandlerResult afterEachCycle() {
  if (Layer.isActive(N)) {
    LEDControl.setCrgbAt(KeyAddr(ROW, COL), CRGB(R, G,B ));
  } else {
    LEDControl.refreshAt(KeyAddr(ROW, COL));
  }

  return EventHandlerResult::OK;
}

…where ROW and COL are the row & column of your layer lock key you want to highlight, and R, G, B are the red, green, blue components of the color you want to use.

The disadvantage is that you have to hard code the location - or scan the active keymap to discover the key, or do some other tricks to figure out what to highlight. The upside is that this does override any active LED effects, while doing it via a macro would set the color, but if you have any effects active that do animation, those would reset the color to whatever the effect thinks it should be.

If you don’t mind that, the macro way is something like this:

void moveToAndHighlight(const uint8_t macro_index, KeyEvent &event) {
  if (!KeyToggledOn(event.state)) return;

  if (Layer.isActive(N)) {
    Layer.deactivate(N);
    LEDControl.refreshAt(event.addr);
  } else {
    Layer.activate(N);
    LEDControl.setCrgbAt(event.addr, CRGB(R, G, B));
  }
};

Thanks, that seems straightforward. I’ll stick with the macro for now as I won’t normally have an effect active & I’d have to read up on plugins to implement a plugin.

Plugins may sound scary, and intimidating, or complicated, but… they’re not. To use the first snippet above as a plugin, you’d just wrap it like this:

namespace kaleidoscope {
class MoveAndHighlight: public kaleidoscope::Plugin {
 public:
  EventHandlerResult afterEachCycle() { /* the code from above */ }
};
}
kaleidoscope::MoveAndHighlight MoveAndHighlight;

…and then you just stick it somewhere into KALEIDOSCOPE_INIT_PLUGINS, preferably near the end so it can override whatever comes before it, and you’re all set.

But if you’re not planning to use any LED effects, then the macro is likely simpler, indeed.

So you can include the plugin code in the same .ino file?

I’ve run into another problem using this idea to swap to another layer. The examples only define the Qukey for layer 0 (so there’s no return if the triggering key isn’t transparent) but when I try using Qukeys::layer_wildcard instead I get errors.

  QUKEYS(
    kaleidoscope::plugin::Qukey(0, KeyAddr(3, 10), LockLayer(NUMPAD)),     // N/Numpad layer
    kaleidoscope::plugin::Qukey(Qukeys::layer_wildcard, KeyAddr(2, 5), M(MACRO_SRAITH_G))      // G/Sraith Gaelach
  )
Model100-Sean:847:32: error: expected primary-expression before '(' token
  847 |     kaleidoscope::plugin::Qukey(Qukeys::layer_wildcard, KeyAddr(2, 5), M(MACRO_SRAITH_G))      // G/Sraith Gaelach

I suppose I’m using this wrong. I could always use a definition for each layer.

Yep! A plugin is just an instance of a C++ class. You can implement it wherever you want to.

Sorry about that. The symbol Qukeys in the global namespace unfortunately refers only to an instance of the kaleidoscope::plugin::Qukeys class, so to refer to the layer_wildcard constant, you either need the unwieldy ::kaleidoscope::plugin::Qukeys::layer_wildcard or the somewhat confusing ::Qukeys.layer_wildcard. The leading :: can be dropped in either case, but I included them to clarify everything with an absolute reference, rather than a relative one. Qukeys.layer_wildcard is the briefest version.