Now that `layer_count` is (potentially) available, we can start
looking for active layers at the top _defined_ layer instead of the
top _possible_ layer. This ought to be more efficient, especially for
sketches that don't have lots of layers defined.
Also introduced the `MAX_LAYERS` constant (#define).
Instead of discrete press & release tracking, press the mousekey when the
physical key is pressed, and like `Keyboard`, send & clear the report once per
cycle, instead on every action.
This fixes#10.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Instead of sending a press & release for the consumer key when the physical key
is released, send a press each cycle it is held, a report along with the
keyboard report, and clear the consumer report each cycle too.
This will prevent these keys getting stuck, or sending multiple presses in the
same report.
Fixes#176.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
If we call updateLiveCompositeKeymap() on key release the keymap gets
updated before the release event occurs, and any ShiftToLayer(N) key
with a different definition on layer N won't work properly. Before its
release event is processed, it gets updated to the new value, and
layer N doesn't get turned off. If we only update the live keymap on
key press events, we don't have this problem.
replacing the Key_16bit macro with CONSUMER_KEY macro allowed us to
add the IS_CONSUMER and SYNTHETIC flags within the CONSUMER_KEY macro
and simplify the Consumer key definitions.
If it's an old sketch, LayerCount will default to 0, so in order for
Layer.on() to function, don't bother checking for out-of-bounds if
LayerCount == 0.
Declaring LayerCount as a weak symbol in layers.cpp lets us override
it if the CREATE_KEYMAP macro is used to define the keymap in the
sketch file, but still allows old sketch files to compile without
errors.
Still some changes necessary to allow old sketches to work
properly (Layer.on() will abort before doing anything).
This macro allows the definition of the LayerCount variable and the
keymaps[] array together. It shouldn't break old sketches, but this is
probably not all that's necessary; LayerCount still doesn't get
initialized outside the macro.
Update key_events.cpp (IS_INTERNAL Handling)
I'm merging this for now, even though I know it's not the 'right' solution. But I'd like Mute to work correctly for MP2 keyboards and we're on deadline
This file is meant to be included in sketch files in order to make
data available to Kaleidoscope functions. In particular, the size of
the keymaps[] array (i.e. the number of defined layers), which is
needed in order to prevent reading uninitialized memory past the end
of that array due to Key_KeymapNext_Momentary.
By moving the IS_CONSUMER flag to B00001000 instead of
B00000010 (swap with IS_INTERNAL) we can detect the if the key is a
consumer key and strip out the flags and use the full 10bit to send to
the hid report. This enable us to use all the Consumer_* keys
Reordered if chain in handleSyntheticKeyswitchEvent to fix a bug preventing some Consumer and System Control HID functions from being sent due to bit overload/collision with the IS_INTERNAL flag.
Instead of trying to track numlock ourselves, rely on the host telling us what
it thinks the state is. This is much more reliable than what we were doing, and
hopefully fixes most of - if not all - the issues we were having with NumLock.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Make Kaleidoscope_ a friend class, so that it can access .begin. The
reason behind this is that .begin is an interface towards
Kaleidoscope.use(), and that function should be the only user. To
discourage its use, make it protected.
This does not break any existing - and valid - code, but allows us to
slowly migrate the plugins to a protected begin() method.
Fixes#177.
As discussed in #196, if we are making `KaleidoscopePlugin.begin` protected, we
might as well give it a better name. That name is `initialSetup`, and this
change is the first step towards the migration. It introduces `initialSetup`
which will call `begin` for now, and deprecate `begin`, which is no longer an
abstract function.
Once everyone migrated to the new name, we can remove `.begin`, and turn
`.initialSetup` into an abstract function.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Intended to force-reactivate the current LED mode, in case we want to refresh
the whole board, and make sure we do so even if the current mode's update is a
no-op.
This can happen when we overrode some keys, and it becomes less costly to update
everything than to iterate over the updated keys.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
When implementing `.refreshAt` before, some dead code was left in
Kaleidoscope-LEDControl.cpp, code that is now implemented in the header.
As these are implemented elsewhere, and are `#if 0`'d out anyway, drop them.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Make `Kaleidoscope_` a friend class, so that it can access `.begin`. The reason
behind this is that `.begin` is an interface towards `Kaleidoscope.use()`, and
that function should be the only user. To discourage its use, make it protected.
This does not break any existing - and valid - code, but allows us to slowly
migrate the plugins to a protected `begin()` method.
Fixes#177.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
`Kaleidoscope.use` is a much better interface, therefore deprecate USE_PLUGINS.
We do this by creating a wrapper function, `__USE_PLUGINS` that will call
`Kaleidoscope.use` under the hood, but has a deprecated attribute attached. We
then make the `USE_PLUGINS` macro call this function.
We do this because we want to make sure that the list is NULL-terminated, and
for that, we need the macro.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
This was only ever used for `Kaleidoscope.setup()`, and while the variant that
takes an argument is deprecated, and emits a warning already, we can do the same
for `KEYMAP_SIZE` too.
This does set the const to 0, so if used anywhere else than
`Kaleidoscope.setup()`, it will have undesired side-effects. But as far as I
saw, it was never used elsewhere, thus, this change should be safe.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
We do not use `keymap_count` anymore, so deprecate this variant of the setup
function, with a message that also tells the user that `KEYMAP_SIZE` is
deprecated too.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Turn `event_handler_hook_use` and `loop_hook_use` into real functions, so that
we can apply a `deprecated` attribute, which in turn will emit a compile-time
warning when either of these functions are used.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Neither of these are used in any plugin, within Arduino-Boards or outside of it.
We keep the `_hook_use` aliases, because there are a few users of it outside of
Arduino-Boards.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
Use `LAYER_SHIFT_OFFSET` instead of `MOMENTARY_OFFSET`, which will start
emitting compile-time warnings now.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
As discussed in #190, and later on IRC, this renames ToggleLayer to
LockLayer (updating the documentation at the same time), and introduces
the UnlockLayer alias, for clarity.
MomentaryLayer also got a new name: ShiftToLayer, and new documentation
to go with it.
Signed-off-by: Csilla Nagyné Martinák <csilla@csillger.hu>
This introduces `ToggleLayer(n)` and `MomentaryLayer(n)`, which make it
easier to switch to layers higher than five, and allow one to use enum
values in place of `n`, such as: `ToggleLayer(NUMPAD)`,
`MomentaryLayer(FUNCTION)`.
Signed-off-by: Csilla Nagyné Martinák <csilla@csillger.hu>
Requiring the end-user to use a macro to have the NumLock effect is a bit
confusing. We can do better than that, by using an event handler hook, and
catching `Keypad_NumLock` presses, and toggle on keypress.
This way, the macro is not necessary, and all the user has to do, is to use the
plugin, configure `numPadLayer`, and done.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
We want to start with a pre-cached state, so we have both less work to do when
keys are first pressed, and so that plugins that rely on the live composite
state will work reliably too.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
For all cases outside of Kaleidoscope itself, we are good with the value of
`highestLayer`, and do not need to re-scan the layer state. For this reason -
upon @obra's suggestion - rename `Layer.highest()` to `Layer.top()`, and the old
`Layer.top()` to `Layer.updateHighestLayer()`, and make the latter private, and
update the `highestLayer` member variable instead of returning the number.
Signed-off-by: Gergely Nagy <kaleidoscope@gergo.csillger.hu>
`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>