This is an extensive rewrite, but I think it simplifies the logic and makes the
plugin's code easier to follow.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This is a major rewrite of TapDance, taking advantage of the active keys cache
and the `KeyAddrEventQueue` class originally written for Qukeys.
fixes#806fixes#922fixes#908fixes#985
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
When Qukeys stops event processing from its `onKeyswitchEvent()` handler, it's
because the event should be treated as non-existent (in most cases, it's merely
delayed). This keeps the active keys cache from getting updated, as well as
completely stopping event processing.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This converts `Layer.live_composite_keymap_[]` from a simple cache to a
representation of the keyboard's current state, and transfers that cache to
`Runtime.active_keys_[]`. With the exception of plugin activity, an idle key
will have the value `Key_Transparent`, and a pressed key will have the value of
whatever key it's currently mapped to in the keymap. A value of `Key_NoKey` will
mask that key until it is released.
If a plugin returns `ABORT` from its `onKeyswitchEvent()` handler, that means
that the keymap cache should not be updated. It's especially important to have
this occur after plugins like OneShot and Qukeys, where the key can stay
active (or become active) after the physical keyswitch has been released.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This will allow plugin handlers to send one of three different signals to the
calling hook functions, with three different interpretations:
`OK`: Continue calling the next handler.
`EVENT_CONSUMED`: Don't proceed to the next handler, but signal to the hook
function's caller that an event was handled successfully.
`ABORT`: Stop processing, and signal to the hook function's caller that the
event should be ignored.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Instead of only aborting hook functions if a handler returns `EVENT_CONSUMED`,
only continue abortable hooks if a handler returns `OK`. For existing core
plugins, this shouldn't make any difference because none of them use the `ERROR`
return value.
Also rename `shouldAbortOnConsumedEvent` to better match the new conditional.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This testcase checks to make sure that the active keys cache gets cleared by
`handleKeyswitchEvent()` when a plugin returns `EVENT_CONSUMED`.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This adds a testcase for rollover from a TapDance key to the key that interrupts
the sequence, and a testcase for a TapDance key that times out while held.
I also adjusted the timing of the existing testcases to match the new version of
TapDance.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
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>