Turning on specific leds when hitting a specific layer

(Jordihs) #22

@algernon Since I changed the arrays to contain byte elements, I am using pgm_read_byte to extract them from progmem, instead of pgm_read_word from your example. Is this correct? As in:

LEDControl.setCrgbAt(x, y, colors[pgm_read_byte(*scheme[x][y])]);

Where colors is the pallette array.

(Gergely Nagy) #23

Yes, it is! I wanted to use pgm_read_byte in the example too, but… forgot to change it. Sorry for the confusion!

(Jordihs) #24

Oh please don’t apologize, you really helped out. Like the newer version?

(Noseglasses) #25

FYI, @jdlien is currently working on a related idea, coloring keys by keycode or keycode group (characters, digits, …).

I find his approach very intetesting because it is less sensitive against keymap changes than coloring by key matrix position.

Maybe this could be useful to you, too.

(JD Lien) #26

Yeah, I was going to chime in that it sounds like you’re headed where FunctionalColors almost is. I got really busy, but even in its current state it’s pretty useful, if not very well documented.

My next plans for FC are to provide a few different sets of defaults that can be tweaked pretty easily so you can just create an instance and have a set of pretty colors.

The impetus for my creating FunctionalColors was that I was experimenting heavily with key layouts and I wanted the key colors to represent the meaning of the keys (to help me understand my current layout at a glance) without having to manually move the LED assignments every time I changed a key position.

(Jordihs) #27

Thanks guys. I looked into FunctionalColors but I could not grasp very well how I would achieve my desired results using It. Plus, loong thread with lots of c++ I dont’ understand.
Also, my scheme is not so cluster oriented nor does it help knowing what each key does.
I don’t expect to type looking at the keys, I will use a printout as a cheat sheet. Color will cue the home row and numpad keys, plus add a very discrete cool factor.
If your keyboard is set to spanish, many keys have different meaning compared to US english. That might be a problem but I’m not certain.If it is, i would apply to any language variant out there.

Anyhow, the bottom line that would invalidate any rebuttal of my arguments, is that I am a programmer and I liked the challenge of baking my own meal :grinning:. Plus, I was bored… And it’s just a few lines, too.
Anyway, thanks for coming in with the tip. If my code turns out to not work, I will keep this in mind.
…which I’ll know whenever I get my MP4 keyboardio some time in april (fingers crossed)

(Jordihs) #28

Okay, and now a little defence of my code, because critical thinking must also be used when discussing code.
I think my approach makes it a piece of cake to remap a color to a different key. You go from changing the keycode to changing the color mapping and that is going to take you seconds.
Hence, unless you really need to change clusters of keys every few days, It doesn’t really pay off to use a more complex approach. For initial setup and later, smaller and sporadic modifications, my code (if it does work!) should be enough.
An exception to this would be if someone wants yo have lots of coloring schemes, since each one is 64 bytes wide. Then a clustered approach may be more progmem frugal. I don’t know, people with maybe four key layers would be spending 256 bytes of progmem if they want each layer colored differently. I’m not sure if that is too much or not due to inexperience, but having 28672 bytes in Arduino I’d guess it’s acceptable?

And this is without knowing much about FunctionalColors and how it is configured. Maybe I’m stretching my imagination too far. But it didn’t seem to solve, for instance, my need to have all keys except a few to be on at a specific base color. Or does it?

That is me just being pragmatic and sincere. Not to say the FunctionalColors is any less useful, just thinking that for a regular user with less need of constant color tweaking it may be overkill. Maybe you could show me the code to replicate my layout in FunctionalColors for comparison?
If for some reason I made a fool of myself I’ll appreciate your criticism stoically.
And still, thanks for the help.

(JD Lien) #29

Yeah, it kind of got a bit out of control. I don’t understand it completely either and it took an entire week of seriously straining my brain to get as far as I have. Blame @noseglasses for that :smiley:
In all seriousness, though, he helped me get this thing down to a level of efficiency and leanness I didn’t even imagine was possible.

When FunctionalColor gets closer to “production ready” it will hopefully be easy enough to use that a non-programmer can do cool things with it and I’ll document it so you don’t have to try to understand all the code just to use it.

I’m only just learning about this, but as a native English speaker, I haven’t had to deal with this. I think that most languages just remap the same keys to different meanings, and that Keyboardio’s firmware has aliases for most of the common meanings. Perhaps if you’re programming for a keyboard and use a non-US English input language you just have to get to know what the “US” keys mean for your keyboard. FunctionalColor itself should be mostly okay with that, except that in some languages my groupings (ie “punctuation” might end up including accented characters).

Later on it would be super useful to have some non-English users give me some feedback on how it works for them, if you ever are interested in helping out with that.

Yeah, I think that FunctionalColor can do this. You can set a default color and then specify a few keys that you want to be different colors. If you have a pretty simple color scheme (as I think you do), it should be a trivial configuration of FunctionalColor. If you, for instance, want to make a rainbow pattern with every key being different, that can be done with FC but it’d be a much more tedious degree of configuration.

