Compare commits

...

5 Commits

Author SHA1 Message Date
Romain Vimont
309d0371eb Define UHID vendorId and productId from the client
Let the client choose the USB ids, that it transmits in UHID_CREATE
requests.
2024-12-07 15:01:26 +01:00
Romain Vimont
a582c0cc1b Split gamepad device added/removed events
Use two separate event structs for gamepad device added and gamepad
device removed.

In theory, some data (like vendorId and productId) could be added
specifically to "device added" events.
2024-12-07 15:00:40 +01:00
Romain Vimont
696295f66d Fix gamepad axis initial value
By default, initialize axis to 0, which is represented by 0x8000 as a
16-bit unsigned value.
2024-12-07 15:00:40 +01:00
Romain Vimont
347169aab6 Fix gamepad HID descriptor
Use Z and Rz for L2/R2, which are more widely supported than
Brake/Accelerator.

The right stick must then be bound to Rx and Ry.
2024-12-06 12:53:28 +01:00
Romain Vimont
75bdd0c831 Fix HID gamepad comments 2024-12-06 12:53:07 +01:00
20 changed files with 171 additions and 119 deletions

View File

@ -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: {

View File

@ -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

View File

@ -15,6 +15,8 @@ struct sc_hid_input {
struct sc_hid_open {
uint16_t hid_id;
uint16_t vendor_id;
uint16_t product_id;
const char *name; // pointer to static memory
const uint8_t *report_desc; // pointer to static memory
size_t report_desc_size;

View File

@ -52,10 +52,10 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
0x09, 0x30,
// Usage (Y) Left stick y
0x09, 0x31,
// Usage (Z) Right stick x
0x09, 0x32,
// Usage (Rz) Right stick y
0x09, 0x35,
// Usage (Rx) Right stick x
0x09, 0x33,
// Usage (Ry) Right stick y
0x09, 0x34,
// Logical Minimum (0)
0x15, 0x00,
// Logical Maximum (65535)
@ -65,15 +65,15 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
0x75, 0x10,
// Report Count (4)
0x95, 0x04,
// Input (Data, Variable, Absolute): 4 bytes (X, Y, Z, Rz)
// Input (Data, Variable, Absolute): 4x2 bytes (X, Y, Z, Rz)
0x81, 0x02,
// Usage Page (Simulation Controls)
0x05, 0x02,
// Usage (Brake)
0x09, 0xC5,
// Usage (Accelerator)
0x09, 0xC4,
// Usage Page (Generic Desktop)
0x05, 0x01,
// Usage (Z)
0x09, 0x32,
// Usage (Rz)
0x09, 0x35,
// Logical Minimum (0)
0x15, 0x00,
// Logical Maximum (32767)
@ -82,7 +82,7 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
0x75, 0x10,
// Report Count (2)
0x95, 0x02,
// Input (Data, Variable, Absolute): 2 bytes (L2, R2)
// Input (Data, Variable, Absolute): 2x2 bytes (L2, R2)
0x81, 0x02,
// Usage Page (Buttons)
@ -182,7 +182,7 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
* `------------- SC_GAMEPAD_BUTTON_RIGHT_STICK
*
* +---------------+
* byte 14: |0 0 0 . . . . .| hat switch (dpad) position (0-8)
* byte 14: |0 0 0 0 . . . .| hat switch (dpad) position (0-8)
* +---------------+
* 9 possible positions and their values:
* 8 1 2
@ -191,16 +191,19 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
* (8 is top-left, 1 is top, 2 is top-right, etc.)
*/
// [-32768 to 32767] -> [0 to 65535]
#define AXIS_RESCALE(V) (uint16_t) (((int32_t) V) + 0x8000)
static void
sc_hid_gamepad_slot_init(struct sc_hid_gamepad_slot *slot,
uint32_t gamepad_id) {
assert(gamepad_id != SC_GAMEPAD_ID_INVALID);
slot->gamepad_id = gamepad_id;
slot->buttons = 0;
slot->axis_left_x = 0;
slot->axis_left_y = 0;
slot->axis_right_x = 0;
slot->axis_right_y = 0;
slot->axis_left_x = AXIS_RESCALE(0);
slot->axis_left_y = AXIS_RESCALE(0);
slot->axis_right_x = AXIS_RESCALE(0);
slot->axis_right_y = AXIS_RESCALE(0);
slot->axis_left_trigger = 0;
slot->axis_right_trigger = 0;
}
@ -233,7 +236,9 @@ sc_hid_gamepad_slot_get_id(size_t slot_idx) {
bool
sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
struct sc_hid_open *hid_open,
uint32_t gamepad_id) {
uint32_t gamepad_id,
uint16_t vendor_id,
uint16_t product_id) {
assert(gamepad_id != SC_GAMEPAD_ID_INVALID);
ssize_t slot_idx = sc_hid_gamepad_slot_find(hid, SC_GAMEPAD_ID_INVALID);
if (slot_idx == -1) {
@ -250,6 +255,8 @@ sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
uint16_t hid_id = sc_hid_gamepad_slot_get_id(slot_idx);
hid_open->hid_id = hid_id;
hid_open->vendor_id = vendor_id;
hid_open->product_id = product_id;
hid_open->name = name;
hid_open->report_desc = SC_HID_GAMEPAD_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_GAMEPAD_REPORT_DESC);
@ -423,8 +430,6 @@ sc_hid_gamepad_generate_input_from_axis(struct sc_hid_gamepad *hid,
struct sc_hid_gamepad_slot *slot = &hid->slots[slot_idx];
// [-32768 to 32767] -> [0 to 65535]
#define AXIS_RESCALE(V) (uint16_t) (((int32_t) V) + 0x8000)
switch (event->axis) {
case SC_GAMEPAD_AXIS_LEFTX:
slot->axis_left_x = AXIS_RESCALE(event->value);

View File

@ -33,7 +33,9 @@ sc_hid_gamepad_init(struct sc_hid_gamepad *hid);
bool
sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
struct sc_hid_open *hid_open,
uint32_t gamepad_id);
uint32_t gamepad_id,
uint16_t vendor_id,
uint16_t product_id);
bool
sc_hid_gamepad_generate_close(struct sc_hid_gamepad *hid,

View File

@ -335,6 +335,8 @@ sc_hid_keyboard_generate_input_from_mods(struct sc_hid_input *hid_input,
void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_KEYBOARD;
hid_open->vendor_id = 0;
hid_open->product_id = 0;
hid_open->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_KEYBOARD_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_KEYBOARD_REPORT_DESC);

View File

@ -190,6 +190,8 @@ sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input,
void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_MOUSE;
hid_open->vendor_id = 0;
hid_open->product_id = 0;
hid_open->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_MOUSE_REPORT_DESC;
hid_open->report_desc_size = sizeof(SC_HID_MOUSE_REPORT_DESC);

View File

@ -412,18 +412,16 @@ struct sc_touch_event {
float pressure;
};
enum sc_gamepad_device_event_type {
SC_GAMEPAD_DEVICE_ADDED,
SC_GAMEPAD_DEVICE_REMOVED,
};
// As documented in <https://wiki.libsdl.org/SDL2/SDL_JoystickID>:
// The ID value starts at 0 and increments from there. The value -1 is an
// invalid ID.
#define SC_GAMEPAD_ID_INVALID UINT32_C(-1)
struct sc_gamepad_device_event {
enum sc_gamepad_device_event_type type;
struct sc_gamepad_added_event {
uint32_t gamepad_id;
};
struct sc_gamepad_removed_event {
uint32_t gamepad_id;
};
@ -503,16 +501,6 @@ sc_mouse_buttons_state_from_sdl(uint32_t buttons_state) {
return buttons_state;
}
static inline enum sc_gamepad_device_event_type
sc_gamepad_device_event_type_from_sdl_type(uint32_t type) {
assert(type == SDL_CONTROLLERDEVICEADDED
|| type == SDL_CONTROLLERDEVICEREMOVED);
if (type == SDL_CONTROLLERDEVICEADDED) {
return SC_GAMEPAD_DEVICE_ADDED;
}
return SC_GAMEPAD_DEVICE_REMOVED;
}
static inline enum sc_gamepad_axis
sc_gamepad_axis_from_sdl(uint8_t axis) {
if (axis <= SDL_CONTROLLER_AXIS_TRIGGERRIGHT) {

View File

@ -908,7 +908,6 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
static void
sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
const SDL_ControllerDeviceEvent *event) {
SDL_JoystickID id;
if (event->type == SDL_CONTROLLERDEVICEADDED) {
SDL_GameController *gc = SDL_GameControllerOpen(event->which);
if (!gc) {
@ -923,9 +922,12 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
return;
}
id = SDL_JoystickInstanceID(joystick);
struct sc_gamepad_added_event evt = {
.gamepad_id = SDL_JoystickInstanceID(joystick),
};
im->gp->ops->process_gamepad_added(im->gp, &evt);
} else if (event->type == SDL_CONTROLLERDEVICEREMOVED) {
id = event->which;
SDL_JoystickID id = event->which;
SDL_GameController *gc = SDL_GameControllerFromInstanceID(id);
if (gc) {
@ -933,16 +935,15 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
} else {
LOGW("Unknown gamepad device removed");
}
struct sc_gamepad_removed_event evt = {
.gamepad_id = id,
};
im->gp->ops->process_gamepad_removed(im->gp, &evt);
} else {
// Nothing to do
return;
}
struct sc_gamepad_device_event evt = {
.type = sc_gamepad_device_event_type_from_sdl_type(event->type),
.gamepad_id = id,
};
im->gp->ops->process_gamepad_device(im->gp, &evt);
}
static void

View File

@ -20,13 +20,22 @@ struct sc_gamepad_processor {
struct sc_gamepad_processor_ops {
/**
* Process a gamepad device added or removed
* Process a gamepad device added
*
* This function is mandatory.
*/
void
(*process_gamepad_device)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event);
(*process_gamepad_added)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_added_event *event);
/**
* Process a gamepad device removed
*
* This function is mandatory.
*/
void
(*process_gamepad_removed)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_removed_event *event);
/**
* Process a gamepad axis event

View File

@ -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 = hid_open->vendor_id;
msg.uhid_create.product_id = hid_open->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;
@ -52,29 +57,33 @@ sc_gamepad_uhid_send_close(struct sc_gamepad_uhid *gamepad,
}
static void
sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) {
sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
const struct sc_gamepad_added_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
if (event->type == SC_GAMEPAD_DEVICE_ADDED) {
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) {
return;
}
sc_gamepad_uhid_send_open(gamepad, &hid_open);
} else {
assert(event->type == SC_GAMEPAD_DEVICE_REMOVED);
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
sc_gamepad_uhid_send_close(gamepad, &hid_close);
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id,
SC_GAMEPAD_UHID_VENDOR_ID,
SC_GAMEPAD_UHID_PRODUCT_ID)) {
return;
}
sc_gamepad_uhid_send_open(gamepad, &hid_open);
}
static void
sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
const struct sc_gamepad_removed_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
sc_gamepad_uhid_send_close(gamepad, &hid_close);
}
static void
@ -114,7 +123,8 @@ sc_gamepad_uhid_init(struct sc_gamepad_uhid *gamepad,
gamepad->controller = controller;
static const struct sc_gamepad_processor_ops ops = {
.process_gamepad_device = sc_gamepad_processor_process_gamepad_device,
.process_gamepad_added = sc_gamepad_processor_process_gamepad_added,
.process_gamepad_removed = sc_gamepad_processor_process_gamepad_removed,
.process_gamepad_axis = sc_gamepad_processor_process_gamepad_axis,
.process_gamepad_button = sc_gamepad_processor_process_gamepad_button,
};

View File

@ -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 = hid_open.vendor_id;
msg.uhid_create.product_id = hid_open.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;

View File

@ -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 = hid_open.vendor_id;
msg.uhid_create.product_id = hid_open.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;

View File

@ -7,33 +7,35 @@
#define DOWNCAST(GP) container_of(GP, struct sc_gamepad_aoa, gamepad_processor)
static void
sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) {
sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
const struct sc_gamepad_added_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
if (event->type == SC_GAMEPAD_DEVICE_ADDED) {
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) {
return;
}
struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id, 0, 0)) {
return;
}
// exit_on_error: false (a gamepad open failure should not exit scrcpy)
if (!sc_aoa_push_open(gamepad->aoa, &hid_open, false)) {
LOGW("Could not push AOA HID open (gamepad)");
}
} else {
assert(event->type == SC_GAMEPAD_DEVICE_REMOVED);
// exit_on_error: false (a gamepad open failure should not exit scrcpy)
if (!sc_aoa_push_open(gamepad->aoa, &hid_open, false)) {
LOGW("Could not push AOA HID open (gamepad)");
}
}
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
static void
sc_gamepad_processor_process_gamepad_removed(struct sc_gamepad_processor *gp,
const struct sc_gamepad_removed_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
if (!sc_aoa_push_close(gamepad->aoa, &hid_close)) {
LOGW("Could not push AOA HID close (gamepad)");
}
struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
event->gamepad_id)) {
return;
}
if (!sc_aoa_push_close(gamepad->aoa, &hid_close)) {
LOGW("Could not push AOA HID close (gamepad)");
}
}
@ -76,7 +78,8 @@ sc_gamepad_aoa_init(struct sc_gamepad_aoa *gamepad, struct sc_aoa *aoa) {
sc_hid_gamepad_init(&gamepad->hid);
static const struct sc_gamepad_processor_ops ops = {
.process_gamepad_device = sc_gamepad_processor_process_gamepad_device,
.process_gamepad_added = sc_gamepad_processor_process_gamepad_added,
.process_gamepad_removed = sc_gamepad_processor_process_gamepad_removed,
.process_gamepad_axis = sc_gamepad_processor_process_gamepad_axis,
.process_gamepad_button = sc_gamepad_processor_process_gamepad_button,
};

View File

@ -175,7 +175,6 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
assert(screen->gamepad);
struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor;
SDL_JoystickID id;
if (event->type == SDL_CONTROLLERDEVICEADDED) {
SDL_GameController *gc = SDL_GameControllerOpen(event->which);
if (!gc) {
@ -190,9 +189,12 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
return;
}
id = SDL_JoystickInstanceID(joystick);
struct sc_gamepad_added_event evt = {
.gamepad_id = SDL_JoystickInstanceID(joystick),
};
gp->ops->process_gamepad_added(gp, &evt);
} else if (event->type == SDL_CONTROLLERDEVICEREMOVED) {
id = event->which;
SDL_JoystickID id = event->which;
SDL_GameController *gc = SDL_GameControllerFromInstanceID(id);
if (gc) {
@ -200,16 +202,12 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
} else {
LOGW("Unknown gamepad device removed");
}
} else {
// Nothing to do
return;
}
struct sc_gamepad_device_event evt = {
.type = sc_gamepad_device_event_type_from_sdl_type(event->type),
.gamepad_id = id,
};
gp->ops->process_gamepad_device(gp, &evt);
struct sc_gamepad_removed_event evt = {
.gamepad_id = id,
};
gp->ops->process_gamepad_removed(gp, &evt);
}
}
static void

View File

@ -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

View File

@ -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 final class ControlMessage {
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 final class ControlMessage {
public boolean getOn() {
return on;
}
public int getVendorId() {
return vendorId;
}
public int getProductId() {
return productId;
}
}

View File

@ -142,9 +142,11 @@ public class ControlMessageReader {
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 {

View File

@ -290,7 +290,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
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());

View File

@ -48,7 +48,7 @@ public final class UhidManager {
}
}
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 final class UhidManager {
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 final class UhidManager {
}
}
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 @@ public final class UhidManager {
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);