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.
This commit is contained in:
Mihai Parparita 2023-11-24 10:00:53 -08:00
parent d37d83c5b6
commit d08b486db0
2 changed files with 34 additions and 30 deletions

View File

@ -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<KeyboardEvent>(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<KeyboardEvent> 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() {

View File

@ -27,6 +27,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <devices/common/adb/adbdevice.h>
#include <devices/common/hwcomponent.h>
#include <deque>
#include <memory>
#include <string>
@ -50,9 +51,9 @@ public:
private:
uint32_t key = 0;
uint8_t key_state = 0;
bool changed = false;
std::deque<std::unique_ptr<KeyboardEvent>> pending_events;
uint8_t consume_pending_event();
};
// ADB Extended Keyboard raw key codes (most of which eventually became virtual