Added HIDAPI support for the 8BitDo Ultimate 2 Wireless Controller running firmware v1.03 or newer over Bluetooth.
This commit is contained in:
8BitDo 2025-04-01 00:56:01 +08:00 committed by GitHub
parent 6b1d6bfbe7
commit e18c6bd2e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 465 additions and 1 deletions

View file

@ -712,6 +712,7 @@
<ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
<ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c" />

View file

@ -63,6 +63,7 @@
<ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
<ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c" />

View file

@ -582,6 +582,7 @@
<ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
<ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c" />

View file

@ -1187,6 +1187,9 @@
<ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c">
<Filter>joystick\gdk</Filter>
</ClCompile>
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>

View file

@ -388,6 +388,7 @@
F32DDAD42AB795A30041EAA5 /* SDL_audioresample.c in Sources */ = {isa = PBXBuildFile; fileRef = F32DDACE2AB795A30041EAA5 /* SDL_audioresample.c */; };
F338A1182D1B37D8007CDFDF /* SDL_tray.m in Sources */ = {isa = PBXBuildFile; fileRef = F338A1172D1B37D8007CDFDF /* SDL_tray.m */; };
F338A11A2D1B37E4007CDFDF /* SDL_tray.c in Sources */ = {isa = PBXBuildFile; fileRef = F338A1192D1B37E4007CDFDF /* SDL_tray.c */; };
F3395BA82D9A5971007246C8 /* SDL_hidapi_8bitdo.c in Sources */ = {isa = PBXBuildFile; fileRef = F3395BA72D9A5971007246C8 /* SDL_hidapi_8bitdo.c */; };
F34400342D40217A003F26D7 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = F373DA182D388A1E002158FA /* LICENSE.txt */; };
F34400362D40217A003F26D7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = F373DA192D388A1E002158FA /* README.md */; };
F344003D2D4022E1003F26D7 /* INSTALL.md in Resources */ = {isa = PBXBuildFile; fileRef = F344003C2D4022E1003F26D7 /* INSTALL.md */; };
@ -946,6 +947,7 @@
F32DDACE2AB795A30041EAA5 /* SDL_audioresample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audioresample.c; sourceTree = "<group>"; };
F338A1172D1B37D8007CDFDF /* SDL_tray.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDL_tray.m; sourceTree = "<group>"; };
F338A1192D1B37E4007CDFDF /* SDL_tray.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_tray.c; sourceTree = "<group>"; };
F3395BA72D9A5971007246C8 /* SDL_hidapi_8bitdo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_8bitdo.c; sourceTree = "<group>"; };
F344003C2D4022E1003F26D7 /* INSTALL.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = INSTALL.md; sourceTree = "<group>"; };
F362B9152B3349E200D30B94 /* controller_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controller_list.h; sourceTree = "<group>"; };
F362B9162B3349E200D30B94 /* SDL_gamepad_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamepad_c.h; sourceTree = "<group>"; };
@ -1923,9 +1925,10 @@
A7D8A7BE23E2513E00DCD162 /* hidapi */ = {
isa = PBXGroup;
children = (
89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */,
F3395BA72D9A5971007246C8 /* SDL_hidapi_8bitdo.c */,
F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */,
A7D8A7C923E2513E00DCD162 /* SDL_hidapi_gamecube.c */,
89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */,
F3F07D59269640160074468B /* SDL_hidapi_luna.c */,
F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */,
F388C95428B5F6F600661ECF /* SDL_hidapi_ps3.c */,
@ -3075,6 +3078,7 @@
000028F8113A53F4333E0000 /* SDL_main_callbacks.c in Sources */,
000098E9DAA43EF6FF7F0000 /* SDL_camera.c in Sources */,
F310138E2C1F2CB700FBE946 /* SDL_random.c in Sources */,
F3395BA82D9A5971007246C8 /* SDL_hidapi_8bitdo.c in Sources */,
00001B2471F503DD3C1B0000 /* SDL_camera_dummy.c in Sources */,
00002B20A48E055EB0350000 /* SDL_camera_coremedia.m in Sources */,
000080903BC03006F24E0000 /* SDL_filesystem.c in Sources */,

View file

@ -1734,6 +1734,19 @@ extern "C" {
*/
#define SDL_HINT_JOYSTICK_HIDAPI_LG4FF "SDL_JOYSTICK_HIDAPI_LG4FF"
/**
* A variable controlling whether the HIDAPI driver for 8BitDo
* controllers should be used.
*
* This variable can be set to the following values:
*
* "0" - HIDAPI driver is not used.
* "1" - HIDAPI driver is used.
*
* The default is the value of SDL_HINT_JOYSTICK_HIDAPI
*/
#define SDL_HINT_JOYSTICK_HIDAPI_8BITDO "SDL_JOYSTICK_HIDAPI_8BITDO"
/**
* A variable controlling whether the HIDAPI driver for Nintendo Switch
* controllers should be used.

View file

@ -814,6 +814,8 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
} else if (SDL_IsJoystickHoriSteamController(vendor, product)) {
/* The Wireless HORIPad for Steam has QAM, Steam, Capsense L/R Sticks, 2 rear buttons, and 2 misc buttons */
SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17", sizeof(mapping_string));
} else if (SDL_IsJoystick8BitDoController(vendor, product)) {
SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,paddle3:b14,paddle4:b13", sizeof(mapping_string));
} else {
switch (SDL_GetGamepadTypeFromGUID(guid, NULL)) {
case SDL_GAMEPAD_TYPE_PS4:

View file

@ -3029,6 +3029,11 @@ bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id)
return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT);
}
bool SDL_IsJoystick8BitDoController(Uint16 vendor_id, Uint16 product_id)
{
return vendor_id == USB_VENDOR_8BITDO && (product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS);
}
bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id)
{
EControllerType eType = GuessControllerType(vendor_id, product_id);

View file

@ -135,6 +135,9 @@ extern bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
// Function to return whether a joystick is a HORI Steam controller
extern bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id);
// Function to return whether a joystick is a 8BitDo controller
extern bool SDL_IsJoystick8BitDoController(Uint16 vendor_id, Uint16 product_id);
// Function to return whether a joystick is a Steam Deck
extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id);

