|
|
|
/* Kaleidoscope - Firmware for computer input devices
|
|
|
|
* Copyright (C) 2013-2021 Keyboard.io, Inc.
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU General Public License as published by the Free Software
|
|
|
|
* Foundation, version 3.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kaleidoscope/Runtime.h"
|
|
|
|
|
|
|
|
#include <Arduino.h> // for millis
|
|
|
|
#include <HardwareSerial.h> // for HardwareSerial
|
|
|
|
|
|
|
|
#include "kaleidoscope/KeyAddr.h" // for KeyAddr
|
|
|
|
#include "kaleidoscope/KeyEvent.h" // for KeyEvent
|
|
|
|
#include "kaleidoscope/LiveKeys.h" // for LiveKeys
|
|
|
|
#include "kaleidoscope/device/device.h" // for Base<>::HID
|
|
|
|
#include "kaleidoscope/driver/hid/keyboardio/Keyboard.h" // for Keyboard
|
|
|
|
#include "kaleidoscope/keyswitch_state.h" // for keyToggledOff
|
|
|
|
#include "kaleidoscope/layers.h" // for Layer, Layer_
|
|
|
|
|
Major redesign of the plugin and hooking interface
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
7 years ago
|
|
|
namespace kaleidoscope {
|
|
|
|
|
|
|
|
uint32_t Runtime_::millis_at_cycle_start_;
|
|
|
|
KeyAddr Runtime_::last_addr_toggled_on_ = KeyAddr::none();
|
|
|
|
|
|
|
|
Runtime_::Runtime_(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::setup(void) {
|
|
|
|
// We are explicitly initializing the Serial port as early as possible to
|
|
|
|
// (temporarily, hopefully) work around an issue on OSX. If we initialize
|
|
|
|
// Serial too late, no matter what we do, we'll end up reading garbage from
|
|
|
|
// the serial port. For more information, see the following issue:
|
|
|
|
// https://github.com/keyboardio/Kaleidoscope-Bundle-Keyboardio/pull/7
|
|
|
|
//
|
|
|
|
// TODO(anyone): Figure out a way we can get rid of this, and fix the bug
|
|
|
|
// properly.
|
Redesign how the hardware objects are defined
Instead of having to define `HARDWARE_IMPLEMENTATION` to the class name of the
device, and define `KeyboardHardware` from within the plugin, let all devices
set `kaleidoscope::Device` to their own class via a typedef. Furthermore,
instead of `KeyboardHardware`, use `Kaleidoscope.device()` instead. This makes
device plugins a little bit simpler, and our naming more consistent.
Because some parts of the firmware need to access the device object before the
`Kaleidoscope` object is available, we can't make it a member of that. For this
reason, the device object is `kaleidoscope_internal::device`, and
`Kaleidoscope.device()` wraps it. In general, the wrapper should be used. But if
access to the device is required before `Kaleidoscope` is available, then that's
also available.
The `Kaleidoscope` object grew a few more wrappers: `storage()` and
`serialPort()`, so that one doesn't need to use `Kaleidoscope.device()`
directly, but can use the wrappers, which are noticably shorter to write.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
5 years ago
|
|
|
device().serialPort().begin(9600);
|
|
|
|
|
|
|
|
kaleidoscope::sketch_exploration::pluginsExploreSketch();
|
Major redesign of the plugin and hooking interface
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
7 years ago
|
|
|
kaleidoscope::Hooks::onSetup();
|
|
|
|
|
Redesign how the hardware objects are defined
Instead of having to define `HARDWARE_IMPLEMENTATION` to the class name of the
device, and define `KeyboardHardware` from within the plugin, let all devices
set `kaleidoscope::Device` to their own class via a typedef. Furthermore,
instead of `KeyboardHardware`, use `Kaleidoscope.device()` instead. This makes
device plugins a little bit simpler, and our naming more consistent.
Because some parts of the firmware need to access the device object before the
`Kaleidoscope` object is available, we can't make it a member of that. For this
reason, the device object is `kaleidoscope_internal::device`, and
`Kaleidoscope.device()` wraps it. In general, the wrapper should be used. But if
access to the device is required before `Kaleidoscope` is available, then that's
also available.
The `Kaleidoscope` object grew a few more wrappers: `storage()` and
`serialPort()`, so that one doesn't need to use `Kaleidoscope.device()`
directly, but can use the wrappers, which are noticably shorter to write.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
5 years ago
|
|
|
device().setup();
|
|
|
|
|
|
|
|
// Clear the keyboard state array (all keys idle at start)
|
|
|
|
live_keys.clear();
|
|
|
|
|
|
|
|
Layer.setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::loop(void) {
|
|
|
|
millis_at_cycle_start_ = millis();
|
|
|
|
|
Major redesign of the plugin and hooking interface
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
7 years ago
|
|
|
kaleidoscope::Hooks::beforeEachCycle();
|
|
|
|
|
|
|
|
// Next, we scan the keyswitches. Any toggle-on or toggle-off events will
|
|
|
|
// trigger a call to `handleKeyswitchEvent()`, which in turn will
|
|
|
|
// (conditionally) result in a HID report. Note that each event gets handled
|
|
|
|
// (and any resulting HID report(s) sent) as soon as it is detected. It is
|
|
|
|
// possible for more than one event to be handled like this in any given
|
|
|
|
// cycle, resulting in multiple HID reports, but guaranteeing that only one
|
|
|
|
// event is being handled at a time.
|
Redesign how the hardware objects are defined
Instead of having to define `HARDWARE_IMPLEMENTATION` to the class name of the
device, and define `KeyboardHardware` from within the plugin, let all devices
set `kaleidoscope::Device` to their own class via a typedef. Furthermore,
instead of `KeyboardHardware`, use `Kaleidoscope.device()` instead. This makes
device plugins a little bit simpler, and our naming more consistent.
Because some parts of the firmware need to access the device object before the
`Kaleidoscope` object is available, we can't make it a member of that. For this
reason, the device object is `kaleidoscope_internal::device`, and
`Kaleidoscope.device()` wraps it. In general, the wrapper should be used. But if
access to the device is required before `Kaleidoscope` is available, then that's
also available.
The `Kaleidoscope` object grew a few more wrappers: `storage()` and
`serialPort()`, so that one doesn't need to use `Kaleidoscope.device()`
directly, but can use the wrappers, which are noticably shorter to write.
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
5 years ago
|
|
|
device().scanMatrix();
|
|
|
|
|
|
|
|
kaleidoscope::Hooks::afterEachCycle();
|
|
|
|
}
|
Major redesign of the plugin and hooking interface
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
7 years ago
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::handleKeyswitchEvent(KeyEvent event) {
|
|
|
|
|
|
|
|
// This function strictly handles physical key events. Any event without a
|
|
|
|
// valid `KeyAddr` gets ignored.
|
|
|
|
if (!event.addr.isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Ignore any (non-)event that's not a state change. This check should be
|
|
|
|
// unnecessary, as we shouldn't call this function otherwise.
|
|
|
|
if (!(keyToggledOn(event.state) || keyToggledOff(event.state)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Set the `Key` value for this event.
|
|
|
|
if (keyToggledOff(event.state)) {
|
|
|
|
// When a key toggles off, set the event's key value to whatever the key's
|
|
|
|
// current value is in the live keys state array.
|
|
|
|
event.key = live_keys[event.addr];
|
|
|
|
// If that key was masked, unmask it and return.
|
|
|
|
if (event.key == Key_Masked) {
|
|
|
|
live_keys.clear(event.addr);
|
|
|
|
return;
|
|
|
|
}
|
Change default value of `KeyEvent` from `Key_NoKey` to `Key_Undefined`
This lets us remove some awkward code from `handleKeyswitchEvent()`, because as
long as the default value (which triggers a keymap lookup) was the same as
`Key_Masked`, it wasn't sufficient for an `onKeyswitchEvent()` handler to change
`event.key` to `Key_Masked`, because that would be interpreted by
`handleKeyEvent()` as a signal to do a keymap lookup.
This also makes it more consistent with other parts of the code. The values
`Key_Undefined`, `Key_Inactive`, and `Key_Transparent` are all the same, and
with this change they are each interpreted the same way by code that encounters
them. In a keymap lookup, if an active layer has a `Key_Transparent` value, we
continue searching for a different value on another layer. In the live keys
array, if we find a `Key_Inactive` entry, we look for a value from the keymap.
And with this change, when processing a key event, if it has a `Key_Undefined`
value, we look for a value from `active_keys` (and then from the keymap layers,
if nothing is found there).
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
4 years ago
|
|
|
} else if (event.key == Key_Undefined) {
|
|
|
|
// When a key toggles on, unless the event already has a key value (i.e. we
|
|
|
|
// were called by a plugin rather than `actOnMatrixScan()`), we look up the
|
|
|
|
// value from the current keymap (overridden by `live_keys`).
|
|
|
|
event.key = lookupKey(event.addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the plugin event handlers
|
|
|
|
auto result = Hooks::onKeyswitchEvent(event);
|
|
|
|
|
|
|
|
// Now we check the result from the plugin event handlers, and stop processing
|
|
|
|
// if it was anything other than `OK`.
|
|
|
|
if (result != EventHandlerResult::OK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If all the plugin handlers returned OK, we proceed to the next step in
|
|
|
|
// processing the event.
|
|
|
|
handleKeyEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::handleKeyEvent(KeyEvent event) {
|
|
|
|
|
|
|
|
// For events that didn't begin with `handleKeyswitchEvent()`, we need to look
|
|
|
|
// up the `Key` value from the keymap (maybe overridden by `live_keys`).
|
|
|
|
if (event.addr.isValid()) {
|
Change default value of `KeyEvent` from `Key_NoKey` to `Key_Undefined`
This lets us remove some awkward code from `handleKeyswitchEvent()`, because as
long as the default value (which triggers a keymap lookup) was the same as
`Key_Masked`, it wasn't sufficient for an `onKeyswitchEvent()` handler to change
`event.key` to `Key_Masked`, because that would be interpreted by
`handleKeyEvent()` as a signal to do a keymap lookup.
This also makes it more consistent with other parts of the code. The values
`Key_Undefined`, `Key_Inactive`, and `Key_Transparent` are all the same, and
with this change they are each interpreted the same way by code that encounters
them. In a keymap lookup, if an active layer has a `Key_Transparent` value, we
continue searching for a different value on another layer. In the live keys
array, if we find a `Key_Inactive` entry, we look for a value from the keymap.
And with this change, when processing a key event, if it has a `Key_Undefined`
value, we look for a value from `active_keys` (and then from the keymap layers,
if nothing is found there).
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
4 years ago
|
|
|
if (keyToggledOff(event.state) || event.key == Key_Undefined) {
|
|
|
|
event.key = lookupKey(event.addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If any `onKeyEvent()` handler returns `ABORT`, we return before updating
|
|
|
|
// the Live Keys state array; as if the event didn't happen.
|
|
|
|
auto result = Hooks::onKeyEvent(event);
|
|
|
|
if (result == EventHandlerResult::ABORT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Update the live keys array based on the new event.
|
|
|
|
if (event.addr.isValid()) {
|
|
|
|
if (keyToggledOff(event.state)) {
|
|
|
|
live_keys.clear(event.addr);
|
|
|
|
} else {
|
|
|
|
live_keys.activate(event.addr, event.key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If any `onKeyEvent()` handler returned a value other than `OK`, stop
|
|
|
|
// processing now. Likewise if the event's `Key` value is a no-op.
|
|
|
|
if (result != EventHandlerResult::OK ||
|
|
|
|
event.key == Key_Masked ||
|
|
|
|
event.key == Key_NoKey ||
|
Change default value of `KeyEvent` from `Key_NoKey` to `Key_Undefined`
This lets us remove some awkward code from `handleKeyswitchEvent()`, because as
long as the default value (which triggers a keymap lookup) was the same as
`Key_Masked`, it wasn't sufficient for an `onKeyswitchEvent()` handler to change
`event.key` to `Key_Masked`, because that would be interpreted by
`handleKeyEvent()` as a signal to do a keymap lookup.
This also makes it more consistent with other parts of the code. The values
`Key_Undefined`, `Key_Inactive`, and `Key_Transparent` are all the same, and
with this change they are each interpreted the same way by code that encounters
them. In a keymap lookup, if an active layer has a `Key_Transparent` value, we
continue searching for a different value on another layer. In the live keys
array, if we find a `Key_Inactive` entry, we look for a value from the keymap.
And with this change, when processing a key event, if it has a `Key_Undefined`
value, we look for a value from `active_keys` (and then from the keymap layers,
if nothing is found there).
Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
4 years ago
|
|
|
event.key == Key_Undefined ||
|
|
|
|
event.key == Key_Transparent)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If it's a built-in Layer key, we handle it here, and skip sending report(s)
|
|
|
|
if (event.key.isLayerKey()) {
|
|
|
|
Layer.handleLayerKeyEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The System Control HID report contains only one keycode, and gets sent
|
|
|
|
// immediately on `pressSystemControl()` or `releaseSystemControl()`. This is
|
|
|
|
// significantly different from the way the other HID reports work, where held
|
|
|
|
// keys remain in effect for subsequent reports.
|
|
|
|
if (event.key.isSystemControlKey()) {
|
|
|
|
if (keyToggledOn(event.state)) {
|
|
|
|
hid().keyboard().pressSystemControl(event.key);
|
|
|
|
} else { /* if (keyToggledOff(key_state)) */
|
|
|
|
hid().keyboard().releaseSystemControl(event.key);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Until this point, the old report was still valid. Now we construct the new
|
|
|
|
// one, based on the contents of the `live_keys` state array.
|
|
|
|
prepareKeyboardReport(event);
|
|
|
|
|
|
|
|
// Finally, send the new keyboard report
|
|
|
|
sendKeyboardReport(event);
|
|
|
|
|
|
|
|
// Now that the report has been sent, let plugins act on it after the fact.
|
|
|
|
// This is useful for plugins that need to react to an event, but must wait
|
|
|
|
// until after that event is processed to do so.
|
|
|
|
Hooks::afterReportingState(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::prepareKeyboardReport(const KeyEvent &event) {
|
|
|
|
// before building the new report, start clean
|
|
|
|
device().hid().keyboard().releaseAllKeys();
|
|
|
|
|
|
|
|
// Build report from composite keymap cache. This can be much more efficient
|
|
|
|
// with a bitfield. What we should be doing here is going through the array
|
|
|
|
// and checking for HID values (Keyboard, Consumer, System) and directly
|
|
|
|
// adding them to their respective reports. This comes before the old plugin
|
|
|
|
// hooks are called for the new event so that the report will be full complete
|
|
|
|
// except for that new event.
|
|
|
|
for (KeyAddr key_addr : KeyAddr::all()) {
|
|
|
|
// Skip this event's key addr; we will deal with that later. This is most
|
|
|
|
// important in the case of a key release, because we can't safely remove
|
|
|
|
// any keycode(s) added to the report later.
|
|
|
|
if (key_addr == event.addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Key key = live_keys[key_addr];
|
|
|
|
|
|
|
|
// If the key is idle or masked, we can ignore it.
|
|
|
|
if (key == Key_Inactive || key == Key_Masked)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
addToReport(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::addToReport(Key key) {
|
|
|
|
// First, call any relevant plugin handlers, to give them a chance to add
|
|
|
|
// other values to the HID report directly and/or to abort the automatic
|
|
|
|
// adding of keycodes below.
|
|
|
|
auto result = Hooks::onAddToReport(key);
|
|
|
|
if (result == EventHandlerResult::ABORT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (key.isKeyboardKey()) {
|
|
|
|
// The only incidental Keyboard modifiers that are allowed are the ones on
|
|
|
|
// the key that generated the event, so we strip any others before adding
|
|
|
|
// them. This might turn out to be too simple to cover all the corner cases,
|
|
|
|
// but the OS should be helpful and do most of the masking we want for us.
|
|
|
|
if (!key.isKeyboardModifier())
|
|
|
|
key.setFlags(0);
|
|
|
|
|
|
|
|
hid().keyboard().pressKey(key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key.isConsumerControlKey()) {
|
|
|
|
hid().keyboard().pressConsumerControl(key);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// System Control keys and Layer keys are not handled here because they only
|
|
|
|
// take effect on toggle-on or toggle-off events, they don't get added to HID
|
|
|
|
// reports when held.
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void
|
|
|
|
Runtime_::sendKeyboardReport(const KeyEvent &event) {
|
|
|
|
// If the keycode for this key is already in the report, we need to send an
|
|
|
|
// extra report without that keycode in order to correctly process the
|
|
|
|
// rollover. It might be better to exempt modifiers from this rule, but it's
|
|
|
|
// not clear that would be better.
|
|
|
|
if (keyToggledOn(event.state) &&
|
|
|
|
event.key.isKeyboardKey()) {
|
|
|
|
// last keyboard key toggled on
|
|
|
|
last_addr_toggled_on_ = event.addr;
|
|
|
|
if (hid().keyboard().isKeyPressed(event.key)) {
|
|
|
|
// The keycode (flags ignored) for `event.key` is active in the current
|
|
|
|
// report. Should this be `wasKeyPressed()` instead? I don't think so,
|
|
|
|
// because (if I'm right) the new event hasn't been added yet.
|
|
|
|
hid().keyboard().releaseKey(event.key);
|
|
|
|
hid().keyboard().sendReport();
|
|
|
|
}
|
|
|
|
if (event.key.getFlags() != 0) {
|
|
|
|
hid().keyboard().pressModifiers(event.key);
|
|
|
|
hid().keyboard().sendReport();
|
|
|
|
}
|
|
|
|
} else if (event.addr != last_addr_toggled_on_) {
|
|
|
|
// (not a keyboard key OR toggled off) AND not last keyboard key toggled on
|
|
|
|
Key last_key = live_keys[last_addr_toggled_on_];
|
|
|
|
if (last_key.isKeyboardKey()) {
|
|
|
|
hid().keyboard().pressModifiers(last_key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (keyToggledOn(event.state)) {
|
|
|
|
addToReport(event.key);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call new pre-report handlers:
|
|
|
|
if (Hooks::beforeReportingState(event) == EventHandlerResult::ABORT)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Finally, send the report:
|
|
|
|
device().hid().keyboard().sendReport();
|
Major redesign of the plugin and hooking interface
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
7 years ago
|
|
|
}
|
|
|
|
|
|
|
|
Runtime_ Runtime;
|
Major redesign of the plugin and hooking interface
With this redesign, we introduce a new way to create plugins, which is easier to
extend with new hook points, provides a better interface, uses less memory, less
program space, and is a tiny bit faster too.
It all begins with `kaleidoscope::Plugin` being the base class, which provides
the hook methods plugins can implement. Plugins should be declared with
`KALEIDOSCOPE_INIT_PLUGINS` instead of `Kaleidoscope.use()`. Behind this macro
is a bit of magic (see the in-code documentation) that allows us to unroll the
hook method calls, avoid vtables, and so on. It creates an override for
`kaleidoscope::Hooks::*` methods, each of which will call the respective methods
of each initialized plugin.
With the new API come new names: all of the methods plugins can implement
received new, more descriptive names that all follow a similar pattern.
The old (dubbed V1) API still remains in place, although deprecated. One can
turn it off by setting the `KALEIDOSCOPE_ENABLE_V1_PLUGIN_API` define to zero,
while compiling the firmware.
This work is based on #276, written by @noseglasses. @obra and @algernon did
some cleaning up and applied a little naming treatment.
Signed-off-by: noseglasses <shinynoseglasses@gmail.com>
Signed-off-by: Jesse Vincent <jesse@keyboard.io>
Signed-off-by: Gergely Nagy <algernon@keyboard.io>
7 years ago
|
|
|
|
|
|
|
} // namespace kaleidoscope
|
|
|
|
|
|
|
|
kaleidoscope::Runtime_ &Kaleidoscope = kaleidoscope::Runtime;
|