LockLayer with timeout?

Hi. I’ve created a custom layer, and activate using the LockLayer macro. My issue is that I will sometimes (Ok, All the time) come back to the keyboard after handling another task IRL and start typing assuming that I’m on my primary layer, and instead start typing gibberish. I’d like to be able to set this so that if no keys are pressed for a period of time, say 30 seconds, the keyboard will automatically reset to the primary layer. I don’t think there’s an existing plugin that does that. Does anyone have some tips or suggestions for how to implement this feature?

Thanks!

You are correct, there’s no existing plugin for that. But, you can take the IdleLEDs plugin as a base, and modify it to reset to the primary layer instead of turning LEDs off. Or, you can use this quick, untested hack I threw together:

namespace kaleidoscope {
namespace plugin {

class IdleLayers: public kaleidoscope::Plugin {
 public:
  IdleLayers();

  static void setIdleTimeSeconds(uint16_t seconds) {
    idle_time_limit_ = seconds * 1000;
  }
  static uint16_t idleTimeSeconds() {
    return idle_time_limit_ / 1000;
  }

  EventHandlerResult beforeEachCycle() {
    if (Kaleidoscope.hasTimeExpired(start_time_, idle_time_limit_) && (Layer.top() > 0)) {
      Layer.move(0);
    }
    return EventHandlerResult::OK;
  }
  EventHandlerResult onKeyswitchEvent(Key &mapped_key, KeyAddr key_addr, uint8_t key_state) {
    start_time_ = Kaleidoscope.millisAtCycleStart();
    return EventHandlerResult::OK;
  }

 private:
  static uint32_t idle_time_limit_ = 30 * 1000;
  static uint32_t start_time_;
};
}
}

kaleidoscope::plugin::IdleLayers IdleLayers;

Then put IdleLayers in your KALEIDOSCOPE_INIT_PLUGINS() list, and it should do the trick. You can place it in your sketch, don’t even need a separate file for it. If you don’t need the idle time to be configurable, it can be simplified further, by removing the setIdleTimeSeconds() and idleTimeSeconds() methods. You could even hardcode the idle time limit in beforeEachCycle() then, but I think a private variable is a bit more readable, and makes it easier to (re-)add support for configurability later on, would you decide to want that.

A quick explanation what this does: the bulk of it is in beforeEachCycle() and onKeyswitchEvent(), the other two methods are just there for ease of use, they’re merely accessors. beforeEachCycle(), as the name implies, runs every cycle. The firmware runs in a loop, checking key states, and doing its business over and over again. The beforeEachCycle() method of each plugin gets called at the beginning of that loop, in every iteration. Our method checks if the timer we set expired, and if we have any layer higher than 0 active. If we do, it switches to layer 0, otherwise it does nothing. The onKeyswitchEvent() method gets called whenever a key is pressed, whether physicially, or via a plugin. All it does, is reset when the idle timeout starts, whenever a key event happens, be that a press, a release, or a hold event.

Thus, if you leave your keyboard, and don’t press any keys, the timer will expire, and the layer gets reset to the primary one. If your cat decides to take a nap on it meanwhile, that will, however, prevent this, unless it stays very very still during its nap.