Make sure HID devices can be opened before making them available to the application
This prevents a number of issues where devices are enumerated but not actually able to be opened, like https://github.com/libsdl-org/SDL/issues/5781. We currently leave the devices open, allowing us to more easily do controller feature detection, protocol negotiation, detect dropped Bluetooth connections, etc. with the expectation that the application is likely to open the controllers shortly.main
parent
2857e3c748
commit
aa2e2f4843
|
@ -130,7 +130,6 @@ struct hid_device_list_node
|
|||
|
||||
static IOHIDManagerRef hid_mgr = 0x0;
|
||||
static struct hid_device_list_node *device_list = 0x0;
|
||||
static int hid_input_monitoring_denied = 0;
|
||||
|
||||
static hid_device *new_hid_device(void)
|
||||
{
|
||||
|
@ -523,10 +522,6 @@ struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id,
|
|||
if (hid_init() < 0)
|
||||
return NULL;
|
||||
|
||||
/* If we don't have permission to open devices, don't enumerate them */
|
||||
if (hid_input_monitoring_denied)
|
||||
return NULL;
|
||||
|
||||
/* give the IOHIDManager a chance to update itself */
|
||||
process_pending_events();
|
||||
|
||||
|
@ -867,11 +862,6 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
|
|||
|
||||
return dev;
|
||||
}
|
||||
else if (ret == kIOReturnNotPermitted) {
|
||||
/* This application doesn't have input monitoring permissions */
|
||||
hid_input_monitoring_denied = 1;
|
||||
goto return_error;
|
||||
}
|
||||
else {
|
||||
goto return_error;
|
||||
}
|
||||
|
|
|
@ -52,12 +52,6 @@ HIDAPI_DriverCombined_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverCombined_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverCombined_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
|
@ -241,7 +235,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined =
|
|||
HIDAPI_DriverCombined_UnregisterHints,
|
||||
HIDAPI_DriverCombined_IsEnabled,
|
||||
HIDAPI_DriverCombined_IsSupportedDevice,
|
||||
HIDAPI_DriverCombined_GetDeviceName,
|
||||
HIDAPI_DriverCombined_InitDevice,
|
||||
HIDAPI_DriverCombined_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverCombined_SetDevicePlayerIndex,
|
||||
|
|
|
@ -89,12 +89,6 @@ HIDAPI_DriverGameCube_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverGameCube_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return "Nintendo GameCube Controller";
|
||||
}
|
||||
|
||||
static void
|
||||
ResetAxisRange(SDL_DriverGameCube_Context *ctx, int joystick_index)
|
||||
{
|
||||
|
@ -151,18 +145,13 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
|||
SDL_EnableGameCubeAdaptors();
|
||||
#endif
|
||||
|
||||
HIDAPI_SetDeviceName(device, "Nintendo GameCube Controller");
|
||||
|
||||
ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
ctx->joysticks[0] = -1;
|
||||
|
@ -184,8 +173,9 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
|||
} else {
|
||||
/* This is all that's needed to initialize the device. Really! */
|
||||
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
|
||||
SDL_SetError("Couldn't initialize WUP-028");
|
||||
goto error;
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Wait for the adapter to initialize */
|
||||
|
@ -230,22 +220,6 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
|||
SDL_GameControllerButtonReportingHintChanged, ctx);
|
||||
|
||||
return SDL_TRUE;
|
||||
|
||||
error:
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
if (device->context) {
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -565,16 +539,6 @@ HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)
|
|||
SDL_GameControllerButtonReportingHintChanged, ctx);
|
||||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE,
|
||||
SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx);
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
|
||||
|
@ -585,7 +549,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
|
|||
HIDAPI_DriverGameCube_UnregisterHints,
|
||||
HIDAPI_DriverGameCube_IsEnabled,
|
||||
HIDAPI_DriverGameCube_IsSupportedDevice,
|
||||
HIDAPI_DriverGameCube_GetDeviceName,
|
||||
HIDAPI_DriverGameCube_InitDevice,
|
||||
HIDAPI_DriverGameCube_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverGameCube_SetDevicePlayerIndex,
|
||||
|
|
|
@ -72,15 +72,20 @@ HIDAPI_DriverLuna_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
|
|||
return (type == SDL_CONTROLLER_TYPE_AMAZON_LUNA) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverLuna_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return "Amazon Luna Controller";
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverLuna_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverLuna_Context *ctx;
|
||||
|
||||
HIDAPI_SetDeviceName(device, "Amazon Luna Controller");
|
||||
|
||||
ctx = (SDL_DriverLuna_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -98,27 +103,14 @@ HIDAPI_DriverLuna_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
static SDL_bool
|
||||
HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverLuna_Context *ctx;
|
||||
SDL_DriverLuna_Context *ctx = (SDL_DriverLuna_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverLuna_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_NUM_LUNA_BUTTONS;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
|
||||
joystick->serial = NULL;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
@ -406,8 +398,7 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -415,6 +406,10 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
#ifdef DEBUG_LUNA_PROTOCOL
|
||||
HIDAPI_DumpPacket("Amazon Luna packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (size) {
|
||||
case 10:
|
||||
HIDAPI_DriverLuna_HandleUSBStatePacket(joystick, ctx, data, size);
|
||||
|
@ -427,7 +422,7 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -435,17 +430,6 @@ HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
static void
|
||||
HIDAPI_DriverLuna_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -461,7 +445,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna =
|
|||
HIDAPI_DriverLuna_UnregisterHints,
|
||||
HIDAPI_DriverLuna_IsEnabled,
|
||||
HIDAPI_DriverLuna_IsSupportedDevice,
|
||||
HIDAPI_DriverLuna_GetDeviceName,
|
||||
HIDAPI_DriverLuna_InitDevice,
|
||||
HIDAPI_DriverLuna_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverLuna_SetDevicePlayerIndex,
|
||||
|
|
|
@ -52,10 +52,10 @@ typedef struct {
|
|||
SDL_bool is_shanwan;
|
||||
SDL_bool report_sensors;
|
||||
SDL_bool effects_updated;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
int player_index;
|
||||
Uint8 rumble_left;
|
||||
Uint8 rumble_right;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
} SDL_DriverPS3_Context;
|
||||
|
||||
|
||||
|
@ -76,16 +76,16 @@ HIDAPI_DriverPS3_UnregisterHints(SDL_HintCallback callback, void *userdata)
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS3_IsEnabled(void)
|
||||
{
|
||||
SDL_bool default_value;
|
||||
|
||||
#if defined(__MACOSX__)
|
||||
/* This works well on macOS */
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3,
|
||||
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI,
|
||||
SDL_HIDAPI_DEFAULT));
|
||||
default_value = SDL_TRUE;
|
||||
#elif defined(__WINDOWS__)
|
||||
/* You can't initialize the controller with the stock Windows drivers
|
||||
* See https://github.com/ViGEm/DsHidMini as an alternative driver
|
||||
*/
|
||||
return SDL_FALSE;
|
||||
default_value = SDL_FALSE;
|
||||
#elif defined(__LINUX__)
|
||||
/* Linux drivers do a better job of managing the transition between
|
||||
* USB and Bluetooth. There are also some quirks in communicating
|
||||
|
@ -93,11 +93,16 @@ HIDAPI_DriverPS3_IsEnabled(void)
|
|||
* for libusb, but are not possible to support using hidraw if the
|
||||
* kernel doesn't already know about them.
|
||||
*/
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE);
|
||||
default_value = SDL_FALSE;
|
||||
#else
|
||||
/* Untested, default off */
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, SDL_FALSE);
|
||||
default_value = SDL_FALSE;
|
||||
#endif
|
||||
|
||||
if (default_value) {
|
||||
default_value = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT);
|
||||
}
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS3, default_value);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
|
@ -112,19 +117,6 @@ HIDAPI_DriverPS3_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverPS3_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_SONY) {
|
||||
if (name && SDL_strncasecmp(name, "ShanWan", 7) == 0) {
|
||||
return "ShanWan PS3 Controller";
|
||||
} else {
|
||||
return "PS3 Controller";
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
|
||||
{
|
||||
SDL_memset(report, 0, length);
|
||||
|
@ -140,6 +132,63 @@ static int SendFeatureReport(SDL_hid_device *dev, Uint8 *report, size_t length)
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS3_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverPS3_Context *ctx;
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
if (SDL_strncasecmp(device->name, "ShanWan", 7) == 0) {
|
||||
HIDAPI_SetDeviceName(device, "ShanWan PS3 Controller");
|
||||
} else {
|
||||
HIDAPI_SetDeviceName(device, "PS3 Controller");
|
||||
}
|
||||
}
|
||||
|
||||
ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
|
||||
device->context = ctx;
|
||||
|
||||
if (SDL_strncasecmp(device->name, "ShanWan", 7) == 0) {
|
||||
ctx->is_shanwan = SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Set the controller into report mode over Bluetooth */
|
||||
{
|
||||
Uint8 data[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
|
||||
|
||||
SendFeatureReport(device->dev, data, sizeof(data));
|
||||
}
|
||||
|
||||
/* Set the controller into report mode over USB */
|
||||
{
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
|
||||
if ((size = ReadFeatureReport(device->dev, 0xf2, data, 17)) < 0) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf2");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef DEBUG_PS3_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size);
|
||||
#endif
|
||||
if ((size = ReadFeatureReport(device->dev, 0xf5, data, 8)) < 0) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_DriverPS3_InitDevice(): Couldn't read feature report 0xf5");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef DEBUG_PS3_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS3 0xF5 packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!ctx->is_shanwan) {
|
||||
/* An output report could cause ShanWan controllers to rumble non-stop */
|
||||
SDL_hid_write(device->dev, data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -190,59 +239,13 @@ HIDAPI_DriverPS3_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS3_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverPS3_Context *ctx;
|
||||
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverPS3_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
ctx->joystick = joystick;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
if (SDL_strncasecmp(device->name, "ShanWan", 7) == 0) {
|
||||
ctx->is_shanwan = SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Set the controller into report mode over Bluetooth */
|
||||
{
|
||||
Uint8 data[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
|
||||
|
||||
SendFeatureReport(device->dev, data, sizeof(data));
|
||||
}
|
||||
|
||||
/* Set the controller into report mode over USB */
|
||||
{
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
|
||||
if ((size = ReadFeatureReport(device->dev, 0xf2, data, 17)) < 0) {
|
||||
SDL_SetError("Couldn't read feature report 0xf2");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef DEBUG_PS3_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS3 0xF2 packet: size = %d", data, size);
|
||||
#endif
|
||||
if ((size = ReadFeatureReport(device->dev, 0xf5, data, 8)) < 0) {
|
||||
SDL_SetError("Couldn't read feature report 0xf5");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef DEBUG_PS3_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS3 0xF5 packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!ctx->is_shanwan) {
|
||||
/* An output report could cause ShanWan controllers to rumble non-stop */
|
||||
SDL_hid_write(device->dev, data, 1);
|
||||
}
|
||||
}
|
||||
ctx->effects_updated = SDL_FALSE;
|
||||
ctx->rumble_left = 0;
|
||||
ctx->rumble_right = 0;
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
/* Initialize player index (needed for setting LEDs) */
|
||||
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
|
||||
|
@ -498,8 +501,7 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -507,10 +509,19 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
#ifdef DEBUG_PS3_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS3 packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size == 7) {
|
||||
/* Seen on a ShanWan PS2 -> PS3 USB converter */
|
||||
HIDAPI_DriverPS3_HandleMiniStatePacket(joystick, ctx, data, size);
|
||||
|
||||
/* Wait for the first report to set the LED state after the controller stops blinking */
|
||||
if (!ctx->effects_updated) {
|
||||
HIDAPI_DriverPS3_UpdateEffects(device);
|
||||
ctx->effects_updated = SDL_TRUE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -538,7 +549,7 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -546,15 +557,9 @@ HIDAPI_DriverPS3_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
static void
|
||||
HIDAPI_DriverPS3_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
SDL_DriverPS3_Context *ctx = (SDL_DriverPS3_Context *)device->context;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
ctx->joystick = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -570,7 +575,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS3 =
|
|||
HIDAPI_DriverPS3_UnregisterHints,
|
||||
HIDAPI_DriverPS3_IsEnabled,
|
||||
HIDAPI_DriverPS3_IsSupportedDevice,
|
||||
HIDAPI_DriverPS3_GetDeviceName,
|
||||
HIDAPI_DriverPS3_InitDevice,
|
||||
HIDAPI_DriverPS3_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverPS3_SetDevicePlayerIndex,
|
||||
|
|
|
@ -142,8 +142,6 @@ typedef struct {
|
|||
Uint8 led_red;
|
||||
Uint8 led_green;
|
||||
Uint8 led_blue;
|
||||
Uint8 volume;
|
||||
Uint32 last_volume_check;
|
||||
PS4StatePacket_t last_state;
|
||||
} SDL_DriverPS4_Context;
|
||||
|
||||
|
@ -176,15 +174,6 @@ HIDAPI_DriverPS4_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
|
|||
return (type == SDL_CONTROLLER_TYPE_PS4) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverPS4_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_SONY) {
|
||||
return "PS4 Controller";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
|
||||
{
|
||||
SDL_memset(report, 0, length);
|
||||
|
@ -222,6 +211,106 @@ SetLedsForPlayerIndex(DS4EffectsState_t *effects, int player_index)
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverPS4_Context *ctx;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
char serial[18];
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
HIDAPI_SetDeviceName(device, "PS4 Controller");
|
||||
}
|
||||
|
||||
ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
|
||||
device->context = ctx;
|
||||
|
||||
if (device->serial && SDL_strlen(device->serial) == 12) {
|
||||
int i, j;
|
||||
|
||||
j = -1;
|
||||
for (i = 0; i < 12; i += 2) {
|
||||
j += 1;
|
||||
SDL_memcpy(&serial[j], &device->serial[i], 2);
|
||||
j += 2;
|
||||
serial[j] = '-';
|
||||
}
|
||||
serial[j] = '\0';
|
||||
} else {
|
||||
serial[0] = '\0';
|
||||
}
|
||||
|
||||
/* Check for type of connection */
|
||||
ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE);
|
||||
if (ctx->is_dongle) {
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
ctx->official_controller = SDL_TRUE;
|
||||
ctx->enhanced_mode = SDL_TRUE;
|
||||
} else if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
/* This will fail if we're on Bluetooth */
|
||||
size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data));
|
||||
if (size >= 7) {
|
||||
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[6], data[5], data[4], data[3], data[2], data[1]);
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
ctx->enhanced_mode = SDL_TRUE;
|
||||
} else {
|
||||
ctx->is_bluetooth = SDL_TRUE;
|
||||
|
||||
/* Read a report to see if we're in enhanced mode */
|
||||
size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16);
|
||||
#ifdef DEBUG_PS4_PROTOCOL
|
||||
if (size > 0) {
|
||||
HIDAPI_DumpPacket("PS4 first packet: size = %d", data, size);
|
||||
} else {
|
||||
SDL_Log("PS4 first packet: size = %d\n", size);
|
||||
}
|
||||
#endif
|
||||
if (size > 0 &&
|
||||
data[0] >= k_EPS4ReportIdBluetoothState1 &&
|
||||
data[0] <= k_EPS4ReportIdBluetoothState9) {
|
||||
ctx->enhanced_mode = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
ctx->official_controller = SDL_TRUE;
|
||||
} else {
|
||||
/* Third party controllers appear to all be wired */
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
ctx->enhanced_mode = SDL_TRUE;
|
||||
}
|
||||
#ifdef DEBUG_PS4
|
||||
SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
|
||||
#endif
|
||||
|
||||
/* Get the device capabilities */
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
} else if ((size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data))) == 48 &&
|
||||
data[2] == 0x27) {
|
||||
Uint8 capabilities = data[4];
|
||||
|
||||
#ifdef DEBUG_PS4_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
|
||||
#endif
|
||||
if ((capabilities & 0x0C) != 0) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x02) != 0) {
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x40) != 0) {
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
HIDAPI_SetDeviceSerial(device, serial);
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -471,7 +560,7 @@ HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
{
|
||||
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
|
||||
|
||||
if (!ctx) {
|
||||
if (!ctx->joystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -484,124 +573,28 @@ HIDAPI_DriverPS4_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverPS4_Context *ctx;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
SDL_bool enhanced_mode = SDL_FALSE;
|
||||
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *) device->context;
|
||||
|
||||
ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
ctx->joystick = joystick;
|
||||
ctx->last_packet = SDL_GetTicks();
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
/* Check for type of connection */
|
||||
ctx->is_dongle = (device->vendor_id == USB_VENDOR_SONY && device->product_id == USB_PRODUCT_SONY_DS4_DONGLE);
|
||||
if (ctx->is_dongle) {
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
ctx->official_controller = SDL_TRUE;
|
||||
enhanced_mode = SDL_TRUE;
|
||||
} else if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
/* This will fail if we're on Bluetooth */
|
||||
size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data));
|
||||
if (size >= 7) {
|
||||
char serial[18];
|
||||
|
||||
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[6], data[5], data[4], data[3], data[2], data[1]);
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
enhanced_mode = SDL_TRUE;
|
||||
} else {
|
||||
ctx->is_bluetooth = SDL_TRUE;
|
||||
|
||||
/* Read a report to see if we're in enhanced mode */
|
||||
size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16);
|
||||
#ifdef DEBUG_PS4_PROTOCOL
|
||||
if (size > 0) {
|
||||
HIDAPI_DumpPacket("PS4 first packet: size = %d", data, size);
|
||||
} else {
|
||||
SDL_Log("PS4 first packet: size = %d\n", size);
|
||||
}
|
||||
#endif
|
||||
if (size > 0 &&
|
||||
data[0] >= k_EPS4ReportIdBluetoothState1 &&
|
||||
data[0] <= k_EPS4ReportIdBluetoothState9) {
|
||||
enhanced_mode = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
ctx->official_controller = SDL_TRUE;
|
||||
} else {
|
||||
/* Third party controllers appear to all be wired */
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
enhanced_mode = SDL_TRUE;
|
||||
}
|
||||
#ifdef DEBUG_PS4
|
||||
SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
|
||||
#endif
|
||||
|
||||
/* Get the device capabilities */
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
} else if ((size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data))) == 48 &&
|
||||
data[2] == 0x27) {
|
||||
Uint8 capabilities = data[4];
|
||||
|
||||
#ifdef DEBUG_PS4_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
|
||||
#endif
|
||||
if ((capabilities & 0x0C) != 0) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x02) != 0) {
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x40) != 0) {
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) {
|
||||
int i, j;
|
||||
char serial[18];
|
||||
|
||||
j = -1;
|
||||
for (i = 0; i < 12; i += 2) {
|
||||
j += 1;
|
||||
SDL_memcpy(&serial[j], &device->serial[i], 2);
|
||||
j += 2;
|
||||
serial[j] = '-';
|
||||
}
|
||||
serial[j] = '\0';
|
||||
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
}
|
||||
ctx->report_sensors = SDL_FALSE;
|
||||
ctx->report_touchpad = SDL_FALSE;
|
||||
ctx->rumble_left = 0;
|
||||
ctx->rumble_right = 0;
|
||||
ctx->color_set = SDL_FALSE;
|
||||
SDL_zero(ctx->last_state);
|
||||
|
||||
/* Initialize player index (needed for setting LEDs) */
|
||||
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
|
||||
|
||||
/* Initialize the joystick capabilities
|
||||
*
|
||||
* We can't dynamically add the touchpad button, so always report it here
|
||||
*/
|
||||
joystick->nbuttons = 16;
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = ctx->touchpad_supported ? 16 : 15;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
|
||||
|
||||
if (enhanced_mode) {
|
||||
if (ctx->enhanced_mode) {
|
||||
/* Force initialization when opening the joystick */
|
||||
ctx->enhanced_mode = SDL_FALSE;
|
||||
HIDAPI_DriverPS4_SetEnhancedMode(device, joystick);
|
||||
} else {
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE,
|
||||
|
@ -879,8 +872,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -891,6 +883,10 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
++packet_count;
|
||||
ctx->last_packet = SDL_GetTicks();
|
||||
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (data[0]) {
|
||||
case k_EPS4ReportIdUsbState:
|
||||
HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]);
|
||||
|
@ -931,7 +927,7 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -944,15 +940,7 @@ HIDAPI_DriverPS4_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick
|
|||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE,
|
||||
SDL_PS4RumbleHintChanged, ctx);
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
ctx->joystick = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -968,7 +956,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
|
|||
HIDAPI_DriverPS4_UnregisterHints,
|
||||
HIDAPI_DriverPS4_IsEnabled,
|
||||
HIDAPI_DriverPS4_IsSupportedDevice,
|
||||
HIDAPI_DriverPS4_GetDeviceName,
|
||||
HIDAPI_DriverPS4_InitDevice,
|
||||
HIDAPI_DriverPS4_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverPS4_SetDevicePlayerIndex,
|
||||
|
|
|
@ -256,15 +256,6 @@ HIDAPI_DriverPS5_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
|
|||
return (type == SDL_CONTROLLER_TYPE_PS5) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverPS5_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_SONY) {
|
||||
return "PS5 Controller";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
|
||||
{
|
||||
SDL_memset(report, 0, length);
|
||||
|
@ -321,6 +312,112 @@ SetLightsForPlayerIndex(DS5EffectsState_t *effects, int player_index)
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverPS5_Context *ctx;
|
||||
Uint8 data[USB_PACKET_LENGTH*2];
|
||||
int size;
|
||||
char serial[18];
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
HIDAPI_SetDeviceName(device, "PS5 Controller");
|
||||
}
|
||||
|
||||
ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
|
||||
device->context = ctx;
|
||||
|
||||
if (device->serial && SDL_strlen(device->serial) == 12) {
|
||||
int i, j;
|
||||
|
||||
j = -1;
|
||||
for (i = 0; i < 12; i += 2) {
|
||||
j += 1;
|
||||
SDL_memcpy(&serial[j], &device->serial[i], 2);
|
||||
j += 2;
|
||||
serial[j] = '-';
|
||||
}
|
||||
serial[j] = '\0';
|
||||
} else {
|
||||
serial[0] = '\0';
|
||||
}
|
||||
|
||||
/* Read a report to see what mode we're in */
|
||||
size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16);
|
||||
#ifdef DEBUG_PS5_PROTOCOL
|
||||
if (size > 0) {
|
||||
HIDAPI_DumpPacket("PS5 first packet: size = %d", data, size);
|
||||
} else {
|
||||
SDL_Log("PS5 first packet: size = %d\n", size);
|
||||
}
|
||||
#endif
|
||||
if (size == 64) {
|
||||
/* Connected over USB */
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
ctx->enhanced_mode = SDL_TRUE;
|
||||
} else if (size > 0 && data[0] == k_EPS5ReportIdBluetoothEffects) {
|
||||
/* Connected over Bluetooth, using enhanced reports */
|
||||
ctx->is_bluetooth = SDL_TRUE;
|
||||
ctx->enhanced_mode = SDL_TRUE;
|
||||
} else {
|
||||
/* Connected over Bluetooth, using simple reports (DirectInput enabled) */
|
||||
ctx->is_bluetooth = SDL_TRUE;
|
||||
|
||||
/* Games written prior the introduction of PS5 controller support in SDL will not be aware of
|
||||
SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, but they did know SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE.
|
||||
To support apps that only knew about the PS4 hint, we'll use the PS4 hint as the default.
|
||||
*/
|
||||
ctx->enhanced_mode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE,
|
||||
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE));
|
||||
}
|
||||
|
||||
if (ctx->enhanced_mode) {
|
||||
/* Read the serial number (Bluetooth address in reverse byte order)
|
||||
This will also enable enhanced reports over Bluetooth
|
||||
*/
|
||||
if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) {
|
||||
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[6], data[5], data[4], data[3], data[2], data[1]);
|
||||
}
|
||||
|
||||
/* Read the firmware version
|
||||
This will also enable enhanced reports over Bluetooth
|
||||
*/
|
||||
if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdFirmwareInfo, data, USB_PACKET_LENGTH) >= 46) {
|
||||
ctx->firmware_version = (Uint16)data[44] | ((Uint16)data[45] << 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the device capabilities */
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
} else if ((size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data))) == 48 &&
|
||||
data[2] == 0x28) {
|
||||
Uint8 capabilities = data[4];
|
||||
|
||||
#ifdef DEBUG_PS5_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
|
||||
#endif
|
||||
if ((capabilities & 0x0C) != 0) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x02) != 0) {
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x40) != 0) {
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
}
|
||||
|
||||
ctx->use_alternate_report = SDL_TRUE;
|
||||
}
|
||||
|
||||
HIDAPI_SetDeviceSerial(device, serial);
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -623,7 +720,7 @@ HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
{
|
||||
SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
|
||||
|
||||
if (!ctx) {
|
||||
if (!ctx->joystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -636,132 +733,31 @@ HIDAPI_DriverPS5_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
static SDL_bool
|
||||
HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverPS5_Context *ctx;
|
||||
Uint8 data[USB_PACKET_LENGTH*2];
|
||||
int size;
|
||||
SDL_bool enhanced_mode = SDL_FALSE;
|
||||
SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
ctx->joystick = joystick;
|
||||
ctx->last_packet = SDL_GetTicks();
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
/* Read a report to see what mode we're in */
|
||||
size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 16);
|
||||
#ifdef DEBUG_PS5_PROTOCOL
|
||||
if (size > 0) {
|
||||
HIDAPI_DumpPacket("PS5 first packet: size = %d", data, size);
|
||||
} else {
|
||||
SDL_Log("PS5 first packet: size = %d\n", size);
|
||||
}
|
||||
#endif
|
||||
if (size == 64) {
|
||||
/* Connected over USB */
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
enhanced_mode = SDL_TRUE;
|
||||
} else if (size > 0 && data[0] == k_EPS5ReportIdBluetoothEffects) {
|
||||
/* Connected over Bluetooth, using enhanced reports */
|
||||
ctx->is_bluetooth = SDL_TRUE;
|
||||
enhanced_mode = SDL_TRUE;
|
||||
} else {
|
||||
/* Connected over Bluetooth, using simple reports (DirectInput enabled) */
|
||||
ctx->is_bluetooth = SDL_TRUE;
|
||||
|
||||
/* Games written prior the introduction of PS5 controller support in SDL will not be aware of
|
||||
SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, but they did know SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE.
|
||||
To support apps that only knew about the PS4 hint, we'll use the PS4 hint as the default.
|
||||
*/
|
||||
enhanced_mode = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE,
|
||||
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, SDL_FALSE));
|
||||
}
|
||||
|
||||
if (enhanced_mode) {
|
||||
/* Read the serial number (Bluetooth address in reverse byte order)
|
||||
This will also enable enhanced reports over Bluetooth
|
||||
*/
|
||||
if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdSerialNumber, data, sizeof(data)) >= 7) {
|
||||
char serial[18];
|
||||
|
||||
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[6], data[5], data[4], data[3], data[2], data[1]);
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
}
|
||||
|
||||
/* Read the firmware version
|
||||
This will also enable enhanced reports over Bluetooth
|
||||
*/
|
||||
if (ReadFeatureReport(device->dev, k_EPS5FeatureReportIdFirmwareInfo, data, USB_PACKET_LENGTH) >= 46) {
|
||||
ctx->firmware_version = (Uint16)data[44] | ((Uint16)data[45] << 8);
|
||||
joystick->firmware_version = ctx->firmware_version;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the device capabilities */
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
} else if ((size = ReadFeatureReport(device->dev, k_EPS5FeatureReportIdCapabilities, data, sizeof(data))) == 48 &&
|
||||
data[2] == 0x28) {
|
||||
Uint8 capabilities = data[4];
|
||||
|
||||
#ifdef DEBUG_PS5_PROTOCOL
|
||||
HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
|
||||
#endif
|
||||
if ((capabilities & 0x0C) != 0) {
|
||||
ctx->effects_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x02) != 0) {
|
||||
ctx->sensors_supported = SDL_TRUE;
|
||||
}
|
||||
if ((capabilities & 0x40) != 0) {
|
||||
ctx->touchpad_supported = SDL_TRUE;
|
||||
}
|
||||
|
||||
ctx->use_alternate_report = SDL_TRUE;
|
||||
}
|
||||
|
||||
if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) {
|
||||
int i, j;
|
||||
char serial[18];
|
||||
|
||||
j = -1;
|
||||
for (i = 0; i < 12; i += 2) {
|
||||
j += 1;
|
||||
SDL_memcpy(&serial[j], &device->serial[i], 2);
|
||||
j += 2;
|
||||
serial[j] = '-';
|
||||
}
|
||||
serial[j] = '\0';
|
||||
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
}
|
||||
ctx->report_sensors = SDL_FALSE;
|
||||
ctx->report_touchpad = SDL_FALSE;
|
||||
ctx->rumble_left = 0;
|
||||
ctx->rumble_right = 0;
|
||||
ctx->color_set = SDL_FALSE;
|
||||
ctx->led_reset_state = k_EDS5LEDResetStateNone;
|
||||
SDL_zero(ctx->last_state);
|
||||
|
||||
/* Initialize player index (needed for setting LEDs) */
|
||||
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
|
||||
ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_TRUE);
|
||||
|
||||
/* Initialize the joystick capabilities
|
||||
*
|
||||
* We can't dynamically add the touchpad button, so always report it here
|
||||
*/
|
||||
joystick->nbuttons = 17;
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = ctx->touchpad_supported ? 17 : 15;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = ctx->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
|
||||
joystick->firmware_version = ctx->firmware_version;
|
||||
|
||||
if (enhanced_mode) {
|
||||
if (ctx->enhanced_mode) {
|
||||
/* Force initialization when opening the joystick */
|
||||
ctx->enhanced_mode = SDL_FALSE;
|
||||
HIDAPI_DriverPS5_SetEnhancedMode(device, joystick);
|
||||
} else {
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE,
|
||||
|
@ -769,6 +765,7 @@ HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|||
}
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED,
|
||||
SDL_PS5PlayerLEDHintChanged, ctx);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1183,8 +1180,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1195,6 +1191,10 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
++packet_count;
|
||||
ctx->last_packet = SDL_GetTicks();
|
||||
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (data[0]) {
|
||||
case k_EPS5ReportIdState:
|
||||
if (size == 10 || size == 78) {
|
||||
|
@ -1241,7 +1241,7 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -1257,15 +1257,7 @@ HIDAPI_DriverPS5_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick
|
|||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED,
|
||||
SDL_PS5PlayerLEDHintChanged, ctx);
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
ctx->joystick = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1281,7 +1273,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 =
|
|||
HIDAPI_DriverPS5_UnregisterHints,
|
||||
HIDAPI_DriverPS5_IsEnabled,
|
||||
HIDAPI_DriverPS5_IsSupportedDevice,
|
||||
HIDAPI_DriverPS5_GetDeviceName,
|
||||
HIDAPI_DriverPS5_InitDevice,
|
||||
HIDAPI_DriverPS5_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverPS5_SetDevicePlayerIndex,
|
||||
|
|
|
@ -107,15 +107,20 @@ HIDAPI_DriverShield_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *nam
|
|||
return (type == SDL_CONTROLLER_TYPE_NVIDIA_SHIELD) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverShield_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return "NVIDIA SHIELD Controller";
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverShield_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx;
|
||||
|
||||
HIDAPI_SetDeviceName(device, "NVIDIA SHIELD Controller");
|
||||
|
||||
ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -133,7 +138,7 @@ HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
|
|||
static int
|
||||
HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx = device->context;
|
||||
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
|
||||
ShieldCommandReport_t cmd_pkt;
|
||||
|
||||
if (size > sizeof(cmd_pkt.payload)) {
|
||||
|
@ -164,21 +169,14 @@ HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void
|
|||
static SDL_bool
|
||||
HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx;
|
||||
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverShield_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
ctx->rumble_report_pending = SDL_FALSE;
|
||||
ctx->rumble_update_pending = SDL_FALSE;
|
||||
ctx->left_motor_amplitude = 0;
|
||||
ctx->right_motor_amplitude = 0;
|
||||
ctx->last_rumble_time = 0;
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = 16;
|
||||
|
@ -186,7 +184,6 @@ HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
|||
joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
|
||||
/* Request battery and charging info */
|
||||
ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
ctx->last_battery_query_time = SDL_GetTicks();
|
||||
HIDAPI_DriverShield_SendCommand(device, CMD_CHARGE_STATE, NULL, 0);
|
||||
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
|
||||
|
@ -367,8 +364,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -376,9 +372,13 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
#ifdef DEBUG_SHIELD_PROTOCOL
|
||||
HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);
|
||||
#endif
|
||||
|
||||
/* Byte 0 is HID report ID */
|
||||
switch (data[0]) {
|
||||
case k_ShieldReportIdControllerState:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverShield_HandleStatePacket(joystick, ctx, data, size);
|
||||
break;
|
||||
case k_ShieldReportIdCommandResponse:
|
||||
|
@ -390,7 +390,9 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
break;
|
||||
case CMD_CHARGE_STATE:
|
||||
ctx->charging = cmd_resp_report->payload[0] != 0;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
|
||||
if (joystick) {
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
|
||||
}
|
||||
break;
|
||||
case CMD_BATTERY_STATE:
|
||||
switch (cmd_resp_report->payload[2]) {
|
||||
|
@ -412,7 +414,9 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
|
||||
if (joystick) {
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -420,7 +424,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
}
|
||||
|
||||
/* Ask for battery state again if we're due for an update */
|
||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) {
|
||||
if (joystick && SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_battery_query_time + BATTERY_POLL_INTERVAL_MS)) {
|
||||
ctx->last_battery_query_time = SDL_GetTicks();
|
||||
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
|
||||
}
|
||||
|
@ -434,7 +438,7 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -442,17 +446,6 @@ HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
static void
|
||||
HIDAPI_DriverShield_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -468,7 +461,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield =
|
|||
HIDAPI_DriverShield_UnregisterHints,
|
||||
HIDAPI_DriverShield_IsEnabled,
|
||||
HIDAPI_DriverShield_IsSupportedDevice,
|
||||
HIDAPI_DriverShield_GetDeviceName,
|
||||
HIDAPI_DriverShield_InitDevice,
|
||||
HIDAPI_DriverShield_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverShield_SetDevicePlayerIndex,
|
||||
|
|
|
@ -73,15 +73,20 @@ HIDAPI_DriverStadia_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *nam
|
|||
return (type == SDL_CONTROLLER_TYPE_GOOGLE_STADIA) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverStadia_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return "Google Stadia Controller";
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverStadia_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverStadia_Context *ctx;
|
||||
|
||||
HIDAPI_SetDeviceName(device, "Google Stadia Controller");
|
||||
|
||||
ctx = (SDL_DriverStadia_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -99,21 +104,9 @@ HIDAPI_DriverStadia_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
|
|||
static SDL_bool
|
||||
HIDAPI_DriverStadia_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverStadia_Context *ctx;
|
||||
SDL_DriverStadia_Context *ctx = (SDL_DriverStadia_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverStadia_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_NUM_STADIA_BUTTONS;
|
||||
|
@ -281,8 +274,7 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -290,12 +282,16 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
#ifdef DEBUG_STADIA_PROTOCOL
|
||||
HIDAPI_DumpPacket("Google Stadia packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HIDAPI_DriverStadia_HandleStatePacket(joystick, ctx, data, size);
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -303,17 +299,6 @@ HIDAPI_DriverStadia_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
static void
|
||||
HIDAPI_DriverStadia_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -329,7 +314,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia =
|
|||
HIDAPI_DriverStadia_UnregisterHints,
|
||||
HIDAPI_DriverStadia_IsEnabled,
|
||||
HIDAPI_DriverStadia_IsSupportedDevice,
|
||||
HIDAPI_DriverStadia_GetDeviceName,
|
||||
HIDAPI_DriverStadia_InitDevice,
|
||||
HIDAPI_DriverStadia_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverStadia_SetDevicePlayerIndex,
|
||||
|
|
|
@ -1022,15 +1022,20 @@ HIDAPI_DriverSteam_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name
|
|||
return SDL_IsJoystickSteamController(vendor_id, product_id);
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverSteam_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return "Steam Controller";
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverSteam_Context *ctx;
|
||||
|
||||
HIDAPI_SetDeviceName(device, "Steam Controller");
|
||||
|
||||
ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -1048,27 +1053,18 @@ HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickI
|
|||
static SDL_bool
|
||||
HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverSteam_Context *ctx;
|
||||
SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
|
||||
uint32_t update_rate_in_us = 0;
|
||||
float update_rate_in_hz = 0.0f;
|
||||
|
||||
ctx = (SDL_DriverSteam_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
goto error;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
goto error;
|
||||
}
|
||||
SDL_hid_set_nonblocking(device->dev, 1);
|
||||
ctx->report_sensors = SDL_FALSE;
|
||||
SDL_zero(ctx->m_assembler);
|
||||
SDL_zero(ctx->m_state);
|
||||
SDL_zero(ctx->m_last_state);
|
||||
|
||||
if (!ResetSteamController(device->dev, false, &update_rate_in_us)) {
|
||||
SDL_SetError("Couldn't reset controller");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
if (update_rate_in_us > 0) {
|
||||
update_rate_in_hz = 1000000.0f / update_rate_in_us;
|
||||
|
@ -1084,21 +1080,6 @@ HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
|
|||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
|
||||
|
||||
return SDL_TRUE;
|
||||
|
||||
error:
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
if (device->context) {
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1117,7 +1098,7 @@ HIDAPI_DriverSteam_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystic
|
|||
static Uint32
|
||||
HIDAPI_DriverSteam_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
/* You should use the full Steam Input API for LED support */
|
||||
/* You should use the full Steam Input API for extended capabilities */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1166,8 +1147,7 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1178,11 +1158,14 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
const Uint8 *pPacket;
|
||||
|
||||
r = ReadSteamController(device->dev, data, sizeof(data));
|
||||
if (r == 0)
|
||||
{
|
||||
if (r == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nPacketLength = 0;
|
||||
if (r > 0) {
|
||||
nPacketLength = WriteSegmentToSteamControllerPacketAssembler(&ctx->m_assembler, data, r);
|
||||
|
@ -1281,17 +1264,7 @@ HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
static void
|
||||
HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
CloseSteamController(device->dev);
|
||||
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
CloseSteamController(device->dev);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1307,7 +1280,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam =
|
|||
HIDAPI_DriverSteam_UnregisterHints,
|
||||
HIDAPI_DriverSteam_IsEnabled,
|
||||
HIDAPI_DriverSteam_IsSupportedDevice,
|
||||
HIDAPI_DriverSteam_GetDeviceName,
|
||||
HIDAPI_DriverSteam_InitDevice,
|
||||
HIDAPI_DriverSteam_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverSteam_SetDevicePlayerIndex,
|
||||
|
|
|
@ -236,6 +236,7 @@ typedef struct
|
|||
|
||||
typedef struct {
|
||||
SDL_HIDAPI_Device *device;
|
||||
SDL_Joystick *joystick;
|
||||
SDL_bool m_bInputOnly;
|
||||
SDL_bool m_bUsingBluetooth;
|
||||
SDL_bool m_bIsGameCube;
|
||||
|
@ -556,6 +557,29 @@ static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
|
|||
return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
|
||||
}
|
||||
|
||||
static ESwitchDeviceInfoControllerType CalculateControllerType(SDL_DriverSwitch_Context *ctx, ESwitchDeviceInfoControllerType eControllerType)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = ctx->device;
|
||||
|
||||
/* The N64 controller reports as a Pro controller over USB */
|
||||
if (eControllerType == k_eSwitchDeviceInfoControllerType_ProController &&
|
||||
device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) {
|
||||
eControllerType = k_eSwitchDeviceInfoControllerType_N64;
|
||||
}
|
||||
|
||||
if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) {
|
||||
/* This might be a Joy-Con that's missing from a charging grip slot */
|
||||
if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) {
|
||||
if (device->interface_number == 1) {
|
||||
eControllerType = k_eSwitchDeviceInfoControllerType_JoyConLeft;
|
||||
} else {
|
||||
eControllerType = k_eSwitchDeviceInfoControllerType_JoyConRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
return eControllerType;
|
||||
}
|
||||
|
||||
static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||
|
@ -566,13 +590,7 @@ static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx)
|
|||
SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
|
||||
size_t i;
|
||||
|
||||
ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)status->ucDeviceType;
|
||||
|
||||
/* The N64 controller reports as a Pro controller over USB */
|
||||
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_ProController &&
|
||||
ctx->device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) {
|
||||
ctx->m_eControllerType = k_eSwitchDeviceInfoControllerType_N64;
|
||||
}
|
||||
ctx->m_eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)status->ucDeviceType);
|
||||
|
||||
for (i = 0; i < sizeof (ctx->m_rgucMACAddress); ++i)
|
||||
ctx->m_rgucMACAddress[i] = status->rgucMACAddress[ sizeof(ctx->m_rgucMACAddress) - i - 1 ];
|
||||
|
@ -584,7 +602,7 @@ static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx)
|
|||
|
||||
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
|
||||
// Byte 2: Controller ID (1=LJC, 2=RJC, 3=Pro)
|
||||
ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType;
|
||||
ctx->m_eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType);
|
||||
|
||||
// Bytes 4-9: MAC address (big-endian)
|
||||
SDL_memcpy(ctx->m_rgucMACAddress, reply->deviceInfo.rgucMACAddress, sizeof(ctx->m_rgucMACAddress));
|
||||
|
@ -909,6 +927,8 @@ static ESwitchDeviceInfoControllerType
|
|||
ReadJoyConControllerType(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
ESwitchDeviceInfoControllerType eControllerType = k_eSwitchDeviceInfoControllerType_Unknown;
|
||||
const int MAX_ATTEMPTS = 20;
|
||||
int attempts = 0;
|
||||
|
||||
/* Create enough of a context to read the controller type from the device */
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
|
@ -917,39 +937,26 @@ ReadJoyConControllerType(SDL_HIDAPI_Device *device)
|
|||
ctx->m_bSyncWrite = SDL_TRUE;
|
||||
ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device);
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (device->dev) {
|
||||
const int MAX_ATTEMPTS = 20;
|
||||
int attempts = 0;
|
||||
for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
|
||||
if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) {
|
||||
SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
|
||||
for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
|
||||
if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) {
|
||||
SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
|
||||
|
||||
eControllerType = (ESwitchDeviceInfoControllerType) status->ucDeviceType;
|
||||
eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)status->ucDeviceType);
|
||||
} else {
|
||||
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||
|
||||
/* The N64 controller reports as a Pro controller over USB */
|
||||
if (eControllerType == k_eSwitchDeviceInfoControllerType_ProController &&
|
||||
device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) {
|
||||
eControllerType = k_eSwitchDeviceInfoControllerType_N64;
|
||||
}
|
||||
} else {
|
||||
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||
|
||||
ctx->m_bUsingBluetooth = SDL_TRUE;
|
||||
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
|
||||
eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType;
|
||||
}
|
||||
}
|
||||
if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) {
|
||||
/* Wait a bit and try again */
|
||||
SDL_Delay(100);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
ctx->m_bUsingBluetooth = SDL_TRUE;
|
||||
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
|
||||
eControllerType = CalculateControllerType(ctx, (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType);
|
||||
}
|
||||
}
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
if (eControllerType == k_eSwitchDeviceInfoControllerType_Unknown) {
|
||||
/* Wait a bit and try again */
|
||||
SDL_Delay(100);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_free(ctx);
|
||||
}
|
||||
|
@ -1144,121 +1151,91 @@ HIDAPI_DriverSwitch_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *nam
|
|||
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverSwitch_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
/* Give a user friendly name for this controller */
|
||||
if (vendor_id == USB_VENDOR_NINTENDO) {
|
||||
if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) {
|
||||
/* We don't know if this is left or right, just leave it alone */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) {
|
||||
return "Nintendo Switch Joy-Con (L)";
|
||||
}
|
||||
|
||||
if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT) {
|
||||
if (SDL_strncmp(name, "NES Controller", 14) == 0) {
|
||||
if (SDL_strstr(name, "(L)") != 0) {
|
||||
return "Nintendo NES Controller (L)";
|
||||
} else if (SDL_strstr(name, "(R)") != 0) {
|
||||
return "Nintendo NES Controller (R)";
|
||||
} else {
|
||||
/* Not sure what this is, just leave it alone */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return "Nintendo Switch Joy-Con (R)";
|
||||
}
|
||||
|
||||
if (product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) {
|
||||
return "Nintendo N64 Controller";
|
||||
}
|
||||
|
||||
if (product_id == USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER) {
|
||||
return "Nintendo SEGA Genesis Controller";
|
||||
}
|
||||
|
||||
if (product_id == USB_PRODUCT_NINTENDO_SNES_CONTROLLER) {
|
||||
return "Nintendo SNES Controller";
|
||||
}
|
||||
}
|
||||
|
||||
return "Nintendo Switch Pro Controller";
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
ESwitchDeviceInfoControllerType eControllerType = (ESwitchDeviceInfoControllerType)device->guid.data[15];
|
||||
const char *name = NULL;
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
|
||||
char serial[18];
|
||||
|
||||
switch (eControllerType) {
|
||||
switch (ctx->m_eControllerType) {
|
||||
case k_eSwitchDeviceInfoControllerType_JoyConLeft:
|
||||
name = "Nintendo Switch Joy-Con (L)";
|
||||
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT);
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Switch Joy-Con (L)");
|
||||
HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT);
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_JoyConRight:
|
||||
name = "Nintendo Switch Joy-Con (R)";
|
||||
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT);
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Switch Joy-Con (R)");
|
||||
HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT);
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_ProController:
|
||||
name = "Nintendo Switch Pro Controller";
|
||||
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SWITCH_PRO);
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Switch Pro Controller");
|
||||
HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SWITCH_PRO);
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_NESLeft:
|
||||
name = "Nintendo NES Controller (L)";
|
||||
HIDAPI_SetDeviceName(device, "Nintendo NES Controller (L)");
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_NESRight:
|
||||
name = "Nintendo NES Controller (R)";
|
||||
HIDAPI_SetDeviceName(device, "Nintendo NES Controller (R)");
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_SNES:
|
||||
name = "Nintendo SNES Controller";
|
||||
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SNES_CONTROLLER);
|
||||
HIDAPI_SetDeviceName(device, "Nintendo SNES Controller");
|
||||
HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SNES_CONTROLLER);
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_N64:
|
||||
name = "Nintendo N64 Controller";
|
||||
device->product_id = USB_PRODUCT_NINTENDO_N64_CONTROLLER;
|
||||
HIDAPI_SetDeviceName(device, "Nintendo N64 Controller");
|
||||
HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_N64_CONTROLLER);
|
||||
break;
|
||||
case k_eSwitchDeviceInfoControllerType_SEGA_Genesis:
|
||||
name = "Nintendo SEGA Genesis Controller";
|
||||
SDL_SetJoystickGUIDProduct(&device->guid, USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER);
|
||||
HIDAPI_SetDeviceName(device, "Nintendo SEGA Genesis Controller");
|
||||
HIDAPI_SetDeviceProduct(device, USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
device->guid.data[15] = ctx->m_eControllerType;
|
||||
|
||||
if (name && (!name || SDL_strcmp(name, device->name) != 0)) {
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(name);
|
||||
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name)));
|
||||
}
|
||||
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
ctx->m_rgucMACAddress[0],
|
||||
ctx->m_rgucMACAddress[1],
|
||||
ctx->m_rgucMACAddress[2],
|
||||
ctx->m_rgucMACAddress[3],
|
||||
ctx->m_rgucMACAddress[4],
|
||||
ctx->m_rgucMACAddress[5]);
|
||||
HIDAPI_SetDeviceSerial(device, serial);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
/* The NES controllers need additional fix up, since we can't detect them without opening the device */
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO) {
|
||||
ESwitchDeviceInfoControllerType eControllerType = ReadJoyConControllerType(device);
|
||||
switch (eControllerType) {
|
||||
case k_eSwitchDeviceInfoControllerType_Unknown:
|
||||
/* This might be a Joy-Con that's missing from a charging grip slot */
|
||||
if (device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) {
|
||||
if (device->interface_number == 1) {
|
||||
device->guid.data[15] = k_eSwitchDeviceInfoControllerType_JoyConLeft;
|
||||
} else {
|
||||
device->guid.data[15] = k_eSwitchDeviceInfoControllerType_JoyConRight;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
device->guid.data[15] = eControllerType;
|
||||
break;
|
||||
SDL_DriverSwitch_Context *ctx;
|
||||
|
||||
ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
device->context = ctx;
|
||||
|
||||
ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device);
|
||||
ctx->m_bSyncWrite = SDL_TRUE;
|
||||
|
||||
if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) {
|
||||
/* This is a controller shaped like a GameCube controller, with a large central A button */
|
||||
ctx->m_bIsGameCube = SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Find out whether or not we can send output reports */
|
||||
ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
|
||||
if (!ctx->m_bInputOnly) {
|
||||
if (!BReadDeviceInfo(ctx)) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_DriverSwitch_InitDevice(): Couldn't read device info");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
UpdateDeviceIdentity(device);
|
||||
}
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -1273,7 +1250,7 @@ HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
|
|||
{
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
|
||||
|
||||
if (!ctx) {
|
||||
if (!ctx->joystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1285,41 +1262,22 @@ HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystick
|
|||
static SDL_bool
|
||||
HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverSwitch_Context *ctx;
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
|
||||
Uint8 input_mode;
|
||||
|
||||
ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
goto error;
|
||||
}
|
||||
ctx->device = device;
|
||||
device->context = ctx;
|
||||
ctx->joystick = joystick;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
goto error;
|
||||
}
|
||||
ctx->m_nMaxWriteAttempts = GetMaxWriteAttempts(device);
|
||||
ctx->m_bSyncWrite = SDL_TRUE;
|
||||
|
||||
/* Find out whether or not we can send output reports */
|
||||
ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
|
||||
if (!ctx->m_bInputOnly) {
|
||||
/* Initialize rumble data */
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
|
||||
|
||||
if (!BReadDeviceInfo(ctx)) {
|
||||
SDL_SetError("Couldn't read device info");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!ctx->m_bUsingBluetooth) {
|
||||
if (!BTrySetupUSB(ctx)) {
|
||||
SDL_SetError("Couldn't setup USB mode");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1365,23 +1323,23 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
|||
|
||||
if (!LoadStickCalibration(ctx, input_mode)) {
|
||||
SDL_SetError("Couldn't load stick calibration");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!LoadIMUCalibration(ctx)) {
|
||||
SDL_SetError("Couldn't load sensor calibration");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!SetVibrationEnabled(ctx, 1)) {
|
||||
SDL_SetError("Couldn't enable vibration");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Set desired input mode */
|
||||
if (!SetInputMode(ctx, input_mode)) {
|
||||
SDL_SetError("Couldn't set input mode");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Start sending USB reports */
|
||||
|
@ -1389,7 +1347,7 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
|||
/* ForceUSB doesn't generate an ACK, so don't wait for a reply */
|
||||
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
|
||||
SDL_SetError("Couldn't start USB reports");
|
||||
goto error;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1404,28 +1362,6 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
|||
SDL_HomeLEDHintChanged, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the serial number */
|
||||
{
|
||||
char serial[18];
|
||||
|
||||
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
ctx->m_rgucMACAddress[0],
|
||||
ctx->m_rgucMACAddress[1],
|
||||
ctx->m_rgucMACAddress[2],
|
||||
ctx->m_rgucMACAddress[3],
|
||||
ctx->m_rgucMACAddress[4],
|
||||
ctx->m_rgucMACAddress[5]);
|
||||
if (joystick->serial) {
|
||||
SDL_free(joystick->serial);
|
||||
}
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) {
|
||||
/* This is a controller shaped like a GameCube controller, with a large central A button */
|
||||
ctx->m_bIsGameCube = SDL_TRUE;
|
||||
}
|
||||
|
||||
if (AlwaysUsesLabels(device->vendor_id, device->product_id, ctx->m_eControllerType)) {
|
||||
|
@ -1453,21 +1389,6 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
|
|||
ctx->m_unLastIMUReset = ctx->m_unLastInput = SDL_GetTicks();
|
||||
|
||||
return SDL_TRUE;
|
||||
|
||||
error:
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
if (device->context) {
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2142,8 +2063,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -2153,35 +2073,39 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
#ifdef DEBUG_SWITCH_PROTOCOL
|
||||
HIDAPI_DumpPacket("Nintendo Switch packet: size = %d", ctx->m_rgucReadBuffer, size);
|
||||
#endif
|
||||
if (ctx->m_bInputOnly) {
|
||||
HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]);
|
||||
} else {
|
||||
switch (ctx->m_rgucReadBuffer[0]) {
|
||||
case k_eSwitchInputReportIDs_SimpleControllerState:
|
||||
HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
|
||||
break;
|
||||
case k_eSwitchInputReportIDs_FullControllerState:
|
||||
HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (joystick) {
|
||||
if (ctx->m_bInputOnly) {
|
||||
HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]);
|
||||
} else {
|
||||
switch (ctx->m_rgucReadBuffer[0]) {
|
||||
case k_eSwitchInputReportIDs_SimpleControllerState:
|
||||
HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
|
||||
break;
|
||||
case k_eSwitchInputReportIDs_FullControllerState:
|
||||
HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx->m_unLastInput = now;
|
||||
}
|
||||
|
||||
if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth &&
|
||||
ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) {
|
||||
const Uint32 INPUT_WAIT_TIMEOUT_MS = 100;
|
||||
if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) {
|
||||
/* Steam may have put the controller back into non-reporting mode */
|
||||
WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE);
|
||||
}
|
||||
} else if (ctx->m_bUsingBluetooth) {
|
||||
const Uint32 INPUT_WAIT_TIMEOUT_MS = 3000;
|
||||
if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) {
|
||||
/* Bluetooth may have disconnected, try reopening the controller */
|
||||
size = -1;
|
||||
if (joystick) {
|
||||
if (!ctx->m_bInputOnly && !ctx->m_bUsingBluetooth &&
|
||||
ctx->device->product_id != USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP) {
|
||||
const Uint32 INPUT_WAIT_TIMEOUT_MS = 100;
|
||||
if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) {
|
||||
/* Steam may have put the controller back into non-reporting mode */
|
||||
WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE);
|
||||
}
|
||||
} else if (ctx->m_bUsingBluetooth) {
|
||||
const Uint32 INPUT_WAIT_TIMEOUT_MS = 3000;
|
||||
if (SDL_TICKS_PASSED(now, ctx->m_unLastInput + INPUT_WAIT_TIMEOUT_MS)) {
|
||||
/* Bluetooth may have disconnected, try reopening the controller */
|
||||
size = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2197,7 +2121,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -2227,15 +2151,7 @@ HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
|
|||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_PLAYER_LED,
|
||||
SDL_PlayerLEDHintChanged, ctx);
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
ctx->joystick = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2251,7 +2167,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic =
|
|||
HIDAPI_DriverNintendoClassic_UnregisterHints,
|
||||
HIDAPI_DriverNintendoClassic_IsEnabled,
|
||||
HIDAPI_DriverNintendoClassic_IsSupportedDevice,
|
||||
HIDAPI_DriverSwitch_GetDeviceName,
|
||||
HIDAPI_DriverSwitch_InitDevice,
|
||||
HIDAPI_DriverSwitch_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverSwitch_SetDevicePlayerIndex,
|
||||
|
@ -2275,7 +2190,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons =
|
|||
HIDAPI_DriverJoyCons_UnregisterHints,
|
||||
HIDAPI_DriverJoyCons_IsEnabled,
|
||||
HIDAPI_DriverJoyCons_IsSupportedDevice,
|
||||
HIDAPI_DriverSwitch_GetDeviceName,
|
||||
HIDAPI_DriverSwitch_InitDevice,
|
||||
HIDAPI_DriverSwitch_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverSwitch_SetDevicePlayerIndex,
|
||||
|
@ -2299,7 +2213,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
|
|||
HIDAPI_DriverSwitch_UnregisterHints,
|
||||
HIDAPI_DriverSwitch_IsEnabled,
|
||||
HIDAPI_DriverSwitch_IsSupportedDevice,
|
||||
HIDAPI_DriverSwitch_GetDeviceName,
|
||||
HIDAPI_DriverSwitch_InitDevice,
|
||||
HIDAPI_DriverSwitch_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverSwitch_SetDevicePlayerIndex,
|
||||
|
|
|
@ -131,6 +131,7 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
SDL_HIDAPI_Device *device;
|
||||
SDL_Joystick *joystick;
|
||||
EWiiCommunicationState m_eCommState;
|
||||
EWiiExtensionControllerType m_eExtensionControllerType;
|
||||
SDL_bool m_bUseButtonLabels;
|
||||
|
@ -185,12 +186,6 @@ HIDAPI_DriverWii_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name,
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverWii_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ReadInput(SDL_DriverWii_Context *ctx)
|
||||
{
|
||||
int size;
|
||||
|
@ -671,45 +666,35 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c
|
|||
static EWiiExtensionControllerType
|
||||
ReadExtensionControllerType(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
|
||||
EWiiExtensionControllerType eExtensionControllerType = k_eWiiExtensionControllerType_Unknown;
|
||||
const int MAX_ATTEMPTS = 20;
|
||||
int attempts = 0;
|
||||
|
||||
/* Create enough of a context to read the controller type from the device */
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (ctx) {
|
||||
ctx->device = device;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (device->dev) {
|
||||
const int MAX_ATTEMPTS = 20;
|
||||
int attempts = 0;
|
||||
for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
|
||||
Uint16 extension;
|
||||
if (SendExtensionIdentify(ctx, SDL_TRUE) &&
|
||||
ParseExtensionIdentifyResponse(ctx, &extension)) {
|
||||
Uint8 motion_plus_mode = 0;
|
||||
if ((extension & WII_EXTENSION_MOTIONPLUS_MASK) == WII_EXTENSION_MOTIONPLUS_ID) {
|
||||
motion_plus_mode = (Uint8)(extension >> 8);
|
||||
}
|
||||
if (motion_plus_mode || extension == WII_EXTENSION_UNINITIALIZED) {
|
||||
SendExtensionReset(ctx, SDL_TRUE);
|
||||
if (SendExtensionIdentify(ctx, SDL_TRUE)) {
|
||||
ParseExtensionIdentifyResponse(ctx, &extension);
|
||||
}
|
||||
}
|
||||
|
||||
eExtensionControllerType = GetExtensionType(extension);
|
||||
|
||||
/* Reset the Motion Plus controller if needed */
|
||||
if (motion_plus_mode) {
|
||||
ActivateMotionPlusWithMode(ctx, motion_plus_mode);
|
||||
}
|
||||
break;
|
||||
for (attempts = 0; attempts < MAX_ATTEMPTS; ++attempts) {
|
||||
Uint16 extension;
|
||||
if (SendExtensionIdentify(ctx, SDL_TRUE) &&
|
||||
ParseExtensionIdentifyResponse(ctx, &extension)) {
|
||||
Uint8 motion_plus_mode = 0;
|
||||
if ((extension & WII_EXTENSION_MOTIONPLUS_MASK) == WII_EXTENSION_MOTIONPLUS_ID) {
|
||||
motion_plus_mode = (Uint8)(extension >> 8);
|
||||
}
|
||||
if (motion_plus_mode || extension == WII_EXTENSION_UNINITIALIZED) {
|
||||
SendExtensionReset(ctx, SDL_TRUE);
|
||||
if (SendExtensionIdentify(ctx, SDL_TRUE)) {
|
||||
ParseExtensionIdentifyResponse(ctx, &extension);
|
||||
}
|
||||
}
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
eExtensionControllerType = GetExtensionType(extension);
|
||||
|
||||
/* Reset the Motion Plus controller if needed */
|
||||
if (motion_plus_mode) {
|
||||
ActivateMotionPlusWithMode(ctx, motion_plus_mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
SDL_free(ctx);
|
||||
}
|
||||
return eExtensionControllerType;
|
||||
}
|
||||
|
@ -717,41 +702,44 @@ ReadExtensionControllerType(SDL_HIDAPI_Device *device)
|
|||
static void
|
||||
UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
EWiiExtensionControllerType eExtensionControllerType = (EWiiExtensionControllerType)device->guid.data[15];
|
||||
const char *name = NULL;
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
|
||||
|
||||
switch (eExtensionControllerType) {
|
||||
case k_eWiiExtensionControllerType_None:
|
||||
name = "Nintendo Wii Remote";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_Nunchuk:
|
||||
name = "Nintendo Wii Remote with Nunchuk";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_Gamepad:
|
||||
name = "Nintendo Wii Remote with Classic Controller";
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_WiiUPro:
|
||||
name = "Nintendo Wii U Pro Controller";
|
||||
break;
|
||||
default:
|
||||
name = "Nintendo Wii Remote with Unknown Extension";
|
||||
break;
|
||||
}
|
||||
if (name && (!name || SDL_strcmp(name, device->name) != 0)) {
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(name);
|
||||
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name)));
|
||||
switch (ctx->m_eExtensionControllerType) {
|
||||
case k_eWiiExtensionControllerType_None:
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Wii Remote");
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_Nunchuk:
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Nunchuk");
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_Gamepad:
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Classic Controller");
|
||||
break;
|
||||
case k_eWiiExtensionControllerType_WiiUPro:
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Wii U Pro Controller");
|
||||
break;
|
||||
default:
|
||||
HIDAPI_SetDeviceName(device, "Nintendo Wii Remote with Unknown Extension");
|
||||
break;
|
||||
}
|
||||
device->guid.data[15] = ctx->m_eExtensionControllerType;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO) {
|
||||
EWiiExtensionControllerType eExtensionControllerType;
|
||||
SDL_DriverWii_Context *ctx;
|
||||
|
||||
ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
device->context = ctx;
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO) {
|
||||
ctx->m_eExtensionControllerType = ReadExtensionControllerType(device);
|
||||
|
||||
eExtensionControllerType = ReadExtensionControllerType(device);
|
||||
device->guid.data[15] = eExtensionControllerType;
|
||||
UpdateDeviceIdentity(device);
|
||||
}
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
|
@ -766,9 +754,9 @@ HIDAPI_DriverWii_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
static void
|
||||
HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
SDL_DriverWii_Context *ctx = device->context;
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
|
||||
|
||||
if (!ctx) {
|
||||
if (!ctx->joystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -780,23 +768,9 @@ HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID
|
|||
static SDL_bool
|
||||
HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverWii_Context *ctx;
|
||||
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverWii_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
goto error;
|
||||
}
|
||||
ctx->device = device;
|
||||
device->context = ctx;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx->m_eExtensionControllerType = (EWiiExtensionControllerType)device->guid.data[15];
|
||||
ctx->joystick = joystick;
|
||||
|
||||
InitializeExtension(ctx);
|
||||
|
||||
|
@ -841,21 +815,6 @@ HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
|||
ctx->m_unLastInput = SDL_GetTicks();
|
||||
|
||||
return SDL_TRUE;
|
||||
|
||||
error:
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
if (device->context) {
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1509,16 +1468,16 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
now = SDL_GetTicks();
|
||||
|
||||
while ((size = ReadInput(ctx)) > 0) {
|
||||
HandleInput(ctx, joystick);
|
||||
|
||||
if (joystick) {
|
||||
HandleInput(ctx, joystick);
|
||||
}
|
||||
ctx->m_unLastInput = now;
|
||||
}
|
||||
|
||||
|
@ -1533,36 +1492,38 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
size = -1;
|
||||
}
|
||||
|
||||
/* These checks aren't needed on the Wii U Pro Controller */
|
||||
if (ctx->m_eExtensionControllerType != k_eWiiExtensionControllerType_WiiUPro) {
|
||||
if (joystick) {
|
||||
/* These checks aren't needed on the Wii U Pro Controller */
|
||||
if (ctx->m_eExtensionControllerType != k_eWiiExtensionControllerType_WiiUPro) {
|
||||
|
||||
/* Check to see if the Motion Plus extension status has changed */
|
||||
if (ctx->m_unNextMotionPlusCheck &&
|
||||
SDL_TICKS_PASSED(now, ctx->m_unNextMotionPlusCheck)) {
|
||||
CheckMotionPlusConnection(ctx);
|
||||
if (NeedsPeriodicMotionPlusCheck(ctx, SDL_FALSE)) {
|
||||
SchedulePeriodicMotionPlusCheck(ctx);
|
||||
} else {
|
||||
ctx->m_unNextMotionPlusCheck = 0;
|
||||
/* Check to see if the Motion Plus extension status has changed */
|
||||
if (ctx->m_unNextMotionPlusCheck &&
|
||||
SDL_TICKS_PASSED(now, ctx->m_unNextMotionPlusCheck)) {
|
||||
CheckMotionPlusConnection(ctx);
|
||||
if (NeedsPeriodicMotionPlusCheck(ctx, SDL_FALSE)) {
|
||||
SchedulePeriodicMotionPlusCheck(ctx);
|
||||
} else {
|
||||
ctx->m_unNextMotionPlusCheck = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Request a status update periodically to make sure our battery value is up to date */
|
||||
if (!ctx->m_unLastStatus ||
|
||||
SDL_TICKS_PASSED(now, ctx->m_unLastStatus + STATUS_UPDATE_TIME_MS)) {
|
||||
Uint8 data[2];
|
||||
/* Request a status update periodically to make sure our battery value is up to date */
|
||||
if (!ctx->m_unLastStatus ||
|
||||
SDL_TICKS_PASSED(now, ctx->m_unLastStatus + STATUS_UPDATE_TIME_MS)) {
|
||||
Uint8 data[2];
|
||||
|
||||
data[0] = k_eWiiOutputReportIDs_StatusRequest;
|
||||
data[1] = ctx->m_bRumbleActive;
|
||||
WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
|
||||
data[0] = k_eWiiOutputReportIDs_StatusRequest;
|
||||
data[1] = ctx->m_bRumbleActive;
|
||||
WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
|
||||
|
||||
ctx->m_unLastStatus = now;
|
||||
ctx->m_unLastStatus = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0 || ctx->m_bDisconnected) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -1578,15 +1539,7 @@ HIDAPI_DriverWii_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick
|
|||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED,
|
||||
SDL_PlayerLEDHintChanged, ctx);
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
ctx->joystick = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1602,7 +1555,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii =
|
|||
HIDAPI_DriverWii_UnregisterHints,
|
||||
HIDAPI_DriverWii_IsEnabled,
|
||||
HIDAPI_DriverWii_IsSupportedDevice,
|
||||
HIDAPI_DriverWii_GetDeviceName,
|
||||
HIDAPI_DriverWii_InitDevice,
|
||||
HIDAPI_DriverWii_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverWii_SetDevicePlayerIndex,
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
typedef struct {
|
||||
SDL_HIDAPI_Device *device;
|
||||
SDL_Joystick *joystick;
|
||||
int player_index;
|
||||
SDL_bool player_lights;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
|
@ -108,12 +109,6 @@ HIDAPI_DriverXbox360_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *na
|
|||
#endif
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverXbox360_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on)
|
||||
{
|
||||
const SDL_bool blink = SDL_FALSE;
|
||||
|
@ -151,6 +146,17 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c
|
|||
static SDL_bool
|
||||
HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverXbox360_Context *ctx;
|
||||
|
||||
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
|
||||
device->context = ctx;
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
|
@ -165,7 +171,7 @@ HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic
|
|||
{
|
||||
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
|
||||
|
||||
if (!ctx) {
|
||||
if (!ctx->joystick) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -177,22 +183,10 @@ HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic
|
|||
static SDL_bool
|
||||
HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverXbox360_Context *ctx;
|
||||
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context;
|
||||
|
||||
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->device = device;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
ctx->joystick = joystick;
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
/* Initialize player index (needed for setting LEDs) */
|
||||
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
|
||||
|
@ -343,8 +337,7 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
|
@ -352,6 +345,10 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
#ifdef DEBUG_XBOX_PROTOCOL
|
||||
HIDAPI_DumpPacket("Xbox 360 packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data[0] == 0x00) {
|
||||
HIDAPI_DriverXbox360_HandleStatePacket(joystick, ctx, data, size);
|
||||
}
|
||||
|
@ -359,7 +356,7 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -372,17 +369,7 @@ HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
|
|||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
|
||||
SDL_PlayerLEDHintChanged, ctx);
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
ctx->joystick = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -398,7 +385,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
|
|||
HIDAPI_DriverXbox360_UnregisterHints,
|
||||
HIDAPI_DriverXbox360_IsEnabled,
|
||||
HIDAPI_DriverXbox360_IsSupportedDevice,
|
||||
HIDAPI_DriverXbox360_GetDeviceName,
|
||||
HIDAPI_DriverXbox360_InitDevice,
|
||||
HIDAPI_DriverXbox360_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverXbox360_SetDevicePlayerIndex,
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
typedef struct {
|
||||
SDL_HIDAPI_Device *device;
|
||||
SDL_bool connected;
|
||||
SDL_bool opened;
|
||||
int player_index;
|
||||
SDL_bool player_lights;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
|
@ -86,12 +85,6 @@ HIDAPI_DriverXbox360W_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *n
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverXbox360W_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return "Xbox 360 Wireless Controller";
|
||||
}
|
||||
|
||||
static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on)
|
||||
{
|
||||
const SDL_bool blink = SDL_FALSE;
|
||||
|
@ -150,6 +143,8 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
|
|||
/* Requests controller presence information from the wireless dongle */
|
||||
const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
HIDAPI_SetDeviceName(device, "Xbox 360 Wireless Controller");
|
||||
|
||||
ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
|
@ -157,12 +152,6 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
|
|||
}
|
||||
ctx->device = device;
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
if (SDL_hid_write(device->dev, init_packet, sizeof(init_packet)) != sizeof(init_packet)) {
|
||||
|
@ -200,8 +189,6 @@ HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
|
|||
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
ctx->opened = SDL_TRUE;
|
||||
|
||||
/* Initialize player index (needed for setting LEDs) */
|
||||
ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
|
||||
ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE);
|
||||
|
@ -367,11 +354,9 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
|
|||
}
|
||||
}
|
||||
|
||||
if (joystick) {
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
}
|
||||
if (size < 0 && device->num_joysticks > 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
@ -383,22 +368,11 @@ HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
|
||||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
|
||||
SDL_PlayerLEDHintChanged, ctx);
|
||||
|
||||
ctx->opened = SDL_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
|
||||
|
@ -409,7 +383,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
|
|||
HIDAPI_DriverXbox360W_UnregisterHints,
|
||||
HIDAPI_DriverXbox360W_IsEnabled,
|
||||
HIDAPI_DriverXbox360W_IsSupportedDevice,
|
||||
HIDAPI_DriverXbox360W_GetDeviceName,
|
||||
HIDAPI_DriverXbox360W_InitDevice,
|
||||
HIDAPI_DriverXbox360W_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverXbox360W_SetDevicePlayerIndex,
|
||||
|
|
|
@ -106,7 +106,6 @@ typedef struct {
|
|||
Uint32 start_time;
|
||||
Uint8 sequence;
|
||||
Uint32 send_time;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
SDL_bool has_guide_packet;
|
||||
SDL_bool has_color_led;
|
||||
SDL_bool has_paddles;
|
||||
|
@ -116,6 +115,7 @@ typedef struct {
|
|||
Uint8 high_frequency_rumble;
|
||||
Uint8 left_trigger_rumble;
|
||||
Uint8 right_trigger_rumble;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
} SDL_DriverXboxOne_Context;
|
||||
|
||||
static SDL_bool
|
||||
|
@ -306,34 +306,8 @@ HIDAPI_DriverXboxOne_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *na
|
|||
return (type == SDL_CONTROLLER_TYPE_XBOXONE) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverXboxOne_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
static SDL_bool HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
|
||||
static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx;
|
||||
|
||||
|
@ -343,12 +317,6 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_free(ctx);
|
||||
SDL_SetError("Couldn't open %s", device->path);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
ctx->vendor_id = device->vendor_id;
|
||||
|
@ -372,6 +340,31 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
|
|||
SDL_Log("Controller version: %d (0x%.4x)\n", device->version, device->version);
|
||||
#endif
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverXboxOne_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
|
||||
|
||||
ctx->low_frequency_rumble = 0;
|
||||
ctx->high_frequency_rumble = 0;
|
||||
ctx->left_trigger_rumble = 0;
|
||||
ctx->right_trigger_rumble = 0;
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = 15;
|
||||
if (ctx->has_share_button) {
|
||||
|
@ -975,12 +968,19 @@ HIDAPI_DriverXboxOne_UpdateInitState(SDL_HIDAPI_Device *device, SDL_DriverXboxOn
|
|||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
|
||||
SDL_Joystick *joystick = NULL;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
} else {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
|
||||
#ifdef DEBUG_XBOX_PROTOCOL
|
||||
HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size);
|
||||
|
@ -988,6 +988,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
if (ctx->bluetooth) {
|
||||
switch (data[0]) {
|
||||
case 0x01:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
if (size >= 16) {
|
||||
HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(joystick, ctx, data, size);
|
||||
} else {
|
||||
|
@ -997,9 +1000,15 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
}
|
||||
break;
|
||||
case 0x02:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(joystick, ctx, data, size);
|
||||
break;
|
||||
case 0x04:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(joystick, ctx, data, size);
|
||||
break;
|
||||
default:
|
||||
|
@ -1045,6 +1054,10 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
break;
|
||||
case 0x03:
|
||||
/* Controller status update */
|
||||
if (!joystick) {
|
||||
/* We actually want to handle this packet any time it arrives */
|
||||
/*break;*/
|
||||
}
|
||||
HIDAPI_DriverXboxOne_HandleStatusPacket(joystick, ctx, data, size);
|
||||
break;
|
||||
case 0x04:
|
||||
|
@ -1054,6 +1067,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
/* Unknown chatty controller information, sent by both sides */
|
||||
break;
|
||||
case 0x07:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverXboxOne_HandleModePacket(joystick, ctx, data, size);
|
||||
break;
|
||||
case 0x1E:
|
||||
|
@ -1066,6 +1082,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
The controller sends that in response to this request:
|
||||
0x1E 0x30 0x07 0x01 0x04
|
||||
*/
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
#ifdef SET_SERIAL_AFTER_OPEN
|
||||
if (size == 20 && data[3] == 0x10) {
|
||||
HIDAPI_DriverXboxOne_HandleSerialIDPacket(joystick, ctx, data, size);
|
||||
|
@ -1082,6 +1101,9 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, ctx, data, size);
|
||||
break;
|
||||
default:
|
||||
|
@ -1111,37 +1133,14 @@ HIDAPI_DriverXboxOne_UpdateJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
|
|||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_Joystick *joystick = NULL;
|
||||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return HIDAPI_DriverXboxOne_UpdateJoystick(device, joystick);
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1157,7 +1156,6 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
|
|||
HIDAPI_DriverXboxOne_UnregisterHints,
|
||||
HIDAPI_DriverXboxOne_IsEnabled,
|
||||
HIDAPI_DriverXboxOne_IsSupportedDevice,
|
||||
HIDAPI_DriverXboxOne_GetDeviceName,
|
||||
HIDAPI_DriverXboxOne_InitDevice,
|
||||
HIDAPI_DriverXboxOne_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverXboxOne_SetDevicePlayerIndex,
|
||||
|
|
|
@ -314,6 +314,20 @@ HIDAPI_CleanupDeviceDriver(SDL_HIDAPI_Device *device)
|
|||
|
||||
device->driver->FreeDevice(device);
|
||||
device->driver = NULL;
|
||||
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
{
|
||||
if (device->dev) {
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
|
||||
if (device->context) {
|
||||
SDL_free(device->context);
|
||||
device->context = NULL;
|
||||
}
|
||||
}
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -344,18 +358,27 @@ HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device)
|
|||
return; /* Already setup */
|
||||
}
|
||||
|
||||
device->driver = HIDAPI_GetDeviceDriver(device);
|
||||
if (device->driver) {
|
||||
const char *name = device->driver->GetDeviceName(device->name, device->vendor_id, device->product_id);
|
||||
if (name && name != device->name) {
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(name);
|
||||
}
|
||||
/* Make sure we can open the device and leave it open for the driver */
|
||||
device->dev = SDL_hid_open_path(device->path, 0);
|
||||
if (!device->dev) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_SetupDeviceDriver() couldn't open %s: %s\n",
|
||||
device->path, SDL_GetError());
|
||||
return;
|
||||
}
|
||||
SDL_hid_set_nonblocking(device->dev, 1);
|
||||
|
||||
device->driver = HIDAPI_GetDeviceDriver(device);
|
||||
|
||||
/* Initialize the device, which may cause a connected event */
|
||||
if (device->driver && !device->driver->InitDevice(device)) {
|
||||
device->driver = NULL;
|
||||
HIDAPI_CleanupDeviceDriver(device);
|
||||
}
|
||||
|
||||
if (!device->driver && device->dev) {
|
||||
/* No driver claimed this device, go ahead and close it */
|
||||
SDL_hid_close(device->dev);
|
||||
device->dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,6 +504,32 @@ HIDAPI_JoystickInstanceIsUnique(SDL_HIDAPI_Device *device, SDL_JoystickID joysti
|
|||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name)
|
||||
{
|
||||
if (name && *name && SDL_strcmp(name, device->name) != 0) {
|
||||
SDL_free(device->name);
|
||||
device->name = SDL_strdup(name);
|
||||
SDL_SetJoystickGUIDCRC(&device->guid, SDL_crc16(0, name, SDL_strlen(name)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 product_id)
|
||||
{
|
||||
/* Don't set the device product ID directly, or we'll constantly re-enumerate this device */
|
||||
SDL_SetJoystickGUIDProduct(&device->guid, product_id);
|
||||
}
|
||||
|
||||
void
|
||||
HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial)
|
||||
{
|
||||
if (serial && *serial && (!device->serial || SDL_strcmp(serial, device->serial) != 0)) {
|
||||
SDL_free(device->serial);
|
||||
device->serial = SDL_strdup(serial);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
|
||||
{
|
||||
|
@ -1102,6 +1151,13 @@ HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
|||
}
|
||||
hwdata->device = device;
|
||||
|
||||
/* Process any pending reports before opening the device */
|
||||
SDL_LockMutex(device->dev_lock);
|
||||
device->updating = SDL_TRUE;
|
||||
device->driver->UpdateDevice(device);
|
||||
device->updating = SDL_FALSE;
|
||||
SDL_UnlockMutex(device->dev_lock);
|
||||
|
||||
if (!device->driver->OpenJoystick(device, joystick)) {
|
||||
/* The open failed, mark this device as disconnected and update devices */
|
||||
HIDAPI_JoystickDisconnected(device, joystickID);
|
||||
|
|
|
@ -103,7 +103,6 @@ typedef struct _SDL_HIDAPI_DeviceDriver
|
|||
void (*UnregisterHints)(SDL_HintCallback callback, void *userdata);
|
||||
SDL_bool (*IsEnabled)(void);
|
||||
SDL_bool (*IsSupportedDevice)(SDL_HIDAPI_Device *device, const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
|
||||
const char *(*GetDeviceName)(const char *name, Uint16 vendor_id, Uint16 product_id);
|
||||
SDL_bool (*InitDevice)(SDL_HIDAPI_Device *device);
|
||||
int (*GetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id);
|
||||
void (*SetDevicePlayerIndex)(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index);
|
||||
|
@ -146,6 +145,9 @@ extern SDL_bool HIDAPI_IsDeviceTypePresent(SDL_GameControllerType type);
|
|||
extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
|
||||
|
||||
extern void HIDAPI_UpdateDevices(void);
|
||||
extern void HIDAPI_SetDeviceName(SDL_HIDAPI_Device *device, const char *name);
|
||||
extern void HIDAPI_SetDeviceProduct(SDL_HIDAPI_Device *device, Uint16 product_id);
|
||||
extern void HIDAPI_SetDeviceSerial(SDL_HIDAPI_Device *device, const char *serial);
|
||||
extern SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID);
|
||||
extern void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID);
|
||||
|
||||
|
|
Loading…
Reference in New Issue