From d08b486db0a060a4da3885cd46ed1489bb805598 Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Fri, 24 Nov 2023 10:00:53 -0800 Subject: [PATCH] Fix keyboard events occasionally being dropped AdbKeyboard would copy the event into its own fields and set the changed field, so that we could return the event when register was 0. However, if a subsequent event was received before ADB polling, the previous event would be overwritten and lost. Fix this by maintaining a queue of events, so that we can return everything since the last poll. --- devices/common/adb/adbkeyboard.cpp | 57 ++++++++++++++++-------------- devices/common/adb/adbkeyboard.h | 7 ++-- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/devices/common/adb/adbkeyboard.cpp b/devices/common/adb/adbkeyboard.cpp index 08706d7..3ef3a03 100644 --- a/devices/common/adb/adbkeyboard.cpp +++ b/devices/common/adb/adbkeyboard.cpp @@ -34,14 +34,7 @@ AdbKeyboard::AdbKeyboard(std::string name) : AdbDevice(name) { } void AdbKeyboard::event_handler(const KeyboardEvent& event) { - this->key = event.key; - if (event.flags & KEYBOARD_EVENT_DOWN) { - this->key_state = 0; - } - else if (event.flags & KEYBOARD_EVENT_UP) { - this->key_state = 1; - } - this->changed = true; + this->pending_events.push_back(std::make_unique(event)); } void AdbKeyboard::reset() { @@ -49,32 +42,42 @@ void AdbKeyboard::reset() { this->dev_handler_id = 2; // Extended ADB keyboard this->exc_event_flag = 1; this->srq_flag = 1; // enable service requests - this->key = 0; - this->key_state = 0; - this->changed = false; + this->pending_events.clear(); } bool AdbKeyboard::get_register_0() { - if (this->changed) { - uint8_t* out_buf = this->host_obj->get_output_buf(); + if (this->pending_events.empty()) { + return false; + } + uint8_t* out_buf = this->host_obj->get_output_buf(); + out_buf[0] = this->consume_pending_event(); + out_buf[1] = this->consume_pending_event(); + this->host_obj->set_output_count(2); + return true; +} - out_buf[0] = (this->key_state << 7) | (this->key & 0x7F); - // It's possible that we get two events before the host polls us, but - // in practice it has not come up. We need to set the key status bit to - // 1 (released), and the key to a non-existent one (0x7F). Otherwise if - // we leave it empty, the host will think that the 'a' key (code 0) is - // pressed. - out_buf[1] = 0xFF; +uint8_t AdbKeyboard::consume_pending_event() { + if (this->pending_events.empty()) { + // In most cases we have only on pending event when the host polls us, + // but we need to fill two entries of the output buffer. We need to set + // the key status bit to 1 (released), and the key to a non-existent + // one (0x7F). Otherwise if we leave it empty, the host will think that + // the 'a' key (code 0) is pressed (status 0). + return 0xFF; + } + std::unique_ptr event = std::move(this->pending_events.front()); + this->pending_events.pop_front(); - this->key = 0; - this->key_state = 0; - this->changed = false; - - this->host_obj->set_output_count(2); - return true; + uint8_t key_state = 0; + if (event->flags & KEYBOARD_EVENT_DOWN) { + key_state = 0; + } else if (event->flags & KEYBOARD_EVENT_UP) { + key_state = 1; + } else { + LOG_F(WARNING, "%s: unknown keyboard event flags %x", this->name.c_str(), event->flags); } - return false; + return (key_state << 7) | (event->key & 0x7F); } void AdbKeyboard::set_register_2() { diff --git a/devices/common/adb/adbkeyboard.h b/devices/common/adb/adbkeyboard.h index f0f5c8a..95a1913 100644 --- a/devices/common/adb/adbkeyboard.h +++ b/devices/common/adb/adbkeyboard.h @@ -27,6 +27,7 @@ along with this program. If not, see . #include #include +#include #include #include @@ -50,9 +51,9 @@ public: private: - uint32_t key = 0; - uint8_t key_state = 0; - bool changed = false; + std::deque> pending_events; + + uint8_t consume_pending_event(); }; // ADB Extended Keyboard raw key codes (most of which eventually became virtual