I will add, though, that FC isn’t really designed for coloring your keyboard in ways that are purely aesthetic, based on the physical position of the keys (which it seems is more what you are going for). You certainly can do this, and it might still be much easier than starting from scratch, but that isn’t really the point of FC.

The need you have that I don’t think FC would address (yet) is that you seem to have four different layers. Is that correct? FC is designed to switch the key colors to highlight the functionality of your function layer when you’re pressing an fn key but it doesn’t, for instance, do anything special with the numlock layer or anything. I don’t think that it’d really be hard to add support for multiple layers, but I’ve never had any need for that, personally, so I haven’t tried yet.

(Jordihs) #30

You might want to look at my layout to better grasp the way a spanish keyboard is laid out (although I have a number of odd mappings and it is still a working progress):
(The blue sybols are the function layer, and the red ones are the numlock layer. Black symbols on the upper right mean you press right alt to get to them, not by layering but as a standard keyboard in Spain).

If you look at my code, you should see that actually I have three layers (the usual ones: qwerty, function and numpad), and only two coloring patterns. Qwerty and fn share the same coloring pattern, which has the home row keys in blue, and the rest in light yellow. Numpad highlights the numpad keys and an extra key I mapped for the comma symbol, since that is the decimal separator in spanish. And on the left hand side, it will higlight esdf which, in the numlock layer, are remapped to wasd for FPS videogames.
If you look at my code, all these mappings should seem quite obvious just by looking at the ‘qwerty’ and ‘numpad’ arrays. Indentation makes it very intuitive IMHO, even more so that the regular KEYMAP_STACKED method of mapping keys.
Except for the highlighting of esdf, the philosophy is not so much of an aesthetic approach (well, or in that case, it is a minimalist approach to aesthetics). I highlight the home row so I can glance at the keyboard without looking at it directly, just with the peripheral sight, to position my fingers properly. Even that might be unnecesary because of the sculpted keys. This is a first approach but once I get the keyboardio I will surely need to make adjustments.
Anyway, my code is not intended to become a plugin as yours is. So, yes, I would add multiple layer support if I was working on a plugin. Ideally, I’d want:

  • Multiple layer support
  • Easy to customize key clusters (add, replace, remove keys)
  • A predefined numpad cluster (numpad numbers and operators)
  • Possibly a ‘transparency’ color mapping, where i.e. you have all keys lit to a color and when you switch, they remain as they are unless the active custers say otherwise.
  • An alternate mode where it works just like my version for those who want fine grain control :slight_smile:

If I knew more c++ I’d be hapy to help (or I might even create my own plugin). Alas, just creating that small piece of code that I am not certain wether it works or not, took me an entire morning. Pointers are weird if you’ve never dealt with them, it was quite a challenge to get everything to compile.
Cheers, keep it up!

(Jordihs) #31

Well, I decided to implement an easier to use version of my code. Now all the code changes required are to adjust the number of layers (LAYER_SIZE const), if you have added or removed from the default. And then there is an array that maps the color schemes to each of the layers.
I also implemented the ‘transparency’ effect, where you can define a key to not change when you switch to it so e.g. if it was yellow and you change to a new layer where the color definition for that key is ‘T’, it will remain yellow.
Here is the main code:

