From 32a8537c282e253891ace1637dbc967f53181018 Mon Sep 17 00:00:00 2001 From: Michael Richters Date: Sat, 17 Mar 2018 23:39:26 -0500 Subject: [PATCH] Added a configurable release delay on qukey release When releasing a qukey, allow a short timeout in case a subsequent key was released effectively simultaneously, treating that near-simultaneous release as intended to use the alternate (i.e. modifier) keycode. --- src/Kaleidoscope/Qukeys.cpp | 47 ++++++++++++++++++++++++++++++------- src/Kaleidoscope/Qukeys.h | 5 ++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/Kaleidoscope/Qukeys.cpp b/src/Kaleidoscope/Qukeys.cpp index b2d04c3b..517c802c 100644 --- a/src/Kaleidoscope/Qukeys.cpp +++ b/src/Kaleidoscope/Qukeys.cpp @@ -85,11 +85,14 @@ uint8_t Qukeys::qukeys_count = 0; bool Qukeys::active_ = true; uint16_t Qukeys::time_limit_ = 250; +uint8_t Qukeys::release_delay_ = 0; QueueItem Qukeys::key_queue_[] = {}; uint8_t Qukeys::key_queue_length_ = 0; byte Qukeys::qukey_state_[] = {}; bool Qukeys::flushing_queue_ = false; +constexpr uint16_t QUKEYS_RELEASE_DELAY_OFFSET = 4096; + // Empty constructor; nothing is stored at the instance level Qukeys::Qukeys(void) {} @@ -116,7 +119,7 @@ void Qukeys::enqueue(uint8_t key_addr) { flushQueue(); } key_queue_[key_queue_length_].addr = key_addr; - key_queue_[key_queue_length_].start_time = (uint16_t)millis(); + key_queue_[key_queue_length_].start_time = millis(); key_queue_length_++; addr::mask(key_addr); } @@ -175,7 +178,7 @@ void Qukeys::flushKey(bool qukey_state, uint8_t keyswitch_state) { memcpy(Keyboard.keyReport.allkeys, hid_report.allkeys, sizeof(hid_report)); // Last, if the key is still down, add its code back in - if (keyswitch_state | IS_PRESSED) + if (keyswitch_state & IS_PRESSED) handleKeyswitchEvent(keycode, row, col, IS_PRESSED | WAS_PRESSED); // Now that we're done sending the report(s), Qukeys can process events again: @@ -197,22 +200,29 @@ void Qukeys::flushQueue(int8_t index) { return; for (int8_t i = 0; i < index; i++) { if (key_queue_length_ == 0) - break; + return; flushKey(QUKEY_STATE_ALTERNATE, IS_PRESSED | WAS_PRESSED); } - flushKey(QUKEY_STATE_PRIMARY, WAS_PRESSED); + if (isQukey(key_queue_[0].addr)) { + flushKey(QUKEY_STATE_PRIMARY, IS_PRESSED | WAS_PRESSED); + } else { + flushKey(QUKEY_STATE_PRIMARY, WAS_PRESSED); + } } // Flush all the non-qukey keys from the front of the queue void Qukeys::flushQueue() { // flush keys until we find a qukey: - while (key_queue_length_ > 0 && - ! isDualUse(key_queue_[0].addr) && - lookupQukey(key_queue_[0].addr) == QUKEY_NOT_FOUND) { + while (key_queue_length_ > 0 && !isQukey(key_queue_[0].addr)) { flushKey(QUKEY_STATE_PRIMARY, IS_PRESSED | WAS_PRESSED); } } +inline +bool Qukeys::isQukey(uint8_t addr) { + return (isDualUse(addr) || lookupQukey(addr) != QUKEY_NOT_FOUND); +} + Key Qukeys::keyScanHook(Key mapped_key, byte row, byte col, uint8_t key_state) { // If key_addr is not a physical key, ignore it; some other plugin injected it @@ -279,6 +289,14 @@ Key Qukeys::keyScanHook(Key mapped_key, byte row, byte col, uint8_t key_state) { } return mapped_key; } + // If there's a release delay in effect, the released key is a qukey, and there's at + // least one key after it in the queue, delay this key's release event: + if (release_delay_ > 0 && + isQukey(key_addr) && + queue_index < (key_queue_length_ - 1)) { + key_queue_[queue_index].start_time = millis() + QUKEYS_RELEASE_DELAY_OFFSET; + return Key_NoKey; + } flushQueue(queue_index); flushQueue(); return Key_NoKey; @@ -314,10 +332,23 @@ Key Qukeys::keyScanHook(Key mapped_key, byte row, byte col, uint8_t key_state) { } void Qukeys::preReportHook(void) { + + uint16_t current_time = millis(); + + if (release_delay_ > 0) { + int16_t diff_time = key_queue_[0].start_time - current_time; + if (diff_time > 0) { + int16_t delay_window = QUKEYS_RELEASE_DELAY_OFFSET - release_delay_; + if (diff_time < delay_window) { + flushKey(QUKEY_STATE_ALTERNATE, WAS_PRESSED); + flushQueue(); + } + } + } + // If the qukey has been held longer than the time limit, set its // state to the alternate keycode and add it to the report while (key_queue_length_ > 0) { - uint16_t current_time = millis(); if ((current_time - key_queue_[0].start_time) > time_limit_) { flushKey(QUKEY_STATE_ALTERNATE, IS_PRESSED | WAS_PRESSED); flushQueue(); diff --git a/src/Kaleidoscope/Qukeys.h b/src/Kaleidoscope/Qukeys.h index 4d718d97..6e654cd5 100644 --- a/src/Kaleidoscope/Qukeys.h +++ b/src/Kaleidoscope/Qukeys.h @@ -94,6 +94,9 @@ class Qukeys : public KaleidoscopePlugin { static void setTimeout(uint16_t time_limit) { time_limit_ = time_limit; } + static void setReleaseDelay(uint8_t release_delay) { + release_delay_ = release_delay; + } static Qukey * qukeys; static uint8_t qukeys_count; @@ -101,6 +104,7 @@ class Qukeys : public KaleidoscopePlugin { private: static bool active_; static uint16_t time_limit_; + static uint8_t release_delay_; static QueueItem key_queue_[QUKEYS_QUEUE_MAX]; static uint8_t key_queue_length_; static bool flushing_queue_; @@ -120,6 +124,7 @@ class Qukeys : public KaleidoscopePlugin { static void flushKey(bool qukey_state, uint8_t keyswitch_state); static void flushQueue(int8_t index); static void flushQueue(void); + static bool isQukey(uint8_t addr); static Key keyScanHook(Key mapped_key, byte row, byte col, uint8_t key_state); static void preReportHook(void);