Scheduled for removal on 2018-08-20, this drops the V1 API and all deprecation
messages. We only keep one message, that errors out in case
`KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` is set. Also drops `Consumer_SNapshot`,
which was a typo'd name.
`UPGRADING.md` updated accordingly.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This is just to clarify to anyone who may be reading the sources as to why B00100000 is missing from the flags defs. Not a big deal but I thought it would be useful…
This, along with the change
keyboardio/Kaleidoscope-HIDAdaptor-KeyboardioHID@a4368f13e7a1b58e, makes
it so a rollover from a key with a mod flag applied to one without will
not result in the flag from the modified key affecting the next keypress.
The breathe function is somewhat costly and is found to cause drag in
mouse movements. This commit seeks to fix this problem.
It is observed that the function doesn't change output value for every
input value. It only causes the output brightness to increase by 128
units (from 80 to 208) over 2048 ms (the half-period). This means 1 unit
for 16 ms. But a brightness change of 1 unit doesn't mean much visually
especially considering persistence of vision. A refresh rate of 20 per
second ie 50 ms between LED updates is found to be sufficient to avoid
the drag effect while maintaining smoothness in brightness changes.
While we do clear the report every cycle, similar to how key release events are
explicitly removed from the report, mouse movements should get removed too. This
makes it possible to use them in macros reliably, without surprising results (an
extra report sent at the end of the macro).
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This mirrors `moveMouse()`, and the intent is to use it when releasing a mouse
key outside of the main event loop (such as during a macro).
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When using `Kaleidoscope.use()` and the V1 API is disabled, we want to display
an error. The current method of doing that is not reliable, it sometimes works,
sometimes will error out even when not using `Kaleidoscope.use()`. To fix this,
delay the initialisation of `.use()`, so it only evaluates when used, and thus,
only fails with a descriptive error in that case.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Override the copy constructor of `combo_t`, so that we can display an error when
initializing using the old-style API.
Fixes#8.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
In preparation for the sunset of the V1 API, when using the V2 API only, give a
nice error message on `Kaleidoscope.use()`, instead of simply not defining it.
This makes the upgrade path a little easier.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When a key was released, we were failing to send the release event explicitly. For most
plugins, this didn't matter, but it was causing a problem for Leader, which acts on
release events. By returning `EVENT_CONSUMED` instead of `OK`, we were stopping the
release event from getting through to Leader, and thus a qukey with a Leader key as its
primary keycode would fail.
When the V1 plugin API is enabled, we need to override `onSetup`, to not call
`setup()` twice: once via the v2 default `onSetup`, and once via the legacy API.
Take special attention to call `LEDControl.mode_add`, so that the effect does
register as a LED mode.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When using the V1 compatibility layer, in the `onSetup()` method, we need to
call `LEDControl.mode_add()`, otherwise the mode does not register, and will not
function.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
If we do not clear `should_cancel_` there, it remains set indefinitely (until it
gets unset for some other reason, like interrupting a non-sticky OneShot). If it
is set, we can't enter sticky mode.
So clear it when canceling stickiness with a third tap, just like we clear it in
`afterEachCycle`.
Fixes#34.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The default `onSetup` will call `.begin`, to support initializing plugins using
the V1 plugins while using `KALEIDOSCOPE_INIT_PLUGINS`. However, plugins that
implement a compatibility layer so that they can be used with both the new API,
and with `Kaleidoscope.use()` will have a `.begin` method too. Which the default
`onSetup` will call, and we'll register the compatibility layer too, in addition
to the new-style event handlers. This results in many things running twice,
which leads to all kinds of problems.
For this reason, override `onSetup`, so that it does not call `begin`. When used
with `Kaleidoscope.use()`, the plugin will still work, so compatibility is
maintained. But the bug is now gone.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Unfortunately, the way we reported the use of an old-style API also triggered
when not using it. Change that to only trigger when we DO use the old API, by
marking the `combo_t` constructor private.
Unfortunately, this does not allow us to use a custom error message.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of manually counting set bits, use gcc's `__builtin_popcount()` for a -
supposedly - more efficient count.
Also initialize the counter to zero, while there.
Fixes#11.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of iterating through all the bits, use `__builtin_popcountl()`, provided
by gcc, which should be considerably more efficient.
Fixes#27.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
`Consumer_SNapshot` really should have been `Consumer_Snapshot`, so lets fix it.
However, the typo'd name is left in place as an alias, in order to not break any
existing user code, however unlikely the use of this key is.
Sadly, we can't easily add a deprecation warning, because key_defs.h, which
defines `Key`, depends on `key_defs_consumerctl.h`, so we'd end up with a
circular dependency if we tried to add a deprecation.
Fixes#339.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
As per UPGRADE.md, remove `Kaleidoscope.setup(KEYMAP_SIZE)`,
`event_handler_hook_use`, `loop_hook_use`, `USE_PLUGINS`, `MOMENTARY_OFFSET`,
`key_was_pressed`, `key_is_pressed`, `key_toggled_on`, and `key_toggled_off`.
These were deprecated between July and October 2017, and have been marked for
deletion for over a month.
Also updated UPGRADE.md, moving the section about these to a new, "deprecated
and removed" section.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When using the old API, fail with a helpful error message that points to
`UPGRADING.md`, which explains in simple detail the migration process.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The old `RxCy` macros were recently changed to be key indexes instead of
per-hand bit indexes, and `KeyboardHardware.isKeyswitchPressed()` and
`KeyboardHardware.pressedKeyswitchCount()` were introduced as a way to peek into
the keyswitch state. This little change migrates TestMode to use them.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of using a list of left/right-hand states and an overrideable global
callback, use a map of action and key-list pairs. This makes the plugin much
more portable, does not require any hardware-specific knowledge within the
plugin, and does not require us to treat the hands separately.
This in turn, results in a friendlier user interface, at the cost of limiting
the maximum length of a combination to five keys. A small price to pay.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of `getKeyswitchStateAtPosition`, which is long, unintuitive and feels
wrong too, introduce `isKeyswitchPressed`, shorter, better, more
reasonable (because it returns a bool - we support only two states anyway!).
Additionally, add `pressedKeyswitchCount()`, which returns the number of key
switches pressed.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of `getKeyswitchStateAtPosition`, which is long, unintuitive and feels
wrong too, introduce `isKeyswitchPressed`, shorter, better, more
reasonable (because it returns a bool - we support only two states anyway!).
Additionally, add `pressedKeyswitchCount()`, which returns the number of key
switches pressed.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This is sufficiently low-level that it is OK to use `KeyboardHardware` for it.
It's not a HID thing, either.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Move `KEY_INDEX` here, and turn it into a `constexpr` function, `keyIndex`, and
convert the `RxCy` macros to constexpr values instead.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
To allow the hardware plugin to use a more efficient way of representing the
index (if need be), and to be able to turn it into a constexpr, move it to the
hardware plugin.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
To be used by the hardware implementations, `KEY_INDEX` tells us the index of a
key, from which we can figure out the row and column as needed. The index starts
at one, so that plugins that work with a list of key indexes can use zero as a
sentinel. This is important, because when we initialize arrays with fewer
elements than the declared array size, the remaining elements will be zero. We
can use this to avoid having to explicitly add a sentinel in user-facing code.
Additionally, we add `getKeyswitchStateAtPosition` to the HID facade. See its
documentation in `Kaleidoscope-Hardware`.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Implement `getKeyswitchStateAtPosition`, a hardware-agnostic way to peek into
the keyswitch state. Also transition the `RxCy` macros to `KEY_INDEX`, to make
it easier for hardware with more keys than 64 to implement them, and to make
their values unique across a keyboard, not just across a keyboard half.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of only having an ifdef in the body of deprecated methods, and leaving
it up to the compiler to optimize out the empty & unused, explicitly wrap the
declaration of them within an ifdef too. This will make it easier to remove
everything V1 at a later point, and we're not at the mercy of the compiler,
either.
Fixes#327.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We do not want user code having to deal with KeyboardHardware, so wrap
.detachFromHost and .attachToHost ourselves.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
These functions can be used to detach from the host, then re-attach, possibly
with different properties, without having to reboot the device.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Having it at the brightest uses too much power, and may result in power use
surges when switching between LED modes and NumPad, which in turn can force the
operating system to disable the whole device. To avoid this, lower the
brightness to 160, a carefull tuned value, also used by the `solidRed` mode in
the factory firmware.
Fixes#9.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The multiplication by 99 can overflow an int8_t depending on whether the
expression is coerced to a regular-sized int (based on the 99 literal).
Just to be safe, perform a cast to int16_t in case the coercion does not
happen.
Previously, diagonal movements were not reduced in the two axes,
resulting in movement that was too quick. This commit divides diagonal
movements by sqrt(2) / 2 to correct the movement speed.
The net result is that diagonal movement should feel smoother and speed
more as expected.
This removes WakeupKeyboard, because a similar feature was integrated into
BootKeyboard itself, rendering it useless.
See keyboardio/KeyboardioHID#35 for an explanation of the whole situation.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of repeating the same cRGB reading code in three places, use the
recently introduced Focus.readColor() function. This both makes the code
cleaner, and more than 50 bytes smaller too.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of using a lambda (which is not constexpr in C++11), use a temporary,
anonymous struct instance to wrap the `static_assert`, which is constexpr in
C++11.
Fixeskeyboardio/Model01-Firmware#53. Thanks to @noseglasses for finding the
cause, and explaining the fix!
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Many plugins use timers, and most of them will call `millis()`, which isn't
wrong, but isn't the most efficient either. While `millis()` isn't terribly
expensive, it's not cheap either. For most cases, we do not need an exact timer,
and one updated once per cycle is enough - which is what `.millisAtCycleStart()`
is. Having a timer that is consistent throughout the whole cycle may also be
beneficial.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of running `scanMatrix` whenever we get there, use Timer1 to set a
consistent period. This does not mean we'll run every time the timer is up, but
we will run at consistent intervals.
Fixes#6.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This adds a very simple debouncing algorithm for debouncing. It works by making
sure a key is not changing state more than a configurable amount of cycles.
Defaults to five cycles for now.
Fixes#1.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The global `ErgoDox` symbol should be a shortcut, an alias, to KeyboardHardware.
When using ErgoDox-specific functionality, `ErgoDox.someMethod()` is much
clearer about that than `KeyboardHardware.someMethod()` would be.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
The member functions of the union now take all arguments const, meaning
that it is not possible to modify this value somehow. This reduces the
chance of subtle bugs and widens the contexts in which these member
functions can be used.
Furthermore, one signature took a `Key' by value while all functions
take `Key' by reference. For the sake of consistency, this was adapted
to.
Making the member functions of Key `const' explicitly flags that they
will not change the union. This will allow to use Key in const contexts.
Adding the `constexpr' specifier to the function makes it possible to
rely on the results at compile time. This puts some kind of restrictions
on the function, especially when using C++11 and not a newer standard,
but these restrictions were already fulfilled, so this seems to be safe.
By far the most common deprecation will be the event handler and loop hook
deprecation. Make them less scary, and point out that unless one's a developer,
they likely need not care.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Moving the deprecation messages to a separate header, and adding a few helpers
allow us to write much more detailed deprecation messages, without needlessly
making the code look incredibly messy.
This also updates most of the deprecation messages to be much more helpful, and
provide hints at how to fix the warnings produced by them.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Due to the plugin API redesign, plugins that migrate may want to ensure they are
compiled against a recent enough Kaleidoscope. Others may opt to provide
separate implementations for each version. For this to work, we need to bump the
API version.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Fixed a conditional so that the event handlers of old-style plugins will be
called. Without this, they don't, and old-style plugins that install event
handlers, would not work.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This commit includes the resetMap method which is used to start the heatmap from 0. I also use it as a workaround for my map starting up with an "infinitely hot" key
Any event with the `INJECTED` flag set is now ignored. This is necessary because OneShot
now sends events with valid `row` & `col` values when it calls `handleKeyswitchEvent()`,
and we need to make sure those events don't get enqueued in the case of a qukey whose
primary keycode value is a OSM key, followed by a key that is meant to be modified by that
key. Fixes#40.
Use a timeout calculation method that is not affected by overflow, and also
requires 16 bits less.
This likely fixes#8.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Ticks depend on the speed of the main loop, and as such, are not a reliable way
to time animations. For this reason, use proper timers instead.
The update delay is set to 40ms, which appears to be a slow, relaxing animation,
and should be roughly in the ballpark the tick-based timing was, before speeding
up the main loop considerably.
Fixes#3.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Sometimes one wants a longer timeout, also wants the sticky behaviour on
double-tap, but would like to use a shorter timeout for the sticky behaviour.
The new `double_tap_timeout` property accomplishes just this.
Defaults to using `time_out`, for backwards compatibility.
Fixes#30.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When we activate a OneShot key, use the coordinates of the (last) physical key
that triggered it. This is done by keeping an array of positions for each
possible OneShot key. While this costs us 16 bytes of RAM and a bit of code, the
benefit is that plugins ordered after OneShot will know where OneShot was
triggered from.
Fixes#13.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This warp mode is similar to the navigation provided by some speech
recognition software. A 9-cell grid may provide more precision and
efficiency than the existing 4-cell warp mode. This adds some extra
key definitions to support the additional sectors and enables a user
to switch the grid size:
MouseKeys.setWarpGridSize(MOUSE_WARP_GRID_3X3);
Signed-off-by: Cy Rossignol <cy@rossignols.me>
With the previous algorithm, once every 65 seconds, there would be a significant jump in
the brightness of the "breathing" LEDs as the 16-bit value recorded from `millis()`
overflowed. Instead of dividing by 12, I changed it to a bit shift (4 bits; equivalent to
division by 16), so when the integer overflow occurs, the next value is what it should be.
This is a somewhat unwieldy fix for all the out of bounds (attempted) array addressing at
both ends. When `pos` goes out of bounds in either direction, the test is the same because
it's an unsigned integer. However, after the change of direction, the trailing LED will
still be out of bounds, so we check that every time we call `setCrgbAt()` for `pos2`.
It's rather ugly, but it does ensure that we don't call `setCrgbAt()` with an
out-of-bounds address.
Before this change, we couldn't use the full functionality of the plugin's
warp feature to drag an item (by holding down a mouse button key). The
plugin would reset the warp state during each scan cycle, so we could
only warp the pointer to a cell in the top-level grid. This fix enables
warping repeatedly into sub-cells while holding a mouse button.
This prevents an insignificant error, but it is more correct to handle the integer
overflow instead of ignoring it. I've also changed syncTimer from a 32-bit to 16-bit
integer, which results in a smaller code size, and changed the computation of the timeout
slightly, so the LED update interval is always the same (we add `syncDelay` to the
previous update's start time, not it's end time), rather than varying based on when
LEDControl's `loopHook()` function is called relative to the last timeout.
There already exist 2 rainbow LED effects, this adds a third, using
the LED-Stalker effect.
When you press a key, the LED on that key will cycle through all the
colors of the rainbow, independent of the colors of other keys.
I had failed to check that the queue length was non-zero before checking release delay
timeouts, causing reading past the end of the `key_queue_` array an repeatedly sending
essentially random input to the host.
In the process of fixing that bug, I realized that I was also assuming that layer changes
weren't happening earlier in the queue and checking whether or not a key is a qukey when
it wasn't the head of the queue. Now we only enact a release delay when `flushKey()` is
called, and always call `setQukeyState()` when enqueuing new keys so that we can
distinguish between keys that should be immediately flushed in the primary state, and ones
that should have keypresses delayed.
When releasing a qukey, allow a short timeout in case a subsequent key was released
effectively simultaneously, treating that near-simultaneous release as intended to use the
alternate (i.e. modifier) keycode.
Any keyswitch events without real physical addresses were injected by other plugins and
should not be processed by Qukeys. There was an interaction with OneShot that prevented
the two plugins from working together because OneShot sends events with a (row, col)
address of `UNKNOWN_KEYSWITCH_LOCATION` (i.e. 255, 255). This meant that if a OneShot
modifier was on when a Qukey was pressed, it would fill up the queue with bogus-address
versions of the Qukey, which would then get flushed in the primary state, cancelling the
OneShot and producing an un-modified, repeating primary keycode, causing both plugins to
fail.
Since keyboardio/Kaleidoscope-Hardware-Model01#23 we do not call
`handleKeyswitchEvent` for keys that are idle. Document this in the comments.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When a keyswitch has been off in the previous cycle and is still off now, do not
call `handleKeyswitchEvent` on it. As an extension, when the whole column is
idle, skip the whole thing.
In practice, handling fully idle keys is not useful. There are many plugins
which explicitly look for this case and return early, because it isn't an
interesting event. As such, not calling the event handler in this case makes
sense, as we save not only a few needless checks in plugins, but our performance
improves greatly too.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
In `actOnMatrixScan`, there is no need to use temporary variables, we can just
pass the data directly to `actOnHalfRow`, and doing so makes the code easier to
follow.
In `actOnHalfRow`, we can further optimize things if instead of reading the Nth
bit, we always read the first, and shift the byte at the end.
All of these optimizations were done by @obra, I just wrote the commit message.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When there are no state changes, and no keys pressed on a row, instead of
iterating through a byte bit-by-bit, just fire idle events without checking the
bits. In all other cases, do the bit-walking like we did before.
The reason this is useful is because bit-walking is costly, and slow. If we can
avoid that, we win quite a lot of performance. Since rows being idle is the most
common case on a keyboard, this is a huge net win. Even in the worst case, where
no rows are idle, this is just one byte comparison and a branch slower than our
previous implementation.
As part of this optimization, `actOnHalfRow` was lifted out into its own
function, to reduce code duplication.
Many thanks to @gedankenexperimenter for the original idea!
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
I made a bunch of changes to improve SpaceCadet for the better.
1. I resolved issue #9 ( https://github.com/keyboardio/Kaleidoscope-SpaceCadet/issues/9 ) to support mappings on Alt keys under Windows. This change in behavior means that we don't send the initial key value (the key with a mapping) until we hit the timeout (if held) or if we hit another key in combination in the mean time (to keep modifiers working as expected in combination with other keys). This means that when you place a mapping on Alt, we don't send Alt if you are just tapping -- we only send the other key value. This prevents Alt capturing the menu bar in Windows apps, and probably means we can better support SpaceCadet on non-modifier keys.
2. I added support for enabling, disabling, and determining if SpaceCadet is currently enabled. This allows other plugins and macros to better interact with SpaceCadet, and allows us to temporarily disable the behavior if that's desired.
3. I added two new virtual Key entries for placing on the user's keymap. One key disables SpaceCadet, and the other key enables SpaceCadet.
I also updated the README.md with all of the relevant changes.
It seems that if we inject the release of the mapped modifier key before injecting the press of the alternate key, we avoid the need to call `hid::sendKeyboardReport`, which in turn fixes#7. Which is nice.
Closes#7
It seems that if we inject the release of the mapped modifier key before injecting the press of the alternate key, we avoid the need to call `hid::sendKeyboardReport`, which in turn fixes#7. Which is nice.
Closes#7
Allow user to specify custom boot greeting key by Key_* or by specific row and column. Add ability to define custom duration of boot greet breathing effect, and add ability to change color hue of breathing effect. Finally, rework logic that happens when plugin is loaded to allow all user custom settings to be properly read and applied as expected.
add hue to the header
Updated readme to support new features
astyle + change to allow custom settings
In `hexToKeysWithNumpad`, have a default case, a pointless one, because we never
take that branch, but it silences a warning.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This avoids the OS being stuck with Numlock on, which leaves the LED on
if other keyboard are attached, and breaks FVWM.
See keyboardio/Model01-Firmware#42
This restricts the data type of the enum to uint16_t, so if anyone ever adds enough values
to it to overflow the 16 bits that are available in the Key structure, even if they do it
without an assignment (e.g. `TOO_BIG_ENUM = 0x10000`), it will result in a compilation
error instead of runtime errors.
These macros were copied and pasted, I'm guessing from the USB HID Usage Tables document,
where this keycode is identified with a parenthetical, unlike all of the others around it:
`AC Download (Save Target As)`. When automatically converted into a preprocessor macro, it
gets a trailing underscore and an argument, which is not what we want.
This change won't actually fix anything that's currently broken, but it might matter
someday.
Reset the bad key bitfields each time a test is started, so that each test starts from a clean slate. Without this, it was confusing to restart the test and get an ever-increasing number of keys to appear bad immediately.
Store any macros key events and play them after the event handler pass has finished, so we
don't have a problem when holding other keys that are handled after the macro key in a
pass. This fixes the problem where held modifiers wouldn't be applied to macros, and also
fast repeating of printing characters.
This change does introduce a limit (default: 8) on the number of concurrent macros that
can be played.
We are moving towards including the Adaptor from the Hardware library, so we
need not pull them in from user sketches (or from core).
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of pulling it in from the user sketch, do so from the hardware plugin.
The hardware and the adaptor are in close relationship anyway, and with
tweakable knobs, we do not need to use a different adaptor library in advanced
cases, either.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
With this change, Qukeys reads DualUse key defs from the keymap, and treats them as
Qukeys, within the limitations of normal DualUse keys. Primary keycodes can only be
unmodified, basic keys, and alternate keycodes can only be modifiers or layer-switch
keys.
Layer changes didn't take effect immediately, and a ShiftToLayer(n) alternate keycode was
never released properly, so it was effectively a LockLayer(n) key. This patch fixes both
problems.
Fixes#28
Instead of implementing the HID adaptors within Kaleidoscope, provide an API
only (by marking the symbols `extern`). For the sake of backwards compatibility,
pull in `Kaleidoscope-HIDAdaptor-KeyboardioHID`, a new shim library implementing
the status quo.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Instead of using `Keyboard.begin` directly, use
`kaleidoscope::hid::initializeKeyboard`. While there, also initialize
`ConsumerControl` and `SystemControl` the same way.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Use `static_assert` instead of `#error` to report an API mismatch, resulting in
a much more informative error message.
Thanks to @cdisselkoen for the request, and @noseglasses for the `static_assert`
idea!
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When the value returned by `millis()` overflows (after ~two months of runtime), a straight
comparison to the end time would fail. This wasn't a really big deal, but it is possible
to do it correctly, and in the process, reduce the size of the time values stored from 32
bits to 16 bits (~one minute), since the largest conceivable useful timeout is measured in
seconds (at most).
We need to prevent infinite loops, and also stop handling keyswitch events when flushing
the queue, but if we do this by setting the `INJECTED` bit in `keyswitch_state` when
calling `handleKeyswitchEvent()`, then other plugins will ignore those events, which is
not what we want; we need them to process those events as if they were real
keypresses. The solution is to use a static boolean to let us know if the queue is being
flushed.
As we guarantee backwards compatibility throughout a major version, it helps if
we have that version available, so plugins / sketches can check if they are
compatible, and issue a helpful error if they are not. As further convenience,
defining `KALEIDOSCOPE_REQUIRED_API_VERSION` before including `Kaleidoscope.h`
will result in a check being done by Kaleidoscope, and an error printed if it
does not match the API shipped.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
As this is a generic plugin, for keyboards that do not have LEDs, don't tie it
to LEDControl, and don't provide a `toggleLEDs` method. Instead, show an example
how to achieve the same thing from the sketch.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
At least on Linux, for a device to be considered capable of waking the host up,
it must be a boot keyboard. As we do not (yet) support a boot keyboard, we fake
one. An USB node that does nothing else than report itself as a boot keyboard,
and does the minimum amount of work to get recognised as such.
Because of this, Linux - and hopefully the other OSes too - will consider the
whole device capable of waking up the host.
This addresses keyboardio/Kaleidoscope#237, if all goes well.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Add LEDControl.paused, which we use to pause LED mode updates if true (defaults
to false). This is useful when we want to stop LED modes from updating without
switching to another (like when the host goes to sleep, and we want to turn LEDs
off).
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This doesn't change behaviour at all; it's just a different way to do the computation,
which I think is much clearer. I also added an explanatory comment.
* It's now all bitwise operations, without arithemetic thrown in.
* It uses the same exact formula for finding bits on both sides of the keyboard.
* It saves 14 bytes in program memory.
When clearing a sticky, also cancel the OneShot state, and clear the pressed
bits too.
Thanks to @glasser for experimenting and coming up with the full fix.
Fixes#17.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
After restoring the current report, if we don't add the keycode for the current key back
in (by calling `handleKeyswitchEvent()` with the "held" state flags if the flushed key is
still held), we'll accidentally leave that keycode out of the next report.
fixes#13
The boolean wasOn was unnecessary, and there was no need to call
bitSet() (or bitClear(), in the case of Layer.off()) if the test
passed. Mostly, I just added a few explanatory comments.
(Aslo reversed the sense of the on/off test in Layer.on() and .off())
@algernon likes it better this way, and I agree.
KeyboardioHID isn't going to get a function to copy the previous
report to the current one, but it is now making the current and
previous HID reports public. This is a much better solution all
around, as it allows us to save and restore the current report in the
midst of a scan, while still sending a modified version of the old
report.
`updateActiveLayers()` makes it impossible to turn off the default
layer, so there's no point searching past it for the highest layer,
and `defaultLayer` can be set to numbers higher than zero.
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).