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>
1. Better matches other _PATH env variables
2. Since it's something that might reasonably get set in the
environment, prefix it with KALEIDOSCOPE
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Since LED modes only send updates to the hardware at `syncDelay` intervals, calling
`update()` on the active mode every cycle doesn't make animations any smoother.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
This decreases the rate at which LEDs get updated from ~60Hz to ~30Hz, which should be
fast enough that human eyes won't be able to tell the difference.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
The LED-Stalker plugin was looping through its table of `step` values (one for each key)
on every call to `update()`, and calling `compute()` on every value there, but those table
entries were only updated once every 50ms (by default), resulting in a lot of repeated
computation. This resulted in the mean idle cycle time increasing from 565µs to 1317µs on
the Model01 with an (almost) unmodified standard sketch.
This change moves the check for the timeout before the loop through the `step` values, and
aborts processing there if not enough time has elapsed. The resulting mean idle cycle time
becomes 577µs -- an almost negligible increase. It also reduces the PROGMEM footprint by
44 bytes.
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>