|
|
|
#include "Kaleidoscope.h"
|
|
|
|
|
|
|
|
static uint8_t DefaultLayer;
|
|
|
|
static uint32_t LayerState;
|
|
|
|
|
|
|
|
uint8_t Layer_::highestLayer;
|
Cache the keymap when changing layers
Instead of going through all the active layers each time we are looking for a
key, whenever we switch layers, compute the effective keymap, and store the
indexes. This makes the lookup a considerably faster operation, and lookups
happen far more often than layer switching.
This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on
the flip side, the lookup operation is now O(1), which is a very nice property
to have, if you want responsiveness. Changing layers is marginally slower,
however, but even with 32 active layers, doing the computation once, instead of
potentially many dozens of time, is still worth it.
We could further reduce the memory requirements if we stored more columns per
byte, but that's for a future optimization.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
uint8_t Layer_::keyMap[ROWS][COLS];
|
|
|
|
Key(*Layer_::getKey)(uint8_t layer, byte row, byte col) = Layer.getKeyFromPROGMEM;
|
|
|
|
|
|
|
|
static void handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
|
|
|
|
if (keymapEntry.keyCode >= MOMENTARY_OFFSET) {
|
|
|
|
uint8_t target = keymapEntry.keyCode - MOMENTARY_OFFSET;
|
|
|
|
|
|
|
|
if (keyToggledOn(keyState)) {
|
|
|
|
if (target == KEYMAP_NEXT) {
|
|
|
|
Layer.next();
|
|
|
|
} else if (target == KEYMAP_PREVIOUS) {
|
|
|
|
Layer.previous();
|
|
|
|
} else {
|
|
|
|
Layer.on(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (keyToggledOff(keyState)) {
|
|
|
|
if (target == KEYMAP_NEXT) {
|
|
|
|
Layer.previous();
|
|
|
|
} else if (target == KEYMAP_PREVIOUS) {
|
|
|
|
Layer.next();
|
|
|
|
} else {
|
|
|
|
Layer.off(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When toggling a layer off, we mask all keys still held. Masked keys
|
|
|
|
* will be ignored until released and pressed again (see
|
|
|
|
* `handleKeyswitchEvent` in key_events.cpp).
|
|
|
|
*
|
|
|
|
* We do this because when holding a momentary layer switch key, then
|
|
|
|
* pressing and holding some others, they will fire as keys on the
|
|
|
|
* momentary layer. But if we release the momentary layer switch key
|
|
|
|
* before releasing the others, they will continue firing, but from
|
|
|
|
* another layer. When typing fast, it may easily happen that we end up in
|
|
|
|
* a situation where the layer key releases first (in the same scan cycle,
|
|
|
|
* but handled first), and it will emit a key from the wrong layer. So we
|
|
|
|
* ignore held keys after releasing a layer key, until they are pressed
|
|
|
|
* again, to avoid the aforementioned issue.
|
|
|
|
*/
|
|
|
|
KeyboardHardware.maskHeldKeys();
|
|
|
|
}
|
|
|
|
|
|
|
|
// switch keymap and stay there
|
|
|
|
} else if (keyToggledOn(keyState)) {
|
|
|
|
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) {
|
|
|
|
if (mappedKey.flags != (SYNTHETIC | SWITCH_TO_KEYMAP))
|
|
|
|
return mappedKey;
|
|
|
|
|
|
|
|
handleKeymapKeyswitchEvent(mappedKey, keyState);
|
|
|
|
return Key_NoKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
Layer_::Layer_(void) {
|
|
|
|
defaultLayer(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Key
|
|
|
|
Layer_::getKeyFromPROGMEM(uint8_t layer, byte row, byte col) {
|
|
|
|
Key key;
|
|
|
|
|
|
|
|
key.raw = pgm_read_word(&(keymaps[layer][row][col]));
|
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
Cache the keymap when changing layers
Instead of going through all the active layers each time we are looking for a
key, whenever we switch layers, compute the effective keymap, and store the
indexes. This makes the lookup a considerably faster operation, and lookups
happen far more often than layer switching.
This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on
the flip side, the lookup operation is now O(1), which is a very nice property
to have, if you want responsiveness. Changing layers is marginally slower,
however, but even with 32 active layers, doing the computation once, instead of
potentially many dozens of time, is still worth it.
We could further reduce the memory requirements if we stored more columns per
byte, but that's for a future optimization.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
void
|
|
|
|
Layer_::mergeLayers(void) {
|
|
|
|
|
|
|
|
memset(keyMap, DefaultLayer, ROWS * COLS);
|
|
|
|
|
|
|
|
if (LayerState == (uint32_t)(1 << DefaultLayer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (uint8_t r = 0; r < ROWS; r++) {
|
|
|
|
for (uint8_t c = 0; c < COLS; c++) {
|
|
|
|
int8_t layer = highestLayer;
|
|
|
|
|
|
|
|
while (layer > DefaultLayer) {
|
|
|
|
if (Layer.isOn(layer)) {
|
|
|
|
Key mappedKey = (*getKey)(layer, r, c);
|
Cache the keymap when changing layers
Instead of going through all the active layers each time we are looking for a
key, whenever we switch layers, compute the effective keymap, and store the
indexes. This makes the lookup a considerably faster operation, and lookups
happen far more often than layer switching.
This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on
the flip side, the lookup operation is now O(1), which is a very nice property
to have, if you want responsiveness. Changing layers is marginally slower,
however, but even with 32 active layers, doing the computation once, instead of
potentially many dozens of time, is still worth it.
We could further reduce the memory requirements if we stored more columns per
byte, but that's for a future optimization.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
|
|
|
|
if (mappedKey != Key_Transparent) {
|
|
|
|
keyMap[r][c] = layer;
|
|
|
|
break;
|
|
|
|
}
|
Cache the keymap when changing layers
Instead of going through all the active layers each time we are looking for a
key, whenever we switch layers, compute the effective keymap, and store the
indexes. This makes the lookup a considerably faster operation, and lookups
happen far more often than layer switching.
This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on
the flip side, the lookup operation is now O(1), which is a very nice property
to have, if you want responsiveness. Changing layers is marginally slower,
however, but even with 32 active layers, doing the computation once, instead of
potentially many dozens of time, is still worth it.
We could further reduce the memory requirements if we stored more columns per
byte, but that's for a future optimization.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
}
|
|
|
|
layer--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Cache the keymap when changing layers
Instead of going through all the active layers each time we are looking for a
key, whenever we switch layers, compute the effective keymap, and store the
indexes. This makes the lookup a considerably faster operation, and lookups
happen far more often than layer switching.
This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on
the flip side, the lookup operation is now O(1), which is a very nice property
to have, if you want responsiveness. Changing layers is marginally slower,
however, but even with 32 active layers, doing the computation once, instead of
potentially many dozens of time, is still worth it.
We could further reduce the memory requirements if we stored more columns per
byte, but that's for a future optimization.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
8 years ago
|
|
|
}
|
|
|
|
|
|
|
|
Key Layer_::lookup(byte row, byte col) {
|
|
|
|
uint8_t layer = keyMap[row][col];
|
|
|
|
|
|
|
|
return (*getKey)(layer, row, col);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t Layer_::top(void) {
|
|
|
|
for (int8_t i = 31; i >= 0; i--) {
|
|
|
|
if (bitRead(LayerState, i))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Layer_::move(uint8_t layer) {
|
|
|
|
LayerState = 0;
|
|
|
|
on(layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Layer_::on(uint8_t layer) {
|
|
|
|
bitSet(LayerState, layer);
|
|
|
|
if (layer > highestLayer)
|
|
|
|
highestLayer = layer;
|
|
|
|
mergeLayers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Layer_::off(uint8_t layer) {
|
|
|
|
bitClear(LayerState, layer);
|
|
|
|
if (layer == highestLayer)
|
|
|
|
highestLayer = top();
|
|
|
|
mergeLayers();
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean Layer_::isOn(uint8_t layer) {
|
|
|
|
return bitRead(LayerState, layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Layer_::next(void) {
|
|
|
|
on(top() + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Layer_::previous(void) {
|
|
|
|
off(top());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Layer_::defaultLayer(uint8_t layer) {
|
|
|
|
move(layer);
|
|
|
|
DefaultLayer = layer;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t Layer_::defaultLayer(void) {
|
|
|
|
return DefaultLayer;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Layer_::getLayerState(void) {
|
|
|
|
return LayerState;
|
|
|
|
}
|
|
|
|
|
|
|
|
Layer_ Layer;
|