Since macros and other injected keys do not clear the report, we need a way to
release keys. The new `release_key` function does just that, similar to how
`press_key` does it for key presses. It is called by the default event handler
when the `keyState` toggles off, and has the `INJECTED` bit set.
The reason behind this is that keys that will need this special treatment will
always be injected keys. And those injected keys that do not need this
treatment, can be handled by an event handler prior to the default.
This should fix the macros not releasing keys issue.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of hardcoding the macro actions into the core firmware, use a
`macroAction` function that is marked weak. This makes it possible to override
the function from Sketches, and implement the handlers there.
While there, also made sure that the `macroAction` is always called, with
`keyState` argument appropriately set. With this, macro actions can trigger on
keyup, or while held, or anytime the implementor wants, not just on keypress.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of having a previousState and a currentState, of which at most
two bits are used, use a single byte. This saves us a lot of code space,
and makes a number of things easier, too.
The helpers were redone as macros, since they are just bit checks now.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
They are not used anywhere, and as such, are a distraction. The states
will be reworked into something similar that was now dropped, but that's
a separate patch.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To make the code in the keyswitch state checking functions clearer, use
a macro instead of repeating the same constant everywhere.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of abusing `Key_NoKey`, use the new `INJECTED` flag in
`handle_key_event` and `handle_key_event_default` to check if the event
is an original, or an injected one.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The INJECTED flag can be used by handlers to determine where the event
originated from: as a result of a direct keypress, or if it was injected
into the event loop some other way.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
When one adds or removes a layer from a keymap, the keymap size has to
be adjusted in the call to `Keyboardio.setup()`. This is easy to forget,
so as a helper, introduce `KEYMAP_SIZE`, a macro that automatically
computes the size at compile time.
This way, one does not need to remember to update the size anywhere.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Save the seen state in EEPROM, so that the boot animation is displayed
only on first boot, and not every time the keyboard boots, or is plugged
in.
This way, we still have a nice welcome animation on first boot, but it
won't become an annoying delay every time the keyboard boots.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The primary reason for the move is to be able to disable mouse keys
completely, and not even compile them in. For this to work, it needs to
be in a separate library, otherwise it will always be included, even if
not active.
So, this patch turns mouse-keys into a simple plugin, included with the
core firmware! This makes the default event handler a bit simpler, the
code marginally smaller, and the feature completely optional.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
With the BootAnimation not functioning as a LED effect anymore, ship a
dedicated off effect.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Having the boot animation as a LED effect, making it function as an
"off" state, while a novel idea, is confusing. For this reason, make it
just a simple function we can call from the Sketch's `setup()` method.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
For those who'd like to work with C arrays, instead of generating
layouts from some other source, the `KEYMAP` macro makes it easier to
define a layer. The parameters in the macro arguments are arranged in
such a way that they can be formatted in a way that matches each hand
more closely. Similarly, a `KEYMAP_STACKED` is introduced, where the
hands are under each other, not side-by-side.
This is just aesthetics, for the C-savvier users.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
It would be nice if LED effects could be activated via their object, not
just their number, so that one could write - say, in a macro -
`myEffect.activate()`, and have it become the active mode.
To implement this, `LEDControl_` gains an `activate` method, that takes
a pointer, finds it in the mode array, and switches to its index (if
found). `LEDMode` gains an `activate` method too, which uses
`LEDControl`s new method of the same name to activate itself.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
While this function had a declaration in the header, it lacked an
implementation. With this patch, `key_led_map` moves to the cpp from the
header, and the function gains an implementation.
An additional helper, `led_set_crgb_at(row, col, color)` is added too,
similarly to the other arities.
This makes it a lot easier to address LEDs when knowing the key
position.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Recreate LEDControl as a class with pluggable parts, similar in vein to
the event handler and loop hooks. Except in this case, only the current
effect runs at any one time, the current one.
All existing effects were separated out into plugins, and the default
firmware example was updated too. All of them were pretty trivial, save
the special NumLock effect: that one also installs a loop hook, and
switches the LED mode if need be. Its setup function also skips to the
next effect, if the mode was selected manually.
Behaviour should be the same as before, but LED effects are now
pluggable, at the cost of some code and data size increase.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Instead of not handling the case where the LED index is out of range,
and thus producing a warning, return a black color instead. It's as good
as anything else, but at least gets rid of the warning.
And, it goes hand-in-hand with the set counterpart, which, in a similar
case, does nothing: thus the out-of-range LED remains black forever.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
After writing the row to Serial, return false, so that the key will be
further processed by the next handler. Also fixes a compile-time warning
with -Wall.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Do the mappedKey lookup earlier, in handle_key_event, so that if any of
our handlers need to look at the mapped key, they do not have to look it
up themselves. This simplifies plugged hooks considerably, as they can
always assume that the mapped key they receive is correct. They still
receive enough information to do the lookup themselves, though, if they
ever need that.
Additionally, in handle_key_event_default, baseKey is only looked up if
mappedKey was NoKey. This is so that hooks can defer to this function,
via handle_key_event, setting their own mappedKey, without having to
worry about setting a row/col that would map to a special key on the
base layer.
Fixes#39.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
To make replacing work sanely, we first NULL out both the eventHandlers
and loopHooks arrays in the Keyboardio_ constructor. This allows the
replace functions to just run through the whole array, and either see
hook pointers there, or NULL. So they don't need to be afraid of garbage
being there.
This makes the replacing very easy: run through the array, and replace
the first occurrence of the old hook with the new. This further
simplifies addition: the old hook we pass in, will be NULL. If we run
out of space, it silently fails, like before.
Replacing hooks is important for cases where one wants to build features
that can be toggled off, or their behaviour otherwise changed at
run-time. In this case, the most efficent way is to replace the hook,
which is what these new helpers allow us to do.
This closes#36.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Briefly document the key event handling flow, to make it clearer how the
functions can be used.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
There are scenarios where one would want to inject a keycode into the
event handler chain, restart the processing from scratch, but with a
keycode different than what the lookup would normally yield. For
example, with one-shot modifiers, a feature one may wish is to be able
to turn the one-shotness off, and have them act as normal modifiers.
This is easily done, if we can remove the one-shot markup, and let the
event handler process the resulting code as-is.
This makes that possible: in a custom event handler, just call
handle_key_event() with the first argument set to the desired code, and
the rest left unchanged. This makes it possible to inject events: not
just register keycodes with the HID, but inject synthetic events,
something much more powerful.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
This moves the layouts to the sketch directory, so that other sketches
can easily use a different keymap. In the process, not much had to be
changed, and a number of things still remain in the core that assume the
default keymap (such as the NUMPAD_KEYMAP thing in LEDControl.cpp), but
this is a first step.
The downside is that the keymap is no longer static, because that would
conflict with the extern declaration, and the NUMPAD_KEYMAP is a byte,
instead of a compile-time define.
Alltogether, the difference is small enough to be acceptable.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Naively using the "1 << n" shifting will default to 8 bits, because 1
fits in there. To make it 32-bit aware, not just by context (at which
point the damage may have already be done), force the "1" into a
uint32_t.
This silences the warnings, and also corrects the defines.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
The RxCx set of macros help addressing key positions within the keydata
the Scanner returns for us. These can be ORed together to form a pattern
to match against, for example, or to look for a certain key by address,
and so on.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
Having the default handler in the list by default prevents other things
to hook up before it. Add it in Keyboardio_::setup instead, so that
others have a chance to add themselves first.
Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>