I took a bunch of the code from this thread and modified it to fit my needs. I’m posting it here in case it helps anybody else.
My use case is as follows:
- I want a hit of the LED button to quickly turn the LEDs on if they are off (and restore to the last mode), and I want them to turn off if they are on (so an accidental hit of the key doesn’t mean I need to cycle through again to get back to what I want).
- I wanted to make Fn+LED cycle the LED modes forward, and Fn+Shift+LED to cycle the LED modes backward.
- Since I have a quick toggle, I didn’t want to include the Off mode in my toggling.
- I actually removed Key_LEDEffectNext from my keymap, so I wanted to make the boot greeting continue to function (because it is cool).
Here’s my change to the MACROS enum:
enum { MACRO_VERSION_INFO,
MACRO_ANY,
MACRO_LED_NEXT_PREV,
MACRO_LED_ON_AND_OFF
};
I added M(MACRO_LED_ON_AND_OFF)
in place of Key_LEDEffectNext
on the first layer of the keymap, and placed M(MACRO_LED_NEXT_PREV)
in the same place on the Function layer.
I added to the Macros section near anyKeyMacro
//Global int for the last LED mode (defaults to LEDOff, or whatever LED mode you have as 1st)
static int lastLedMode = -1;
/** turnLedsOnAndOff turns off LEDs, saving the current state, and turns them back on
* expanded by aedifica from a sample algernon posted at
* https://community.keyboard.io/t/how-does-one-make-a-key-that-turns-the-leds-off/554/2
* with tips from merlin
*/
static void turnLedsOnAndOff(uint8_t key_state) {
if (keyToggledOn(key_state)) { /*when button is pressed*/
if (LEDControl.get_mode() != &LEDOff) { /* if LEDs are on */
lastLedMode = LEDControl.get_mode_index(); /* first, store the current mode */
LEDOff.activate(); /* then activate the "off" mode */
} else if(lastLedMode >= 0) {
LEDControl.set_mode(lastLedMode); /* set our LED to the last mode */
} else {
//Either do the first item on the list that isn't the Off mode...
nextPrevLedMode(key_state, true);
//Or set it to something you want by default...
//StalkerEffect.activate();
}
}
}
/* Toggle forward regularly, and toggle in reverse if shift is held */
static void nextPrevLedMode(uint8_t key_state, bool skipOff) {
//Ensure a key was pressed
if (keyToggledOn(key_state)) {
if(
kaleidoscope::hid::wasModifierKeyActive(Key_LeftShift)
|| kaleidoscope::hid::wasModifierKeyActive(Key_RightShift)
) {
//shift held, so go backward
do {
LEDControl.prev_mode();
} while (
skipOff && LEDControl.get_mode() == &LEDOff
);
} else {
//No shift, so go forward
do {
LEDControl.next_mode();
} while (
skipOff && LEDControl.get_mode() == &LEDOff
);
}
//Set the last LED mode
lastLedMode = LEDControl.get_mode_index();
}
}
And finally I added macroAction
case statement the following two cases:
case MACRO_LED_ON_AND_OFF:
turnLedsOnAndOff(keyState);
break;
case MACRO_LED_NEXT_PREV:
nextPrevLedMode(keyState, true);
break;
You can edit the turnLedsOnAndOff
function and explicitly set the initial LED mode you wish to use, by name. If one isn’t set, it’ll just choose the first one in the list of LED modes that isn’t LEDOff.
Now, doing all of this will break the BootGreeting function that flashes the LED button for 10 seconds, because I removed the Key_LEDEffectNext key from the mapping in favor of a macro. The boot greeting code explicitly looks for that key, and since it can’t find it it doesn’t activate. I modified the BootGreeting code so that it accepts a parameter for a row and column position, which lets you hardcode a specific key to enable. Doing this, you can actually make any key that you desire light up (such as the any
key or the butterfly
key, or just the LED
key like before.
If this bothers you, you can add the following to your sketch:
//Cutom bootgreeting effect
static kaleidoscope::BootGreetingEffect BootGreetingEffectHardcoded(0,6);
and then replace the BootGreetingEffect
in your Keyboardio.use
call:
Kaleidoscope.use(
// The boot greeting effect pulses the LED button for 10 seconds after the keyboard is first connected
&BootGreetingEffectHardcoded,
// The hardware test mode, which can be invoked by tapping Prog, LED and the left Fn button at the same time.
&TestMode,
You’ll want to replace the Library versions of Kaleidoscope-LEDEffect-BootGreeting
(.h. /cpp) the following versions below:
Kaleidoscope-LEDEffect-BootGreeting.h
/* -*- mode: c++ -*-
* Kaleidoscope-LEDEffect-BootGreeting -- Small greeting at boot time
* Copyright (C) 2017 Gergely Nagy
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Kaleidoscope-LEDControl.h"
namespace kaleidoscope {
class BootGreetingEffect : public KaleidoscopePlugin {
public:
BootGreetingEffect(void) {}
BootGreetingEffect(byte, byte);
void begin(void) final;
static byte key_row;
static byte key_col;
private:
static void loopHook(const bool post_clear);
static bool done_;
static byte row_;
static byte col_;
};
}
extern kaleidoscope::BootGreetingEffect BootGreetingEffect;
Kaleidoscope-LEDEffect-BootGreeting.cpp
/* -*- mode: c++ -*-
* Kaleidoscope-LEDEffect-BootGreeting -- Small greeting at boot time
* Copyright (C) 2017 Gergely Nagy
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Kaleidoscope-LEDEffect-BootGreeting.h"
#include "LEDUtils.h"
namespace kaleidoscope {
bool BootGreetingEffect::done_;
byte BootGreetingEffect::row_;
byte BootGreetingEffect::col_;
byte BootGreetingEffect::key_row = 255;
byte BootGreetingEffect::key_col = 255;
BootGreetingEffect::BootGreetingEffect(byte pos_row, byte pos_col){
key_row = pos_row;
key_col = pos_col;
}
void BootGreetingEffect::begin(void) {
Kaleidoscope.useLoopHook(loopHook);
// Find the LED key.
for (uint8_t r = 0; r < ROWS; r++) {
for (uint8_t c = 0; c < COLS; c++) {
Key k = Layer.lookupOnActiveLayer(r, c);
if (
k == Key_LEDEffectNext
|| (key_row != 255 && key_col != 255 && key_row == r && key_col == c)
) {
row_ = r;
col_ = c;
return;
}
}
}
// We didn't find the LED key. Let's just pretend we're "done".
done_ = true;
}
void BootGreetingEffect::loopHook(const bool post_clear) {
if (!post_clear || done_)
return;
if (millis() > 9200) {
done_ = true;
::LEDControl.refreshAt(row_, col_);
return;
}
cRGB color = breath_compute();
::LEDControl.setCrgbAt(row_, col_, color);
}
}
kaleidoscope::BootGreetingEffect BootGreetingEffect;
The end result is that a hit of the LED button will toggle the LEDs on or off, the boot greeting still works, and you can scroll forward or backward through the array of LED modes by use Fn+LED (+optional shift for reverse).