// Color pallette. Can have up to 254 definitions (of any available color). 
// The only requirement is for the first item to remain unchanged. 
// The first item is used to shut down the led in any given key. 
const cRGB colorPallette[4] = {
  CRGB(0,0,0),       // Off state, index 0
  CRGB(255,255,100), // Base color, index 1
  CRGB(0,0,255),     // blue highlighting, index 2
  CRGB(255,0,0)      // red highlighting, index 3

// A 'transparent' mapping, will leave the key led in the same state as with the previous active layer
static const byte T = 255;

// Each number here is referencing an index from the colors array. 
// The formatting reflects the actual key layout on the board
static const byte qwertyColor [ROWS][COLS] PROGMEM =  {
  {1,1,1,1,1,1,1,       1,  1,        1,1,1,1,1,1,1},
  {1,1,1,1,1,1,1,       1,  1,        1,1,1,1,1,1,1},
  {1,2,2,2,2,1,1,       1,  1,        1,1,2,2,2,2,1},
  {1,1,1,1,1,1,    1,   1,  1,    1,    1,1,1,1,1,1}

// I moved wasd to esdf for FPS so they get highlighted for fraggin' :-)
// As an example, I am using 'transparent' colors but 1 instead of T would work as well. 
static const byte numpadColor [ROWS][COLS] PROGMEM = {
  {T,T,T,T,T,T,T,       T,  T,        T,T,3,3,3,T,T},
  {T,T,3,T,T,T,T,       T,  T,        T,T,3,3,3,3,T},
  {T,3,3,3,1,T,T,       T,  T,        T,T,3,3,3,3,T},
  {T,T,T,T,T,T,    T,   T,  T,    T,    3,3,3,3,3,3}

// The number of key mapping layers (by default, 3, i.e. QWERTY, NUMPAD and FUNCTION). 
static const byte LAYER_SIZE = 3;

// Mapping color schemes to key mapping layers. 
static const byte (*colorMapping[LAYER_SIZE]) [ROWS][COLS];

// A global variable to store the previously selected layer
static uint8_t previous_layer = -1;

   Loop hook to override LED colors
static void layerColorOverride(bool post_clear) {
    if (!post_clear)

    uint8_t top = Layer.top();

    // Failsafe
    if(top >= LAYER_SIZE)
    // Reference for the color scheme to use
    const byte (*prevScheme)[ROWS][COLS];
    const byte (*scheme)[ROWS][COLS];

    for(byte x = 0; x < LAYER_SIZE; x++) {
      if(top == x)        
        scheme = colorMapping[x];
      else if (previous_layer == x) 
        prevScheme = colorMapping[x];
    // Remember this layer for future calls
    previous_layer = top;

    // If the layer coming in is the same as last time, do nothing. 
    // Also in this case, qwerty and function are equivalent. 
    if(scheme == prevScheme)

    // Apply the scheme to the button LEDs
    for(byte x = 0; x < ROWS;x++) {
      for(byte y = 0; y < COLS;y++){
        byte colorIndex = pgm_read_byte(*scheme[x][y]);
        // Skip 'transparent' LED settings so they remain as is
        if(T == colorIndex)
        LEDControl.setCrgbAt(x, y, colorPallette[colorIndex]);
        // Ensuring led shuts down if it was assigned to be off
        if(0 == colorIndex)

And here is the code to add in the setup() method to bind layers to color schemes:

  // Assign color schemes to the colorMapping array. In this case, QWERTY and FUNCTION have the same scheme. 
  colorMapping[QWERTY] = &qwertyColor;
  colorMapping[NUMPAD] = &numpadColor;
  colorMapping[FUNCTION] = &qwertyColor;

If somebody has the time to review my code and suggest changes I’d be really thankful.
@algernon and everyone else: would you think this is worth putting in a plugin?
Also, I would really appreciate if someone gave this a test drive. Anyone?

(Jordihs) #32

Also, one question: is there an easy way to figure out the number of layers that have been defined in the keymaps const?

(Gergely Nagy) #33

You can figure it out from the sketch itself with sizeof(keymaps)/ROWS/COLS/sizeof(uint16_t), but this won’t work anywhere outside of it.

(Michael Richters) #34

If you use the KEYMAPS() macro instead of defining the keymap array directly, there is a layer_count variable defined (see layers.h), which stores that info. If not, it defaults to the maximum allowed (32). There’s a PR for Model01-Firmware to make this change, but I don’t know if it’s ever going to be merged.

(JD Lien) #35

This is an interesting idea… currently I have a bunch of functions like isNumber() that tell if a key passed to it is a Number. But I don’t (yet?) have the ability to have user-customizable functions of this nature. I’ll think about how this could be done.

This is the way it works already… the key stays the way it was unless something tells it to change. However, what I can’t currently do it override a key that has a color from its grouping to have no color… I guess in that case, instead of switching the color it’d skip that part of the loop (continue) or something.

(Jordihs) #36

Maybe I put you in a position where you feel a need to add functionality to your plugin that is really not a core feature and might be difficult to implement (I’ve seen that in the FunctionalColors thread you posted about it).
What I mean by not core is that your initial idea was to predefine clusters of ‘natural’ key groups, and my request might be out of scope.
On the other hand, some clusters might not make sense in international keyboard layouts (see @andrewg threads to understand the complexities there).
But I’d hate to be the one that put you in a position where you just blow up your code way out of the initial scope. A clustered coloring option is nice in and of itself. Some users will enjoy it, while others might want to go in a different direction. In my experience, a software project needs to keep focused on its core target functionality or else it grows out of proportion and becomes unmantainable (isn’t that what we face on our day jobs on a regular basis?)
I’m not saying not to implement that, I am rather giving a heads up about this matter because my feature requests, put in perspective, are just not part of the gist of your project. It may be better to have one plugin like yours and possibly (if I figure it out) one plugin like mine. Then users will choose what fits them better.
Anyway, thanks for taking consideration of my requests, and if in the end you do want to implement them, by all means do it.

(Noseglasses) #37

Yes, you can. See my reply to the other thread.

(JD Lien) #38

I don’t think this is really out of scope… It was actually a request from somebody else that made me realize that somehow I need the ability to customize any key and create arbitrary groups. @noseglasses already provided the means for that but I’m just trying to polish things up and make it a little bit more user-friendly. I think I know what I need to do now to get this to a state where I’m comfortable “releasing” it.

(JD Lien) #39

By the way, I thought I would mention that I have finished my work on FunctionalColors if you were interested in having a look. It should address your needs for the most part I think.

Let me know if you have any questions about that.

(Jordihs) #40

Much appreciated, I will give it a try and let you know… once I get the keyboard.

(Anton) #41

With last API updates this example is not working, and upgrade tips are too vague.
Would you please tell minimal example how to do it now?