mirror of
https://github.com/libsdl-org/SDL.git
synced 2024-11-24 03:13:34 +08:00
joystick: Add HIDAPI driver for NVIDIA SHIELD 2017 controller
Basic input already works using the OS HID driver, but this enables force feedback and battery state reporting.
This commit is contained in:
parent
3242265ff1
commit
6e712d2440
@ -89,7 +89,7 @@ SRCS+= SDL_systimer.c
|
||||
SRCS+= SDL_sysloadso.c
|
||||
SRCS+= SDL_sysfilesystem.c
|
||||
SRCS+= SDL_os2joystick.c SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
|
||||
SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
|
||||
SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
|
||||
SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
|
||||
SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
|
||||
SRCS+= SDL_dummysensor.c
|
||||
|
@ -65,7 +65,7 @@ SRCS+= SDL_systimer.c
|
||||
SRCS+= SDL_sysloadso.c
|
||||
SRCS+= SDL_sysfilesystem.c
|
||||
SRCS+= SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
|
||||
SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
|
||||
SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
|
||||
SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
|
||||
SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
|
||||
SRCS+= SDL_dummysensor.c
|
||||
|
@ -595,6 +595,7 @@
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps5.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
|
||||
|
@ -1065,6 +1065,9 @@
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c">
|
||||
<Filter>joystick\hidapi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c">
|
||||
<Filter>joystick\hidapi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c">
|
||||
<Filter>joystick\hidapi</Filter>
|
||||
</ClCompile>
|
||||
|
@ -486,6 +486,7 @@
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps5.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
|
||||
|
@ -1058,6 +1058,9 @@
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_rumble.c">
|
||||
<Filter>joystick\hidapi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_shield.c">
|
||||
<Filter>joystick\hidapi</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_stadia.c">
|
||||
<Filter>joystick\hidapi</Filter>
|
||||
</ClCompile>
|
||||
|
@ -93,6 +93,15 @@
|
||||
75E09169241EA924004729E1 /* SDL_virtualjoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */; };
|
||||
75E0916A241EA924004729E1 /* SDL_virtualjoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */; };
|
||||
75E0916B241EA924004729E1 /* SDL_virtualjoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */; };
|
||||
9846B07C287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B07D287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B07E287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B07F287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B080287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B081287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B082287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B083287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
9846B084287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
|
||||
A1626A3E2617006A003F1973 /* SDL_triangle.c in Sources */ = {isa = PBXBuildFile; fileRef = A1626A3D2617006A003F1973 /* SDL_triangle.c */; };
|
||||
A1626A3F2617006A003F1973 /* SDL_triangle.c in Sources */ = {isa = PBXBuildFile; fileRef = A1626A3D2617006A003F1973 /* SDL_triangle.c */; };
|
||||
A1626A402617006A003F1973 /* SDL_triangle.c in Sources */ = {isa = PBXBuildFile; fileRef = A1626A3D2617006A003F1973 /* SDL_triangle.c */; };
|
||||
@ -3629,6 +3638,7 @@
|
||||
5C2EF7001FC9EF0F003F5197 /* SDL_egl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_egl.h; sourceTree = "<group>"; };
|
||||
75E09158241EA924004729E1 /* SDL_virtualjoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_virtualjoystick.c; sourceTree = "<group>"; };
|
||||
75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = "<group>"; };
|
||||
9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_shield.c; sourceTree = "<group>"; };
|
||||
A1626A3D2617006A003F1973 /* SDL_triangle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_triangle.c; sourceTree = "<group>"; };
|
||||
A1626A512617008C003F1973 /* SDL_triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_triangle.h; sourceTree = "<group>"; };
|
||||
A1BB8B6127F6CF320057CFA8 /* SDL_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_list.c; sourceTree = "<group>"; };
|
||||
@ -4902,6 +4912,7 @@
|
||||
A7D8A7BE23E2513E00DCD162 /* hidapi */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */,
|
||||
A7D8A7C923E2513E00DCD162 /* SDL_hidapi_gamecube.c */,
|
||||
F3F07D59269640160074468B /* SDL_hidapi_luna.c */,
|
||||
A7D8A7C323E2513E00DCD162 /* SDL_hidapi_ps4.c */,
|
||||
@ -7631,6 +7642,7 @@
|
||||
A75FCE3B23E25AB700529352 /* SDL_wave.c in Sources */,
|
||||
A75FCE3C23E25AB700529352 /* s_tan.c in Sources */,
|
||||
A75FCE3D23E25AB700529352 /* SDL_hints.c in Sources */,
|
||||
9846B083287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A75FCE3E23E25AB700529352 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A75FCE3F23E25AB700529352 /* SDL_pixels.c in Sources */,
|
||||
A75FCE4123E25AB700529352 /* SDL_sysloadso.c in Sources */,
|
||||
@ -7823,6 +7835,7 @@
|
||||
A75FCFF423E25AC700529352 /* SDL_wave.c in Sources */,
|
||||
A75FCFF523E25AC700529352 /* s_tan.c in Sources */,
|
||||
A75FCFF623E25AC700529352 /* SDL_hints.c in Sources */,
|
||||
9846B084287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A75FCFF723E25AC700529352 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A75FCFF823E25AC700529352 /* SDL_pixels.c in Sources */,
|
||||
A75FCFFA23E25AC700529352 /* SDL_sysloadso.c in Sources */,
|
||||
@ -8001,6 +8014,7 @@
|
||||
A769B1BE23E259AE00872273 /* SDL_error.c in Sources */,
|
||||
A769B1BF23E259AE00872273 /* SDL_blit.c in Sources */,
|
||||
A769B1C023E259AE00872273 /* SDL_rwops.c in Sources */,
|
||||
9846B081287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A769B1C123E259AE00872273 /* SDL_uikitviewcontroller.m in Sources */,
|
||||
A769B1C223E259AE00872273 /* s_cos.c in Sources */,
|
||||
A769B1C323E259AE00872273 /* SDL_steamcontroller.c in Sources */,
|
||||
@ -8208,6 +8222,7 @@
|
||||
A7D8B54023E2514300DCD162 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A7D8AD6F23E2514100DCD162 /* SDL_pixels.c in Sources */,
|
||||
5616CA52252BB35A005D5928 /* SDL_url.c in Sources */,
|
||||
9846B07D287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A7D8B75F23E2514300DCD162 /* SDL_sysloadso.c in Sources */,
|
||||
A7D8B5F423E2514300DCD162 /* SDL_syspower.c in Sources */,
|
||||
A7D8B95123E2514400DCD162 /* SDL_iconv.c in Sources */,
|
||||
@ -8400,6 +8415,7 @@
|
||||
A7D8B54123E2514300DCD162 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A7D8AD7023E2514100DCD162 /* SDL_pixels.c in Sources */,
|
||||
5616CA55252BB35B005D5928 /* SDL_url.c in Sources */,
|
||||
9846B07E287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A7D8B76023E2514300DCD162 /* SDL_sysloadso.c in Sources */,
|
||||
A7D8B5F523E2514300DCD162 /* SDL_syspower.c in Sources */,
|
||||
A7D8B95223E2514400DCD162 /* SDL_iconv.c in Sources */,
|
||||
@ -8578,6 +8594,7 @@
|
||||
A7D8B8E823E2514400DCD162 /* SDL_error.c in Sources */,
|
||||
A7D8AD6C23E2514100DCD162 /* SDL_blit.c in Sources */,
|
||||
A7D8B5C123E2514300DCD162 /* SDL_rwops.c in Sources */,
|
||||
9846B080287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A7D8ACD323E2514100DCD162 /* SDL_uikitviewcontroller.m in Sources */,
|
||||
A7D8BA9523E2514400DCD162 /* s_cos.c in Sources */,
|
||||
A7D8B4D423E2514300DCD162 /* SDL_steamcontroller.c in Sources */,
|
||||
@ -8699,6 +8716,7 @@
|
||||
A7D8B62F23E2514300DCD162 /* SDL_sysfilesystem.m in Sources */,
|
||||
A7D8BAC723E2514500DCD162 /* e_pow.c in Sources */,
|
||||
A7D8B41C23E2514300DCD162 /* SDL_systls.c in Sources */,
|
||||
9846B07C287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A7D8BBD923E2574800DCD162 /* SDL_uikitmessagebox.m in Sources */,
|
||||
A7D8AD2923E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
|
||||
A7D8A95123E2514000DCD162 /* SDL_spinlock.c in Sources */,
|
||||
@ -8889,6 +8907,7 @@
|
||||
A7D8AE7F23E2514100DCD162 /* SDL_yuv.c in Sources */,
|
||||
A7D8B63223E2514300DCD162 /* SDL_sysfilesystem.m in Sources */,
|
||||
A7D8BACA23E2514500DCD162 /* e_pow.c in Sources */,
|
||||
9846B07F287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A7D8B41F23E2514300DCD162 /* SDL_systls.c in Sources */,
|
||||
A7D8AD2C23E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
|
||||
A7D8A95423E2514000DCD162 /* SDL_spinlock.c in Sources */,
|
||||
@ -9079,6 +9098,7 @@
|
||||
A7D8B63423E2514300DCD162 /* SDL_sysfilesystem.m in Sources */,
|
||||
A7D8BACC23E2514500DCD162 /* e_pow.c in Sources */,
|
||||
A7D8B42123E2514300DCD162 /* SDL_systls.c in Sources */,
|
||||
9846B082287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */,
|
||||
A7D8AD2E23E2514100DCD162 /* SDL_vulkan_utils.c in Sources */,
|
||||
A7D8A95623E2514000DCD162 /* SDL_spinlock.c in Sources */,
|
||||
A7D8BAB423E2514400DCD162 /* s_atan.c in Sources */,
|
||||
|
@ -69,7 +69,8 @@ typedef enum
|
||||
SDL_CONTROLLER_TYPE_VIRTUAL,
|
||||
SDL_CONTROLLER_TYPE_PS5,
|
||||
SDL_CONTROLLER_TYPE_AMAZON_LUNA,
|
||||
SDL_CONTROLLER_TYPE_GOOGLE_STADIA
|
||||
SDL_CONTROLLER_TYPE_GOOGLE_STADIA,
|
||||
SDL_CONTROLLER_TYPE_NVIDIA_SHIELD
|
||||
} SDL_GameControllerType;
|
||||
|
||||
typedef enum
|
||||
|
@ -674,6 +674,17 @@ extern "C" {
|
||||
*/
|
||||
#define SDL_HINT_JOYSTICK_HIDAPI_LUNA "SDL_JOYSTICK_HIDAPI_LUNA"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for NVIDIA SHIELD 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_SHIELD "SDL_JOYSTICK_HIDAPI_SHIELD"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for PS4 controllers should be used.
|
||||
*
|
||||
|
@ -634,6 +634,10 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
|
||||
/* The Google Stadia controller has a share button and a Google Assistant button */
|
||||
SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string));
|
||||
break;
|
||||
case SDL_CONTROLLER_TYPE_NVIDIA_SHIELD:
|
||||
/* The NVIDIA SHIELD controller has a home button between back and start buttons */
|
||||
SDL_strlcat(mapping_string, "misc1:b15,", sizeof(mapping_string));
|
||||
break;
|
||||
default:
|
||||
if (vendor == 0 && product == 0) {
|
||||
/* This is a Bluetooth Nintendo Switch Pro controller */
|
||||
|
@ -1957,6 +1957,9 @@ SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product, const
|
||||
} else if (vendor == USB_VENDOR_GOOGLE && product == USB_PRODUCT_GOOGLE_STADIA_CONTROLLER) {
|
||||
type = SDL_CONTROLLER_TYPE_GOOGLE_STADIA;
|
||||
|
||||
} else if (vendor == USB_VENDOR_NVIDIA && product == USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER) {
|
||||
type = SDL_CONTROLLER_TYPE_NVIDIA_SHIELD;
|
||||
|
||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_GRIP) {
|
||||
type = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, SDL_FALSE) ? SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO : SDL_CONTROLLER_TYPE_UNKNOWN;
|
||||
|
||||
|
443
src/joystick/hidapi/SDL_hidapi_shield.c
Normal file
443
src/joystick/hidapi/SDL_hidapi_shield.c
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2022 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_hints.h"
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "SDL_gamecontroller.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SHIELD
|
||||
|
||||
/* Define this if you want to log all packets from the controller */
|
||||
/*#define DEBUG_SHIELD_PROTOCOL*/
|
||||
|
||||
#define CMD_BATTERY_STATE 0x07
|
||||
#define CMD_RUMBLE 0x39
|
||||
#define CMD_CHARGE_STATE 0x3A
|
||||
|
||||
/* Milliseconds between polls of battery state */
|
||||
#define BATTERY_POLL_INTERVAL_MS 60000
|
||||
|
||||
/* Milliseconds between retransmission of rumble to keep motors running */
|
||||
#define RUMBLE_REFRESH_INTERVAL_MS 500
|
||||
|
||||
/* Reports that are too small are dropped over Bluetooth */
|
||||
#define HID_REPORT_SIZE 33
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_CONTROLLER_BUTTON_SHIELD_HOME = 15,
|
||||
SDL_CONTROLLER_NUM_SHIELD_BUTTONS,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Uint8 seq_num;
|
||||
|
||||
SDL_JoystickPowerLevel battery_level;
|
||||
SDL_bool charging;
|
||||
Uint32 last_battery_query_time;
|
||||
|
||||
SDL_bool rumble_report_pending;
|
||||
SDL_bool rumble_update_pending;
|
||||
Uint8 left_motor_amplitude;
|
||||
Uint8 right_motor_amplitude;
|
||||
Uint32 last_rumble_time;
|
||||
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
} SDL_DriverShield_Context;
|
||||
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverShield_IsSupportedDevice(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, Uint8* data, int size)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx = device->context;
|
||||
Uint8 cmd_pkt[HID_REPORT_SIZE];
|
||||
|
||||
if (size >= sizeof(cmd_pkt) - 3) {
|
||||
return SDL_SetError("Invalid command data");
|
||||
}
|
||||
|
||||
if (SDL_HIDAPI_LockRumble() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_pkt[0] = 0x04;
|
||||
cmd_pkt[1] = cmd;
|
||||
cmd_pkt[2] = ctx->seq_num++;
|
||||
if (data) {
|
||||
SDL_memcpy(&cmd_pkt[3], data, size);
|
||||
}
|
||||
|
||||
if (SDL_HIDAPI_SendRumbleAndUnlock(device, cmd_pkt, sizeof(cmd_pkt)) != sizeof(cmd_pkt)) {
|
||||
return SDL_SetError("Couldn't send command packet");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx;
|
||||
|
||||
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;
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_NUM_SHIELD_BUTTONS;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
|
||||
/* Request battery and charging info */
|
||||
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);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_SendNextRumble(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx = device->context;
|
||||
Uint8 rumble_data[3];
|
||||
|
||||
if (!ctx->rumble_update_pending) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rumble_data[0] = 0x01; /* enable */
|
||||
rumble_data[1] = ctx->left_motor_amplitude;
|
||||
rumble_data[2] = ctx->right_motor_amplitude;
|
||||
|
||||
ctx->rumble_update_pending = SDL_FALSE;
|
||||
ctx->last_rumble_time = SDL_GetTicks();
|
||||
|
||||
return HIDAPI_DriverShield_SendCommand(device, CMD_RUMBLE, rumble_data, sizeof(rumble_data));
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx = device->context;
|
||||
|
||||
/* The rumble motors are quite intense, so tone down the intensity like the official driver does */
|
||||
ctx->left_motor_amplitude = low_frequency_rumble >> 11;
|
||||
ctx->right_motor_amplitude = high_frequency_rumble >> 11;
|
||||
ctx->rumble_update_pending = SDL_TRUE;
|
||||
|
||||
if (ctx->rumble_report_pending) {
|
||||
/* We will service this after the hardware acknowledges the previous request */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return HIDAPI_DriverShield_SendNextRumble(device);
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static Uint32
|
||||
HIDAPI_DriverShield_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
return SDL_JOYCAP_RUMBLE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverShield_HandleStatePacket(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
if (size < 23) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->last_state[2] != data[2]) {
|
||||
SDL_bool dpad_up = SDL_FALSE;
|
||||
SDL_bool dpad_down = SDL_FALSE;
|
||||
SDL_bool dpad_left = SDL_FALSE;
|
||||
SDL_bool dpad_right = SDL_FALSE;
|
||||
|
||||
switch (data[2]) {
|
||||
case 0:
|
||||
dpad_up = SDL_TRUE;
|
||||
break;
|
||||
case 1:
|
||||
dpad_up = SDL_TRUE;
|
||||
dpad_right = SDL_TRUE;
|
||||
break;
|
||||
case 2:
|
||||
dpad_right = SDL_TRUE;
|
||||
break;
|
||||
case 3:
|
||||
dpad_right = SDL_TRUE;
|
||||
dpad_down = SDL_TRUE;
|
||||
break;
|
||||
case 4:
|
||||
dpad_down = SDL_TRUE;
|
||||
break;
|
||||
case 5:
|
||||
dpad_left = SDL_TRUE;
|
||||
dpad_down = SDL_TRUE;
|
||||
break;
|
||||
case 6:
|
||||
dpad_left = SDL_TRUE;
|
||||
break;
|
||||
case 7:
|
||||
dpad_up = SDL_TRUE;
|
||||
dpad_left = SDL_TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
|
||||
}
|
||||
|
||||
if (ctx->last_state[3] != data[3]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (ctx->last_state[4] != data[4]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, SDL_SwapLE16(*(Sint16*)&data[9]) - 0x8000);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, SDL_SwapLE16(*(Sint16*)&data[11]) - 0x8000);
|
||||
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, SDL_SwapLE16(*(Sint16*)&data[13]) - 0x8000);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, SDL_SwapLE16(*(Sint16*)&data[15]) - 0x8000);
|
||||
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_SwapLE16(*(Sint16*)&data[19]) - 0x8000);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, SDL_SwapLE16(*(Sint16*)&data[21]) - 0x8000);
|
||||
|
||||
if (ctx->last_state[17] != data[17]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_SHIELD_HOME, (data[17] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[17] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
|
||||
SDL_Joystick *joystick = NULL;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size = 0;
|
||||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
|
||||
}
|
||||
if (!joystick) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
|
||||
#ifdef DEBUG_SHIELD_PROTOCOL
|
||||
HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);
|
||||
#endif
|
||||
switch (data[0]) {
|
||||
case 0x01:
|
||||
HIDAPI_DriverShield_HandleStatePacket(joystick, ctx, data, size);
|
||||
break;
|
||||
case 0x03:
|
||||
switch (data[1]) {
|
||||
case CMD_RUMBLE:
|
||||
ctx->rumble_report_pending = SDL_FALSE;
|
||||
HIDAPI_DriverShield_SendNextRumble(device);
|
||||
break;
|
||||
case CMD_CHARGE_STATE:
|
||||
ctx->charging = data[2] != 0;
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
|
||||
break;
|
||||
case CMD_BATTERY_STATE:
|
||||
switch (data[5]) {
|
||||
case 0:
|
||||
ctx->battery_level = SDL_JOYSTICK_POWER_EMPTY;
|
||||
break;
|
||||
case 1:
|
||||
ctx->battery_level = SDL_JOYSTICK_POWER_LOW;
|
||||
break;
|
||||
case 2: /* 40% */
|
||||
case 3: /* 60% */
|
||||
case 4: /* 80% */
|
||||
ctx->battery_level = SDL_JOYSTICK_POWER_MEDIUM;
|
||||
break;
|
||||
case 5:
|
||||
ctx->battery_level = SDL_JOYSTICK_POWER_FULL;
|
||||
break;
|
||||
default:
|
||||
ctx->battery_level = SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
SDL_PrivateJoystickBatteryLevel(joystick, ctx->charging ? SDL_JOYSTICK_POWER_WIRED : ctx->battery_level);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
ctx->last_battery_query_time = SDL_GetTicks();
|
||||
HIDAPI_DriverShield_SendCommand(device, CMD_BATTERY_STATE, NULL, 0);
|
||||
}
|
||||
|
||||
/* Retransmit rumble packets if they've lasted longer than the hardware supports */
|
||||
if ((ctx->left_motor_amplitude != 0 || ctx->right_motor_amplitude != 0) &&
|
||||
SDL_TICKS_PASSED(SDL_GetTicks(), ctx->last_rumble_time + RUMBLE_REFRESH_INTERVAL_MS)) {
|
||||
ctx->rumble_update_pending = SDL_TRUE;
|
||||
HIDAPI_DriverShield_SendNextRumble(device);
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
/* Read error, device is disconnected */
|
||||
HIDAPI_JoystickDisconnected(device, joystick->instance_id);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
||||
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
|
||||
HIDAPI_DriverShield_FreeDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield =
|
||||
{
|
||||
SDL_HINT_JOYSTICK_HIDAPI_SHIELD,
|
||||
SDL_TRUE,
|
||||
SDL_TRUE,
|
||||
HIDAPI_DriverShield_IsSupportedDevice,
|
||||
HIDAPI_DriverShield_GetDeviceName,
|
||||
HIDAPI_DriverShield_InitDevice,
|
||||
HIDAPI_DriverShield_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverShield_SetDevicePlayerIndex,
|
||||
HIDAPI_DriverShield_UpdateDevice,
|
||||
HIDAPI_DriverShield_OpenJoystick,
|
||||
HIDAPI_DriverShield_RumbleJoystick,
|
||||
HIDAPI_DriverShield_RumbleJoystickTriggers,
|
||||
HIDAPI_DriverShield_GetJoystickCapabilities,
|
||||
HIDAPI_DriverShield_SetJoystickLED,
|
||||
HIDAPI_DriverShield_SendJoystickEffect,
|
||||
HIDAPI_DriverShield_SetJoystickSensorsEnabled,
|
||||
HIDAPI_DriverShield_CloseJoystick,
|
||||
HIDAPI_DriverShield_FreeDevice,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI_SHIELD */
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
@ -49,6 +49,9 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_LUNA
|
||||
&SDL_HIDAPI_DriverLuna,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SHIELD
|
||||
&SDL_HIDAPI_DriverShield,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_PS4
|
||||
&SDL_HIDAPI_DriverPS4,
|
||||
#endif
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
#define SDL_JOYSTICK_HIDAPI_XBOX360
|
||||
#define SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
#define SDL_JOYSTICK_HIDAPI_SHIELD
|
||||
|
||||
#if defined(__IPHONEOS__) || defined(__TVOS__) || defined(__ANDROID__)
|
||||
/* Very basic Steam Controller support on mobile devices */
|
||||
@ -111,6 +112,7 @@ typedef struct _SDL_HIDAPI_DeviceDriver
|
||||
/* HIDAPI device support */
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverShield;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia;
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define USB_VENDOR_SONY 0x054c
|
||||
#define USB_VENDOR_VALVE 0x28de
|
||||
|
||||
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER 0x7214
|
||||
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
|
||||
#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER 0x9400
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER 0x1846
|
||||
|
Loading…
Reference in New Issue
Block a user