This is a short-term solution for the problem of qukeys rollover from
mod-flagged keys. When flushing its queue, Qukeys stashes a copy of the
current keyboard HID report, and bases the new (usually mid-cycle) report on
the previous one, because it's complete, unlike the partial current report. This
prevents bugs where it would cause undesired repeats of keys scanned later in
the cycle, but results in a bypassing of the system in the HIDAdaptor that masks
modifier flags when rolling over to a key without those flags.
By first storing a copy of the previous key report's modifiers byte and then
restoring it after the report for a released qukey is sent, we remove any
modifier flags it added to that report, so the next key in the queue (if any)
won't base it's report on those modifiers (which would normally be masked by the
HIDAdaptor).
This is a temporary fix. The real fix will probably involve changes to both
KeyboardioHID and the HIDAdaptor, and will allow Qukeys to stop accessing the
HID reports, which really ought to be private member variables of the Keyboard
class.
Fixes#619.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Recently a proposed change to the firmware required a change to one of
the event handlers'/hooks' signatures.
Up to now, we only supported a single overload/implementation of a
event handler of a specific type. This means that changing handler signatures
was only possible by adding a handler method with a similar name and
a different signature like
EventHandlerResult
onKeyswitchEvent(Key &mappedKey, byte row, byte col, uint8_t keyState);
and
EventHandlerResult
onKeyswitchEvent2(Key &mappedKey, KeyAddr key_addr, uint8_t keyState);
As this was regarded as unacceptable confusion of the users of our
programming interface, this commit introduces some changes to the
event handler management.
Important changes:
* handlers can now be overloaded,
* handler signatures can be versioned,
* individual versions can be declared as deprecated,
* we now abort the compile if a handler reimplementation with a bad signature
is found,
* or if two or more handlers with correct signatures are detected that
are furtheron considered as ambiguous.
Impact on resources:
The proposed changes only affect the way things are handled at compile time.
No changes in terms of PROGMEM or RAM are to be expected.
Signed-off-by: Florian Fleissner <fleissner@inpartik.de>
Previously, if a Topsy key was pressed, then a non-Topsy key was
pressed, then the Topsy key was released, we'd return the event consumed
before toggling off the active state, leaving Shift keys consumed until
a Topsy key got pressed again.
Toggle the active state before the early return for Topsy key events.
Signed-off-by: Lisa Ugray <lisa.ugray@gmail.com>
Introduce an MCU driver, with a few convenience methods to disable JTAG or clock
division. Both of these were re-implemented by various hardware plugins on their
own, this collapses them into a common implementation.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
If we found no modifiers on the current layer, force a re-scan. This way we'll
scan the keymap without having to change layers first. We can't do the same
thing at `onSetup()` time, because that's too early, so we do a check in
`beforeReportingState()`.
Fixes#608.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
OneShot keys were failing to activate on the first press because of how the timeout was
implemented. Most of the time, at the end of a cycle, `should_cancel_` was being set to
`true` because the current time was being compared to the last time a OneShot key was
activated, regardless of whether or not a OneShot key was active. As a result, OneShot
keys that were pressed for the first time in a while would fail to register as OneShots.
This change prevents checking the timeout unless there is an active OneShot key.
Fixes#603.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Some systems (I've confirmed this on an iMac and a MacBook Escape) have a long delay after
the host begins to "sleep" and the keyboard responding to the HostPowerManagement
plugin (i.e. turning off LEDs).
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This should stop layers from getting stuck on when a release delay is in use. Instead of
recording the keycode of the key that will be released, I now have Qukeys just use the
key's coordinates, and have it do a lookup in `Layer.live_composite_keymap_` the usual
way.
I also stopped overloading the `key_queue[x].start_time` and instead record the release
delay time in a separate variable. This greatly simplifies the timeout math, and saves
another good-sized chunk of PROGMEM, as well as avoiding timeout-conflict bugs.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Now, when we flush a key from the queue, we just insert whatever its final `Key` value
should be into `Layer.live_composite_keymap_`, obviating the need to independently track
whether a flushed qukey is in its primary or alternate state. We can also get rid of all
the code for correcting `mapped_key`, because once a key has been flushed, it won't show
up as a qukey (or DualUse key) any longer.
This substantially reduces PROGMEM usage (~300 bytes) and reduces RAM usage by 8
bytes (for the Model01 hardware).
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
With qukey defined with an alternate `Key` value of `ShiftToLayer(N)`, we need a way to
send the toggle-off event in order to get the layer to deactivate. Since the physical key
was already released, we need to keep track of the delayed-release qukey, and send the
appropriate release event after the rest of the queue has been flushed.
This change records the delayed key at the time of the delay, and sends the release event
after the ensuing key has been flushed from the queue.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
With the changes to the updating of `Layer.live_composite_keymap_`, the code that changes
the `mapped_key` values for keys that have been flushed from the queue is unnecessary.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
SpaceCadet was sending a keyswitch event with the row & column coordinates of the wrong
key. The coordinates were coming from the keypress, but the injected event was for a
previously-pressed (different) key that's still held. With the mutable
`live_composite_keymap_[]` change, this meant that pressing (and holding) `shift` then
another key would result in only a single character, rather than a repeating
character. Regardless of the minor bug, using the row & col for the event was still
logically incorrect here.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
An `EPHEMERAL` keyswitch event is one that gets ignored by updates to
`live_composite_keymap_[]`, and thus doesn't change the keymap at all. This is useful for
a plugin that needs to retain its own key type in the keymap in order to do something
particular when it toggles off, but needs to inject an event with a different `Key` value,
with real key coordinates.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
If we're sending injected events with `UNKNOWN_KEYSWITCH_LOCATION` instead of
the (row,col) of the OneShot key, there's no need for the function that does this
conversion.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
With the changes to live_composite_keymap_, OneShot keys were no longer working. OneShot
modifiers would get stuck on, because the entry for the `OSM` key would get changed to the
modifier key value, and when the key was released, it wouldn't be processed by the OneShot
plugin, which would continue to re-apply the modifier indefinitely. At the same time,
OneShot layers wouldn't work at all, because the key would get changed to the layer shift
key, which would then turn the layer off when it was released.
This change fixes the problem by injecting keyswitch events from OneShot without physical
key coordinates, so nothing in `live_composite_keymap_` can get updated from it. OneShot
wants the `Key` entries there to remain as OneShot keys, not as whatever they're changed
to, so this is the most appropriate way I can think of to fix the issue.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
If `handleKeyswitchEvent()` is called with a `mappedKey` other than `Key_NoKey`, update
`live_composite_keymap_` with the specified `mappedKey` instead of doing a keymap lookup
on active layers. This allows a plugin to call `handleKeyswitchEvent()` and specify what
the `Key` value should be, and not have to separately track what value to change it to
every cycle.
This is especially important when there's a layer change. In particular, this is the
simplest way to allow Qukeys to use `ShiftToLayer()` keys that work properly.
Fixes#501.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This adds a new version of `updateLiveCompositeKeymap()` which takes three parameters:
row, column, and a `Key` value. Instead of looking up the value to update in the key map,
it just updates `live_composite_keymap_` with the specified `Key` value.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
Instead of trying to be clever by checking if a mask applies to a layer index,
just check if the layer is higher or equal (or lower, as appropriate) than our
`IGNORE_HARDCODED_LAYER` value.
This addresses keyboardio/Chrysalis#341.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>