View file

@ -0,0 +1,425 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_JOYSTICK_HIDAPI
#include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h"
#ifdef SDL_JOYSTICK_HIDAPI_8BITDO
// Define this if you want to log all packets from the controller
// #define DEBUG_8BITDO_PROTOCOL
enum
{
SDL_GAMEPAD_BUTTON_8BITDO_L4 = 11,
SDL_GAMEPAD_BUTTON_8BITDO_R4,
SDL_GAMEPAD_BUTTON_8BITDO_PL,
SDL_GAMEPAD_BUTTON_8BITDO_PR,
SDL_GAMEPAD_NUM_8BITDO_BUTTONS,
};
#define ABITDO_GYRO_SCALE 14.2842f
#define ABITDO_ACCEL_SCALE 4096.f
typedef struct
{
bool sensors_supported;
bool touchpad_01_supported;
bool touchpad_02_supported;
bool rumble_supported;
bool rumble_type;
bool rgb_supported;
bool player_led_supported;
Uint8 serial[6];
Uint16 version;
Uint16 version_beta;
float accelScale;
float gyroScale;
Uint8 last_state[USB_PACKET_LENGTH];
} SDL_Driver8BitDo_Context;
#pragma pack(push,1)
typedef struct
{
bool sensors_supported;
bool touchpad_01_supported;
bool touchpad_02_supported;
bool rumble_supported;
bool rumble_type;
bool rgb_supported;
Uint8 device_type;
Uint8 serial[6];
Uint16 version;
Uint16 version_beta;
Uint16 pid;
} ABITDO_DEVICE_INFO;
typedef struct
{
// Accelerometer values
short sAccelX;
short sAccelY;
short sAccelZ;
// Gyroscope values
short sGyroX;
short sGyroY;
short sGyroZ;
} ABITDO_SENSORS;
#pragma pack(pop)
static void HIDAPI_Driver8BitDo_RegisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, callback, userdata);
}
static void HIDAPI_Driver8BitDo_UnregisterHints(SDL_HintCallback callback, void *userdata)
{
SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, callback, userdata);
}
static bool HIDAPI_Driver8BitDo_IsEnabled(void)
{
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
}
static bool HIDAPI_Driver8BitDo_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
return SDL_IsJoystick8BitDoController(vendor_id, product_id);
}
static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
{
SDL_Driver8BitDo_Context *ctx;
ctx = (SDL_Driver8BitDo_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) {
return false;
}
device->context = ctx;
if (device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
ctx->sensors_supported = true;
ctx->rumble_supported = true;
ctx->rumble_type = 0;
ctx->rgb_supported = true;
}
return HIDAPI_JoystickConnected(device, NULL);
}
static int HIDAPI_Driver8BitDo_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{
return -1;
}
static void HIDAPI_Driver8BitDo_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{
}
static bool HIDAPI_Driver8BitDo_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
SDL_AssertJoysticksLocked();
SDL_zeroa(ctx->last_state);
// Initialize the joystick capabilities
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
joystick->nhats = 1;
if (ctx->sensors_supported) {
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
ctx->accelScale = SDL_STANDARD_GRAVITY / ABITDO_ACCEL_SCALE;
ctx->gyroScale = SDL_PI_F / 180.0f / ABITDO_GYRO_SCALE;
}
return true;
}
static bool HIDAPI_Driver8BitDo_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
if (ctx->rumble_supported) {
Uint8 rumble_packet[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
rumble_packet[1] = low_frequency_rumble >> 8;
rumble_packet[2] = high_frequency_rumble >> 8;
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
return true;
} else {
return SDL_Unsupported();
}
}
static bool HIDAPI_Driver8BitDo_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static Uint32 HIDAPI_Driver8BitDo_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
Uint32 caps = 0;
if (ctx->rumble_supported) {
caps |= SDL_JOYSTICK_CAP_RUMBLE;
}
if (ctx->rgb_supported) {
caps |= SDL_JOYSTICK_CAP_RGB_LED;
}
return caps;
}
static bool HIDAPI_Driver8BitDo_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
return SDL_Unsupported();
}
static bool HIDAPI_Driver8BitDo_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
static bool HIDAPI_Driver8BitDo_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
{
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
if (ctx->sensors_supported) {
return true;
}
return SDL_Unsupported();
}
static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
{
Sint16 axis;
Uint64 timestamp = SDL_GetTicksNS();
if (data[0] != 0x03 && data[0] != 0x01) {
// We don't know how to handle this report
return;
}
if (ctx->last_state[1] != data[1]) {
Uint8 hat;
switch (data[1]) {
case 0:
hat = SDL_HAT_UP;
break;
case 1:
hat = SDL_HAT_RIGHTUP;
break;
case 2:
hat = SDL_HAT_RIGHT;
break;
case 3:
hat = SDL_HAT_RIGHTDOWN;
break;
case 4:
hat = SDL_HAT_DOWN;
break;
case 5:
hat = SDL_HAT_LEFTDOWN;
break;
case 6:
hat = SDL_HAT_LEFT;
break;
case 7:
hat = SDL_HAT_LEFTUP;
break;
default:
hat = SDL_HAT_CENTERED;
break;
}
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
}
if (ctx->last_state[8] != data[8]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[8] & 0x01) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[8] & 0x02) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[8] & 0x08) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[8] & 0x10) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[8] & 0x40) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[8] & 0x80) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_PL, ((data[8] & 0x20) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_PR, ((data[8] & 0x04) != 0));
}
if (ctx->last_state[9] != data[9]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[9] & 0x10) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[9] & 0x04) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[9] & 0x08) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[9] & 0x20) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
}
if (ctx->last_state[10] != data[10]) {
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_L4, ((data[10] & 0x01) != 0));
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_R4, ((data[10] & 0x02) != 0));
}
#define READ_STICK_AXIS(offset) \
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16))
{
axis = READ_STICK_AXIS(2);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
axis = READ_STICK_AXIS(3);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
axis = READ_STICK_AXIS(4);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
axis = READ_STICK_AXIS(5);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
}
#undef READ_STICK_AXIS
#define READ_TRIGGER_AXIS(offset) \
(Sint16)(((int)data[offset] * 257) - 32768)
{
axis = READ_TRIGGER_AXIS(7);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
axis = READ_TRIGGER_AXIS(6);
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
}
#undef READ_TRIGGER_AXIS
SDL_PowerState state;
int percent;
Uint8 status = data[14] >> 7;
Uint8 level = (data[14] & 0x7f);
if (level == 100) {
status = 2;
}
switch (status) {
case 0:
state = SDL_POWERSTATE_ON_BATTERY;
percent = level;
break;
case 1:
state = SDL_POWERSTATE_CHARGING;
percent = level;
break;
case 2:
state = SDL_POWERSTATE_CHARGED;
percent = 100;
break;
default:
state = SDL_POWERSTATE_UNKNOWN;
percent = 0;
break;
}
SDL_SendJoystickPowerInfo(joystick, state, percent);
if (ctx->sensors_supported) {
Uint64 sensor_timestamp;
float values[3];
ABITDO_SENSORS *sensors = (ABITDO_SENSORS *)&data[15];
sensor_timestamp = timestamp;
values[0] = (sensors->sGyroX) * (ctx->gyroScale);
values[1] = (sensors->sGyroZ) * (ctx->gyroScale);
values[2] = (sensors->sGyroY) * (ctx->gyroScale);
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, values, 3);
values[0] = (sensors->sAccelX) * (ctx->accelScale);
values[1] = (sensors->sAccelZ) * (ctx->accelScale);
values[2] = (sensors->sAccelY) * (ctx->accelScale);
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, values, 3);
}
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
}
static bool HIDAPI_Driver8BitDo_UpdateDevice(SDL_HIDAPI_Device *device)
{
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
SDL_Joystick *joystick = NULL;
Uint8 data[USB_PACKET_LENGTH];
int size = 0;
if (device->num_joysticks > 0) {
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
} else {
return false;
}
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
if (!joystick) {
continue;
}
HIDAPI_Driver8BitDo_HandleStatePacket(joystick, ctx, data, size);
}
if (size < 0) {
// Read error, device is disconnected
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
return (size >= 0);
}
static void HIDAPI_Driver8BitDo_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
}
static void HIDAPI_Driver8BitDo_FreeDevice(SDL_HIDAPI_Device *device)
{
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_Driver8BitDo = {
SDL_HINT_JOYSTICK_HIDAPI_8BITDO,
true,
HIDAPI_Driver8BitDo_RegisterHints,
HIDAPI_Driver8BitDo_UnregisterHints,
HIDAPI_Driver8BitDo_IsEnabled,
HIDAPI_Driver8BitDo_IsSupportedDevice,
HIDAPI_Driver8BitDo_InitDevice,
HIDAPI_Driver8BitDo_GetDevicePlayerIndex,
HIDAPI_Driver8BitDo_SetDevicePlayerIndex,
HIDAPI_Driver8BitDo_UpdateDevice,
HIDAPI_Driver8BitDo_OpenJoystick,
HIDAPI_Driver8BitDo_RumbleJoystick,
HIDAPI_Driver8BitDo_RumbleJoystickTriggers,
HIDAPI_Driver8BitDo_GetJoystickCapabilities,
HIDAPI_Driver8BitDo_SetJoystickLED,
HIDAPI_Driver8BitDo_SendJoystickEffect,
HIDAPI_Driver8BitDo_SetJoystickSensorsEnabled,
HIDAPI_Driver8BitDo_CloseJoystick,
HIDAPI_Driver8BitDo_FreeDevice,
};
#endif // SDL_JOYSTICK_HIDAPI_8BitDo
#endif // SDL_JOYSTICK_HIDAPI

View file

@ -88,6 +88,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
#ifdef SDL_JOYSTICK_HIDAPI_LG4FF
&SDL_HIDAPI_DriverLg4ff,
#endif
#ifdef SDL_JOYSTICK_HIDAPI_8BITDO
&SDL_HIDAPI_Driver8BitDo,
#endif
};
static int SDL_HIDAPI_numdrivers = 0;
static SDL_AtomicInt SDL_HIDAPI_updating_devices;

View file

@ -41,6 +41,7 @@
#define SDL_JOYSTICK_HIDAPI_SHIELD
#define SDL_JOYSTICK_HIDAPI_STEAM_HORI
#define SDL_JOYSTICK_HIDAPI_LG4FF
#define SDL_JOYSTICK_HIDAPI_8BITDO
// Joystick capability definitions
#define SDL_JOYSTICK_CAP_MONO_LED 0x00000001
@ -159,6 +160,7 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLg4ff;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_Driver8BitDo;
// Return true if a HID device is present and supported as a joystick of the given type
extern bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type);

View file

@ -61,6 +61,7 @@
#define USB_PRODUCT_8BITDO_XBOX_CONTROLLER1 0x2002 // Ultimate Wired Controller for Xbox
#define USB_PRODUCT_8BITDO_XBOX_CONTROLLER2 0x3106 // Ultimate Wireless / Pro 2 Wired Controller
#define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS 0x6012
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103