Skip to content

Commit

Permalink
Fix keyboard events occasionally being dropped
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mihaip committed Nov 24, 2023
1 parent d37d83c commit d08b486
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 32 deletions.
61 changes: 32 additions & 29 deletions devices/common/adb/adbkeyboard.cpp
Expand Up @@ -34,47 +34,50 @@ 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() {
this->my_addr = ADB_ADDR_KBD;
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();

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;

this->key = 0;
this->key_state = 0;
this->changed = false;

this->host_obj->set_output_count(2);
return true;
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;
}

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();

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() {
Expand Down
7 changes: 4 additions & 3 deletions devices/common/adb/adbkeyboard.h
Expand Up @@ -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>

Expand All @@ -50,9 +51,9 @@ class AdbKeyboard : public AdbDevice {


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
Expand Down

0 comments on commit d08b486

Please sign in to comment.