Simplify UHID outputs routing

There was a registration mechanism to listen to HID outputs with a
specific HID id.

However, the UHID gamepad processor handles several ids, so it cannot
work. We could complexify the registration mechanism, but instead,
directly dispatch to the expected processor based on the UHID id.

Concretely, instead of passing a sc_uhid_devices instance to construct a
sc_keyboard_uhid, so that it can register itself, construct the
sc_uhid_devices with all the UHID instances (currently only
sc_keyboard_uhid) so that it can dispatch HID outputs directly.

PR #5270 <https://github.com/Genymobile/scrcpy/pull/5270>
This commit is contained in:
Romain Vimont 2024-09-06 23:08:08 +02:00
parent 7f250dd669
commit bf2b679e70
6 changed files with 45 additions and 72 deletions

View File

@ -67,14 +67,8 @@ task_uhid_output(void *userdata) {
struct sc_uhid_output_task_data *data = userdata; struct sc_uhid_output_task_data *data = userdata;
struct sc_uhid_receiver *uhid_receiver = sc_uhid_devices_process_hid_output(data->uhid_devices, data->id, data->data,
sc_uhid_devices_get_receiver(data->uhid_devices, data->id);
if (uhid_receiver) {
uhid_receiver->ops->process_output(uhid_receiver, data->data,
data->size); data->size);
} else {
LOGW("No UHID receiver for id %" PRIu16, data->id);
}
free(data->data); free(data->data);
free(data); free(data);

View File

@ -402,7 +402,6 @@ scrcpy(struct scrcpy_options *options) {
bool timeout_started = false; bool timeout_started = false;
struct sc_acksync *acksync = NULL; struct sc_acksync *acksync = NULL;
struct sc_uhid_devices *uhid_devices = NULL;
uint32_t scid = scrcpy_generate_scid(); uint32_t scid = scrcpy_generate_scid();
@ -725,6 +724,8 @@ aoa_complete:
assert(options->mouse_input_mode != SC_MOUSE_INPUT_MODE_AOA); assert(options->mouse_input_mode != SC_MOUSE_INPUT_MODE_AOA);
#endif #endif
struct sc_keyboard_uhid *uhid_keyboard = NULL;
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_SDK) { if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_SDK) {
sc_keyboard_sdk_init(&s->keyboard_sdk, &s->controller, sc_keyboard_sdk_init(&s->keyboard_sdk, &s->controller,
options->key_inject_mode, options->key_inject_mode,
@ -732,14 +733,12 @@ aoa_complete:
kp = &s->keyboard_sdk.key_processor; kp = &s->keyboard_sdk.key_processor;
} else if (options->keyboard_input_mode } else if (options->keyboard_input_mode
== SC_KEYBOARD_INPUT_MODE_UHID) { == SC_KEYBOARD_INPUT_MODE_UHID) {
sc_uhid_devices_init(&s->uhid_devices); bool ok = sc_keyboard_uhid_init(&s->keyboard_uhid, &s->controller);
bool ok = sc_keyboard_uhid_init(&s->keyboard_uhid, &s->controller,
&s->uhid_devices);
if (!ok) { if (!ok) {
goto end; goto end;
} }
uhid_devices = &s->uhid_devices;
kp = &s->keyboard_uhid.key_processor; kp = &s->keyboard_uhid.key_processor;
uhid_keyboard = &s->keyboard_uhid;
} }
if (options->mouse_input_mode == SC_MOUSE_INPUT_MODE_SDK) { if (options->mouse_input_mode == SC_MOUSE_INPUT_MODE_SDK) {
@ -759,6 +758,12 @@ aoa_complete:
gp = &s->gamepad_uhid.gamepad_processor; gp = &s->gamepad_uhid.gamepad_processor;
} }
struct sc_uhid_devices *uhid_devices = NULL;
if (uhid_keyboard) {
sc_uhid_devices_init(&s->uhid_devices, uhid_keyboard);
uhid_devices = &s->uhid_devices;
}
sc_controller_configure(&s->controller, acksync, uhid_devices); sc_controller_configure(&s->controller, acksync, uhid_devices);
if (!sc_controller_start(&s->controller)) { if (!sc_controller_start(&s->controller)) {

View File

@ -95,21 +95,19 @@ sc_keyboard_uhid_to_sc_mod(uint8_t hid_led) {
return mod; return mod;
} }
static void void
sc_uhid_receiver_process_output(struct sc_uhid_receiver *receiver, sc_keyboard_uhid_process_hid_output(struct sc_keyboard_uhid *kb,
const uint8_t *data, size_t len) { const uint8_t *data, size_t size) {
assert(sc_thread_get_id() == SC_MAIN_THREAD_ID); assert(sc_thread_get_id() == SC_MAIN_THREAD_ID);
assert(len); assert(size);
// Also check at runtime (do not trust the server) // Also check at runtime (do not trust the server)
if (!len) { if (!size) {
LOGE("Unexpected empty HID output message"); LOGE("Unexpected empty HID output message");
return; return;
} }
struct sc_keyboard_uhid *kb = DOWNCAST_RECEIVER(receiver);
uint8_t hid_led = data[0]; uint8_t hid_led = data[0];
uint16_t device_mod = sc_keyboard_uhid_to_sc_mod(hid_led); uint16_t device_mod = sc_keyboard_uhid_to_sc_mod(hid_led);
kb->device_mod = device_mod; kb->device_mod = device_mod;
@ -117,8 +115,7 @@ sc_uhid_receiver_process_output(struct sc_uhid_receiver *receiver,
bool bool
sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb, sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
struct sc_controller *controller, struct sc_controller *controller) {
struct sc_uhid_devices *uhid_devices) {
sc_hid_keyboard_init(&kb->hid); sc_hid_keyboard_init(&kb->hid);
kb->controller = controller; kb->controller = controller;
@ -137,14 +134,6 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
kb->key_processor.hid = true; kb->key_processor.hid = true;
kb->key_processor.ops = &ops; kb->key_processor.ops = &ops;
static const struct sc_uhid_receiver_ops uhid_receiver_ops = {
.process_output = sc_uhid_receiver_process_output,
};
kb->uhid_receiver.id = SC_HID_ID_KEYBOARD;
kb->uhid_receiver.ops = &uhid_receiver_ops;
sc_uhid_devices_add_receiver(uhid_devices, &kb->uhid_receiver);
struct sc_hid_open hid_open; struct sc_hid_open hid_open;
sc_hid_keyboard_generate_open(&hid_open); sc_hid_keyboard_generate_open(&hid_open);
assert(hid_open.hid_id == SC_HID_ID_KEYBOARD); assert(hid_open.hid_id == SC_HID_ID_KEYBOARD);

View File

@ -7,12 +7,10 @@
#include "controller.h" #include "controller.h"
#include "hid/hid_keyboard.h" #include "hid/hid_keyboard.h"
#include "uhid/uhid_output.h"
#include "trait/key_processor.h" #include "trait/key_processor.h"
struct sc_keyboard_uhid { struct sc_keyboard_uhid {
struct sc_key_processor key_processor; // key processor trait struct sc_key_processor key_processor; // key processor trait
struct sc_uhid_receiver uhid_receiver;
struct sc_hid_keyboard hid; struct sc_hid_keyboard hid;
struct sc_controller *controller; struct sc_controller *controller;
@ -21,7 +19,10 @@ struct sc_keyboard_uhid {
bool bool
sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb, sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb,
struct sc_controller *controller, struct sc_controller *controller);
struct sc_uhid_devices *uhid_devices);
void
sc_keyboard_uhid_process_hid_output(struct sc_keyboard_uhid *kb,
const uint8_t *data, size_t size);
#endif #endif

View File

@ -1,25 +1,27 @@
#include "uhid_output.h" #include "uhid_output.h"
#include <assert.h> #include <assert.h>
#include <inttypes.h>
#include "uhid/keyboard_uhid.h"
#include "util/log.h"
void void
sc_uhid_devices_init(struct sc_uhid_devices *devices) { sc_uhid_devices_init(struct sc_uhid_devices *devices,
devices->count = 0; struct sc_keyboard_uhid *keyboard) {
devices->keyboard = keyboard;
} }
void void
sc_uhid_devices_add_receiver(struct sc_uhid_devices *devices, sc_uhid_devices_process_hid_output(struct sc_uhid_devices *devices, uint16_t id,
struct sc_uhid_receiver *receiver) { const uint8_t *data, size_t size) {
assert(devices->count < SC_UHID_MAX_RECEIVERS); if (id == SC_HID_ID_KEYBOARD) {
devices->receivers[devices->count++] = receiver; if (devices->keyboard) {
} sc_keyboard_uhid_process_hid_output(devices->keyboard, data, size);
} else {
struct sc_uhid_receiver * LOGW("Unexpected keyboard HID output without UHID keyboard");
sc_uhid_devices_get_receiver(struct sc_uhid_devices *devices, uint16_t id) {
for (size_t i = 0; i < devices->count; ++i) {
if (devices->receivers[i]->id == id) {
return devices->receivers[i];
} }
} else {
LOGW("HID output ignored for id %" PRIu16, id);
} }
return NULL;
} }

View File

@ -9,37 +9,19 @@
/** /**
* The communication with UHID devices is bidirectional. * The communication with UHID devices is bidirectional.
* *
* This component manages the registration of receivers to handle UHID output * This component dispatches HID outputs to the expected processor.
* messages (sent from the device to the computer).
*/ */
struct sc_uhid_receiver {
uint16_t id;
const struct sc_uhid_receiver_ops *ops;
};
struct sc_uhid_receiver_ops {
void
(*process_output)(struct sc_uhid_receiver *receiver,
const uint8_t *data, size_t len);
};
#define SC_UHID_MAX_RECEIVERS 1
struct sc_uhid_devices { struct sc_uhid_devices {
struct sc_uhid_receiver *receivers[SC_UHID_MAX_RECEIVERS]; struct sc_keyboard_uhid *keyboard;
unsigned count;
}; };
void void
sc_uhid_devices_init(struct sc_uhid_devices *devices); sc_uhid_devices_init(struct sc_uhid_devices *devices,
struct sc_keyboard_uhid *keyboard);
void void
sc_uhid_devices_add_receiver(struct sc_uhid_devices *devices, sc_uhid_devices_process_hid_output(struct sc_uhid_devices *devices, uint16_t id,
struct sc_uhid_receiver *receiver); const uint8_t *data, size_t size);
struct sc_uhid_receiver *
sc_uhid_devices_get_receiver(struct sc_uhid_devices *devices, uint16_t id);
#endif #endif