This class should help plugins that implement `onKeyswitchEvent()` to ensure that they won't process the same event more than once. Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>pull/1024/head
parent
1946e1de0b
commit
015b8e3140
@ -0,0 +1,104 @@
|
||||
/* Kaleidoscope - Firmware for computer input devices
|
||||
* Copyright (C) 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "kaleidoscope/event_handler_result.h" // for EventHandlerResult
|
||||
#include "kaleidoscope/KeyEvent.h" // for KeyEvent, KeyEventId
|
||||
|
||||
namespace kaleidoscope {
|
||||
|
||||
/// An event tracker for plugins that implement `onKeyswitchEvent()`
|
||||
///
|
||||
/// Plugins that implement the `onKeyswitchEvent()` are required to agree to a
|
||||
/// contract wherein they promise to only process each event once. They may
|
||||
/// delay an event by returning `EventHandlerResult::ABORT` when they first
|
||||
/// encounter an event, then re-start it (in response to a subsequent event or a
|
||||
/// timeout) by calling `Runtime.handleKeyswitchEvent()`. When they do so, they
|
||||
/// must take pains to ensure that they ignore that event when it gets passed to
|
||||
/// their `onKeyswitchEvent()` handler a second time. In addition, a subsequent
|
||||
/// plugin's `onKeyswitchEvent()` handler might do the same thing, and the event
|
||||
/// must be ignored in that case as well. This `KeyEventTracker` class is a
|
||||
/// helper that makes it easy for plugins to abide by the terms of the
|
||||
/// `onKeyswitchEvent()` contract.
|
||||
///
|
||||
/// All that's required is adding a private member variable to the plugin's
|
||||
/// class definition, as follows:
|
||||
///
|
||||
/// ```c++
|
||||
/// class MyPlugin : public Plugin {
|
||||
/// private:
|
||||
/// KeyEventTracker event_tracker_;
|
||||
/// public:
|
||||
/// EventHandlerResult onKeyswitchEvent(KeyEvent &event);
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Then, in the definition of that plugin's `onKeyswitchEvent()` function, use
|
||||
/// the tracker's `shouldIgnore()` function to let already-processed events pass
|
||||
/// through:
|
||||
///
|
||||
/// ```c++
|
||||
/// EventHandlerResult MyPlugin::onKeyswitchEvent(KeyEvent &event) {
|
||||
/// if (event_tracker_.shouldIgnore(event))
|
||||
/// return EventHandlerResult::OK;
|
||||
/// ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// As a side effect, the `shouldIgnore()` function will record the `id` of the
|
||||
/// event, if it is not one that the tracker has seen "recently". It works by
|
||||
/// keeping track of the "newest" event ID that it has seen, by subtracting the
|
||||
/// ID of the event passed to it from the current "newest" event ID. If the
|
||||
/// result is greater than zero, the event is considered to be "new" and the
|
||||
/// tracked ID is updated. The mechanism isn't perfect; if 128 (`KeyEventId`
|
||||
/// stores ony byte of data) new event IDs are generated without any of them
|
||||
/// reaching the plugin's `onKeyswitchEvent()` handler, it is theoretically
|
||||
/// possible to overflow and a new event will be treated as old.
|
||||
|
||||
class KeyEventTracker {
|
||||
|
||||
private:
|
||||
// The ID of the "newest" event this tracker has seen.
|
||||
KeyEventId last_id_seen_{-1};
|
||||
|
||||
public:
|
||||
/// Check if an event should be ignored by the client plugin
|
||||
///
|
||||
/// This function should be called by a plugin's `onKeyswitchEvent()` handler
|
||||
/// function to determined if the `event` has an `id` member that this tracker
|
||||
/// has seen "recently".
|
||||
bool shouldIgnore(const KeyEvent &event) {
|
||||
return !isNew(event);
|
||||
}
|
||||
|
||||
/// Report if a given event is "new" to this tracker
|
||||
///
|
||||
/// Returns `true` if the input event is newer than the latest event the
|
||||
/// tracker has seen. If it is newer, also update the tracker to reflect the
|
||||
/// new event ID.
|
||||
bool isNew(const KeyEvent &event) {
|
||||
KeyEventId offset = event.id() - last_id_seen_;
|
||||
if (offset > 0) {
|
||||
last_id_seen_ = event.id();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace kaleidoscope
|
Loading…
Reference in new issue