With the new implementation, there are two lookup functions, because we have two
caches, and different parts of the firmware will want to use either this or
that (or perhaps both, in rare cases).
First of all, we use caches because looking up a key through all the layers
is costy, and the cost increases dramatically the more layers we have.
Then, we have the `effectiveKeymapCache`, because to have layer behaviours
we want, that is, if you hold a key on a layer, release the layer key but
continue holding the other, we want for the layered keycode to continue
repeating. At the same time, we want other keys to not be affected by the
now-turned-off layer. So we update the keycode in the cache on-demand, when
the key is pressed or released. (see the top of `handleKeyswitchEvent`).
On the other hand, we also have plugins that scan the whole keymap, and do
things based on that information, such as highlighting keys that changed
between layers. These need to be able to look at a state of where the
keymap *should* be, not necessarily where it is. The `effectiveKeymapCache`
is not useful here. So we use a `keymapCache` which we update whenever
layers change (see `Layer.on` and `Layer.off`), and it updates the cache to
show how the keymap should look, without the `effectiveKeymapCache`-induced
behaviour.
Thus, if we are curious about what a given key will do, use `lookup`. If we
are curious what the active layer state describes the key as, use
`lookupUncached`.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Only update the keymap cache if the layer state changed for real. If we turn a
layer that was already on, on again, we do not need to update. Same for turning
them off.
This results in a tiny speedup if we have code that calls `Layer.on()` or
`Layer.off()` often.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When we change layers, we want to update the key cache for the whole keyboard,
so that LED modes and other things that depend on all keys being up-to-date will
work as expected.
Do the same at `Kaleidoscope.setup` time, so we start with a good state too.
This fixeskeyboardio/Kaleidoscope-Numlock#7.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
It may happen that we get passed an UNKNOWN_KEYSWITCH_LOCATION, which will
always be out of bounds. Lets not corrupt random memory when in this situation,
but instead, return quickly.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
For some odd reason, initializing it there crashes the firmware early on. Until
I figure out how to fix this, lets default to an implicit false.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Switch from the masking behaviour to repeating the symbol the key had when first
pressed.
This - along with the previous changes - fixes#158.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of storing the layer for each key, store the keycode, so that lookups
are considerably faster (one array lookup instead of two). This saves us almost
a full millisecond per scan cycle. Furthermore, inline `Layer_.lookup`, saving
us even more time.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This changes how key caching & lookup works: instead of updating the whole key
cache whenever we change the layer state, we update each key before they are
pressed or released. This allows us to have two different ways in which layers
can work:
- Keys still held when releasing the layer key will be masked out until they are
released. (This is the current behaviour)
- Keys held will repeat the keycode they had when they toggled on, even if the
layer key gets released prior to this other key, while other keys will not be
affected.
One can toggle between the two modes by setting
`Kaleidoscope.repeat_first_press` to `true` (second behaviour) or `false` (first
behaviour).
For now, the default behaviour is left unchanged.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When a masked key is released, instead of unmasking it and returning, unmask it
and let the event through. This fixeskeyboardio/Kaleidoscope-OneShot#10.
Reported-by: Craig Disselkoen
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The goal is to ignore key events from still-held keys in a situation where we
just turned a layer off. Thus, if one holds a momentary layer key, then presses
and holds another key, releases the layer key, we want to ignore the other held
keys until they are released.
This is accomplished by masking all held keys when a momentary layer has been
turned off, and ignoring all masked key events in `handleKeyswitchEvent` until
they are released, when we unmask them.
This should address #150, but requires
keyboardio/Kaleidoscope-Hardware-Model01#9.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
rather than send key down events for a while before sending a key
release event as we did with the old scheme, this sends the events
paired together as "one shot". This is closer to the spec and what OSX
needs to accept these events
Based on suggestions from Wez Furlong (@wez) in #135, this replaces the
`Kaleidoscope.use` function with one that does its thing at compile time.
The net result is that we save a considerable amount of code, while still having
all of the benefits, and being 100% backwards compatible, no code needs to
change.
We may want to adjust existing code to use `Kaleidoscope.use` directly, and drop
any trailing NULLs we may have had. But there is no rush to do so.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of using the argument as-is, which could be misinterpreted as a
reference (at least by linkers), wrap them in parens to make it clear they are
not.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
WDT is AVR specific, so it has a much better place in the hardware plugins. Move
it there, and call `KeyboardHardware.setup()` earlier, so it can call
`wdt_disable()` before all the other things it needs.
The delay after WDT disabling moves to the hardware plugin too.
Thanks to @wez and @obra for figuring out what to move where (see
keyboardio/Kaleidoscope#129).
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This is the smallest change to make Kaleidoscope compile for
nRF52 BLE boards.
https://github.com/wez/KaleidoscopeKeyboards
has more code and build machinery for my proof of concept for using
Kaleidoscope as the driver for a keyboard using the new nRF52 based
board from Adafruit.
Implements the `layer.on`, `layer.off`, and `layer.getState` commands, which can
be used to control the active layers from the host.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To be used in places where we have absolutely, positively no clue where a key
event came from, coordinate-wise.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of calling the `.write` method of `ConsumerControl`/`SystemControl`,
which registers the key, sends a report, then unregisters, and reports again,
just `.press` it when the key is pressed, as we did before.
However, since `.press` always sends a report, and so does `.releaseAll`, we
can't have it the same way we do for `Keyboard`. We need to explicitly release
the consumer/system key, when the triggering key is released too. Not doing so
makes the key stuck, as we never release it, and that will upset the operating
system very much.
With this patch, we do an explicit release when the key toggles off, and thus,
we support both holding the key, and allowing the OS to trigger repeat, and, the
key won't be stuck, either!
Fixes#120.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
We want to allow plugins to change how keys are looked up - or where they are
looked up from -, and for this, the way we do that final lookup from `keymaps`
or elsewhere, must be overrideable.
We do this by having a `getKey` function pointer in the `Layer_` class, which
defaults to `getKeyFromPROGMEM`. Any plugin, or sketch, can change where
`getKey` points to, and thereby change the way keys are looked up.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
If we want to allow plugins to implement EEPROM storage, it is best if we don't
do anything with EEPROM in the core firmware. As such, remove the
`Layer.defaultLayer` call from `Kaleidoscope.setup`.
With that gone, the `keymap_count` argument is obsolete, so drop it from
`Kaleidoscope.setup()` - but we keep an temporary `setup()` with the old arity,
so that plugins can be updated at a slower pace.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The `USE_PLUGINS()` macro is a clever hack, to make it seem like
`Kaleidoscope.use()` is type-safe. It pushes its arguments into an appropriately
typed array, so anything that does not fit the criteria, will trigger a compiler
error.
It then never uses the array, and passes the plugins over to
`Kaleidoscope.use`, adding the trailing `NULL`, making it even easier to
use.
Since the array this macro creates is never used, the compiler will
optimize it out fully. As such, by using this macro, we incur neither
any size penalties, nor any run-time penalties. Everything happens at
compile-time.
Fixes#100.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To make things easier, just include the main header. It includes
everything else we need, and this way we do not need to cherry pick, nor
care if any of the other headers move, disappear, etc.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Having the hooks, and the hook methods in the Kaleidoscope object means
we don't have to litter the definitions of the arrays around, and that
the hooks are more tied to the object. We pollute the global namespace
less, and having them in the object means that the hook helper functions
will not be optimized out if not used within the Kaleidoscope repo.
All in all, this saves us about 56 bytes of code, allows us to remove
some hacks, and pulls things that are closely knit, closer together.
While there, also changed the name of the `custom_handler_t` and
`custom_loop_t` types to `eventHandlerHook` and `loopHook` (both under
the `Kaleidoscope_` class), to better reflect what they are for.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The plugin.h header only defined the KaleidoscopePlugin class, and while
there was a reason it was separate from Kaleidoscope.h, that reason is
long gone. Merge it there, and remove any reference to plugin.h, as it
is not needed anymore.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Since we pre-fill the cached `keyMap` with the value of `DefaultLayer`, there is
no need to check that layer again, looking for a non-transparent key. Whatever
is there, will be used anyway.
This way we save a cycle for keys that are transparent everywhere but the
default layer.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
We fill the cached `keyMap` with the value of `DefaultLayer`, so if that is the
only layer active, then we can bail out early.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of going through all the active layers each time we are looking for a
key, whenever we switch layers, compute the effective keymap, and store the
indexes. This makes the lookup a considerably faster operation, and lookups
happen far more often than layer switching.
This comes at a cost of ROWS*COLS amount of memory, and a bit of code, but on
the flip side, the lookup operation is now O(1), which is a very nice property
to have, if you want responsiveness. Changing layers is marginally slower,
however, but even with 32 active layers, doing the computation once, instead of
potentially many dozens of time, is still worth it.
We could further reduce the memory requirements if we stored more columns per
byte, but that's for a future optimization.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of always iterating through all layers, which slows us down
considerably, keep track of the highest active one, and start from there.
This has a VERY noticeable impact on the speed at which we finish a scan cycle.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Momentary layer switchers were broken, because they had the flags/keyCode parts
swapped. Apparently, I missed these when swapping the rest.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
It had the COLS & ROWS defines, which are hardware-specific, and were moved to
the hardware lib.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Moved all of the hardware-specific code to a separate library. As such, use the
special `KEYBOARDIO_HARDWARE_H` define to include the appropriate header, as set
by the board's `boards.txt`.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
All of the plugins have been updated, there is no need to keep the deprecated
functions around anymore.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When toggling a layer, the same keycode should toggle the layer off, too.
Without this, toggling layers won't work at all, because the target layer will
never be turned off.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Turn the `event_handler_hook_add` and `loop_hook_add` aliases into real
functions, that emit a deprecation warning during compilation. This makes it a
little bit easier to see what needs to be updated still.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
In most cases, one only wants a single copy of a hook. On the other hand,
plugins that depend on other plugins, may want to make it easier for the
end-user to use the plugin, and call the setup function of the dependent plugins
too. In case the end-user calls the same setup function, we'd end up with hooks
registered multiple times.
To avoid this, protection against double-registration has been introduced. The
new `event_handler_hook_use` and `loop_hook_use` functions will only allow one
copy of the hook. The `event_handler_hook_append` and `loop_hook_append`
functions will, on the other hand, just append the hooks, and not care about
protection.
The `event_handler_hook_add` and `loop_hook_add` functions are gone, but for the
time being, they are aliases to the `_use` functions, until all plugins have
been updated, and the aliases can be removed.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Moves the LED control code, along with the built-in effects into the
Keyboardio-LEDControl plugin.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
I forgot to update the `LCTRL`, `LALT`, etc macros, and they still assumed the
previous order. This little patch fixes that.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
With the swap, using `raw` becomes more straightforward, because the flags will
occupy the higher bits, and the keyCode the lower ones. This makes range checks
much more intuitive.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>