An `EPHEMERAL` keyswitch event is one that gets ignored by updates to
`live_composite_keymap_[]`, and thus doesn't change the keymap at all. This is useful for
a plugin that needs to retain its own key type in the keymap in order to do something
particular when it toggles off, but needs to inject an event with a different `Key` value,
with real key coordinates.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
If we're sending injected events with `UNKNOWN_KEYSWITCH_LOCATION` instead of
the (row,col) of the OneShot key, there's no need for the function that does this
conversion.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
With the changes to live_composite_keymap_, OneShot keys were no longer working. OneShot
modifiers would get stuck on, because the entry for the `OSM` key would get changed to the
modifier key value, and when the key was released, it wouldn't be processed by the OneShot
plugin, which would continue to re-apply the modifier indefinitely. At the same time,
OneShot layers wouldn't work at all, because the key would get changed to the layer shift
key, which would then turn the layer off when it was released.
This change fixes the problem by injecting keyswitch events from OneShot without physical
key coordinates, so nothing in `live_composite_keymap_` can get updated from it. OneShot
wants the `Key` entries there to remain as OneShot keys, not as whatever they're changed
to, so this is the most appropriate way I can think of to fix the issue.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
If `handleKeyswitchEvent()` is called with a `mappedKey` other than `Key_NoKey`, update
`live_composite_keymap_` with the specified `mappedKey` instead of doing a keymap lookup
on active layers. This allows a plugin to call `handleKeyswitchEvent()` and specify what
the `Key` value should be, and not have to separately track what value to change it to
every cycle.
This is especially important when there's a layer change. In particular, this is the
simplest way to allow Qukeys to use `ShiftToLayer()` keys that work properly.
Fixes#501.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This adds a new version of `updateLiveCompositeKeymap()` which takes three parameters:
row, column, and a `Key` value. Instead of looking up the value to update in the key map,
it just updates `live_composite_keymap_` with the specified `Key` value.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Instead of trying to be clever by checking if a mask applies to a layer index,
just check if the layer is higher or equal (or lower, as appropriate) than our
`IGNORE_HARDCODED_LAYER` value.
This addresses keyboardio/Chrysalis#341.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Since LED modes only send updates to the hardware at `syncDelay` intervals, calling
`update()` on the active mode every cycle doesn't make animations any smoother.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This decreases the rate at which LEDs get updated from ~60Hz to ~30Hz, which should be
fast enough that human eyes won't be able to tell the difference.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
The LED-Stalker plugin was looping through its table of `step` values (one for each key)
on every call to `update()`, and calling `compute()` on every value there, but those table
entries were only updated once every 50ms (by default), resulting in a lot of repeated
computation. This resulted in the mean idle cycle time increasing from 565µs to 1317µs on
the Model01 with an (almost) unmodified standard sketch.
This change moves the check for the timeout before the loop through the `step` values, and
aborts processing there if not enough time has elapsed. The resulting mean idle cycle time
becomes 577µs -- an almost negligible increase. It also reduces the PROGMEM footprint by
44 bytes.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This commit silences a warning due to an undefined variable.
A first attemt to locally supress the warning using compiler pragmas was
unsuccessfull due to a compiler bug in all gcc versions. This bug
in all gcc versions below 6.1 makes local diagnostics suppression useless.
As future versions of Arduino will ship with later versions of gcc
from a certain point on, the supplied warning suppression macros will become useful
to avoid the necessity to set global compiler flags like -Wno... and to
enable more precise warning suppression.
The new header file comes with an example that explains how to use
the suppression mechanism.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
Various old methods provided by `Layer` have been deprecated for a while, and
were scheduled to be removed by February 14, 2019. We're past that, so lets
remove them.
Fixes#577.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
On AVR8, 16-bit bit-operations are expensive. Switch from using 3 16-bit
bitfields to using a 16-element array of a carefully constructed struct.
This saves us almost 300 bytes of PROGMEM at the cost of 10 bytes of memory.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
I tried to be smart and use `sizeof()` instead of hard-coding the array size,
but I used it wrong, and we iterated to 32 instead of 16, overflowing the array
and looking at parts of the memory we had no business looking at. This resulted
in `isPressed()` and `isSticky()` always being true.
Instead of trying to be clever, use `OneShot::ONESHOT_KEY_COUNT` throughout,
which is a constexpr defined at 16, the number of oneshot keys we have.
Fixes#572.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
In `beforeReportingState()` and `afterEachCycle()` we used to return early if no
OneShots were active. This was easy to do when we were using a bitfield, we'd
just tested for non-zero. Since we're using an array now, this check is more
expensive, and the extra work negates any benefit of returning early.
For this reason, these early returns are removed.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Now that we're using a struct with descriptive member names, drop the helper
macros that made using bitfield manipulation readable. The code's readable
without them by now.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
On AVR8, 16-bit bit-operations are expensive. Switch from using 4(!) 16-bit
bitfields to using a 16-element array of a carefully constructed struct.
This saves us about 242 PROGMEM at the cost of 8 bytes of memory, and a tiny
performance hit.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We want to be able to notice when the layout of the EEPROM *settings*
changed (which the CRC does not cover). For this reason, we're repurposing the
existing version setting, which wasn't widely used: it is now internal.
We use the version to determine whether the EEPROM has been written to yet, or
if it is uninitialized. This helps us make sure we're starting up with sensible
defaults.
Fixes#559, and fixes#558.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Previously we requested a slice in `onSetup()`, but this had a major,
problematic implication: if we went from a sketch with `EEPROM-Keymap`, but
withot `LED-Palette-Theme` enabled to one with it, the EEPROM layout was not
compatible, no matter what the order of plugins in `KALEIDOSCOPE_INIT_PLUGINS`
were. This happened because `EEPROM-Keymap` requested space *after* `onSetup()`
already ran.
To fix this issue, request a slice in `.reserveThemes`, only if we didn't
request a slice yet. This way the EEPROM layout is decided by the order of
initialization in `setup()`, and we do not sneakily steal a slice in
`onSetup()`.
This is required to address keyboardio/Chrysalis#270.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of having a single `keymap.map` Focus command that tries to be smart
about what layers it presents, we should have two separate commands: one to
query the defaults (PROGMEM), and one to get/set the custom keymap (EEPROM).
This makes `keymap.map` and `keymap.roLayers` obsolete, and they're now removed.
Furthermore, having to specify whether the EEPROM keymap extends the built-in
one or not proved to be unflexible. So we re-purposed the highest bit of the
first EEPROM byte, to signal whether we should use EEPROM layers only or not.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We want to give the hardware enough time to give us a stable read of the pins.
If we unroll the loop, we will not have that. In practice, this leads to entire
rows or columns behaving erratically.
To fix that, we tell the compiler not to unroll loops in the `readCols()`
method (it's free to unroll them elsewhere). This makes the function a tiny bit
slower, but gives us a stable read.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Counting cycles is an incredibly unreliable way of timing animations. Use timers
instead.
Fixes#545.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When not using the `CRGB()` macro, colors may end up being different than
intended if the board we're running on implements RGB order differently.
Fixes#548.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Since `Focus.send()` does not send a newline implicitly, we should do so
explicitly. Introduce `Focus.NEWLINE` to help with this, and not have many
copies of `'\n'` lying around.
Fixes#544.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The KBD4x has a set of WS2812 LEDs, which are very picky about timing. To make
them happy (even though we do not use them yet), we need to disable clock
division at startup.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We deprecated a number of interfaces, which were scheduled to be removed on the
14th of January. Lets remove them now.
Incidentally, we had a number of places where we used the old names internally
too, and this has been corrected as well now.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
EEPROM defaults to `0xff` when uninitialized, which means we'd start off with a
bright white palette. That's a problem, because it draws a lot of power,
especially when all keys are lit bright. For this reason, flip the bits when
reading or storing palette colors, so the default `0xff` becomes `0x00`, black.
Fixes#529.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Brace-initialization has issues, especially with newer compilers that try to do
more, and better optimizations. To allow them to do these, we should be striving
for better type safety. For this reason, use the new Key() constructors to
initialize the various key defines. This gives the compiler much better hints.
The code becomes much more readable too.
This is fully backwards compatible, we're not removing any existing interface,
just using a newly introduced one. The old ways still work. They might produce
warnings with newer compilers, but they did so before anyway.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We need to guard the `k` argument, place it within parens, to make sure it is
treated as a single argument, even if it expands to something that would be
ambigous. This is required, because most - if not all - keys are defined as a
list casted to `Key`, which the pre-processor would misinterpret without the
extra parens.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
To make it easier to create custom shortcuts, that do not interfere with system
ones, an old trick is to use many modifiers. To make this easier, Ctrl+Shift+Alt
is commonly abbreviated as "Meh", while Ctrl+Shift+Alt+GUI is often called
"Hyper". To support this, we offer the `Key_Meh` and `Key_Hyper` aliases, along
with `MEH(k)` and `HYPER(k)` to go with them.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We should be using a different variant of the `default_layer()` method to query
the default layer instead of abusing 0xff as a special valie.
Fixes#522.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Add `REDIAL` to `kaleidoscope::ranges`, so the plugin can define `Key_Redial`
itself, and won't need `Redial.key` to be set in the user sketch either. This is
a breaking change, but one that's easy to upgrade to, hence no effort was made
to make it at least partially backwards-compatible.
Fixes#519.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When selecting a new default layer via Focus, we should be moving there too,
because there may be no other way to switch to the new layer, and having to
reboot the keyboard for changes to take effect is not our desired behaviour.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When sending `Key`s, there's no need for an extra separator, because
`send(key.raw)` will send one anyway. Not sending one results in 10 bytes less
PROGMEM used, and plenty of bytes less spent over the wire.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When we use `lookup()`, we're looking up from the cache, not from the active
layer. If the cache gets updated later than we're called, we won't notice. So do
an explicit lookup.
Fixes#507.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Due to the plugin needing a key coordinate -> geometric space mapping, it
depends on the keyboard used. As such, restrict it to the Keyboard.io Model01,
for which the mapping was set up.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
While the rainbow colors are great, some may want to restrict the colors to a
single hue. For this purpose, the `ripple_hue` property was introduced. It
defaults to `Wavepool.rainbow_hue` (a special value that tells the plugin to use
multiple hues).
Inspired by @bjc's ToyKeeper/Kaleidoscope-LED-Wavepool#8.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Based largely on ToyKeeper/Kaleidoscope-LED-Wavepool#8, this smooths out the hue
transitions, so that the ripple is a nice rainbow, without oddly flashing colors
while cycling through the effect.
Thanks @bjc for the change!
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Methods that originate from the `kaleidoscope::Hardware` base class need not be
documented every time they're being overridden. That leads to duplication, and
higher chance of documentation going stale. As such, remove such cases, and rely
on the base class having plenty of documentation instead.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Since all implementations of detachFromHost/attachToHost are the same for all
our current keyboards, move it to the base class as a default.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This is basically the old Kaleidoscope-Hardware plugin pulled in, and made into
a base class. The purpose is documentation (#167) mostly. The base class has
default implementations for all methods (most do nothing), and can be overridden
by derived classes. Since the hardware object is always going to be called
through `KeyboardHardware`, which has the exact type of the hardware, we do not
need to use virtual functions. The derived class will just shadow the default
implementations.
All hardware plugins were updated to use this (directly or indirectly). The
resulting compiled binary is the same, but we were able to remove a few
boilerplate lines from here and there.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
In general, we want method names to be verbs, because they convey actions. The
`Layer.on()`, `Layer.off()`, etc family of functions weren't like that. It
wasn't immediately obvious that they turn layers on and off.
Furthermore, `Layer.next()` and `Layer.previous()` were even more confusing,
because one could easily think they implied moving to the selected layers, while
in practice, they just activated them.
All of these have new names, that better describe what they do. The old names
are still present, but emit a deprecation warning.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
In the original `KeyboardioFirmware`, this was used to store the default keymap
index in EEPROM. When we removed the EEPROM storage, it was meant to be used by
sketches to set a default layer (the minimum layer one can switch to), which was
not nearly as useful. Even worse, the behaviour was complicated to reason about,
and it wasn't used anyway.
For these reasons, it is now deprecated, and will eventually be removed.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
As the name implies, this makes it possible to set all leds to the same color
depending on which layer is the topmost active one.
Fixes#492.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The ATMega32u4 chip Splitography does not have the JTAG interface disabled in
fuses, so we must do so from the firmware. Otherwise PIN_F4 - PIN_F7 would not
be usable for I/O.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
To work around an issue on OSX, initalize Serial as the very first thing in
`Kaleidoscope.setup`. This is a - hopefully - temporary workaround, until we can
track down the real issue.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Based on a discussion on Discord, this implements a simple plugin that can
temporarily disable the Windows (GUI) keys.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When I did the GPLv3+ -> GPLv3-only change, and assigned my copyright to
Keyboard.io, some of the plugins were missed. This updates those too.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Make it possible to use the plugin for all known Atreus variants: the post-2016
PCB with A* and the FalbaTech handwired one with a Teensy (these two were the
only supported ones until now), the pre-2016 PCB with A*, and the legacy Teensy2
variant.
Fixes#430.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The pin list (and consequently the key layout list) was rearranged in the early
days of the plugin for more optimal scanning code. With -O3 and moving to
`ATMegaKeyboard`, that optimization is no longer relevant. This restores the pin
list and the layout to its original order, the order at which the hardware is
laid out.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Introduce a couple of helper methods that make it easier to work with Focus.
These abstract away the dependency on Serial as a side-effect. The intent is
that all traffic will go through Focus.
Fixes#476.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Improved the ATMega parts of row toggling, similar to how `ATMegaKeyboard` does
it, and separated it from selecting extender rows. This results in a tiny
increase in speed, and better clarity.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of only reporting the state when the timer triggers, report it every
loop, even if it is unchanged.
This is based on a similar change to `ATMegaKeyboard`.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Set the previous key state when reporting the state to Kaleidoscope, instead of
on every read. This eliminates a possible chatter bug. Idea taken from a similar
change made to `ATMegaKeyboard`.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Based on the change made to `ATMegaKeyboard`, apply the same treatment to the
`ErgoDoxScanner` too, and run debouncing only 3 times per 5ms, which is closer
to what switch manufacturers recommend.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>