From e492b175f01cd4567930ba706adf6ac11f07f513 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sat, 7 Dec 2024 12:43:49 +0100 Subject: [PATCH] Define UHID vendorId and productId from the client Let the client choose the USB ids, that it transmits in UHID_CREATE requests. PR #5623 --- app/src/control_msg.c | 14 ++++++++++---- app/src/control_msg.h | 2 ++ app/src/uhid/gamepad_uhid.c | 5 +++++ app/src/uhid/keyboard_uhid.c | 2 ++ app/src/uhid/mouse_uhid.c | 2 ++ app/tests/test_control_msg_serialize.c | 6 +++++- .../genymobile/scrcpy/control/ControlMessage.java | 14 +++++++++++++- .../scrcpy/control/ControlMessageReader.java | 4 +++- .../com/genymobile/scrcpy/control/Controller.java | 2 +- .../com/genymobile/scrcpy/control/UhidManager.java | 10 +++++----- .../scrcpy/control/ControlMessageReaderTest.java | 4 ++++ 11 files changed, 52 insertions(+), 13 deletions(-) diff --git a/app/src/control_msg.c b/app/src/control_msg.c index 0defda9257..e78f0c573e 100644 --- a/app/src/control_msg.c +++ b/app/src/control_msg.c @@ -152,8 +152,10 @@ sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf) { return 2; case SC_CONTROL_MSG_TYPE_UHID_CREATE: sc_write16be(&buf[1], msg->uhid_create.id); + sc_write16be(&buf[3], msg->uhid_create.vendor_id); + sc_write16be(&buf[5], msg->uhid_create.product_id); - size_t index = 3; + size_t index = 7; index += write_string_tiny(&buf[index], msg->uhid_create.name, 127); sc_write16be(&buf[index], msg->uhid_create.report_desc_size); @@ -278,9 +280,13 @@ sc_control_msg_log(const struct sc_control_msg *msg) { // Quote only if name is not null const char *name = msg->uhid_create.name; const char *quote = name ? "\"" : ""; - LOG_CMSG("UHID create [%" PRIu16 "] name=%s%s%s " - "report_desc_size=%" PRIu16, msg->uhid_create.id, - quote, name, quote, msg->uhid_create.report_desc_size); + LOG_CMSG("UHID create [%" PRIu16 "] %04" PRIx16 ":%04" PRIx16 + " name=%s%s%s report_desc_size=%" PRIu16, + msg->uhid_create.id, + msg->uhid_create.vendor_id, + msg->uhid_create.product_id, + quote, name, quote, + msg->uhid_create.report_desc_size); break; } case SC_CONTROL_MSG_TYPE_UHID_INPUT: { diff --git a/app/src/control_msg.h b/app/src/control_msg.h index f0a2e37346..74dbcba800 100644 --- a/app/src/control_msg.h +++ b/app/src/control_msg.h @@ -94,6 +94,8 @@ struct sc_control_msg { } set_display_power; struct { uint16_t id; + uint16_t vendor_id; + uint16_t product_id; const char *name; // pointer to static data uint16_t report_desc_size; const uint8_t *report_desc; // pointer to static data diff --git a/app/src/uhid/gamepad_uhid.c b/app/src/uhid/gamepad_uhid.c index 42db63e75e..5b5744097c 100644 --- a/app/src/uhid/gamepad_uhid.c +++ b/app/src/uhid/gamepad_uhid.c @@ -7,6 +7,9 @@ /** Downcast gamepad processor to sc_gamepad_uhid */ #define DOWNCAST(GP) container_of(GP, struct sc_gamepad_uhid, gamepad_processor) +#define SC_GAMEPAD_UHID_VENDOR_ID 0 +#define SC_GAMEPAD_UHID_PRODUCT_ID 0 + static void sc_gamepad_uhid_send_input(struct sc_gamepad_uhid *gamepad, const struct sc_hid_input *hid_input, @@ -30,6 +33,8 @@ sc_gamepad_uhid_send_open(struct sc_gamepad_uhid *gamepad, struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.uhid_create.id = hid_open->hid_id; + msg.uhid_create.vendor_id = SC_GAMEPAD_UHID_VENDOR_ID; + msg.uhid_create.product_id = SC_GAMEPAD_UHID_PRODUCT_ID; msg.uhid_create.name = hid_open->name; msg.uhid_create.report_desc = hid_open->report_desc; msg.uhid_create.report_desc_size = hid_open->report_desc_size; diff --git a/app/src/uhid/keyboard_uhid.c b/app/src/uhid/keyboard_uhid.c index 496da23d79..4d2c978d23 100644 --- a/app/src/uhid/keyboard_uhid.c +++ b/app/src/uhid/keyboard_uhid.c @@ -141,6 +141,8 @@ sc_keyboard_uhid_init(struct sc_keyboard_uhid *kb, struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.uhid_create.id = SC_HID_ID_KEYBOARD; + msg.uhid_create.vendor_id = 0; + msg.uhid_create.product_id = 0; msg.uhid_create.name = hid_open.name; msg.uhid_create.report_desc = hid_open.report_desc; msg.uhid_create.report_desc_size = hid_open.report_desc_size; diff --git a/app/src/uhid/mouse_uhid.c b/app/src/uhid/mouse_uhid.c index 1dc02777bd..d6044bdcd2 100644 --- a/app/src/uhid/mouse_uhid.c +++ b/app/src/uhid/mouse_uhid.c @@ -81,6 +81,8 @@ sc_mouse_uhid_init(struct sc_mouse_uhid *mouse, struct sc_control_msg msg; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.uhid_create.id = SC_HID_ID_MOUSE; + msg.uhid_create.vendor_id = 0; + msg.uhid_create.product_id = 0; msg.uhid_create.name = hid_open.name; msg.uhid_create.report_desc = hid_open.report_desc; msg.uhid_create.report_desc_size = hid_open.report_desc_size; diff --git a/app/tests/test_control_msg_serialize.c b/app/tests/test_control_msg_serialize.c index 9adf2a3d7f..af97182d6b 100644 --- a/app/tests/test_control_msg_serialize.c +++ b/app/tests/test_control_msg_serialize.c @@ -329,6 +329,8 @@ static void test_serialize_uhid_create(void) { .type = SC_CONTROL_MSG_TYPE_UHID_CREATE, .uhid_create = { .id = 42, + .vendor_id = 0x1234, + .product_id = 0x5678, .name = "ABC", .report_desc_size = sizeof(report_desc), .report_desc = report_desc, @@ -337,11 +339,13 @@ static void test_serialize_uhid_create(void) { uint8_t buf[SC_CONTROL_MSG_MAX_SIZE]; size_t size = sc_control_msg_serialize(&msg, buf); - assert(size == 20); + assert(size == 24); const uint8_t expected[] = { SC_CONTROL_MSG_TYPE_UHID_CREATE, 0, 42, // id + 0x12, 0x34, // vendor id + 0x56, 0x78, // product id 3, // name size 65, 66, 67, // "ABC" 0, 11, // report desc size diff --git a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java index 7455cdf836..0eb96adcbc 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessage.java @@ -51,6 +51,8 @@ public final class ControlMessage { private int id; private byte[] data; private boolean on; + private int vendorId; + private int productId; private ControlMessage() { } @@ -131,10 +133,12 @@ public static ControlMessage createEmpty(int type) { return msg; } - public static ControlMessage createUhidCreate(int id, String name, byte[] reportDesc) { + public static ControlMessage createUhidCreate(int id, int vendorId, int productId, String name, byte[] reportDesc) { ControlMessage msg = new ControlMessage(); msg.type = TYPE_UHID_CREATE; msg.id = id; + msg.vendorId = vendorId; + msg.productId = productId; msg.text = name; msg.data = reportDesc; return msg; @@ -237,4 +241,12 @@ public byte[] getData() { public boolean getOn() { return on; } + + public int getVendorId() { + return vendorId; + } + + public int getProductId() { + return productId; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java index b82615ede8..e503ec615e 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/ControlMessageReader.java @@ -142,9 +142,11 @@ private ControlMessage parseSetDisplayPower() throws IOException { private ControlMessage parseUhidCreate() throws IOException { int id = dis.readUnsignedShort(); + int vendorId = dis.readUnsignedShort(); + int productId = dis.readUnsignedShort(); String name = parseString(1); byte[] data = parseByteArray(2); - return ControlMessage.createUhidCreate(id, name, data); + return ControlMessage.createUhidCreate(id, vendorId, productId, name, data); } private ControlMessage parseUhidInput() throws IOException { diff --git a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java index a0bdc58427..5e64a4c5b6 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -290,7 +290,7 @@ private boolean handleEvent() throws IOException { Device.rotateDevice(getActionDisplayId()); break; case ControlMessage.TYPE_UHID_CREATE: - getUhidManager().open(msg.getId(), msg.getText(), msg.getData()); + getUhidManager().open(msg.getId(), msg.getVendorId(), msg.getProductId(), msg.getText(), msg.getData()); break; case ControlMessage.TYPE_UHID_INPUT: getUhidManager().writeInput(msg.getId(), msg.getData()); diff --git a/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java b/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java index 8121adfcb7..1d7678ecba 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/UhidManager.java @@ -48,7 +48,7 @@ public UhidManager(DeviceMessageSender sender) { } } - public void open(int id, String name, byte[] reportDesc) throws IOException { + public void open(int id, int vendorId, int productId, String name, byte[] reportDesc) throws IOException { try { FileDescriptor fd = Os.open("/dev/uhid", OsConstants.O_RDWR, 0); try { @@ -58,7 +58,7 @@ public void open(int id, String name, byte[] reportDesc) throws IOException { close(old); } - byte[] req = buildUhidCreate2Req(name, reportDesc); + byte[] req = buildUhidCreate2Req(vendorId, productId, name, reportDesc); Os.write(fd, req, 0, req.length); registerUhidListener(id, fd); @@ -148,7 +148,7 @@ public void writeInput(int id, byte[] data) throws IOException { } } - private static byte[] buildUhidCreate2Req(String name, byte[] reportDesc) { + private static byte[] buildUhidCreate2Req(int vendorId, int productId, String name, byte[] reportDesc) { /* * struct uhid_event { * uint32_t type; @@ -183,8 +183,8 @@ private static byte[] buildUhidCreate2Req(String name, byte[] reportDesc) { buf.putShort((short) reportDesc.length); buf.putShort(BUS_VIRTUAL); - buf.putInt(0); // vendor id - buf.putInt(0); // product id + buf.putInt(vendorId); + buf.putInt(productId); buf.putInt(0); // version buf.putInt(0); // country; buf.put(reportDesc); diff --git a/server/src/test/java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java b/server/src/test/java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java index a25507b483..74df064f7d 100644 --- a/server/src/test/java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java +++ b/server/src/test/java/com/genymobile/scrcpy/control/ControlMessageReaderTest.java @@ -322,6 +322,8 @@ public void testParseUhidCreate() throws IOException { DataOutputStream dos = new DataOutputStream(bos); dos.writeByte(ControlMessage.TYPE_UHID_CREATE); dos.writeShort(42); // id + dos.writeShort(0x1234); // vendorId + dos.writeShort(0x5678); // productId dos.writeByte(3); // name size dos.write("ABC".getBytes(StandardCharsets.US_ASCII)); byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; @@ -335,6 +337,8 @@ public void testParseUhidCreate() throws IOException { ControlMessage event = reader.read(); Assert.assertEquals(ControlMessage.TYPE_UHID_CREATE, event.getType()); Assert.assertEquals(42, event.getId()); + Assert.assertEquals(0x1234, event.getVendorId()); + Assert.assertEquals(0x5678, event.getProductId()); Assert.assertEquals("ABC", event.getText()); Assert.assertArrayEquals(data, event.getData());