diff --git a/examples/Features/KeyGroups/ArrayBasedMembership/ArrayBasedMembership.ino b/examples/Features/KeyGroups/ArrayBasedMembership/ArrayBasedMembership.ino
new file mode 100644
index 0000000000..7682e462ca
--- /dev/null
+++ b/examples/Features/KeyGroups/ArrayBasedMembership/ArrayBasedMembership.ino
@@ -0,0 +1,113 @@
+/* -*- mode: c++ -*-
+ * Basic -- A very basic Kaleidoscope example
+ * Copyright (C) 2018 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 .
+ */
+
+#include "Kaleidoscope.h"
+
+#include "Kaleidoscope-LED-ActiveLayerColor.h"
+
+// This example demonstrates how keys can be grouped by
+// a decision function that relies on a keymap layer kind of array
+// that stores the key group id of every individual key.
+//
+// Please note that the function groupOfKey(..) may only return values
+// in the range [0;5].
+
+enum { AMap, BMap };
+
+/* *INDENT-OFF* */
+KEYMAPS(
+ [AMap] = KEYMAP_STACKED
+ (
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+
+ Key_A, Key_A, Key_A, Key_A,
+ KeyGroup(KEY_GROUP_2, ShiftToLayer(BMap)),
+
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+
+ Key_A, Key_A, Key_A, Key_A,
+ KeyGroup(KEY_GROUP_1, ShiftToLayer(BMap))
+ ),
+
+ [BMap] = KEYMAP_STACKED
+ (
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+
+ Key_B, Key_B, Key_B, Key_B,
+ ___,
+
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+
+ Key_B, Key_B, Key_B, Key_B,
+ ___
+ )
+)
+/* *INDENT-ON* */
+
+KALEIDOSCOPE_INIT_PLUGINS(
+ LEDControl,
+ LEDActiveLayerColorEffect
+)
+
+KEY_GROUP_IDS_STACKED(
+ 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0,
+ 0,
+
+ 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2,
+ 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0,
+ 0
+)
+
+uint8_t groupOfKey(uint8_t row, uint8_t col) {
+ return GROUP_OF_KEY(row, col);
+}
+
+void setup() {
+ Kaleidoscope.setup();
+
+ static const cRGB layerColormap[] PROGMEM = {
+ CRGB(128, 0, 0),
+ CRGB(0, 128, 0)
+ };
+
+ LEDActiveLayerColorEffect.setColormap(layerColormap);
+}
+
+void loop() {
+ Kaleidoscope.loop();
+}
diff --git a/examples/Features/KeyGroups/ConditionalMembership/ConditionalMembership.ino b/examples/Features/KeyGroups/ConditionalMembership/ConditionalMembership.ino
new file mode 100644
index 0000000000..1a5df7f8ec
--- /dev/null
+++ b/examples/Features/KeyGroups/ConditionalMembership/ConditionalMembership.ino
@@ -0,0 +1,94 @@
+/* -*- mode: c++ -*-
+ * Basic -- A very basic Kaleidoscope example
+ * Copyright (C) 2018 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 .
+ */
+
+#include "Kaleidoscope.h"
+
+#include "Kaleidoscope-LED-ActiveLayerColor.h"
+
+// This example demonstrates how keys can be grouped using conditionals
+// in a decision function.
+//
+// Please note that the function groupOfKey(...) may only return values
+// in the range [0;5].
+
+enum { AMap, BMap };
+
+/* *INDENT-OFF* */
+KEYMAPS(
+ [AMap] = KEYMAP_STACKED
+ (
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+
+ Key_A, Key_A, Key_A, Key_A,
+ KeyGroup(KEY_GROUP_1, ShiftToLayer(BMap)),
+
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+
+ Key_A, Key_A, Key_A, Key_A,
+ KeyGroup(KEY_GROUP_0 | KEY_GROUP_2, ShiftToLayer(BMap))
+ ),
+
+ [BMap] = KEYMAP_STACKED
+ (
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+
+ Key_B, Key_B, Key_B, Key_B,
+ ___,
+
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+
+ Key_B, Key_B, Key_B, Key_B,
+ ___
+ )
+)
+/* *INDENT-ON* */
+
+KALEIDOSCOPE_INIT_PLUGINS(
+ LEDControl,
+ LEDActiveLayerColorEffect
+)
+
+uint8_t groupOfKey(uint8_t row, uint8_t col) {
+ return row;
+}
+
+void setup() {
+ Kaleidoscope.setup();
+
+ static const cRGB layerColormap[] PROGMEM = {
+ CRGB(128, 0, 0),
+ CRGB(0, 128, 0)
+ };
+
+ LEDActiveLayerColorEffect.setColormap(layerColormap);
+}
+
+void loop() {
+ Kaleidoscope.loop();
+}
diff --git a/examples/Features/KeyGroups/Default/Default.ino b/examples/Features/KeyGroups/Default/Default.ino
new file mode 100644
index 0000000000..57ba1238d7
--- /dev/null
+++ b/examples/Features/KeyGroups/Default/Default.ino
@@ -0,0 +1,88 @@
+/* -*- mode: c++ -*-
+ * Basic -- A very basic Kaleidoscope example
+ * Copyright (C) 2018 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 .
+ */
+
+#include "Kaleidoscope.h"
+
+#include "Kaleidoscope-LED-ActiveLayerColor.h"
+
+// This example demonstrates the default key grouping mechanism
+// where the left hand is assigned to key group 0 (KEY_GROUP_LEFT_HAND),
+// the right hand to key group 1 (KEY_GROUP_RIGHT_HAND).
+
+enum { AMap, BMap };
+
+/* *INDENT-OFF* */
+KEYMAPS(
+ [AMap] = KEYMAP_STACKED
+ (
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+
+ Key_A, Key_A, Key_A, Key_A,
+ KeyGroup(KEY_GROUP_RIGHT_HAND, ShiftToLayer(BMap)),
+
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+ Key_A, Key_A, Key_A, Key_A, Key_A, Key_A, Key_A,
+
+ Key_A, Key_A, Key_A, Key_A,
+ KeyGroup(KEY_GROUP_LEFT_HAND, ShiftToLayer(BMap))
+ ),
+
+ [BMap] = KEYMAP_STACKED
+ (
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+
+ Key_B, Key_B, Key_B, Key_B,
+ ___,
+
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+ Key_B, Key_B, Key_B, Key_B, Key_B, Key_B, Key_B,
+
+ Key_B, Key_B, Key_B, Key_B,
+ ___
+ )
+)
+/* *INDENT-ON* */
+
+KALEIDOSCOPE_INIT_PLUGINS(
+ LEDControl,
+ LEDActiveLayerColorEffect
+)
+
+void setup() {
+ Kaleidoscope.setup();
+
+ static const cRGB layerColormap[] PROGMEM = {
+ CRGB(128, 0, 0),
+ CRGB(0, 128, 0)
+ };
+
+ LEDActiveLayerColorEffect.setColormap(layerColormap);
+}
+
+void loop() {
+ Kaleidoscope.loop();
+}
diff --git a/src/Kaleidoscope-KeyGroups.h b/src/Kaleidoscope-KeyGroups.h
new file mode 100644
index 0000000000..73497b7973
--- /dev/null
+++ b/src/Kaleidoscope-KeyGroups.h
@@ -0,0 +1,20 @@
+/* -*- mode: c++ -*-
+ * Kaleidoscope-Hardware-EZ-ErgoDox -- ErgoDox hardware support for Kaleidoscope
+ * Copyright (C) 2018 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, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 .
+ */
+
+#pragma once
+#include "kaleidoscope/key_groups.h"
diff --git a/src/kaleidoscope/Hardware.h b/src/kaleidoscope/Hardware.h
index 35a303a4b7..f7bef6bd9d 100644
--- a/src/kaleidoscope/Hardware.h
+++ b/src/kaleidoscope/Hardware.h
@@ -50,11 +50,18 @@
typedef struct cRGB cRGB;
namespace kaleidoscope {
+
/** Kaleidoscope Hardware base class.
* Essential methods all hardware libraries must implement.
*/
class Hardware {
public:
+
+ // This class method can be overridden by hardware implementations.
+ constexpr static bool isOnLeftHalf(uint8_t /*row*/, uint8_t /*col*/) {
+ return true;
+ }
+
/**
* @defgroup kaleidoscope_hardware_leds Kaleidoscope::Hardware/LEDs
* @{
diff --git a/src/kaleidoscope/hardware/ez/ErgoDox.h b/src/kaleidoscope/hardware/ez/ErgoDox.h
index 8724956067..ca17047e35 100644
--- a/src/kaleidoscope/hardware/ez/ErgoDox.h
+++ b/src/kaleidoscope/hardware/ez/ErgoDox.h
@@ -56,6 +56,10 @@ class ErgoDox : public kaleidoscope::Hardware {
static constexpr byte matrix_rows = 14;
static constexpr int8_t led_count = 0;
+ static constexpr bool isOnLeftHalf(uint8_t row, uint8_t /*col*/) {
+ return row < 7;
+ }
+
void scanMatrix(void);
void readMatrix(void);
void actOnMatrixScan(void);
diff --git a/src/kaleidoscope/hardware/kbdfans/KBD4x.h b/src/kaleidoscope/hardware/kbdfans/KBD4x.h
index 11951015d4..de914c42ab 100644
--- a/src/kaleidoscope/hardware/kbdfans/KBD4x.h
+++ b/src/kaleidoscope/hardware/kbdfans/KBD4x.h
@@ -67,6 +67,9 @@ class KBD4x: public kaleidoscope::hardware::ATMegaKeyboard {
static constexpr int8_t led_count = 0;
+ // TODO: Implement
+ // static constexpr bool isOnLeftHalf(uint8_t row, uint8_t col);
+
void resetDevice();
};
diff --git a/src/kaleidoscope/hardware/keyboardio/Model01.cpp b/src/kaleidoscope/hardware/keyboardio/Model01.cpp
index 0db6545843..7487eac396 100644
--- a/src/kaleidoscope/hardware/keyboardio/Model01.cpp
+++ b/src/kaleidoscope/hardware/keyboardio/Model01.cpp
@@ -244,7 +244,6 @@ void Model01::rebootBootloader() {
// halves, with eight keys per logical row.
constexpr byte HIGH_BIT = B10000000;
-constexpr byte HAND_BIT = B00001000;
constexpr byte ROW_BITS = B00110000;
constexpr byte COL_BITS = B00000111;
diff --git a/src/kaleidoscope/hardware/keyboardio/Model01.h b/src/kaleidoscope/hardware/keyboardio/Model01.h
index 5457f87bd1..1494532f99 100644
--- a/src/kaleidoscope/hardware/keyboardio/Model01.h
+++ b/src/kaleidoscope/hardware/keyboardio/Model01.h
@@ -37,6 +37,14 @@ namespace keyboardio {
class Model01 : public kaleidoscope::Hardware {
public:
+
+ static constexpr byte HAND_BIT = B00001000;
+
+ static constexpr bool isOnLeftHalf(uint8_t /*row*/, uint8_t col) {
+ // If HAND_BIT is set, we are on the right hand side
+ return !(col & HAND_BIT);
+ }
+
Model01(void);
static constexpr byte matrix_rows = 4;
diff --git a/src/kaleidoscope/hardware/olkb/Planck.h b/src/kaleidoscope/hardware/olkb/Planck.h
index e42eb15cd5..c331df9100 100644
--- a/src/kaleidoscope/hardware/olkb/Planck.h
+++ b/src/kaleidoscope/hardware/olkb/Planck.h
@@ -40,6 +40,9 @@ class Planck: public kaleidoscope::hardware::ATMegaKeyboard {
COL_PIN_LIST({ PIN_F1, PIN_F0, PIN_B0, PIN_C7, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_D4, PIN_D6, PIN_B4, PIN_D7 })
);
+ // TODO: Implement
+ // static constexpr bool isOnLeftHalf(uint8_t row, uint8_t col);
+
static constexpr int8_t led_count = 0;
};
diff --git a/src/kaleidoscope/hardware/softhruf/Splitography.h b/src/kaleidoscope/hardware/softhruf/Splitography.h
index 01d42b779e..98a11cbb9e 100644
--- a/src/kaleidoscope/hardware/softhruf/Splitography.h
+++ b/src/kaleidoscope/hardware/softhruf/Splitography.h
@@ -68,6 +68,9 @@ class Splitography: public kaleidoscope::hardware::ATMegaKeyboard {
COL_PIN_LIST({ PIN_F0, PIN_F1, PIN_F4, PIN_F5, PIN_F6, PIN_F7, PIN_C7, PIN_C6, PIN_B6, PIN_B5, PIN_B4, PIN_D7 })
);
+ // TODO: Implement
+ // static constexpr bool isOnLeftHalf(uint8_t row, uint8_t col);
+
static constexpr int8_t led_count = 0;
};
diff --git a/src/kaleidoscope/hardware/technomancy/Atreus.h b/src/kaleidoscope/hardware/technomancy/Atreus.h
index 00ce781b98..ac1c474d1e 100644
--- a/src/kaleidoscope/hardware/technomancy/Atreus.h
+++ b/src/kaleidoscope/hardware/technomancy/Atreus.h
@@ -67,6 +67,9 @@ class Atreus: public kaleidoscope::hardware::ATMegaKeyboard {
void resetDevice();
+ // TODO: Implement
+ // static constexpr bool isOnLeftHalf(uint8_t row, uint8_t col);
+
protected:
};
diff --git a/src/kaleidoscope/key_groups.h b/src/kaleidoscope/key_groups.h
new file mode 100644
index 0000000000..3bd490d137
--- /dev/null
+++ b/src/kaleidoscope/key_groups.h
@@ -0,0 +1,94 @@
+/* Kaleidoscope - Firmware for computer input devices
+ * Copyright (C) 2013-2018 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 .
+ */
+
+#pragma once
+
+#include "kaleidoscope/key_defs.h"
+
+static constexpr uint8_t encodeKeyGroupFlags(uint8_t key_group_flags) {
+
+ // We use the unused bits in the key flags of layer change/toggle keycodes
+ // to code the key groups that are affected by a layer operation.
+ // Every bit thereby represents one keygroup.
+ // Unfortunately, the unused bits that are available dont form
+ // a contiguous part of the flags byte.
+ //
+ // The following bits of the key flags bitfield are already used:
+ // SYNTHETIC(B01000000) | SWITCH_TO_KEYMAP(B00000100)
+ //
+ // Thus, the following bits (those set to one) B10111011 can be used
+ // to code affected key groups. Every group is assigned one bit.
+ // Because of this, only a maximum of six key groups can be defined.
+ // If all flags are set to zero, this means the same as if all related
+ // flags are set to one. This is necessary to provide backwards compatibility
+ // for those layer toggle/switch commands that are not associated with
+ // key groups. Those commands then mean "all groups affected".
+
+ return (key_group_flags & B00000011)
+ | ((key_group_flags & B00011100) << 1)
+ | ((key_group_flags & B00100000) << 2);
+}
+
+static constexpr uint8_t decodeKeyGroupFlags(uint8_t coded_flags) {
+
+ return (coded_flags & B00000011)
+ | ((coded_flags & B00111000) >> 1)
+ | ((coded_flags & B10000000) >> 2);
+}
+
+inline static constexpr Key KeyGroup(uint8_t key_group_flags, Key k) {
+ return Key(k.keyCode, k.flags | encodeKeyGroupFlags(key_group_flags));
+}
+
+// Key group flags
+static constexpr uint8_t KEY_GROUP_0 = B00000001;
+static constexpr uint8_t KEY_GROUP_1 = B00000010;
+static constexpr uint8_t KEY_GROUP_2 = B00000100;
+static constexpr uint8_t KEY_GROUP_3 = B00001000;
+static constexpr uint8_t KEY_GROUP_4 = B00010000;
+static constexpr uint8_t KEY_GROUP_5 = B00100000;
+
+// The default configuration of key grouping is that group 0 is assigned
+// to the left hand, group 1 to the right. We provide constants to be used in
+// user sketches.
+static constexpr uint8_t KEY_GROUP_LEFT_HAND = KEY_GROUP_0;
+static constexpr uint8_t KEY_GROUP_RIGHT_HAND = KEY_GROUP_1;
+
+// This is also the default if no key group is assigned to a layer toggle
+// keycode.
+static constexpr uint8_t ALL_KEY_GROUPS = B00111111;
+
+namespace kaleidoscope {
+
+// The maximum number of possible key groups. This cannot be exceeded
+// as there are not more than six unused bits in the key flags left to
+// code the keygroup.
+static constexpr uint8_t max_num_key_groups = 6;
+
+static constexpr bool isKeyGroupFlagSet(uint8_t key_group_flags, uint8_t flag_id) {
+ return key_group_flags & (B00000001 << flag_id);
+}
+
+} // end kaleidoscope
+
+#define KEY_GROUP_IDS_STACKED(group_ids_per_key...) \
+ const uint8_t key_groups[ROWS][COLS] PROGMEM = KEYMAP_STACKED(group_ids_per_key);
+
+#define KEY_GROUP_IDS(group_ids_per_key...) \
+ const uint8_t key_groups[ROWS][COLS] PROGMEM = KEYMAP(group_ids_per_key);
+
+#define GROUP_OF_KEY(row, col) \
+ pgm_read_byte(&(key_groups[row][col]))
diff --git a/src/kaleidoscope/layers.cpp b/src/kaleidoscope/layers.cpp
index e581703ec9..00f01210b3 100644
--- a/src/kaleidoscope/layers.cpp
+++ b/src/kaleidoscope/layers.cpp
@@ -27,29 +27,37 @@
uint8_t layer_count __attribute__((weak)) = MAX_LAYERS;
namespace kaleidoscope {
-uint32_t Layer_::layer_state_;
-uint8_t Layer_::top_active_layer_;
+uint32_t Layer_::layer_state_[kaleidoscope::max_num_key_groups] = { 0, 0, 0, 0, 0, 0 };
+uint8_t Layer_::top_active_layer_[kaleidoscope::max_num_key_groups] = { 0, 0, 0, 0, 0, 0 };
Key Layer_::live_composite_keymap_[ROWS][COLS];
uint8_t Layer_::active_layers_[ROWS][COLS];
Key(*Layer_::getKey)(uint8_t layer, byte row, byte col) = Layer.getKeyFromPROGMEM;
void Layer_::handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
+
+ uint8_t key_group_flags = decodeKeyGroupFlags(keymapEntry.flags);
+
+ if (key_group_flags == 0) {
+ key_group_flags = ALL_KEY_GROUPS;
+ }
+
if (keymapEntry.keyCode >= LAYER_SHIFT_OFFSET) {
+
uint8_t target = keymapEntry.keyCode - LAYER_SHIFT_OFFSET;
switch (target) {
case KEYMAP_NEXT:
if (keyToggledOn(keyState))
- activateNext();
+ activateNext(key_group_flags);
else if (keyToggledOff(keyState))
- deactivateTop();
+ deactivateTop(key_group_flags);
break;
case KEYMAP_PREVIOUS:
if (keyToggledOn(keyState))
- deactivateTop();
+ deactivateTop(key_group_flags);
else if (keyToggledOff(keyState))
- activateNext();
+ activateNext(key_group_flags);
break;
default:
@@ -68,24 +76,24 @@ void Layer_::handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState) {
* layer will toggle back on in the same cycle.
*/
if (keyIsPressed(keyState)) {
- if (!Layer.isActive(target))
- activate(target);
+ if (!Layer.isActive(target, key_group_flags))
+ activate(target, key_group_flags);
} else if (keyToggledOff(keyState)) {
- deactivate(target);
+ deactivate(target, key_group_flags);
}
break;
}
} else if (keyToggledOn(keyState)) {
// switch keymap and stay there
- if (Layer.isActive(keymapEntry.keyCode) && keymapEntry.keyCode)
- deactivate(keymapEntry.keyCode);
+ if (Layer.isActive(keymapEntry.keyCode, key_group_flags) && keymapEntry.keyCode)
+ deactivate(keymapEntry.keyCode, key_group_flags);
else
- activate(keymapEntry.keyCode);
+ activate(keymapEntry.keyCode, key_group_flags);
}
}
Key Layer_::eventHandler(Key mappedKey, byte row, byte col, uint8_t keyState) {
- if (mappedKey.flags != (SYNTHETIC | SWITCH_TO_KEYMAP))
+ if (!((mappedKey.flags & SYNTHETIC) && (mappedKey.flags & SWITCH_TO_KEYMAP)))
return mappedKey;
handleKeymapKeyswitchEvent(mappedKey, keyState);
@@ -109,10 +117,13 @@ void Layer_::updateActiveLayers(void) {
memset(active_layers_, 0, ROWS * COLS);
for (byte row = 0; row < ROWS; row++) {
for (byte col = 0; col < COLS; col++) {
- int8_t layer = top_active_layer_;
+
+ uint8_t key_group = groupOfKey(row, col);
+
+ int8_t layer = top_active_layer_[key_group];
while (layer > 0) {
- if (Layer.isActive(layer)) {
+ if (Layer.isActive(layer, key_group)) {
Key mappedKey = (*getKey)(layer, row, col);
if (mappedKey != Key_Transparent) {
@@ -126,43 +137,67 @@ void Layer_::updateActiveLayers(void) {
}
}
-void Layer_::updateTopActiveLayer(void) {
+void Layer_::updateTopActiveLayer(uint8_t key_group) {
+
// 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;
+ if (bitRead(layer_state_[key_group], i)) {
+ top_active_layer_[key_group] = 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;
+ top_active_layer_[key_group] = 0;
}
-void Layer_::move(uint8_t layer) {
- layer_state_ = 0;
- activate(layer);
+void Layer_::move(uint8_t layer, uint8_t key_group_flags) {
+
+ for (uint8_t key_group = 0; key_group < kaleidoscope::max_num_key_groups; ++key_group) {
+
+ if (!isKeyGroupFlagSet(key_group_flags, key_group)) {
+ continue;
+ }
+
+ layer_state_[key_group] = 0;
+ }
+
+ activate(layer, key_group_flags);
}
// Activate a given layer
-void Layer_::activate(uint8_t layer) {
- // If we're trying to turn on a layer that doesn't exist, abort (but
- // if the keymap wasn't defined using the KEYMAPS() macro, proceed anyway
- if (layer >= layer_count)
- return;
+void Layer_::activate(uint8_t layer, uint8_t key_group_flags) {
+
+ bool changes_applied = false;
+
+ for (uint8_t key_group = 0; key_group < kaleidoscope::max_num_key_groups; ++key_group) {
+
+ if (!isKeyGroupFlagSet(key_group_flags, key_group)) {
+ continue;
+ }
+
+ // If we're trying to turn on a layer that doesn't exist, abort (but
+ // if the keymap wasn't defined using the KEYMAPS() macro, proceed anyway
+ if (layer >= layer_count)
+ return;
+
+ // If the target layer was already on, return
+ if (isActive(layer, key_group_flags))
+ continue;
- // If the target layer was already on, return
- if (isActive(layer))
- return;
+ changes_applied = true;
- // Otherwise, turn on its bit in layer_state_
- bitSet(layer_state_, layer);
+ // Otherwise, turn on its bit in layer_state_
+ bitSet(layer_state_[key_group], layer);
- // If the target layer is above the previous highest active layer,
- // update top_active_layer_
- if (layer > top_active_layer_)
- updateTopActiveLayer();
+ // If the target layer is above the previous highest active layer,
+ // update top_active_layer_
+ if (layer > top_active_layer_[key_group])
+ updateTopActiveLayer(key_group);
+ }
+
+ if (!changes_applied) return;
// Update the keymap cache (but not live_composite_keymap_; that gets
// updated separately, when keys toggle on or off. See layers.h)
@@ -172,18 +207,33 @@ void Layer_::activate(uint8_t layer) {
}
// Deactivate a given layer
-void Layer_::deactivate(uint8_t layer) {
- // If the target layer was already off, return
- if (!bitRead(layer_state_, layer))
- return;
- // Turn off its bit in layer_state_
- bitClear(layer_state_, layer);
+void Layer_::deactivate(uint8_t layer, uint8_t key_group_flags) {
+
+ bool changes_applied = false;
+
+ for (uint8_t key_group = 0; key_group < kaleidoscope::max_num_key_groups; ++key_group) {
+
+ if (!isKeyGroupFlagSet(key_group_flags, key_group)) {
+ continue;
+ }
+
+ // If the target layer was already off, return
+ if (!bitRead(layer_state_[key_group], layer))
+ continue;
+
+ changes_applied = true;
+
+ // Turn off its bit in layer_state_
+ bitClear(layer_state_[key_group], layer);
+
+ // If the target layer was the previous highest active layer,
+ // update top_active_layer_
+ if (layer == top_active_layer_[key_group])
+ updateTopActiveLayer(key_group);
+ }
- // If the target layer was the previous highest active layer,
- // update top_active_layer_
- if (layer == top_active_layer_)
- updateTopActiveLayer();
+ if (!changes_applied) return;
// Update the keymap cache (but not live_composite_keymap_; that gets
// updated separately, when keys toggle on or off. See layers.h)
@@ -192,18 +242,37 @@ void Layer_::deactivate(uint8_t layer) {
kaleidoscope::Hooks::onLayerChange();
}
-boolean Layer_::isActive(uint8_t layer) {
- return bitRead(layer_state_, layer);
+boolean Layer_::isActive(uint8_t layer, uint8_t key_group) {
+ return bitRead(layer_state_[key_group], layer);
}
-void Layer_::activateNext(void) {
- activate(top_active_layer_ + 1);
+void Layer_::activateNext(uint8_t key_group_flags) {
+
+ for (uint8_t key_group = 0; key_group < kaleidoscope::max_num_key_groups; ++key_group) {
+
+ if (!isKeyGroupFlagSet(key_group_flags, key_group)) {
+ continue;
+ }
+ activate(top_active_layer_[key_group] + 1, key_group_flags);
+ }
+}
+
+void Layer_::deactivateTop(uint8_t key_group_flags) {
+
+ for (uint8_t key_group = 0; key_group < kaleidoscope::max_num_key_groups; ++key_group) {
+
+ if (!isKeyGroupFlagSet(key_group_flags, key_group)) {
+ continue;
+ }
+ deactivate(top_active_layer_[key_group]);
+ }
}
-void Layer_::deactivateTop(void) {
- deactivate(top_active_layer_);
}
+__attribute__((weak))
+uint8_t groupOfKey(uint8_t row, uint8_t col) {
+ return HARDWARE_IMPLEMENTATION::isOnLeftHalf(row, col) ? 0 : 1;
}
kaleidoscope::Layer_ Layer;
diff --git a/src/kaleidoscope/layers.h b/src/kaleidoscope/layers.h
index 587a5e5aa4..72ab68c69c 100644
--- a/src/kaleidoscope/layers.h
+++ b/src/kaleidoscope/layers.h
@@ -18,6 +18,7 @@
#include
#include "kaleidoscope/key_defs.h"
+#include "kaleidoscope/key_groups.h"
#include KALEIDOSCOPE_HARDWARE_H
extern const Key keymaps[][ROWS][COLS];
@@ -33,6 +34,7 @@ extern const Key keymaps[][ROWS][COLS];
extern uint8_t layer_count;
namespace kaleidoscope {
+
class Layer_ {
public:
Layer_() {}
@@ -77,19 +79,19 @@ class Layer_ {
return active_layers_[row][col];
}
- static void activate(uint8_t layer);
- static void deactivate(uint8_t layer);
- static void activateNext();
- static void deactivateTop();
- static void move(uint8_t layer);
+ static void activate(uint8_t layer, uint8_t key_group_flags = ALL_KEY_GROUPS);
+ static void deactivate(uint8_t layer, uint8_t key_group_flags = ALL_KEY_GROUPS);
+ static void activateNext(uint8_t key_group_flags = ALL_KEY_GROUPS);
+ static void deactivateTop(uint8_t key_group_flags = ALL_KEY_GROUPS);
+ static void move(uint8_t layer, uint8_t key_group_flags = ALL_KEY_GROUPS);
- static uint8_t top(void) {
- return top_active_layer_;
+ static uint8_t top(uint8_t key_group = 0) {
+ return top_active_layer_[key_group];
}
- static boolean isActive(uint8_t layer);
+ static boolean isActive(uint8_t layer, uint8_t key_group = 0);
- static uint32_t getLayerState(void) {
- return layer_state_;
+ static uint32_t getLayerState(uint8_t key_group = 0) {
+ return layer_state_[key_group];
}
static Key eventHandler(Key mappedKey, byte row, byte col, uint8_t keyState);
@@ -102,14 +104,18 @@ class Layer_ {
static void updateActiveLayers(void);
private:
- static uint32_t layer_state_;
- static uint8_t top_active_layer_;
+ static uint32_t layer_state_[kaleidoscope::max_num_key_groups];
+ static uint8_t top_active_layer_[kaleidoscope::max_num_key_groups];
static Key live_composite_keymap_[ROWS][COLS];
static uint8_t active_layers_[ROWS][COLS];
static void handleKeymapKeyswitchEvent(Key keymapEntry, uint8_t keyState);
- static void updateTopActiveLayer(void);
+
+ static void updateTopActiveLayer(uint8_t key_group);
};
+
}
+extern uint8_t groupOfKey(uint8_t row, uint8_t col);
+
extern kaleidoscope::Layer_ Layer;
diff --git a/src/kaleidoscope/plugin/Colormap.cpp b/src/kaleidoscope/plugin/Colormap.cpp
index ac7b3144b1..bb18670729 100644
--- a/src/kaleidoscope/plugin/Colormap.cpp
+++ b/src/kaleidoscope/plugin/Colormap.cpp
@@ -28,7 +28,6 @@ namespace plugin {
uint16_t ColormapEffect::map_base_;
uint8_t ColormapEffect::max_layers_;
-uint8_t ColormapEffect::top_layer_;
void ColormapEffect::max_layers(uint8_t max_) {
if (map_base_ != 0)
@@ -42,14 +41,18 @@ void ColormapEffect::onActivate(void) {
if (!Kaleidoscope.has_leds)
return;
- top_layer_ = Layer.top();
- if (top_layer_ <= max_layers_)
- ::LEDPaletteTheme.updateHandler(map_base_, top_layer_);
+ for (uint8_t row = 0; row < ROWS; ++row) {
+ for (uint8_t col = 0; col < COLS; ++col) {
+ refreshAt(row, col);
+ }
+ }
}
void ColormapEffect::refreshAt(byte row, byte col) {
- if (top_layer_ <= max_layers_)
- ::LEDPaletteTheme.refreshAt(map_base_, top_layer_, row, col);
+ uint8_t key_group = groupOfKey(row, col);
+ uint8_t top_layer = ::Layer.top(key_group);
+ if (top_layer <= max_layers_)
+ ::LEDPaletteTheme.refreshAt(map_base_, top_layer, row, col);
}
EventHandlerResult ColormapEffect::onLayerChange() {
diff --git a/src/kaleidoscope/plugin/Colormap.h b/src/kaleidoscope/plugin/Colormap.h
index 7837a8c354..6219b3bbc1 100644
--- a/src/kaleidoscope/plugin/Colormap.h
+++ b/src/kaleidoscope/plugin/Colormap.h
@@ -36,7 +36,6 @@ class ColormapEffect : public LEDMode {
void refreshAt(byte row, byte col) final;
private:
- static uint8_t top_layer_;
static uint8_t max_layers_;
static uint16_t map_base_;
};
diff --git a/src/kaleidoscope/plugin/EEPROM-Keymap-Programmer.cpp b/src/kaleidoscope/plugin/EEPROM-Keymap-Programmer.cpp
index 956c6bb866..1c61f60a12 100644
--- a/src/kaleidoscope/plugin/EEPROM-Keymap-Programmer.cpp
+++ b/src/kaleidoscope/plugin/EEPROM-Keymap-Programmer.cpp
@@ -56,9 +56,11 @@ EventHandlerResult EEPROMKeymapProgrammer::onKeyswitchEvent(Key &mapped_key, byt
if (state_ == WAIT_FOR_KEY) {
if (keyToggledOn(key_state)) {
+ // TODO: Check use of Layer.top() in presence of multiple key groups
update_position_ = Layer.top() * ROWS * COLS + row * COLS + col;
}
if (keyToggledOff(key_state)) {
+ // TODO: Check use of Layer.top() in presence of multiple key groups
if ((uint16_t)(Layer.top() * ROWS * COLS + row * COLS + col) == update_position_)
nextState();
}
@@ -67,9 +69,11 @@ EventHandlerResult EEPROMKeymapProgrammer::onKeyswitchEvent(Key &mapped_key, byt
if (state_ == WAIT_FOR_SOURCE_KEY) {
if (keyToggledOn(key_state)) {
+ // TODO: Check use of Layer.top() in presence of multiple key groups
new_key_ = Layer.getKeyFromPROGMEM(Layer.top(), row, col);
}
if (keyToggledOff(key_state)) {
+ // TODO: Check use of Layer.top() in presence of multiple key groups
if (new_key_ == Layer.getKeyFromPROGMEM(Layer.top(), row, col))
nextState();
}
diff --git a/src/kaleidoscope/plugin/LED-ActiveLayerColor.cpp b/src/kaleidoscope/plugin/LED-ActiveLayerColor.cpp
index ae7fd6185c..8136839d16 100644
--- a/src/kaleidoscope/plugin/LED-ActiveLayerColor.cpp
+++ b/src/kaleidoscope/plugin/LED-ActiveLayerColor.cpp
@@ -20,18 +20,16 @@
namespace kaleidoscope {
namespace plugin {
-cRGB LEDActiveLayerColorEffect::active_color_;
+// cRGB LEDActiveLayerColorEffect::active_color_;
const cRGB *LEDActiveLayerColorEffect::colormap_;
void LEDActiveLayerColorEffect::setColormap(const cRGB colormap[]) {
colormap_ = colormap;
}
-cRGB LEDActiveLayerColorEffect::getActiveColor() {
+cRGB LEDActiveLayerColorEffect::getActiveColor(uint8_t top_layer) {
cRGB color;
- uint8_t top_layer = ::Layer.top();
-
color.r = pgm_read_byte(&(colormap_[top_layer].r));
color.g = pgm_read_byte(&(colormap_[top_layer].g));
color.b = pgm_read_byte(&(colormap_[top_layer].b));
@@ -42,13 +40,22 @@ cRGB LEDActiveLayerColorEffect::getActiveColor() {
void LEDActiveLayerColorEffect::onActivate(void) {
if (!Kaleidoscope.has_leds)
return;
+ /*
+ active_color_ = getActiveColor();
+ ::LEDControl.set_all_leds_to(active_color_);*/
- active_color_ = getActiveColor();
- ::LEDControl.set_all_leds_to(active_color_);
+ for (uint8_t row = 0; row < ROWS; ++row) {
+ for (uint8_t col = 0; col < COLS; ++col) {
+ refreshAt(row, col);
+ }
+ }
}
void LEDActiveLayerColorEffect::refreshAt(byte row, byte col) {
- ::LEDControl.setCrgbAt(row, col, active_color_);
+ uint8_t key_group = groupOfKey(row, col);
+ uint8_t top_layer = ::Layer.top(key_group);
+ cRGB active_color = getActiveColor(top_layer);
+ ::LEDControl.setCrgbAt(row, col, active_color);
}
EventHandlerResult LEDActiveLayerColorEffect::onLayerChange() {
diff --git a/src/kaleidoscope/plugin/LED-ActiveLayerColor.h b/src/kaleidoscope/plugin/LED-ActiveLayerColor.h
index 611b6b19f3..38f2738630 100644
--- a/src/kaleidoscope/plugin/LED-ActiveLayerColor.h
+++ b/src/kaleidoscope/plugin/LED-ActiveLayerColor.h
@@ -34,9 +34,9 @@ class LEDActiveLayerColorEffect : public LEDMode {
private:
static const cRGB *colormap_;
- static cRGB active_color_;
+// static cRGB active_color_;
- static cRGB getActiveColor();
+ static cRGB getActiveColor(uint8_t top_layer);
};
}
}
diff --git a/src/kaleidoscope/plugin/LED-ActiveModColor.cpp b/src/kaleidoscope/plugin/LED-ActiveModColor.cpp
index 8b49f20fa7..8b18b082ff 100644
--- a/src/kaleidoscope/plugin/LED-ActiveModColor.cpp
+++ b/src/kaleidoscope/plugin/LED-ActiveModColor.cpp
@@ -80,7 +80,7 @@ EventHandlerResult ActiveModColorEffect::beforeReportingState() {
if (layer >= LAYER_SHIFT_OFFSET)
layer -= LAYER_SHIFT_OFFSET;
- if (Layer.isActive(layer))
+ if (Layer.isActive(layer, groupOfKey(r, c)))
::LEDControl.setCrgbAt(r, c, highlight_color);
else
::LEDControl.refreshAt(r, c);
diff --git a/src/kaleidoscope/plugin/NumPad.cpp b/src/kaleidoscope/plugin/NumPad.cpp
index 64257af70f..d3a6fd6432 100644
--- a/src/kaleidoscope/plugin/NumPad.cpp
+++ b/src/kaleidoscope/plugin/NumPad.cpp
@@ -86,6 +86,7 @@ void NumPad::setKeyboardLEDColors(void) {
}
EventHandlerResult NumPad::afterEachCycle() {
+ // TODO: How could this work with more than one keygroup?
if (!Layer.isActive(numPadLayer)) {
cleanupNumlockState();
} else {