Turning on specific leds when hitting a specific layer

@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.

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

1 Like

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

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.

1 Like

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.

2 Likes

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)

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.

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.

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):
http://www.keyboard-layout-editor.com/#/gists/150d746e66ce08c6f4deea8e77a8620f
(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!

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)
      return;

    uint8_t top = Layer.top();

    // Failsafe
    if(top >= LAYER_SIZE)
      return;
    
    // 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)
      return;

    // 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)
          continue;
          
        LEDControl.setCrgbAt(x, y, colorPallette[colorIndex]);
        
        // Ensuring led shuts down if it was assigned to be off
        if(0 == colorIndex)
          LEDControl.refreshAt(x,y);
      }
    }
}

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?

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

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.

2 Likes

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.

2 Likes

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.

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.

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

1 Like

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.

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.

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

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?