|
|
|
@ -39,7 +39,7 @@ Qukey::Qukey(int8_t layer, byte row, byte col, Key alt_keycode) {
|
|
|
|
|
Qukey * Qukeys::qukeys_;
|
|
|
|
|
uint8_t Qukeys::qukeys_count_ = 0;
|
|
|
|
|
bool Qukeys::active_ = true;
|
|
|
|
|
uint16_t Qukeys::time_limit_ = 200;
|
|
|
|
|
uint16_t Qukeys::time_limit_ = 500;
|
|
|
|
|
QueueItem Qukeys::key_queue_[QUKEYS_QUEUE_MAX] = {};
|
|
|
|
|
uint8_t Qukeys::key_queue_length_ = 0;
|
|
|
|
|
|
|
|
|
@ -52,15 +52,15 @@ Qukeys::Qukeys(void) {}
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
int8_t Qukeys::lookupQukey(uint8_t key_addr) {
|
|
|
|
|
if (key_addr == QUKEY_UNKNOWN_ADDR)
|
|
|
|
|
if (key_addr == QUKEY_UNKNOWN_ADDR) {
|
|
|
|
|
return QUKEY_NOT_FOUND;
|
|
|
|
|
}
|
|
|
|
|
for (int8_t i = 0; i < qukeys_count_; i++) {
|
|
|
|
|
Qukey qukey = qukeys_[i];
|
|
|
|
|
if (qukey.addr == key_addr) {
|
|
|
|
|
if (qukeys_[i].addr == key_addr) {
|
|
|
|
|
byte row = addr::row(key_addr);
|
|
|
|
|
byte col = addr::col(key_addr);
|
|
|
|
|
if ((qukey.layer == QUKEY_ALL_LAYERS) ||
|
|
|
|
|
(qukey.layer == Layer.lookupActiveLayer(row, col))) {
|
|
|
|
|
if ((qukeys_[i].layer == QUKEY_ALL_LAYERS) ||
|
|
|
|
|
(qukeys_[i].layer == Layer.lookupActiveLayer(row, col))) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -70,7 +70,7 @@ int8_t Qukeys::lookupQukey(uint8_t key_addr) {
|
|
|
|
|
|
|
|
|
|
void Qukeys::enqueue(uint8_t key_addr) {
|
|
|
|
|
if (key_queue_length_ == QUKEYS_QUEUE_MAX) {
|
|
|
|
|
flushKey(QUKEY_STATE_PRIMARY);
|
|
|
|
|
flushKey(QUKEY_STATE_PRIMARY, IS_PRESSED | WAS_PRESSED);
|
|
|
|
|
}
|
|
|
|
|
key_queue_[key_queue_length_].addr = key_addr;
|
|
|
|
|
key_queue_[key_queue_length_].flush_time = millis() + time_limit_;
|
|
|
|
@ -82,11 +82,11 @@ int8_t Qukeys::searchQueue(uint8_t key_addr) {
|
|
|
|
|
if (key_queue_[i].addr == key_addr)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
return QUKEY_NOT_FOUND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// flush a single entry from the head of the queue
|
|
|
|
|
void Qukeys::flushKey(int8_t state) {
|
|
|
|
|
void Qukeys::flushKey(int8_t state, uint8_t keyswitch_state) {
|
|
|
|
|
int8_t qukey_index = lookupQukey(key_queue_[0].addr);
|
|
|
|
|
if (qukey_index != QUKEY_NOT_FOUND) {
|
|
|
|
|
qukeys_[qukey_index].state = state;
|
|
|
|
@ -112,23 +112,43 @@ void Qukeys::flushKey(int8_t state) {
|
|
|
|
|
handleKeyswitchEvent(keycode, row, col, IS_PRESSED | INJECTED);
|
|
|
|
|
// Now we send the report (if there were any changes)
|
|
|
|
|
hid::sendKeyboardReport();
|
|
|
|
|
// Now for the tricky bit; we need to know if the key was actually
|
|
|
|
|
// released, or if it's still being held. Otherwise, we'll screw up
|
|
|
|
|
// the next call to flushKey().
|
|
|
|
|
handleKeyswitchEvent(keycode, row, col, keyswitch_state | INJECTED);
|
|
|
|
|
hid::sendKeyboardReport();
|
|
|
|
|
|
|
|
|
|
// Shift the queue, so key_queue[0] is always the first key that gets processed
|
|
|
|
|
for (byte i = 0; i < key_queue_length_; i++) {
|
|
|
|
|
key_queue_[i] = key_queue_[i + 1];
|
|
|
|
|
}
|
|
|
|
|
key_queue_length_--;
|
|
|
|
|
// If a qukey was released, reset its state to undetermined. This
|
|
|
|
|
// probably doesn't hurt, but it's also probably useless:
|
|
|
|
|
if (!(keyswitch_state & IS_PRESSED) &&
|
|
|
|
|
(qukey_index != QUKEY_NOT_FOUND)) {
|
|
|
|
|
qukeys_[qukey_index].state = QUKEY_STATE_UNDETERMINED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Qukeys::flushQueue(int8_t state, int8_t index) {
|
|
|
|
|
for (int8_t i = 0; i <= index; i++) {
|
|
|
|
|
// flushQueue() is called when a key that's in the key_queue is
|
|
|
|
|
// released. This means that all the keys ahead of it in the queue are
|
|
|
|
|
// still being held, so first we flush them, then we flush the
|
|
|
|
|
// released key (with different parameters).
|
|
|
|
|
void Qukeys::flushQueue(int8_t index) {
|
|
|
|
|
if (index == QUKEY_NOT_FOUND)
|
|
|
|
|
return;
|
|
|
|
|
for (int8_t i = 0; i < index; i++) {
|
|
|
|
|
if (key_queue_length_ == 0)
|
|
|
|
|
break;
|
|
|
|
|
flushKey(state);
|
|
|
|
|
flushKey(QUKEY_STATE_ALTERNATE, IS_PRESSED | WAS_PRESSED);
|
|
|
|
|
}
|
|
|
|
|
flushKey(QUKEY_STATE_PRIMARY, WAS_PRESSED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Key Qukeys::keyScanHook(Key mapped_key, byte row, byte col, uint8_t key_state) {
|
|
|
|
|
// Uncomment this for debugging, so as not to make flashing difficult
|
|
|
|
|
//if (row == 0 && col == 0) return mapped_key;
|
|
|
|
|
|
|
|
|
|
// If Qukeys is turned off, continue to next plugin
|
|
|
|
|
if (!active_)
|
|
|
|
@ -165,10 +185,15 @@ Key Qukeys::keyScanHook(Key mapped_key, byte row, byte col, uint8_t key_state) {
|
|
|
|
|
|
|
|
|
|
// If the key was just released:
|
|
|
|
|
if (keyToggledOff(key_state)) {
|
|
|
|
|
if (queue_index == QUKEY_NOT_FOUND)
|
|
|
|
|
// If the key isn't in the key_queue, proceed
|
|
|
|
|
if (queue_index == QUKEY_NOT_FOUND) {
|
|
|
|
|
// If a qukey that was not in the queue toggles off, reset its state
|
|
|
|
|
if (qukey_index != QUKEY_NOT_FOUND)
|
|
|
|
|
qukeys_[qukey_index].state = QUKEY_STATE_UNDETERMINED;
|
|
|
|
|
return mapped_key;
|
|
|
|
|
}
|
|
|
|
|
flushQueue(queue_index);
|
|
|
|
|
return mapped_key;
|
|
|
|
|
flushQueue(QUKEY_STATE_ALTERNATE, queue_index);
|
|
|
|
|
return Key_NoKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, the key is still pressed
|
|
|
|
@ -200,7 +225,7 @@ void Qukeys::preReportHook(void) {
|
|
|
|
|
uint32_t current_time = millis();
|
|
|
|
|
for (int8_t i = 0; i < key_queue_length_; i++) {
|
|
|
|
|
if (current_time > key_queue_[i].flush_time) {
|
|
|
|
|
flushKey(QUKEY_STATE_ALTERNATE);
|
|
|
|
|
flushKey(QUKEY_STATE_ALTERNATE, IS_PRESSED | WAS_PRESSED);
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|