Need help making a layer that has a modifier key held down for some keys

I want to make a layer that works like this:

  • tapping the layer lock key holds the Win key down
  • there are keys on that layer for tapping 0-9
  • tapping the layer lock key again releases the Win key and takes you off of that layer
  • there are other keys on the layer that do not have the Win key held down - i.e., either the other keys release the Win key before they do anything, or the 0-9 keys have the Win key held down the first time they are pressed on the layer

How do I do that? The simplest approach does not work because with the new revisions, a macro can’t release a key that it didn’t press. :frowning:

Upon closer examination, I am not sure this is true. The docs say:

Macros now operates by manipulating keys on a small supplemental virtual keyboard when using Macros.press() and Macros.release() (which are called by D() and U(), et al, respectively). This means that it has no built-in facility for releasing other keys that are held on the keyboard.

https://kaleidoscope.readthedocs.io/en/latest/UPGRADING.html

So it looks like if a key was pressed by one macro on the virtual keyboard, another one could release it.

The problem is that this doesn’t work:

  case M_Purple:
      if (keyToggledOn(event.state)) {
         if (Layer.isActive(PURPLELAYER)) {
                   Layer.deactivate(PURPLELAYER);
          return MACRO(U(LeftGui));
         }
         else {
                   Layer.activate(PURPLELAYER);
          return MACRO(D(LeftGui));
         }
      }
      break;

What happens is that running this macro doesn’t hold down the Win key, it just taps it, even though I’m using the D macro!

Looking at the docs, I see that the macro doesn’t hold keys… but I can’t use event.key or Macros.press, either, since those options will release the modifier after I release the macro key.

So how do I make a macro that holds down a modifier?

@gdxpr in the Discord was able to help me and was kind enough to write a small custom plugin to do this.

I put ML(LeftGui, PURPLELAYER) in the keymap - these are the new ModLayer keys that combine a mod with a ShiftToLayer.

Then to make it lock, I needed this plugin:

namespace kaleidoscope {
namespace plugin {

class AutoStickyGuiLayer : public Plugin {
  public:
    EventHandlerResult onKeyEvent(KeyEvent &event) {
      if (keyToggledOn(event.state) &&
          event.key == ML(LeftGui, PURPLELAYER) &&
          !::OneShot.isSticky(event.addr)) {
        ::OneShot.setSticky(event.addr);
        // To stop OneShot from processing this as an event that cancels the
        // sticky key, we mark it as "injected".
        event.state |= INJECTED;
      }
      return EventHandlerResult::OK;
    }
};

}  // namespace plugin
}  // namespace kaleidoscope

Then I just had to put AutoStickyGuiLayer in KALEIDOSCOPE_INIT_PLUGINS somewhere after OneShot.