From e4163321f00bb3830c6049bdb6c1515e7cc668a0 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 21 Oct 2021 21:33:15 +0200 Subject: [PATCH] Delay HID events on Ctrl+v When Ctrl+v is pressed, a control is sent to the device to set the device clipboard before injecting Ctrl+v. With the InputManager method, it is guaranteed that the device synchronization is executed before handling Ctrl+v, since the commands are executed on the device in sequence. However, HID are injected from the computer, so there is no such guarantee. As a consequence, on Android, Ctrl+v triggers a paste with the old clipboard content. To workaround the issue, wait a bit (2 milliseconds) from the AOA thread before injecting the event, to leave enough time for the clipboard to be set before injecting Ctrl+v. --- app/src/aoa_hid.c | 17 +++++++++++++++++ app/src/aoa_hid.h | 2 ++ app/src/hid_keyboard.c | 13 +++++++++++++ 3 files changed, 32 insertions(+) diff --git a/app/src/aoa_hid.c b/app/src/aoa_hid.c index 7fc0f34c..4c0b2bda 100644 --- a/app/src/aoa_hid.c +++ b/app/src/aoa_hid.c @@ -35,6 +35,7 @@ sc_hid_event_init(struct sc_hid_event *hid_event, uint16_t accessory_id, hid_event->accessory_id = accessory_id; hid_event->buffer = buffer; hid_event->size = buffer_size; + hid_event->delay = 0; } void @@ -330,6 +331,22 @@ run_aoa_thread(void *data) { bool non_empty = cbuf_take(&aoa->queue, &event); assert(non_empty); (void) non_empty; + + assert(event.delay >= 0); + if (event.delay) { + // Wait during the specified delay before injecting the HID event + sc_tick deadline = sc_tick_now() + event.delay; + bool timed_out = false; + while (!aoa->stopped && !timed_out) { + timed_out = !sc_cond_timedwait(&aoa->event_cond, &aoa->mutex, + deadline); + } + if (aoa->stopped) { + sc_mutex_unlock(&aoa->mutex); + break; + } + } + sc_mutex_unlock(&aoa->mutex); bool ok = sc_aoa_send_hid_event(aoa, &event); diff --git a/app/src/aoa_hid.h b/app/src/aoa_hid.h index 11b879ce..11cc57b8 100644 --- a/app/src/aoa_hid.h +++ b/app/src/aoa_hid.h @@ -9,11 +9,13 @@ #include "scrcpy.h" #include "util/cbuf.h" #include "util/thread.h" +#include "util/tick.h" struct sc_hid_event { uint16_t accessory_id; unsigned char *buffer; uint16_t size; + sc_tick delay; }; // Takes ownership of buffer diff --git a/app/src/hid_keyboard.c b/app/src/hid_keyboard.c index 425516af..c6fba21c 100644 --- a/app/src/hid_keyboard.c +++ b/app/src/hid_keyboard.c @@ -297,6 +297,19 @@ sc_key_processor_process_key(struct sc_key_processor *kp, kb->mod_lock_synchronized = true; } } + + SDL_Keycode keycode = event->keysym.sym; + bool down = event->type == SDL_KEYDOWN; + bool ctrl = event->keysym.mod & KMOD_CTRL; + bool shift = event->keysym.mod & KMOD_SHIFT; + if (ctrl && !shift && keycode == SDLK_v && down) { + // Ctrl+v is pressed, so clipboard synchronization has been + // requested. Wait a bit so that the clipboard is set before + // injecting Ctrl+v via HID, otherwise it would paste the old + // clipboard content. + hid_event.delay = SC_TICK_FROM_MS(2); + } + if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) { sc_hid_event_destroy(&hid_event); LOGW("Could request HID event");