Compare commits

...

5 Commits

Author SHA1 Message Date
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
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
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
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
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; return 2;
case SC_CONTROL_MSG_TYPE_UHID_CREATE: case SC_CONTROL_MSG_TYPE_UHID_CREATE:
sc_write16be(&buf[1], msg->uhid_create.id); 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); index += write_string_tiny(&buf[index], msg->uhid_create.name, 127);
sc_write16be(&buf[index], msg->uhid_create.report_desc_size); 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 // Quote only if name is not null
const char *name = msg->uhid_create.name; const char *name = msg->uhid_create.name;
const char *quote = name ? "\"" : ""; const char *quote = name ? "\"" : "";
LOG_CMSG("UHID create [%" PRIu16 "] name=%s%s%s " LOG_CMSG("UHID create [%" PRIu16 "] %04" PRIx16 ":%04" PRIx16
"report_desc_size=%" PRIu16, msg->uhid_create.id, " name=%s%s%s report_desc_size=%" PRIu16,
quote, name, quote, msg->uhid_create.report_desc_size); msg->uhid_create.id,
msg->uhid_create.vendor_id,
msg->uhid_create.product_id,
quote, name, quote,
msg->uhid_create.report_desc_size);
break; break;
} }
case SC_CONTROL_MSG_TYPE_UHID_INPUT: { case SC_CONTROL_MSG_TYPE_UHID_INPUT: {

View File

@ -94,6 +94,8 @@ struct sc_control_msg {
} set_display_power; } set_display_power;
struct { struct {
uint16_t id; uint16_t id;
uint16_t vendor_id;
uint16_t product_id;
const char *name; // pointer to static data const char *name; // pointer to static data
uint16_t report_desc_size; uint16_t report_desc_size;
const uint8_t *report_desc; // pointer to static data const uint8_t *report_desc; // pointer to static data

View File

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

View File

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

View File

@ -33,7 +33,9 @@ sc_hid_gamepad_init(struct sc_hid_gamepad *hid);
bool bool
sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid, sc_hid_gamepad_generate_open(struct sc_hid_gamepad *hid,
struct sc_hid_open *hid_open, struct sc_hid_open *hid_open,
uint32_t gamepad_id); uint32_t gamepad_id,
uint16_t vendor_id,
uint16_t product_id);
bool bool
sc_hid_gamepad_generate_close(struct sc_hid_gamepad *hid, 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) { void sc_hid_keyboard_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_KEYBOARD; 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->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_KEYBOARD_REPORT_DESC; hid_open->report_desc = SC_HID_KEYBOARD_REPORT_DESC;
hid_open->report_desc_size = sizeof(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) { void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open) {
hid_open->hid_id = SC_HID_ID_MOUSE; 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->name = NULL; // No name specified after "scrcpy"
hid_open->report_desc = SC_HID_MOUSE_REPORT_DESC; hid_open->report_desc = SC_HID_MOUSE_REPORT_DESC;
hid_open->report_desc_size = sizeof(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; 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>: // 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 // The ID value starts at 0 and increments from there. The value -1 is an
// invalid ID. // invalid ID.
#define SC_GAMEPAD_ID_INVALID UINT32_C(-1) #define SC_GAMEPAD_ID_INVALID UINT32_C(-1)
struct sc_gamepad_device_event { struct sc_gamepad_added_event {
enum sc_gamepad_device_event_type type; uint32_t gamepad_id;
};
struct sc_gamepad_removed_event {
uint32_t gamepad_id; uint32_t gamepad_id;
}; };
@ -503,16 +501,6 @@ sc_mouse_buttons_state_from_sdl(uint32_t buttons_state) {
return 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 static inline enum sc_gamepad_axis
sc_gamepad_axis_from_sdl(uint8_t axis) { sc_gamepad_axis_from_sdl(uint8_t axis) {
if (axis <= SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { 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 static void
sc_input_manager_process_gamepad_device(struct sc_input_manager *im, sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
const SDL_ControllerDeviceEvent *event) { const SDL_ControllerDeviceEvent *event) {
SDL_JoystickID id;
if (event->type == SDL_CONTROLLERDEVICEADDED) { if (event->type == SDL_CONTROLLERDEVICEADDED) {
SDL_GameController *gc = SDL_GameControllerOpen(event->which); SDL_GameController *gc = SDL_GameControllerOpen(event->which);
if (!gc) { if (!gc) {
@ -923,9 +922,12 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
return; 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) { } else if (event->type == SDL_CONTROLLERDEVICEREMOVED) {
id = event->which; SDL_JoystickID id = event->which;
SDL_GameController *gc = SDL_GameControllerFromInstanceID(id); SDL_GameController *gc = SDL_GameControllerFromInstanceID(id);
if (gc) { if (gc) {
@ -933,16 +935,15 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im,
} else { } else {
LOGW("Unknown gamepad device removed"); LOGW("Unknown gamepad device removed");
} }
struct sc_gamepad_removed_event evt = {
.gamepad_id = id,
};
im->gp->ops->process_gamepad_removed(im->gp, &evt);
} else { } else {
// Nothing to do // Nothing to do
return; 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 static void

View File

@ -20,13 +20,22 @@ struct sc_gamepad_processor {
struct sc_gamepad_processor_ops { struct sc_gamepad_processor_ops {
/** /**
* Process a gamepad device added or removed * Process a gamepad device added
* *
* This function is mandatory. * This function is mandatory.
*/ */
void void
(*process_gamepad_device)(struct sc_gamepad_processor *gp, (*process_gamepad_added)(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event); 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 * Process a gamepad axis event

View File

@ -7,6 +7,9 @@
/** Downcast gamepad processor to sc_gamepad_uhid */ /** Downcast gamepad processor to sc_gamepad_uhid */
#define DOWNCAST(GP) container_of(GP, struct sc_gamepad_uhid, gamepad_processor) #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 static void
sc_gamepad_uhid_send_input(struct sc_gamepad_uhid *gamepad, sc_gamepad_uhid_send_input(struct sc_gamepad_uhid *gamepad,
const struct sc_hid_input *hid_input, 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; struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = hid_open->hid_id; 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.name = hid_open->name;
msg.uhid_create.report_desc = hid_open->report_desc; msg.uhid_create.report_desc = hid_open->report_desc;
msg.uhid_create.report_desc_size = hid_open->report_desc_size; msg.uhid_create.report_desc_size = hid_open->report_desc_size;
@ -52,20 +57,25 @@ sc_gamepad_uhid_send_close(struct sc_gamepad_uhid *gamepad,
} }
static void static void
sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) { const struct sc_gamepad_added_event *event) {
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp); struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
if (event->type == SC_GAMEPAD_DEVICE_ADDED) {
struct sc_hid_open hid_open; struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open, if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) { event->gamepad_id,
SC_GAMEPAD_UHID_VENDOR_ID,
SC_GAMEPAD_UHID_PRODUCT_ID)) {
return; return;
} }
sc_gamepad_uhid_send_open(gamepad, &hid_open); sc_gamepad_uhid_send_open(gamepad, &hid_open);
} else { }
assert(event->type == SC_GAMEPAD_DEVICE_REMOVED);
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; struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close, if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
@ -75,7 +85,6 @@ sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
sc_gamepad_uhid_send_close(gamepad, &hid_close); sc_gamepad_uhid_send_close(gamepad, &hid_close);
} }
}
static void static void
sc_gamepad_processor_process_gamepad_axis(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_axis(struct sc_gamepad_processor *gp,
@ -114,7 +123,8 @@ sc_gamepad_uhid_init(struct sc_gamepad_uhid *gamepad,
gamepad->controller = controller; gamepad->controller = controller;
static const struct sc_gamepad_processor_ops ops = { 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_axis = sc_gamepad_processor_process_gamepad_axis,
.process_gamepad_button = sc_gamepad_processor_process_gamepad_button, .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; struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = SC_HID_ID_KEYBOARD; 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.name = hid_open.name;
msg.uhid_create.report_desc = hid_open.report_desc; msg.uhid_create.report_desc = hid_open.report_desc;
msg.uhid_create.report_desc_size = hid_open.report_desc_size; 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; struct sc_control_msg msg;
msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE; msg.type = SC_CONTROL_MSG_TYPE_UHID_CREATE;
msg.uhid_create.id = SC_HID_ID_MOUSE; 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.name = hid_open.name;
msg.uhid_create.report_desc = hid_open.report_desc; msg.uhid_create.report_desc = hid_open.report_desc;
msg.uhid_create.report_desc_size = hid_open.report_desc_size; msg.uhid_create.report_desc_size = hid_open.report_desc_size;

View File

@ -7,14 +7,13 @@
#define DOWNCAST(GP) container_of(GP, struct sc_gamepad_aoa, gamepad_processor) #define DOWNCAST(GP) container_of(GP, struct sc_gamepad_aoa, gamepad_processor)
static void static void
sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp,
const struct sc_gamepad_device_event *event) { const struct sc_gamepad_added_event *event) {
struct sc_gamepad_aoa *gamepad = DOWNCAST(gp); struct sc_gamepad_aoa *gamepad = DOWNCAST(gp);
if (event->type == SC_GAMEPAD_DEVICE_ADDED) {
struct sc_hid_open hid_open; struct sc_hid_open hid_open;
if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open, if (!sc_hid_gamepad_generate_open(&gamepad->hid, &hid_open,
event->gamepad_id)) { event->gamepad_id, 0, 0)) {
return; return;
} }
@ -22,8 +21,12 @@ sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
if (!sc_aoa_push_open(gamepad->aoa, &hid_open, false)) { if (!sc_aoa_push_open(gamepad->aoa, &hid_open, false)) {
LOGW("Could not push AOA HID open (gamepad)"); LOGW("Could not push AOA HID open (gamepad)");
} }
} else { }
assert(event->type == SC_GAMEPAD_DEVICE_REMOVED);
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);
struct sc_hid_close hid_close; struct sc_hid_close hid_close;
if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close, if (!sc_hid_gamepad_generate_close(&gamepad->hid, &hid_close,
@ -35,7 +38,6 @@ sc_gamepad_processor_process_gamepad_device(struct sc_gamepad_processor *gp,
LOGW("Could not push AOA HID close (gamepad)"); LOGW("Could not push AOA HID close (gamepad)");
} }
} }
}
static void static void
sc_gamepad_processor_process_gamepad_axis(struct sc_gamepad_processor *gp, sc_gamepad_processor_process_gamepad_axis(struct sc_gamepad_processor *gp,
@ -76,7 +78,8 @@ sc_gamepad_aoa_init(struct sc_gamepad_aoa *gamepad, struct sc_aoa *aoa) {
sc_hid_gamepad_init(&gamepad->hid); sc_hid_gamepad_init(&gamepad->hid);
static const struct sc_gamepad_processor_ops ops = { 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_axis = sc_gamepad_processor_process_gamepad_axis,
.process_gamepad_button = sc_gamepad_processor_process_gamepad_button, .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); assert(screen->gamepad);
struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor;
SDL_JoystickID id;
if (event->type == SDL_CONTROLLERDEVICEADDED) { if (event->type == SDL_CONTROLLERDEVICEADDED) {
SDL_GameController *gc = SDL_GameControllerOpen(event->which); SDL_GameController *gc = SDL_GameControllerOpen(event->which);
if (!gc) { if (!gc) {
@ -190,9 +189,12 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
return; 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) { } else if (event->type == SDL_CONTROLLERDEVICEREMOVED) {
id = event->which; SDL_JoystickID id = event->which;
SDL_GameController *gc = SDL_GameControllerFromInstanceID(id); SDL_GameController *gc = SDL_GameControllerFromInstanceID(id);
if (gc) { if (gc) {
@ -200,16 +202,12 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen,
} else { } else {
LOGW("Unknown gamepad device removed"); LOGW("Unknown gamepad device removed");
} }
} else {
// Nothing to do
return;
}
struct sc_gamepad_device_event evt = { struct sc_gamepad_removed_event evt = {
.type = sc_gamepad_device_event_type_from_sdl_type(event->type),
.gamepad_id = id, .gamepad_id = id,
}; };
gp->ops->process_gamepad_device(gp, &evt); gp->ops->process_gamepad_removed(gp, &evt);
}
} }
static void static void

View File

@ -329,6 +329,8 @@ static void test_serialize_uhid_create(void) {
.type = SC_CONTROL_MSG_TYPE_UHID_CREATE, .type = SC_CONTROL_MSG_TYPE_UHID_CREATE,
.uhid_create = { .uhid_create = {
.id = 42, .id = 42,
.vendor_id = 0x1234,
.product_id = 0x5678,
.name = "ABC", .name = "ABC",
.report_desc_size = sizeof(report_desc), .report_desc_size = sizeof(report_desc),
.report_desc = 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]; uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
size_t size = sc_control_msg_serialize(&msg, buf); size_t size = sc_control_msg_serialize(&msg, buf);
assert(size == 20); assert(size == 24);
const uint8_t expected[] = { const uint8_t expected[] = {
SC_CONTROL_MSG_TYPE_UHID_CREATE, SC_CONTROL_MSG_TYPE_UHID_CREATE,
0, 42, // id 0, 42, // id
0x12, 0x34, // vendor id
0x56, 0x78, // product id
3, // name size 3, // name size
65, 66, 67, // "ABC" 65, 66, 67, // "ABC"
0, 11, // report desc size 0, 11, // report desc size

View File

@ -51,6 +51,8 @@ public final class ControlMessage {
private int id; private int id;
private byte[] data; private byte[] data;
private boolean on; private boolean on;
private int vendorId;
private int productId;
private ControlMessage() { private ControlMessage() {
} }
@ -131,10 +133,12 @@ public final class ControlMessage {
return msg; 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(); ControlMessage msg = new ControlMessage();
msg.type = TYPE_UHID_CREATE; msg.type = TYPE_UHID_CREATE;
msg.id = id; msg.id = id;
msg.vendorId = vendorId;
msg.productId = productId;
msg.text = name; msg.text = name;
msg.data = reportDesc; msg.data = reportDesc;
return msg; return msg;
@ -237,4 +241,12 @@ public final class ControlMessage {
public boolean getOn() { public boolean getOn() {
return on; 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 { private ControlMessage parseUhidCreate() throws IOException {
int id = dis.readUnsignedShort(); int id = dis.readUnsignedShort();
int vendorId = dis.readUnsignedShort();
int productId = dis.readUnsignedShort();
String name = parseString(1); String name = parseString(1);
byte[] data = parseByteArray(2); byte[] data = parseByteArray(2);
return ControlMessage.createUhidCreate(id, name, data); return ControlMessage.createUhidCreate(id, vendorId, productId, name, data);
} }
private ControlMessage parseUhidInput() throws IOException { private ControlMessage parseUhidInput() throws IOException {

View File

@ -290,7 +290,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
Device.rotateDevice(getActionDisplayId()); Device.rotateDevice(getActionDisplayId());
break; break;
case ControlMessage.TYPE_UHID_CREATE: 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; break;
case ControlMessage.TYPE_UHID_INPUT: case ControlMessage.TYPE_UHID_INPUT:
getUhidManager().writeInput(msg.getId(), msg.getData()); 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 { try {
FileDescriptor fd = Os.open("/dev/uhid", OsConstants.O_RDWR, 0); FileDescriptor fd = Os.open("/dev/uhid", OsConstants.O_RDWR, 0);
try { try {
@ -58,7 +58,7 @@ public final class UhidManager {
close(old); close(old);
} }
byte[] req = buildUhidCreate2Req(name, reportDesc); byte[] req = buildUhidCreate2Req(vendorId, productId, name, reportDesc);
Os.write(fd, req, 0, req.length); Os.write(fd, req, 0, req.length);
registerUhidListener(id, fd); 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 { * struct uhid_event {
* uint32_t type; * uint32_t type;
@ -183,8 +183,8 @@ public final class UhidManager {
buf.putShort((short) reportDesc.length); buf.putShort((short) reportDesc.length);
buf.putShort(BUS_VIRTUAL); buf.putShort(BUS_VIRTUAL);
buf.putInt(0); // vendor id buf.putInt(vendorId);
buf.putInt(0); // product id buf.putInt(productId);
buf.putInt(0); // version buf.putInt(0); // version
buf.putInt(0); // country; buf.putInt(0); // country;
buf.put(reportDesc); buf.put(reportDesc);