|
|
@ -21,14 +21,14 @@
|
|
|
|
using namespace KaleidoscopePlugins::Ranges;
|
|
|
|
using namespace KaleidoscopePlugins::Ranges;
|
|
|
|
|
|
|
|
|
|
|
|
namespace KaleidoscopePlugins {
|
|
|
|
namespace KaleidoscopePlugins {
|
|
|
|
// --- state ---
|
|
|
|
// --- state ---
|
|
|
|
Key Leader::sequence[LEADER_MAX_SEQUENCE_LENGTH + 1];
|
|
|
|
Key Leader::sequence[LEADER_MAX_SEQUENCE_LENGTH + 1];
|
|
|
|
uint8_t Leader::sequencePos;
|
|
|
|
uint8_t Leader::sequencePos;
|
|
|
|
uint32_t Leader::endTime;
|
|
|
|
uint32_t Leader::endTime;
|
|
|
|
uint16_t Leader::timeOut = 1000;
|
|
|
|
uint16_t Leader::timeOut = 1000;
|
|
|
|
const Leader::dictionary_t *Leader::dictionary;
|
|
|
|
const Leader::dictionary_t *Leader::dictionary;
|
|
|
|
|
|
|
|
|
|
|
|
// --- helpers ---
|
|
|
|
// --- helpers ---
|
|
|
|
|
|
|
|
|
|
|
|
#define PARTIAL_MATCH -1
|
|
|
|
#define PARTIAL_MATCH -1
|
|
|
|
#define NO_MATCH -2
|
|
|
|
#define NO_MATCH -2
|
|
|
@ -36,142 +36,142 @@ namespace KaleidoscopePlugins {
|
|
|
|
#define isLeader(k) (k.raw >= LEAD_FIRST && k.raw <= LEAD_LAST)
|
|
|
|
#define isLeader(k) (k.raw >= LEAD_FIRST && k.raw <= LEAD_LAST)
|
|
|
|
#define isActive() (sequence[0].raw != Key_NoKey.raw)
|
|
|
|
#define isActive() (sequence[0].raw != Key_NoKey.raw)
|
|
|
|
|
|
|
|
|
|
|
|
// --- actions ---
|
|
|
|
// --- actions ---
|
|
|
|
int8_t
|
|
|
|
int8_t
|
|
|
|
Leader::lookup (void) {
|
|
|
|
Leader::lookup (void) {
|
|
|
|
bool match;
|
|
|
|
bool match;
|
|
|
|
|
|
|
|
|
|
|
|
for (uint8_t seqIndex = 0; ; seqIndex++) {
|
|
|
|
for (uint8_t seqIndex = 0; ; seqIndex++) {
|
|
|
|
match = true;
|
|
|
|
match = true;
|
|
|
|
|
|
|
|
|
|
|
|
if (pgm_read_word (&(dictionary[seqIndex].sequence[0].raw)) == Key_NoKey.raw)
|
|
|
|
if (pgm_read_word (&(dictionary[seqIndex].sequence[0].raw)) == Key_NoKey.raw)
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
Key seqKey;
|
|
|
|
Key seqKey;
|
|
|
|
for (uint8_t i = 0; i <= sequencePos; i++) {
|
|
|
|
for (uint8_t i = 0; i <= sequencePos; i++) {
|
|
|
|
seqKey.raw = pgm_read_word (&(dictionary[seqIndex].sequence[i].raw));
|
|
|
|
seqKey.raw = pgm_read_word (&(dictionary[seqIndex].sequence[i].raw));
|
|
|
|
|
|
|
|
|
|
|
|
if (sequence[i].raw != seqKey.raw) {
|
|
|
|
if (sequence[i].raw != seqKey.raw) {
|
|
|
|
match = false;
|
|
|
|
match = false;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!match)
|
|
|
|
if (!match)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
seqKey.raw = pgm_read_word (&(dictionary[seqIndex].sequence[sequencePos + 1].raw));
|
|
|
|
seqKey.raw = pgm_read_word (&(dictionary[seqIndex].sequence[sequencePos + 1].raw));
|
|
|
|
if (seqKey.raw == Key_NoKey.raw) {
|
|
|
|
if (seqKey.raw == Key_NoKey.raw) {
|
|
|
|
return seqIndex;
|
|
|
|
return seqIndex;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
return PARTIAL_MATCH;
|
|
|
|
return PARTIAL_MATCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return NO_MATCH;
|
|
|
|
return NO_MATCH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- api ---
|
|
|
|
// --- api ---
|
|
|
|
|
|
|
|
|
|
|
|
Leader::Leader (void) {
|
|
|
|
Leader::Leader (void) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
void
|
|
|
|
Leader::begin (void) {
|
|
|
|
Leader::begin (void) {
|
|
|
|
event_handler_hook_use (this->eventHandlerHook);
|
|
|
|
event_handler_hook_use (this->eventHandlerHook);
|
|
|
|
loop_hook_use (this->loopHook);
|
|
|
|
loop_hook_use (this->loopHook);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
void
|
|
|
|
Leader::configure (const Leader::dictionary_t dictionary_[]) {
|
|
|
|
Leader::configure (const Leader::dictionary_t dictionary_[]) {
|
|
|
|
dictionary = dictionary_;
|
|
|
|
dictionary = dictionary_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
void
|
|
|
|
Leader::reset (void) {
|
|
|
|
Leader::reset (void) {
|
|
|
|
sequencePos = 0;
|
|
|
|
sequencePos = 0;
|
|
|
|
sequence[0].raw = Key_NoKey.raw;
|
|
|
|
sequence[0].raw = Key_NoKey.raw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
void
|
|
|
|
Leader::inject (Key key, uint8_t keyState) {
|
|
|
|
Leader::inject (Key key, uint8_t keyState) {
|
|
|
|
eventHandlerHook (key, 255, 255, keyState);
|
|
|
|
eventHandlerHook (key, 255, 255, keyState);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- hooks ---
|
|
|
|
// --- hooks ---
|
|
|
|
Key
|
|
|
|
Key
|
|
|
|
Leader::eventHandlerHook (Key mappedKey, byte row, byte col, uint8_t keyState) {
|
|
|
|
Leader::eventHandlerHook (Key mappedKey, byte row, byte col, uint8_t keyState) {
|
|
|
|
if (keyState & INJECTED)
|
|
|
|
if (keyState & INJECTED)
|
|
|
|
return mappedKey;
|
|
|
|
return mappedKey;
|
|
|
|
|
|
|
|
|
|
|
|
if (!key_is_pressed (keyState) && !key_was_pressed (keyState)) {
|
|
|
|
if (!key_is_pressed (keyState) && !key_was_pressed (keyState)) {
|
|
|
|
if (isLeader (mappedKey))
|
|
|
|
if (isLeader (mappedKey))
|
|
|
|
return Key_NoKey;
|
|
|
|
return Key_NoKey;
|
|
|
|
return mappedKey;
|
|
|
|
return mappedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isActive () && !isLeader (mappedKey))
|
|
|
|
if (!isActive () && !isLeader (mappedKey))
|
|
|
|
return mappedKey;
|
|
|
|
return mappedKey;
|
|
|
|
|
|
|
|
|
|
|
|
if (!isActive ()) {
|
|
|
|
if (!isActive ()) {
|
|
|
|
// Must be a leader key!
|
|
|
|
// Must be a leader key!
|
|
|
|
|
|
|
|
|
|
|
|
if (key_toggled_off (keyState)) {
|
|
|
|
if (key_toggled_off (keyState)) {
|
|
|
|
// not active, but a leader key = start the sequence on key release!
|
|
|
|
// not active, but a leader key = start the sequence on key release!
|
|
|
|
endTime = millis () + timeOut;
|
|
|
|
endTime = millis () + timeOut;
|
|
|
|
sequencePos = 0;
|
|
|
|
sequencePos = 0;
|
|
|
|
sequence[sequencePos].raw = mappedKey.raw;
|
|
|
|
sequence[sequencePos].raw = mappedKey.raw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If the sequence was not active yet, ignore the key.
|
|
|
|
// If the sequence was not active yet, ignore the key.
|
|
|
|
return Key_NoKey;
|
|
|
|
return Key_NoKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// active
|
|
|
|
// active
|
|
|
|
int8_t actionIndex = lookup ();
|
|
|
|
int8_t actionIndex = lookup ();
|
|
|
|
|
|
|
|
|
|
|
|
if (key_toggled_on (keyState)) {
|
|
|
|
if (key_toggled_on (keyState)) {
|
|
|
|
sequencePos++;
|
|
|
|
sequencePos++;
|
|
|
|
if (sequencePos > LEADER_MAX_SEQUENCE_LENGTH) {
|
|
|
|
if (sequencePos > LEADER_MAX_SEQUENCE_LENGTH) {
|
|
|
|
reset ();
|
|
|
|
reset ();
|
|
|
|
return mappedKey;
|
|
|
|
return mappedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endTime = millis () + timeOut;
|
|
|
|
endTime = millis () + timeOut;
|
|
|
|
sequence[sequencePos].raw = mappedKey.raw;
|
|
|
|
sequence[sequencePos].raw = mappedKey.raw;
|
|
|
|
actionIndex = lookup ();
|
|
|
|
actionIndex = lookup ();
|
|
|
|
|
|
|
|
|
|
|
|
if (actionIndex >= 0)
|
|
|
|
if (actionIndex >= 0)
|
|
|
|
return Key_NoKey;
|
|
|
|
return Key_NoKey;
|
|
|
|
} else if (key_is_pressed (keyState)) {
|
|
|
|
} else if (key_is_pressed (keyState)) {
|
|
|
|
// held, no need for anything here.
|
|
|
|
// held, no need for anything here.
|
|
|
|
return Key_NoKey;
|
|
|
|
return Key_NoKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (actionIndex == NO_MATCH) {
|
|
|
|
if (actionIndex == NO_MATCH) {
|
|
|
|
reset ();
|
|
|
|
reset ();
|
|
|
|
return mappedKey;
|
|
|
|
return mappedKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (actionIndex == PARTIAL_MATCH) {
|
|
|
|
if (actionIndex == PARTIAL_MATCH) {
|
|
|
|
return Key_NoKey;
|
|
|
|
return Key_NoKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
action_t leaderAction = (action_t) pgm_read_ptr (&(dictionary[actionIndex].action));
|
|
|
|
action_t leaderAction = (action_t) pgm_read_ptr (&(dictionary[actionIndex].action));
|
|
|
|
(*leaderAction) (actionIndex);
|
|
|
|
(*leaderAction) (actionIndex);
|
|
|
|
return Key_NoKey;
|
|
|
|
return Key_NoKey;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
void
|
|
|
|
Leader::loopHook (bool postClear) {
|
|
|
|
Leader::loopHook (bool postClear) {
|
|
|
|
if (!postClear)
|
|
|
|
if (!postClear)
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!isActive ())
|
|
|
|
if (!isActive ())
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (millis () >= endTime)
|
|
|
|
if (millis () >= endTime)
|
|
|
|
reset ();
|
|
|
|
reset ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
KaleidoscopePlugins::Leader Leader;
|
|
|
|
KaleidoscopePlugins::Leader Leader;
|
|
|
|