Instead of safeguarding against an unrecoverable blank layer state by
guaranteeing that layer 0 is always active (and therefore always at the bottom
of the layer stack), we safeguard by a move to layer 0 if the only active layer
is deactivated.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
The `INSTANTIATE_WEAK_HOOK_FUNCTION` claimed that it's there for v1 API
compatibility alone - it is not. It allows us to have sketches that use no
plugins too, without them having to use `KALEIDOSCOPE_INIT_PLUGINS()` with a
dummy plugin.
We'd need a dummy plugin because `KALEIDOSCOPE_INIT_PLUGINS()` does not support
being invoked with an empty plugin list, due to technical reasons. From an
end-user point of view, not using the macro is much preferable to using it with
a dummy plugin. We can't automatically inject a dummy plugin either, again, due
to technical reasons.
Fixes#1005.
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
In the process of moving towards a single repository for everything
Kaleidoscope, integrate KeyboardioScanner as a driver. This is a direct copy of
KeyboardioScanner as of 2090cd426cae25b07c0ce3a6b7365b95c21dd87b, renamed and
namespaced to fit into Kaleidoscope.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We're going to merge KeyboardioScanner into Kaleidoscope as a driver, but we
can't name that model01::Hand, because then we have a filename conflict due to
our use of static archiving during linking. To avoid that, both will use a
similar, but unique naming pattern, and raise::Hand becomes raise::RaiseSide
instead.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This change adds test methods to the `Key` class for the builtin variants for
the different HID types (Keyboard, Consumer Control, and System Control), and
layer change keys:
- `key.isKeyboardKey()`
- `key.isConsumerControlKey()`
- `key.isSystemControlKey()`
- `key.isLayerKey()`
In addition, a few useful sub-variants are called out. These will probably be
more commonly used by plugins:
- `key.isKeyboardModifier()` returns `true` if `key` is a HID Keyboard key, and
its keycode is a modifier. Note that this includes modifiers with modifier
flags, so it will also return `true` for `Key_Meh`, for example.
- `key.isKeyboardShift()` returns true if `key` both above tests pass, and
either the base keycode is a modifier, or the shift mod flag is set.
Shift is a special case, even among modifiers, because it is more often of
concern by plugins (e.g. TopsyTurvy, ShapeShifter) than others.
- `key.isLayerShift()` returns `true` if `key` is a layer shift key.
Layer shifts are tested more often than other types of layer changing keys
because they, like HID Keyboard modifiers, are used chorded, rather than simply
having an effect that completes when they toggle on.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This is a convenience only, but it's much more straightforward than the
expression `key_addr = KeyAddr(KeyAddr::invalide_state)` or the overly enigmatic
`key_addr = KeyAddr()`.
`KeyAddr::none()` is meant to be useful for initialization of variables:
`KeyAddr my_addr = KeyAddr::none()`
`KeyAddr::clear()` is meant to be the counterpart of the `isValid()` test, to
set an existing variable to an invalid address:
`my_addr.clear()` vs `if (my_addr.isValid()) ...`
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
The virtual hardware device, unlike others, was calling `handleKeyswitchEvent()`
for every keyswitch, every cycle. It should suppress calls corresponding to idle
keyswitches, just like the other devices.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
The code for guarding against integer overflow on the prior interval timestamp
was in the wrong place, and wouldn't get executed on cycles when the keyboard
was idle, leading to a very slim chance of getting the wrong qukey value if all
keys were idle long enough (65 seconds).
Also fixed the same problem in the first quarter-second after the keyboard power
on. Not likely to ever be observed, but costs nothing extra to fix.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Macros was still using its own bit in the `Key.flags_` byte to define Macros
keys, unlike all the other plugins that define their own special `Key`
values. This standardizes Macros to make it more like other plugins.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Some users have pointed out that certain keys (in particular, `space` &
`backspace`) are inconvenient to require the minimum prior interval to make a
qukey resolve to a modifier (especially `shift`). We could blacklist those keys,
but it's hard to predict what they all might be. The problem is mainly one for
very fast typists, and therefore I expect it to show up when following the
"normal" printable keys, not often other keys.
This could also be made into a configurable list, but I'd prefer not to do so
unless there's serious demand for it, as Qukeys already has too many settings.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Unintended modifiers are becoming an increasingly big problem among users of
Qukeys. This change adds yet another configuration option to prevent this from
happening while users are typing fast. It introduces a new requirement to make a
qukey eligible to become a qukey; a minimum amount of time that must pass
between the keypress event for a non-modifier key and the subsequent keypress
event of the qukey.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
When starting up, we correctly set the active layer counter to one, and the
active layer stack will therefore correctly contain layer 0 as an active layer.
However, we weren't setting the `layer_state_` bitmap up properly, and as such,
`Layer.isActive(0)` was returning false, despite the layer being active as far
as lookups were concerned.
To fix this, we explicitly flip the 0th bit on in the newly introduced
`Layer.setup()` method, where the initial keymap cache update was moved to, too.
Fixes#951.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
When rollover occurs from a non-modifier key to a qukey, if we delay the release
event of that key until after the qukey's state is resolved, and if the hold
timeout is set to a fairly large value (on the order of 500ms), unintended
repeats would occur for a key that was actually only tapped. To prevent this, if
there's only one event in the queue (the press of the qukey), and we see a
release of a non-modifier key that's not the qukey, it's okay to allow that
release event to skip the queue and simply proceed as if it had been released
before the qukey was pressed.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Previously, we used index-ordering for layers, meaning, we looked keys up based
on the index of active layers. This turned out to be confusing, and in many
cases, limiting, since we couldn't easily shift to a lower layer from a higher
one. As such, index-ordering required careful planning of one's layers, and a
deeper understanding of the system.
This patch switches us to activation-ordering: the layer subsystem now keeps
track of the order in which layers are activated, and uses that order to look
keys up, instead of the index of layers. This makes it easier to understand how
the system works, and allows us to shift to lower layers too.
It does require a bit more resources, since we can't just store a bitmap of
active layers, but need 32 bytes to store the order. We still keep the bitmap,
to make `Layer.isActive()` fast: looking up a bit in the bitmap is more
efficient than walking the active layer array, and this function is often used
in cases where speed matters.
As a side effect of the switch, a number of methods were deprecated, and similar
ones with more appropriate names were introduced. See the updated `UPGRADING.md`
document for more details.
Plugins that used the deprecated methods were updated to use the new ones.
Fixes#857.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
This change makes Qukeys require a certain minimum amount of time for a
key to be held before it is eligible to get its alternate (i.e. modifier)
value. This should help faster typists avoid unintended modifiers in the
output.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Two new functions have been introduced in namespace kaleidoscope.
One to conveniently add keyflags to an existing Key variable and
another one that can be overloaded to convert other types to type Key.
The keymap definition macros and the modifier function macro (LCTRL,
LALT, ...) are now using the to-Key conversion functions. This
allows users to use alternative ways to define keymaps by
defining types of their own that automatically convert to type Key.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
This refactors the KEYMAPS(...) macro and factors out
a header and footer portion that are now define as individual
macros START_KEYMAPS and END_KEYMAPS. The original
KEYMAPS(...) macro now relies on the newly defined macros.
The newly introduced macros enable keymap definitions that
allow for macro definitions between the start and end part
which is not possible inside the KEYMAPS(...) macro invocation.
Signed-off-by: Florian Fleissner <florian.fleissner@inpartik.de>
There were a few minor problems in the way Consumer `Key` objects were
constructed (using `CONSUMER_KEY()`). First, no masking of the high
bits was being done, so it was possible to create a "Consumer" key
with the `RESERVED` bit set (e.g. `Key_Transparent`), or the
`SWITCH_TO_KEYMAP` bit (in fact, any `Key` value with both the
`SYNTHETIC` and `IS_CONSUMER` bits set was possible).
This change fixes these potential problems by setting the six bits
taht could conflict to zero. When we need to have special behavior
based on those bits, this can change.
There were a few minor problems in the way Consumer `Key` objects were
constructed (using `CONSUMER_KEY()`). First, no masking of the high
bits was being done, so it was possible to create a "Consumer" key
with the `RESERVED` bit set (e.g. `Key_Transparent`), or the
`SWITCH_TO_KEYMAP` bit (in fact, any `Key` value with both the
`SYNTHETIC` and `IS_CONSUMER` bits set was possible).
Second, the high six bits of the raw `Key` value should always be
`010010` (`SYNTHETIC | IS_CONSUMER`), as Consumer keys don't have any
flags. The macro should really only take one argument: a 16-bit
integer keycode value. The `HID_TYPE_*` constants really shouldn't be
used at all in defining the keys in key_defs_consumer.h, because
setting those bits could potentially cause a key to be misidentified
by some plugin.
This change fixes these potential problems by ignoring the `flags`
parameter, masking the high six bits of the `code` supplied, and
setting those high six bits to the correct value.
For some of our single-parameter constructors, we _want_ to have implicit
conversions, because that makes the code more readable. Mark these up for
cpplint to ignore.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Within some of the internal headers, we do not have a complete declaration of
some namespaces, and that's ok. Most of these cases are within macros anyway.
Since there's no sane way to make cpplint happy otherwise, lets ignore these
warnings instead.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
In both cases, the warning is about a function argument that we do not use.
There's no benefit of doing a c++-style cast there, especially since they're
function arguments. In fact, doing anything else would just make the code less
readable. As such, we opt to ignore these warnings instead.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Since there's only two places where we use the `kaleidoscope::ranges` namespace,
and it's easy to use `ranges::` there, instead of the bare enum, lets do that,
and make cpplint happier.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
All of these places use a template argument (usually indirectly) for array
sizes, so they are _not_ variable sized. It just so happens that cpplint is
unable to figure that out on its own. For this reason, mark them explicitly, and
let cpplint ignore these false positives.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
While `using namespace` certainly has its downsides, in these cases, the scope
is local to a single file, and makes the code _much_ more readable, offsetting
any downsides the directive otherwise has. As such, lets tell cpplint to ignore
these.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We do not need `getShortName()` anymore: setting the shortname is now done via
device properties instead. Doing it with `getShortName` only results in
duplicated symbols.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Previously, rolling over from one System Control key to another would
cause the second one to be released as soon as the first one was
released, because the empty release report would be sent
unconditionally on release of any System Control key.
This change stores the value of the last System Control key
pressed. When a System Control key is released, it first checks to see
that the released key's keycode matches the last one pressed before
sending the empty report.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Since the PR was made for the ButterStick and FaunchPad, ATMega32U4Keyboard has
had a breaking API update. Follow up on that now.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Key masking was a bandaid, and we have better ways to achieve the same thing
now. All current users have been switched over to different methods now, so lets
deprecate the masking.
We only put the `DEPRECATED` label on the `maskKey` method, because the rest are
used internally too, and we do not want to emit warnings for those.
Fixes#884.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We want to remove the use of key masking, so instead of masking the key when
escaping a OneShot, map it to `NoKey` instead, and continue doing so until
released. Which is effectively what masking did, but localized and simpler.
Doing this will make our cache have `NoKey` for the key until release, and we'll
avoid sending unintended Escape keycodes, without having to use the global
masking functions.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
We introduced the masking to avoid sending extra keys when the mapped key
changes prior to release - but since the introduction of the caching mechanism,
we no longer need to do this.
However, for the caching to work the way we want it to, we need to map the key
to `NoKey` once, upon interrupting.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
squash! TapDance: Do not mask interrupting keys anymore
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
To make their purpose clearer, rearrange our state: we now have the row-based
array on the top level, instead of every member being an array on its own. The
name of the state variable was changed to `matrix_state_`, to reflect its
purpose. This also allowed us to have its members be named `current`,
`previous`, `debouncer` and `masks`.
All devices using these APIs, and the documentation were updated accordingly.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>