Switch to activation-order for Layers

Previously, we used index-ordering for layers, meaning, we looked keys up based
on the index of active layers. This turned out to be confusing, and in many
cases, limiting, since we couldn't easily shift to a lower layer from a higher
one. As such, index-ordering required careful planning of one's layers, and a
deeper understanding of the system.

This patch switches us to activation-ordering: the layer subsystem now keeps
track of the order in which layers are activated, and uses that order to look
keys up, instead of the index of layers. This makes it easier to understand how
the system works, and allows us to shift to lower layers too.

It does require a bit more resources, since we can't just store a bitmap of
active layers, but need 32 bytes to store the order. We still keep the bitmap,
to make `Layer.isActive()` fast: looking up a bit in the bitmap is more
efficient than walking the active layer array, and this function is often used
in cases where speed matters.

As a side effect of the switch, a number of methods were deprecated, and similar
ones with more appropriate names were introduced. See the updated `UPGRADING.md`
document for more details.

Plugins that used the deprecated methods were updated to use the new ones.

Fixes #857.

Signed-off-by: Gergely Nagy <algernon@keyboard.io>
pull/867/head
Gergely Nagy 5 years ago
parent 78b32f6b80
commit ab3b661cd5
No known key found for this signature in database
GPG Key ID: AC1E90BAC433F68F

