You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Kaleidoscope/src/layers.cpp

163 lines
3.5 KiB

#include "Kaleidoscope.h"
static uint8_t DefaultLayer;
static uint32_t LayerState;
uint8_t Layer_::highestLayer;
Key Layer_::liveCompositeKeymap[ROWS][COLS];
uint8_t Layer_::activeLayers[ROWS][COLS];
8 years ago
Key(*Layer_::getKey)(uint8_t layer, byte row, byte col) = Layer.getKeyFromPROGMEM;
static void handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
8 years ago
if (keymapEntry.keyCode >= MOMENTARY_OFFSET) {
uint8_t target = keymapEntry.keyCode - MOMENTARY_OFFSET;
switch (target) {
case KEYMAP_NEXT:
if (keyToggledOn(keyState))
8 years ago
Layer.next();
else if (keyToggledOff(keyState))
8 years ago
Layer.previous();
break;
case KEYMAP_PREVIOUS:
if (keyToggledOn(keyState))
8 years ago
Layer.previous();
else if (keyToggledOff(keyState))
8 years ago
Layer.next();
break;
default:
if (keyIsPressed(keyState)) {
if (!Layer.isOn(target))
Layer.on(target);
} else if (keyToggledOff(keyState)) {
8 years ago
Layer.off(target);
}
break;
8 years ago
}
} else if (keyToggledOn(keyState)) {
// switch keymap and stay there
8 years ago
if (Layer.isOn(keymapEntry.keyCode) && keymapEntry.keyCode)
Layer.off(keymapEntry.keyCode);
else
Layer.on(keymapEntry.keyCode);
}
}
Key
Layer_::eventHandler(Key mappedKey, byte row, byte col, uint8_t keyState) {
8 years ago
if (mappedKey.flags != (SYNTHETIC | SWITCH_TO_KEYMAP))
return mappedKey;
handleKeymapKeyswitchEvent(mappedKey, keyState);
8 years ago
return Key_NoKey;
}
8 years ago
Layer_::Layer_(void) {
defaultLayer(0);
}
Key
8 years ago
Layer_::getKeyFromPROGMEM(uint8_t layer, byte row, byte col) {
Key key;
8 years ago
key.raw = pgm_read_word(&(keymaps[layer][row][col]));
8 years ago
return key;
}
void
Layer_::updateLiveCompositeKeymap(byte row, byte col) {
int8_t layer = activeLayers[row][col];
liveCompositeKeymap[row][col] = (*getKey)(layer, row, col);
}
void
Layer_::updateActiveLayers(void) {
memset(activeLayers, DefaultLayer, ROWS * COLS);
for (byte row = 0; row < ROWS; row++) {
for (byte col = 0; col < COLS; col++) {
layers: Implement a two-stage cache With the new implementation, there are two lookup functions, because we have two caches, and different parts of the firmware will want to use either this or that (or perhaps both, in rare cases). First of all, we use caches because looking up a key through all the layers is costy, and the cost increases dramatically the more layers we have. Then, we have the `effectiveKeymapCache`, because to have layer behaviours we want, that is, if you hold a key on a layer, release the layer key but continue holding the other, we want for the layered keycode to continue repeating. At the same time, we want other keys to not be affected by the now-turned-off layer. So we update the keycode in the cache on-demand, when the key is pressed or released. (see the top of `handleKeyswitchEvent`). On the other hand, we also have plugins that scan the whole keymap, and do things based on that information, such as highlighting keys that changed between layers. These need to be able to look at a state of where the keymap *should* be, not necessarily where it is. The `effectiveKeymapCache` is not useful here. So we use a `keymapCache` which we update whenever layers change (see `Layer.on` and `Layer.off`), and it updates the cache to show how the keymap should look, without the `effectiveKeymapCache`-induced behaviour. Thus, if we are curious about what a given key will do, use `lookup`. If we are curious what the active layer state describes the key as, use `lookupUncached`. Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
7 years ago
int8_t layer = highestLayer;
while (layer > DefaultLayer) {
if (Layer.isOn(layer)) {
Key mappedKey = (*getKey)(layer, row, col);
if (mappedKey != Key_Transparent) {
activeLayers[row][col] = layer;
layers: Implement a two-stage cache With the new implementation, there are two lookup functions, because we have two caches, and different parts of the firmware will want to use either this or that (or perhaps both, in rare cases). First of all, we use caches because looking up a key through all the layers is costy, and the cost increases dramatically the more layers we have. Then, we have the `effectiveKeymapCache`, because to have layer behaviours we want, that is, if you hold a key on a layer, release the layer key but continue holding the other, we want for the layered keycode to continue repeating. At the same time, we want other keys to not be affected by the now-turned-off layer. So we update the keycode in the cache on-demand, when the key is pressed or released. (see the top of `handleKeyswitchEvent`). On the other hand, we also have plugins that scan the whole keymap, and do things based on that information, such as highlighting keys that changed between layers. These need to be able to look at a state of where the keymap *should* be, not necessarily where it is. The `effectiveKeymapCache` is not useful here. So we use a `keymapCache` which we update whenever layers change (see `Layer.on` and `Layer.off`), and it updates the cache to show how the keymap should look, without the `effectiveKeymapCache`-induced behaviour. Thus, if we are curious about what a given key will do, use `lookup`. If we are curious what the active layer state describes the key as, use `lookupUncached`. Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
7 years ago
break;
}
}
layer--;
}
}
}
}
8 years ago
uint8_t Layer_::top(void) {
for (int8_t i = 31; i >= 0; i--) {
if (bitRead(LayerState, i))
return i;
}
return 0;
}
8 years ago
void Layer_::move(uint8_t layer) {
LayerState = 0;
on(layer);
}
8 years ago
void Layer_::on(uint8_t layer) {
bool wasOn = isOn(layer);
8 years ago
bitSet(LayerState, layer);
if (layer > highestLayer)
highestLayer = layer;
layers: Implement a two-stage cache With the new implementation, there are two lookup functions, because we have two caches, and different parts of the firmware will want to use either this or that (or perhaps both, in rare cases). First of all, we use caches because looking up a key through all the layers is costy, and the cost increases dramatically the more layers we have. Then, we have the `effectiveKeymapCache`, because to have layer behaviours we want, that is, if you hold a key on a layer, release the layer key but continue holding the other, we want for the layered keycode to continue repeating. At the same time, we want other keys to not be affected by the now-turned-off layer. So we update the keycode in the cache on-demand, when the key is pressed or released. (see the top of `handleKeyswitchEvent`). On the other hand, we also have plugins that scan the whole keymap, and do things based on that information, such as highlighting keys that changed between layers. These need to be able to look at a state of where the keymap *should* be, not necessarily where it is. The `effectiveKeymapCache` is not useful here. So we use a `keymapCache` which we update whenever layers change (see `Layer.on` and `Layer.off`), and it updates the cache to show how the keymap should look, without the `effectiveKeymapCache`-induced behaviour. Thus, if we are curious about what a given key will do, use `lookup`. If we are curious what the active layer state describes the key as, use `lookupUncached`. Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
7 years ago
/* If the layer did turn on, update the keymap cache. See layers.h for an
* explanation about the caches we have. */
if (!wasOn)
updateActiveLayers();
}
8 years ago
void Layer_::off(uint8_t layer) {
bool wasOn = isOn(layer);
8 years ago
bitClear(LayerState, layer);
if (layer == highestLayer)
highestLayer = top();
layers: Implement a two-stage cache With the new implementation, there are two lookup functions, because we have two caches, and different parts of the firmware will want to use either this or that (or perhaps both, in rare cases). First of all, we use caches because looking up a key through all the layers is costy, and the cost increases dramatically the more layers we have. Then, we have the `effectiveKeymapCache`, because to have layer behaviours we want, that is, if you hold a key on a layer, release the layer key but continue holding the other, we want for the layered keycode to continue repeating. At the same time, we want other keys to not be affected by the now-turned-off layer. So we update the keycode in the cache on-demand, when the key is pressed or released. (see the top of `handleKeyswitchEvent`). On the other hand, we also have plugins that scan the whole keymap, and do things based on that information, such as highlighting keys that changed between layers. These need to be able to look at a state of where the keymap *should* be, not necessarily where it is. The `effectiveKeymapCache` is not useful here. So we use a `keymapCache` which we update whenever layers change (see `Layer.on` and `Layer.off`), and it updates the cache to show how the keymap should look, without the `effectiveKeymapCache`-induced behaviour. Thus, if we are curious about what a given key will do, use `lookup`. If we are curious what the active layer state describes the key as, use `lookupUncached`. Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
7 years ago
/* If the layer did turn off, update the keymap cache. See layers.h for an
* explanation about the caches we have. */
if (wasOn)
updateActiveLayers();
}
8 years ago
boolean Layer_::isOn(uint8_t layer) {
return bitRead(LayerState, layer);
}
8 years ago
void Layer_::next(void) {
on(top() + 1);
}
8 years ago
void Layer_::previous(void) {
off(top());
}
8 years ago
void Layer_::defaultLayer(uint8_t layer) {
move(layer);
DefaultLayer = layer;
}
8 years ago
uint8_t Layer_::defaultLayer(void) {
return DefaultLayer;
}
8 years ago
uint32_t Layer_::getLayerState(void) {
return LayerState;
}
Layer_ Layer;