`layer_getKey` was introduced in 6d641e7fc5, by
mistake, it was never implemented. Remove it now to avoid any possible
confusion.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Use `Kaleidoscope.useEventHandlerHook` and `Kaleidoscope.useLoopHook` instead of
the deprecated `event_handler_hook_use` and `loop_hook_use` interfaces.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
As `USE_PLUGINS` and `loop_hook_use` are getting deprecated, use the newer APIs:
`Kaleidoscope.use` and `Kaleidoscope.useLoopHook`.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Use `Kaleidoscope.useEventHandlerHook` instead of `event_handler_hook_use`,
which is getting deprecated.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Sometimes we would like to know the highest active layer, which is available in
the `highestLayer` private variable, and via `.top()` too. We do not want to
make `highestLayer` public, because we want to be the only ones changing it. And
while `top()` gets us roughly the same information, it does so at a cost. For a
lot of purposes, the cached `highestLayer` would be perfectly adequate.
The new `Layer.highest()` accessor does just this.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
There were a number of issues with the model we had before, namely that plugins
that changed LED colors outside of LED modes had no way to signal "go back to
whatever color this key was". To this end, the `LEDMode.refreshAt` method is
introduced, which these plugins can call to tell the mode to update a given key.
As part of this, the API was redesigned, with code that is common between all
LED modes moving to the base class, among other things, much better names, and a
flow of control that is easier to follow.
In the new setup, there are four methods a LED mode can implement:
- `setup()` to do boot-time initialization (registering hooks, etc).
- `onActivate()` called every time the mode is activated.
- `update()` called each cycle.
- `refreshAt()` may be called by other plugins to refresh a particular key.
All of these are protected methods, to be called via `LEDControl` only.
Much of the new API design was done by @cdisselkoen, huge thanks for his work!
Fixes#9.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
For every key we press, we keep a map of its state each cycle (for 8 cycles).
When the key is released, we color it white if we had more than two state
changes (ie, chatter), otherwise we turn it blue (all is well).
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Refactor the momentary layer handling part of `handleKeymapKeyswitchEvent`.
Instead of a bunch of ifs that are increasingly hard to follow, use a switch
based on the target layer, and branch out depending on `keyState` from there.
Makes it easier to follow what happens.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
If we have two keys on our keymap that momentarily go to the same layer (which
is the case for the factory firmware), we hold both, and release one, we want
the layer to remain active still.
To this effect, in `handleKeymapKeyswitchEvent` we will handle the case when a
momentary layer key is pressed, but not toggled on (that is, it is held): if it
is not a next/previous switch, we re-activate the layer if it wasn't on.
This fixes#154, thanks to @ToyKeeper for the report.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
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>
Uses mickeys (1/16th subpixel units) now instead of pixels. Much smoother!
Added "speedLimit" config var to set maximum cursor speed.
Ensured default values are sane.
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>
To make it easier to type a set of strings, apply some template magic to the
`Macros.type()` method. The same trick that is used in `Kaleidoscope.use()`.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Since we have a nice keydata_t union, use that, to convey it even more clearly
that we are mimicking the hand states in a way.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
By not using 32-bit ints, we already saved a noticeable amount of space. If we
follow the `*HandState` bit layout more closely, we can shave off some more
bytes too.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Dealing with 32-bit numbers on Atmega32u4 is very costy, so lets try to avoid
that, and use four 8-bit uints instead. This save us about a hundred bytes of
progmem.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The `SCANBIT` macro was not using `row` and `col` properly: if either was
anything else than a number (such as `col - 8`), the macro did not expand them
correctly, preserving operator precedence. As such, the right-hand side SCANBITs
were broken when used with masking, because the masking code uses `SCANBIT(row,
col - 8)`, and the `(7 - col)` part would expand to `(7 - col - 8)` which is
very different than `(7 - (col - 8))`.
This patch addresses the issue.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Before this commit, any SolidColor effects would appear in the LEDMode rotation twice (e.g. in the stock Model01-Firmware). They would be added to the rotation both on construction and in Kaleidoscope.use(). This removes the duplication, and makes SolidColor effects behave similarly to other effects.
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>
There are situations when one wants to ignore key events for a while, and mask
them out. These newly introduced functions help do that.
They are in the Hardware plugin, because this is where it is most efficient to
implement the masks: the hardware library knows how many bits it needs, and how
best to represent the masks. We use a 32-bit bitmap here, other keyboards may
use a different size, or an entirely different approach too.
This is one part of the fix to address keyboardio/Kaleidoscope#150.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of trying to exclude layer keys, exclude everything with a flag. Thus,
only the basic keys will receive the highlighting treatment, and the rest,
`Prog`, `Any` and the layer keys will not.
Thanks to @chughes87 for the report!
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To avoid issues with static initialization order, move the Mouse & AbsoluteMouse
initialization from the MouseWrapper constructor to MouseWrapper.begin, which
will be called from MouseKeys.begin. Thus, user code does not need to change.
This fixeskeyboardio/Kaleidoscope#140.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
As there are - or at least may be - other keys on the layer, not just NumPad
ones, those should be highlighted too.
Addresses the bulk of keyboardio/Kaleidoscope#149, by comparing the looked up
key with what is directly on the `numPadLayer`: if they are the same, then it is
a key that we assume changed, and do the coloring. If they are different (in
other words, the key on the `numPadLayer` is transparent or off), we skip the
highlight.
The downside is that we highlight layer switching keys too, which we may not
want. That will be addressed separately.
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
Requiring end-users to terminate macros with END strikes me as
easy to mess up, and perhaps inelegant. This commit removes the
requirement for end-users to terminate macros with END.
As a result of this commit, end-users (including other plugins) who
do use END will see a tiny amount of increased code size (1 byte per
declared macro I believe), but functionality remains intact.
Usage of END is hereby deprecated, and eventually #define END may
be removed in a future commit.
README.md has been modified with the new usage instructions, and
a note that usage of END is deprecated.
Instead of requiring the NumLock key row and column, and the numpad layer index
to be passed to `NumLock.toggle` on every call, derive the first two from
Macros.row and Macros.col respectively, and the latter from a new class
variable, which should be set in the `setup()` method of the sketch.
This way, `NumLock.toggle()` becomes argument-less.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To make sure that the active LED mode is restored to a good state, re-init it.
Without this change, LED modes that do all their work in the `init()` method
will not refresh when NumLock is turned off.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The new `init_mode()` method simply (re-)inits the current mode. Useful when a
plugin that changes LEDs outside of LED modes wants to reset the active LED
mode. Doubly useful when the active LED mode does all the work in its `init()`
method.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Having the LED effects of the NumLock layer as a special LED mode has a number
of drawbacks, like not interacting well with led mode switching: one can't get
back to the NumLock effect once switching away from it (but the mode remains
active nevertheless).
To avoid this and other issues, don't make the effect a LED mode. Instead,
override the active LED mode with the numlock layer colors. This way, it is
always in sync with the layer.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Adds a `Macros.type()` method, which expects a string in PROGMEM, iterates
through it, and simulates key presses. It converts ASCII codes to Key codes
during the process.
Assumes an US QWERTY layout on the host, supports all printable chars, and a few
control codes too.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
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>
A while ago, we added a bit of code to `bootAnimation()` that only did the
animation on first boot - this is not a desirable thing anymore, not in
`bootAnimation()` itself.
These days, one would use `Kaleidoscope-EEPROM-Settings`, and decide whether to
do the boot animation there. Since `bootAnimation()` is an optional thing, just
do the animation whenever the function is called, and remove the obsolete EEPROM
bits.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Updated the code to conform to the latest style guide. And added a bit of
documentation too, while there.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Given a `row`/`col` coordinate, this new function returns the index of the LED
under that key. To be used with the `led_set_crgb_at(i, crgb)` function.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of doing gamma correction when setting a LED color, do it elsewhere,
when talking to the LED hardware. This way, both the programmer, and the
end-user will deal with the unaltered, raw RGB values, and neither has to care
about when and how gamma correction is applied.
The counterpart of this will be in KeyboardioScanner, that re-introduces gamma
correction on that end.
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.
Allows setting all of the LEDs to custom, distinct colors (as opposed to
`led.setAll`, which sets them all to the same color). This allows one to
upload a theme in one go, without having to set each LED one by one.
Fixes#5.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of separating `flags` and `keyCode`, just use the `raw` combination.
Easier for higher level tools to work with.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
`eeprom.dump` and `eeprom.upload` has been merged into `eeprom.contents`,
reflect that in the command list, too.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
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>
Full documentation takes way too much space, and command names are a reasonable
compromise for discoverability.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Full documentation takes way too much space, and command names are a reasonable
compromise for discoverability.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Lift out the keyCode reading, event handling, and report sending into a small
helper function. Pretty much the same code has been called in a number of
different cases, lifting them out into a common helper improves clarity, and
reduces the size of the code, too.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The new step variants only use a one-byte argument, the `keyCode` part of a
`Key`, and they implicitly set flags to zero. This allows us to make macros even
more compact, by not having to use the flags when they are zero anyway.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of having to use a keydown & keyup step each time we tap a key, use a
combined event that does both. While this adds a tiny bit of code to
`Macros.play`, if our macros have many key taps (which by and large the most
common thing), we save a lot more. Three bytes per tap!
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This method uses the EEPROM only to augment the PROGMEM keymap: if EEPROM is
transparent, then PROGMEM is used. As such, the keymap in EEPROM is only an
overlay in this case.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The keymap.transfer command is only useful if we have both PROGMEM & EEPROM
keymaps, which will rarely be a case, and likely only temporarily, too. As such,
lift that out of the `focusKeymap` function, into its own. This makes the
command optional, and can save us some 140 bytes of program space (even more if
documentation is enabled).
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This adds the Kaleidoscope::AlphaSquareSymbols namespace, for symbols that fall
outside of the normal alphanumerics. The first such symbol is `λ`.
Fixes#3.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
We expect the keymap in EEPROM to be set up by the time we get to use it,
instead of having uninitialized EEPROM there. So remove the special handling of
0xffff.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Allows other plugins to request a slice of EEPROM, and returns the starting
location of their area. Makes a CRC out of the slice sizes, so that it can
detect when the EEPROM and the Sketch become out of sync. Handling that case is
left up to the user.
As a consequence, we no longer reserve a big chunk of EEPROM for the keymap,
that just becomes another slice of it, which can be anywhere. This makes it a
bit harder to adjust the size of it, but as far as this plugin goes, playing
with the EEPROM layout will usually mean having to update its contents from
scratch, anyway.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The `keymap.dump` command should dump up to `maxLayers` amount of layers,
instead of a hardcoded four.
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>
With these changes, the vertical scrolling of the mouse wheel is now properly
supported. It has no acceleration, because the wheel doesn't have one either. It
has a delay, however, which I tried to tune to a reasonable speed.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
WARP + Button makes no sense together, so reuse the _BUTTON bit for _WARP_END.
This will allow us to use the free'd up bit for something else.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
While it was a neat optimization to only turn LEDs off at init time, that is not
enough if there are other plugins in play, that work with the LEDs independently
of the active LED mode. Such a plugin is LED-ActiveModColor, which never turns
LEDs off, and relies on the LED mode to do that.
Since LEDOff did not turn things off on update(), when used together with
LED-ActiveModColor, the LEDs under the modifiers stayed active, even after the
modifiers went inactive.
With this simple change, LEDOff will now update, and the problem's gone.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When using AlphaSquareEffect, in the event handler hook, return early if the
currently active LED mode is not us.
Fixes#2.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
If we start with isLEDChanged unset, then after flashing, the `R0C0` key will
remain lit, because we think it is off, while it is not. Setting this flag
results in the first update cycle updating everything, no matter what, which is
the safest thing we can do.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Since we keep the eventHandler on at all times, even when we are not active,
clear the map when switching to the layer. It's easier this way than trying to
turn the eventHandler off.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When we light up a new key, clear the previous one (but only if it isn't the
same, to avoid flickering).
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The new singleton objects implements a LED mode where each pressed key
will light up the appropriate symbol on the LEDs, on the side it was
pressed on. We use different timers for each half.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
While it is possible to play with the ->color property, sometimes one
just wants to override the color once. In this case, saving the previous
value, and changing it back would be an overkill.
Instead, add a few functions that take a color argument as well, and
make the color-less arities use the global property.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of using the supplied linear color component values as-is,
convert them to gamma-corrected, non-linear values first. This way, we
can use numbers like 127 to mean half brightness, and have it
automatically translated to the correct, gamma-corrected value.
Table copied from:
https://learn.adafruit.com/led-tricks-gamma-correction/the-quick-fix
This adds a bit over 256 bytes of code, but makes working with colors a
lot easier.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Call `macroAction` for all `keyState`s, not only when a key toggled on. This
lets the macro itself decide when to act, and makes it possible to have macro
effects on the other states.
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>
Drop the `load_primary_layer` and `save_primary_layer` methods, because
`save_primary_layer` is not used anywhere, and as such, the whole thing is
pointless at this time.
Furthermore, if we want to allow plugins to implement EEPROM storage, then its
best if we leave the default layer save/load to the plugins too.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To further improve the LED performance, sync only when there is a change. We do
this by tracking when change happens, assuming everyone uses the provided
accessors.
While we do a bit of extra work each cycle to do the tracking, that pales in
comparison to what we gain by not having to transfer data needlessly.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of calculating time deltas every time we want to check a
timeout, calculate the projected end ahead of time.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of calculating the time delta each time we want to check for a
timeout, calculate the projected ending time ahead of time.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of calculating the time delta each time we check for a timeout,
pre-calculate the projected ending time, and compare against that.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of doing a substraction and a compare in the if check, whenever we reset
the timer, add `syncDelay`, and compare against the timer only. Should result in
marginally better performing code.
Thanks @obra for the suggestion!
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Because `led_sync` is a major cause of slowness, do not sync every cycle. In
most cases, it is pointless to sync 100 times a second, about 60 - or even 30 -
may be more than enough.
For this reason, introduce a timer, and a settable delay: we'll only call
`led_sync` once the delay's up. It can be set to 0 to call it every time, but
defaults to 16 (for about 62 syncs/sec), as a safe bet.
This speeds the loop up dramatically, except for the few exceptions where sync
is called.
Fixes#1.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The `CRGB` macro takes rgb values as arguments, in this order, and creates a
`cRGB` instance with the components rearranged to fit the ordering of the
hardware (in the case of the Model01, bgr).
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>
Renamed the library to Kaleidoscope-LEDEffect-SolidColor, and followed up with
other renames.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Not all keyboard hardware has per-key LEDs, and not all of them define the LED_*
helpers. To make the LEDControl at least compile for these, guard the
BootAnimation with a Model01-specific ifdef.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of counting loops for the purpose of calculating acceleration, use
timers and steps instead. This means that we can now tune how often the mouse
moves (`speedDelay`), how much it moves when it does (`speed`), how fast
acceleration is (`accelSpeed`), and how often we accelerate (`accelDelay`).
By default, the movement speed is one, and there is no delay, while acceleration
has an 50ms delay, and a speed of one.
But all of these can be tuned at run-time: we can turn off acceleration
completely, or slow down the mouse considerably - the possibilities are almost
endless!
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
With the recent speedup of the scan cycle, we need some delays for the animation
to look nice.
Fixes#2.
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>
Moved over the primary layer read/write code from KeyboardioFirmware, and
renamed them to `load_primary_layer`/`save_primary_layer`, because they deal
with layers, not keymaps now.
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>
This is a library that implements the hardware-specific pieces for the
Keyboardio Model01, to be used with KeyboardioFirmware.
It's the same as `src/Model01.cpp`, `src/Model01.h`, `src/KeyboardConfig.cpp`,
`src/KeyboardConfig.h`, `src/utils.cpp`, and `src/utils.h` from
KeyboardioFirmware, merged into two files.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This works both when the hardware bits are still in KeyboardioFirmware, and when
lifted out, too.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When acting on `moveIntent`, set up the direction first, and move the cursor
only once, instead of twice (once for each axis). This makes the movement even
smoother, and also saves us a few bytes of code.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Move the hooks inside the `MouseKeys_` object, and drop the
`handle_mouse_key_event` function, by inlining it into the event handler hook.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of calculating separate acceleration for the x and y axes, use only a
single one, that applies to both axes. Thus, holding mouse up, and then pressing
and holding right will move the mouse cursor in a straight diagonal line,
instead of a curve.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of acting on mouse movement keys immediately in the event handler hook,
just store them, and act on them during a loop hook. This has the effect of
collecting all movement intents noticed in a full scan, and acting on them in
one go, rather than acting individually.
This makes diagonal movement (up & right keys pressed at the same time) a lot
smoother, at the cost of a few ms of delay. The delay is not noticeable, and the
smoothing would be a good trade anyway. No more jerky diagonal movements!
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
`TOGGLENUMLOCK` is the index of the macro, to be used in the `macroAction`
function, and `Key_ToggleNumlock` is to be used in the keymap, instead of
`M(0)`. This is considerably friendlier than before.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To make the signature of `macroAction` simple, the `row` and `col` properties
are not passed in every time anymore, but they are available as `Macros.row` and
`Macros.col`, respectively.
This keeps the function simple, but still allows access to these properties for
the rarer case of needing them.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This way the end-user does not have to explicitly call
`Keyboardio.use(&LEDControl)`, it is enough to use a LED effect.
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>
First of all, to disallow switching to LEDNumlock, we need to do the check in
the `.init()` method, not in `.setup()`. Second, tracking the previous LED mode
can be done a lot simpler - and a lot reliably.
With these changes, the NumLock LED effect works as it is expected to.
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>
This is a slightly tweaked version of LEDControl from core
KeyboardioFirmware, along with the built-in LED effects.
The one major change is that LED sync is now called just before the update,
instead of at the end of the main loop. This, however, should not be a
noticeable change.
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>
This is the same Keyboardio-MouseKeys that lived in core KeyboardioFirmware up
until this point. It has been lifted out, the same GPL-2 license file added,
along with a README, and the URL in library.properties has been updated.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This is the same plugin that was in KeyboardioFirmware before, with a README,
and a license file attached, and the URL corrected in library.properties.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Only turn the LED off if it was on before. Otherwise we will turn off those too
that were not in the map yet.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of relying on the active effect to turn the LED off, do so
ourselves at the end.
Fixes#1.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of syncing right after updating, sync at the end of the loop. This
allows hooks (both loop and event handler hooks) to override LED colors, without
cooperation from the active LED effect, and without flickering.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Because we have `raw`, `rawKey` was confusing. Rename it to `keyCode` instead,
which better conveys what the byte is for.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Makes some code not only easier to follow (by not having to use `.raw`
all the time), but for some odd reason, smaller too, in many cases.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
We want the `Keyboardio` object to be a singleton. If it is static, then
each library that gets compiled separately, and uses it in one way or
the other, will have a copy of it.
Making it extern, we'll only have one copy, as it should be.
I don't think there were any bugs caused by it being static, but it was
certainly a tiny bit of wasted code and memory.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
With the Layer code not using the hooks anymore, the Arduino builder will tell
the linker to remove any unreferenced code. As we are using dot_a_linkage, that
means that the hook functions will be removed due to being unreferenced before
plugins had a chance to reference them.
Add a dummy call in Keyboardio_::setup() to prevent this case.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The layer handling is a core functionality, it should be active at all times,
and should be at the very end, before the default event handler. Otherwise there
may be ordering issues, when a plugin wants to return layer keys from its own
event handler.
This also saves us a couple of bytes of both code and data, as an additional
bonus!
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Makes it obvious when one forgets to close the arguments with a sentinel, by
giving the compiler a hint.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When trying to update the LEDs, do not unconditionally call `modes[mode]->init`
and `modes[mode]->update`: we may have no effects installed. This change stops
the firmware from crashing with an NPE if no LED effects are enabled.
Also sets mode and previousMode to zero in the constructor, so we start with a
deterministic state.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of returning a bool, to signal whether further processing should be
done, return a Key. Reason being, if we want to replace a key with another, for
subsequent handlers, it is a lot easier if we can modify what gets passed along,
than it is to inject a key, and try to avoid loops and infinite recursion.
Nevertheless, injecting keys is still possible.
This is not immediately useful for the core firmware, but makes it trivially
easy to upgrade keys from their normal behaviour to something special: for
example, a one-shot handler can auto-promote modifiers to one-shot, simply by
scheduling a promoter handler before the real one.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Some behaviour would benefit from knowing the last report, some would want a
clear report and a way to pre-fill the next one. For this reason, we need two
places to call loop hooks from: one after scanning the matrix and updating LEDs,
and another after sending and clearing the report.
To save space and sanity, we call the same hooks twice, but the second time, we
set the `postClear` flag, which is false the first time.
All users have been updated.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To make keymaps look nicer, easier to read, introduce the `___` and `XXX`
aliases. The former is an alias to `Key_Transparent`, the latter to `Key_NoKey`.
The `genetare_keymaps.pl` tool was updated to support these, too, with the
additional functionality, that all strings that are made up entirely of
underscore or Xes, and are two or more characters long, will be treated as
`___`/`XXX`, respectively. This makes it possible to space keys in a nicer way
in the source layout files.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
`keymapEntry.rawKey` contains the target layer, but offset by
`MOMENTARY_OFFSET`. That value must be subtracted from the value before
comparing it to anything, or switching to another layer.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of having a primary and a temporary layer, store the state of at
most 32 layers in a bitfield. These can be individually turned on and
off, and key lookup starts from the top, and goes downwards until the
default layer to find a non-transparent key.
This allows one to reuse a partially transparent layer: set the default,
and the transparent parts will be reused. The numpad layer was updated
accordingly.
Having an interface to the layer switching things also makes it easier
to build other behaviour on top of these.
As part of the rework, layer handling was moved to a separate file, and into its
own, full-blown handler. Furthermore, we now use a single bit for all keymap
events.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of registering the default handler late, always call it at the end if no
other handler took care of the event. This makes it less of an issue to order
`Keyboardio.use()` and `Keyboardio.setup()`.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Introduces the RESERVED bit, a bit reserved for plugins. If it is set, the core
handlers will not handle the event.
Also rearranges the SYNTHETIC bits, to make slightly more sense. In practice,
this means that LED_TOGGLE was promoted to a flag bit, under IS_INTERNAL.
The handler that deals with synthetic events was updated to look at the flag
bits in an order that does not cause confusion, and preparations were also made
to turn it into an independent handler on its own (but that step has not been
taken yet).
This is just groundwork to clean things up, and make the event flow easier to
follow.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
We can't register hooks from constructors, because there is no guaranteed order
in which the objects will be created. So it may well happen that the Keyboardio
object gets created later, and zeroes out everything. Or it gets created first,
and registers the default handler as the first one, making all the others
pointless.
Instead, we create a KeyboardioPlugin class, that has a `begin` method. This is
responsible for setting up the hooks and whatnot. To make things simpler (for
some values of simple), a `Keyboardio.use` method is introduced, which, when
given a NULL-terminated list of plugin object pointers, will call the begin
method of each.
All LED effects and other plugins that used to register a static object now use
an extern, and had their initialization moved to the `begin` method.
The end result is not the nicest thing, but it works. We can try figuring out
something nicer later.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Wraps the value LCTRL & friends in parens, so that they can be easily passed on
to other macros without the compiler getting confused.
Also moved the definition up, just below the _HELD bits, so that these macros
can be used for other key definitions, such as `Key_Pipe`, and so on.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Add a number of helper macros that aid in constructing the Key code for
keys with modifiers held. These can, of course, be embedded in each
other, so to have a key on the keymap that has all currently supported
modifiers pressed, along with `X`, one would write:
`LCTRL(LALT(RALT(LSHIFT(LGUI(X)))))`
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of calling loop hooks before anything else, including scanning
the matrix, call it after all that, at the end of `Keyboardio_::loop()`.
This is less surprising, and should not have any ill side-effects,
either.
(Based on a discussion with @obra on IRC.)
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>