@ -12,6 +12,7 @@ If any of this does not make sense to you, or you have trouble updating your .in
- [Bidirectional communication for plugins](#bidirectional-communication-for-plugins) - [Bidirectional communication for plugins](#bidirectional-communication-for-plugins)
- [Consistent timing](#consistent-timing) - [Consistent timing](#consistent-timing)
+ [Breaking changes](#breaking-changes) + [Breaking changes](#breaking-changes)
- [Layer system switched to activation-order](#layer-system-switched-to-activation-order)
- [Deprecation of the HID facade](#deprecation-of-the-hid-facade) - [Deprecation of the HID facade](#deprecation-of-the-hid-facade)
- [Implementation of type Key internally changed from C++ union to class](#implementation-of-type-key-internally-changed-from-union-to-class) - [Implementation of type Key internally changed from C++ union to class](#implementation-of-type-key-internally-changed-from-union-to-class)
- [The `RxCy` macros and peeking into the keyswitch state](#the-rxcy-macros-and-peeking-into-the-keyswitch-state) - [The `RxCy` macros and peeking into the keyswitch state](#the-rxcy-macros-and-peeking-into-the-keyswitch-state)
@ -314,6 +315,26 @@ As a developer, one can continue using `millis()`, but migrating to `Kaleidoscop
## Breaking changes ## Breaking changes
### Layer system switched to activation order
The layer system used to be index-ordered, meaning that we'd look keys up on
layers based on the _index_ of active layers. Kaleidoscope now uses activation
order, which looks up keys based on the order of layer activation.
This means that the following functions are deprecated, and will be removed by **2020-09-16**:
- `Layer.top()`, which used to return the topmost layer index. Use
`Layer.mostRecent()` instead, which returns the most recently activated layer.
Until removed, the old function will return the most recent layer.
- `Layer.deactivateTop()`, which used to return the topmost layer index. Use
`Layer.deactivateMostRecent()` instead. The old function will deactivate the
most recent layer.
- `Layer.getLayerState()`, which used to return a bitmap of the active layers.
With activation-order, a simple bitmap is not enough. For now, we still return
the bitmap, but without the ordering, it is almost useless. Use
`Layer.forEachActiveLayer()` to walk the active layers in order (from least
recent to most).
### Deprecation of the HID facade ### Deprecation of the HID facade
With the new Device APIs it became possible to replace the HID facade (the `kaleidoscope::hid` family of functions) with a driver. As such, the old APIs are deprecated, and will be removed by **2020-09-16**. Please use `Kaleidoscope.hid()` instead. With the new Device APIs it became possible to replace the HID facade (the `kaleidoscope::hid` family of functions) with a driver. As such, the old APIs are deprecated, and will be removed by **2020-09-16**. Please use `Kaleidoscope.hid()` instead.

@ -21,6 +21,10 @@ will be active, without any stacking.
If you want the layer switch to be active only while the key is held, like in If you want the layer switch to be active only while the key is held, like in
the case of modifiers, the `ShiftToLayer(n)` method does just that. the case of modifiers, the `ShiftToLayer(n)` method does just that.
While switching layers this way is similar to how modifiers work, there are
subtle differences. For a longer explanation, see
[later](#layers-transparency-and-how-lookup-works).
## Layer theory ## Layer theory
First of all, the most important thing to remember is that layers are like a First of all, the most important thing to remember is that layers are like a
@ -111,36 +115,28 @@ They're like overrides. Any layer you place on top of the existing stack, will
override keys in the layers below. override keys in the layers below.
When you have multiple layers active, to figure out what a key does, the When you have multiple layers active, to figure out what a key does, the
firmware will first look at the key position on the topmost active layer, and firmware will first look at the key position on the most recently activated
see if there's a non-transparent key there. If there is, it will use that. If layer, and see if there's a non-transparent key there. If there is, it will use
there isn't, it will start walking backwards on the stack of _active_ layers to that. If there isn't, it will start walking backwards on the stack of _active_
find the highest one with a non-transparent key. The first one it finds is whose layers to find the highest one with a non-transparent key. The first one it
key it will use. If it finds none, then a transparent key will act like a blank finds is whose key it will use. If it finds none, then a transparent key will
one, and do nothing. act like a blank one, and do nothing.
It is important to note that transparent keys are looked up from active layers It is important to note that transparent keys are looked up from active layers
only, from highest to lowest. Lets consider that we have three layers, 0, 1, only, from most recently activated to least. Lets consider that we have three
and 2. On a given position, we have a non-transparent key on layers 0 and 1, but layers, 0, 1, and 2. On a given position, we have a non-transparent key on
the same position is transparent on layer 2. If we have layer 0 and 2 active, layers 0 and 1, but the same position is transparent on layer 2. If we have
the key will be looked up from layer 0, because layer 2 is transparent. If we layer 0 and 2 active, the key will be looked up from layer 0, because layer 2 is
activate layer 1 too, it will be looked up from there, since layer 1 is higher transparent. If we activate layer 1 too, it will be looked up from there, since
in the stack than layer 0. layer 1 is higher in the stack than layer 0. In this case, since we activated
layer 1 most recently, layer 2 wouldn't even be looked at.
As we just saw, another important factor is that layers are ordered by their As we just saw, another important factor is that layers are ordered by their
index, not by the order of activation. Whether you activate layer 1 or 2 first order of activation. Whether you activate layer 1 or 2 first, matters. Lets look
doesn't matter. What matters is their index. In other words, when you have layer at another example: we have three layers, 0, 1, and 2. On a given position, we
0 and 2 active, then activate layer 1, that is like placing the layer 1 foil have a non-transparent key on every layer. If we have just layer 0 active, it
between 0 and 2. will be looked up from there. If we activate layer 2, then the firmware will
look there first. If we activate layer 1 as well, then - since now layer 1 is
A side-effect of this is that while you can activate a lower-indexed layer from the most recently activated layer - the firmware will look the code up from
a higher index, the higher indexed one will still override the lower-indexed layer 1, without looking at layer 2. It would only look at layer 2 if the key
one. As such, as a general rule of thumb, you want to order your layers in such was transparent on layer 1.
a way that this doesn't become a problem.
This can be a little confusing at first, but it is easy to get used to with some
practice. Once mastered, layers are an incredibly powerful feature.
Nevertheless, we have the `MoveToLayer(n)` method, where only one layer is ever
active. This way, we do not need to care about transparency, and we can freely
move from a higher layer to a lower one, because the higher one will get
disabled, and will not be able to shadow the lower-indexed one.

@ -0,0 +1,104 @@
/* -*- mode: c++ -*-
* Kaleidoscope - Firmware for computer input devices
* Copyright (C) 2020 Keyboard.io, Inc.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Kaleidoscope.h>
#include <Kaleidoscope-FocusSerial.h>
#include <Kaleidoscope-MouseKeys.h>
enum { PRIMARY, NUMPAD, FUNCTION }; // layers
// *INDENT-OFF*
KEYMAPS(
[PRIMARY] = KEYMAP_STACKED
(___, Key_1, Key_2, Key_3, Key_4, Key_5, XXX,
Key_Backtick, Key_Q, Key_W, Key_E, Key_R, Key_T, Key_Tab,
Key_PageUp, Key_A, Key_S, Key_D, Key_F, Key_G,
Key_PageDown, Key_Z, Key_X, Key_C, Key_V, Key_B, Key_Escape,
Key_LeftControl, Key_Backspace, Key_LeftGui, Key_LeftShift,
ShiftToLayer(FUNCTION),
XXX, Key_6, Key_7, Key_8, Key_9, Key_0, LockLayer(NUMPAD),
Key_Enter, Key_Y, Key_U, Key_I, Key_O, Key_P, Key_Equals,
Key_H, Key_J, Key_K, Key_L, Key_Semicolon, Key_Quote,
Key_RightAlt, Key_N, Key_M, Key_Comma, Key_Period, Key_Slash, Key_Minus,
Key_RightShift, Key_LeftAlt, Key_Spacebar, Key_RightControl,
ShiftToLayer(FUNCTION)),
[NUMPAD] = KEYMAP_STACKED
(___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___,
___, ___, ___, ___, ___, ___, ___,
___, ___, ___, ___,
___,
XXX, ___, Key_7, Key_8, Key_9, Key_KeypadSubtract, ___,
___, ___, Key_4, Key_5, Key_6, Key_KeypadAdd, ___,
___, Key_1, Key_2, Key_3, Key_Equals, ___,
___, ___, Key_0, Key_Period, Key_KeypadMultiply, Key_KeypadDivide, Key_Enter,
___, ___, ___, ___,
___),
[FUNCTION] = KEYMAP_STACKED
(ShiftToLayer(NUMPAD), Key_F1, Key_F2, Key_F3, Key_F4, Key_F5, Key_CapsLock,
Key_Tab, ___, Key_mouseUp, ___, Key_mouseBtnR, Key_mouseWarpEnd, Key_mouseWarpNE,
Key_Home, Key_mouseL, Key_mouseDn, Key_mouseR, Key_mouseBtnL, Key_mouseWarpNW,
Key_End, Key_PrintScreen, Key_Insert, ___, Key_mouseBtnM, Key_mouseWarpSW, Key_mouseWarpSE,
___, Key_Delete, ___, ___,
___,
Consumer_ScanPreviousTrack, Key_F6, Key_F7, Key_F8, Key_F9, Key_F10, Key_F11,
Consumer_PlaySlashPause, Consumer_ScanNextTrack, Key_LeftCurlyBracket, Key_RightCurlyBracket, Key_LeftBracket, Key_RightBracket, Key_F12,
Key_LeftArrow, Key_DownArrow, Key_UpArrow, Key_RightArrow, ___, ___,
Key_PcApplication, Consumer_Mute, Consumer_VolumeDecrement, Consumer_VolumeIncrement, ___, Key_Backslash, Key_Pipe,
___, ___, Key_Enter, ___,
___)
)
// *INDENT-OFF*
namespace kaleidoscope {
class LayerDumper: public Plugin {
public:
LayerDumper() {}
static void dumpLayerState(uint8_t index, uint8_t layer) {
Serial.print(index);
Serial.print(" -> ");
Serial.println(layer);
}
EventHandlerResult onLayerChange() {
Serial.println("Active Layers:");
Layer.forEachActiveLayer(&dumpLayerState);
Serial.println();
return EventHandlerResult::OK;
}
};
}
kaleidoscope::LayerDumper LayerDumper;
KALEIDOSCOPE_INIT_PLUGINS(Focus, LayerDumper, MouseKeys);
void setup() {
Kaleidoscope.setup();
}
void loop() {
Kaleidoscope.loop();
}

@ -39,9 +39,11 @@ extern constexpr Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows
namespace kaleidoscope { namespace kaleidoscope {
uint32_t Layer_::layer_state_; uint32_t Layer_::layer_state_;
uint8_t Layer_::top_active_layer_; uint8_t Layer_::active_layer_count_ = 1;
int8_t Layer_::active_layers_[31];
Key Layer_::live_composite_keymap_[Runtime.device().numKeys()]; Key Layer_::live_composite_keymap_[Runtime.device().numKeys()];
uint8_t Layer_::active_layers_[Runtime.device().numKeys()]; uint8_t Layer_::active_layer_keymap_[Runtime.device().numKeys()];
Layer_::GetKeyFunction Layer_::getKey = &Layer_::getKeyFromPROGMEM; Layer_::GetKeyFunction Layer_::getKey = &Layer_::getKeyFromPROGMEM;
void Layer_::handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) { void Layer_::handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
@ -57,12 +59,12 @@ void Layer_::handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
if (keyToggledOn(keyState)) if (keyToggledOn(keyState))
activateNext(); activateNext();
else if (keyToggledOff(keyState)) else if (keyToggledOff(keyState))
deactivateTop(); deactivateMostRecent();
break; break;
case KEYMAP_PREVIOUS: case KEYMAP_PREVIOUS:
if (keyToggledOn(keyState)) if (keyToggledOn(keyState))
deactivateTop(); deactivateMostRecent();
else if (keyToggledOff(keyState)) else if (keyToggledOff(keyState))
activateNext(); activateNext();
break; break;
@ -112,41 +114,27 @@ Key Layer_::getKeyFromPROGMEM(uint8_t layer, KeyAddr key_addr) {
} }
void Layer_::updateLiveCompositeKeymap(KeyAddr key_addr) { void Layer_::updateLiveCompositeKeymap(KeyAddr key_addr) {
int8_t layer = active_layers_[key_addr.toInt()]; int8_t layer = active_layer_keymap_[key_addr.toInt()];
live_composite_keymap_[key_addr.toInt()] = (*getKey)(layer, key_addr); live_composite_keymap_[key_addr.toInt()] = (*getKey)(layer, key_addr);
} }
void Layer_::updateActiveLayers(void) { void Layer_::updateActiveLayers(void) {
memset(active_layers_, 0, Runtime.device().numKeys()); memset(active_layer_keymap_, 0, Runtime.device().numKeys());
for (auto key_addr : KeyAddr::all()) { for (auto key_addr : KeyAddr::all()) {
int8_t layer = top_active_layer_; int8_t layer_index = active_layer_count_;
while (layer_index > 0) {
while (layer > 0) { uint8_t layer = active_layers_[layer_index - 1];
if (Layer.isActive(layer)) { if (Layer.isActive(layer)) {
Key mappedKey = (*getKey)(layer, key_addr); Key mappedKey = (*getKey)(layer, key_addr);
if (mappedKey != Key_Transparent) { if (mappedKey != Key_Transparent) {
active_layers_[key_addr.toInt()] = layer; active_layer_keymap_[key_addr.toInt()] = layer;
break; break;
} }
} }
layer--; layer_index--;
}
}
}
void Layer_::updateTopActiveLayer(void) {
// If layer_count is set, start there, otherwise search from the
// highest possible layer (MAX_LAYERS) for the top active layer
for (byte i = (layer_count - 1); i > 0; i--) {
if (bitRead(layer_state_, i)) {
top_active_layer_ = i;
return;
} }
} }
// It's not possible to turn off the default layer (see
// updateActiveLayers()), so if no other layers are active:
top_active_layer_ = 0;
} }
void Layer_::move(uint8_t layer) { void Layer_::move(uint8_t layer) {
@ -159,8 +147,9 @@ void Layer_::move(uint8_t layer) {
layer = 0; layer = 0;
} }
bitSet(layer_state_, layer); bitSet(layer_state_, layer);
active_layer_count_ = 1;
active_layers_[0] = layer;
updateTopActiveLayer();
updateActiveLayers(); updateActiveLayers();
kaleidoscope::Hooks::onLayerChange(); kaleidoscope::Hooks::onLayerChange();
@ -179,11 +168,7 @@ void Layer_::activate(uint8_t layer) {
// Otherwise, turn on its bit in layer_state_ // Otherwise, turn on its bit in layer_state_
bitSet(layer_state_, layer); bitSet(layer_state_, layer);
active_layers_[active_layer_count_++] = layer;
// If the target layer is above the previous highest active layer,
// update top_active_layer_
if (layer > top_active_layer_)
updateTopActiveLayer();
// Update the keymap cache (but not live_composite_keymap_; that gets // Update the keymap cache (but not live_composite_keymap_; that gets
// updated separately, when keys toggle on or off. See layers.h) // updated separately, when keys toggle on or off. See layers.h)
@ -201,10 +186,16 @@ void Layer_::deactivate(uint8_t layer) {
// Turn off its bit in layer_state_ // Turn off its bit in layer_state_
bitClear(layer_state_, layer); bitClear(layer_state_, layer);
// If the target layer was the previous highest active layer, // Rearrange the activation order array...
// update top_active_layer_ uint8_t idx = 0;
if (layer == top_active_layer_) for (uint8_t i = active_layer_count_; i > 0; i--) {
updateTopActiveLayer(); if (active_layers_[i] == layer) {
idx = i;
break;
}
}
memmove(&active_layers_[idx], &active_layers_[idx + 1], active_layer_count_ - idx);
active_layer_count_--;
// Update the keymap cache (but not live_composite_keymap_; that gets // Update the keymap cache (but not live_composite_keymap_; that gets
// updated separately, when keys toggle on or off. See layers.h) // updated separately, when keys toggle on or off. See layers.h)
@ -218,11 +209,17 @@ boolean Layer_::isActive(uint8_t layer) {
} }
void Layer_::activateNext(void) { void Layer_::activateNext(void) {
activate(top_active_layer_ + 1); activate(active_layers_[active_layer_count_ - 1] + 1);
} }
void Layer_::deactivateTop(void) { void Layer_::deactivateMostRecent(void) {
deactivate(top_active_layer_); deactivate(active_layers_[active_layer_count_ - 1]);
}
void Layer_::forEachActiveLayer(forEachHandler h) {
for (uint8_t i = 0; i < active_layer_count_; i++) {
(*h)(i, active_layers_[i]);
}
} }
} }

@ -23,6 +23,7 @@
#include "kaleidoscope_internal/device.h" #include "kaleidoscope_internal/device.h"
#include "kaleidoscope_internal/sketch_exploration/sketch_exploration.h" #include "kaleidoscope_internal/sketch_exploration/sketch_exploration.h"
#include "kaleidoscope_internal/shortname.h" #include "kaleidoscope_internal/shortname.h"
#include "kaleidoscope_internal/deprecations.h"
#define START_KEYMAPS __NL__ \ #define START_KEYMAPS __NL__ \
constexpr Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] PROGMEM = { constexpr Key keymaps_linear[][kaleidoscope_internal::device.matrix_rows * kaleidoscope_internal::device.matrix_columns] PROGMEM = {
@ -83,25 +84,31 @@ class Layer_ {
return live_composite_keymap_[key_addr.toInt()]; return live_composite_keymap_[key_addr.toInt()];
} }
static Key lookupOnActiveLayer(KeyAddr key_addr) { static Key lookupOnActiveLayer(KeyAddr key_addr) {
uint8_t layer = active_layers_[key_addr.toInt()]; uint8_t layer = active_layer_keymap_[key_addr.toInt()];
return (*getKey)(layer, key_addr); return (*getKey)(layer, key_addr);
} }
static uint8_t lookupActiveLayer(KeyAddr key_addr) { static uint8_t lookupActiveLayer(KeyAddr key_addr) {
return active_layers_[key_addr.toInt()]; return active_layer_keymap_[key_addr.toInt()];
} }
static void activate(uint8_t layer); static void activate(uint8_t layer);
static void deactivate(uint8_t layer); static void deactivate(uint8_t layer);
static void activateNext(); static void activateNext();
static void deactivateTop(); static void deactivateTop() DEPRECATED(LAYER_DEACTIVATETOP) {
deactivateMostRecent();
}
static void deactivateMostRecent();
static void move(uint8_t layer); static void move(uint8_t layer);
static uint8_t top(void) { static uint8_t top(void) DEPRECATED(LAYER_TOP) {
return top_active_layer_; return mostRecent();
}
static uint8_t mostRecent() {
return active_layers_[active_layer_count_ - 1];
} }
static boolean isActive(uint8_t layer); static boolean isActive(uint8_t layer);
static uint32_t getLayerState(void) { static uint32_t getLayerState(void) DEPRECATED(LAYER_GETLAYERSTATE) {
return layer_state_; return layer_state_;
} }
@ -118,14 +125,20 @@ class Layer_ {
static void updateLiveCompositeKeymap(KeyAddr key_addr); static void updateLiveCompositeKeymap(KeyAddr key_addr);
static void updateActiveLayers(void); static void updateActiveLayers(void);
private:
using forEachHandler = void(*)(uint8_t index, uint8_t layer);
public:
static void forEachActiveLayer(forEachHandler h);
private: private:
static uint32_t layer_state_; static uint32_t layer_state_;
static uint8_t top_active_layer_; static uint8_t active_layer_count_;
static int8_t active_layers_[31];
static Key live_composite_keymap_[kaleidoscope_internal::device.numKeys()]; static Key live_composite_keymap_[kaleidoscope_internal::device.numKeys()];
static uint8_t active_layers_[kaleidoscope_internal::device.numKeys()]; static uint8_t active_layer_keymap_[kaleidoscope_internal::device.numKeys()];
static void handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState); static void handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState);
static void updateTopActiveLayer(void);
}; };
} }

@ -40,7 +40,7 @@ void ColormapEffect::TransientLEDMode::onActivate(void) {
if (!Runtime.has_leds) if (!Runtime.has_leds)
return; return;
parent_->top_layer_ = Layer.top(); parent_->top_layer_ = Layer.mostRecent();
if (parent_->top_layer_ <= parent_->max_layers_) if (parent_->top_layer_ <= parent_->max_layers_)
::LEDPaletteTheme.updateHandler(parent_->map_base_, parent_->top_layer_); ::LEDPaletteTheme.updateHandler(parent_->map_base_, parent_->top_layer_);
} }

@ -59,10 +59,10 @@ EventHandlerResult EEPROMKeymapProgrammer::onKeyswitchEvent(Key &mapped_key, Key
if (state_ == WAIT_FOR_KEY) { if (state_ == WAIT_FOR_KEY) {
if (keyToggledOn(key_state)) { if (keyToggledOn(key_state)) {
update_position_ = Layer.top() * Runtime.device().numKeys() + key_addr.toInt(); update_position_ = Layer.mostRecent() * Runtime.device().numKeys() + key_addr.toInt();
} }
if (keyToggledOff(key_state)) { if (keyToggledOff(key_state)) {
if ((uint16_t)(Layer.top() * Runtime.device().numKeys() + key_addr.toInt()) == update_position_) if ((uint16_t)(Layer.mostRecent() * Runtime.device().numKeys() + key_addr.toInt()) == update_position_)
nextState(); nextState();
} }
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;
@ -70,10 +70,10 @@ EventHandlerResult EEPROMKeymapProgrammer::onKeyswitchEvent(Key &mapped_key, Key
if (state_ == WAIT_FOR_SOURCE_KEY) { if (state_ == WAIT_FOR_SOURCE_KEY) {
if (keyToggledOn(key_state)) { if (keyToggledOn(key_state)) {
new_key_ = Layer.getKeyFromPROGMEM(Layer.top(), key_addr); new_key_ = Layer.getKeyFromPROGMEM(Layer.mostRecent(), key_addr);
} }
if (keyToggledOff(key_state)) { if (keyToggledOff(key_state)) {
if (new_key_ == Layer.getKeyFromPROGMEM(Layer.top(), key_addr)) if (new_key_ == Layer.getKeyFromPROGMEM(Layer.mostRecent(), key_addr))
nextState(); nextState();
} }
return EventHandlerResult::EVENT_CONSUMED; return EventHandlerResult::EVENT_CONSUMED;

@ -36,7 +36,7 @@ void LEDActiveLayerColorEffect::setColormap(const cRGB colormap[]) {
cRGB LEDActiveLayerColorEffect::TransientLEDMode::getActiveColor() { cRGB LEDActiveLayerColorEffect::TransientLEDMode::getActiveColor() {
cRGB color; cRGB color;
uint8_t top_layer = ::Layer.top(); uint8_t top_layer = ::Layer.mostRecent();
color.r = pgm_read_byte(&(parent_->colormap_[top_layer].r)); color.r = pgm_read_byte(&(parent_->colormap_[top_layer].r));
color.g = pgm_read_byte(&(parent_->colormap_[top_layer].g)); color.g = pgm_read_byte(&(parent_->colormap_[top_layer].g));

@ -33,6 +33,19 @@
"For further information and examples on how to do that, \n" __NL__ \ "For further information and examples on how to do that, \n" __NL__ \
"please see UPGRADING.md" "please see UPGRADING.md"
#define _DEPRECATED_MESSAGE_LAYER_DEACTIVATETOP __NL__ \
"`Layer.deactivateTop()` is deprecated.\n" __NL__ \
"Please use `Layer.deactivateMostRecent()` instead."
#define _DEPRECATED_MESSAGE_LAYER_TOP __NL__ \
"`Layer.top()` is deprecated.\n" __NL__ \
"Please use `Layer.mostRecent()` instead."
#define _DEPRECATED_MESSAGE_LAYER_GETLAYERSTATE __NL__ \
"`Layer.getLayerState()` is deprecated.\n" __NL__ \
"Layers are now in activation-order, please use" __NL__ \
"`Layer.forEachActiveLayer()` instead."
#define _DEPRECATED_MESSAGE_HID_FACADE __NL__ \ #define _DEPRECATED_MESSAGE_HID_FACADE __NL__ \
"The HID facade in the `kaleidoscope::hid` namespace is deprecated.\n" __NL__ \ "The HID facade in the `kaleidoscope::hid` namespace is deprecated.\n" __NL__ \
"Please use `Kaleidoscope.hid()` instead." "Please use `Kaleidoscope.hid()` instead."

Loading…
Cancel
Save