You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
12 KiB
250 lines
12 KiB
4 years ago
|
# Kaleidoscope's Plugin Event Handlers
|
||
|
|
||
|
Kaleidoscope provides a set of hook functions that plugins can define in order
|
||
|
to do their work. If one or more of the functions listed here are defined as
|
||
|
methods in a plugin class, that plugin can act on the input events that drive
|
||
|
Kaleidoscope.
|
||
|
|
||
|
In response to input events (plus a few other places), Kaleidoscope calls the
|
||
|
event handlers for each plugin that defines them, in sequence.
|
||
|
|
||
|
## Return values
|
||
|
|
||
|
Every Kaleidoscope event handler function returns a value of type
|
||
|
`EventHandlerResult`, an enum with several variants. In some handlers,
|
||
|
Kaleidoscope ignores the return value, but for others, the result is used as a
|
||
|
signal to control Kaleidoscope's behavior. In particular, some event handler
|
||
|
hooks are "abortable". For those hooks, the return value of the plugin handlers
|
||
|
are used to control what Kaleidoscope does after each plugin's event handler
|
||
|
returns.
|
||
|
|
||
|
- `EventHandlerResult::OK` is used to signal that Kaleidoscope should continue
|
||
|
on to the next handler in the sequence.
|
||
|
|
||
|
- `EventHandlerResult::ABORT` is used to signal that Kaleidoscope should not
|
||
|
continue to call the other plugin handlers in the sequence, and stop
|
||
|
processing the event entirely. This is used by some plugins to cancel events
|
||
|
and/or delay them so that they occur at a later time, possibly with different
|
||
|
values.
|
||
|
|
||
|
- `EventHandlerResult::EVENT_CONSUMED` is used to signal that the plugin has
|
||
|
successfully handled the event, and that there is nothing further to be done,
|
||
|
so there is no point in continuing to call further plugin event handlers for
|
||
|
the event.
|
||
|
|
||
|
## Non-event "event" handlers
|
||
|
|
||
|
There are three special "event" handlers that are not called in response to
|
||
|
input events, but are instead called at fixed points during Kaleidoscope's run
|
||
|
time.
|
||
|
|
||
|
### `onSetup()`
|
||
|
|
||
|
This handler is called when Kaleidoscope first starts. If a plugin needs to do
|
||
|
some work after its constructor is called, but before Kaleidoscope enters its
|
||
|
main loop and starts scanning for keyswitch events, it can do it in this
|
||
|
function.
|
||
|
|
||
|
### `beforeEachCycle()`
|
||
|
|
||
|
This handler gets called at the beginning of every keyswitch scan cycle, before
|
||
|
the scan. It can be used by plugins to do things that need to be done
|
||
|
repeatedly, regardless of any input from the user. Typically, this involves
|
||
|
things like checking for timeouts.
|
||
|
|
||
|
### `afterEachCycle()`
|
||
|
|
||
|
This is just like `beforeEachCycle()`, but gets called after the keyswitches
|
||
|
have been scanned (and any input events handled).
|
||
|
|
||
|
## Keyswitch input event handlers
|
||
|
|
||
|
This group of event handlers is triggered when keys on the keyboard are pressed
|
||
|
and released. With one exception, they use a `KeyEvent` object as their one
|
||
|
parameter. The `KeyEvent` class encapsulates the essential data about a key
|
||
|
press (or release):
|
||
|
|
||
|
- `event.addr` contains the `KeyAddr` of the key that toggled on or off.
|
||
|
|
||
|
- `event.state` contains information about the current and former state of the
|
||
|
key in the form of a `uint8_t` bitfield.
|
||
|
|
||
|
- `event.key` contains the `Key` value of the event. For key presses, this is
|
||
|
generally determined by means of a keymap lookup. For releases, the value is
|
||
|
taken from the `live_keys` structure. Because the `event` is passed by
|
||
|
reference, changing this value in a plugin handler will affect which value
|
||
|
ends up in the `live_keys` array, and thus, the output of the keyboard.
|
||
|
|
||
|
- `event.id` contains a `KeyEventId` value: an integer, usually monotonically
|
||
|
increasing. This is useful as a tool to allow plugins to avoid re-processing
|
||
|
the same event, thus avoiding infinite loops without resorting to an
|
||
|
`INJECTED` key state flag which would cause other plugins to ignore events
|
||
|
that they might otherwise be interested in.
|
||
|
|
||
|
### `onKeyswitchEvent(KeyEvent &event)`
|
||
|
|
||
|
This handler is called in response to changes detected in the state of
|
||
|
keyswitches, via the `Runtime.handleKeyswitchEvent()` function. After the
|
||
|
keyswitches are scanned in each cycle, Kaleidoscope goes through them all and
|
||
|
compares the state of each one to its previous state. For any of them that have
|
||
|
either toggled on or off, plugins that define this function get called (until
|
||
|
one of them returns either `ABORT` or `EVENT_CONSUMED`).
|
||
|
|
||
|
This handler should be defined by any plugin that is concerned only with
|
||
|
physical keyswitch events, where the user has pressed or released a physical
|
||
|
key. For example, plugins that determine key values based on the timing of these
|
||
|
physical events should define this handler (for example, Qukeys and
|
||
|
TapDance). Plugins that don't explicitly need to use this handler should define
|
||
|
`onKeyEvent()` instead.
|
||
|
|
||
|
Plugins that use this handler should abide by certain rules in order to interact
|
||
|
with each other to avoid infinite loops. A plugin might return `ABORT` to delay
|
||
|
an event (until some other event or a timeout occurs), then later re-start
|
||
|
processing of the same event by calling `Runtime.handleKeyswitchEvent()`. When
|
||
|
it does this, it must take care to use the same `KeyEventId` value as that
|
||
|
event's `id` parameter, and it should also take care to preserve the order of
|
||
|
any such events. This way, plugins implementing `onKeyswitchEvent()` are able
|
||
|
to keep track of event id numbers that they have already processed fully, and
|
||
|
ignore those events when plugins later in the sequence re-start them.
|
||
|
|
||
|
In more specific detail, plugins that implement `onKeyswitchEvent()` must
|
||
|
guarantee that the `event.id` values they emit when returning `OK` are
|
||
|
monotonically increasing, and should only include `id` values that the plugin
|
||
|
has already received as input. Additionally, such plugins must ignore any event
|
||
|
with an `id` value that it has recently received and finished processing. The
|
||
|
class `KeyEventTracker` can help simplify following these rules.
|
||
|
|
||
|
### `onKeyEvent(KeyEvent &event)`
|
||
|
|
||
|
After a physical keyswitch event is processed by all of the plugins with
|
||
|
`onKeyswitchEvent()` handlers (and they all return `OK`), Kaleidoscope passes
|
||
|
that event on to the `Runtime.handleKeyEvent()` function, which calls plugins'
|
||
|
`onKeyEvent()` handlers. This is also the starting point for events which do not
|
||
|
correspond to physical key events, and can have an invalid `event.addr` value.
|
||
|
|
||
|
Plugins that need to respond to keyboard input, but which do not need to be
|
||
|
closely tied to physical key events (and only those events) should use
|
||
|
`onKeyEvent()` to do their work.
|
||
|
|
||
|
After all `onKeyEvent()` handlers have returned `OK` for an event, the
|
||
|
`live_keys` state array gets updated. For a key press event, the final
|
||
|
`event.key` value gets inserted into `live_keys[event.addr]`. From that point
|
||
|
on, the keyboard will behave as though a key with that value is being held until
|
||
|
that entry in `live_keys` is cleared (most likely as a result of a key release
|
||
|
event's `onKeyEvent()` handlers returning `OK`). Thus, if an `onKeyEvent()`
|
||
|
handler returns `ABORT` for a key release event, the keyboard will behave as
|
||
|
though that key is still held after it has been released. This is what enables
|
||
|
plugins like OneShot to function, but it also means that plugin authors need to
|
||
|
take care about returning `ABORT` (but not `EVENT_CONSUMED`) from an
|
||
|
`onKeyEvent()` handler, because it could result in "stuck" keys.
|
||
|
|
||
|
`onKeyEvent()` handlers should not store events and release them later (by
|
||
|
calling `Runtime.handleKeyEvent()`), and must never call
|
||
|
`Runtime.handleKeyswitchEvent()`.
|
||
|
|
||
|
### `onAddToReport(Key key)`
|
||
|
|
||
|
After the `onKeyEvent()` handlers have all returned `OK`, Kaleidoscope moves on
|
||
|
to sending Keyboard HID reports. It clears the current report, and iterates
|
||
|
through the `live_keys` array, looking for non-empty values, and adding them to
|
||
|
the report. For System Control, Consumer Control, and Keyboard HID type `Key`
|
||
|
values, Kaleidoscope handles adding the keycodes to the correct report, but it
|
||
|
also calls this handler, in case a plugin needs to alter that report.
|
||
|
|
||
|
A return value of `OK` allows Kaleidoscope to proceed with adding the
|
||
|
corresponding keycode(s) to the HID report, and `ABORT` causes it to leave and
|
||
|
keycodes from `key` out of the report.
|
||
|
|
||
|
Note that this only applies to the Keyboard and Consumer Control HID reports,
|
||
|
not the System Control report, which has different semantics, and only supports
|
||
|
a single keycode at a time.
|
||
|
|
||
|
### `beforeReportingState(const KeyEvent &event)`
|
||
|
|
||
|
This gets called right before a set of HID reports is sent. At this point,
|
||
|
plugins have access to a (tentative) complete HID report, as well as the full
|
||
|
state of all live keys on the keyboard. This is especially useful for plugins
|
||
|
that might need to do things like remove keycodes (such as keyboard modifiers)
|
||
|
from the forthcoming report just before it gets sent.
|
||
|
|
||
|
This event handler still has access to the event information for the event that
|
||
|
triggered the report, but because it is passed as a `const` reference, it is no
|
||
|
longer possible to change any of its values.
|
||
|
|
||
|
[Note: The older version of `beforeReportingState()` got called once per cycle,
|
||
|
regardless of the pattern of keyswitches toggling on and off, and many plugins
|
||
|
used it as a place to do things like check for timeouts. This new version does
|
||
|
not get called every cycle, so when porting old code to the newer handlers, it's
|
||
|
important to move any code that must be called every cycle to either
|
||
|
`beforeEachCycle()` or `afterEachCycle()`.]
|
||
|
|
||
|
[Also note: Unlike the deprecated `beforeReportingState()`, this one is
|
||
|
abortable. That is, if it returns a result other than `OK` it will stop the
|
||
|
subsequent handlers from getting called, and if it returns `ABORT`, it will also
|
||
|
stop the report from being sent.]
|
||
|
|
||
|
## Other events
|
||
|
|
||
|
### `onLayerChange()`
|
||
|
|
||
|
Called whenever one or more keymap layers are activated or deactivated (just
|
||
|
after the change takes place).
|
||
|
|
||
|
### `onLEDModeChange()`
|
||
|
|
||
|
Called by `LEDControl` whenever the active LED mode changes.
|
||
|
|
||
|
### `beforeSyncingLeds()`
|
||
|
|
||
|
Called immediately before Kaleidoscope sends updated color values to the
|
||
|
LEDs. This event handler is particularly useful to plugins that need to override
|
||
|
the active LED mode (e.g. LED-ActiveModColor).
|
||
|
|
||
|
### `onFocusEvent()`
|
||
|
|
||
|
### `onNameQuery()`
|
||
|
|
||
|
### `exploreSketch()`
|
||
|
|
||
|
## Deprecated
|
||
|
|
||
|
Two existing "event" handlers have been deprecated. In the old version of
|
||
|
Kaleidoscope's main loop, the keyboard's state information was stored in the
|
||
|
keyscanner (which physical switches were on in the current and former scans),
|
||
|
and in the HID reports. The Keyboard HID report would be cleared at the start of
|
||
|
every cycle, and re-populated, on key at a time, calling every
|
||
|
`onKeyswitchEvent()` handler for every active key. Then, once the tentative HID
|
||
|
report was complete, the `beforeReportingState()` handlers would be called, and
|
||
|
the complete report would be sent to the host. In most cycles, that report would
|
||
|
be identical to the previous report, and would be suppressed.
|
||
|
|
||
|
The new system stores the keyboard's current state in the `live_keys` array
|
||
|
instead, and only calls event handlers in response to keyswitch state changes
|
||
|
(and artificially generated events), ultimately sending HID reports in response
|
||
|
to events, rather than at the end of every cycle.
|
||
|
|
||
|
### `onKeyswitchEvent(Key &key, KeyAddr key_addr, uint8_t key_state)`
|
||
|
|
||
|
This handler was called in every cycle, for every non-idle key. Its concept of
|
||
|
an "event" included held keys that did not have a state change. These deprecated
|
||
|
handlers are still called, in response to events and also when preparing the HID
|
||
|
reports, but there is no longer a reasonable mechanism to call them in every
|
||
|
cycle, for every active key, so some functionality could be lost.
|
||
|
|
||
|
It is strongly recommended to switch to using one of the two `KeyEvent`
|
||
|
functions instead, depending on the needs of the plugin (either `onKeyEvent()`
|
||
|
if it is fit for the purpose, or `onKeyswitchEvent()` if necessary). The
|
||
|
`onAddToReport()` function might also be useful, particularly if the plugin in
|
||
|
question uses special `Key` values not recognized by Kaleidoscope itself, but
|
||
|
which should result in keycodes being added to HID reports.
|
||
|
|
||
|
### `beforeReportingState()`
|
||
|
|
||
|
The old version of this handler has been deprecated, but it will still be called
|
||
|
both before HID reports are sent and also once per cycle. It is likely that
|
||
|
these handlers will continue to function, but the code therein should be moved
|
||
|
either to the new `KeyEvent` version of `beforeReportingState()` and/or
|
||
|
`afterEachCycle()` (or `beforeEachCycle()`), depending on whether it needs to be
|
||
|
run only in response to input events or if it must execute every cycle,
|
||
|
respectively.
|