Multiple layers?

More detail, if you’re interested:

Whenever a layer gets activated (turned on) or deactivated (turned off), Kaleidoscope updates the current keymap in memory, using the highest-numbered active layer on which each key is defined. So if the top active layer has a transparent key entry ("___"), it looks on the next-highest active layer, and so on, until it finds an active layer with a specified keycode for that key.

So, on the default keymap (Model01-Firmware.ino), there are three layers: QWERTY (0), FUNCTION (1), and NUMPAD (2). Holding Fn activates the FUNCTION layer using ShiftToLayer(FUNCTION), which updates the current keymap, overwriting many of the keycodes, but not all of them. In particular, the key that was Key_Spacebar defined on the QWERTY layer) is now mapped to Key_Enter.

When Fn is released, the keymap gets updated again, and all of the keys now get their keycodes from the QWERTY layer. This example assumes NumLock is off the whole time, of course.

Running through that example has made me wonder what would happen if I defined both palm keys as ShiftToLayer(1) on layer 0, and LockLayer(1) on layer 1. I could then shift to layer 1 by holding down a palm key (which I believe retains its mapping from layer 0 as long as it’s held), start typing on layer 1, then decide I want to stay in layer 1, and tap the other palm key before releasing the held palm key. Would releasing the ShiftToLayer(1) key result in layer 1 toggling off, or would the tap on LockLayer(1) keep layer 1 active in the keymap?

In this case, since the release would be for a LockLayer(1) key, you’d stay on that layer. However, with this setup ShiftToLayer(1) would effectively work as a LockLayer(), because the firmware would never see a release event for it.

I didn’t make that example clear enough. Here’s the sequence of events, starting with only layer 0 active:

  1. press left palm key: ShiftToLayer(1)

  2. press right palm key: LockLayer(1)

  3. release right palm key

  4. release left palm key

Unless I misunderstand, the left palm key continues to be mapped to ShiftToLayer(1) until step 4, because it was held at the time of a layer update, so it wouldn’t be effectively the same as LockLayer(1). Then, when it’s released, I’m not sure if it changes to LockLayer(1) before it would trigger the call to Layer.off().

1 Like

Ah, I see. In this case, the layer would still be turned off, because the lock/shift mechanism is currently implemented by the key event handler, not the layering code itself. In other words, we are tied to key events, and don’t keep track of whether a layer is locked or shifted.

If/when the layer stuff moves to a plugin, it would be quite easy to write a plugin that would make the behaviour you described possible. I have a feeling that we could build it on the same foundation that the current behaviour is built upon, with very little change (they’d share a base class).

Making this possible with the current code… hmm, that would be more complicated than I’d feel comfortable with. At least if we stick to ShiftToLayer/LockLayer… because there’s another option, that can work on top of what we already have! We can create a plugin that implements this behaviour! All it has to do is capture LockLayer/ShiftToLayer, and flip a bit in a bitfield if a layer is locked to, and refuse to turn it off via ShiftToLayer. Should be a few dozen lines, I guess.

Can you file a GitHub issue about this, linking to your post (or copying it there, whichever is more convenient)? Makes it easier for me to remember to try doing it at some point in the not so distant future =)

2 Likes

Apologies if this has been asked already, but I’m struggling to find a way to toggle/lock multiple layers simultaneously.

The closest I seem to be able to get to is to have a Macro bound to a key which then resolves to a function such as:

static void resetFunctionLeft(uint8_t keyState) {
  if (keyToggledOn(keyState)) {
    LockLayer(FUNCTION_LEFT);
    LockLayer(YTREWQ);
  }
}

However, this unfortunately doesn’t work. I assume because I’m mixing Macros with functions here.

I essentially want to unlock (not toggle) two specific layers. Luckily I know that my context is such that when this function is called, both those layers are enabled, so calling LockLayer will unlock them.

You can use Layer.off(FUNCTION_LEFT); Layer.off(YTREWQ); to do just that.

2 Likes

Brilliant, thanks! This works a treat :slight_smile:

1 Like

Sorry for bumping this old thread but I came across when searching for something else.

I too found LockLayer somewhat not entirely descriptive and confusing for the same reason as @merlin. To me if ShiftToLayer were named TempLayer instead, then LockLayer could be renamed to ToggleLayer and the contrast with TempLayer would convey all that is needed. Normally if you “toggle” something it is understood that it stays on/off until the next toggle happens, IMO.

2 Likes

MomentaryLayer?

It fails the “functions are verbs” heuristic, and kind of causes ToggleLayer to start failing it too, but it does import a handy physical metaphor, if you’re an electronics nerd.

As long as the underlying design allows multiple active layers, MoveToLayer is an ill-named function too. But now that I’ve given up on verb-named functions, SoleLayer might work.

1 Like

Ah, but those macros are not functions; they’re really just a shorthand for naming a Key value. It’s true that something happens when you press a ShiftToLayer(N) key, but that’s also true of Key_A. This is one reason why I think the names LayerShift and LayerLock would be better.