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>
Based on #306, with slightly improved text. Thanks to Ross Donaldson
(@Gastove) for the original pull request!
Closes#306.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
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.
We no longer have a `KaleidoscopePlugins` namespace, and have to use
`kaleidoscope` instead - lets do that.
Noticed by Jordihs on the Keyboardio forums, thank you!
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
Since we switched to using a separate node for the absolute mouse, it works with
all three major operating systems. For that reason, the note about OS
compatibility is incorrect, and with this patch, we drop it.
Reported by @noseglasses, thanks!
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
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