-
Notifications
You must be signed in to change notification settings - Fork 258
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a complete rewrite of Qukeys, in order to implement several improvements and new features: - A new EventQueue class has been introduced, in order to store both key press and release events in the queue. - The direct dependence on KeyboardioHID is removed by only flushing one event from the queue per cycle. - The array of Qukey objects is now stored in PROGMEM instead of SRAM. - There is a new algorithm for determining which state a qukey will collapse into in the case of rollover from qukey to another key, which should reduce the rate of errors for "sloppy" typists. - A Qukey with a primary key value that is a modifier (including layer shift keys) is treated like a SpaceCadet key, with different semantics. The alternate (non-modifier) key value is only used if the SpaceCadet key is pressed and released on its own, without rolling over to any other key. - The code is generally simpler and easier to understand, with better inline comments explaining how it all works. Signed-off-by: Michael Richters <gedankenexperimenter@gmail.com>
- Loading branch information
1 parent
be860f1
commit 928c6d9
Showing
6 changed files
with
693 additions
and
407 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// -*- mode: c++ -*- | ||
/* Kaleidoscope - Firmware for computer input devices | ||
* Copyright (C) 2013-2019 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 <Arduino.h> | ||
|
||
#include "kaleidoscope/Kaleidoscope.h" | ||
#include "kaleidoscope/KeyAddr.h" | ||
|
||
namespace kaleidoscope { | ||
|
||
// This class defines a generic event queue that stores both key press and | ||
// release events, recording the key address, a timestamp, and the keyswitch | ||
// state (press or release). | ||
template <uint8_t _max_length, | ||
typename _Bitfield = uint8_t, | ||
typename _Timestamp = uint16_t> | ||
class EventQueue { | ||
|
||
static_assert(_max_length <= 255, | ||
"EventQueue error: _max_length must be less than 256!"); | ||
static_assert(_max_length <= (sizeof(_Bitfield) * 8), | ||
"EventQueue error: _Bitfield type too small for _max_length!"); | ||
|
||
private: | ||
uint8_t length_{0}; | ||
KeyAddr addrs_[_max_length]; | ||
_Timestamp timestamps_[_max_length]; | ||
_Bitfield release_event_bits_; | ||
|
||
public: | ||
uint8_t length() const { return length_; } | ||
bool isEmpty() const { return (length_ == 0); } | ||
bool isFull() const { return (length_ == _max_length); } | ||
|
||
KeyAddr addr(uint8_t index) const { return addrs_[index]; } | ||
|
||
_Timestamp timestamp(uint8_t index) const { return timestamps_[index]; } | ||
|
||
bool isRelease(uint8_t index) const { | ||
return bitRead(release_event_bits_, index); | ||
} | ||
bool isPress(uint8_t index) const { return !isRelease(index); } | ||
|
||
// Append a new event on the end of the queue. | ||
void append(KeyAddr k, uint8_t keyswitch_state) { | ||
addrs_[length_] = k; | ||
timestamps_[length_] = Kaleidoscope.millisAtCycleStart(); | ||
bitWrite(release_event_bits_, length_, keyToggledOff(keyswitch_state)); | ||
++length_; | ||
} | ||
|
||
// Remove the first event from the head of the queue, shifting the others. | ||
void shift() { | ||
--length_; | ||
for (uint8_t i{0}; i < length_; ++i) { | ||
addrs_[i] = addrs_[i + 1]; | ||
timestamps_[i] = timestamps_[i + 1]; | ||
} | ||
release_event_bits_ >>= 1; | ||
} | ||
|
||
// Remove an event from the middle of the queue. This is considerably more | ||
// costly than removing the event at the head of the queue with `shift()` (see | ||
// above). | ||
void remove(uint8_t index) { | ||
--length_; | ||
for (uint8_t i{index}; i < length_; ++i) { | ||
addrs_[i] = addrs_[i + 1]; | ||
timestamps_[i] = timestamps_[i + 1]; | ||
} | ||
static constexpr _Bitfield all = -1; | ||
|
||
_Bitfield tail_mask = all << index; | ||
_Bitfield head_mask = ~tail_mask; | ||
|
||
_Bitfield tail = (release_event_bits_ >> 1) & tail_mask; | ||
_Bitfield head = release_event_bits_ & head_mask; | ||
|
||
release_event_bits_ = tail | head; | ||
} | ||
|
||
// Empty the queue entirely. | ||
void clear() { | ||
length_ = 0; | ||
release_event_bits_ = 0; | ||
} | ||
}; | ||
|
||
} // namespace kaleidoscope |
Oops, something went wrong.