mirror of https://github.com/encounter/SDL.git
Added HIDAPI joystick drivers for more consistent support for Xbox, PS4 and Nintendo Switch Pro controller support across platforms.
Added SDL_GameControllerRumble() and SDL_JoystickRumble() for simple force feedback outside of the SDL haptics API
This commit is contained in:
parent
ba90412cda
commit
d2042e1ed4
19
Android.mk
19
Android.mk
|
@ -31,7 +31,7 @@ LOCAL_SRC_FILES := \
|
|||
$(wildcard $(LOCAL_PATH)/src/haptic/android/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
|
||||
$(LOCAL_PATH)/src/joystick/steam/SDL_steamcontroller.c \
|
||||
$(wildcard $(LOCAL_PATH)/src/joystick/hidapi/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/power/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/power/android/*.c) \
|
||||
|
@ -48,6 +48,8 @@ LOCAL_SRC_FILES := \
|
|||
$(wildcard $(LOCAL_PATH)/src/video/yuv2rgb/*.c) \
|
||||
$(wildcard $(LOCAL_PATH)/src/test/*.c))
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := hidapi
|
||||
|
||||
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
|
||||
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
|
||||
|
||||
|
@ -88,4 +90,19 @@ LOCAL_MODULE_FILENAME := libSDL2main
|
|||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
###########################
|
||||
#
|
||||
# hidapi library
|
||||
#
|
||||
###########################
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CPPFLAGS += -std=c++11
|
||||
|
||||
LOCAL_SRC_FILES := $(LOCAL_PATH)/src/hidapi/android/hid.cpp
|
||||
|
||||
LOCAL_MODULE := libhidapi
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
|
|
@ -80,6 +80,18 @@
|
|||
<CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Program Files %28x86%29\Microsoft DirectX SDK %28June 2010%29\Lib\x86;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>D:\dev\steam\rel\streaming_client\SDL\src\hidapi\hidapi;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<IncludePath>D:\dev\steam\rel\streaming_client\SDL\src\hidapi\hidapi;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>D:\dev\steam\rel\streaming_client\SDL\src\hidapi\hidapi;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>D:\dev\steam\rel\streaming_client\SDL\src\hidapi\hidapi;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<PreBuildEvent>
|
||||
<Command>
|
||||
|
@ -109,7 +121,7 @@
|
|||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>setupapi.lib;winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -140,7 +152,7 @@
|
|||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>setupapi.lib;winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -174,7 +186,7 @@
|
|||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>setupapi.lib;winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -206,7 +218,7 @@
|
|||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>setupapi.lib;winmm.lib;imm32.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -318,6 +330,8 @@
|
|||
<ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
|
||||
<ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
|
||||
<ClInclude Include="..\..\src\haptic\windows\SDL_xinputhaptic_c.h" />
|
||||
<ClInclude Include="..\..\src\joystick\hidapi\controller_type.h" />
|
||||
<ClInclude Include="..\..\src\joystick\hidapi\SDL_hidapijoystick_c.h" />
|
||||
<ClInclude Include="..\..\src\joystick\SDL_joystick_c.h" />
|
||||
<ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h" />
|
||||
<ClInclude Include="..\..\src\joystick\windows\SDL_dinputjoystick_c.h" />
|
||||
|
@ -411,6 +425,12 @@
|
|||
<ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />
|
||||
<ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c" />
|
||||
<ClCompile Include="..\..\src\haptic\windows\SDL_xinputhaptic.c" />
|
||||
<ClCompile Include="..\..\src\hidapi\windows\hid.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
|
||||
<ClCompile Include="..\..\src\joystick\SDL_gamecontroller.c" />
|
||||
<ClCompile Include="..\..\src\joystick\SDL_joystick.c" />
|
||||
<ClCompile Include="..\..\src\joystick\windows\SDL_dinputjoystick.c" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
???<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="API Headers">
|
||||
|
@ -313,6 +313,8 @@
|
|||
<ClInclude Include="..\..\src\video\yuv2rgb\yuv_rgb.h" />
|
||||
<ClInclude Include="..\..\src\render\direct3d11\SDL_shaders_d3d11.h" />
|
||||
<ClInclude Include="..\..\src\render\direct3d\SDL_shaders_d3d.h" />
|
||||
<ClInclude Include="..\..\src\joystick\hidapi\controller_type.h" />
|
||||
<ClInclude Include="..\..\src\joystick\hidapi\SDL_hidapijoystick_c.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\libm\e_atan2.c" />
|
||||
|
@ -454,6 +456,12 @@
|
|||
<ClCompile Include="..\..\src\video\yuv2rgb\yuv_rgb.c" />
|
||||
<ClCompile Include="..\..\src\render\direct3d11\SDL_shaders_d3d11.c" />
|
||||
<ClCompile Include="..\..\src\render\direct3d\SDL_shaders_d3d.c" />
|
||||
<ClCompile Include="..\..\src\hidapi\windows\hid.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
|
||||
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\src\main\windows\version.rc" />
|
||||
|
|
|
@ -110,8 +110,8 @@
|
|||
56F9D5601DF73BA400C15B5D /* SDL_dataqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 566726431DF72CF5001DD3DB /* SDL_dataqueue.c */; };
|
||||
93CB792313FC5E5200BD3E05 /* SDL_uikitviewcontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = 93CB792213FC5E5200BD3E05 /* SDL_uikitviewcontroller.h */; };
|
||||
93CB792613FC5F5300BD3E05 /* SDL_uikitviewcontroller.m in Sources */ = {isa = PBXBuildFile; fileRef = 93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */; };
|
||||
A7A9EEA91F702631002A5589 /* SDL_steamcontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */; };
|
||||
A7A9EEAA1F702631002A5589 /* SDL_steamcontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A9EEA81F702631002A5589 /* SDL_steamcontroller.h */; };
|
||||
A704172E20F7E74800A82227 /* controller_type.h in Headers */ = {isa = PBXBuildFile; fileRef = A704172D20F7E74800A82227 /* controller_type.h */; };
|
||||
A704172F20F7E76000A82227 /* SDL_gamecontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */; };
|
||||
A7F629241FE06523002F9CC9 /* SDL_uikitmetalview.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7516F81EE1C28A00820EEA /* SDL_uikitmetalview.m */; };
|
||||
AA0AD06216647BBB00CE5896 /* SDL_gamecontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */; };
|
||||
AA0AD06516647BD400CE5896 /* SDL_gamecontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0AD06416647BD400CE5896 /* SDL_gamecontroller.h */; };
|
||||
|
@ -194,7 +194,18 @@
|
|||
AADC5A631FDA10C800960936 /* SDL_shaders_metal_ios.h in Headers */ = {isa = PBXBuildFile; fileRef = AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */; };
|
||||
AADC5A641FDA10C800960936 /* SDL_render_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = AADC5A621FDA10C800960936 /* SDL_render_metal.m */; };
|
||||
AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */ = {isa = PBXBuildFile; fileRef = AADC5A621FDA10C800960936 /* SDL_render_metal.m */; };
|
||||
AAE7A4222041CCA90096E65A /* SDL_steamcontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */; };
|
||||
F3BDD77620F51C3C004ECBF3 /* hid.mm in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD77520F51C3C004ECBF3 /* hid.mm */; };
|
||||
F3BDD79220F51CB8004ECBF3 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */; };
|
||||
F3BDD79320F51CB8004ECBF3 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */; };
|
||||
F3BDD79420F51CB8004ECBF3 /* SDL_hidapi_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */; };
|
||||
F3BDD79520F51CB8004ECBF3 /* SDL_hidapi_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */; };
|
||||
F3BDD79620F51CB8004ECBF3 /* SDL_hidapi_xboxone.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78D20F51CB8004ECBF3 /* SDL_hidapi_xboxone.c */; };
|
||||
F3BDD79720F51CB8004ECBF3 /* SDL_hidapi_xboxone.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78D20F51CB8004ECBF3 /* SDL_hidapi_xboxone.c */; };
|
||||
F3BDD79820F51CB8004ECBF3 /* SDL_hidapi_ps4.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78E20F51CB8004ECBF3 /* SDL_hidapi_ps4.c */; };
|
||||
F3BDD79920F51CB8004ECBF3 /* SDL_hidapi_ps4.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD78E20F51CB8004ECBF3 /* SDL_hidapi_ps4.c */; };
|
||||
F3BDD79B20F51CB8004ECBF3 /* SDL_hidapijoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3BDD79020F51CB8004ECBF3 /* SDL_hidapijoystick_c.h */; };
|
||||
F3BDD79C20F51CB8004ECBF3 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */; };
|
||||
F3BDD79D20F51CB8004ECBF3 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */; };
|
||||
FA1DC2721C62BE65008F99A0 /* SDL_uikitclipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */; };
|
||||
FA1DC2731C62BE65008F99A0 /* SDL_uikitclipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */; };
|
||||
FAB5981D1BB5C31500BE72C5 /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */; };
|
||||
|
@ -223,7 +234,6 @@
|
|||
FAB5984C1BB5C31600BE72C5 /* SDL_syshaptic.c in Sources */ = {isa = PBXBuildFile; fileRef = 047677B80EA76A31008ABAF1 /* SDL_syshaptic.c */; };
|
||||
FAB5984D1BB5C31600BE72C5 /* SDL_haptic.c in Sources */ = {isa = PBXBuildFile; fileRef = 047677B90EA76A31008ABAF1 /* SDL_haptic.c */; };
|
||||
FAB598501BB5C31600BE72C5 /* SDL_sysjoystick.m in Sources */ = {isa = PBXBuildFile; fileRef = FD689F000E26E5B600F90B21 /* SDL_sysjoystick.m */; };
|
||||
FAB598511BB5C31600BE72C5 /* SDL_gamecontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */; };
|
||||
FAB598521BB5C31600BE72C5 /* SDL_joystick.c in Sources */ = {isa = PBXBuildFile; fileRef = FD5F9D1E0E0E08B3008E885B /* SDL_joystick.c */; };
|
||||
FAB598551BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */ = {isa = PBXBuildFile; fileRef = 047AF1B20EA98D6C00811173 /* SDL_sysloadso.c */; };
|
||||
FAB598561BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */ = {isa = PBXBuildFile; fileRef = FD8BD8190E27E25900B52CD5 /* SDL_sysloadso.c */; };
|
||||
|
@ -432,8 +442,7 @@
|
|||
56ED04E2118A8EFD00A56AA6 /* SDL_syspower.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDL_syspower.m; path = ../../src/power/uikit/SDL_syspower.m; sourceTree = SOURCE_ROOT; };
|
||||
93CB792213FC5E5200BD3E05 /* SDL_uikitviewcontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitviewcontroller.h; sourceTree = "<group>"; };
|
||||
93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitviewcontroller.m; sourceTree = "<group>"; };
|
||||
A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_steamcontroller.c; sourceTree = "<group>"; };
|
||||
A7A9EEA81F702631002A5589 /* SDL_steamcontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_steamcontroller.h; sourceTree = "<group>"; };
|
||||
A704172D20F7E74800A82227 /* controller_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controller_type.h; sourceTree = "<group>"; };
|
||||
AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gamecontroller.c; sourceTree = "<group>"; };
|
||||
AA0AD06416647BD400CE5896 /* SDL_gamecontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamecontroller.h; sourceTree = "<group>"; };
|
||||
AA0F8494178D5F1A00823F9D /* SDL_systls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_systls.c; sourceTree = "<group>"; };
|
||||
|
@ -510,6 +519,13 @@
|
|||
AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_bits.h; sourceTree = "<group>"; };
|
||||
AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_shaders_metal_ios.h; sourceTree = "<group>"; };
|
||||
AADC5A621FDA10C800960936 /* SDL_render_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_render_metal.m; sourceTree = "<group>"; };
|
||||
F3BDD77520F51C3C004ECBF3 /* hid.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = hid.mm; sourceTree = "<group>"; };
|
||||
F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_xbox360.c; sourceTree = "<group>"; };
|
||||
F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_switch.c; sourceTree = "<group>"; };
|
||||
F3BDD78D20F51CB8004ECBF3 /* SDL_hidapi_xboxone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_xboxone.c; sourceTree = "<group>"; };
|
||||
F3BDD78E20F51CB8004ECBF3 /* SDL_hidapi_ps4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_ps4.c; sourceTree = "<group>"; };
|
||||
F3BDD79020F51CB8004ECBF3 /* SDL_hidapijoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_hidapijoystick_c.h; sourceTree = "<group>"; };
|
||||
F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapijoystick.c; sourceTree = "<group>"; };
|
||||
FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitclipboard.h; sourceTree = "<group>"; };
|
||||
FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitclipboard.m; sourceTree = "<group>"; };
|
||||
FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -778,15 +794,6 @@
|
|||
name = uikit;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A7A9EEA61F702607002A5589 /* steam */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */,
|
||||
A7A9EEA81F702631002A5589 /* SDL_steamcontroller.h */,
|
||||
);
|
||||
path = steam;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AA13B3521FB8B41700D9FEE6 /* yuv2rgb */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -807,6 +814,36 @@
|
|||
path = metal;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F35CEA6E20F51B7F003ECE98 /* hidapi */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3BDD77420F51C18004ECBF3 /* ios */,
|
||||
);
|
||||
name = hidapi;
|
||||
path = ../../src/hidapi;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
F3BDD77420F51C18004ECBF3 /* ios */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3BDD77520F51C3C004ECBF3 /* hid.mm */,
|
||||
);
|
||||
path = ios;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F3BDD78A20F51C8D004ECBF3 /* hidapi */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3BDD78E20F51CB8004ECBF3 /* SDL_hidapi_ps4.c */,
|
||||
F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */,
|
||||
F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */,
|
||||
F3BDD78D20F51CB8004ECBF3 /* SDL_hidapi_xboxone.c */,
|
||||
F3BDD79020F51CB8004ECBF3 /* SDL_hidapijoystick_c.h */,
|
||||
F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */,
|
||||
);
|
||||
path = hidapi;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FD3F4A6F0DEA620800C5B771 /* stdlib */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -824,8 +861,9 @@
|
|||
FD5F9D080E0E08B3008E885B /* joystick */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A7A9EEA61F702607002A5589 /* steam */,
|
||||
F3BDD78A20F51C8D004ECBF3 /* hidapi */,
|
||||
FD689EFF0E26E5B600F90B21 /* iphoneos */,
|
||||
A704172D20F7E74800A82227 /* controller_type.h */,
|
||||
AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */,
|
||||
FD5F9D1E0E0E08B3008E885B /* SDL_joystick.c */,
|
||||
FD5F9D1F0E0E08B3008E885B /* SDL_joystick_c.h */,
|
||||
|
@ -970,6 +1008,7 @@
|
|||
FD99B99D0DD52EDC00FB1D6B /* file */,
|
||||
56C181E017C44D6900406AE3 /* filesystem */,
|
||||
047677B60EA769DF008ABAF1 /* haptic */,
|
||||
F35CEA6E20F51B7F003ECE98 /* hidapi */,
|
||||
FD5F9D080E0E08B3008E885B /* joystick */,
|
||||
FD8BD8150E27E25900B52CD5 /* loadso */,
|
||||
56ED04DE118A8E9A00A56AA6 /* power */,
|
||||
|
@ -1213,13 +1252,13 @@
|
|||
AA13B3591FB8B46400D9FEE6 /* yuv_rgb.h in Headers */,
|
||||
04F7807712FB751400FC43C0 /* SDL_blendfillrect.h in Headers */,
|
||||
04F7807912FB751400FC43C0 /* SDL_blendline.h in Headers */,
|
||||
F3BDD79B20F51CB8004ECBF3 /* SDL_hidapijoystick_c.h in Headers */,
|
||||
04F7807B12FB751400FC43C0 /* SDL_blendpoint.h in Headers */,
|
||||
04F7807C12FB751400FC43C0 /* SDL_draw.h in Headers */,
|
||||
04F7807E12FB751400FC43C0 /* SDL_drawline.h in Headers */,
|
||||
AA13B34E1FB8B27800D9FEE6 /* SDL_yuv_c.h in Headers */,
|
||||
04F7808012FB751400FC43C0 /* SDL_drawpoint.h in Headers */,
|
||||
04F7808412FB753F00FC43C0 /* SDL_nullframebuffer_c.h in Headers */,
|
||||
A7A9EEAA1F702631002A5589 /* SDL_steamcontroller.h in Headers */,
|
||||
0442EC5012FE1C1E004C9285 /* SDL_render_sw_c.h in Headers */,
|
||||
FA1DC2721C62BE65008F99A0 /* SDL_uikitclipboard.h in Headers */,
|
||||
0402A85A12FE70C600CECEE3 /* SDL_shaders_gles2.h in Headers */,
|
||||
|
@ -1250,6 +1289,7 @@
|
|||
AA7558AA1595D55500BBD41B /* SDL_joystick.h in Headers */,
|
||||
AA13B34B1FB8B27800D9FEE6 /* SDL_shape_internals.h in Headers */,
|
||||
AA7558AB1595D55500BBD41B /* SDL_keyboard.h in Headers */,
|
||||
A704172E20F7E74800A82227 /* controller_type.h in Headers */,
|
||||
AA7558AC1595D55500BBD41B /* SDL_keycode.h in Headers */,
|
||||
AA7558AD1595D55500BBD41B /* SDL_loadso.h in Headers */,
|
||||
AA7558AE1595D55500BBD41B /* SDL_log.h in Headers */,
|
||||
|
@ -1432,6 +1472,7 @@
|
|||
FAB598251BB5C31500BE72C5 /* SDL_audiocvt.c in Sources */,
|
||||
FAB598271BB5C31500BE72C5 /* SDL_audiotypecvt.c in Sources */,
|
||||
FAB598281BB5C31500BE72C5 /* SDL_mixer.c in Sources */,
|
||||
F3BDD79720F51CB8004ECBF3 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
FAB5982A1BB5C31500BE72C5 /* SDL_wave.c in Sources */,
|
||||
FAFDF8C61D88D4530083E6F2 /* SDL_uikitclipboard.m in Sources */,
|
||||
FAB5982C1BB5C31500BE72C5 /* SDL_cpuinfo.c in Sources */,
|
||||
|
@ -1442,7 +1483,9 @@
|
|||
A7F629241FE06523002F9CC9 /* SDL_uikitmetalview.m in Sources */,
|
||||
FAB5983C1BB5C31500BE72C5 /* SDL_gesture.c in Sources */,
|
||||
FAB5983E1BB5C31500BE72C5 /* SDL_keyboard.c in Sources */,
|
||||
F3BDD79520F51CB8004ECBF3 /* SDL_hidapi_switch.c in Sources */,
|
||||
FAB598401BB5C31500BE72C5 /* SDL_mouse.c in Sources */,
|
||||
A704172F20F7E76000A82227 /* SDL_gamecontroller.c in Sources */,
|
||||
FAB598421BB5C31500BE72C5 /* SDL_quit.c in Sources */,
|
||||
FAB598441BB5C31500BE72C5 /* SDL_touch.c in Sources */,
|
||||
FAB598461BB5C31500BE72C5 /* SDL_windowevents.c in Sources */,
|
||||
|
@ -1454,8 +1497,8 @@
|
|||
AADC5A5F1FDA105600960936 /* SDL_vulkan_utils.c in Sources */,
|
||||
AADC5A5E1FDA105300960936 /* SDL_yuv.c in Sources */,
|
||||
FAB5984D1BB5C31600BE72C5 /* SDL_haptic.c in Sources */,
|
||||
F3BDD79320F51CB8004ECBF3 /* SDL_hidapi_xbox360.c in Sources */,
|
||||
FAB598501BB5C31600BE72C5 /* SDL_sysjoystick.m in Sources */,
|
||||
FAB598511BB5C31600BE72C5 /* SDL_gamecontroller.c in Sources */,
|
||||
FAB598521BB5C31600BE72C5 /* SDL_joystick.c in Sources */,
|
||||
FAB598551BB5C31600BE72C5 /* SDL_sysloadso.c in Sources */,
|
||||
AADC5A651FDA10CB00960936 /* SDL_render_metal.m in Sources */,
|
||||
|
@ -1482,6 +1525,7 @@
|
|||
FAB598761BB5C31600BE72C5 /* SDL_stdlib.c in Sources */,
|
||||
FAB598771BB5C31600BE72C5 /* SDL_string.c in Sources */,
|
||||
FAB598781BB5C31600BE72C5 /* SDL_syscond.c in Sources */,
|
||||
F3BDD79D20F51CB8004ECBF3 /* SDL_hidapijoystick.c in Sources */,
|
||||
AADC5A601FDA10A400960936 /* SDL_uikitvulkan.m in Sources */,
|
||||
FAB598791BB5C31600BE72C5 /* SDL_sysmutex.c in Sources */,
|
||||
FAB5987B1BB5C31600BE72C5 /* SDL_syssem.c in Sources */,
|
||||
|
@ -1492,6 +1536,7 @@
|
|||
FAB598821BB5C31600BE72C5 /* SDL_systimer.c in Sources */,
|
||||
FAB598831BB5C31600BE72C5 /* SDL_timer.c in Sources */,
|
||||
FAB598871BB5C31600BE72C5 /* SDL_uikitappdelegate.m in Sources */,
|
||||
F3BDD79920F51CB8004ECBF3 /* SDL_hidapi_ps4.c in Sources */,
|
||||
FAB598891BB5C31600BE72C5 /* SDL_uikitevents.m in Sources */,
|
||||
FAB5988B1BB5C31600BE72C5 /* SDL_uikitmessagebox.m in Sources */,
|
||||
FAB5988D1BB5C31600BE72C5 /* SDL_uikitmodes.m in Sources */,
|
||||
|
@ -1535,7 +1580,6 @@
|
|||
files = (
|
||||
FD6526810DE8FCDD002AD96B /* SDL_systimer.c in Sources */,
|
||||
FD6526800DE8FCDD002AD96B /* SDL_timer.c in Sources */,
|
||||
A7A9EEA91F702631002A5589 /* SDL_steamcontroller.c in Sources */,
|
||||
FD3F4A7B0DEA620800C5B771 /* SDL_string.c in Sources */,
|
||||
FD6526660DE8FCDD002AD96B /* SDL_dummyaudio.c in Sources */,
|
||||
FD6526670DE8FCDD002AD96B /* SDL_audio.c in Sources */,
|
||||
|
@ -1566,7 +1610,9 @@
|
|||
FD3F4A760DEA620800C5B771 /* SDL_getenv.c in Sources */,
|
||||
FD3F4A770DEA620800C5B771 /* SDL_iconv.c in Sources */,
|
||||
FD3F4A780DEA620800C5B771 /* SDL_malloc.c in Sources */,
|
||||
F3BDD79220F51CB8004ECBF3 /* SDL_hidapi_xbox360.c in Sources */,
|
||||
FD3F4A790DEA620800C5B771 /* SDL_qsort.c in Sources */,
|
||||
F3BDD79820F51CB8004ECBF3 /* SDL_hidapi_ps4.c in Sources */,
|
||||
FD3F4A7A0DEA620800C5B771 /* SDL_stdlib.c in Sources */,
|
||||
FDA6844D0DF2374E00F98A1A /* SDL_blit.c in Sources */,
|
||||
FDA6844F0DF2374E00F98A1A /* SDL_blit_0.c in Sources */,
|
||||
|
@ -1599,11 +1645,13 @@
|
|||
FD689F270E26E5D900F90B21 /* SDL_uikitopenglview.m in Sources */,
|
||||
FD689FCE0E26E9D400F90B21 /* SDL_uikitappdelegate.m in Sources */,
|
||||
FD8BD8250E27E25900B52CD5 /* SDL_sysloadso.c in Sources */,
|
||||
F3BDD79C20F51CB8004ECBF3 /* SDL_hidapijoystick.c in Sources */,
|
||||
047677BB0EA76A31008ABAF1 /* SDL_syshaptic.c in Sources */,
|
||||
047677BC0EA76A31008ABAF1 /* SDL_haptic.c in Sources */,
|
||||
047AF1B30EA98D6C00811173 /* SDL_sysloadso.c in Sources */,
|
||||
046387460F0B5B7D0041FD65 /* SDL_fillrect.c in Sources */,
|
||||
04F2AF561104ABD200D6DDF7 /* SDL_assert.c in Sources */,
|
||||
F3BDD79620F51CB8004ECBF3 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
56ED04E1118A8EE200A56AA6 /* SDL_power.c in Sources */,
|
||||
56ED04E3118A8EFD00A56AA6 /* SDL_syspower.m in Sources */,
|
||||
006E9889119552DD001DE610 /* SDL_rwopsbundlesupport.m in Sources */,
|
||||
|
@ -1629,10 +1677,12 @@
|
|||
0402A85912FE70C600CECEE3 /* SDL_shaders_gles2.c in Sources */,
|
||||
04BAC09D1300C1290055DE28 /* SDL_log.c in Sources */,
|
||||
56EA86FB13E9EC2B002E47EB /* SDL_coreaudio.m in Sources */,
|
||||
F3BDD79420F51CB8004ECBF3 /* SDL_hidapi_switch.c in Sources */,
|
||||
93CB792613FC5F5300BD3E05 /* SDL_uikitviewcontroller.m in Sources */,
|
||||
AA628ADB159369E3005138DD /* SDL_rotate.c in Sources */,
|
||||
AA126AD51617C5E7005ABC8F /* SDL_uikitmodes.m in Sources */,
|
||||
AA704DD7162AA90A0076D1C1 /* SDL_dropevents.c in Sources */,
|
||||
F3BDD77620F51C3C004ECBF3 /* hid.mm in Sources */,
|
||||
AABCC3951640643D00AB8930 /* SDL_uikitmessagebox.m in Sources */,
|
||||
AA0AD06216647BBB00CE5896 /* SDL_gamecontroller.c in Sources */,
|
||||
AA0F8495178D5F1A00823F9D /* SDL_systls.c in Sources */,
|
||||
|
|
|
@ -462,6 +462,30 @@
|
|||
5C2EF6FE1FC9EE65003F5197 /* SDL_egl.c in Sources */ = {isa = PBXBuildFile; fileRef = 5C2EF6F51FC9EE35003F5197 /* SDL_egl.c */; };
|
||||
5C2EF6FF1FC9EE65003F5197 /* SDL_rect_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C2EF6F41FC9EE34003F5197 /* SDL_rect_c.h */; };
|
||||
5C2EF7011FC9EF10003F5197 /* SDL_egl.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C2EF7001FC9EF0F003F5197 /* SDL_egl.h */; };
|
||||
A704170920F09A9800A82227 /* hid.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170820F09A9800A82227 /* hid.c */; };
|
||||
A704170A20F09A9800A82227 /* hid.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170820F09A9800A82227 /* hid.c */; };
|
||||
A704170B20F09A9800A82227 /* hid.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170820F09A9800A82227 /* hid.c */; };
|
||||
A704171420F09AC900A82227 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170D20F09AC800A82227 /* SDL_hidapijoystick.c */; };
|
||||
A704171520F09AC900A82227 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170D20F09AC800A82227 /* SDL_hidapijoystick.c */; };
|
||||
A704171620F09AC900A82227 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170D20F09AC800A82227 /* SDL_hidapijoystick.c */; };
|
||||
A704171720F09AC900A82227 /* SDL_hidapijoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = A704170E20F09AC800A82227 /* SDL_hidapijoystick_c.h */; };
|
||||
A704171820F09AC900A82227 /* SDL_hidapijoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = A704170E20F09AC800A82227 /* SDL_hidapijoystick_c.h */; };
|
||||
A704171920F09AC900A82227 /* SDL_hidapijoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = A704170E20F09AC800A82227 /* SDL_hidapijoystick_c.h */; };
|
||||
A704171A20F09AC900A82227 /* SDL_hidapi_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170F20F09AC800A82227 /* SDL_hidapi_switch.c */; };
|
||||
A704171B20F09AC900A82227 /* SDL_hidapi_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170F20F09AC800A82227 /* SDL_hidapi_switch.c */; };
|
||||
A704171C20F09AC900A82227 /* SDL_hidapi_switch.c in Sources */ = {isa = PBXBuildFile; fileRef = A704170F20F09AC800A82227 /* SDL_hidapi_switch.c */; };
|
||||
A704171D20F09AC900A82227 /* controller_type.h in Headers */ = {isa = PBXBuildFile; fileRef = A704171020F09AC900A82227 /* controller_type.h */; };
|
||||
A704171E20F09AC900A82227 /* controller_type.h in Headers */ = {isa = PBXBuildFile; fileRef = A704171020F09AC900A82227 /* controller_type.h */; };
|
||||
A704171F20F09AC900A82227 /* controller_type.h in Headers */ = {isa = PBXBuildFile; fileRef = A704171020F09AC900A82227 /* controller_type.h */; };
|
||||
A704172020F09AC900A82227 /* SDL_hidapi_ps4.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171120F09AC900A82227 /* SDL_hidapi_ps4.c */; };
|
||||
A704172120F09AC900A82227 /* SDL_hidapi_ps4.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171120F09AC900A82227 /* SDL_hidapi_ps4.c */; };
|
||||
A704172220F09AC900A82227 /* SDL_hidapi_ps4.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171120F09AC900A82227 /* SDL_hidapi_ps4.c */; };
|
||||
A704172320F09AC900A82227 /* SDL_hidapi_xboxone.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171220F09AC900A82227 /* SDL_hidapi_xboxone.c */; };
|
||||
A704172420F09AC900A82227 /* SDL_hidapi_xboxone.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171220F09AC900A82227 /* SDL_hidapi_xboxone.c */; };
|
||||
A704172520F09AC900A82227 /* SDL_hidapi_xboxone.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171220F09AC900A82227 /* SDL_hidapi_xboxone.c */; };
|
||||
A704172620F09AC900A82227 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171320F09AC900A82227 /* SDL_hidapi_xbox360.c */; };
|
||||
A704172720F09AC900A82227 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171320F09AC900A82227 /* SDL_hidapi_xbox360.c */; };
|
||||
A704172820F09AC900A82227 /* SDL_hidapi_xbox360.c in Sources */ = {isa = PBXBuildFile; fileRef = A704171320F09AC900A82227 /* SDL_hidapi_xbox360.c */; };
|
||||
A7381E961D8B69D600B177DD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E951D8B69D600B177DD /* CoreAudio.framework */; };
|
||||
A7381E971D8B6A0300B177DD /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7381E931D8B69C300B177DD /* AudioToolbox.framework */; };
|
||||
A77E6EB4167AB0A90010E40B /* SDL_gamecontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A77E6EB3167AB0A90010E40B /* SDL_gamecontroller.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
@ -1114,6 +1138,14 @@
|
|||
5C2EF6F51FC9EE35003F5197 /* SDL_egl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_egl.c; sourceTree = "<group>"; };
|
||||
5C2EF6F61FC9EE35003F5197 /* SDL_egl_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_egl_c.h; sourceTree = "<group>"; };
|
||||
5C2EF7001FC9EF0F003F5197 /* SDL_egl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_egl.h; sourceTree = "<group>"; };
|
||||
A704170820F09A9800A82227 /* hid.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hid.c; sourceTree = "<group>"; };
|
||||
A704170D20F09AC800A82227 /* SDL_hidapijoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapijoystick.c; sourceTree = "<group>"; };
|
||||
A704170E20F09AC800A82227 /* SDL_hidapijoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_hidapijoystick_c.h; sourceTree = "<group>"; };
|
||||
A704170F20F09AC800A82227 /* SDL_hidapi_switch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_switch.c; sourceTree = "<group>"; };
|
||||
A704171020F09AC900A82227 /* controller_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controller_type.h; sourceTree = "<group>"; };
|
||||
A704171120F09AC900A82227 /* SDL_hidapi_ps4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_ps4.c; sourceTree = "<group>"; };
|
||||
A704171220F09AC900A82227 /* SDL_hidapi_xboxone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_xboxone.c; sourceTree = "<group>"; };
|
||||
A704171320F09AC900A82227 /* SDL_hidapi_xbox360.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_xbox360.c; sourceTree = "<group>"; };
|
||||
A7381E931D8B69C300B177DD /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
|
||||
A7381E951D8B69D600B177DD /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = System/Library/Frameworks/CoreAudio.framework; sourceTree = SDKROOT; };
|
||||
A77E6EB3167AB0A90010E40B /* SDL_gamecontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamecontroller.h; sourceTree = "<group>"; };
|
||||
|
@ -1536,6 +1568,7 @@
|
|||
04BDFDFF12E6671700899322 /* joystick */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A704170C20F09AA600A82227 /* hidapi */,
|
||||
04BDFE0612E6671700899322 /* darwin */,
|
||||
04BDFE1612E6671700899322 /* SDL_joystick.c */,
|
||||
04BDFE1712E6671700899322 /* SDL_joystick_c.h */,
|
||||
|
@ -1818,6 +1851,7 @@
|
|||
567E2F1F17C44BBB005F1892 /* filesystem */,
|
||||
04BDFDEC12E6671700899322 /* file */,
|
||||
04BDFDF112E6671700899322 /* haptic */,
|
||||
A73EBCD520F099C10043B449 /* hidapi */,
|
||||
04BDFDFF12E6671700899322 /* joystick */,
|
||||
04BDFE2F12E6671700899322 /* loadso */,
|
||||
04BDFE4512E6671700899322 /* power */,
|
||||
|
@ -1879,6 +1913,37 @@
|
|||
path = opengles2;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A704170720F09A6700A82227 /* mac */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A704170820F09A9800A82227 /* hid.c */,
|
||||
);
|
||||
path = mac;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A704170C20F09AA600A82227 /* hidapi */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A704171020F09AC900A82227 /* controller_type.h */,
|
||||
A704171120F09AC900A82227 /* SDL_hidapi_ps4.c */,
|
||||
A704170F20F09AC800A82227 /* SDL_hidapi_switch.c */,
|
||||
A704171320F09AC900A82227 /* SDL_hidapi_xbox360.c */,
|
||||
A704171220F09AC900A82227 /* SDL_hidapi_xboxone.c */,
|
||||
A704170E20F09AC800A82227 /* SDL_hidapijoystick_c.h */,
|
||||
A704170D20F09AC800A82227 /* SDL_hidapijoystick.c */,
|
||||
);
|
||||
path = hidapi;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A73EBCD520F099C10043B449 /* hidapi */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A704170720F09A6700A82227 /* mac */,
|
||||
);
|
||||
name = hidapi;
|
||||
path = ../../src/hidapi;
|
||||
sourceTree = SOURCE_ROOT;
|
||||
};
|
||||
AA9A7F0E1FB0200B00FED37F /* yuv2rgb */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1993,6 +2058,7 @@
|
|||
AA7558421595D4D800BBD41B /* SDL_revision.h in Headers */,
|
||||
AA7558441595D4D800BBD41B /* SDL_rwops.h in Headers */,
|
||||
AA7558461595D4D800BBD41B /* SDL_scancode.h in Headers */,
|
||||
A704171720F09AC900A82227 /* SDL_hidapijoystick_c.h in Headers */,
|
||||
AA7558481595D4D800BBD41B /* SDL_shape.h in Headers */,
|
||||
AA75584A1595D4D800BBD41B /* SDL_stdinc.h in Headers */,
|
||||
AA75584C1595D4D800BBD41B /* SDL_surface.h in Headers */,
|
||||
|
@ -2083,6 +2149,7 @@
|
|||
04BD01F912E6671800899322 /* SDL_x11window.h in Headers */,
|
||||
041B2CA612FA0D680087D585 /* SDL_sysrender.h in Headers */,
|
||||
AA9A7F161FB0209D00FED37F /* SDL_yuv_c.h in Headers */,
|
||||
A704171D20F09AC900A82227 /* controller_type.h in Headers */,
|
||||
04409B9312FA97ED00FB9AA8 /* SDL_yuv_sw_c.h in Headers */,
|
||||
04F7803912FB748500FC43C0 /* SDL_nullframebuffer_c.h in Headers */,
|
||||
04F7804A12FB74A200FC43C0 /* SDL_blendfillrect.h in Headers */,
|
||||
|
@ -2132,6 +2199,7 @@
|
|||
AA75581F1595D4D800BBD41B /* SDL_joystick.h in Headers */,
|
||||
AA7558211595D4D800BBD41B /* SDL_keyboard.h in Headers */,
|
||||
AA7558231595D4D800BBD41B /* SDL_keycode.h in Headers */,
|
||||
A704171E20F09AC900A82227 /* controller_type.h in Headers */,
|
||||
AA7558251595D4D800BBD41B /* SDL_loadso.h in Headers */,
|
||||
AA7558271595D4D800BBD41B /* SDL_log.h in Headers */,
|
||||
AA7558291595D4D800BBD41B /* SDL_main.h in Headers */,
|
||||
|
@ -2207,6 +2275,7 @@
|
|||
04BD02DC12E6671800899322 /* SDL_systhread_c.h in Headers */,
|
||||
04BD02E312E6671800899322 /* SDL_systhread.h in Headers */,
|
||||
04BD02E512E6671800899322 /* SDL_thread_c.h in Headers */,
|
||||
A704171820F09AC900A82227 /* SDL_hidapijoystick_c.h in Headers */,
|
||||
04BD02F212E6671800899322 /* SDL_timer_c.h in Headers */,
|
||||
04BD030D12E6671800899322 /* SDL_cocoaclipboard.h in Headers */,
|
||||
04BD030F12E6671800899322 /* SDL_cocoaevents.h in Headers */,
|
||||
|
@ -2296,6 +2365,7 @@
|
|||
DB313FD917554B71006C0E22 /* SDL_joystick.h in Headers */,
|
||||
DB313FDA17554B71006C0E22 /* SDL_keyboard.h in Headers */,
|
||||
DB313FDB17554B71006C0E22 /* SDL_keycode.h in Headers */,
|
||||
A704171F20F09AC900A82227 /* controller_type.h in Headers */,
|
||||
DB313FDC17554B71006C0E22 /* SDL_loadso.h in Headers */,
|
||||
DB313FDD17554B71006C0E22 /* SDL_log.h in Headers */,
|
||||
DB313FDE17554B71006C0E22 /* SDL_main.h in Headers */,
|
||||
|
@ -2371,6 +2441,7 @@
|
|||
DB313F9317554B71006C0E22 /* SDL_systhread_c.h in Headers */,
|
||||
DB313F9417554B71006C0E22 /* SDL_systhread.h in Headers */,
|
||||
DB313F9517554B71006C0E22 /* SDL_thread_c.h in Headers */,
|
||||
A704171920F09AC900A82227 /* SDL_hidapijoystick_c.h in Headers */,
|
||||
DB313F9617554B71006C0E22 /* SDL_timer_c.h in Headers */,
|
||||
DB313F9717554B71006C0E22 /* SDL_cocoaclipboard.h in Headers */,
|
||||
DB313F9817554B71006C0E22 /* SDL_cocoaevents.h in Headers */,
|
||||
|
@ -2602,6 +2673,7 @@
|
|||
04BD004112E6671800899322 /* SDL_cpuinfo.c in Sources */,
|
||||
04BD004812E6671800899322 /* SDL_clipboardevents.c in Sources */,
|
||||
04BD004A12E6671800899322 /* SDL_events.c in Sources */,
|
||||
A704172620F09AC900A82227 /* SDL_hidapi_xbox360.c in Sources */,
|
||||
04BD004C12E6671800899322 /* SDL_gesture.c in Sources */,
|
||||
04BD004E12E6671800899322 /* SDL_keyboard.c in Sources */,
|
||||
04BD005012E6671800899322 /* SDL_mouse.c in Sources */,
|
||||
|
@ -2640,6 +2712,7 @@
|
|||
04BD00F612E6671800899322 /* SDL_cocoaevents.m in Sources */,
|
||||
04BD00F812E6671800899322 /* SDL_cocoakeyboard.m in Sources */,
|
||||
AA9A7F151FB0209D00FED37F /* SDL_yuv.c in Sources */,
|
||||
A704171A20F09AC900A82227 /* SDL_hidapi_switch.c in Sources */,
|
||||
04BD00FA12E6671800899322 /* SDL_cocoamodes.m in Sources */,
|
||||
4D16644F1EDD6023003DE88E /* SDL_vulkan_utils.c in Sources */,
|
||||
04BD00FC12E6671800899322 /* SDL_cocoamouse.m in Sources */,
|
||||
|
@ -2648,6 +2721,7 @@
|
|||
04BD010212E6671800899322 /* SDL_cocoavideo.m in Sources */,
|
||||
04BD010412E6671800899322 /* SDL_cocoawindow.m in Sources */,
|
||||
04BD011712E6671800899322 /* SDL_nullevents.c in Sources */,
|
||||
A704172320F09AC900A82227 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
04BD011B12E6671800899322 /* SDL_nullvideo.c in Sources */,
|
||||
04BD017512E6671800899322 /* SDL_blit.c in Sources */,
|
||||
04BD017712E6671800899322 /* SDL_blit_0.c in Sources */,
|
||||
|
@ -2656,6 +2730,8 @@
|
|||
04BD017912E6671800899322 /* SDL_blit_A.c in Sources */,
|
||||
04BD017A12E6671800899322 /* SDL_blit_auto.c in Sources */,
|
||||
04BD017C12E6671800899322 /* SDL_blit_copy.c in Sources */,
|
||||
A704172020F09AC900A82227 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A704170920F09A9800A82227 /* hid.c in Sources */,
|
||||
04BD017E12E6671800899322 /* SDL_blit_N.c in Sources */,
|
||||
04BD017F12E6671800899322 /* SDL_blit_slow.c in Sources */,
|
||||
04BD018112E6671800899322 /* SDL_bmp.c in Sources */,
|
||||
|
@ -2664,6 +2740,7 @@
|
|||
04BD018C12E6671800899322 /* SDL_pixels.c in Sources */,
|
||||
04BD018E12E6671800899322 /* SDL_rect.c in Sources */,
|
||||
04BD019612E6671800899322 /* SDL_RLEaccel.c in Sources */,
|
||||
A704171420F09AC900A82227 /* SDL_hidapijoystick.c in Sources */,
|
||||
04BD019812E6671800899322 /* SDL_shape.c in Sources */,
|
||||
04BD019A12E6671800899322 /* SDL_stretch.c in Sources */,
|
||||
04BD019B12E6671800899322 /* SDL_surface.c in Sources */,
|
||||
|
@ -2731,6 +2808,7 @@
|
|||
04BD024812E6671800899322 /* SDL_audiotypecvt.c in Sources */,
|
||||
04BD024912E6671800899322 /* SDL_mixer.c in Sources */,
|
||||
04BD025112E6671800899322 /* SDL_wave.c in Sources */,
|
||||
A704172720F09AC900A82227 /* SDL_hidapi_xbox360.c in Sources */,
|
||||
04BD025C12E6671800899322 /* SDL_cpuinfo.c in Sources */,
|
||||
04BD026312E6671800899322 /* SDL_clipboardevents.c in Sources */,
|
||||
04BD026512E6671800899322 /* SDL_events.c in Sources */,
|
||||
|
@ -2769,6 +2847,7 @@
|
|||
04BD02E412E6671800899322 /* SDL_thread.c in Sources */,
|
||||
04BD02F112E6671800899322 /* SDL_timer.c in Sources */,
|
||||
04BD02F312E6671800899322 /* SDL_systimer.c in Sources */,
|
||||
A704171B20F09AC900A82227 /* SDL_hidapi_switch.c in Sources */,
|
||||
04BD030E12E6671800899322 /* SDL_cocoaclipboard.m in Sources */,
|
||||
04BD031012E6671800899322 /* SDL_cocoaevents.m in Sources */,
|
||||
04BD031212E6671800899322 /* SDL_cocoakeyboard.m in Sources */,
|
||||
|
@ -2777,6 +2856,7 @@
|
|||
5C2EF6A31FC98B38003F5197 /* SDL_yuv.c in Sources */,
|
||||
5C2EF6F11FC9D181003F5197 /* SDL_cocoaopengles.m in Sources */,
|
||||
04BD031812E6671800899322 /* SDL_cocoaopengl.m in Sources */,
|
||||
A704172420F09AC900A82227 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
04BD031A12E6671800899322 /* SDL_cocoashape.m in Sources */,
|
||||
04BD031C12E6671800899322 /* SDL_cocoavideo.m in Sources */,
|
||||
04BD031E12E6671800899322 /* SDL_cocoawindow.m in Sources */,
|
||||
|
@ -2785,6 +2865,8 @@
|
|||
5C2EF6A51FC98B6B003F5197 /* yuv_rgb.c in Sources */,
|
||||
04BD038F12E6671800899322 /* SDL_blit.c in Sources */,
|
||||
04BD039112E6671800899322 /* SDL_blit_0.c in Sources */,
|
||||
A704172120F09AC900A82227 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A704170A20F09A9800A82227 /* hid.c in Sources */,
|
||||
04BD039212E6671800899322 /* SDL_blit_1.c in Sources */,
|
||||
04BD039312E6671800899322 /* SDL_blit_A.c in Sources */,
|
||||
04BD039412E6671800899322 /* SDL_blit_auto.c in Sources */,
|
||||
|
@ -2793,6 +2875,7 @@
|
|||
04BD039912E6671800899322 /* SDL_blit_slow.c in Sources */,
|
||||
04BD039B12E6671800899322 /* SDL_bmp.c in Sources */,
|
||||
04BD039C12E6671800899322 /* SDL_clipboard.c in Sources */,
|
||||
A704171520F09AC900A82227 /* SDL_hidapijoystick.c in Sources */,
|
||||
04BD03A112E6671800899322 /* SDL_fillrect.c in Sources */,
|
||||
04BD03A612E6671800899322 /* SDL_pixels.c in Sources */,
|
||||
04BD03A812E6671800899322 /* SDL_rect.c in Sources */,
|
||||
|
@ -2860,6 +2943,7 @@
|
|||
DB31400617554B71006C0E22 /* SDL_audiotypecvt.c in Sources */,
|
||||
DB31400717554B71006C0E22 /* SDL_mixer.c in Sources */,
|
||||
DB31400817554B71006C0E22 /* SDL_wave.c in Sources */,
|
||||
A704172820F09AC900A82227 /* SDL_hidapi_xbox360.c in Sources */,
|
||||
DB31400917554B71006C0E22 /* SDL_cpuinfo.c in Sources */,
|
||||
DB31400A17554B71006C0E22 /* SDL_clipboardevents.c in Sources */,
|
||||
DB31400B17554B71006C0E22 /* SDL_events.c in Sources */,
|
||||
|
@ -2898,6 +2982,7 @@
|
|||
DB31402B17554B71006C0E22 /* SDL_thread.c in Sources */,
|
||||
DB31402C17554B71006C0E22 /* SDL_timer.c in Sources */,
|
||||
DB31402D17554B71006C0E22 /* SDL_systimer.c in Sources */,
|
||||
A704171C20F09AC900A82227 /* SDL_hidapi_switch.c in Sources */,
|
||||
DB31402E17554B71006C0E22 /* SDL_cocoaclipboard.m in Sources */,
|
||||
DB31402F17554B71006C0E22 /* SDL_cocoaevents.m in Sources */,
|
||||
DB31403017554B71006C0E22 /* SDL_cocoakeyboard.m in Sources */,
|
||||
|
@ -2906,6 +2991,7 @@
|
|||
5C2EF6A41FC98B39003F5197 /* SDL_yuv.c in Sources */,
|
||||
5C2EF6F31FC9D182003F5197 /* SDL_cocoaopengles.m in Sources */,
|
||||
DB31403317554B71006C0E22 /* SDL_cocoaopengl.m in Sources */,
|
||||
A704172520F09AC900A82227 /* SDL_hidapi_xboxone.c in Sources */,
|
||||
DB31403417554B71006C0E22 /* SDL_cocoashape.m in Sources */,
|
||||
DB31403517554B71006C0E22 /* SDL_cocoavideo.m in Sources */,
|
||||
DB31403617554B71006C0E22 /* SDL_cocoawindow.m in Sources */,
|
||||
|
@ -2914,6 +3000,8 @@
|
|||
5C2EF6A61FC98B6C003F5197 /* yuv_rgb.c in Sources */,
|
||||
DB31403917554B71006C0E22 /* SDL_blit.c in Sources */,
|
||||
DB31403A17554B71006C0E22 /* SDL_blit_0.c in Sources */,
|
||||
A704172220F09AC900A82227 /* SDL_hidapi_ps4.c in Sources */,
|
||||
A704170B20F09A9800A82227 /* hid.c in Sources */,
|
||||
DB31403B17554B71006C0E22 /* SDL_blit_1.c in Sources */,
|
||||
DB31403C17554B71006C0E22 /* SDL_blit_A.c in Sources */,
|
||||
DB31403D17554B71006C0E22 /* SDL_blit_auto.c in Sources */,
|
||||
|
@ -2922,6 +3010,7 @@
|
|||
DB31404017554B71006C0E22 /* SDL_blit_slow.c in Sources */,
|
||||
DB31404117554B71006C0E22 /* SDL_bmp.c in Sources */,
|
||||
DB31404217554B71006C0E22 /* SDL_clipboard.c in Sources */,
|
||||
A704171620F09AC900A82227 /* SDL_hidapijoystick.c in Sources */,
|
||||
DB31404317554B71006C0E22 /* SDL_fillrect.c in Sources */,
|
||||
DB31404417554B71006C0E22 /* SDL_pixels.c in Sources */,
|
||||
DB31404517554B71006C0E22 /* SDL_rect.c in Sources */,
|
||||
|
@ -3019,6 +3108,7 @@
|
|||
/usr/X11R6/include,
|
||||
"$(VULKAN_SDK)/include",
|
||||
../../src/video/khronos,
|
||||
../../src/hidapi/hidapi,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
SDKROOT = macosx;
|
||||
|
@ -3114,6 +3204,7 @@
|
|||
/usr/X11R6/include,
|
||||
"$(VULKAN_SDK)/include",
|
||||
../../src/video/khronos,
|
||||
../../src/hidapi/hidapi,
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.6;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
interface HIDDevice
|
||||
{
|
||||
public int getId();
|
||||
public int getVendorId();
|
||||
public int getProductId();
|
||||
public String getSerialNumber();
|
||||
public int getVersion();
|
||||
public String getManufacturerName();
|
||||
public String getProductName();
|
||||
public boolean open();
|
||||
public int sendFeatureReport(byte[] report);
|
||||
public int sendOutputReport(byte[] report);
|
||||
public boolean getFeatureReport(byte[] report);
|
||||
public void setFrozen(boolean frozen);
|
||||
public void close();
|
||||
public void shutdown();
|
||||
}
|
|
@ -0,0 +1,640 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCallback;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattDescriptor;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
import java.lang.Runnable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.UUID;
|
||||
|
||||
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
|
||||
|
||||
private static final String TAG = "hidapi";
|
||||
private HIDDeviceManager mManager;
|
||||
private BluetoothDevice mDevice;
|
||||
private int mDeviceId;
|
||||
private BluetoothGatt mGatt;
|
||||
private boolean mIsRegistered = false;
|
||||
private boolean mIsConnected = false;
|
||||
private boolean mIsChromebook = false;
|
||||
private boolean mIsReconnecting = false;
|
||||
private boolean mFrozen = false;
|
||||
private LinkedList<GattOperation> mOperations;
|
||||
GattOperation mCurrentOperation = null;
|
||||
private Handler mHandler;
|
||||
|
||||
private static final int TRANSPORT_AUTO = 0;
|
||||
private static final int TRANSPORT_BREDR = 1;
|
||||
private static final int TRANSPORT_LE = 2;
|
||||
|
||||
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
|
||||
|
||||
static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
|
||||
static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
|
||||
static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
|
||||
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
|
||||
|
||||
static class GattOperation {
|
||||
private enum Operation {
|
||||
CHR_READ,
|
||||
CHR_WRITE,
|
||||
ENABLE_NOTIFICATION
|
||||
}
|
||||
|
||||
Operation mOp;
|
||||
UUID mUuid;
|
||||
byte[] mValue;
|
||||
BluetoothGatt mGatt;
|
||||
boolean mResult = true;
|
||||
|
||||
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
|
||||
mGatt = gatt;
|
||||
mOp = operation;
|
||||
mUuid = uuid;
|
||||
}
|
||||
|
||||
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
|
||||
mGatt = gatt;
|
||||
mOp = operation;
|
||||
mUuid = uuid;
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// This is executed in main thread
|
||||
BluetoothGattCharacteristic chr;
|
||||
|
||||
switch (mOp) {
|
||||
case CHR_READ:
|
||||
chr = getCharacteristic(mUuid);
|
||||
//Log.v(TAG, "Reading characteristic " + chr.getUuid());
|
||||
if (!mGatt.readCharacteristic(chr)) {
|
||||
Log.e(TAG, "Unable to read characteristic " + mUuid.toString());
|
||||
mResult = false;
|
||||
break;
|
||||
}
|
||||
mResult = true;
|
||||
break;
|
||||
case CHR_WRITE:
|
||||
chr = getCharacteristic(mUuid);
|
||||
//Log.v(TAG, "Writing characteristic " + chr.getUuid() + " value=" + HexDump.toHexString(value));
|
||||
chr.setValue(mValue);
|
||||
if (!mGatt.writeCharacteristic(chr)) {
|
||||
Log.e(TAG, "Unable to write characteristic " + mUuid.toString());
|
||||
mResult = false;
|
||||
break;
|
||||
}
|
||||
mResult = true;
|
||||
break;
|
||||
case ENABLE_NOTIFICATION:
|
||||
chr = getCharacteristic(mUuid);
|
||||
//Log.v(TAG, "Writing descriptor of " + chr.getUuid());
|
||||
if (chr != null) {
|
||||
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
|
||||
if (cccd != null) {
|
||||
int properties = chr.getProperties();
|
||||
byte[] value;
|
||||
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == BluetoothGattCharacteristic.PROPERTY_NOTIFY) {
|
||||
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
|
||||
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE) {
|
||||
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
|
||||
} else {
|
||||
Log.e(TAG, "Unable to start notifications on input characteristic");
|
||||
mResult = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mGatt.setCharacteristicNotification(chr, true);
|
||||
cccd.setValue(value);
|
||||
if (!mGatt.writeDescriptor(cccd)) {
|
||||
Log.e(TAG, "Unable to write descriptor " + mUuid.toString());
|
||||
mResult = false;
|
||||
return;
|
||||
}
|
||||
mResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean finish() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
|
||||
BluetoothGattService valveService = mGatt.getService(steamControllerService);
|
||||
if (valveService == null)
|
||||
return null;
|
||||
return valveService.getCharacteristic(uuid);
|
||||
}
|
||||
|
||||
static public GattOperation readCharacteristic(BluetoothGatt gatt, UUID uuid) {
|
||||
return new GattOperation(gatt, Operation.CHR_READ, uuid);
|
||||
}
|
||||
|
||||
static public GattOperation writeCharacteristic(BluetoothGatt gatt, UUID uuid, byte[] value) {
|
||||
return new GattOperation(gatt, Operation.CHR_WRITE, uuid, value);
|
||||
}
|
||||
|
||||
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
|
||||
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
|
||||
mManager = manager;
|
||||
mDevice = device;
|
||||
mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
|
||||
mIsRegistered = false;
|
||||
mIsChromebook = mManager.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
|
||||
mOperations = new LinkedList<GattOperation>();
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
mGatt = connectGatt();
|
||||
final HIDDeviceBLESteamController finalThis = this;
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finalThis.checkConnectionForChromebookIssue();
|
||||
}
|
||||
}, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return String.format("SteamController.%s", mDevice.getAddress());
|
||||
}
|
||||
|
||||
public BluetoothGatt getGatt() {
|
||||
return mGatt;
|
||||
}
|
||||
|
||||
// Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
|
||||
// of TRANSPORT_LE. Let's force ourselves to connect low energy.
|
||||
private BluetoothGatt connectGatt(boolean managed) {
|
||||
try {
|
||||
Method m = mDevice.getClass().getDeclaredMethod("connectGatt", Context.class, boolean.class, BluetoothGattCallback.class, int.class);
|
||||
return (BluetoothGatt) m.invoke(mDevice, mManager.getContext(), managed, this, TRANSPORT_LE);
|
||||
} catch (Exception e) {
|
||||
return mDevice.connectGatt(mManager.getContext(), managed, this);
|
||||
}
|
||||
}
|
||||
|
||||
private BluetoothGatt connectGatt() {
|
||||
return connectGatt(false);
|
||||
}
|
||||
|
||||
protected int getConnectionState() {
|
||||
|
||||
Context context = mManager.getContext();
|
||||
if (context == null) {
|
||||
// We are lacking any context to get our Bluetooth information. We'll just assume disconnected.
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
BluetoothManager btManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
if (btManager == null) {
|
||||
// This device doesn't support Bluetooth. We should never be here, because how did
|
||||
// we instantiate a device to start with?
|
||||
return BluetoothProfile.STATE_DISCONNECTED;
|
||||
}
|
||||
|
||||
return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
|
||||
}
|
||||
|
||||
public void reconnect() {
|
||||
|
||||
if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
|
||||
mGatt.disconnect();
|
||||
mGatt = connectGatt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void checkConnectionForChromebookIssue() {
|
||||
if (!mIsChromebook) {
|
||||
// We only do this on Chromebooks, because otherwise it's really annoying to just attempt
|
||||
// over and over.
|
||||
return;
|
||||
}
|
||||
|
||||
int connectionState = getConnectionState();
|
||||
|
||||
switch (connectionState) {
|
||||
case BluetoothProfile.STATE_CONNECTED:
|
||||
if (!mIsConnected) {
|
||||
// We are in the Bad Chromebook Place. We can force a disconnect
|
||||
// to try to recover.
|
||||
Log.v(TAG, "Chromebook: We are in a very bad state; the controller shows as connected in the underlying Bluetooth layer, but we never received a callback. Forcing a reconnect.");
|
||||
mIsReconnecting = true;
|
||||
mGatt.disconnect();
|
||||
mGatt = connectGatt(false);
|
||||
break;
|
||||
}
|
||||
else if (!isRegistered()) {
|
||||
if (mGatt.getServices().size() > 0) {
|
||||
Log.v(TAG, "Chromebook: We are connected to a controller, but never got our registration. Trying to recover.");
|
||||
probeService(this);
|
||||
}
|
||||
else {
|
||||
Log.v(TAG, "Chromebook: We are connected to a controller, but never discovered services. Trying to recover.");
|
||||
mIsReconnecting = true;
|
||||
mGatt.disconnect();
|
||||
mGatt = connectGatt(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log.v(TAG, "Chromebook: We are connected, and registered. Everything's good!");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case BluetoothProfile.STATE_DISCONNECTED:
|
||||
Log.v(TAG, "Chromebook: We have either been disconnected, or the Chromebook BtGatt.ContextMap bug has bitten us. Attempting a disconnect/reconnect, but we may not be able to recover.");
|
||||
|
||||
mIsReconnecting = true;
|
||||
mGatt.disconnect();
|
||||
mGatt = connectGatt(false);
|
||||
break;
|
||||
|
||||
case BluetoothProfile.STATE_CONNECTING:
|
||||
Log.v(TAG, "Chromebook: We're still trying to connect. Waiting a bit longer.");
|
||||
break;
|
||||
}
|
||||
|
||||
final HIDDeviceBLESteamController finalThis = this;
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finalThis.checkConnectionForChromebookIssue();
|
||||
}
|
||||
}, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
|
||||
}
|
||||
|
||||
private boolean isRegistered() {
|
||||
return mIsRegistered;
|
||||
}
|
||||
|
||||
private void setRegistered() {
|
||||
mIsRegistered = true;
|
||||
}
|
||||
|
||||
private boolean probeService(HIDDeviceBLESteamController controller) {
|
||||
|
||||
if (isRegistered()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mIsConnected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.v(TAG, "probeService controller=" + controller);
|
||||
|
||||
for (BluetoothGattService service : mGatt.getServices()) {
|
||||
if (service.getUuid().equals(steamControllerService)) {
|
||||
Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
|
||||
|
||||
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
|
||||
if (chr.getUuid().equals(inputCharacteristic)) {
|
||||
Log.v(TAG, "Found input characteristic");
|
||||
// Start notifications
|
||||
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
|
||||
if (cccd != null) {
|
||||
enableNotification(chr.getUuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ((mGatt.getServices().size() == 0) && mIsChromebook && !mIsReconnecting) {
|
||||
Log.e(TAG, "Chromebook: Discovered services were empty; this almost certainly means the BtGatt.ContextMap bug has bitten us.");
|
||||
mIsConnected = false;
|
||||
mIsReconnecting = true;
|
||||
mGatt.disconnect();
|
||||
mGatt = connectGatt(false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void finishCurrentGattOperation() {
|
||||
GattOperation op = null;
|
||||
synchronized (mOperations) {
|
||||
if (mCurrentOperation != null) {
|
||||
op = mCurrentOperation;
|
||||
mCurrentOperation = null;
|
||||
}
|
||||
}
|
||||
if (op != null) {
|
||||
boolean result = op.finish(); // TODO: Maybe in main thread as well?
|
||||
|
||||
// Our operation failed, let's add it back to the beginning of our queue.
|
||||
if (!result) {
|
||||
mOperations.addFirst(op);
|
||||
}
|
||||
}
|
||||
executeNextGattOperation();
|
||||
}
|
||||
|
||||
private void executeNextGattOperation() {
|
||||
synchronized (mOperations) {
|
||||
if (mCurrentOperation != null)
|
||||
return;
|
||||
|
||||
if (mOperations.isEmpty())
|
||||
return;
|
||||
|
||||
mCurrentOperation = mOperations.removeFirst();
|
||||
}
|
||||
|
||||
// Run in main thread
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mOperations) {
|
||||
if (mCurrentOperation == null) {
|
||||
Log.e(TAG, "Current operation null in executor?");
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentOperation.run();
|
||||
// now wait for the GATT callback and when it comes, finish this operation
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void queueGattOperation(GattOperation op) {
|
||||
synchronized (mOperations) {
|
||||
mOperations.add(op);
|
||||
}
|
||||
executeNextGattOperation();
|
||||
}
|
||||
|
||||
private void enableNotification(UUID chrUuid) {
|
||||
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid);
|
||||
queueGattOperation(op);
|
||||
}
|
||||
|
||||
public void writeCharacteristic(UUID uuid, byte[] value) {
|
||||
GattOperation op = HIDDeviceBLESteamController.GattOperation.writeCharacteristic(mGatt, uuid, value);
|
||||
queueGattOperation(op);
|
||||
}
|
||||
|
||||
public void readCharacteristic(UUID uuid) {
|
||||
GattOperation op = HIDDeviceBLESteamController.GattOperation.readCharacteristic(mGatt, uuid);
|
||||
queueGattOperation(op);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////// BluetoothGattCallback overridden methods
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void onConnectionStateChange(BluetoothGatt g, int status, int newState) {
|
||||
//Log.v(TAG, "onConnectionStateChange status=" + status + " newState=" + newState);
|
||||
mIsReconnecting = false;
|
||||
if (newState == 2) {
|
||||
mIsConnected = true;
|
||||
// Run directly, without GattOperation
|
||||
if (!isRegistered()) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mGatt.discoverServices();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (newState == 0) {
|
||||
mIsConnected = false;
|
||||
}
|
||||
|
||||
// Disconnection is handled in SteamLink using the ACTION_ACL_DISCONNECTED Intent.
|
||||
}
|
||||
|
||||
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
|
||||
//Log.v(TAG, "onServicesDiscovered status=" + status);
|
||||
if (status == 0) {
|
||||
if (gatt.getServices().size() == 0) {
|
||||
Log.v(TAG, "onServicesDiscovered returned zero services; something has gone horribly wrong down in Android's Bluetooth stack.");
|
||||
mIsReconnecting = true;
|
||||
mIsConnected = false;
|
||||
gatt.disconnect();
|
||||
mGatt = connectGatt(false);
|
||||
}
|
||||
else {
|
||||
probeService(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
//Log.v(TAG, "onCharacteristicRead status=" + status + " uuid=" + characteristic.getUuid());
|
||||
|
||||
if (characteristic.getUuid().equals(reportCharacteristic) && !mFrozen) {
|
||||
mManager.HIDDeviceFeatureReport(getId(), characteristic.getValue());
|
||||
}
|
||||
|
||||
finishCurrentGattOperation();
|
||||
}
|
||||
|
||||
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
||||
//Log.v(TAG, "onCharacteristicWrite status=" + status + " uuid=" + characteristic.getUuid());
|
||||
|
||||
if (characteristic.getUuid().equals(reportCharacteristic)) {
|
||||
// Only register controller with the native side once it has been fully configured
|
||||
if (!isRegistered()) {
|
||||
Log.v(TAG, "Registering Steam Controller with ID: " + getId());
|
||||
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0);
|
||||
setRegistered();
|
||||
}
|
||||
}
|
||||
|
||||
finishCurrentGattOperation();
|
||||
}
|
||||
|
||||
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
|
||||
// Enable this for verbose logging of controller input reports
|
||||
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
|
||||
|
||||
if (characteristic.getUuid().equals(inputCharacteristic)) {
|
||||
mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
||||
//Log.v(TAG, "onDescriptorRead status=" + status);
|
||||
}
|
||||
|
||||
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
||||
BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
|
||||
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
|
||||
|
||||
if (chr.getUuid().equals(inputCharacteristic)) {
|
||||
boolean hasWrittenInputDescriptor = true;
|
||||
BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic);
|
||||
if (reportChr != null) {
|
||||
Log.v(TAG, "Writing report characteristic to enter valve mode");
|
||||
reportChr.setValue(enterValveMode);
|
||||
gatt.writeCharacteristic(reportChr);
|
||||
}
|
||||
}
|
||||
|
||||
finishCurrentGattOperation();
|
||||
}
|
||||
|
||||
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
|
||||
//Log.v(TAG, "onReliableWriteCompleted status=" + status);
|
||||
}
|
||||
|
||||
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
|
||||
//Log.v(TAG, "onReadRemoteRssi status=" + status);
|
||||
}
|
||||
|
||||
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
|
||||
//Log.v(TAG, "onMtuChanged status=" + status);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////// Public API
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return mDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVendorId() {
|
||||
// Valve Corporation
|
||||
final int VALVE_USB_VID = 0x28DE;
|
||||
return VALVE_USB_VID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProductId() {
|
||||
// We don't have an easy way to query from the Bluetooth device, but we know what it is
|
||||
final int D0G_BLE2_PID = 0x1106;
|
||||
return D0G_BLE2_PID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialNumber() {
|
||||
// This will be read later via feature report by Steam
|
||||
return "12345";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturerName() {
|
||||
return "Valve Corporation";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProductName() {
|
||||
return "Steam Controller";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean open() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendFeatureReport(byte[] report) {
|
||||
if (!isRegistered()) {
|
||||
Log.e(TAG, "Attempted sendFeatureReport before Steam Controller is registered!");
|
||||
if (mIsConnected) {
|
||||
probeService(this);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// We need to skip the first byte, as that doesn't go over the air
|
||||
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
|
||||
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(actual_report));
|
||||
writeCharacteristic(reportCharacteristic, actual_report);
|
||||
return report.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendOutputReport(byte[] report) {
|
||||
if (!isRegistered()) {
|
||||
Log.e(TAG, "Attempted sendOutputReport before Steam Controller is registered!");
|
||||
if (mIsConnected) {
|
||||
probeService(this);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(report));
|
||||
writeCharacteristic(reportCharacteristic, report);
|
||||
return report.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFeatureReport(byte[] report) {
|
||||
if (!isRegistered()) {
|
||||
Log.e(TAG, "Attempted getFeatureReport before Steam Controller is registered!");
|
||||
if (mIsConnected) {
|
||||
probeService(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//Log.v(TAG, "getFeatureReport");
|
||||
readCharacteristic(reportCharacteristic);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrozen(boolean frozen) {
|
||||
mFrozen = frozen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
BluetoothGatt g = mGatt;
|
||||
if (g != null) {
|
||||
g.disconnect();
|
||||
g.close();
|
||||
mGatt = null;
|
||||
}
|
||||
mManager = null;
|
||||
mIsRegistered = false;
|
||||
mIsConnected = false;
|
||||
mOperations.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,614 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.BluetoothProfile;
|
||||
import android.util.Log;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.usb.*;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HIDDeviceManager {
|
||||
private static final String TAG = "hidapi";
|
||||
private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION";
|
||||
|
||||
protected Context mContext;
|
||||
private HashMap<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>();
|
||||
private HashMap<UsbDevice, HIDDeviceUSB> mUSBDevices = new HashMap<UsbDevice, HIDDeviceUSB>();
|
||||
private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
|
||||
private int mNextDeviceId = 0;
|
||||
private SharedPreferences mSharedPreferences = null;
|
||||
private boolean mIsChromebook = false;
|
||||
private UsbManager mUsbManager;
|
||||
private Handler mHandler;
|
||||
private BluetoothManager mBluetoothManager;
|
||||
private List<BluetoothDevice> mLastBluetoothDevices;
|
||||
|
||||
private final BroadcastReceiver mUsbBroadcast = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
|
||||
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
handleUsbDeviceAttached(usbDevice);
|
||||
} else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
|
||||
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
handleUsbDeviceDetached(usbDevice);
|
||||
} else if (action.equals(HIDDeviceManager.ACTION_USB_PERMISSION)) {
|
||||
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
handleUsbDevicePermission(usbDevice, intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final BroadcastReceiver mBluetoothBroadcast = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
// Bluetooth device was connected. If it was a Steam Controller, handle it
|
||||
if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
|
||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
Log.d(TAG, "Bluetooth device connected: " + device);
|
||||
|
||||
if (isSteamController(device)) {
|
||||
connectBluetoothDevice(device);
|
||||
}
|
||||
}
|
||||
|
||||
// Bluetooth device was disconnected, remove from controller manager (if any)
|
||||
if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
|
||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
Log.d(TAG, "Bluetooth device disconnected: " + device);
|
||||
|
||||
disconnectBluetoothDevice(device);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public HIDDeviceManager(Context context) {
|
||||
mContext = context;
|
||||
|
||||
HIDDeviceRegisterCallback(this);
|
||||
|
||||
mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
|
||||
mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
|
||||
|
||||
// if (shouldClear) {
|
||||
// SharedPreferences.Editor spedit = mSharedPreferences.edit();
|
||||
// spedit.clear();
|
||||
// spedit.commit();
|
||||
// }
|
||||
// else
|
||||
{
|
||||
mNextDeviceId = mSharedPreferences.getInt("next_device_id", 0);
|
||||
}
|
||||
|
||||
initializeUSB();
|
||||
initializeBluetooth();
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public int getDeviceIDForIdentifier(String identifier) {
|
||||
SharedPreferences.Editor spedit = mSharedPreferences.edit();
|
||||
|
||||
int result = mSharedPreferences.getInt(identifier, 0);
|
||||
if (result == 0) {
|
||||
result = mNextDeviceId++;
|
||||
spedit.putInt("next_device_id", mNextDeviceId);
|
||||
}
|
||||
|
||||
spedit.putInt(identifier, result);
|
||||
spedit.commit();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void initializeUSB() {
|
||||
mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
|
||||
|
||||
/*
|
||||
// Logging
|
||||
for (UsbDevice device : mUsbManager.getDeviceList().values()) {
|
||||
Log.i(TAG,"Path: " + device.getDeviceName());
|
||||
Log.i(TAG,"Manufacturer: " + device.getManufacturerName());
|
||||
Log.i(TAG,"Product: " + device.getProductName());
|
||||
Log.i(TAG,"ID: " + device.getDeviceId());
|
||||
Log.i(TAG,"Class: " + device.getDeviceClass());
|
||||
Log.i(TAG,"Protocol: " + device.getDeviceProtocol());
|
||||
Log.i(TAG,"Vendor ID " + device.getVendorId());
|
||||
Log.i(TAG,"Product ID: " + device.getProductId());
|
||||
Log.i(TAG,"Interface count: " + device.getInterfaceCount());
|
||||
Log.i(TAG,"---------------------------------------");
|
||||
|
||||
// Get interface details
|
||||
for (int index = 0; index < device.getInterfaceCount(); index++) {
|
||||
UsbInterface mUsbInterface = device.getInterface(index);
|
||||
Log.i(TAG," ***** *****");
|
||||
Log.i(TAG," Interface index: " + index);
|
||||
Log.i(TAG," Interface ID: " + mUsbInterface.getId());
|
||||
Log.i(TAG," Interface class: " + mUsbInterface.getInterfaceClass());
|
||||
Log.i(TAG," Interface subclass: " + mUsbInterface.getInterfaceSubclass());
|
||||
Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
|
||||
Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
|
||||
|
||||
// Get endpoint details
|
||||
for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
|
||||
{
|
||||
UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
|
||||
Log.i(TAG," ++++ ++++ ++++");
|
||||
Log.i(TAG," Endpoint index: " + epi);
|
||||
Log.i(TAG," Attributes: " + mEndpoint.getAttributes());
|
||||
Log.i(TAG," Direction: " + mEndpoint.getDirection());
|
||||
Log.i(TAG," Number: " + mEndpoint.getEndpointNumber());
|
||||
Log.i(TAG," Interval: " + mEndpoint.getInterval());
|
||||
Log.i(TAG," Packet size: " + mEndpoint.getMaxPacketSize());
|
||||
Log.i(TAG," Type: " + mEndpoint.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.i(TAG," No more devices connected.");
|
||||
*/
|
||||
|
||||
// Register for USB broadcasts and permission completions
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
|
||||
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
|
||||
filter.addAction(HIDDeviceManager.ACTION_USB_PERMISSION);
|
||||
mContext.registerReceiver(mUsbBroadcast, filter);
|
||||
|
||||
for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
|
||||
handleUsbDeviceAttached(usbDevice);
|
||||
}
|
||||
}
|
||||
|
||||
UsbManager getUSBManager() {
|
||||
return mUsbManager;
|
||||
}
|
||||
|
||||
protected void shutdownUSB() {
|
||||
mContext.unregisterReceiver(mUsbBroadcast);
|
||||
}
|
||||
|
||||
protected boolean isHIDDeviceUSB(UsbDevice usbDevice) {
|
||||
for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); ++interface_number) {
|
||||
if (isHIDDeviceInterface(usbDevice, interface_number)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isHIDDeviceInterface(UsbDevice usbDevice, int interface_number) {
|
||||
UsbInterface usbInterface = usbDevice.getInterface(interface_number);
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
|
||||
return true;
|
||||
}
|
||||
if (interface_number == 0) {
|
||||
if (isXbox360Controller(usbDevice, usbInterface) || isXboxOneController(usbDevice, usbInterface)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
|
||||
final int XB360_IFACE_SUBCLASS = 93;
|
||||
final int XB360_IFACE_PROTOCOL = 1; // Wired only
|
||||
final int[] SUPPORTED_VENDORS = {
|
||||
0x0079, // GPD Win 2
|
||||
0x044f, // Thrustmaster
|
||||
0x045e, // Microsoft
|
||||
0x046d, // Logitech
|
||||
0x056e, // Elecom
|
||||
0x06a3, // Saitek
|
||||
0x0738, // Mad Catz
|
||||
0x07ff, // Mad Catz
|
||||
0x0e6f, // Unknown
|
||||
0x0f0d, // Hori
|
||||
0x11c9, // Nacon
|
||||
0x12ab, // Unknown
|
||||
0x1430, // RedOctane
|
||||
0x146b, // BigBen
|
||||
0x1532, // Razer Sabertooth
|
||||
0x15e4, // Numark
|
||||
0x162e, // Joytech
|
||||
0x1689, // Razer Onza
|
||||
0x1bad, // Harmonix
|
||||
0x24c6, // PowerA
|
||||
};
|
||||
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
|
||||
usbInterface.getInterfaceSubclass() == XB360_IFACE_SUBCLASS &&
|
||||
usbInterface.getInterfaceProtocol() == XB360_IFACE_PROTOCOL) {
|
||||
int vendor_id = usbDevice.getVendorId();
|
||||
for (int supportedVid : SUPPORTED_VENDORS) {
|
||||
if (vendor_id == supportedVid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
|
||||
final int XB1_IFACE_SUBCLASS = 71;
|
||||
final int XB1_IFACE_PROTOCOL = 208;
|
||||
final int[] SUPPORTED_VENDORS = {
|
||||
0x045e, // Microsoft
|
||||
0x0738, // Mad Catz
|
||||
0x0e6f, // Unknown
|
||||
0x0f0d, // Hori
|
||||
0x1532, // Razer Wildcat
|
||||
0x24c6, // PowerA
|
||||
};
|
||||
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
|
||||
usbInterface.getInterfaceSubclass() == XB1_IFACE_SUBCLASS &&
|
||||
usbInterface.getInterfaceProtocol() == XB1_IFACE_PROTOCOL) {
|
||||
int vendor_id = usbDevice.getVendorId();
|
||||
for (int supportedVid : SUPPORTED_VENDORS) {
|
||||
if (vendor_id == supportedVid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void handleUsbDeviceAttached(UsbDevice usbDevice) {
|
||||
if (isHIDDeviceUSB(usbDevice)) {
|
||||
connectHIDDeviceUSB(usbDevice);
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleUsbDeviceDetached(UsbDevice usbDevice) {
|
||||
HIDDeviceUSB device = mUSBDevices.get(usbDevice);
|
||||
if (device == null)
|
||||
return;
|
||||
|
||||
int id = device.getId();
|
||||
mUSBDevices.remove(usbDevice);
|
||||
mDevicesById.remove(id);
|
||||
device.shutdown();
|
||||
HIDDeviceDisconnected(id);
|
||||
}
|
||||
|
||||
protected void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
|
||||
HIDDeviceUSB device = mUSBDevices.get(usbDevice);
|
||||
if (device == null)
|
||||
return;
|
||||
|
||||
boolean opened = false;
|
||||
if (permission_granted) {
|
||||
opened = device.open();
|
||||
}
|
||||
HIDDeviceOpenResult(device.getId(), opened);
|
||||
}
|
||||
|
||||
protected void connectHIDDeviceUSB(UsbDevice usbDevice) {
|
||||
synchronized (this) {
|
||||
for (int interface_number = 0; interface_number < usbDevice.getInterfaceCount(); interface_number++) {
|
||||
if (isHIDDeviceInterface(usbDevice, interface_number)) {
|
||||
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_number);
|
||||
int id = device.getId();
|
||||
mUSBDevices.put(usbDevice, device);
|
||||
mDevicesById.put(id, device);
|
||||
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), interface_number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void initializeBluetooth() {
|
||||
Log.d(TAG, "Initializing Bluetooth");
|
||||
|
||||
// Find bonded bluetooth controllers and create SteamControllers for them
|
||||
mBluetoothManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
if (mBluetoothManager == null) {
|
||||
// This device doesn't support Bluetooth.
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothAdapter btAdapter = mBluetoothManager.getAdapter();
|
||||
if (btAdapter == null) {
|
||||
// This device has Bluetooth support in the codebase, but has no available adapters.
|
||||
return;
|
||||
}
|
||||
|
||||
// Get our bonded devices.
|
||||
for (BluetoothDevice device : btAdapter.getBondedDevices()) {
|
||||
|
||||
Log.d(TAG, "Bluetooth device available: " + device);
|
||||
if (isSteamController(device)) {
|
||||
connectBluetoothDevice(device);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOTE: These don't work on Chromebooks, to my undying dismay.
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
|
||||
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
|
||||
mContext.registerReceiver(mBluetoothBroadcast, filter);
|
||||
|
||||
if (mIsChromebook) {
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mLastBluetoothDevices = new ArrayList<>();
|
||||
|
||||
// final HIDDeviceManager finalThis = this;
|
||||
// mHandler.postDelayed(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// finalThis.chromebookConnectionHandler();
|
||||
// }
|
||||
// }, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
protected void shutdownBluetooth() {
|
||||
mContext.unregisterReceiver(mBluetoothBroadcast);
|
||||
}
|
||||
|
||||
// Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
|
||||
// This function provides a sort of dummy version of that, watching for changes in the
|
||||
// connected devices and attempting to add controllers as things change.
|
||||
public void chromebookConnectionHandler() {
|
||||
if (!mIsChromebook) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<BluetoothDevice> disconnected = new ArrayList<>();
|
||||
ArrayList<BluetoothDevice> connected = new ArrayList<>();
|
||||
|
||||
List<BluetoothDevice> currentConnected = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
|
||||
|
||||
for (BluetoothDevice bluetoothDevice : currentConnected) {
|
||||
if (!mLastBluetoothDevices.contains(bluetoothDevice)) {
|
||||
connected.add(bluetoothDevice);
|
||||
}
|
||||
}
|
||||
for (BluetoothDevice bluetoothDevice : mLastBluetoothDevices) {
|
||||
if (!currentConnected.contains(bluetoothDevice)) {
|
||||
disconnected.add(bluetoothDevice);
|
||||
}
|
||||
}
|
||||
|
||||
mLastBluetoothDevices = currentConnected;
|
||||
|
||||
for (BluetoothDevice bluetoothDevice : disconnected) {
|
||||
disconnectBluetoothDevice(bluetoothDevice);
|
||||
}
|
||||
for (BluetoothDevice bluetoothDevice : connected) {
|
||||
connectBluetoothDevice(bluetoothDevice);
|
||||
}
|
||||
|
||||
final HIDDeviceManager finalThis = this;
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
finalThis.chromebookConnectionHandler();
|
||||
}
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
|
||||
Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
|
||||
synchronized (this) {
|
||||
if (mBluetoothDevices.containsKey(bluetoothDevice)) {
|
||||
Log.v(TAG, "Steam controller with address " + bluetoothDevice + " already exists, attempting reconnect");
|
||||
|
||||
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
|
||||
device.reconnect();
|
||||
|
||||
return false;
|
||||
}
|
||||
HIDDeviceBLESteamController device = new HIDDeviceBLESteamController(this, bluetoothDevice);
|
||||
int id = device.getId();
|
||||
mBluetoothDevices.put(bluetoothDevice, device);
|
||||
mDevicesById.put(id, device);
|
||||
|
||||
// The Steam Controller will mark itself connected once initialization is complete
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
|
||||
synchronized (this) {
|
||||
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
|
||||
if (device == null)
|
||||
return;
|
||||
|
||||
int id = device.getId();
|
||||
mBluetoothDevices.remove(bluetoothDevice);
|
||||
mDevicesById.remove(id);
|
||||
device.shutdown();
|
||||
HIDDeviceDisconnected(id);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSteamController(BluetoothDevice bluetoothDevice) {
|
||||
// Sanity check. If you pass in a null device, by definition it is never a Steam Controller.
|
||||
if (bluetoothDevice == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the device has no local name, we really don't want to try an equality check against it.
|
||||
if (bluetoothDevice.getName() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
shutdownUSB();
|
||||
shutdownBluetooth();
|
||||
synchronized (this) {
|
||||
for (HIDDevice device : mDevicesById.values()) {
|
||||
device.shutdown();
|
||||
}
|
||||
mDevicesById.clear();
|
||||
mBluetoothDevices.clear();
|
||||
HIDDeviceReleaseCallback();
|
||||
}
|
||||
}
|
||||
|
||||
public void setFrozen(boolean frozen) {
|
||||
synchronized (this) {
|
||||
for (HIDDevice device : mDevicesById.values()) {
|
||||
device.setFrozen(frozen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private HIDDevice getDevice(int id) {
|
||||
synchronized (this) {
|
||||
HIDDevice result = mDevicesById.get(id);
|
||||
if (result == null) {
|
||||
Log.v(TAG, "No device for id: " + id);
|
||||
Log.v(TAG, "Available devices: " + mDevicesById.keySet());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////// JNI interface functions
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
boolean openDevice(int deviceID) {
|
||||
// Look to see if this is a USB device and we have permission to access it
|
||||
for (HIDDeviceUSB device : mUSBDevices.values()) {
|
||||
if (deviceID == device.getId()) {
|
||||
UsbDevice usbDevice = device.getDevice();
|
||||
if (!mUsbManager.hasPermission(usbDevice)) {
|
||||
HIDDeviceOpenPending(deviceID);
|
||||
try {
|
||||
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
|
||||
} catch (Exception e) {
|
||||
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
|
||||
HIDDeviceOpenResult(deviceID, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Log.v(TAG, "openDevice deviceID=" + deviceID);
|
||||
HIDDevice device;
|
||||
device = getDevice(deviceID);
|
||||
if (device == null) {
|
||||
HIDDeviceDisconnected(deviceID);
|
||||
return false;
|
||||
}
|
||||
|
||||
return device.open();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int sendOutputReport(int deviceID, byte[] report) {
|
||||
try {
|
||||
Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
|
||||
HIDDevice device;
|
||||
device = getDevice(deviceID);
|
||||
if (device == null) {
|
||||
HIDDeviceDisconnected(deviceID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return device.sendOutputReport(report);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sendFeatureReport(int deviceID, byte[] report) {
|
||||
try {
|
||||
Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
|
||||
HIDDevice device;
|
||||
device = getDevice(deviceID);
|
||||
if (device == null) {
|
||||
HIDDeviceDisconnected(deviceID);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return device.sendFeatureReport(report);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
boolean getFeatureReport(int deviceID, byte[] report) {
|
||||
try {
|
||||
Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
|
||||
HIDDevice device;
|
||||
device = getDevice(deviceID);
|
||||
if (device == null) {
|
||||
HIDDeviceDisconnected(deviceID);
|
||||
return false;
|
||||
}
|
||||
|
||||
return device.getFeatureReport(report);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void closeDevice(int deviceID) {
|
||||
try {
|
||||
Log.v(TAG, "closeDevice deviceID=" + deviceID);
|
||||
HIDDevice device;
|
||||
device = getDevice(deviceID);
|
||||
if (device == null) {
|
||||
HIDDeviceDisconnected(deviceID);
|
||||
return;
|
||||
}
|
||||
|
||||
device.close();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////// Native methods
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private native void HIDDeviceRegisterCallback(Object callbackHandler);
|
||||
private native void HIDDeviceReleaseCallback();
|
||||
|
||||
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number);
|
||||
native void HIDDeviceOpenPending(int deviceID);
|
||||
native void HIDDeviceOpenResult(int deviceID, boolean opened);
|
||||
native void HIDDeviceDisconnected(int deviceID);
|
||||
|
||||
native void HIDDeviceInputReport(int deviceID, byte[] report);
|
||||
native void HIDDeviceFeatureReport(int deviceID, byte[] report);
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
package org.libsdl.app;
|
||||
|
||||
import android.hardware.usb.*;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import java.util.Arrays;
|
||||
|
||||
class HIDDeviceUSB implements HIDDevice {
|
||||
|
||||
private static final String TAG = "hidapi";
|
||||
|
||||
protected HIDDeviceManager mManager;
|
||||
protected UsbDevice mDevice;
|
||||
protected int mInterface;
|
||||
protected int mDeviceId;
|
||||
protected UsbDeviceConnection mConnection;
|
||||
protected UsbEndpoint mInputEndpoint;
|
||||
protected UsbEndpoint mOutputEndpoint;
|
||||
protected InputThread mInputThread;
|
||||
protected boolean mRunning;
|
||||
protected boolean mFrozen;
|
||||
|
||||
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_number) {
|
||||
mManager = manager;
|
||||
mDevice = usbDevice;
|
||||
mInterface = interface_number;
|
||||
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
|
||||
mRunning = false;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return String.format("%s/%x/%x", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return mDeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVendorId() {
|
||||
return mDevice.getVendorId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProductId() {
|
||||
return mDevice.getProductId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSerialNumber() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
result = mDevice.getSerialNumber();
|
||||
}
|
||||
if (result == null) {
|
||||
result = "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturerName() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
result = mDevice.getManufacturerName();
|
||||
}
|
||||
if (result == null) {
|
||||
result = String.format("%x", getVendorId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProductName() {
|
||||
String result = null;
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
result = mDevice.getProductName();
|
||||
}
|
||||
if (result == null) {
|
||||
result = String.format("%x", getProductId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public UsbDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean open() {
|
||||
mConnection = mManager.getUSBManager().openDevice(mDevice);
|
||||
if (mConnection == null) {
|
||||
Log.w(TAG, "Unable to open USB device " + getDeviceName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force claim all interfaces
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface iface = mDevice.getInterface(i);
|
||||
|
||||
if (!mConnection.claimInterface(iface, true)) {
|
||||
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the endpoints
|
||||
UsbInterface iface = mDevice.getInterface(mInterface);
|
||||
for (int j = 0; j < iface.getEndpointCount(); j++) {
|
||||
UsbEndpoint endpt = iface.getEndpoint(j);
|
||||
switch (endpt.getDirection()) {
|
||||
case UsbConstants.USB_DIR_IN:
|
||||
if (mInputEndpoint == null) {
|
||||
mInputEndpoint = endpt;
|
||||
}
|
||||
break;
|
||||
case UsbConstants.USB_DIR_OUT:
|
||||
if (mOutputEndpoint == null) {
|
||||
mOutputEndpoint = endpt;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the required endpoints were present
|
||||
if (mInputEndpoint == null || mOutputEndpoint == null) {
|
||||
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start listening for input
|
||||
mRunning = true;
|
||||
mInputThread = new InputThread();
|
||||
mInputThread.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendFeatureReport(byte[] report) {
|
||||
int res = -1;
|
||||
int offset = 0;
|
||||
int length = report.length;
|
||||
boolean skipped_report_id = false;
|
||||
byte report_number = report[0];
|
||||
|
||||
if (report_number == 0x0) {
|
||||
++offset;
|
||||
--length;
|
||||
skipped_report_id = true;
|
||||
}
|
||||
|
||||
res = mConnection.controlTransfer(
|
||||
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
|
||||
0x09/*HID set_report*/,
|
||||
(3/*HID feature*/ << 8) | report_number,
|
||||
0,
|
||||
report, offset, length,
|
||||
1000/*timeout millis*/);
|
||||
|
||||
if (res < 0) {
|
||||
Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (skipped_report_id) {
|
||||
++length;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendOutputReport(byte[] report) {
|
||||
int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
|
||||
if (r != report.length) {
|
||||
Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getFeatureReport(byte[] report) {
|
||||
int res = -1;
|
||||
int offset = 0;
|
||||
int length = report.length;
|
||||
boolean skipped_report_id = false;
|
||||
byte report_number = report[0];
|
||||
|
||||
if (report_number == 0x0) {
|
||||
/* Offset the return buffer by 1, so that the report ID
|
||||
will remain in byte 0. */
|
||||
++offset;
|
||||
--length;
|
||||
skipped_report_id = true;
|
||||
}
|
||||
|
||||
res = mConnection.controlTransfer(
|
||||
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
|
||||
0x01/*HID get_report*/,
|
||||
(3/*HID feature*/ << 8) | report_number,
|
||||
0,
|
||||
report, offset, length,
|
||||
1000/*timeout millis*/);
|
||||
|
||||
if (res < 0) {
|
||||
Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skipped_report_id) {
|
||||
++res;
|
||||
++length;
|
||||
}
|
||||
|
||||
byte[] data;
|
||||
if (res == length) {
|
||||
data = report;
|
||||
} else {
|
||||
data = Arrays.copyOfRange(report, 0, res);
|
||||
}
|
||||
mManager.HIDDeviceFeatureReport(mDeviceId, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mRunning = false;
|
||||
if (mInputThread != null) {
|
||||
while (mInputThread.isAlive()) {
|
||||
mInputThread.interrupt();
|
||||
try {
|
||||
mInputThread.join();
|
||||
} catch (InterruptedException e) {
|
||||
// Keep trying until we're done
|
||||
}
|
||||
}
|
||||
mInputThread = null;
|
||||
}
|
||||
if (mConnection != null) {
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface iface = mDevice.getInterface(i);
|
||||
mConnection.releaseInterface(iface);
|
||||
}
|
||||
mConnection.close();
|
||||
mConnection = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
close();
|
||||
mManager = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrozen(boolean frozen) {
|
||||
mFrozen = frozen;
|
||||
}
|
||||
|
||||
protected class InputThread extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
int packetSize = mInputEndpoint.getMaxPacketSize();
|
||||
byte[] packet = new byte[packetSize];
|
||||
while (mRunning) {
|
||||
int r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
|
||||
if (r < 0) {
|
||||
// Could be a timeout or an I/O error
|
||||
}
|
||||
if (r > 0) {
|
||||
byte[] data;
|
||||
if (r == packetSize) {
|
||||
data = packet;
|
||||
} else {
|
||||
data = Arrays.copyOfRange(packet, 0, r);
|
||||
}
|
||||
|
||||
if (!mFrozen) {
|
||||
mManager.HIDDeviceInputReport(mDeviceId, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
protected static Hashtable<Integer, Object> mCursors;
|
||||
protected static int mLastCursorID;
|
||||
protected static SDLGenericMotionListener_API12 mMotionListener;
|
||||
|
||||
protected static HIDDeviceManager mHIDDeviceManager;
|
||||
|
||||
// This is what SDL runs in. It invokes SDL_main(), eventually
|
||||
protected static Thread mSDLThread;
|
||||
|
@ -241,6 +241,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
mClipboardHandler = new SDLClipboardHandler_Old();
|
||||
}
|
||||
|
||||
mHIDDeviceManager = new HIDDeviceManager(this);
|
||||
|
||||
// Set up the surface
|
||||
mSurface = new SDLSurface(getApplication());
|
||||
|
||||
|
@ -276,6 +278,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
return;
|
||||
}
|
||||
|
||||
if (mHIDDeviceManager != null) {
|
||||
mHIDDeviceManager.setFrozen(true);
|
||||
}
|
||||
|
||||
SDLActivity.handleNativeState();
|
||||
}
|
||||
|
||||
|
@ -290,6 +296,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
return;
|
||||
}
|
||||
|
||||
if (mHIDDeviceManager != null) {
|
||||
mHIDDeviceManager.setFrozen(false);
|
||||
}
|
||||
|
||||
SDLActivity.handleNativeState();
|
||||
}
|
||||
|
||||
|
@ -330,6 +340,11 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
protected void onDestroy() {
|
||||
Log.v(TAG, "onDestroy()");
|
||||
|
||||
if (mHIDDeviceManager != null) {
|
||||
mHIDDeviceManager.close();
|
||||
mHIDDeviceManager = null;
|
||||
}
|
||||
|
||||
if (SDLActivity.mBrokenLibraries) {
|
||||
super.onDestroy();
|
||||
// Reset everything in case the user re opens the app
|
||||
|
@ -466,10 +481,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||
/* The native thread has finished */
|
||||
public static void handleNativeExit() {
|
||||
SDLActivity.mSDLThread = null;
|
||||
|
||||
// Make sure we currently have a singleton before we try to call it.
|
||||
if (mSingleton != null)
|
||||
mSingleton.finish();
|
||||
mSingleton.finish();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -868,6 +868,7 @@ enable_pthread_sem
|
|||
enable_directx
|
||||
enable_wasapi
|
||||
enable_sdl_dlopen
|
||||
enable_hidapi
|
||||
enable_clock_gettime
|
||||
enable_rpath
|
||||
enable_render_d3d
|
||||
|
@ -1623,6 +1624,8 @@ Optional Features:
|
|||
--enable-directx use DirectX for Windows audio/video [[default=yes]]
|
||||
--enable-wasapi use the Windows WASAPI audio driver [[default=yes]]
|
||||
--enable-sdl-dlopen use dlopen for shared object loading [[default=yes]]
|
||||
--enable-hidapi use HIDAPI for low level joystick drivers
|
||||
[[default=no]]
|
||||
--enable-clock_gettime use clock_gettime() instead of gettimeofday() on
|
||||
UNIX [[default=yes]]
|
||||
--enable-rpath use an rpath when linking SDL [[default=yes]]
|
||||
|
@ -16773,7 +16776,7 @@ $as_echo "#define HAVE_SA_SIGACTION 1" >>confdefs.h
|
|||
fi
|
||||
|
||||
|
||||
for ac_header in libunwind.h
|
||||
for ac_header in libunwind.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "libunwind.h" "ac_cv_header_libunwind_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_libunwind_h" = xyes; then :
|
||||
|
@ -18377,7 +18380,7 @@ fi
|
|||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PulseAudio $PULSEAUDIO_REQUIRED_VERSION support" >&5
|
||||
$as_echo_n "checking for PulseAudio $PULSEAUDIO_REQUIRED_VERSION support... " >&6; }
|
||||
if test x$PKG_CONFIG != xno; then
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.7 && $PKG_CONFIG --atleast-version $PULSEAUDIO_REQUIRED_VERSION libpulse-simple; then
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.7 && $PKG_CONFIG --atleast-version $PULSEAUDIO_REQUIRED_VERSION libpulse-simple; then
|
||||
PULSEAUDIO_CFLAGS=`$PKG_CONFIG --cflags libpulse-simple`
|
||||
PULSEAUDIO_LIBS=`$PKG_CONFIG --libs libpulse-simple`
|
||||
audio_pulseaudio=yes
|
||||
|
@ -20463,7 +20466,7 @@ $as_echo_n "checking for XGenericEvent... " >&6; }
|
|||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
int
|
||||
main ()
|
||||
|
@ -20807,13 +20810,13 @@ $as_echo "#define SDL_VIDEO_DRIVER_X11_XINPUT2 1" >>confdefs.h
|
|||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xinput2 multitouch" >&5
|
||||
$as_echo_n "checking for xinput2 multitouch... " >&6; }
|
||||
have_xinput2_multitouch=no
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
have_xinput2_multitouch=no
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
|
||||
int
|
||||
main ()
|
||||
|
@ -20828,14 +20831,14 @@ XITouchClassInfo *t;
|
|||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
|
||||
have_xinput2_multitouch=yes
|
||||
$as_echo "#define SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1" >>confdefs.h
|
||||
have_xinput2_multitouch=yes
|
||||
$as_echo "#define SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH 1" >>confdefs.h
|
||||
|
||||
SUMMARY_video_x11="${SUMMARY_video_x11} xinput2_multitouch"
|
||||
SUMMARY_video_x11="${SUMMARY_video_x11} xinput2_multitouch"
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_xinput2_multitouch" >&5
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_xinput2_multitouch" >&5
|
||||
$as_echo "$have_xinput2_multitouch" >&6; }
|
||||
fi
|
||||
# Check whether --enable-video-x11-xrandr was given.
|
||||
|
@ -23728,6 +23731,93 @@ $as_echo "#define SDL_JOYSTICK_USBHID 1" >>confdefs.h
|
|||
esac
|
||||
}
|
||||
|
||||
CheckHIDAPI()
|
||||
{
|
||||
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
|
||||
# so we'll just use libusb when it's available.
|
||||
#
|
||||
# Except that libusb requires root permissions to open devices, so that's not generally useful, and we'll disable this by default.
|
||||
# Check whether --enable-hidapi was given.
|
||||
if test "${enable_hidapi+set}" = set; then :
|
||||
enableval=$enable_hidapi;
|
||||
else
|
||||
enable_hidapi=no
|
||||
fi
|
||||
|
||||
if test x$enable_joystick = xyes -a x$enable_hidapi = xyes; then
|
||||
hidapi_support=no
|
||||
# Extract the first word of "pkg-config", so it can be a program name with args.
|
||||
set dummy pkg-config; ac_word=$2
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
|
||||
$as_echo_n "checking for $ac_word... " >&6; }
|
||||
if ${ac_cv_path_PKG_CONFIG+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
case $PKG_CONFIG in
|
||||
[\\/]* | ?:[\\/]*)
|
||||
ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
|
||||
;;
|
||||
*)
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for ac_exec_ext in '' $ac_executable_extensions; do
|
||||
if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
|
||||
ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
|
||||
$as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
IFS=$as_save_IFS
|
||||
|
||||
test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
PKG_CONFIG=$ac_cv_path_PKG_CONFIG
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
|
||||
$as_echo "$PKG_CONFIG" >&6; }
|
||||
else
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
$as_echo "no" >&6; }
|
||||
fi
|
||||
|
||||
|
||||
if test x$PKG_CONFIG != xno; then
|
||||
LIBUSB_CFLAGS=`$PKG_CONFIG --cflags libusb-1.0`
|
||||
LIBUSB_LDFLAGS=`$PKG_CONFIG --libs libusb-1.0`
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$save_CFLAGS $LIBUSB_CFLAGS"
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_libusb_h" = xyes; then :
|
||||
have_libusb_h=yes
|
||||
fi
|
||||
|
||||
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
if test x$have_libusb_h = xyes; then
|
||||
hidapi_support=yes
|
||||
|
||||
$as_echo "#define SDL_JOYSTICK_HIDAPI 1" >>confdefs.h
|
||||
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/hidapi/libusb/hid.c"
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBUSB_CFLAGS"
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBUSB_LDFLAGS"
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for hidapi support" >&5
|
||||
$as_echo_n "checking for hidapi support... " >&6; }
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hidapi_support" >&5
|
||||
$as_echo "$hidapi_support" >&6; }
|
||||
fi
|
||||
}
|
||||
|
||||
CheckClockGettime()
|
||||
{
|
||||
# Check whether --enable-clock_gettime was given.
|
||||
|
@ -23939,6 +24029,7 @@ case "$host" in
|
|||
esac
|
||||
CheckTslib
|
||||
CheckUSBHID
|
||||
CheckHIDAPI
|
||||
CheckPTHREAD
|
||||
CheckClockGettime
|
||||
CheckLinuxVersion
|
||||
|
@ -24514,7 +24605,13 @@ $as_echo "#define SDL_AUDIO_DRIVER_COREAUDIO 1" >>confdefs.h
|
|||
|
||||
$as_echo "#define SDL_JOYSTICK_IOKIT 1" >>confdefs.h
|
||||
|
||||
|
||||
$as_echo "#define SDL_JOYSTICK_HIDAPI 1" >>confdefs.h
|
||||
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/darwin/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/hidapi/mac/hid.c"
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
|
||||
have_joystick=yes
|
||||
fi
|
||||
# Set up files for the haptic library
|
||||
|
|
70
configure.in
70
configure.in
|
@ -285,7 +285,7 @@ if test x$enable_libc = xyes; then
|
|||
|
||||
AC_CHECK_MEMBER(struct sigaction.sa_sigaction,[AC_DEFINE([HAVE_SA_SIGACTION], 1, [ ])], ,[#include <signal.h>])
|
||||
|
||||
dnl Check for additional non-standard headers
|
||||
dnl Check for additional non-standard headers
|
||||
AC_CHECK_HEADERS(libunwind.h)
|
||||
fi
|
||||
|
||||
|
@ -963,7 +963,7 @@ AC_HELP_STRING([--enable-pulseaudio], [use PulseAudio [[default=yes]]]),
|
|||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
AC_MSG_CHECKING(for PulseAudio $PULSEAUDIO_REQUIRED_VERSION support)
|
||||
if test x$PKG_CONFIG != xno; then
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.7 && $PKG_CONFIG --atleast-version $PULSEAUDIO_REQUIRED_VERSION libpulse-simple; then
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.7 && $PKG_CONFIG --atleast-version $PULSEAUDIO_REQUIRED_VERSION libpulse-simple; then
|
||||
PULSEAUDIO_CFLAGS=`$PKG_CONFIG --cflags libpulse-simple`
|
||||
PULSEAUDIO_LIBS=`$PKG_CONFIG --libs libpulse-simple`
|
||||
audio_pulseaudio=yes
|
||||
|
@ -1748,7 +1748,7 @@ AC_HELP_STRING([--enable-x11-shared], [dynamically load X11 support [[default=ma
|
|||
AC_MSG_CHECKING([for XGenericEvent])
|
||||
have_XGenericEvent=no
|
||||
AC_TRY_COMPILE([
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
],[
|
||||
Display *display;
|
||||
XEvent event;
|
||||
|
@ -1862,20 +1862,20 @@ AC_HELP_STRING([--enable-video-x11-xinput], [enable X11 XInput extension for man
|
|||
SUMMARY_video_x11="${SUMMARY_video_x11} xinput2"
|
||||
AC_DEFINE(SDL_VIDEO_DRIVER_X11_XINPUT2, 1, [ ])
|
||||
AC_MSG_CHECKING(for xinput2 multitouch)
|
||||
have_xinput2_multitouch=no
|
||||
AC_TRY_COMPILE([
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
],[
|
||||
have_xinput2_multitouch=no
|
||||
AC_TRY_COMPILE([
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xproto.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
],[
|
||||
int event_type = XI_TouchBegin;
|
||||
XITouchClassInfo *t;
|
||||
],[
|
||||
have_xinput2_multitouch=yes
|
||||
AC_DEFINE([SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH], 1, [])
|
||||
SUMMARY_video_x11="${SUMMARY_video_x11} xinput2_multitouch"
|
||||
])
|
||||
AC_MSG_RESULT($have_xinput2_multitouch)
|
||||
],[
|
||||
have_xinput2_multitouch=yes
|
||||
AC_DEFINE([SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH], 1, [])
|
||||
SUMMARY_video_x11="${SUMMARY_video_x11} xinput2_multitouch"
|
||||
])
|
||||
AC_MSG_RESULT($have_xinput2_multitouch)
|
||||
fi
|
||||
AC_ARG_ENABLE(video-x11-xrandr,
|
||||
AC_HELP_STRING([--enable-video-x11-xrandr], [enable X11 Xrandr extension for fullscreen [[default=yes]]]),
|
||||
|
@ -3265,6 +3265,41 @@ CheckUSBHID()
|
|||
esac
|
||||
}
|
||||
|
||||
dnl Check for HIDAPI joystick drivers
|
||||
CheckHIDAPI()
|
||||
{
|
||||
# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
|
||||
# so we'll just use libusb when it's available.
|
||||
#
|
||||
# Except that libusb requires root permissions to open devices, so that's not generally useful, and we'll disable this by default.
|
||||
AC_ARG_ENABLE(hidapi,
|
||||
AC_HELP_STRING([--enable-hidapi], [use HIDAPI for low level joystick drivers [[default=no]]]),
|
||||
, enable_hidapi=no)
|
||||
if test x$enable_joystick = xyes -a x$enable_hidapi = xyes; then
|
||||
hidapi_support=no
|
||||
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
|
||||
if test x$PKG_CONFIG != xno; then
|
||||
LIBUSB_CFLAGS=`$PKG_CONFIG --cflags libusb-1.0`
|
||||
LIBUSB_LDFLAGS=`$PKG_CONFIG --libs libusb-1.0`
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$save_CFLAGS $LIBUSB_CFLAGS"
|
||||
AC_CHECK_HEADER(libusb.h, have_libusb_h=yes)
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
if test x$have_libusb_h = xyes; then
|
||||
hidapi_support=yes
|
||||
AC_DEFINE(SDL_JOYSTICK_HIDAPI, 1, [ ])
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/hidapi/libusb/hid.c"
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBUSB_CFLAGS"
|
||||
EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBUSB_LDFLAGS"
|
||||
fi
|
||||
AC_MSG_CHECKING(for hidapi support)
|
||||
AC_MSG_RESULT($hidapi_support)
|
||||
fi
|
||||
}
|
||||
|
||||
dnl Check for clock_gettime()
|
||||
CheckClockGettime()
|
||||
{
|
||||
|
@ -3386,6 +3421,7 @@ case "$host" in
|
|||
esac
|
||||
CheckTslib
|
||||
CheckUSBHID
|
||||
CheckHIDAPI
|
||||
CheckPTHREAD
|
||||
CheckClockGettime
|
||||
CheckLinuxVersion
|
||||
|
@ -3811,7 +3847,11 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
|
|||
# Set up files for the joystick library
|
||||
if test x$enable_joystick = xyes; then
|
||||
AC_DEFINE(SDL_JOYSTICK_IOKIT, 1, [ ])
|
||||
AC_DEFINE(SDL_JOYSTICK_HIDAPI, 1, [ ])
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/darwin/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
|
||||
SOURCES="$SOURCES $srcdir/src/hidapi/mac/hid.c"
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
|
||||
have_joystick=yes
|
||||
fi
|
||||
# Set up files for the haptic library
|
||||
|
|
|
@ -279,6 +279,7 @@
|
|||
#undef SDL_JOYSTICK_WINMM
|
||||
#undef SDL_JOYSTICK_USBHID
|
||||
#undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
|
||||
#undef SDL_JOYSTICK_HIDAPI
|
||||
#undef SDL_JOYSTICK_EMSCRIPTEN
|
||||
#undef SDL_HAPTIC_DUMMY
|
||||
#undef SDL_HAPTIC_ANDROID
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
|
||||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_ANDROID 1
|
||||
#define SDL_JOYSTICK_HIDAPI 1
|
||||
#define SDL_HAPTIC_ANDROID 1
|
||||
|
||||
/* Enable various shared object loading systems */
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
|
||||
/* Enable MFi joystick support */
|
||||
#define SDL_JOYSTICK_MFI 1
|
||||
#define SDL_JOYSTICK_HIDAPI 1
|
||||
|
||||
/* Enable Unix style SO loading */
|
||||
#define SDL_LOADSO_DLOPEN 1
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
|
||||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_IOKIT 1
|
||||
#define SDL_JOYSTICK_HIDAPI 1
|
||||
#define SDL_HAPTIC_IOKIT 1
|
||||
|
||||
/* Enable various shared object loading systems */
|
||||
|
|
|
@ -190,6 +190,7 @@ typedef unsigned int uintptr_t;
|
|||
/* Enable various input drivers */
|
||||
#define SDL_JOYSTICK_DINPUT 1
|
||||
#define SDL_JOYSTICK_XINPUT 1
|
||||
#define SDL_JOYSTICK_HIDAPI 1
|
||||
#define SDL_HAPTIC_DINPUT 1
|
||||
#define SDL_HAPTIC_XINPUT 1
|
||||
|
||||
|
|
|
@ -353,6 +353,19 @@ SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
|
|||
extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
|
||||
SDL_GameControllerButton button);
|
||||
|
||||
/**
|
||||
* Trigger a rumble effect
|
||||
* Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
|
||||
*
|
||||
* \param gamecontroller The controller to vibrate
|
||||
* \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
|
||||
* \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
|
||||
* \param duration_ms The duration of the rumble effect, in milliseconds
|
||||
*
|
||||
* \return 0, or -1 if rumble isn't supported on this joystick
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
|
||||
/**
|
||||
* Close a controller previously opened with SDL_GameControllerOpen().
|
||||
*/
|
||||
|
|
|
@ -656,8 +656,8 @@ typedef struct SDL_HapticRamp
|
|||
* This struct is exclusively for the ::SDL_HAPTIC_LEFTRIGHT effect.
|
||||
*
|
||||
* The Left/Right effect is used to explicitly control the large and small
|
||||
* motors, commonly found in modern game controllers. One motor is high
|
||||
* frequency, the other is low frequency.
|
||||
* motors, commonly found in modern game controllers. The small (right) motor
|
||||
* is high frequency, and the large (left) motor is low frequency.
|
||||
*
|
||||
* \sa SDL_HAPTIC_LEFTRIGHT
|
||||
* \sa SDL_HapticEffect
|
||||
|
@ -668,7 +668,7 @@ typedef struct SDL_HapticLeftRight
|
|||
Uint16 type; /**< ::SDL_HAPTIC_LEFTRIGHT */
|
||||
|
||||
/* Replay */
|
||||
Uint32 length; /**< Duration of the effect. */
|
||||
Uint32 length; /**< Duration of the effect in milliseconds. */
|
||||
|
||||
/* Rumble */
|
||||
Uint16 large_magnitude; /**< Control of the large controller motor. */
|
||||
|
|
|
@ -465,6 +465,84 @@ extern "C" {
|
|||
*/
|
||||
#define SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI joystick drivers should be used.
|
||||
*
|
||||
* This variable can be set to the following values:
|
||||
* "0" - HIDAPI drivers are not used
|
||||
* "1" - HIDAPI drivers are used (the default)
|
||||
*
|
||||
* This variable is the default for all drivers, but can be overridden by the hints for specific drivers below.
|
||||
*/
|
||||
#define SDL_HINT_JOYSTICK_HIDAPI "SDL_JOYSTICK_HIDAPI"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for PS4 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_PS4 "SDL_JOYSTICK_HIDAPI_PS4"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for Steam 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_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for Nintendo Switch 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_SWITCH "SDL_JOYSTICK_HIDAPI_SWITCH"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for XBox 360 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_XBOX360 "SDL_JOYSTICK_HIDAPI_XBOX360"
|
||||
|
||||
/**
|
||||
* \brief A variable controlling whether the HIDAPI driver for XBox One 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_XBOXONE "SDL_JOYSTICK_HIDAPI_XBOXONE"
|
||||
|
||||
/**
|
||||
* \brief A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
|
||||
*
|
||||
* The variable can be set to the following values:
|
||||
* "0" - Do not scan for Steam Controllers
|
||||
* "1" - Scan for Steam Controllers (the default)
|
||||
*
|
||||
* The default value is "1". This hint must be set before initializing the joystick subsystem.
|
||||
*/
|
||||
#define SDL_HINT_ENABLE_STEAM_CONTROLLERS "SDL_ENABLE_STEAM_CONTROLLERS"
|
||||
|
||||
|
||||
/**
|
||||
* \brief If set to "0" then never set the top most bit on a SDL Window, even if the video mode expects it.
|
||||
* This is a debugging aid for developers and not expected to be used by end users. The default is "1"
|
||||
|
|
|
@ -97,10 +97,10 @@ typedef enum
|
|||
typedef enum
|
||||
{
|
||||
SDL_JOYSTICK_POWER_UNKNOWN = -1,
|
||||
SDL_JOYSTICK_POWER_EMPTY,
|
||||
SDL_JOYSTICK_POWER_LOW,
|
||||
SDL_JOYSTICK_POWER_MEDIUM,
|
||||
SDL_JOYSTICK_POWER_FULL,
|
||||
SDL_JOYSTICK_POWER_EMPTY, /* <= 5% */
|
||||
SDL_JOYSTICK_POWER_LOW, /* <= 20% */
|
||||
SDL_JOYSTICK_POWER_MEDIUM, /* <= 70% */
|
||||
SDL_JOYSTICK_POWER_FULL, /* <= 100% */
|
||||
SDL_JOYSTICK_POWER_WIRED,
|
||||
SDL_JOYSTICK_POWER_MAX
|
||||
} SDL_JoystickPowerLevel;
|
||||
|
@ -361,6 +361,19 @@ extern DECLSPEC int SDLCALL SDL_JoystickGetBall(SDL_Joystick * joystick,
|
|||
extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
|
||||
int button);
|
||||
|
||||
/**
|
||||
* Trigger a rumble effect
|
||||
* Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
|
||||
*
|
||||
* \param joystick The joystick to vibrate
|
||||
* \param low_frequency_rumble The intensity of the low frequency (left) rumble motor, from 0 to 0xFFFF
|
||||
* \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
|
||||
* \param duration_ms The duration of the rumble effect, in milliseconds
|
||||
*
|
||||
* \return 0, or -1 if rumble isn't supported on this joystick
|
||||
*/
|
||||
extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
|
||||
/**
|
||||
* Close a joystick previously opened with SDL_JoystickOpen().
|
||||
*/
|
||||
|
|
|
@ -450,6 +450,7 @@ extern DECLSPEC void *SDLCALL SDL_memcpy(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_
|
|||
extern DECLSPEC void *SDLCALL SDL_memmove(SDL_OUT_BYTECAP(len) void *dst, SDL_IN_BYTECAP(len) const void *src, size_t len);
|
||||
extern DECLSPEC int SDLCALL SDL_memcmp(const void *s1, const void *s2, size_t len);
|
||||
|
||||
extern DECLSPEC wchar_t *SDLCALL SDL_wcsdup(const wchar_t *wstr);
|
||||
extern DECLSPEC size_t SDLCALL SDL_wcslen(const wchar_t *wstr);
|
||||
extern DECLSPEC size_t SDLCALL SDL_wcslcpy(SDL_OUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
|
||||
extern DECLSPEC size_t SDLCALL SDL_wcslcat(SDL_INOUT_Z_CAP(maxlen) wchar_t *dst, const wchar_t *src, size_t maxlen);
|
||||
|
|
|
@ -677,3 +677,6 @@
|
|||
#define SDL_AndroidBackButton SDL_AndroidBackButton_REAL
|
||||
#define SDL_exp SDL_exp_REAL
|
||||
#define SDL_expf SDL_expf_REAL
|
||||
#define SDL_wcsdup SDL_wcsdup_REAL
|
||||
#define SDL_GameControllerRumble SDL_GameControllerRumble_REAL
|
||||
#define SDL_JoystickRumble SDL_JoystickRumble_REAL
|
||||
|
|
|
@ -715,9 +715,10 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX512F,(void),(),return)
|
|||
#ifdef __ANDROID__
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_IsChromebook,(void),(),return)
|
||||
SDL_DYNAPI_PROC(SDL_bool,SDL_IsDeXMode,(void),(),return)
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
SDL_DYNAPI_PROC(void,SDL_AndroidBackButton,(void),(),return)
|
||||
#endif
|
||||
SDL_DYNAPI_PROC(double,SDL_exp,(double a),(a),return)
|
||||
SDL_DYNAPI_PROC(float,SDL_expf,(float a),(a),return)
|
||||
SDL_DYNAPI_PROC(wchar_t*,SDL_wcsdup,(const wchar_t *a),(a),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_GameControllerRumble,(SDL_GameController *a, Uint16 b, Uint16 c, Uint32 d),(a,b,c,d),return)
|
||||
SDL_DYNAPI_PROC(int,SDL_JoystickRumble,(SDL_Joystick *a, Uint16 b, Uint16 c, Uint32 d),(a,b,c,d),return)
|
||||
|
|
|
@ -102,6 +102,7 @@ typedef struct _ControllerMapping_t
|
|||
static SDL_JoystickGUID s_zeroGUID;
|
||||
static ControllerMapping_t *s_pSupportedControllers = NULL;
|
||||
static ControllerMapping_t *s_pDefaultMapping = NULL;
|
||||
static ControllerMapping_t *s_pHIDAPIMapping = NULL;
|
||||
static ControllerMapping_t *s_pXInputMapping = NULL;
|
||||
|
||||
/* The SDL game controller structure */
|
||||
|
@ -430,6 +431,10 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickG
|
|||
}
|
||||
pSupportedController = pSupportedController->next;
|
||||
}
|
||||
if (guid->data[14] == 'h') {
|
||||
/* This is a HIDAPI device */
|
||||
return s_pHIDAPIMapping;
|
||||
}
|
||||
#if SDL_JOYSTICK_XINPUT
|
||||
if (guid->data[14] == 'x') {
|
||||
/* This is an XInput device */
|
||||
|
@ -1130,6 +1135,7 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
char *pchGUID;
|
||||
SDL_JoystickGUID jGUID;
|
||||
SDL_bool is_default_mapping = SDL_FALSE;
|
||||
SDL_bool is_hidapi_mapping = SDL_FALSE;
|
||||
SDL_bool is_xinput_mapping = SDL_FALSE;
|
||||
SDL_bool existing = SDL_FALSE;
|
||||
ControllerMapping_t *pControllerMapping;
|
||||
|
@ -1144,6 +1150,8 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
}
|
||||
if (!SDL_strcasecmp(pchGUID, "default")) {
|
||||
is_default_mapping = SDL_TRUE;
|
||||
} else if (!SDL_strcasecmp(pchGUID, "hidapi")) {
|
||||
is_hidapi_mapping = SDL_TRUE;
|
||||
} else if (!SDL_strcasecmp(pchGUID, "xinput")) {
|
||||
is_xinput_mapping = SDL_TRUE;
|
||||
}
|
||||
|
@ -1160,6 +1168,8 @@ SDL_PrivateGameControllerAddMapping(const char *mappingString, SDL_ControllerMap
|
|||
} else {
|
||||
if (is_default_mapping) {
|
||||
s_pDefaultMapping = pControllerMapping;
|
||||
} else if (is_hidapi_mapping) {
|
||||
s_pHIDAPIMapping = pControllerMapping;
|
||||
} else if (is_xinput_mapping) {
|
||||
s_pXInputMapping = pControllerMapping;
|
||||
}
|
||||
|
@ -1458,7 +1468,6 @@ SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
|
|||
}
|
||||
|
||||
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
|
||||
vidpid = MAKE_VIDPID(vendor, product);
|
||||
|
||||
if (SDL_GetHintBoolean("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD", SDL_FALSE)) {
|
||||
/* We shouldn't ignore Steam's virtual gamepad since it's using the hints to filter out the real controllers so it can remap input for the virtual controller */
|
||||
|
@ -1476,6 +1485,8 @@ SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
|
|||
}
|
||||
}
|
||||
|
||||
vidpid = MAKE_VIDPID(vendor, product);
|
||||
|
||||
if (SDL_allowed_controllers.num_entries > 0) {
|
||||
for (i = 0; i < SDL_allowed_controllers.num_entries; ++i) {
|
||||
if (vidpid == SDL_allowed_controllers.entries[i]) {
|
||||
|
@ -1503,22 +1514,18 @@ SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid)
|
|||
SDL_GameController *
|
||||
SDL_GameControllerOpen(int device_index)
|
||||
{
|
||||
SDL_JoystickID instance_id;
|
||||
SDL_GameController *gamecontroller;
|
||||
SDL_GameController *gamecontrollerlist;
|
||||
ControllerMapping_t *pSupportedController = NULL;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
|
||||
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
|
||||
SDL_UnlockJoysticks();
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
gamecontrollerlist = SDL_gamecontrollers;
|
||||
/* If the controller is already open, return it */
|
||||
instance_id = SDL_JoystickGetDeviceInstanceID(device_index);
|
||||
while (gamecontrollerlist) {
|
||||
if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
|
||||
if (instance_id == gamecontrollerlist->joystick->instance_id) {
|
||||
gamecontroller = gamecontrollerlist;
|
||||
++gamecontroller->ref_count;
|
||||
SDL_UnlockJoysticks();
|
||||
|
@ -1834,6 +1841,12 @@ SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameControll
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_JoystickRumble(SDL_GameControllerGetJoystick(gamecontroller), low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
}
|
||||
|
||||
void
|
||||
SDL_GameControllerClose(SDL_GameController * gamecontroller)
|
||||
{
|
||||
|
|
|
@ -555,6 +555,7 @@ static const char *s_ControllerMappings [] =
|
|||
"05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
"050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
"050000005509000010720000ffff3f00,NVIDIA Controller v01.03,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
"050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,", /* Extremely slow in Bluetooth mode on Android */
|
||||
"050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
"050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
|
||||
"050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
|
||||
|
@ -575,6 +576,7 @@ static const char *s_ControllerMappings [] =
|
|||
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
|
||||
"default,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
#endif
|
||||
"hidapi,*,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
/* This is the joystick API for Simple DirectMedia Layer */
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_atomic.h"
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_sysjoystick.h"
|
||||
#include "SDL_assert.h"
|
||||
|
@ -33,11 +34,45 @@
|
|||
#endif
|
||||
#include "../video/SDL_sysvideo.h"
|
||||
|
||||
/* This is included in only one place because it has a large static list of controllers */
|
||||
#include "controller_type.h"
|
||||
|
||||
#ifdef __WIN32__
|
||||
/* Needed for checking for input remapping programs */
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
|
||||
#undef UNICODE /* We want ASCII functions */
|
||||
#include <tlhelp32.h>
|
||||
#endif
|
||||
|
||||
static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||
#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
|
||||
&SDL_WINDOWS_JoystickDriver,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_LINUX
|
||||
&SDL_LINUX_JoystickDriver,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_IOKIT
|
||||
&SDL_DARWIN_JoystickDriver,
|
||||
#endif
|
||||
#if defined(__IPHONEOS__) || defined(__TVOS__)
|
||||
&SDL_IOS_JoystickDriver,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_ANDROID
|
||||
&SDL_ANDROID_JoystickDriver,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
&SDL_HIDAPI_JoystickDriver,
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
|
||||
&SDL_DUMMY_JoystickDriver
|
||||
#endif
|
||||
};
|
||||
static SDL_bool SDL_joystick_allows_background_events = SDL_FALSE;
|
||||
static SDL_Joystick *SDL_joysticks = NULL;
|
||||
static SDL_bool SDL_updating_joystick = SDL_FALSE;
|
||||
static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
|
||||
static SDL_atomic_t SDL_next_joystick_instance_id;
|
||||
|
||||
void
|
||||
SDL_LockJoysticks(void)
|
||||
|
@ -69,7 +104,7 @@ SDL_JoystickAllowBackgroundEventsChanged(void *userdata, const char *name, const
|
|||
int
|
||||
SDL_JoystickInit(void)
|
||||
{
|
||||
int status;
|
||||
int i, status;
|
||||
|
||||
SDL_GameControllerInitMappings();
|
||||
|
||||
|
@ -88,11 +123,13 @@ SDL_JoystickInit(void)
|
|||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
|
||||
status = SDL_SYS_JoystickInit();
|
||||
if (status >= 0) {
|
||||
status = 0;
|
||||
status = -1;
|
||||
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
|
||||
if (SDL_joystick_drivers[i]->Init() >= 0) {
|
||||
status = 0;
|
||||
}
|
||||
}
|
||||
return (status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -101,7 +138,48 @@ SDL_JoystickInit(void)
|
|||
int
|
||||
SDL_NumJoysticks(void)
|
||||
{
|
||||
return SDL_SYS_NumJoysticks();
|
||||
int i, total_joysticks = 0;
|
||||
SDL_LockJoysticks();
|
||||
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
|
||||
total_joysticks += SDL_joystick_drivers[i]->GetCount();
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
return total_joysticks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next available joystick instance ID
|
||||
* This may be called by drivers from multiple threads, unprotected by any locks
|
||||
*/
|
||||
SDL_JoystickID SDL_GetNextJoystickInstanceID()
|
||||
{
|
||||
return SDL_AtomicIncRef(&SDL_next_joystick_instance_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the driver and device index for an API device index
|
||||
* This should be called while the joystick lock is held, to prevent another thread from updating the list
|
||||
*/
|
||||
SDL_bool
|
||||
SDL_GetDriverAndJoystickIndex(int device_index, SDL_JoystickDriver **driver, int *driver_index)
|
||||
{
|
||||
int i, num_joysticks, total_joysticks = 0;
|
||||
|
||||
if (device_index >= 0) {
|
||||
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
|
||||
num_joysticks = SDL_joystick_drivers[i]->GetCount();
|
||||
if (device_index < num_joysticks) {
|
||||
*driver = SDL_joystick_drivers[i];
|
||||
*driver_index = device_index;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
device_index -= num_joysticks;
|
||||
total_joysticks += num_joysticks;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetError("There are %d joysticks available", total_joysticks);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -127,11 +205,17 @@ SDL_FixupJoystickName(const char *name)
|
|||
const char *
|
||||
SDL_JoystickNameForIndex(int device_index)
|
||||
{
|
||||
if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
|
||||
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
|
||||
return (NULL);
|
||||
SDL_JoystickDriver *driver;
|
||||
const char *name = NULL;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
|
||||
name = SDL_FixupJoystickName(driver->GetDeviceName(device_index));
|
||||
}
|
||||
return SDL_FixupJoystickName(SDL_SYS_JoystickNameForDeviceIndex(device_index));
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
/* FIXME: Really we should reference count this name so it doesn't go away after unlock */
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -176,27 +260,30 @@ SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
|
|||
SDL_Joystick *
|
||||
SDL_JoystickOpen(int device_index)
|
||||
{
|
||||
SDL_JoystickDriver *driver;
|
||||
SDL_JoystickID instance_id;
|
||||
SDL_Joystick *joystick;
|
||||
SDL_Joystick *joysticklist;
|
||||
const char *joystickname = NULL;
|
||||
|
||||
if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
|
||||
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
if (!SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
|
||||
SDL_UnlockJoysticks();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
joysticklist = SDL_joysticks;
|
||||
/* If the joystick is already open, return it
|
||||
* it is important that we have a single joystick * for each instance id
|
||||
*/
|
||||
instance_id = driver->GetDeviceInstanceID(device_index);
|
||||
while (joysticklist) {
|
||||
if (SDL_JoystickGetDeviceInstanceID(device_index) == joysticklist->instance_id) {
|
||||
if (instance_id == joysticklist->instance_id) {
|
||||
joystick = joysticklist;
|
||||
++joystick->ref_count;
|
||||
SDL_UnlockJoysticks();
|
||||
return (joystick);
|
||||
return joystick;
|
||||
}
|
||||
joysticklist = joysticklist->next;
|
||||
}
|
||||
|
@ -208,18 +295,23 @@ SDL_JoystickOpen(int device_index)
|
|||
SDL_UnlockJoysticks();
|
||||
return NULL;
|
||||
}
|
||||
joystick->driver = driver;
|
||||
joystick->instance_id = instance_id;
|
||||
|
||||
if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
|
||||
if (driver->Open(joystick, device_index) < 0) {
|
||||
SDL_free(joystick);
|
||||
SDL_UnlockJoysticks();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
joystickname = SDL_SYS_JoystickNameForDeviceIndex(device_index);
|
||||
if (joystickname)
|
||||
joystickname = driver->GetDeviceName(device_index);
|
||||
if (joystickname) {
|
||||
joystick->name = SDL_strdup(joystickname);
|
||||
else
|
||||
} else {
|
||||
joystick->name = NULL;
|
||||
}
|
||||
|
||||
joystick->guid = driver->GetDeviceGUID(device_index);
|
||||
|
||||
if (joystick->naxes > 0) {
|
||||
joystick->axes = (SDL_JoystickAxisInfo *) SDL_calloc(joystick->naxes, sizeof(SDL_JoystickAxisInfo));
|
||||
|
@ -263,9 +355,9 @@ SDL_JoystickOpen(int device_index)
|
|||
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
SDL_SYS_JoystickUpdate(joystick);
|
||||
driver->Update(joystick);
|
||||
|
||||
return (joystick);
|
||||
return joystick;
|
||||
}
|
||||
|
||||
|
||||
|
@ -294,9 +386,9 @@ int
|
|||
SDL_JoystickNumAxes(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
return (joystick->naxes);
|
||||
return joystick->naxes;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -306,9 +398,9 @@ int
|
|||
SDL_JoystickNumHats(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
return (joystick->nhats);
|
||||
return joystick->nhats;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -318,9 +410,9 @@ int
|
|||
SDL_JoystickNumBalls(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
return (joystick->nballs);
|
||||
return joystick->nballs;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -330,9 +422,9 @@ int
|
|||
SDL_JoystickNumButtons(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
return (joystick->nbuttons);
|
||||
return joystick->nbuttons;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -344,7 +436,7 @@ SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
|
|||
Sint16 state;
|
||||
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
if (axis < joystick->naxes) {
|
||||
state = joystick->axes[axis].value;
|
||||
|
@ -352,7 +444,7 @@ SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
|
|||
SDL_SetError("Joystick only has %d axes", joystick->naxes);
|
||||
state = 0;
|
||||
}
|
||||
return (state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -383,7 +475,7 @@ SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
|
|||
Uint8 state;
|
||||
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
if (hat < joystick->nhats) {
|
||||
state = joystick->hats[hat];
|
||||
|
@ -391,7 +483,7 @@ SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
|
|||
SDL_SetError("Joystick only has %d hats", joystick->nhats);
|
||||
state = 0;
|
||||
}
|
||||
return (state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -403,7 +495,7 @@ SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
|
|||
int retval;
|
||||
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
|
@ -419,7 +511,7 @@ SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
|
|||
} else {
|
||||
return SDL_SetError("Joystick only has %d balls", joystick->nballs);
|
||||
}
|
||||
return (retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -431,7 +523,7 @@ SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
|
|||
Uint8 state;
|
||||
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
if (button < joystick->nbuttons) {
|
||||
state = joystick->buttons[button];
|
||||
|
@ -439,7 +531,7 @@ SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
|
|||
SDL_SetError("Joystick only has %d buttons", joystick->nbuttons);
|
||||
state = 0;
|
||||
}
|
||||
return (state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -453,7 +545,7 @@ SDL_JoystickGetAttached(SDL_Joystick * joystick)
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
return SDL_SYS_JoystickAttached(joystick);
|
||||
return joystick->driver->IsAttached(joystick);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -463,10 +555,10 @@ SDL_JoystickID
|
|||
SDL_JoystickInstanceID(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (joystick->instance_id);
|
||||
return joystick->instance_id;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -495,12 +587,21 @@ const char *
|
|||
SDL_JoystickName(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SDL_FixupJoystickName(joystick->name);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return -1;
|
||||
}
|
||||
return joystick->driver->Rumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a joystick previously opened with SDL_JoystickOpen()
|
||||
*/
|
||||
|
@ -510,7 +611,7 @@ SDL_JoystickClose(SDL_Joystick * joystick)
|
|||
SDL_Joystick *joysticklist;
|
||||
SDL_Joystick *joysticklistprev;
|
||||
|
||||
if (!joystick) {
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -527,7 +628,7 @@ SDL_JoystickClose(SDL_Joystick * joystick)
|
|||
return;
|
||||
}
|
||||
|
||||
SDL_SYS_JoystickClose(joystick);
|
||||
joystick->driver->Close(joystick);
|
||||
joystick->hwdata = NULL;
|
||||
|
||||
joysticklist = SDL_joysticks;
|
||||
|
@ -561,6 +662,8 @@ SDL_JoystickClose(SDL_Joystick * joystick)
|
|||
void
|
||||
SDL_JoystickQuit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Make sure we're not getting called in the middle of updating joysticks */
|
||||
SDL_assert(!SDL_updating_joystick);
|
||||
|
||||
|
@ -573,7 +676,9 @@ SDL_JoystickQuit(void)
|
|||
}
|
||||
|
||||
/* Quit the joystick setup */
|
||||
SDL_SYS_JoystickQuit();
|
||||
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
|
||||
SDL_joystick_drivers[i]->Quit();
|
||||
}
|
||||
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
|
@ -609,10 +714,16 @@ SDL_PrivateJoystickShouldIgnoreEvent()
|
|||
|
||||
/* These are global for SDL_sysjoystick.c and SDL_events.c */
|
||||
|
||||
void SDL_PrivateJoystickAdded(int device_index)
|
||||
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
|
||||
{
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
SDL_Event event;
|
||||
int device_index;
|
||||
|
||||
device_index = SDL_JoystickGetDeviceIndexFromInstanceID(device_instance);
|
||||
if (device_index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.type = SDL_JOYDEVICEADDED;
|
||||
|
||||
|
@ -722,7 +833,7 @@ SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
|
|||
posted = SDL_PushEvent(&event) == 1;
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
return (posted);
|
||||
return posted;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -762,7 +873,7 @@ SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
|
|||
posted = SDL_PushEvent(&event) == 1;
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
return (posted);
|
||||
return posted;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -798,7 +909,7 @@ SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
|
|||
posted = SDL_PushEvent(&event) == 1;
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
return (posted);
|
||||
return posted;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -817,7 +928,7 @@ SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
|
|||
break;
|
||||
default:
|
||||
/* Invalid state -- bail */
|
||||
return (0);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
|
||||
|
@ -850,12 +961,13 @@ SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
|
|||
posted = SDL_PushEvent(&event) == 1;
|
||||
}
|
||||
#endif /* !SDL_EVENTS_DISABLED */
|
||||
return (posted);
|
||||
return posted;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_JoystickUpdate(void)
|
||||
{
|
||||
int i;
|
||||
SDL_Joystick *joystick;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
@ -872,15 +984,13 @@ SDL_JoystickUpdate(void)
|
|||
SDL_UnlockJoysticks();
|
||||
|
||||
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
|
||||
SDL_SYS_JoystickUpdate(joystick);
|
||||
joystick->driver->Update(joystick);
|
||||
|
||||
if (joystick->delayed_guide_button) {
|
||||
SDL_GameControllerHandleDelayedGuideButton(joystick);
|
||||
}
|
||||
|
||||
if (joystick->force_recentering) {
|
||||
int i;
|
||||
|
||||
/* Tell the app that everything is centered/unpressed... */
|
||||
for (i = 0; i < joystick->naxes; i++) {
|
||||
if (joystick->axes[i].has_initial_value) {
|
||||
|
@ -914,7 +1024,9 @@ SDL_JoystickUpdate(void)
|
|||
/* this needs to happen AFTER walking the joystick list above, so that any
|
||||
dangling hardware data from removed devices can be free'd
|
||||
*/
|
||||
SDL_SYS_JoystickDetect();
|
||||
for (i = 0; i < SDL_arraysize(SDL_joystick_drivers); ++i) {
|
||||
SDL_joystick_drivers[i]->Detect();
|
||||
}
|
||||
|
||||
SDL_UnlockJoysticks();
|
||||
}
|
||||
|
@ -947,7 +1059,7 @@ SDL_JoystickEventState(int state)
|
|||
}
|
||||
break;
|
||||
}
|
||||
return (state);
|
||||
return state;
|
||||
#endif /* SDL_EVENTS_DISABLED */
|
||||
}
|
||||
|
||||
|
@ -963,7 +1075,7 @@ void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *prod
|
|||
/* guid16[4] is product ID */
|
||||
guid16[5] == 0x0000
|
||||
/* guid16[6] is product version */
|
||||
) {
|
||||
) {
|
||||
if (vendor) {
|
||||
*vendor = guid16[2];
|
||||
}
|
||||
|
@ -986,6 +1098,43 @@ void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *prod
|
|||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IsJoystickPS4(Uint16 vendor, Uint16 product)
|
||||
{
|
||||
return (GuessControllerType(vendor, product) == k_eControllerType_PS4Controller);
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IsJoystickNintendoSwitchPro(Uint16 vendor, Uint16 product)
|
||||
{
|
||||
return (GuessControllerType(vendor, product) == k_eControllerType_SwitchProController);
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product)
|
||||
{
|
||||
return BIsSteamController(GuessControllerType(vendor, product)) ? SDL_TRUE : SDL_FALSE;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IsJoystickXbox360(Uint16 vendor, Uint16 product)
|
||||
{
|
||||
/* Filter out some bogus values here */
|
||||
if (vendor == 0x0000 && product == 0x0000) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
if (vendor == 0x0001 && product == 0x0001) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return (GuessControllerType(vendor, product) == k_eControllerType_XBox360Controller);
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
|
||||
{
|
||||
return (GuessControllerType(vendor, product) == k_eControllerType_XBoxOneController);
|
||||
}
|
||||
|
||||
static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
|
||||
{
|
||||
static Uint32 wheel_joysticks[] = {
|
||||
|
@ -1092,19 +1241,80 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_JoystickGUID guid)
|
|||
return SDL_JOYSTICK_TYPE_THROTTLE;
|
||||
}
|
||||
|
||||
if (GuessControllerType(vendor, product) != k_eControllerType_UnknownNonSteamController) {
|
||||
return SDL_JOYSTICK_TYPE_GAMECONTROLLER;
|
||||
}
|
||||
|
||||
return SDL_JOYSTICK_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static SDL_bool SDL_IsPS4RemapperRunning(void)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
const char *mapper_processes[] = {
|
||||
"DS4Windows.exe",
|
||||
"InputMapper.exe",
|
||||
};
|
||||
int i;
|
||||
PROCESSENTRY32 pe32;
|
||||
SDL_bool found = SDL_FALSE;
|
||||
|
||||
/* Take a snapshot of all processes in the system */
|
||||
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hProcessSnap != INVALID_HANDLE_VALUE) {
|
||||
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||
if (Process32First(hProcessSnap, &pe32)) {
|
||||
do
|
||||
{
|
||||
for (i = 0; i < SDL_arraysize(mapper_processes); ++i) {
|
||||
if (SDL_strcasecmp(pe32.szExeFile, mapper_processes[i]) == 0) {
|
||||
found = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
} while (Process32Next(hProcessSnap, &pe32) && !found);
|
||||
}
|
||||
CloseHandle(hProcessSnap);
|
||||
}
|
||||
return found;
|
||||
#else
|
||||
return SDL_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
|
||||
{
|
||||
Uint16 vendor;
|
||||
Uint16 product;
|
||||
|
||||
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
|
||||
|
||||
if (SDL_IsJoystickPS4(vendor, product) && SDL_IsPS4RemapperRunning()) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
if (SDL_IsGameControllerNameAndGUID(name, guid) &&
|
||||
SDL_ShouldIgnoreGameController(name, guid)) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* return the guid for this index */
|
||||
SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
|
||||
SDL_JoystickGUID emptyGUID;
|
||||
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
|
||||
SDL_zero(emptyGUID);
|
||||
return emptyGUID;
|
||||
SDL_JoystickDriver *driver;
|
||||
SDL_JoystickGUID guid;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
|
||||
guid = driver->GetDeviceGUID(device_index);
|
||||
} else {
|
||||
SDL_zero(guid);
|
||||
}
|
||||
return SDL_SYS_JoystickGetDeviceGUID(device_index);
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return guid;
|
||||
}
|
||||
|
||||
Uint16 SDL_JoystickGetDeviceVendor(int device_index)
|
||||
|
@ -1150,11 +1360,33 @@ SDL_JoystickType SDL_JoystickGetDeviceType(int device_index)
|
|||
|
||||
SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
if (device_index < 0 || device_index >= SDL_NumJoysticks()) {
|
||||
SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
|
||||
return -1;
|
||||
SDL_JoystickDriver *driver;
|
||||
SDL_JoystickID instance_id = -1;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
|
||||
instance_id = driver->GetDeviceInstanceID(device_index);
|
||||
}
|
||||
return SDL_SYS_GetInstanceIdOfDeviceIndex(device_index);
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return instance_id;
|
||||
}
|
||||
|
||||
int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id)
|
||||
{
|
||||
int i, num_joysticks, device_index = -1;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
num_joysticks = SDL_NumJoysticks();
|
||||
for (i = 0; i < num_joysticks; ++i) {
|
||||
if (SDL_JoystickGetDeviceInstanceID(i) == instance_id) {
|
||||
device_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return device_index;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
|
@ -1164,7 +1396,7 @@ SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
|
|||
SDL_zero(emptyGUID);
|
||||
return emptyGUID;
|
||||
}
|
||||
return SDL_SYS_JoystickGetGUID(joystick);
|
||||
return joystick->guid;
|
||||
}
|
||||
|
||||
Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
|
||||
|
@ -1229,7 +1461,6 @@ void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
|
|||
*pszGUID = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Purpose: Returns the 4 bit nibble for a hex character
|
||||
* Input : c -
|
||||
|
@ -1254,7 +1485,6 @@ static unsigned char nibble(char c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* convert the string version of a joystick guid to the struct */
|
||||
SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
|
||||
{
|
||||
|
@ -1277,19 +1507,17 @@ SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
|
|||
return guid;
|
||||
}
|
||||
|
||||
|
||||
/* update the power level for this joystick */
|
||||
void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
|
||||
{
|
||||
joystick->epowerlevel = ePowerLevel;
|
||||
}
|
||||
|
||||
|
||||
/* return its power level */
|
||||
SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!SDL_PrivateJoystickValid(joystick)) {
|
||||
return (SDL_JOYSTICK_POWER_UNKNOWN);
|
||||
return SDL_JOYSTICK_POWER_UNKNOWN;
|
||||
}
|
||||
return joystick->epowerlevel;
|
||||
}
|
||||
|
|
|
@ -23,19 +23,48 @@
|
|||
/* Useful functions and variables from SDL_joystick.c */
|
||||
#include "SDL_joystick.h"
|
||||
|
||||
struct _SDL_JoystickDriver;
|
||||
|
||||
/* Initialization and shutdown functions */
|
||||
extern int SDL_JoystickInit(void);
|
||||
extern void SDL_JoystickQuit(void);
|
||||
|
||||
/* Function to get the next available joystick instance ID */
|
||||
extern SDL_JoystickID SDL_GetNextJoystickInstanceID(void);
|
||||
|
||||
/* Initialization and shutdown functions */
|
||||
extern int SDL_GameControllerInitMappings(void);
|
||||
extern void SDL_GameControllerQuitMappings(void);
|
||||
extern int SDL_GameControllerInit(void);
|
||||
extern void SDL_GameControllerQuit(void);
|
||||
|
||||
/* Function to get the joystick driver and device index for an API device index */
|
||||
extern SDL_bool SDL_GetDriverAndJoystickIndex(int device_index, struct _SDL_JoystickDriver **driver, int *driver_index);
|
||||
|
||||
/* Function to return the device index for a joystick ID, or -1 if not found */
|
||||
extern int SDL_JoystickGetDeviceIndexFromInstanceID(SDL_JoystickID instance_id);
|
||||
|
||||
/* Function to extract information from an SDL joystick GUID */
|
||||
extern void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version);
|
||||
|
||||
/* Function to return whether a joystick is a PS4 controller */
|
||||
extern SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
/* Function to return whether a joystick is a Nintendo Switch Pro controller */
|
||||
extern SDL_bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
/* Function to return whether a joystick is a Steam Controller */
|
||||
extern SDL_bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
/* Function to return whether a joystick is an Xbox 360 controller */
|
||||
extern SDL_bool SDL_IsJoystickXbox360(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
/* Function to return whether a joystick is an Xbox One controller */
|
||||
extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
/* Function to return whether a joystick should be ignored */
|
||||
extern SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid);
|
||||
|
||||
/* Function to return whether a joystick name and GUID is a game controller */
|
||||
extern SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGUID guid);
|
||||
|
||||
|
@ -46,7 +75,7 @@ extern SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUI
|
|||
extern void SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick);
|
||||
|
||||
/* Internal event queueing functions */
|
||||
extern void SDL_PrivateJoystickAdded(int device_index);
|
||||
extern void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance);
|
||||
extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance);
|
||||
extern int SDL_PrivateJoystickAxis(SDL_Joystick * joystick,
|
||||
Uint8 axis, Sint16 value);
|
||||
|
|
|
@ -42,6 +42,7 @@ struct _SDL_Joystick
|
|||
{
|
||||
SDL_JoystickID instance_id; /* Device instance, monotonically increasing from 0 */
|
||||
char *name; /* Joystick name - system dependent */
|
||||
SDL_JoystickGUID guid; /* Joystick guid */
|
||||
|
||||
int naxes; /* Number of axis controls on the joystick */
|
||||
SDL_JoystickAxisInfo *axes;
|
||||
|
@ -58,69 +59,95 @@ struct _SDL_Joystick
|
|||
int nbuttons; /* Number of buttons on the joystick */
|
||||
Uint8 *buttons; /* Current button states */
|
||||
|
||||
struct joystick_hwdata *hwdata; /* Driver dependent information */
|
||||
|
||||
int ref_count; /* Reference count for multiple opens */
|
||||
|
||||
SDL_bool is_game_controller;
|
||||
SDL_bool delayed_guide_button; /* SDL_TRUE if this device has the guide button event delayed */
|
||||
SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */
|
||||
SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
|
||||
struct _SDL_JoystickDriver *driver;
|
||||
|
||||
struct joystick_hwdata *hwdata; /* Driver dependent information */
|
||||
|
||||
int ref_count; /* Reference count for multiple opens */
|
||||
|
||||
struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */
|
||||
};
|
||||
|
||||
#if defined(__IPHONEOS__) || defined(__ANDROID__)
|
||||
#define HAVE_STEAMCONTROLLERS
|
||||
#define USE_STEAMCONTROLLER_HIDAPI
|
||||
#elif defined(__LINUX__)
|
||||
#define HAVE_STEAMCONTROLLERS
|
||||
#define USE_STEAMCONTROLLER_LINUX
|
||||
#endif
|
||||
|
||||
/* Device bus definitions */
|
||||
#define SDL_HARDWARE_BUS_USB 0x03
|
||||
#define SDL_HARDWARE_BUS_BLUETOOTH 0x05
|
||||
|
||||
/* Macro to combine a USB vendor ID and product ID into a single Uint32 value */
|
||||
#define MAKE_VIDPID(VID, PID) (((Uint32)(VID))<<16|(PID))
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* This function should return the number of available joysticks, or -1
|
||||
* on an unrecoverable fatal error.
|
||||
*/
|
||||
extern int SDL_SYS_JoystickInit(void);
|
||||
typedef struct _SDL_JoystickDriver
|
||||
{
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* This function should return 0, or -1 on an unrecoverable error.
|
||||
*/
|
||||
int (*Init)(void);
|
||||
|
||||
/* Function to return the number of joystick devices plugged in right now */
|
||||
extern int SDL_SYS_NumJoysticks(void);
|
||||
/* Function to return the number of joystick devices plugged in right now */
|
||||
int (*GetCount)(void);
|
||||
|
||||
/* Function to cause any queued joystick insertions to be processed */
|
||||
extern void SDL_SYS_JoystickDetect(void);
|
||||
/* Function to cause any queued joystick insertions to be processed */
|
||||
void (*Detect)(void);
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
extern const char *SDL_SYS_JoystickNameForDeviceIndex(int device_index);
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *(*GetDeviceName)(int device_index);
|
||||
|
||||
/* Function to get the current instance id of the joystick located at device_index */
|
||||
extern SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index);
|
||||
/* Function to return the stable GUID for a plugged in device */
|
||||
SDL_JoystickGUID (*GetDeviceGUID)(int device_index);
|
||||
|
||||
/* Function to open a joystick for use.
|
||||
The joystick to open is specified by the device index.
|
||||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
extern int SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index);
|
||||
/* Function to get the current instance id of the joystick located at device_index */
|
||||
SDL_JoystickID (*GetDeviceInstanceID)(int device_index);
|
||||
|
||||
/* Function to query if the joystick is currently attached
|
||||
* It returns SDL_TRUE if attached, SDL_FALSE otherwise.
|
||||
*/
|
||||
extern SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick * joystick);
|
||||
/* Function to open a joystick for use.
|
||||
The joystick to open is specified by the device index.
|
||||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int (*Open)(SDL_Joystick * joystick, int device_index);
|
||||
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
* This function shouldn't update the joystick structure directly,
|
||||
* but instead should call SDL_PrivateJoystick*() to deliver events
|
||||
* and update joystick device state.
|
||||
*/
|
||||
extern void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick);
|
||||
/* Function to query if the joystick is currently attached
|
||||
* It returns SDL_TRUE if attached, SDL_FALSE otherwise.
|
||||
*/
|
||||
SDL_bool (*IsAttached)(SDL_Joystick * joystick);
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
extern void SDL_SYS_JoystickClose(SDL_Joystick * joystick);
|
||||
/* Rumble functionality */
|
||||
int (*Rumble)(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
extern void SDL_SYS_JoystickQuit(void);
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
* This function shouldn't update the joystick structure directly,
|
||||
* but instead should call SDL_PrivateJoystick*() to deliver events
|
||||
* and update joystick device state.
|
||||
*/
|
||||
void (*Update)(SDL_Joystick * joystick);
|
||||
|
||||
/* Function to return the stable GUID for a plugged in device */
|
||||
extern SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index);
|
||||
/* Function to close a joystick after use */
|
||||
void (*Close)(SDL_Joystick * joystick);
|
||||
|
||||
/* Function to return the stable GUID for a opened joystick */
|
||||
extern SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick);
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void (*Quit)(void);
|
||||
|
||||
} SDL_JoystickDriver;
|
||||
|
||||
/* The available joystick drivers */
|
||||
extern SDL_JoystickDriver SDL_ANDROID_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_DARWIN_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_DUMMY_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
|
||||
extern SDL_JoystickDriver SDL_WINDOWS_JoystickDriver;
|
||||
|
||||
#endif /* SDL_sysjoystick_h_ */
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "../SDL_joystick_c.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../core/android/SDL_android.h"
|
||||
#include "../steam/SDL_steamcontroller.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
|
||||
#include "android/keycodes.h"
|
||||
|
||||
|
@ -69,7 +69,6 @@ static SDL_joylist_item * JoystickByDeviceId(int device_id);
|
|||
static SDL_joylist_item *SDL_joylist = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail = NULL;
|
||||
static int numjoysticks = 0;
|
||||
static int instance_counter = 0;
|
||||
|
||||
|
||||
/* Public domain CRC implementation adapted from:
|
||||
|
@ -326,7 +325,6 @@ Android_OnHat(int device_id, int hat_id, int x, int y)
|
|||
int
|
||||
Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, SDL_bool is_accelerometer, int button_mask, int naxes, int nhats, int nballs)
|
||||
{
|
||||
const Uint16 BUS_BLUETOOTH = 0x05;
|
||||
SDL_joylist_item *item;
|
||||
SDL_JoystickGUID guid;
|
||||
Uint16 *guid16 = (Uint16 *)guid.data;
|
||||
|
@ -345,6 +343,13 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo
|
|||
return -1;
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(vendor_id, product_id)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats\n", name, desc, vendor_id, product_id, naxes, nhats);
|
||||
#endif
|
||||
|
@ -378,7 +383,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo
|
|||
|
||||
/* We only need 16 bits for each of these; space them out to fill 128. */
|
||||
/* Byteswap so devices get same GUID on little/big endian platforms. */
|
||||
*guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
|
||||
*guid16++ = 0;
|
||||
|
||||
if (vendor_id && product_id) {
|
||||
|
@ -424,7 +429,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo
|
|||
item->naxes = naxes;
|
||||
item->nhats = nhats;
|
||||
item->nballs = nballs;
|
||||
item->device_instance = instance_counter++;
|
||||
item->device_instance = SDL_GetNextJoystickInstanceID();
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
|
@ -435,7 +440,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, int vendo
|
|||
/* Need to increment the joystick count before we post the event */
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
SDL_PrivateJoystickAdded(item->device_instance);
|
||||
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
SDL_Log("Added joystick %s with device_id %d", name, device_id);
|
||||
|
@ -492,104 +497,29 @@ Android_RemoveJoystick(int device_id)
|
|||
}
|
||||
|
||||
|
||||
static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
|
||||
static void ANDROID_JoystickDetect();
|
||||
|
||||
static int
|
||||
ANDROID_JoystickInit(void)
|
||||
{
|
||||
SDL_joylist_item *item;
|
||||
|
||||
item = (SDL_joylist_item *)SDL_calloc(1, sizeof (SDL_joylist_item));
|
||||
if (item == NULL) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
*device_instance = item->device_instance = instance_counter++;
|
||||
item->device_id = -1;
|
||||
item->name = SDL_strdup(name);
|
||||
item->guid = guid;
|
||||
SDL_GetSteamControllerInputs(&item->nbuttons,
|
||||
&item->naxes,
|
||||
&item->nhats);
|
||||
item->m_bSteamController = SDL_TRUE;
|
||||
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
SDL_joylist_tail->next = item;
|
||||
SDL_joylist_tail = item;
|
||||
}
|
||||
|
||||
/* Need to increment the joystick count before we post the event */
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static void SteamControllerDisconnectedCallback(int device_instance)
|
||||
{
|
||||
SDL_joylist_item *item = SDL_joylist;
|
||||
SDL_joylist_item *prev = NULL;
|
||||
|
||||
while (item != NULL) {
|
||||
if (item->device_instance == device_instance) {
|
||||
break;
|
||||
}
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->joystick) {
|
||||
item->joystick->hwdata = NULL;
|
||||
}
|
||||
|
||||
if (prev != NULL) {
|
||||
prev->next = item->next;
|
||||
} else {
|
||||
SDL_assert(SDL_joylist == item);
|
||||
SDL_joylist = item->next;
|
||||
}
|
||||
if (item == SDL_joylist_tail) {
|
||||
SDL_joylist_tail = prev;
|
||||
}
|
||||
|
||||
/* Need to decrement the joystick count before we post the event */
|
||||
--numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickRemoved(item->device_instance);
|
||||
|
||||
SDL_free(item->name);
|
||||
SDL_free(item);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
{
|
||||
SDL_SYS_JoystickDetect();
|
||||
ANDROID_JoystickDetect();
|
||||
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
|
||||
/* Default behavior, accelerometer as joystick */
|
||||
Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, 0, 0, SDL_TRUE, 0, 3, 0, 0);
|
||||
}
|
||||
|
||||
SDL_InitSteamControllers(SteamControllerConnectedCallback,
|
||||
SteamControllerDisconnectedCallback);
|
||||
|
||||
return (numjoysticks);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
ANDROID_JoystickGetCount(void)
|
||||
{
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
ANDROID_JoystickDetect(void)
|
||||
{
|
||||
/* Support for device connect/disconnect is API >= 16 only,
|
||||
* so we poll every three seconds
|
||||
|
@ -600,8 +530,6 @@ SDL_SYS_JoystickDetect(void)
|
|||
timeout = SDL_GetTicks() + 3000;
|
||||
Android_JNI_PollInputDevices();
|
||||
}
|
||||
|
||||
SDL_UpdateSteamControllers();
|
||||
}
|
||||
|
||||
static SDL_joylist_item *
|
||||
|
@ -635,7 +563,7 @@ JoystickByDeviceId(int device_id)
|
|||
}
|
||||
|
||||
/* Joystick not found, try adding it */
|
||||
SDL_SYS_JoystickDetect();
|
||||
ANDROID_JoystickDetect();
|
||||
|
||||
while (item != NULL) {
|
||||
if (item->device_id == device_id) {
|
||||
|
@ -647,26 +575,26 @@ JoystickByDeviceId(int device_id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
static const char *
|
||||
ANDROID_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->name;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickGUID
|
||||
ANDROID_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
static SDL_JoystickID
|
||||
ANDROID_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->device_instance;
|
||||
}
|
||||
|
||||
/* Function to open a joystick for use.
|
||||
The joystick to open is specified by the device index.
|
||||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static int
|
||||
ANDROID_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByDevIndex(device_index);
|
||||
|
||||
|
@ -689,14 +617,20 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/* Function to determine if this joystick is attached to the system right now */
|
||||
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
static SDL_bool
|
||||
ANDROID_JoystickIsAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
return joystick->hwdata != NULL;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static int
|
||||
ANDROID_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void
|
||||
ANDROID_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
|
||||
|
||||
|
@ -704,11 +638,6 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
return;
|
||||
}
|
||||
|
||||
if (item->m_bSteamController) {
|
||||
SDL_UpdateSteamController(joystick);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->is_accelerometer) {
|
||||
int i;
|
||||
Sint16 value;
|
||||
|
@ -729,9 +658,8 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
}
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
ANDROID_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
|
||||
if (item) {
|
||||
|
@ -739,9 +667,8 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
|||
}
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
ANDROID_JoystickQuit(void)
|
||||
{
|
||||
/* We don't have any way to scan for joysticks at init, so don't wipe the list
|
||||
* of joysticks here in case this is a reinit.
|
||||
|
@ -759,28 +686,24 @@ SDL_SYS_JoystickQuit(void)
|
|||
SDL_joylist = SDL_joylist_tail = NULL;
|
||||
|
||||
numjoysticks = 0;
|
||||
instance_counter = 0;
|
||||
#endif /* 0 */
|
||||
|
||||
SDL_QuitSteamControllers();
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
|
||||
SDL_JoystickDriver SDL_ANDROID_JoystickDriver =
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
|
||||
if (joystick->hwdata != NULL) {
|
||||
return ((SDL_joylist_item*)joystick->hwdata)->guid;
|
||||
}
|
||||
|
||||
SDL_zero(guid);
|
||||
return guid;
|
||||
}
|
||||
ANDROID_JoystickInit,
|
||||
ANDROID_JoystickGetCount,
|
||||
ANDROID_JoystickDetect,
|
||||
ANDROID_JoystickGetDeviceName,
|
||||
ANDROID_JoystickGetDeviceGUID,
|
||||
ANDROID_JoystickGetDeviceInstanceID,
|
||||
ANDROID_JoystickOpen,
|
||||
ANDROID_JoystickIsAttached,
|
||||
ANDROID_JoystickRumble,
|
||||
ANDROID_JoystickUpdate,
|
||||
ANDROID_JoystickClose,
|
||||
ANDROID_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_ANDROID */
|
||||
|
||||
|
|
|
@ -47,9 +47,6 @@ typedef struct SDL_joylist_item
|
|||
int nbuttons, naxes, nhats, nballs;
|
||||
int dpad_state;
|
||||
|
||||
/* Steam Controller support */
|
||||
SDL_bool m_bSteamController;
|
||||
|
||||
struct SDL_joylist_item *next;
|
||||
} SDL_joylist_item;
|
||||
|
||||
|
|
|
@ -22,29 +22,79 @@
|
|||
|
||||
#ifdef SDL_JOYSTICK_IOKIT
|
||||
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
|
||||
/* For force feedback testing. */
|
||||
#include <ForceFeedback/ForceFeedback.h>
|
||||
#include <ForceFeedback/ForceFeedbackConstants.h>
|
||||
|
||||
#include "SDL_events.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
#include "SDL_sysjoystick_c.h"
|
||||
#include "SDL_events.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
#include "../../haptic/darwin/SDL_syshaptic_c.h" /* For haptic hot plugging */
|
||||
|
||||
|
||||
#define SDL_JOYSTICK_RUNLOOP_MODE CFSTR("SDLJoystick")
|
||||
|
||||
#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF)
|
||||
|
||||
/* The base object of the HID Manager API */
|
||||
static IOHIDManagerRef hidman = NULL;
|
||||
|
||||
/* Linked list of all available devices */
|
||||
static recDevice *gpDeviceList = NULL;
|
||||
|
||||
/* static incrementing counter for new joystick devices seen on the system. Devices should start with index 0 */
|
||||
static int s_joystick_instance_id = -1;
|
||||
void FreeRumbleEffectData(FFEFFECT *effect)
|
||||
{
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
SDL_free(effect->rgdwAxes);
|
||||
SDL_free(effect->rglDirection);
|
||||
SDL_free(effect->lpvTypeSpecificParams);
|
||||
SDL_free(effect);
|
||||
}
|
||||
|
||||
FFEFFECT *CreateRumbleEffectData(Sint16 magnitude, Uint32 duration_ms)
|
||||
{
|
||||
FFEFFECT *effect;
|
||||
FFPERIODIC *periodic;
|
||||
|
||||
/* Create the effect */
|
||||
effect = (FFEFFECT *)SDL_calloc(1, sizeof(*effect));
|
||||
if (!effect) {
|
||||
return NULL;
|
||||
}
|
||||
effect->dwSize = sizeof(*effect);
|
||||
effect->dwGain = 10000;
|
||||
effect->dwFlags = FFEFF_OBJECTOFFSETS;
|
||||
effect->dwDuration = duration_ms * 1000; /* In microseconds. */
|
||||
effect->dwTriggerButton = FFEB_NOTRIGGER;
|
||||
|
||||
effect->cAxes = 2;
|
||||
effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD));
|
||||
if (!effect->rgdwAxes) {
|
||||
FreeRumbleEffectData(effect);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG));
|
||||
if (!effect->rglDirection) {
|
||||
FreeRumbleEffectData(effect);
|
||||
return NULL;
|
||||
}
|
||||
effect->dwFlags |= FFEFF_CARTESIAN;
|
||||
|
||||
periodic = (FFPERIODIC *)SDL_calloc(1, sizeof(*periodic));
|
||||
if (!periodic) {
|
||||
FreeRumbleEffectData(effect);
|
||||
return NULL;
|
||||
}
|
||||
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
|
||||
periodic->dwPeriod = 1000000;
|
||||
|
||||
effect->cbTypeSpecificParams = sizeof(*periodic);
|
||||
effect->lpvTypeSpecificParams = periodic;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
static recDevice *GetDeviceForIndex(int device_index)
|
||||
{
|
||||
|
@ -157,6 +207,19 @@ JoystickDeviceWasRemovedCallback(void *ctx, IOReturn result, void *sender)
|
|||
recDevice *device = (recDevice *) ctx;
|
||||
device->removed = SDL_TRUE;
|
||||
device->deviceRef = NULL; // deviceRef was invalidated due to the remove
|
||||
if (device->ffeffect_ref) {
|
||||
FFDeviceReleaseEffect(device->ffdevice, device->ffeffect_ref);
|
||||
device->ffeffect_ref = NULL;
|
||||
}
|
||||
if (device->ffeffect) {
|
||||
FreeRumbleEffectData(device->ffeffect);
|
||||
device->ffeffect = NULL;
|
||||
}
|
||||
if (device->ffdevice) {
|
||||
FFReleaseDevice(device->ffdevice);
|
||||
device->ffdevice = NULL;
|
||||
device->ff_initialized = SDL_FALSE;
|
||||
}
|
||||
#if SDL_HAPTIC_IOKIT
|
||||
MacHaptic_MaybeRemoveDevice(device->ffservice);
|
||||
#endif
|
||||
|
@ -333,8 +396,6 @@ AddHIDElement(const void *value, void *parameter)
|
|||
static SDL_bool
|
||||
GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
|
||||
{
|
||||
const Uint16 BUS_USB = 0x03;
|
||||
const Uint16 BUS_BLUETOOTH = 0x05;
|
||||
Sint32 vendor = 0;
|
||||
Sint32 product = 0;
|
||||
Sint32 version = 0;
|
||||
|
@ -389,10 +450,17 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
|
|||
CFNumberGetValue(refCF, kCFNumberSInt32Type, &version);
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(vendor, product)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
SDL_memset(pDevice->guid.data, 0, sizeof(pDevice->guid.data));
|
||||
|
||||
if (vendor && product) {
|
||||
*guid16++ = SDL_SwapLE16(BUS_USB);
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16((Uint16)vendor);
|
||||
*guid16++ = 0;
|
||||
|
@ -401,7 +469,7 @@ GetDeviceInfo(IOHIDDeviceRef hidDevice, recDevice *pDevice)
|
|||
*guid16++ = SDL_SwapLE16((Uint16)version);
|
||||
*guid16++ = 0;
|
||||
} else {
|
||||
*guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
|
||||
*guid16++ = 0;
|
||||
SDL_strlcpy((char*)guid16, pDevice->product, sizeof(pDevice->guid.data) - 4);
|
||||
}
|
||||
|
@ -444,7 +512,6 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
|
|||
}
|
||||
|
||||
device = (recDevice *) SDL_calloc(1, sizeof(recDevice));
|
||||
|
||||
if (!device) {
|
||||
SDL_OutOfMemory();
|
||||
return;
|
||||
|
@ -455,8 +522,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
|
|||
return; /* not a device we care about, probably. */
|
||||
}
|
||||
|
||||
if (SDL_IsGameControllerNameAndGUID(device->product, device->guid) &&
|
||||
SDL_ShouldIgnoreGameController(device->product, device->guid)) {
|
||||
if (SDL_ShouldIgnoreJoystick(device->product, device->guid)) {
|
||||
SDL_free(device);
|
||||
return;
|
||||
}
|
||||
|
@ -466,16 +532,16 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
|
|||
IOHIDDeviceScheduleWithRunLoop(ioHIDDeviceObject, CFRunLoopGetCurrent(), SDL_JOYSTICK_RUNLOOP_MODE);
|
||||
|
||||
/* Allocate an instance ID for this device */
|
||||
device->instance_id = ++s_joystick_instance_id;
|
||||
device->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
/* We have to do some storage of the io_service_t for SDL_HapticOpenFromJoystick */
|
||||
ioservice = IOHIDDeviceGetService(ioHIDDeviceObject);
|
||||
#if SDL_HAPTIC_IOKIT
|
||||
if ((ioservice) && (FFIsForceFeedback(ioservice) == FF_OK)) {
|
||||
device->ffservice = ioservice;
|
||||
#if SDL_HAPTIC_IOKIT
|
||||
MacHaptic_MaybeAddDevice(ioservice);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Add device to the end of the list */
|
||||
if ( !gpDeviceList ) {
|
||||
|
@ -492,7 +558,7 @@ JoystickDeviceWasAddedCallback(void *ctx, IOReturn res, void *sender, IOHIDDevic
|
|||
++device_index; /* bump by one since we counted by pNext. */
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAdded(device_index);
|
||||
SDL_PrivateJoystickAdded(device->instance_id);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
|
@ -577,13 +643,8 @@ CreateHIDManager(void)
|
|||
}
|
||||
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* This function should return the number of available joysticks, or -1
|
||||
* on an unrecoverable fatal error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
static int
|
||||
DARWIN_JoystickInit(void)
|
||||
{
|
||||
if (gpDeviceList) {
|
||||
return SDL_SetError("Joystick: Device list already inited.");
|
||||
|
@ -593,12 +654,11 @@ SDL_SYS_JoystickInit(void)
|
|||
return SDL_SetError("Joystick: Couldn't initialize HID Manager");
|
||||
}
|
||||
|
||||
return SDL_SYS_NumJoysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function to return the number of joystick devices plugged in right now */
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
DARWIN_JoystickGetCount(void)
|
||||
{
|
||||
recDevice *device = gpDeviceList;
|
||||
int nJoySticks = 0;
|
||||
|
@ -613,10 +673,8 @@ SDL_SYS_NumJoysticks(void)
|
|||
return nJoySticks;
|
||||
}
|
||||
|
||||
/* Function to cause any queued joystick insertions to be processed
|
||||
*/
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
DARWIN_JoystickDetect(void)
|
||||
{
|
||||
recDevice *device = gpDeviceList;
|
||||
while (device) {
|
||||
|
@ -627,37 +685,43 @@ SDL_SYS_JoystickDetect(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* run this after the checks above so we don't set device->removed and delete the device before
|
||||
SDL_SYS_JoystickUpdate can run to clean up the SDL_Joystick object that owns this device */
|
||||
while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) {
|
||||
/* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */
|
||||
}
|
||||
/* run this after the checks above so we don't set device->removed and delete the device before
|
||||
DARWIN_JoystickUpdate can run to clean up the SDL_Joystick object that owns this device */
|
||||
while (CFRunLoopRunInMode(SDL_JOYSTICK_RUNLOOP_MODE,0,TRUE) == kCFRunLoopRunHandledSource) {
|
||||
/* no-op. Pending callbacks will fire in CFRunLoopRunInMode(). */
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
DARWIN_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
recDevice *device = GetDeviceForIndex(device_index);
|
||||
return device ? device->product : "UNKNOWN";
|
||||
}
|
||||
|
||||
/* Function to return the instance id of the joystick at device_index
|
||||
*/
|
||||
SDL_JoystickID
|
||||
SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickGUID
|
||||
DARWIN_JoystickGetDeviceGUID( int device_index )
|
||||
{
|
||||
recDevice *device = GetDeviceForIndex(device_index);
|
||||
SDL_JoystickGUID guid;
|
||||
if (device) {
|
||||
guid = device->guid;
|
||||
} else {
|
||||
SDL_zero(guid);
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
|
||||
static SDL_JoystickID
|
||||
DARWIN_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
recDevice *device = GetDeviceForIndex(device_index);
|
||||
return device ? device->instance_id : 0;
|
||||
}
|
||||
|
||||
/* Function to open a joystick for use.
|
||||
* The joystick to open is specified by the device index.
|
||||
* This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
* It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static int
|
||||
DARWIN_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
recDevice *device = GetDeviceForIndex(device_index);
|
||||
|
||||
|
@ -672,22 +736,144 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Function to query if the joystick is currently attached
|
||||
* It returns SDL_TRUE if attached, SDL_FALSE otherwise.
|
||||
*/
|
||||
SDL_bool
|
||||
SDL_SYS_JoystickAttached(SDL_Joystick * joystick)
|
||||
static SDL_bool
|
||||
DARWIN_JoystickIsAttached(SDL_Joystick * joystick)
|
||||
{
|
||||
return joystick->hwdata != NULL;
|
||||
}
|
||||
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
* This function shouldn't update the joystick structure directly,
|
||||
* but instead should call SDL_PrivateJoystick*() to deliver events
|
||||
* and update joystick device state.
|
||||
/*
|
||||
* Like strerror but for force feedback errors.
|
||||
*/
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static const char *
|
||||
FFStrError(unsigned int err)
|
||||
{
|
||||
switch (err) {
|
||||
case FFERR_DEVICEFULL:
|
||||
return "device full";
|
||||
/* This should be valid, but for some reason isn't defined... */
|
||||
/* case FFERR_DEVICENOTREG:
|
||||
return "device not registered"; */
|
||||
case FFERR_DEVICEPAUSED:
|
||||
return "device paused";
|
||||
case FFERR_DEVICERELEASED:
|
||||
return "device released";
|
||||
case FFERR_EFFECTPLAYING:
|
||||
return "effect playing";
|
||||
case FFERR_EFFECTTYPEMISMATCH:
|
||||
return "effect type mismatch";
|
||||
case FFERR_EFFECTTYPENOTSUPPORTED:
|
||||
return "effect type not supported";
|
||||
case FFERR_GENERIC:
|
||||
return "undetermined error";
|
||||
case FFERR_HASEFFECTS:
|
||||
return "device has effects";
|
||||
case FFERR_INCOMPLETEEFFECT:
|
||||
return "incomplete effect";
|
||||
case FFERR_INTERNAL:
|
||||
return "internal fault";
|
||||
case FFERR_INVALIDDOWNLOADID:
|
||||
return "invalid download id";
|
||||
case FFERR_INVALIDPARAM:
|
||||
return "invalid parameter";
|
||||
case FFERR_MOREDATA:
|
||||
return "more data";
|
||||
case FFERR_NOINTERFACE:
|
||||
return "interface not supported";
|
||||
case FFERR_NOTDOWNLOADED:
|
||||
return "effect is not downloaded";
|
||||
case FFERR_NOTINITIALIZED:
|
||||
return "object has not been initialized";
|
||||
case FFERR_OUTOFMEMORY:
|
||||
return "out of memory";
|
||||
case FFERR_UNPLUGGED:
|
||||
return "device is unplugged";
|
||||
case FFERR_UNSUPPORTED:
|
||||
return "function call unsupported";
|
||||
case FFERR_UNSUPPORTEDAXIS:
|
||||
return "axis unsupported";
|
||||
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude, Uint32 duration_ms)
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
if (!device->ffdevice) {
|
||||
result = FFCreateDevice(device->ffservice, &device->ffdevice);
|
||||
if (result != FF_OK) {
|
||||
return SDL_SetError("Unable to create force feedback device from service: %s", FFStrError(result));
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset and then enable actuators */
|
||||
result = FFDeviceSendForceFeedbackCommand(device->ffdevice, FFSFFC_RESET);
|
||||
if (result != FF_OK) {
|
||||
return SDL_SetError("Unable to reset force feedback device: %s", FFStrError(result));
|
||||
}
|
||||
|
||||
result = FFDeviceSendForceFeedbackCommand(device->ffdevice, FFSFFC_SETACTUATORSON);
|
||||
if (result != FF_OK) {
|
||||
return SDL_SetError("Unable to enable force feedback actuators: %s", FFStrError(result));
|
||||
}
|
||||
|
||||
/* Create the effect */
|
||||
device->ffeffect = CreateRumbleEffectData(magnitude, duration_ms);
|
||||
if (!device->ffeffect) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
result = FFDeviceCreateEffect(device->ffdevice, kFFEffectType_Sine_ID,
|
||||
device->ffeffect, &device->ffeffect_ref);
|
||||
if (result != FF_OK) {
|
||||
return SDL_SetError("Haptic: Unable to create effect: %s", FFStrError(result));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
HRESULT result;
|
||||
recDevice *device = joystick->hwdata;
|
||||
|
||||
/* Scale and average the two rumble strengths */
|
||||
Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
|
||||
|
||||
if (!device->ffservice) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
if (device->ff_initialized) {
|
||||
FFPERIODIC *periodic = ((FFPERIODIC *)device->ffeffect->lpvTypeSpecificParams);
|
||||
device->ffeffect->dwDuration = duration_ms * 1000; /* In microseconds. */
|
||||
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
|
||||
|
||||
result = FFEffectSetParameters(device->ffeffect_ref, device->ffeffect,
|
||||
(FFEP_DURATION | FFEP_TYPESPECIFICPARAMS));
|
||||
if (result != FF_OK) {
|
||||
return SDL_SetError("Unable to update rumble effect: %s", FFStrError(result));
|
||||
}
|
||||
} else {
|
||||
if (DARWIN_JoystickInitRumble(device, magnitude, duration_ms) < 0) {
|
||||
return -1;
|
||||
}
|
||||
device->ff_initialized = SDL_TRUE;
|
||||
}
|
||||
|
||||
result = FFEffectStart(device->ffeffect_ref, 1, 0);
|
||||
if (result != FF_OK) {
|
||||
return SDL_SetError("Unable to run the rumble effect: %s", FFStrError(result));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
DARWIN_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
recDevice *device = joystick->hwdata;
|
||||
recElement *element;
|
||||
|
@ -792,15 +978,13 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
}
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
DARWIN_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
DARWIN_JoystickQuit(void)
|
||||
{
|
||||
while (FreeDevice(gpDeviceList)) {
|
||||
/* spin */
|
||||
|
@ -814,23 +998,21 @@ SDL_SYS_JoystickQuit(void)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
SDL_JoystickDriver SDL_DARWIN_JoystickDriver =
|
||||
{
|
||||
recDevice *device = GetDeviceForIndex(device_index);
|
||||
SDL_JoystickGUID guid;
|
||||
if (device) {
|
||||
guid = device->guid;
|
||||
} else {
|
||||
SDL_zero(guid);
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick *joystick)
|
||||
{
|
||||
return joystick->hwdata->guid;
|
||||
}
|
||||
DARWIN_JoystickInit,
|
||||
DARWIN_JoystickGetCount,
|
||||
DARWIN_JoystickDetect,
|
||||
DARWIN_JoystickGetDeviceName,
|
||||
DARWIN_JoystickGetDeviceGUID,
|
||||
DARWIN_JoystickGetDeviceInstanceID,
|
||||
DARWIN_JoystickOpen,
|
||||
DARWIN_JoystickIsAttached,
|
||||
DARWIN_JoystickRumble,
|
||||
DARWIN_JoystickUpdate,
|
||||
DARWIN_JoystickClose,
|
||||
DARWIN_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_IOKIT */
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#define SDL_JOYSTICK_IOKIT_H
|
||||
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <ForceFeedback/ForceFeedback.h>
|
||||
#include <ForceFeedback/ForceFeedbackConstants.h>
|
||||
|
||||
struct recElement
|
||||
{
|
||||
|
@ -45,6 +47,10 @@ struct joystick_hwdata
|
|||
{
|
||||
IOHIDDeviceRef deviceRef; /* HIDManager device handle */
|
||||
io_service_t ffservice; /* Interface for force feedback, 0 = no ff */
|
||||
FFDeviceObjectReference ffdevice;
|
||||
FFEFFECT *ffeffect;
|
||||
FFEffectObjectReference ffeffect_ref;
|
||||
SDL_bool ff_initialized;
|
||||
|
||||
char product[256]; /* name of product */
|
||||
uint32_t usage; /* usage page from IOUSBHID Parser.h which defines general usage */
|
||||
|
|
|
@ -28,99 +28,92 @@
|
|||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
|
||||
static int
|
||||
DUMMY_JoystickInit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
DUMMY_JoystickGetCount(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
DUMMY_JoystickDetect(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
static const char *
|
||||
DUMMY_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
SDL_SetError("Logic error: No joysticks available");
|
||||
return (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickGUID
|
||||
DUMMY_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
return device_index;
|
||||
SDL_JoystickGUID guid;
|
||||
SDL_zero(guid);
|
||||
return guid;
|
||||
}
|
||||
|
||||
/* Function to open a joystick for use.
|
||||
The joystick to open is specified by the device index.
|
||||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static SDL_JoystickID
|
||||
DUMMY_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
DUMMY_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
return SDL_SetError("Logic error: No joysticks available");
|
||||
}
|
||||
|
||||
/* Function to determine if this joystick is attached to the system right now */
|
||||
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
static SDL_bool
|
||||
DUMMY_JoystickIsAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
return SDL_TRUE;
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
* This function shouldn't update the joystick structure directly,
|
||||
* but instead should call SDL_PrivateJoystick*() to deliver events
|
||||
* and update joystick device state.
|
||||
*/
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static int
|
||||
DUMMY_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void
|
||||
DUMMY_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
DUMMY_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
DUMMY_JoystickQuit(void)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
SDL_JoystickDriver SDL_DUMMY_JoystickDriver =
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
|
||||
SDL_zero( guid );
|
||||
SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
|
||||
return guid;
|
||||
}
|
||||
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
/* the GUID is just the first 16 chars of the name for now */
|
||||
const char *name = joystick->name;
|
||||
SDL_zero( guid );
|
||||
SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
|
||||
return guid;
|
||||
}
|
||||
DUMMY_JoystickInit,
|
||||
DUMMY_JoystickGetCount,
|
||||
DUMMY_JoystickDetect,
|
||||
DUMMY_JoystickGetDeviceName,
|
||||
DUMMY_JoystickGetDeviceGUID,
|
||||
DUMMY_JoystickGetDeviceInstanceID,
|
||||
DUMMY_JoystickOpen,
|
||||
DUMMY_JoystickIsAttached,
|
||||
DUMMY_JoystickRumble,
|
||||
DUMMY_JoystickUpdate,
|
||||
DUMMY_JoystickClose,
|
||||
DUMMY_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_DUMMY || SDL_JOYSTICK_DISABLED */
|
||||
|
||||
|
|
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 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_log.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"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_PS4
|
||||
|
||||
#define SONY_USB_VID 0x054C
|
||||
#define SONY_DS4_PID 0x05C4
|
||||
#define SONY_DS4_DONGLE_PID 0x0BA0
|
||||
#define SONY_DS4_SLIM_PID 0x09CC
|
||||
|
||||
#define USB_PACKET_LENGTH 64
|
||||
|
||||
#define VOLUME_CHECK_INTERVAL_MS (10 * 1000)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
k_EPS4ReportIdUsbState = 1,
|
||||
k_EPS4ReportIdUsbEffects = 5,
|
||||
k_EPS4ReportIdBluetoothState = 17,
|
||||
k_EPS4ReportIdBluetoothEffects = 17,
|
||||
k_EPS4ReportIdDisconnectMessage = 226,
|
||||
} EPS4ReportId;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
k_ePS4FeatureReportIdGyroCalibration_USB = 0x02,
|
||||
k_ePS4FeatureReportIdGyroCalibration_BT = 0x05,
|
||||
k_ePS4FeatureReportIdSerialNumber = 0x12,
|
||||
} EPS4FeatureReportID;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 ucLeftJoystickX;
|
||||
Uint8 ucLeftJoystickY;
|
||||
Uint8 ucRightJoystickX;
|
||||
Uint8 ucRightJoystickY;
|
||||
Uint8 rgucButtonsHatAndCounter[ 3 ];
|
||||
Uint8 ucTriggerLeft;
|
||||
Uint8 ucTriggerRight;
|
||||
Uint8 _rgucPad0[ 3 ];
|
||||
Sint16 sGyroX;
|
||||
Sint16 sGyroY;
|
||||
Sint16 sGyroZ;
|
||||
Sint16 sAccelX;
|
||||
Sint16 sAccelY;
|
||||
Sint16 sAccelZ;
|
||||
Uint8 _rgucPad1[ 5 ];
|
||||
Uint8 ucBatteryLevel;
|
||||
Uint8 _rgucPad2[ 4 ];
|
||||
Uint8 ucTrackpadCounter1;
|
||||
Uint8 rgucTrackpadData1[ 3 ];
|
||||
Uint8 ucTrackpadCounter2;
|
||||
Uint8 rgucTrackpadData2[ 3 ];
|
||||
} PS4StatePacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 ucRumbleRight;
|
||||
Uint8 ucRumbleLeft;
|
||||
Uint8 ucLedRed;
|
||||
Uint8 ucLedGreen;
|
||||
Uint8 ucLedBlue;
|
||||
Uint8 ucLedDelayOn;
|
||||
Uint8 ucLedDelayOff;
|
||||
Uint8 _rgucPad0[ 8 ];
|
||||
Uint8 ucVolumeLeft;
|
||||
Uint8 ucVolumeRight;
|
||||
Uint8 ucVolumeMic;
|
||||
Uint8 ucVolumeSpeaker;
|
||||
} DS4EffectsState_t;
|
||||
|
||||
typedef struct {
|
||||
SDL_bool is_dongle;
|
||||
SDL_bool is_bluetooth;
|
||||
SDL_bool audio_supported;
|
||||
Uint8 volume;
|
||||
Uint32 last_volume_check;
|
||||
Uint32 rumble_expiration;
|
||||
PS4StatePacket_t last_state;
|
||||
} SDL_DriverPS4_Context;
|
||||
|
||||
|
||||
/* Public domain CRC implementation adapted from:
|
||||
http://home.thep.lu.se/~bjorn/crc/crc32_simple.c
|
||||
*/
|
||||
static Uint32 crc32_for_byte(Uint32 r)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 8; ++i) {
|
||||
r = (r & 1? 0: (Uint32)0xEDB88320L) ^ r >> 1;
|
||||
}
|
||||
return r ^ (Uint32)0xFF000000L;
|
||||
}
|
||||
|
||||
static Uint32 crc32(Uint32 crc, const void *data, int count)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < count; ++i) {
|
||||
crc = crc32_for_byte((Uint8)crc ^ ((const Uint8*)data)[i]) ^ crc >> 8;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
#ifdef __WIN32__
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
|
||||
/* Define Vista for the Audio related includes below to work */
|
||||
#undef NTDDI_VERSION
|
||||
#define NTDDI_VERSION NTDDI_VISTA
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#define COBJMACROS
|
||||
#include <Mmdeviceapi.h>
|
||||
#include <Audioclient.h>
|
||||
#include <Endpointvolume.h>
|
||||
|
||||
#undef DEFINE_GUID
|
||||
#define DEFINE_GUID(n,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) static const GUID n = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
|
||||
DEFINE_GUID(IID_IAudioEndpointVolume, 0x5CDF2C82, 0x841E, 0x4546, 0x97, 0x22, 0x0C, 0xF7, 0x40, 0x78, 0x22, 0x9A);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static float GetSystemVolume(void)
|
||||
{
|
||||
float volume = -1.0f; /* Return this if we can't get system volume */
|
||||
|
||||
#ifdef __WIN32__
|
||||
HRESULT hr = WIN_CoInitialize();
|
||||
if (SUCCEEDED(hr)) {
|
||||
IMMDeviceEnumerator *pEnumerator;
|
||||
|
||||
/* This should gracefully fail on XP and succeed on everything Vista and above */
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, (LPVOID*)&pEnumerator);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IMMDevice *pDevice;
|
||||
|
||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eConsole, &pDevice);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IAudioEndpointVolume *pEndpointVolume;
|
||||
|
||||
hr = IMMDevice_Activate(pDevice, &IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (LPVOID*)&pEndpointVolume);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IAudioEndpointVolume_GetMasterVolumeLevelScalar(pEndpointVolume, &volume);
|
||||
IUnknown_Release(pEndpointVolume);
|
||||
}
|
||||
IUnknown_Release(pDevice);
|
||||
}
|
||||
IUnknown_Release(pEnumerator);
|
||||
}
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
#endif /* __WIN32__ */
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
static uint8_t GetPlaystationVolumeFromFloat(float fVolume)
|
||||
{
|
||||
const int k_nVolumeFitRatio = 15;
|
||||
const int k_nVolumeFitOffset = 9;
|
||||
float fVolLog;
|
||||
|
||||
if (fVolume > 1.0f || fVolume < 0.0f) {
|
||||
fVolume = 0.30f;
|
||||
}
|
||||
fVolLog = SDL_logf(fVolume * 100);
|
||||
|
||||
return (Uint8)((fVolLog * k_nVolumeFitRatio) + k_nVolumeFitOffset);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverPS4_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, int interface_number, Uint16 usage_page, Uint16 usage)
|
||||
{
|
||||
/* The Revolution Pro Controller exposes multiple interfaces on Windows */
|
||||
const Uint16 NACON_USB_VID = 0x146b;
|
||||
if (vendor_id == NACON_USB_VID && usage_page != 0 && usage_page != 1) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
return SDL_IsJoystickPS4(vendor_id, product_id);
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == SONY_USB_VID) {
|
||||
return "PS4 Controller";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool ReadFeatureReport(hid_device *dev, Uint8 report_id, Uint8 *data, size_t size)
|
||||
{
|
||||
Uint8 report[USB_PACKET_LENGTH + 1];
|
||||
|
||||
SDL_memset(report, 0, sizeof(report));
|
||||
report[0] = report_id;
|
||||
if (hid_get_feature_report(dev, report, sizeof(report)) < 0) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
SDL_memcpy(data, report, SDL_min(size, sizeof(report)));
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool CheckUSBConnected(hid_device *dev)
|
||||
{
|
||||
int i;
|
||||
Uint8 data[16];
|
||||
|
||||
/* This will fail if we're on Bluetooth */
|
||||
if (ReadFeatureReport(dev, k_ePS4FeatureReportIdSerialNumber, data, sizeof(data))) {
|
||||
for (i = 0; i < sizeof(data); ++i) {
|
||||
if (data[i] != 0x00) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
/* Maybe the dongle without a connected controller? */
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverPS4_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
|
||||
{
|
||||
SDL_DriverPS4_Context *ctx;
|
||||
|
||||
ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
*context = ctx;
|
||||
|
||||
/* Check for type of connection */
|
||||
ctx->is_dongle = (vendor_id == SONY_USB_VID && product_id == SONY_DS4_DONGLE_PID);
|
||||
if (ctx->is_dongle) {
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
} else if (vendor_id == SONY_USB_VID) {
|
||||
ctx->is_bluetooth = !CheckUSBConnected(dev);
|
||||
} else {
|
||||
/* Third party controllers appear to all be wired */
|
||||
ctx->is_bluetooth = SDL_FALSE;
|
||||
}
|
||||
#ifdef DEBUG_PS4
|
||||
SDL_Log("PS4 dongle = %s, bluetooth = %s\n", ctx->is_dongle ? "TRUE" : "FALSE", ctx->is_bluetooth ? "TRUE" : "FALSE");
|
||||
#endif
|
||||
|
||||
/* Check to see if audio is supported */
|
||||
if (vendor_id == SONY_USB_VID &&
|
||||
(product_id == SONY_DS4_SLIM_PID || product_id == SONY_DS4_DONGLE_PID )) {
|
||||
ctx->audio_supported = SDL_TRUE;
|
||||
}
|
||||
|
||||
/* Initialize LED and effect state */
|
||||
HIDAPI_DriverPS4_Rumble(joystick, dev, ctx, 0, 0, 0);
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
|
||||
DS4EffectsState_t *effects;
|
||||
Uint8 data[78];
|
||||
int report_size, offset;
|
||||
|
||||
/* In order to send rumble, we have to send a complete effect packet */
|
||||
SDL_memset(data, 0, sizeof(data));
|
||||
|
||||
if (ctx->is_bluetooth) {
|
||||
data[0] = k_EPS4ReportIdBluetoothEffects;
|
||||
data[1] = 0xC0 | 0x04; /* Magic value HID + CRC, also sets interval to 4ms for samples */
|
||||
data[3] = 0x03; /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
|
||||
|
||||
report_size = 78;
|
||||
offset = 6;
|
||||
} else {
|
||||
data[0] = k_EPS4ReportIdUsbEffects;
|
||||
data[1] = 0x07; /* Magic value */
|
||||
|
||||
report_size = 32;
|
||||
offset = 4;
|
||||
}
|
||||
effects = (DS4EffectsState_t *)&data[offset];
|
||||
|
||||
effects->ucRumbleLeft = (low_frequency_rumble >> 8);
|
||||
effects->ucRumbleRight = (high_frequency_rumble >> 8);
|
||||
|
||||
effects->ucLedRed = 0;
|
||||
effects->ucLedGreen = 0;
|
||||
effects->ucLedBlue = 80;
|
||||
|
||||
if (ctx->audio_supported) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (!ctx->last_volume_check ||
|
||||
SDL_TICKS_PASSED(now, ctx->last_volume_check + VOLUME_CHECK_INTERVAL_MS)) {
|
||||
ctx->volume = GetPlaystationVolumeFromFloat(GetSystemVolume());
|
||||
ctx->last_volume_check = now;
|
||||
}
|
||||
|
||||
effects->ucVolumeRight = ctx->volume;
|
||||
effects->ucVolumeLeft = ctx->volume;
|
||||
effects->ucVolumeSpeaker = ctx->volume;
|
||||
effects->ucVolumeMic = 0xFF;
|
||||
}
|
||||
|
||||
if (ctx->is_bluetooth) {
|
||||
/* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
|
||||
Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
|
||||
Uint32 unCRC;
|
||||
unCRC = crc32(0, &ubHdr, 1);
|
||||
unCRC = crc32(unCRC, data, (Uint32)(report_size - sizeof(unCRC)));
|
||||
SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
|
||||
}
|
||||
|
||||
if (hid_write(dev, data, report_size) != report_size) {
|
||||
return SDL_SetError("Couldn't send rumble packet");
|
||||
}
|
||||
|
||||
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
|
||||
ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
|
||||
} else {
|
||||
ctx->rumble_expiration = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet)
|
||||
{
|
||||
Sint16 axis;
|
||||
|
||||
if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) {
|
||||
{
|
||||
Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4);
|
||||
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
{
|
||||
Uint8 data = (packet->rgucButtonsHatAndCounter[0] & 0x0F);
|
||||
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) {
|
||||
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.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) {
|
||||
Uint8 data = packet->rgucButtonsHatAndCounter[1];
|
||||
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) {
|
||||
Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
|
||||
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
axis = ((int)packet->ucTriggerLeft * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
|
||||
axis = ((int)packet->ucTriggerRight * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
|
||||
axis = ((int)packet->ucLeftJoystickX * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
|
||||
axis = ((int)packet->ucLeftJoystickY * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
|
||||
axis = ((int)packet->ucRightJoystickX * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
|
||||
axis = ((int)packet->ucRightJoystickY * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
|
||||
|
||||
if (packet->ucBatteryLevel & 0x10) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
} else {
|
||||
/* Battery level ranges from 0 to 10 */
|
||||
int level = (packet->ucBatteryLevel & 0xF);
|
||||
if (level == 0) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
|
||||
} else if (level <= 2) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
|
||||
} else if (level <= 7) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
|
||||
} else {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverPS4_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
|
||||
while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
|
||||
switch (data[0]) {
|
||||
case k_EPS4ReportIdUsbState:
|
||||
HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[1]);
|
||||
break;
|
||||
case k_EPS4ReportIdBluetoothState:
|
||||
/* Bluetooth state packets have two additional bytes at the beginning */
|
||||
HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[3]);
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
SDL_Log("Unknown PS4 packet: 0x%.2x\n", data[0]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->rumble_expiration) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
|
||||
HIDAPI_DriverPS4_Rumble(joystick, dev, context, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverPS4_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_free(context);
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
|
||||
{
|
||||
SDL_HINT_JOYSTICK_HIDAPI_PS4,
|
||||
SDL_TRUE,
|
||||
HIDAPI_DriverPS4_IsSupportedDevice,
|
||||
HIDAPI_DriverPS4_GetDeviceName,
|
||||
HIDAPI_DriverPS4_Init,
|
||||
HIDAPI_DriverPS4_Rumble,
|
||||
HIDAPI_DriverPS4_Update,
|
||||
HIDAPI_DriverPS4_Quit
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI_PS4 */
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,899 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 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_log.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"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
|
||||
typedef enum {
|
||||
k_eSwitchInputReportIDs_SubcommandReply = 0x21,
|
||||
k_eSwitchInputReportIDs_FullControllerState = 0x30,
|
||||
k_eSwitchInputReportIDs_SimpleControllerState = 0x3F,
|
||||
k_eSwitchInputReportIDs_CommandAck = 0x81,
|
||||
} ESwitchInputReportIDs;
|
||||
|
||||
typedef enum {
|
||||
k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01,
|
||||
k_eSwitchOutputReportIDs_Rumble = 0x10,
|
||||
k_eSwitchOutputReportIDs_Proprietary = 0x80,
|
||||
} ESwitchOutputReportIDs;
|
||||
|
||||
typedef enum {
|
||||
k_eSwitchSubcommandIDs_BluetoothManualPair = 0x01,
|
||||
k_eSwitchSubcommandIDs_RequestDeviceInfo = 0x02,
|
||||
k_eSwitchSubcommandIDs_SetInputReportMode = 0x03,
|
||||
k_eSwitchSubcommandIDs_SetHCIState = 0x06,
|
||||
k_eSwitchSubcommandIDs_SPIFlashRead = 0x10,
|
||||
k_eSwitchSubcommandIDs_SetPlayerLights = 0x30,
|
||||
k_eSwitchSubcommandIDs_SetHomeLight = 0x38,
|
||||
k_eSwitchSubcommandIDs_EnableIMU = 0x40,
|
||||
k_eSwitchSubcommandIDs_SetIMUSensitivity = 0x41,
|
||||
k_eSwitchSubcommandIDs_EnableVibration = 0x48,
|
||||
} ESwitchSubcommandIDs;
|
||||
|
||||
typedef enum {
|
||||
k_eSwitchProprietaryCommandIDs_Handshake = 0x02,
|
||||
k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03,
|
||||
k_eSwitchProprietaryCommandIDs_ForceUSB = 0x04,
|
||||
k_eSwitchProprietaryCommandIDs_ClearUSB = 0x05,
|
||||
k_eSwitchProprietaryCommandIDs_ResetMCU = 0x06,
|
||||
} ESwitchProprietaryCommandIDs;
|
||||
|
||||
typedef enum {
|
||||
k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1,
|
||||
k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2,
|
||||
k_eSwitchDeviceInfoControllerType_ProController = 0x3,
|
||||
} ESwitchDeviceInfoControllerType;
|
||||
|
||||
#define k_unSwitchOutputPacketDataLength 49
|
||||
#define k_unSwitchMaxOutputPacketLength 64
|
||||
#define k_unSwitchBluetoothPacketLength k_unSwitchOutputPacketDataLength
|
||||
#define k_unSwitchUSBPacketLength k_unSwitchMaxOutputPacketLength
|
||||
|
||||
#define k_unSPIStickCalibrationStartOffset 0x603D
|
||||
#define k_unSPIStickCalibrationEndOffset 0x604E
|
||||
#define k_unSPIStickCalibrationLength (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1)
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
Uint8 rgucButtons[2];
|
||||
Uint8 ucStickHat;
|
||||
Sint16 sJoystickLeft[2];
|
||||
Sint16 sJoystickRight[2];
|
||||
} SwitchSimpleStatePacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 ucCounter;
|
||||
Uint8 ucBatteryAndConnection;
|
||||
Uint8 rgucButtons[3];
|
||||
Uint8 rgucJoystickLeft[3];
|
||||
Uint8 rgucJoystickRight[3];
|
||||
Uint8 ucVibrationCode;
|
||||
} SwitchControllerStatePacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SwitchControllerStatePacket_t controllerState;
|
||||
|
||||
struct {
|
||||
Sint16 sAccelX;
|
||||
Sint16 sAccelY;
|
||||
Sint16 sAccelZ;
|
||||
|
||||
Sint16 sGyroX;
|
||||
Sint16 sGyroY;
|
||||
Sint16 sGyroZ;
|
||||
} imuState[3];
|
||||
} SwitchStatePacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint32 unAddress;
|
||||
Uint8 ucLength;
|
||||
} SwitchSPIOpData_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SwitchControllerStatePacket_t m_controllerState;
|
||||
|
||||
Uint8 ucSubcommandAck;
|
||||
Uint8 ucSubcommandID;
|
||||
|
||||
#define k_unSubcommandDataBytes 35
|
||||
union {
|
||||
Uint8 rgucSubcommandData[ k_unSubcommandDataBytes ];
|
||||
|
||||
struct {
|
||||
SwitchSPIOpData_t opData;
|
||||
Uint8 rgucReadData[ k_unSubcommandDataBytes - sizeof(SwitchSPIOpData_t) ];
|
||||
} spiReadData;
|
||||
|
||||
struct {
|
||||
Uint8 rgucFirmwareVersion[2];
|
||||
Uint8 ucDeviceType;
|
||||
Uint8 ucFiller1;
|
||||
Uint8 rgucMACAddress[6];
|
||||
Uint8 ucFiller2;
|
||||
Uint8 ucColorLocation;
|
||||
} deviceInfo;
|
||||
};
|
||||
} SwitchSubcommandInputPacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 rgucData[4];
|
||||
} SwitchRumbleData_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 ucPacketType;
|
||||
Uint8 ucPacketNumber;
|
||||
SwitchRumbleData_t rumbleData[2];
|
||||
} SwitchCommonOutputPacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SwitchCommonOutputPacket_t commonData;
|
||||
|
||||
Uint8 ucSubcommandID;
|
||||
Uint8 rgucSubcommandData[ k_unSwitchOutputPacketDataLength - sizeof(SwitchCommonOutputPacket_t) - 1 ];
|
||||
} SwitchSubcommandOutputPacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 ucPacketType;
|
||||
Uint8 ucProprietaryID;
|
||||
|
||||
Uint8 rgucProprietaryData[ k_unSwitchOutputPacketDataLength - 1 - 1 ];
|
||||
} SwitchProprietaryOutputPacket_t;
|
||||
#pragma pack()
|
||||
|
||||
typedef struct {
|
||||
hid_device *dev;
|
||||
SDL_bool m_bIsUsingBluetooth;
|
||||
Uint8 m_nCommandNumber;
|
||||
SwitchCommonOutputPacket_t m_RumblePacket;
|
||||
Uint32 m_nRumbleExpiration;
|
||||
Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
|
||||
SwitchSimpleStatePacket_t m_lastSimpleState;
|
||||
SwitchStatePacket_t m_lastFullState;
|
||||
|
||||
struct StickCalibrationData {
|
||||
struct {
|
||||
Sint16 sCenter;
|
||||
Sint16 sMin;
|
||||
Sint16 sMax;
|
||||
} axis[2];
|
||||
} m_StickCalData[2];
|
||||
|
||||
struct StickExtents {
|
||||
struct {
|
||||
Sint16 sMin;
|
||||
Sint16 sMax;
|
||||
} axis[2];
|
||||
} m_StickExtents[2];
|
||||
} SDL_DriverSwitch_Context;
|
||||
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverSwitch_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, int interface_number, Uint16 usage_page, Uint16 usage)
|
||||
{
|
||||
return SDL_IsJoystickNintendoSwitchPro(vendor_id, product_id);
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
/* Give a user friendly name for this controller */
|
||||
if (SDL_IsJoystickNintendoSwitchPro(vendor_id, product_id)) {
|
||||
return "Nintendo Switch Pro Controller";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ReadInput(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
return hid_read_timeout(ctx->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
|
||||
}
|
||||
|
||||
static int WriteOutput(SDL_DriverSwitch_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
return hid_write(ctx->dev, data, size);
|
||||
}
|
||||
|
||||
static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
|
||||
{
|
||||
/* Average response time for messages is ~30ms */
|
||||
Uint32 TimeoutMs = 100;
|
||||
Uint32 startTicks = SDL_GetTicks();
|
||||
|
||||
int nRead = 0;
|
||||
while ((nRead = ReadInput(ctx)) != -1) {
|
||||
if (nRead > 0) {
|
||||
if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) {
|
||||
SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&ctx->m_rgucReadBuffer[ 1 ];
|
||||
if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) {
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SDL_Delay(1);
|
||||
}
|
||||
|
||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs expectedID)
|
||||
{
|
||||
/* Average response time for messages is ~30ms */
|
||||
Uint32 TimeoutMs = 100;
|
||||
Uint32 startTicks = SDL_GetTicks();
|
||||
|
||||
int nRead = 0;
|
||||
while ((nRead = ReadInput(ctx)) != -1) {
|
||||
if (nRead > 0) {
|
||||
if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck && ctx->m_rgucReadBuffer[ 1 ] == expectedID) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
} else {
|
||||
SDL_Delay(1);
|
||||
}
|
||||
|
||||
if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
|
||||
{
|
||||
SDL_memset(outPacket, 0, sizeof(*outPacket));
|
||||
|
||||
outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
|
||||
outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber;
|
||||
|
||||
SDL_memcpy(&outPacket->commonData.rumbleData, &ctx->m_RumblePacket.rumbleData, sizeof(ctx->m_RumblePacket.rumbleData));
|
||||
|
||||
outPacket->ucSubcommandID = ucCommandID;
|
||||
SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen);
|
||||
|
||||
ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
|
||||
}
|
||||
|
||||
static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucLen)
|
||||
{
|
||||
Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
|
||||
const size_t unWriteSize = ctx->m_bIsUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
|
||||
|
||||
if (ucLen > k_unSwitchOutputPacketDataLength) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (ucLen < unWriteSize) {
|
||||
SDL_memcpy(rgucBuf, pBuf, ucLen);
|
||||
SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen);
|
||||
pBuf = rgucBuf;
|
||||
ucLen = (Uint8)unWriteSize;
|
||||
}
|
||||
return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0);
|
||||
}
|
||||
|
||||
static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
|
||||
{
|
||||
int nRetries = 5;
|
||||
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||
|
||||
while (!reply && nRetries--) {
|
||||
SwitchSubcommandOutputPacket_t commandPacket;
|
||||
ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket);
|
||||
|
||||
if (!WritePacket(ctx, &commandPacket, sizeof(commandPacket))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
reply = ReadSubcommandReply(ctx, ucCommandID);
|
||||
}
|
||||
|
||||
if (ppReply) {
|
||||
*ppReply = reply;
|
||||
}
|
||||
return reply != NULL;
|
||||
}
|
||||
|
||||
static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply)
|
||||
{
|
||||
int nRetries = 5;
|
||||
|
||||
while (nRetries--) {
|
||||
SwitchProprietaryOutputPacket_t packet;
|
||||
|
||||
if ((!pBuf && ucLen > 0) || ucLen > sizeof(packet.rgucProprietaryData)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
|
||||
packet.ucProprietaryID = ucCommand;
|
||||
SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen);
|
||||
|
||||
if (!WritePacket(ctx, &packet, sizeof(packet))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
|
||||
{
|
||||
pRumble->rgucData[0] = 0x00;
|
||||
pRumble->rgucData[1] = 0x01;
|
||||
pRumble->rgucData[2] = 0x40;
|
||||
pRumble->rgucData[3] = 0x40;
|
||||
}
|
||||
|
||||
static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 ucHighFreqAmp, Uint8 ucLowFreq, Uint16 usLowFreqAmp)
|
||||
{
|
||||
if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) {
|
||||
// High-band frequency and low-band amplitude are actually nine-bits each so they
|
||||
// take a bit from the high-band amplitude and low-band frequency bytes respectively
|
||||
pRumble->rgucData[0] = usHighFreq & 0xFF;
|
||||
pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01);
|
||||
|
||||
pRumble->rgucData[2] = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80);
|
||||
pRumble->rgucData[3] = usLowFreqAmp & 0xFF;
|
||||
|
||||
#ifdef DEBUG_RUMBLE
|
||||
SDL_Log("Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X\n",
|
||||
usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq,
|
||||
ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
|
||||
#endif
|
||||
} else {
|
||||
SetNeutralRumble(pRumble);
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
/* Write into m_RumblePacket rather than a temporary buffer to allow the current rumble state
|
||||
* to be retained for subsequent rumble or subcommand packets sent to the controller
|
||||
*/
|
||||
ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble;
|
||||
ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber;
|
||||
ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
|
||||
|
||||
return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
|
||||
}
|
||||
|
||||
static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
/* We have to send a connection handshake to the controller when communicating over USB
|
||||
* before we're able to send it other commands. Luckily this command is not supported
|
||||
* over Bluetooth, so we can use the controller's lack of response as a way to
|
||||
* determine if the connection is over USB or Bluetooth
|
||||
*/
|
||||
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_HighSpeed, NULL, 0, SDL_TRUE)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool SetVibrationEnabled(SDL_DriverSwitch_Context *ctx, Uint8 enabled)
|
||||
{
|
||||
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableVibration, &enabled, sizeof(enabled), NULL);
|
||||
|
||||
}
|
||||
static SDL_bool SetInputMode(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
|
||||
{
|
||||
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1, NULL);
|
||||
}
|
||||
|
||||
static SDL_bool SetHomeLED(SDL_DriverSwitch_Context *ctx, Uint8 brightness)
|
||||
{
|
||||
Uint8 ucLedIntensity = 0;
|
||||
Uint8 rgucBuffer[4];
|
||||
|
||||
if (brightness > 0) {
|
||||
if (brightness < 65) {
|
||||
ucLedIntensity = (brightness + 5) / 10;
|
||||
} else {
|
||||
ucLedIntensity = (Uint8)SDL_ceilf(0xF * SDL_powf((float)brightness / 100.f, 2.13f));
|
||||
}
|
||||
}
|
||||
|
||||
rgucBuffer[0] = (0x0 << 4) | 0x1; /* 0 mini cycles (besides first), cycle duration 8ms */
|
||||
rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0; /* LED start intensity (0x0-0xF), 0 cycles (LED stays on at start intensity after first cycle) */
|
||||
rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0; /* First cycle LED intensity, 0x0 intensity for second cycle */
|
||||
rgucBuffer[3] = (0x0 << 4) | 0x0; /* 8ms fade transition to first cycle, 8ms first cycle LED duration */
|
||||
|
||||
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer, sizeof(rgucBuffer), NULL);
|
||||
}
|
||||
|
||||
static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot)
|
||||
{
|
||||
Uint8 led_data = (1 << slot);
|
||||
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
|
||||
}
|
||||
|
||||
static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
Uint8 *pStickCal;
|
||||
size_t stick, axis;
|
||||
SwitchSubcommandInputPacket_t *reply = NULL;
|
||||
|
||||
/* Read Calibration Info */
|
||||
SwitchSPIOpData_t readParams;
|
||||
readParams.unAddress = k_unSPIStickCalibrationStartOffset;
|
||||
readParams.ucLength = k_unSPIStickCalibrationLength;
|
||||
|
||||
if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Stick calibration values are 12-bits each and are packed by bit
|
||||
* For whatever reason the fields are in a different order for each stick
|
||||
* Left: X-Max, Y-Max, X-Center, Y-Center, X-Min, Y-Min
|
||||
* Right: X-Center, Y-Center, X-Min, Y-Min, X-Max, Y-Max
|
||||
*/
|
||||
pStickCal = reply->spiReadData.rgucReadData;
|
||||
|
||||
/* Left stick */
|
||||
ctx->m_StickCalData[0].axis[0].sMax = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0]; /* X Axis max above center */
|
||||
ctx->m_StickCalData[0].axis[1].sMax = (pStickCal[2] << 4) | (pStickCal[1] >> 4); /* Y Axis max above center */
|
||||
ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3]; /* X Axis center */
|
||||
ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4); /* Y Axis center */
|
||||
ctx->m_StickCalData[0].axis[0].sMin = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6]; /* X Axis min below center */
|
||||
ctx->m_StickCalData[0].axis[1].sMin = (pStickCal[8] << 4) | (pStickCal[7] >> 4); /* Y Axis min below center */
|
||||
|
||||
/* Right stick */
|
||||
ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9]; /* X Axis center */
|
||||
ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4); /* Y Axis center */
|
||||
ctx->m_StickCalData[1].axis[0].sMin = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12]; /* X Axis min below center */
|
||||
ctx->m_StickCalData[1].axis[1].sMin = (pStickCal[14] << 4) | (pStickCal[13] >> 4); /* Y Axis min below center */
|
||||
ctx->m_StickCalData[1].axis[0].sMax = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15]; /* X Axis max above center */
|
||||
ctx->m_StickCalData[1].axis[1].sMax = (pStickCal[17] << 4) | (pStickCal[16] >> 4); /* Y Axis max above center */
|
||||
|
||||
/* Filter out any values that were uninitialized (0xFFF) in the SPI read */
|
||||
for (stick = 0; stick < 2; ++stick) {
|
||||
for (axis = 0; axis < 2; ++axis) {
|
||||
if (ctx->m_StickCalData[stick].axis[axis].sCenter == 0xFFF) {
|
||||
ctx->m_StickCalData[stick].axis[axis].sCenter = 0;
|
||||
}
|
||||
if (ctx->m_StickCalData[stick].axis[axis].sMax == 0xFFF) {
|
||||
ctx->m_StickCalData[stick].axis[axis].sMax = 0;
|
||||
}
|
||||
if (ctx->m_StickCalData[stick].axis[axis].sMin == 0xFFF) {
|
||||
ctx->m_StickCalData[stick].axis[axis].sMin = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->m_bIsUsingBluetooth) {
|
||||
for (stick = 0; stick < 2; ++stick) {
|
||||
for(axis = 0; axis < 2; ++axis) {
|
||||
ctx->m_StickExtents[stick].axis[axis].sMin = (Sint16)(SDL_MIN_SINT16 * 0.5f);
|
||||
ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(SDL_MAX_SINT16 * 0.5f);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (stick = 0; stick < 2; ++stick) {
|
||||
for(axis = 0; axis < 2; ++axis) {
|
||||
ctx->m_StickExtents[stick].axis[axis].sMin = -(Sint16)(ctx->m_StickCalData[stick].axis[axis].sMin * 0.7f);
|
||||
ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(ctx->m_StickCalData[stick].axis[axis].sMax * 0.7f);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static float fsel(float fComparand, float fValGE, float fLT)
|
||||
{
|
||||
return fComparand >= 0 ? fValGE : fLT;
|
||||
}
|
||||
|
||||
static float RemapVal(float val, float A, float B, float C, float D)
|
||||
{
|
||||
if (A == B) {
|
||||
return fsel(val - B , D , C);
|
||||
}
|
||||
return C + (D - C) * (val - A) / (B - A);
|
||||
}
|
||||
|
||||
static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue, Sint16 sCenter)
|
||||
{
|
||||
sRawValue -= sCenter;
|
||||
|
||||
if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
|
||||
}
|
||||
if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
|
||||
ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
|
||||
}
|
||||
|
||||
if (sRawValue > 0) {
|
||||
return (Sint16)(RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16));
|
||||
} else {
|
||||
return (Sint16)(RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
|
||||
{
|
||||
return ApplyStickCalibrationCentered(ctx, nStick, nAxis, sRawValue, ctx->m_StickCalData[nStick].axis[nAxis].sCenter);
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverSwitch_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
|
||||
{
|
||||
SDL_DriverSwitch_Context *ctx;
|
||||
Uint8 input_mode;
|
||||
|
||||
ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
ctx->dev = dev;
|
||||
|
||||
*context = ctx;
|
||||
|
||||
/* Initialize rumble data */
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
|
||||
|
||||
/* Try setting up USB mode, and if that fails we're using Bluetooth */
|
||||
if (!BTrySetupUSB(ctx)) {
|
||||
ctx->m_bIsUsingBluetooth = SDL_TRUE;
|
||||
}
|
||||
|
||||
if (!LoadStickCalibration(ctx)) {
|
||||
SDL_SetError("Couldn't load stick calibration");
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!SetVibrationEnabled(ctx, 1)) {
|
||||
SDL_SetError("Couldn't enable vibration");
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Set the desired input mode */
|
||||
if (ctx->m_bIsUsingBluetooth) {
|
||||
input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
|
||||
} else {
|
||||
input_mode = k_eSwitchInputReportIDs_FullControllerState;
|
||||
}
|
||||
if (!SetInputMode(ctx, input_mode)) {
|
||||
SDL_SetError("Couldn't set input mode");
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Start sending USB reports */
|
||||
if (!ctx->m_bIsUsingBluetooth) {
|
||||
/* 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");
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the LED state */
|
||||
SetHomeLED(ctx, 100);
|
||||
SetSlotLED(ctx, (joystick->instance_id % 4));
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverSwitch_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
|
||||
|
||||
/* Experimentally determined rumble values. These will only matter on some controllers as tested ones
|
||||
* seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble
|
||||
*
|
||||
* More information about these values can be found here:
|
||||
* https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
|
||||
*/
|
||||
const Uint16 k_usHighFreq = 0x0074;
|
||||
const Uint8 k_ucHighFreqAmp = 0xBE;
|
||||
const Uint8 k_ucLowFreq = 0x3D;
|
||||
const Uint16 k_usLowFreqAmp = 0x806F;
|
||||
|
||||
if (low_frequency_rumble) {
|
||||
EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
|
||||
} else {
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
|
||||
}
|
||||
|
||||
if (high_frequency_rumble) {
|
||||
EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
|
||||
} else {
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
|
||||
}
|
||||
|
||||
if (!WriteRumble(ctx)) {
|
||||
SDL_SetError("Couldn't send rumble packet");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
|
||||
ctx->m_nRumbleExpiration = SDL_GetTicks() + duration_ms;
|
||||
} else {
|
||||
ctx->m_nRumbleExpiration = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchSimpleStatePacket_t *packet)
|
||||
{
|
||||
/* 0x8000 is the neutral value for all joystick axes */
|
||||
const Uint16 usJoystickCenter = 0x8000;
|
||||
Sint16 axis;
|
||||
|
||||
if (packet->rgucButtons[0] != ctx->m_lastSimpleState.rgucButtons[0]) {
|
||||
Uint8 data = packet->rgucButtons[0];
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
|
||||
axis = (data & 0x40) ? 32767 : -32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
|
||||
|
||||
axis = (data & 0x80) ? 32767 : -32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
|
||||
}
|
||||
|
||||
if (packet->rgucButtons[1] != ctx->m_lastSimpleState.rgucButtons[1]) {
|
||||
Uint8 data = packet->rgucButtons[1];
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (packet->ucStickHat != ctx->m_lastSimpleState.ucStickHat) {
|
||||
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 (packet->ucStickHat) {
|
||||
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);
|
||||
}
|
||||
|
||||
axis = ApplyStickCalibrationCentered(ctx, 0, 0, packet->sJoystickLeft[0], (Sint16)usJoystickCenter);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
|
||||
|
||||
axis = ApplyStickCalibrationCentered(ctx, 0, 1, packet->sJoystickLeft[1], (Sint16)usJoystickCenter);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
|
||||
|
||||
axis = ApplyStickCalibrationCentered(ctx, 1, 0, packet->sJoystickRight[0], (Sint16)usJoystickCenter);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
|
||||
|
||||
axis = ApplyStickCalibrationCentered(ctx, 1, 1, packet->sJoystickRight[1], (Sint16)usJoystickCenter);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
|
||||
|
||||
ctx->m_lastSimpleState = *packet;
|
||||
}
|
||||
|
||||
static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
|
||||
{
|
||||
Sint16 axis;
|
||||
|
||||
if (packet->controllerState.rgucButtons[0] != ctx->m_lastFullState.controllerState.rgucButtons[0]) {
|
||||
Uint8 data = packet->controllerState.rgucButtons[0];
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
axis = (data & 0x80) ? 32767 : -32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
|
||||
}
|
||||
|
||||
if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) {
|
||||
Uint8 data = packet->controllerState.rgucButtons[1];
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) {
|
||||
Uint8 data = packet->controllerState.rgucButtons[2];
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
axis = (data & 0x80) ? 32767 : -32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
|
||||
}
|
||||
|
||||
axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8);
|
||||
axis = ApplyStickCalibration(ctx, 0, 0, axis);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
|
||||
|
||||
axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4);
|
||||
axis = ApplyStickCalibration(ctx, 0, 1, axis);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
|
||||
|
||||
axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8);
|
||||
axis = ApplyStickCalibration(ctx, 1, 0, axis);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
|
||||
|
||||
axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4);
|
||||
axis = ApplyStickCalibration(ctx, 1, 1, axis);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
|
||||
|
||||
/* High nibble of battery/connection byte is battery level, low nibble is connection status
|
||||
* LSB of connection nibble is USB/Switch connection status
|
||||
*/
|
||||
if (packet->controllerState.ucBatteryAndConnection & 0x1) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
} else {
|
||||
/* LSB of the battery nibble is used to report charging.
|
||||
* The battery level is reported from 0(empty)-8(full)
|
||||
*/
|
||||
int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
|
||||
if (level == 0) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
|
||||
} else if (level <= 2) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
|
||||
} else if (level <= 6) {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
|
||||
} else {
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->m_lastFullState = *packet;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverSwitch_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
|
||||
|
||||
while (ReadInput(ctx) > 0) {
|
||||
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 (ctx->m_nRumbleExpiration) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(now, ctx->m_nRumbleExpiration)) {
|
||||
HIDAPI_DriverSwitch_Rumble(joystick, dev, context, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverSwitch_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
|
||||
|
||||
/* Restore simple input mode for other applications */
|
||||
SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
|
||||
|
||||
SDL_free(context);
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
|
||||
{
|
||||
SDL_HINT_JOYSTICK_HIDAPI_SWITCH,
|
||||
SDL_TRUE,
|
||||
HIDAPI_DriverSwitch_IsSupportedDevice,
|
||||
HIDAPI_DriverSwitch_GetDeviceName,
|
||||
HIDAPI_DriverSwitch_Init,
|
||||
HIDAPI_DriverSwitch_Rumble,
|
||||
HIDAPI_DriverSwitch_Update,
|
||||
HIDAPI_DriverSwitch_Quit
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 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_log.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"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
|
||||
|
||||
#define USB_PACKET_LENGTH 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint16 vendor_id;
|
||||
Uint16 product_id;
|
||||
const char *name;
|
||||
} SDL_DriverXbox360_DeviceName;
|
||||
|
||||
static const SDL_DriverXbox360_DeviceName xbox360_devicenames[] = {
|
||||
{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller" },
|
||||
{ 0x044f, 0xb326, "Thrustmaster Gamepad GP XID" },
|
||||
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad" },
|
||||
{ 0x045e, 0x028f, "Microsoft X-Box 360 pad v2" },
|
||||
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)" },
|
||||
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver" },
|
||||
{ 0x046d, 0xc21d, "Logitech Gamepad F310" },
|
||||
{ 0x046d, 0xc21e, "Logitech Gamepad F510" },
|
||||
{ 0x046d, 0xc21f, "Logitech Gamepad F710" },
|
||||
{ 0x046d, 0xc242, "Logitech Chillstream Controller" },
|
||||
{ 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel" },
|
||||
{ 0x056e, 0x2004, "Elecom JC-U3613M" },
|
||||
{ 0x06a3, 0xf51a, "Saitek P3600" },
|
||||
{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller" },
|
||||
{ 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE" },
|
||||
{ 0x0738, 0x4726, "Mad Catz Xbox 360 Controller" },
|
||||
{ 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad" },
|
||||
{ 0x0738, 0x4736, "Mad Catz MicroCon Gamepad" },
|
||||
{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)" },
|
||||
{ 0x0738, 0x4740, "Mad Catz Beat Pad" },
|
||||
{ 0x0738, 0x4758, "Mad Catz Arcade Game Stick" },
|
||||
{ 0x0738, 0x9871, "Mad Catz Portable Drum" },
|
||||
{ 0x0738, 0xb726, "Mad Catz Xbox controller - MW2" },
|
||||
{ 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2" },
|
||||
{ 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad" },
|
||||
{ 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360" },
|
||||
{ 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360" },
|
||||
{ 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02" },
|
||||
{ 0x0738, 0xf738, "Super SFIV FightStick TE S" },
|
||||
{ 0x07ff, 0xffff, "Mad Catz GamePad" },
|
||||
{ 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad" },
|
||||
{ 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360" },
|
||||
{ 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller" },
|
||||
{ 0x0e6f, 0x0131, "PDP EA Sports Controller" },
|
||||
{ 0x0e6f, 0x0133, "Xbox 360 Wired Controller" },
|
||||
{ 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller" },
|
||||
{ 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360" },
|
||||
{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360" },
|
||||
{ 0x0e6f, 0x0301, "Logic3 Controller" },
|
||||
{ 0x0e6f, 0x0401, "Logic3 Controller" },
|
||||
{ 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360" },
|
||||
{ 0x0e6f, 0x0501, "PDP Xbox 360 Controller" },
|
||||
{ 0x0e6f, 0xf900, "PDP Afterglow AX.1" },
|
||||
{ 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick" },
|
||||
{ 0x0f0d, 0x000c, "Hori PadEX Turbo" },
|
||||
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2" },
|
||||
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX" },
|
||||
{ 0x0f0d, 0x001b, "Hori Real Arcade Pro VX" },
|
||||
{ 0x11c9, 0x55f0, "Nacon GC-100XF" },
|
||||
{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad" },
|
||||
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1" },
|
||||
{ 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick" },
|
||||
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer" },
|
||||
{ 0x1430, 0xf801, "RedOctane Controller" },
|
||||
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller" },
|
||||
{ 0x1532, 0x0037, "Razer Sabertooth" },
|
||||
{ 0x15e4, 0x3f00, "Power A Mini Pro Elite" },
|
||||
{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller" },
|
||||
{ 0x15e4, 0x3f10, "Batarang Xbox 360 controller" },
|
||||
{ 0x162e, 0xbeef, "Joytech Neo-Se Take2" },
|
||||
{ 0x1689, 0xfd00, "Razer Onza Tournament Edition" },
|
||||
{ 0x1689, 0xfd01, "Razer Onza Classic Edition" },
|
||||
{ 0x1689, 0xfe00, "Razer Sabertooth" },
|
||||
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar" },
|
||||
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit" },
|
||||
{ 0x1bad, 0x0130, "Ion Drum Rocker" },
|
||||
{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller" },
|
||||
{ 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick" },
|
||||
{ 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360" },
|
||||
{ 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad" },
|
||||
{ 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)" },
|
||||
{ 0x1bad, 0xf025, "Mad Catz Call Of Duty" },
|
||||
{ 0x1bad, 0xf027, "Mad Catz FPS Pro" },
|
||||
{ 0x1bad, 0xf028, "Street Fighter IV FightPad" },
|
||||
{ 0x1bad, 0xf02e, "Mad Catz Fightpad" },
|
||||
{ 0x1bad, 0xf030, "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel" },
|
||||
{ 0x1bad, 0xf036, "Mad Catz MicroCon GamePad Pro" },
|
||||
{ 0x1bad, 0xf038, "Street Fighter IV FightStick TE" },
|
||||
{ 0x1bad, 0xf039, "Mad Catz MvC2 TE" },
|
||||
{ 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro" },
|
||||
{ 0x1bad, 0xf03d, "Street Fighter IV Arcade Stick TE - Chun Li" },
|
||||
{ 0x1bad, 0xf03e, "Mad Catz MLG FightStick TE" },
|
||||
{ 0x1bad, 0xf03f, "Mad Catz FightStick SoulCaliber" },
|
||||
{ 0x1bad, 0xf042, "Mad Catz FightStick TES+" },
|
||||
{ 0x1bad, 0xf080, "Mad Catz FightStick TE2" },
|
||||
{ 0x1bad, 0xf501, "HoriPad EX2 Turbo" },
|
||||
{ 0x1bad, 0xf502, "Hori Real Arcade Pro.VX SA" },
|
||||
{ 0x1bad, 0xf503, "Hori Fighting Stick VX" },
|
||||
{ 0x1bad, 0xf504, "Hori Real Arcade Pro. EX" },
|
||||
{ 0x1bad, 0xf505, "Hori Fighting Stick EX2B" },
|
||||
{ 0x1bad, 0xf506, "Hori Real Arcade Pro.EX Premium VLX" },
|
||||
{ 0x1bad, 0xf900, "Harmonix Xbox 360 Controller" },
|
||||
{ 0x1bad, 0xf901, "Gamestop Xbox 360 Controller" },
|
||||
{ 0x1bad, 0xf903, "Tron Xbox 360 controller" },
|
||||
{ 0x1bad, 0xf904, "PDP Versus Fighting Pad" },
|
||||
{ 0x1bad, 0xf906, "MortalKombat FightStick" },
|
||||
{ 0x1bad, 0xfa01, "MadCatz GamePad" },
|
||||
{ 0x1bad, 0xfd00, "Razer Onza TE" },
|
||||
{ 0x1bad, 0xfd01, "Razer Onza" },
|
||||
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick" },
|
||||
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller" },
|
||||
{ 0x24c6, 0x5303, "Xbox Airflo wired controller" },
|
||||
{ 0x24c6, 0x530a, "Xbox 360 Pro EX Controller" },
|
||||
{ 0x24c6, 0x531a, "PowerA Pro Ex" },
|
||||
{ 0x24c6, 0x5397, "FUS1ON Tournament Controller" },
|
||||
{ 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo" },
|
||||
{ 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA" },
|
||||
{ 0x24c6, 0x5502, "Hori Fighting Stick VX Alt" },
|
||||
{ 0x24c6, 0x5503, "Hori Fighting Edge" },
|
||||
{ 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick" },
|
||||
{ 0x24c6, 0x550d, "Hori GEM Xbox controller" },
|
||||
{ 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360" },
|
||||
{ 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel" },
|
||||
{ 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller" },
|
||||
{ 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel" },
|
||||
{ 0x24c6, 0x5d04, "Razer Sabertooth" },
|
||||
{ 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360" },
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
Uint32 rumble_expiration;
|
||||
} SDL_DriverXbox360_Context;
|
||||
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXbox360_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, int interface_number, Uint16 usage_page, Uint16 usage)
|
||||
{
|
||||
#ifdef __MACOSX__
|
||||
return SDL_IsJoystickXbox360(vendor_id, product_id) || SDL_IsJoystickXboxOne(vendor_id, product_id);
|
||||
#else
|
||||
return SDL_IsJoystickXbox360(vendor_id, product_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverXbox360_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDL_arraysize(xbox360_devicenames); ++i) {
|
||||
const SDL_DriverXbox360_DeviceName *entry = &xbox360_devicenames[i];
|
||||
if (vendor_id == entry->vendor_id && product_id == entry->product_id) {
|
||||
return entry->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
|
||||
{
|
||||
const Uint8 led_packet[] = { 0x01, 0x03, (2 + slot) };
|
||||
|
||||
if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
|
||||
{
|
||||
SDL_DriverXbox360_Context *ctx;
|
||||
|
||||
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
*context = ctx;
|
||||
|
||||
/* Set the controller LED */
|
||||
SetSlotLED(dev, (joystick->instance_id % 4));
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
|
||||
#ifdef __MACOSX__
|
||||
/* On Mac OS X the 360Controller driver uses this short report,
|
||||
and we need to prefix it with a magic token so hidapi passes it through untouched
|
||||
*/
|
||||
Uint8 rumble_packet[] = { 'M', 'A', 'G', 'I', 'C', '0', 0x00, 0x04, 0x00, 0x00 };
|
||||
|
||||
rumble_packet[6+2] = (low_frequency_rumble >> 8);
|
||||
rumble_packet[6+3] = (high_frequency_rumble >> 8);
|
||||
#else
|
||||
Uint8 rumble_packet[] = { 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
rumble_packet[3] = (low_frequency_rumble >> 8);
|
||||
rumble_packet[4] = (high_frequency_rumble >> 8);
|
||||
#endif
|
||||
|
||||
if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||
return SDL_SetError("Couldn't send rumble packet");
|
||||
}
|
||||
|
||||
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
|
||||
ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
|
||||
} else {
|
||||
ctx->rumble_expiration = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXbox360_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
#ifdef __MACOSX__
|
||||
const SDL_bool invert_y_axes = SDL_FALSE;
|
||||
#else
|
||||
const SDL_bool invert_y_axes = SDL_TRUE;
|
||||
#endif
|
||||
|
||||
if (ctx->last_state[2] != data[2]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[2] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[2] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (ctx->last_state[3] != data[3]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[3] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[3] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[3] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[3] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[3] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[3] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[3] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
axis = ((int)data[4] * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
|
||||
axis = ((int)data[5] * 257) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
|
||||
axis = *(Sint16*)(&data[6]);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
|
||||
axis = *(Sint16*)(&data[8]);
|
||||
if (invert_y_axes) {
|
||||
axis = ~axis;
|
||||
}
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
|
||||
axis = *(Sint16*)(&data[10]);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
|
||||
axis = *(Sint16*)(&data[12]);
|
||||
if (invert_y_axes) {
|
||||
axis = ~axis;
|
||||
}
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
|
||||
while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
|
||||
switch (data[0]) {
|
||||
case 0x00:
|
||||
HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
SDL_Log("Unknown Xbox 360 packet: 0x%.2x\n", data[0]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->rumble_expiration) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
|
||||
HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_free(context);
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
|
||||
{
|
||||
SDL_HINT_JOYSTICK_HIDAPI_XBOX360,
|
||||
SDL_TRUE,
|
||||
HIDAPI_DriverXbox360_IsSupportedDevice,
|
||||
HIDAPI_DriverXbox360_GetDeviceName,
|
||||
HIDAPI_DriverXbox360_Init,
|
||||
HIDAPI_DriverXbox360_Rumble,
|
||||
HIDAPI_DriverXbox360_Update,
|
||||
HIDAPI_DriverXbox360_Quit
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 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_log.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"
|
||||
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
|
||||
#define USB_PACKET_LENGTH 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint16 vendor_id;
|
||||
Uint16 product_id;
|
||||
const char *name;
|
||||
} SDL_DriverXboxOne_DeviceName;
|
||||
|
||||
static const SDL_DriverXboxOne_DeviceName xboxone_devicenames[] = {
|
||||
{ 0x045e, 0x02d1, "Microsoft X-Box One pad" },
|
||||
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)" },
|
||||
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad" },
|
||||
{ 0x045e, 0x02ea, "Microsoft X-Box One S pad" },
|
||||
{ 0x045e, 0x02ff, "Microsoft X-Box One pad" },
|
||||
{ 0x0738, 0x4a01, "Mad Catz FightStick TE 2" },
|
||||
{ 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller" },
|
||||
{ 0x0e6f, 0x013a, "PDP Xbox One Controller" },
|
||||
{ 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One" },
|
||||
{ 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller" },
|
||||
{ 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick" },
|
||||
{ 0x0e6f, 0x0161, "PDP Xbox One Controller" },
|
||||
{ 0x0e6f, 0x0162, "PDP Xbox One Controller" },
|
||||
{ 0x0e6f, 0x0163, "PDP Xbox One Controller" },
|
||||
{ 0x0e6f, 0x0164, "PDP Battlefield One" },
|
||||
{ 0x0e6f, 0x0165, "PDP Titanfall 2" },
|
||||
{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015" },
|
||||
{ 0x0e6f, 0x02ab, "PDP Controller for Xbox One" },
|
||||
{ 0x0e6f, 0x02a4, "PDP Wired Controller for Xbox One - Stealth Series" },
|
||||
{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016" },
|
||||
{ 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One" },
|
||||
{ 0x0f0d, 0x0067, "HORIPAD ONE" },
|
||||
{ 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One" },
|
||||
{ 0x1532, 0x0a00, "Razer Atrox Arcade Stick" },
|
||||
{ 0x1532, 0x0a03, "Razer Wildcat" },
|
||||
{ 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller" },
|
||||
{ 0x24c6, 0x542a, "Xbox ONE spectra" },
|
||||
{ 0x24c6, 0x543a, "PowerA Xbox One wired controller" },
|
||||
{ 0x24c6, 0x551a, "PowerA FUSION Pro Controller" },
|
||||
{ 0x24c6, 0x561a, "PowerA FUSION Controller" },
|
||||
};
|
||||
|
||||
/*
|
||||
* This packet is required for all Xbox One pads with 2015
|
||||
* or later firmware installed (or present from the factory).
|
||||
*/
|
||||
static const Uint8 xboxone_fw2015_init[] = {
|
||||
0x05, 0x20, 0x00, 0x01, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* This packet is required for the Titanfall 2 Xbox One pads
|
||||
* (0x0e6f:0x0165) to finish initialization and for Hori pads
|
||||
* (0x0f0d:0x0067) to make the analog sticks work.
|
||||
*/
|
||||
static const Uint8 xboxone_hori_init[] = {
|
||||
0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
|
||||
0x00, 0x00, 0x00, 0x80, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* This packet is required for some of the PDP pads to start
|
||||
* sending input reports. These pads include: (0x0e6f:0x02ab),
|
||||
* (0x0e6f:0x02a4).
|
||||
*/
|
||||
static const Uint8 xboxone_pdp_init1[] = {
|
||||
0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
|
||||
};
|
||||
|
||||
/*
|
||||
* This packet is required for some of the PDP pads to start
|
||||
* sending input reports. These pads include: (0x0e6f:0x02ab),
|
||||
* (0x0e6f:0x02a4).
|
||||
*/
|
||||
static const Uint8 xboxone_pdp_init2[] = {
|
||||
0x06, 0x20, 0x00, 0x02, 0x01, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* A specific rumble packet is required for some PowerA pads to start
|
||||
* sending input reports. One of those pads is (0x24c6:0x543a).
|
||||
*/
|
||||
static const Uint8 xboxone_rumblebegin_init[] = {
|
||||
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
|
||||
0x1D, 0x1D, 0xFF, 0x00, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* A rumble packet with zero FF intensity will immediately
|
||||
* terminate the rumbling required to init PowerA pads.
|
||||
* This should happen fast enough that the motors don't
|
||||
* spin up to enough speed to actually vibrate the gamepad.
|
||||
*/
|
||||
static const Uint8 xboxone_rumbleend_init[] = {
|
||||
0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* This specifies the selection of init packets that a gamepad
|
||||
* will be sent on init *and* the order in which they will be
|
||||
* sent. The correct sequence number will be added when the
|
||||
* packet is going to be sent.
|
||||
*/
|
||||
typedef struct {
|
||||
Uint16 vendor_id;
|
||||
Uint16 product_id;
|
||||
const Uint8 *data;
|
||||
int size;
|
||||
} SDL_DriverXboxOne_InitPacket;
|
||||
|
||||
static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
|
||||
{ 0x0e6f, 0x0165, xboxone_hori_init, sizeof(xboxone_hori_init) },
|
||||
{ 0x0f0d, 0x0067, xboxone_hori_init, sizeof(xboxone_hori_init) },
|
||||
{ 0x0000, 0x0000, xboxone_fw2015_init, sizeof(xboxone_fw2015_init) },
|
||||
{ 0x0e6f, 0x0246, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
|
||||
{ 0x0e6f, 0x0246, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
|
||||
{ 0x0e6f, 0x02ab, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
|
||||
{ 0x0e6f, 0x02ab, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
|
||||
{ 0x0e6f, 0x02a4, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
|
||||
{ 0x0e6f, 0x02a4, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
|
||||
{ 0x24c6, 0x541a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
|
||||
{ 0x24c6, 0x542a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
|
||||
{ 0x24c6, 0x543a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
|
||||
{ 0x24c6, 0x541a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
|
||||
{ 0x24c6, 0x542a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
|
||||
{ 0x24c6, 0x543a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Uint8 sequence;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
Uint32 rumble_expiration;
|
||||
} SDL_DriverXboxOne_Context;
|
||||
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, int interface_number, Uint16 usage_page, Uint16 usage)
|
||||
{
|
||||
return SDL_IsJoystickXboxOne(vendor_id, product_id);
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SDL_arraysize(xboxone_devicenames); ++i) {
|
||||
const SDL_DriverXboxOne_DeviceName *entry = &xboxone_devicenames[i];
|
||||
if (vendor_id == entry->vendor_id && product_id == entry->product_id) {
|
||||
return entry->name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx;
|
||||
int i;
|
||||
Uint8 init_packet[USB_PACKET_LENGTH];
|
||||
|
||||
ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
SDL_OutOfMemory();
|
||||
return SDL_FALSE;
|
||||
}
|
||||
*context = ctx;
|
||||
|
||||
/* Send the controller init data */
|
||||
for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
|
||||
const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
|
||||
if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
|
||||
SDL_memcpy(init_packet, packet->data, packet->size);
|
||||
init_packet[2] = ctx->sequence++;
|
||||
if (hid_write(dev, init_packet, packet->size) != packet->size) {
|
||||
SDL_SetError("Couldn't write Xbox One initialization packet");
|
||||
SDL_free(ctx);
|
||||
return SDL_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
|
||||
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
|
||||
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
|
||||
Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
|
||||
|
||||
/* The Rock Candy Xbox One Controller limits the range of
|
||||
low frequency rumble strength in the range of [0 - 0x99]
|
||||
high frequency rumble strength in the range of [0 - 0x82]
|
||||
|
||||
I think the valid range of rumble at the firmware level is [0 - 0x7F]
|
||||
*/
|
||||
rumble_packet[2] = ctx->sequence++;
|
||||
rumble_packet[8] = (low_frequency_rumble >> 9);
|
||||
rumble_packet[9] = (high_frequency_rumble >> 9);
|
||||
|
||||
if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||
return SDL_SetError("Couldn't send rumble packet");
|
||||
}
|
||||
|
||||
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
|
||||
ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
|
||||
} else {
|
||||
ctx->rumble_expiration = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
|
||||
if (ctx->last_state[4] != data[4]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[4] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[4] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[4] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[4] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[4] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[4] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
if (ctx->last_state[5] != data[5]) {
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data[5] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data[5] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data[5] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data[5] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[5] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[5] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[5] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[5] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
|
||||
axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
|
||||
axis = *(Sint16*)(&data[10]);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
|
||||
axis = *(Sint16*)(&data[12]);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
|
||||
axis = *(Sint16*)(&data[14]);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
|
||||
axis = *(Sint16*)(&data[16]);
|
||||
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
if (data[1] == 0x30) {
|
||||
/* The Xbox One S controller needs acks for mode reports */
|
||||
const Uint8 seqnum = data[2];
|
||||
const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
hid_write(dev, ack, sizeof(ack));
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[4] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size;
|
||||
|
||||
while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
|
||||
switch (data[0]) {
|
||||
case 0x20:
|
||||
HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
|
||||
break;
|
||||
case 0x07:
|
||||
HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->rumble_expiration) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
|
||||
HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
|
||||
{
|
||||
SDL_free(context);
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
|
||||
{
|
||||
SDL_HINT_JOYSTICK_HIDAPI_XBOXONE,
|
||||
SDL_TRUE,
|
||||
HIDAPI_DriverXboxOne_IsSupportedDevice,
|
||||
HIDAPI_DriverXboxOne_GetDeviceName,
|
||||
HIDAPI_DriverXboxOne_Init,
|
||||
HIDAPI_DriverXboxOne_Rumble,
|
||||
HIDAPI_DriverXboxOne_Update,
|
||||
HIDAPI_DriverXboxOne_Quit
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 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_endian.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_log.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_joystick.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
|
||||
|
||||
struct joystick_hwdata
|
||||
{
|
||||
SDL_HIDAPI_DeviceDriver *driver;
|
||||
void *context;
|
||||
|
||||
hid_device *dev;
|
||||
};
|
||||
|
||||
typedef struct _SDL_HIDAPI_Device
|
||||
{
|
||||
SDL_JoystickID instance_id;
|
||||
char *name;
|
||||
char *path;
|
||||
Uint16 vendor_id;
|
||||
Uint16 product_id;
|
||||
SDL_JoystickGUID guid;
|
||||
int interface_number; /* Available on Windows and Linux */
|
||||
Uint16 usage_page; /* Available on Windows and Mac OS X */
|
||||
Uint16 usage; /* Available on Windows and Mac OS X */
|
||||
SDL_HIDAPI_DeviceDriver *driver;
|
||||
|
||||
/* Used during scanning for device changes */
|
||||
SDL_bool seen;
|
||||
|
||||
struct _SDL_HIDAPI_Device *next;
|
||||
} SDL_HIDAPI_Device;
|
||||
|
||||
static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_PS4
|
||||
&SDL_HIDAPI_DriverPS4,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_STEAM
|
||||
&SDL_HIDAPI_DriverSteam,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
&SDL_HIDAPI_DriverSwitch,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOX360
|
||||
&SDL_HIDAPI_DriverXbox360,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
&SDL_HIDAPI_DriverXboxOne,
|
||||
#endif
|
||||
};
|
||||
static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
|
||||
static int SDL_HIDAPI_numjoysticks = 0;
|
||||
static Uint32 SDL_HIDAPI_last_detect = 0;
|
||||
|
||||
static SDL_HIDAPI_DeviceDriver *
|
||||
HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (SDL_ShouldIgnoreJoystick(device->name, device->guid)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
|
||||
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
|
||||
if (driver->enabled && driver->IsSupportedDevice(device->vendor_id, device->product_id, device->interface_number, device->usage_page, device->usage)) {
|
||||
return driver;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_HIDAPI_Device *
|
||||
HIDAPI_GetJoystickByIndex(int device_index)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
if (device->driver) {
|
||||
if (device_index == 0) {
|
||||
break;
|
||||
}
|
||||
--device_index;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
static SDL_HIDAPI_Device *
|
||||
HIDAPI_GetJoystickByInfo(const char *path, Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
if (device->vendor_id == vendor_id && device->product_id == product_id &&
|
||||
SDL_strcmp(device->path, path) == 0) {
|
||||
break;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
static void SDLCALL
|
||||
SDL_HIDAPIDriverHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
|
||||
{
|
||||
int i;
|
||||
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
|
||||
SDL_bool enabled = (!hint || !*hint || ((*hint != '0') && (SDL_strcasecmp(hint, "false") != 0)));
|
||||
|
||||
if (SDL_strcmp(name, SDL_HINT_JOYSTICK_HIDAPI) == 0) {
|
||||
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
|
||||
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
|
||||
driver->enabled = SDL_GetHintBoolean(driver->hint, enabled);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
|
||||
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
|
||||
if (SDL_strcmp(name, driver->hint) == 0) {
|
||||
driver->enabled = enabled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update device list if driver availability changes */
|
||||
while (device) {
|
||||
if (device->driver) {
|
||||
if (!device->driver->enabled) {
|
||||
device->driver = NULL;
|
||||
|
||||
--SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickRemoved(device->instance_id);
|
||||
}
|
||||
} else {
|
||||
device->driver = HIDAPI_GetDeviceDriver(device);
|
||||
if (device->driver) {
|
||||
device->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(device->instance_id);
|
||||
}
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDAPI_JoystickDetect(void);
|
||||
|
||||
static int
|
||||
HIDAPI_JoystickInit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (hid_init() < 0) {
|
||||
SDL_SetError("Couldn't initialize hidapi");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
|
||||
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
|
||||
SDL_AddHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL);
|
||||
}
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI,
|
||||
SDL_HIDAPIDriverHintChanged, NULL);
|
||||
SDL_HIDAPI_last_detect = 0;
|
||||
HIDAPI_JoystickDetect();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_JoystickGetCount(void)
|
||||
{
|
||||
return SDL_HIDAPI_numjoysticks;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_AddDevice(struct hid_device_info *info)
|
||||
{
|
||||
SDL_HIDAPI_Device *device;
|
||||
SDL_HIDAPI_Device *curr, *last = NULL;
|
||||
|
||||
for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
|
||||
continue;
|
||||
}
|
||||
|
||||
device = (SDL_HIDAPI_Device *)SDL_calloc(1, sizeof(*device));
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
device->instance_id = -1;
|
||||
device->seen = SDL_TRUE;
|
||||
device->vendor_id = info->vendor_id;
|
||||
device->product_id = info->product_id;
|
||||
device->interface_number = info->interface_number;
|
||||
device->usage_page = info->usage_page;
|
||||
device->usage = info->usage;
|
||||
{
|
||||
/* FIXME: Is there any way to tell whether this is a Bluetooth device? */
|
||||
const Uint16 vendor = device->vendor_id;
|
||||
const Uint16 product = device->product_id;
|
||||
const Uint16 version = 0;
|
||||
Uint16 *guid16 = (Uint16 *)device->guid.data;
|
||||
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(vendor);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(product);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(version);
|
||||
*guid16++ = 0;
|
||||
|
||||
/* Note that this is a HIDAPI device for special handling elsewhere */
|
||||
device->guid.data[14] = 'h';
|
||||
device->guid.data[15] = 0;
|
||||
}
|
||||
device->driver = HIDAPI_GetDeviceDriver(device);
|
||||
|
||||
if (device->driver) {
|
||||
const char *name = device->driver->GetDeviceName(device->vendor_id, device->product_id);
|
||||
if (name) {
|
||||
device->name = SDL_strdup(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!device->name && info->manufacturer_string && info->product_string) {
|
||||
char *manufacturer_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t));
|
||||
char *product_string = SDL_iconv_string("UTF-8", "WCHAR_T", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
|
||||
if (!manufacturer_string && !product_string) {
|
||||
if (sizeof(wchar_t) == sizeof(Uint16)) {
|
||||
manufacturer_string = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t));
|
||||
product_string = SDL_iconv_string("UTF-8", "UCS-2-INTERNAL", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
|
||||
} else if (sizeof(wchar_t) == sizeof(Uint32)) {
|
||||
manufacturer_string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char*)info->manufacturer_string, (SDL_wcslen(info->manufacturer_string)+1)*sizeof(wchar_t));
|
||||
product_string = SDL_iconv_string("UTF-8", "UCS-4-INTERNAL", (char*)info->product_string, (SDL_wcslen(info->product_string)+1)*sizeof(wchar_t));
|
||||
}
|
||||
}
|
||||
if (manufacturer_string && product_string) {
|
||||
size_t name_size = (SDL_strlen(manufacturer_string) + 1 + SDL_strlen(product_string) + 1);
|
||||
device->name = (char *)SDL_malloc(name_size);
|
||||
if (device->name) {
|
||||
SDL_snprintf(device->name, name_size, "%s %s", manufacturer_string, product_string);
|
||||
}
|
||||
}
|
||||
if (manufacturer_string) {
|
||||
SDL_free(manufacturer_string);
|
||||
}
|
||||
if (product_string) {
|
||||
SDL_free(product_string);
|
||||
}
|
||||
}
|
||||
if (!device->name) {
|
||||
size_t name_size = (6 + 1 + 6 + 1);
|
||||
device->name = (char *)SDL_malloc(name_size);
|
||||
if (!device->name) {
|
||||
SDL_free(device);
|
||||
return;
|
||||
}
|
||||
SDL_snprintf(device->name, name_size, "0x%.4x/0x%.4x", info->vendor_id, info->product_id);
|
||||
}
|
||||
|
||||
device->path = SDL_strdup(info->path);
|
||||
if (!device->path) {
|
||||
SDL_free(device->name);
|
||||
SDL_free(device);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HIDAPI
|
||||
SDL_Log("Adding HIDAPI device '%s' interface %d, usage page 0x%.4x, usage 0x%.4x\n", device->name, device->interface_number, device->usage_page, device->usage);
|
||||
#endif
|
||||
|
||||
/* Add it to the list */
|
||||
if (last) {
|
||||
last->next = device;
|
||||
} else {
|
||||
SDL_HIDAPI_devices = device;
|
||||
}
|
||||
|
||||
if (device->driver) {
|
||||
/* It's a joystick! */
|
||||
device->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
++SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(device->instance_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
HIDAPI_DelDevice(SDL_HIDAPI_Device *device, SDL_bool send_event)
|
||||
{
|
||||
SDL_HIDAPI_Device *curr, *last;
|
||||
for (curr = SDL_HIDAPI_devices, last = NULL; curr; last = curr, curr = curr->next) {
|
||||
if (curr == device) {
|
||||
if (last) {
|
||||
last->next = curr->next;
|
||||
} else {
|
||||
SDL_HIDAPI_devices = curr->next;
|
||||
}
|
||||
|
||||
if (device->driver && send_event) {
|
||||
/* Need to decrement the joystick count before we post the event */
|
||||
--SDL_HIDAPI_numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickRemoved(device->instance_id);
|
||||
}
|
||||
|
||||
SDL_free(device->name);
|
||||
SDL_free(device->path);
|
||||
SDL_free(device);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_UpdateDeviceList(void)
|
||||
{
|
||||
SDL_HIDAPI_Device *device;
|
||||
struct hid_device_info *devs, *info;
|
||||
|
||||
/* Prepare the existing device list */
|
||||
device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
device->seen = SDL_FALSE;
|
||||
device = device->next;
|
||||
}
|
||||
|
||||
/* Enumerate the devices */
|
||||
devs = hid_enumerate(0, 0);
|
||||
if (devs) {
|
||||
for (info = devs; info; info = info->next) {
|
||||
device = HIDAPI_GetJoystickByInfo(info->path, info->vendor_id, info->product_id);
|
||||
if (device) {
|
||||
device->seen = SDL_TRUE;
|
||||
} else {
|
||||
HIDAPI_AddDevice(info);
|
||||
}
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
}
|
||||
|
||||
/* Remove any devices that weren't seen */
|
||||
device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
SDL_HIDAPI_Device *next = device->next;
|
||||
|
||||
if (!device->seen) {
|
||||
HIDAPI_DelDevice(device, SDL_TRUE);
|
||||
}
|
||||
device = next;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
SDL_HIDAPI_Device *device;
|
||||
|
||||
/* Make sure the device list is completely up to date when we check for device presence */
|
||||
HIDAPI_UpdateDeviceList();
|
||||
|
||||
device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
if (device->vendor_id == vendor_id && device->product_id == product_id && device->driver) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_JoystickDetect(void)
|
||||
{
|
||||
const Uint32 SDL_HIDAPI_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (!SDL_HIDAPI_last_detect || SDL_TICKS_PASSED(now, SDL_HIDAPI_last_detect + SDL_HIDAPI_DETECT_INTERVAL_MS)) {
|
||||
HIDAPI_UpdateDeviceList();
|
||||
SDL_HIDAPI_last_detect = now;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
HIDAPI_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
return HIDAPI_GetJoystickByIndex(device_index)->name;
|
||||
}
|
||||
|
||||
static SDL_JoystickGUID
|
||||
HIDAPI_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
return HIDAPI_GetJoystickByIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
static SDL_JoystickID
|
||||
HIDAPI_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return HIDAPI_GetJoystickByIndex(device_index)->instance_id;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = HIDAPI_GetJoystickByIndex(device_index);
|
||||
struct joystick_hwdata *hwdata;
|
||||
|
||||
hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
|
||||
if (!hwdata) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
hwdata->driver = device->driver;
|
||||
hwdata->dev = hid_open_path(device->path, 0);
|
||||
if (!hwdata->dev) {
|
||||
SDL_free(hwdata);
|
||||
return SDL_SetError("Couldn't open HID device %s", device->path);
|
||||
}
|
||||
|
||||
if (!device->driver->Init(joystick, hwdata->dev, device->vendor_id, device->product_id, &hwdata->context)) {
|
||||
hid_close(hwdata->dev);
|
||||
SDL_free(hwdata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
joystick->hwdata = hwdata;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
HIDAPI_JoystickIsAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
|
||||
while (device) {
|
||||
if (device->driver) {
|
||||
if (joystick->instance_id == device->instance_id) {
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
struct joystick_hwdata *hwdata = joystick->hwdata;
|
||||
SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
|
||||
return driver->Rumble(joystick, hwdata->dev, hwdata->context, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
struct joystick_hwdata *hwdata = joystick->hwdata;
|
||||
SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
|
||||
driver->Update(joystick, hwdata->dev, hwdata->context);
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
struct joystick_hwdata *hwdata = joystick->hwdata;
|
||||
SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
|
||||
driver->Quit(joystick, hwdata->dev, hwdata->context);
|
||||
|
||||
hid_close(hwdata->dev);
|
||||
SDL_free(hwdata);
|
||||
joystick->hwdata = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
HIDAPI_JoystickQuit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
while (SDL_HIDAPI_devices) {
|
||||
HIDAPI_DelDevice(SDL_HIDAPI_devices, SDL_FALSE);
|
||||
}
|
||||
for (i = 0; i < SDL_arraysize(SDL_HIDAPI_drivers); ++i) {
|
||||
SDL_HIDAPI_DeviceDriver *driver = SDL_HIDAPI_drivers[i];
|
||||
SDL_DelHintCallback(driver->hint, SDL_HIDAPIDriverHintChanged, NULL);
|
||||
}
|
||||
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI,
|
||||
SDL_HIDAPIDriverHintChanged, NULL);
|
||||
SDL_HIDAPI_numjoysticks = 0;
|
||||
|
||||
hid_exit();
|
||||
}
|
||||
|
||||
SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
|
||||
{
|
||||
HIDAPI_JoystickInit,
|
||||
HIDAPI_JoystickGetCount,
|
||||
HIDAPI_JoystickDetect,
|
||||
HIDAPI_JoystickGetDeviceName,
|
||||
HIDAPI_JoystickGetDeviceGUID,
|
||||
HIDAPI_JoystickGetDeviceInstanceID,
|
||||
HIDAPI_JoystickOpen,
|
||||
HIDAPI_JoystickIsAttached,
|
||||
HIDAPI_JoystickRumble,
|
||||
HIDAPI_JoystickUpdate,
|
||||
HIDAPI_JoystickClose,
|
||||
HIDAPI_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 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"
|
||||
|
||||
#ifndef SDL_JOYSTICK_HIDAPI_H
|
||||
#define SDL_JOYSTICK_HIDAPI_H
|
||||
|
||||
#include "../../hidapi/hidapi/hidapi.h"
|
||||
|
||||
/* This is the full set of HIDAPI drivers available */
|
||||
#define SDL_JOYSTICK_HIDAPI_PS4
|
||||
#define SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
#define SDL_JOYSTICK_HIDAPI_XBOX360
|
||||
#define SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
/* On Windows, Xbox controllers are handled by the XInput driver */
|
||||
#undef SDL_JOYSTICK_HIDAPI_XBOX360
|
||||
#undef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
#endif
|
||||
|
||||
#ifdef __MACOSX__
|
||||
/* On Mac OS X, Xbox One controllers are handled by the Xbox 360 driver */
|
||||
#undef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
#endif
|
||||
|
||||
typedef struct _SDL_HIDAPI_DeviceDriver
|
||||
{
|
||||
const char *hint;
|
||||
SDL_bool enabled;
|
||||
SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, int interface_number, Uint16 usage_page, Uint16 usage);
|
||||
const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id);
|
||||
SDL_bool (*Init)(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context);
|
||||
int (*Rumble)(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
void (*Update)(SDL_Joystick *joystick, hid_device *dev, void *context);
|
||||
void (*Quit)(SDL_Joystick *joystick, hid_device *dev, void *context);
|
||||
|
||||
} SDL_HIDAPI_DeviceDriver;
|
||||
|
||||
/* HIDAPI device support */
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
|
||||
|
||||
/* Return true if a HID device is present and supported as a joystick */
|
||||
extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
#endif /* SDL_JOYSTICK_HIDAPI_H */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
|
@ -33,7 +33,6 @@
|
|||
#include "SDL_stdinc.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
#include "../steam/SDL_steamcontroller.h"
|
||||
|
||||
|
||||
#if !SDL_EVENTS_DISABLED
|
||||
|
@ -59,7 +58,6 @@ static CMMotionManager *motionManager = nil;
|
|||
static SDL_JoystickDeviceItem *deviceList = NULL;
|
||||
|
||||
static int numjoysticks = 0;
|
||||
static SDL_JoystickID instancecounter = 0;
|
||||
int SDL_AppleTVRemoteOpenedAsJoystick = 0;
|
||||
|
||||
static SDL_JoystickDeviceItem *
|
||||
|
@ -80,10 +78,9 @@ GetDeviceForIndex(int device_index)
|
|||
}
|
||||
|
||||
static void
|
||||
SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
|
||||
IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller)
|
||||
{
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
const Uint16 BUS_BLUETOOTH = 0x05;
|
||||
const Uint16 VENDOR_APPLE = 0x05AC;
|
||||
Uint16 *guid16 = (Uint16 *)device->guid.data;
|
||||
Uint16 vendor = 0;
|
||||
|
@ -136,7 +133,7 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr
|
|||
|
||||
/* We only need 16 bits for each of these; space them out to fill 128. */
|
||||
/* Byteswap so devices get same GUID on little/big endian platforms. */
|
||||
*guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(vendor);
|
||||
*guid16++ = 0;
|
||||
|
@ -157,7 +154,7 @@ SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *contr
|
|||
}
|
||||
|
||||
static void
|
||||
SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
||||
IOS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = deviceList;
|
||||
|
||||
|
@ -183,7 +180,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
|||
}
|
||||
|
||||
device->accelerometer = accelerometer;
|
||||
device->instance_id = instancecounter++;
|
||||
device->instance_id = SDL_GetNextJoystickInstanceID();
|
||||
|
||||
if (accelerometer) {
|
||||
#if TARGET_OS_TV
|
||||
|
@ -199,7 +196,7 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
|||
SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name)));
|
||||
#endif /* TARGET_OS_TV */
|
||||
} else if (controller) {
|
||||
SDL_SYS_AddMFIJoystickDevice(device, controller);
|
||||
IOS_AddMFIJoystickDevice(device, controller);
|
||||
}
|
||||
|
||||
if (deviceList == NULL) {
|
||||
|
@ -214,11 +211,11 @@ SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer)
|
|||
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
SDL_PrivateJoystickAdded(device->instance_id);
|
||||
}
|
||||
|
||||
static SDL_JoystickDeviceItem *
|
||||
SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
|
||||
IOS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device)
|
||||
{
|
||||
SDL_JoystickDeviceItem *prev = NULL;
|
||||
SDL_JoystickDeviceItem *next = NULL;
|
||||
|
@ -287,78 +284,27 @@ SDL_AppleTVRemoteRotationHintChanged(void *udata, const char *name, const char *
|
|||
}
|
||||
#endif /* TARGET_OS_TV */
|
||||
|
||||
static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = (SDL_JoystickDeviceItem *)SDL_calloc(1, sizeof(SDL_JoystickDeviceItem));
|
||||
if (device == NULL) {
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
*device_instance = device->instance_id = instancecounter++;
|
||||
device->name = SDL_strdup(name);
|
||||
device->guid = guid;
|
||||
SDL_GetSteamControllerInputs(&device->nbuttons,
|
||||
&device->naxes,
|
||||
&device->nhats);
|
||||
device->m_bSteamController = SDL_TRUE;
|
||||
|
||||
if (deviceList == NULL) {
|
||||
deviceList = device;
|
||||
} else {
|
||||
SDL_JoystickDeviceItem *lastdevice = deviceList;
|
||||
while (lastdevice->next != NULL) {
|
||||
lastdevice = lastdevice->next;
|
||||
}
|
||||
lastdevice->next = device;
|
||||
}
|
||||
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static void SteamControllerDisconnectedCallback(int device_instance)
|
||||
{
|
||||
SDL_JoystickDeviceItem *item;
|
||||
|
||||
for (item = deviceList; item; item = item->next) {
|
||||
if (item->instance_id == device_instance) {
|
||||
SDL_SYS_RemoveJoystickDevice(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
static int
|
||||
IOS_JoystickInit(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
|
||||
SDL_InitSteamControllers(SteamControllerConnectedCallback,
|
||||
SteamControllerDisconnectedCallback);
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
|
||||
/* Default behavior, accelerometer as joystick */
|
||||
SDL_SYS_AddJoystickDevice(nil, SDL_TRUE);
|
||||
IOS_AddJoystickDevice(nil, SDL_TRUE);
|
||||
}
|
||||
#endif /* !TARGET_OS_TV */
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
/* GameController.framework was added in iOS 7. */
|
||||
if (![GCController class]) {
|
||||
return numjoysticks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (GCController *controller in [GCController controllers]) {
|
||||
SDL_SYS_AddJoystickDevice(controller, SDL_FALSE);
|
||||
IOS_AddJoystickDevice(controller, SDL_FALSE);
|
||||
}
|
||||
|
||||
#if TARGET_OS_TV
|
||||
|
@ -371,7 +317,7 @@ SDL_SYS_JoystickInit(void)
|
|||
queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
GCController *controller = note.object;
|
||||
SDL_SYS_AddJoystickDevice(controller, SDL_FALSE);
|
||||
IOS_AddJoystickDevice(controller, SDL_FALSE);
|
||||
}];
|
||||
|
||||
disconnectObserver = [center addObserverForName:GCControllerDidDisconnectNotification
|
||||
|
@ -382,7 +328,7 @@ SDL_SYS_JoystickInit(void)
|
|||
SDL_JoystickDeviceItem *device = deviceList;
|
||||
while (device != NULL) {
|
||||
if (device->controller == controller) {
|
||||
SDL_SYS_RemoveJoystickDevice(device);
|
||||
IOS_RemoveJoystickDevice(device);
|
||||
break;
|
||||
}
|
||||
device = device->next;
|
||||
|
@ -391,43 +337,49 @@ SDL_SYS_JoystickInit(void)
|
|||
#endif /* SDL_JOYSTICK_MFI */
|
||||
}
|
||||
|
||||
return numjoysticks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
IOS_JoystickGetCount(void)
|
||||
{
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
IOS_JoystickDetect(void)
|
||||
{
|
||||
SDL_UpdateSteamControllers();
|
||||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
static const char *
|
||||
IOS_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
|
||||
return device ? device->name : "Unknown";
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickGUID
|
||||
IOS_JoystickGetDeviceGUID( int device_index )
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
|
||||
return device ? device->instance_id : 0;
|
||||
SDL_JoystickGUID guid;
|
||||
if (device) {
|
||||
guid = device->guid;
|
||||
} else {
|
||||
SDL_zero(guid);
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
|
||||
/* Function to open a joystick for use.
|
||||
The joystick to open is specified by the device index.
|
||||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static SDL_JoystickID
|
||||
IOS_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
|
||||
return device ? device->instance_id : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
IOS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
|
||||
if (device == NULL) {
|
||||
|
@ -473,15 +425,14 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Function to determine if this joystick is attached to the system right now */
|
||||
SDL_bool
|
||||
SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
static SDL_bool
|
||||
IOS_JoystickIsAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
return joystick->hwdata != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
|
||||
IOS_AccelerometerUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
#if !TARGET_OS_TV
|
||||
const float maxgforce = SDL_IPHONE_MAX_GFORCE;
|
||||
|
@ -526,7 +477,7 @@ SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick)
|
|||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
static Uint8
|
||||
SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
|
||||
IOS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
|
||||
{
|
||||
Uint8 hat = 0;
|
||||
|
||||
|
@ -551,7 +502,7 @@ SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad)
|
|||
#endif
|
||||
|
||||
static void
|
||||
SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
||||
IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
#if SDL_JOYSTICK_MFI
|
||||
@autoreleasepool {
|
||||
|
@ -581,7 +532,7 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
|||
gamepad.rightShoulder.isPressed,
|
||||
};
|
||||
|
||||
hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
|
||||
hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
|
||||
|
||||
for (i = 0; i < SDL_arraysize(axes); i++) {
|
||||
/* The triggers (axes 2 and 5) are resting at -32768 but SDL
|
||||
|
@ -608,7 +559,7 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
|||
gamepad.rightShoulder.isPressed,
|
||||
};
|
||||
|
||||
hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad);
|
||||
hatstate = IOS_MFIJoystickHatStateForDPad(gamepad.dpad);
|
||||
|
||||
for (i = 0; i < SDL_arraysize(buttons); i++) {
|
||||
updateplayerindex |= (joystick->buttons[i] != buttons[i]);
|
||||
|
@ -678,13 +629,14 @@ SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick)
|
|||
#endif /* SDL_JOYSTICK_MFI */
|
||||
}
|
||||
|
||||
/* Function to update the state of a joystick - called as a device poll.
|
||||
* This function shouldn't update the joystick structure directly,
|
||||
* but instead should call SDL_PrivateJoystick*() to deliver events
|
||||
* and update joystick device state.
|
||||
*/
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static int
|
||||
IOS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void
|
||||
IOS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = joystick->hwdata;
|
||||
|
||||
|
@ -692,21 +644,15 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
return;
|
||||
}
|
||||
|
||||
if (device->m_bSteamController) {
|
||||
SDL_UpdateSteamController(joystick);
|
||||
return;
|
||||
}
|
||||
|
||||
if (device->accelerometer) {
|
||||
SDL_SYS_AccelerometerUpdate(joystick);
|
||||
IOS_AccelerometerUpdate(joystick);
|
||||
} else if (device->controller) {
|
||||
SDL_SYS_MFIJoystickUpdate(joystick);
|
||||
IOS_MFIJoystickUpdate(joystick);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
IOS_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = joystick->hwdata;
|
||||
|
||||
|
@ -734,9 +680,8 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
|||
}
|
||||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
IOS_JoystickQuit(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
|
@ -759,7 +704,7 @@ SDL_SYS_JoystickQuit(void)
|
|||
#endif /* SDL_JOYSTICK_MFI */
|
||||
|
||||
while (deviceList != NULL) {
|
||||
SDL_SYS_RemoveJoystickDevice(deviceList);
|
||||
IOS_RemoveJoystickDevice(deviceList);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
|
@ -767,34 +712,23 @@ SDL_SYS_JoystickQuit(void)
|
|||
#endif /* !TARGET_OS_TV */
|
||||
}
|
||||
|
||||
SDL_QuitSteamControllers();
|
||||
|
||||
numjoysticks = 0;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID
|
||||
SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
SDL_JoystickDriver SDL_IOS_JoystickDriver =
|
||||
{
|
||||
SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index);
|
||||
SDL_JoystickGUID guid;
|
||||
if (device) {
|
||||
guid = device->guid;
|
||||
} else {
|
||||
SDL_zero(guid);
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID
|
||||
SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
SDL_JoystickGUID guid;
|
||||
if (joystick->hwdata) {
|
||||
guid = joystick->hwdata->guid;
|
||||
} else {
|
||||
SDL_zero(guid);
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
IOS_JoystickInit,
|
||||
IOS_JoystickGetCount,
|
||||
IOS_JoystickDetect,
|
||||
IOS_JoystickGetDeviceName,
|
||||
IOS_JoystickGetDeviceGUID,
|
||||
IOS_JoystickGetDeviceInstanceID,
|
||||
IOS_JoystickOpen,
|
||||
IOS_JoystickIsAttached,
|
||||
IOS_JoystickRumble,
|
||||
IOS_JoystickUpdate,
|
||||
IOS_JoystickClose,
|
||||
IOS_JoystickQuit,
|
||||
};
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -46,9 +46,6 @@ typedef struct joystick_hwdata
|
|||
int nbuttons;
|
||||
int nhats;
|
||||
|
||||
/* Steam Controller support */
|
||||
SDL_bool m_bSteamController;
|
||||
|
||||
struct joystick_hwdata *next;
|
||||
} joystick_hwdata;
|
||||
|
||||
|
|
|
@ -29,10 +29,11 @@
|
|||
/* This is the Linux implementation of the SDL joystick API */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h> /* errno, strerror */
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <limits.h> /* For the definition of PATH_MAX */
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/joystick.h>
|
||||
|
||||
#include "SDL_assert.h"
|
||||
|
@ -43,6 +44,7 @@
|
|||
#include "../SDL_joystick_c.h"
|
||||
#include "../steam/SDL_steamcontroller.h"
|
||||
#include "SDL_sysjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
|
||||
/* This isn't defined in older Linux kernel headers */
|
||||
#ifndef SYN_DROPPED
|
||||
|
@ -76,7 +78,6 @@ typedef struct SDL_joylist_item
|
|||
static SDL_joylist_item *SDL_joylist = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail = NULL;
|
||||
static int numjoysticks = 0;
|
||||
static int instance_counter = 0;
|
||||
|
||||
|
||||
#define test_bit(nr, addr) \
|
||||
|
@ -209,6 +210,13 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check the joystick blacklist */
|
||||
id = MAKE_VIDPID(inpid.vendor, inpid.product);
|
||||
for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
|
||||
|
@ -239,8 +247,7 @@ IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *gui
|
|||
SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
|
||||
}
|
||||
|
||||
if (SDL_IsGameControllerNameAndGUID(namebuf, *guid) &&
|
||||
SDL_ShouldIgnoreGameController(namebuf, *guid)) {
|
||||
if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -325,14 +332,14 @@ MaybeAddDevice(const char *path)
|
|||
item->name = SDL_strdup(namebuf);
|
||||
item->guid = guid;
|
||||
|
||||
if ( (item->path == NULL) || (item->name == NULL) ) {
|
||||
if ((item->path == NULL) || (item->name == NULL)) {
|
||||
SDL_free(item->path);
|
||||
SDL_free(item->name);
|
||||
SDL_free(item);
|
||||
return -1;
|
||||
}
|
||||
|
||||
item->device_instance = instance_counter++;
|
||||
item->device_instance = SDL_GetNextJoystickInstanceID();
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
|
@ -343,7 +350,7 @@ MaybeAddDevice(const char *path)
|
|||
/* Need to increment the joystick count before we post the event */
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
SDL_PrivateJoystickAdded(item->device_instance);
|
||||
|
||||
return numjoysticks;
|
||||
}
|
||||
|
@ -409,7 +416,7 @@ JoystickInitWithoutUdev(void)
|
|||
MaybeAddDevice(path);
|
||||
}
|
||||
|
||||
return numjoysticks;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -430,7 +437,7 @@ JoystickInitWithUdev(void)
|
|||
/* Force a scan to build the initial device list */
|
||||
SDL_UDEV_Scan();
|
||||
|
||||
return numjoysticks;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -455,7 +462,7 @@ static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickG
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
*device_instance = item->device_instance = instance_counter++;
|
||||
*device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
|
||||
if (SDL_joylist_tail == NULL) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
} else {
|
||||
|
@ -466,7 +473,7 @@ static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickG
|
|||
/* Need to increment the joystick count before we post the event */
|
||||
++numjoysticks;
|
||||
|
||||
SDL_PrivateJoystickAdded(numjoysticks - 1);
|
||||
SDL_PrivateJoystickAdded(item->device_instance);
|
||||
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
@ -505,8 +512,8 @@ static void SteamControllerDisconnectedCallback(int device_instance)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
static int
|
||||
LINUX_JoystickInit(void)
|
||||
{
|
||||
/* First see if the user specified one or more joysticks to use */
|
||||
if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
|
||||
|
@ -534,14 +541,14 @@ SDL_SYS_JoystickInit(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
LINUX_JoystickGetCount(void)
|
||||
{
|
||||
return numjoysticks;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
LINUX_JoystickDetect(void)
|
||||
{
|
||||
#if SDL_USE_LIBUDEV
|
||||
SDL_UDEV_Poll();
|
||||
|
@ -569,14 +576,21 @@ JoystickByDevIndex(int device_index)
|
|||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
static const char *
|
||||
LINUX_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->name;
|
||||
}
|
||||
|
||||
static SDL_JoystickGUID
|
||||
LINUX_JoystickGetDeviceGUID( int device_index )
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping from device index to the instance id for this index */
|
||||
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickID
|
||||
LINUX_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->device_instance;
|
||||
}
|
||||
|
@ -624,6 +638,7 @@ ConfigJoystick(SDL_Joystick * joystick, int fd)
|
|||
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
|
||||
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
|
||||
unsigned long relbit[NBITS(REL_MAX)] = { 0 };
|
||||
unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
|
||||
|
||||
/* See if this device uses the new unified event API */
|
||||
if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
|
||||
|
@ -719,6 +734,15 @@ ConfigJoystick(SDL_Joystick * joystick, int fd)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
|
||||
if (test_bit(FF_RUMBLE, ffbit)) {
|
||||
joystick->hwdata->ff_rumble = SDL_TRUE;
|
||||
}
|
||||
if (test_bit(FF_SINE, ffbit)) {
|
||||
joystick->hwdata->ff_sine = SDL_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -727,8 +751,8 @@ ConfigJoystick(SDL_Joystick * joystick, int fd)
|
|||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static int
|
||||
LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByDevIndex(device_index);
|
||||
|
||||
|
@ -744,6 +768,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
}
|
||||
joystick->hwdata->item = item;
|
||||
joystick->hwdata->guid = item->guid;
|
||||
joystick->hwdata->effect.id = -1;
|
||||
joystick->hwdata->m_bSteamController = item->m_bSteamController;
|
||||
|
||||
if (item->m_bSteamController) {
|
||||
|
@ -752,7 +777,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
&joystick->naxes,
|
||||
&joystick->nhats);
|
||||
} else {
|
||||
int fd = open(item->path, O_RDONLY, 0);
|
||||
int fd = open(item->path, O_RDWR, 0);
|
||||
if (fd < 0) {
|
||||
SDL_free(joystick->hwdata);
|
||||
joystick->hwdata = NULL;
|
||||
|
@ -785,11 +810,52 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
}
|
||||
|
||||
/* Function to determine if this joystick is attached to the system right now */
|
||||
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
|
||||
static SDL_bool
|
||||
LINUX_JoystickIsAttached(SDL_Joystick *joystick)
|
||||
{
|
||||
return joystick->hwdata->item != NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
struct input_event event;
|
||||
|
||||
if (joystick->hwdata->effect.id < 0) {
|
||||
if (joystick->hwdata->ff_rumble) {
|
||||
struct ff_effect *effect = &joystick->hwdata->effect;
|
||||
|
||||
effect->type = FF_RUMBLE;
|
||||
effect->replay.length = SDL_min(duration_ms, 32767);
|
||||
effect->u.rumble.strong_magnitude = low_frequency_rumble;
|
||||
effect->u.rumble.weak_magnitude = high_frequency_rumble;
|
||||
} else if (joystick->hwdata->ff_sine) {
|
||||
/* Scale and average the two rumble strengths */
|
||||
Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
|
||||
struct ff_effect *effect = &joystick->hwdata->effect;
|
||||
|
||||
effect->type = FF_PERIODIC;
|
||||
effect->replay.length = SDL_min(duration_ms, 32767);
|
||||
effect->u.periodic.waveform = FF_SINE;
|
||||
effect->u.periodic.magnitude = magnitude;
|
||||
} else {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
}
|
||||
|
||||
if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
|
||||
return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
|
||||
}
|
||||
|
||||
event.type = EV_FF;
|
||||
event.code = joystick->hwdata->effect.id;
|
||||
event.value = 1;
|
||||
if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
|
||||
return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_INLINE void
|
||||
HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
|
||||
{
|
||||
|
@ -963,8 +1029,8 @@ HandleInputEvents(SDL_Joystick * joystick)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static void
|
||||
LINUX_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -990,10 +1056,14 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
LINUX_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
if (joystick->hwdata) {
|
||||
if (joystick->hwdata->effect.id >= 0) {
|
||||
ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
|
||||
joystick->hwdata->effect.id = -1;
|
||||
}
|
||||
if (joystick->hwdata->fd >= 0) {
|
||||
close(joystick->hwdata->fd);
|
||||
}
|
||||
|
@ -1008,8 +1078,8 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
|||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
LINUX_JoystickQuit(void)
|
||||
{
|
||||
SDL_joylist_item *item = NULL;
|
||||
SDL_joylist_item *next = NULL;
|
||||
|
@ -1024,7 +1094,6 @@ SDL_SYS_JoystickQuit(void)
|
|||
SDL_joylist = SDL_joylist_tail = NULL;
|
||||
|
||||
numjoysticks = 0;
|
||||
instance_counter = 0;
|
||||
|
||||
#if SDL_USE_LIBUDEV
|
||||
SDL_UDEV_DelCallback(joystick_udev_callback);
|
||||
|
@ -1034,15 +1103,21 @@ SDL_SYS_JoystickQuit(void)
|
|||
SDL_QuitSteamControllers();
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
|
||||
SDL_JoystickDriver SDL_LINUX_JoystickDriver =
|
||||
{
|
||||
return JoystickByDevIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
return joystick->hwdata->guid;
|
||||
}
|
||||
LINUX_JoystickInit,
|
||||
LINUX_JoystickGetCount,
|
||||
LINUX_JoystickDetect,
|
||||
LINUX_JoystickGetDeviceName,
|
||||
LINUX_JoystickGetDeviceGUID,
|
||||
LINUX_JoystickGetDeviceInstanceID,
|
||||
LINUX_JoystickOpen,
|
||||
LINUX_JoystickIsAttached,
|
||||
LINUX_JoystickRumble,
|
||||
LINUX_JoystickUpdate,
|
||||
LINUX_JoystickClose,
|
||||
LINUX_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_LINUX */
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ struct joystick_hwdata
|
|||
SDL_JoystickGUID guid;
|
||||
char *fname; /* Used in haptic subsystem */
|
||||
|
||||
SDL_bool ff_rumble;
|
||||
SDL_bool ff_sine;
|
||||
struct ff_effect effect;
|
||||
|
||||
/* The current Linux joystick driver maps hats to two axes */
|
||||
struct hwdata_hat
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "SDL_windowsjoystick_c.h"
|
||||
#include "SDL_dinputjoystick_c.h"
|
||||
#include "SDL_xinputjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
|
||||
#ifndef DIDFT_OPTIONAL
|
||||
#define DIDFT_OPTIONAL 0x80000000
|
||||
|
@ -35,6 +36,8 @@
|
|||
#define INPUT_QSIZE 32 /* Buffer up to 32 input messages */
|
||||
#define JOY_AXIS_THRESHOLD (((SDL_JOYSTICK_AXIS_MAX)-(SDL_JOYSTICK_AXIS_MIN))/100) /* 1% motion */
|
||||
|
||||
#define CONVERT_MAGNITUDE(x) (((x)*10000) / 0x7FFF)
|
||||
|
||||
/* external variables referenced. */
|
||||
extern HWND SDL_HelperWindow;
|
||||
|
||||
|
@ -46,170 +49,170 @@ static UINT SDL_RawDevListCount = 0;
|
|||
|
||||
/* Taken from Wine - Thanks! */
|
||||
static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
|
||||
{ &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, DIJOFS_X, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, DIJOFS_Y, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, DIJOFS_Z, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, DIJOFS_RX, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, DIJOFS_RY, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, DIJOFS_RZ, DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, DIJOFS_SLIDER(0), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, DIJOFS_SLIDER(1), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(0), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(1), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(2), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_POV, DIJOFS_POV(3), DIDFT_OPTIONAL | DIDFT_POV | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(0), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(1), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(2), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(3), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(4), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(5), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(6), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(7), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(8), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(9), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(10), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(11), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(12), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(13), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(14), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(15), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(16), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(17), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(18), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(19), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(20), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(21), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(22), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(23), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(24), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(25), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(26), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(27), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(28), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(29), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(30), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(31), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(32), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(33), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(34), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(35), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(36), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(37), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(38), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(39), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(40), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(41), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(42), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(43), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(44), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(45), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(46), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(47), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(48), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(49), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(50), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(51), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(52), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(53), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(54), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(55), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(56), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(57), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(58), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(59), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(60), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(61), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(62), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(63), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(64), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(65), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(66), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(67), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(68), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(69), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(70), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(71), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(72), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(73), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(74), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(75), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(76), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(77), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(78), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(79), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(80), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(81), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(82), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(83), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(84), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(85), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(86), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(87), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(88), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(89), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(90), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(91), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(92), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(93), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(94), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(95), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(96), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(97), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(98), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(99), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(100), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(101), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(102), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(103), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(104), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(105), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(106), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(107), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(108), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(109), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(110), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(111), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(112), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(113), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(114), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(115), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(116), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(117), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(118), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(119), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(120), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(121), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(122), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(123), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(124), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(125), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(126), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ NULL, DIJOFS_BUTTON(127), DIDFT_OPTIONAL | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lVX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lVY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lVZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lVRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lVRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lVRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglVSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lAX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lAY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lAZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lARx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lARy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lARz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglASlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_XAxis, FIELD_OFFSET(DIJOYSTATE2, lFX), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_YAxis, FIELD_OFFSET(DIJOYSTATE2, lFY), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_ZAxis, FIELD_OFFSET(DIJOYSTATE2, lFZ), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RxAxis, FIELD_OFFSET(DIJOYSTATE2, lFRx), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RyAxis, FIELD_OFFSET(DIJOYSTATE2, lFRy), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_RzAxis, FIELD_OFFSET(DIJOYSTATE2, lFRz), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[0]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
{ &GUID_Slider, FIELD_OFFSET(DIJOYSTATE2, rglFSlider[1]), DIDFT_OPTIONAL | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 },
|
||||
};
|
||||
|
||||
const DIDATAFORMAT SDL_c_dfDIJoystick2 = {
|
||||
|
@ -311,6 +314,61 @@ SDL_IsXInputDevice(const GUID* pGuidProductFromDirectInput)
|
|||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
void FreeRumbleEffectData(DIEFFECT *effect)
|
||||
{
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
SDL_free(effect->rgdwAxes);
|
||||
SDL_free(effect->rglDirection);
|
||||
SDL_free(effect->lpvTypeSpecificParams);
|
||||
SDL_free(effect);
|
||||
}
|
||||
|
||||
DIEFFECT *CreateRumbleEffectData(Sint16 magnitude, Uint32 duration_ms)
|
||||
{
|
||||
DIEFFECT *effect;
|
||||
DIPERIODIC *periodic;
|
||||
|
||||
/* Create the effect */
|
||||
effect = (DIEFFECT *)SDL_calloc(1, sizeof(*effect));
|
||||
if (!effect) {
|
||||
return NULL;
|
||||
}
|
||||
effect->dwSize = sizeof(*effect);
|
||||
effect->dwGain = 10000;
|
||||
effect->dwFlags = DIEFF_OBJECTOFFSETS;
|
||||
effect->dwDuration = duration_ms * 1000; /* In microseconds. */
|
||||
effect->dwTriggerButton = DIEB_NOTRIGGER;
|
||||
|
||||
effect->cAxes = 2;
|
||||
effect->rgdwAxes = (DWORD *)SDL_calloc(effect->cAxes, sizeof(DWORD));
|
||||
if (!effect->rgdwAxes) {
|
||||
FreeRumbleEffectData(effect);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
effect->rglDirection = (LONG *)SDL_calloc(effect->cAxes, sizeof(LONG));
|
||||
if (!effect->rglDirection) {
|
||||
FreeRumbleEffectData(effect);
|
||||
return NULL;
|
||||
}
|
||||
effect->dwFlags |= DIEFF_CARTESIAN;
|
||||
|
||||
periodic = (DIPERIODIC *)SDL_calloc(1, sizeof(*periodic));
|
||||
if (!periodic) {
|
||||
FreeRumbleEffectData(effect);
|
||||
return NULL;
|
||||
}
|
||||
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
|
||||
periodic->dwPeriod = 1000000;
|
||||
|
||||
effect->cbTypeSpecificParams = sizeof(*periodic);
|
||||
effect->lpvTypeSpecificParams = periodic;
|
||||
|
||||
return effect;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_DINPUT_JoystickInit(void)
|
||||
{
|
||||
|
@ -348,28 +406,29 @@ SDL_DINPUT_JoystickInit(void)
|
|||
static BOOL CALLBACK
|
||||
EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
|
||||
{
|
||||
const Uint16 BUS_USB = 0x03;
|
||||
const Uint16 BUS_BLUETOOTH = 0x05;
|
||||
JoyStick_DeviceData *pNewJoystick;
|
||||
JoyStick_DeviceData *pPrevJoystick = NULL;
|
||||
const DWORD devtype = (pdidInstance->dwDevType & 0xFF);
|
||||
Uint16 *guid16;
|
||||
Uint16 vendor = 0;
|
||||
Uint16 product = 0;
|
||||
Uint16 version = 0;
|
||||
WCHAR hidPath[MAX_PATH];
|
||||
|
||||
if (devtype == DI8DEVTYPE_SUPPLEMENTAL) {
|
||||
/* Add any supplemental devices that should be ignored here */
|
||||
#define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID)
|
||||
static DWORD ignored_devices[] = {
|
||||
MAKE_TABLE_ENTRY(0, 0)
|
||||
};
|
||||
#define MAKE_TABLE_ENTRY(VID, PID) ((((DWORD)PID)<<16)|VID)
|
||||
static DWORD ignored_devices[] = {
|
||||
MAKE_TABLE_ENTRY(0, 0)
|
||||
};
|
||||
#undef MAKE_TABLE_ENTRY
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < SDL_arraysize(ignored_devices); ++i) {
|
||||
if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < SDL_arraysize(ignored_devices); ++i) {
|
||||
if (pdidInstance->guidProduct.Data1 == ignored_devices[i]) {
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_IsXInputDevice(&pdidInstance->guidProduct)) {
|
||||
|
@ -452,27 +511,38 @@ EnumJoysticksCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext)
|
|||
|
||||
guid16 = (Uint16 *)pNewJoystick->guid.data;
|
||||
if (SDL_memcmp(&pdidInstance->guidProduct.Data4[2], "PIDVID", 6) == 0) {
|
||||
*guid16++ = SDL_SwapLE16(BUS_USB);
|
||||
vendor = (Uint16)LOWORD(pdidInstance->guidProduct.Data1);
|
||||
product = (Uint16)HIWORD(pdidInstance->guidProduct.Data1);
|
||||
version = 0;
|
||||
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16((Uint16)LOWORD(pdidInstance->guidProduct.Data1)); /* vendor */
|
||||
*guid16++ = SDL_SwapLE16(vendor);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16((Uint16)HIWORD(pdidInstance->guidProduct.Data1)); /* product */
|
||||
*guid16++ = SDL_SwapLE16(product);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = 0; /* version */
|
||||
*guid16++ = SDL_SwapLE16(version);
|
||||
*guid16++ = 0;
|
||||
} else {
|
||||
*guid16++ = SDL_SwapLE16(BUS_BLUETOOTH);
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_BLUETOOTH);
|
||||
*guid16++ = 0;
|
||||
SDL_strlcpy((char*)guid16, pNewJoystick->joystickname, sizeof(pNewJoystick->guid.data) - 4);
|
||||
}
|
||||
|
||||
if (SDL_IsGameControllerNameAndGUID(pNewJoystick->joystickname, pNewJoystick->guid) &&
|
||||
SDL_ShouldIgnoreGameController(pNewJoystick->joystickname, pNewJoystick->guid)) {
|
||||
if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
|
||||
SDL_free(pNewJoystick);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
SDL_SYS_AddJoystickDevice(pNewJoystick);
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(vendor, product)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
SDL_free(pNewJoystick);
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
WINDOWS_AddJoystickDevice(pNewJoystick);
|
||||
|
||||
return DIENUM_CONTINUE; /* get next device, please */
|
||||
}
|
||||
|
@ -683,7 +753,6 @@ SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde
|
|||
|
||||
/* Force capable? */
|
||||
if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
|
||||
|
||||
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::Acquire", result);
|
||||
|
@ -752,6 +821,89 @@ SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
SDL_DINPUT_JoystickInitRumble(SDL_Joystick * joystick, Sint16 magnitude, Uint32 duration_ms)
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
/* Reset and then enable actuators */
|
||||
result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
|
||||
if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
|
||||
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
|
||||
if (SUCCEEDED(result)) {
|
||||
result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_RESET);
|
||||
}
|
||||
}
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_RESET)", result);
|
||||
}
|
||||
|
||||
result = IDirectInputDevice8_SendForceFeedbackCommand(joystick->hwdata->InputDevice, DISFFC_SETACTUATORSON);
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::SendForceFeedbackCommand(DISFFC_SETACTUATORSON)", result);
|
||||
}
|
||||
|
||||
/* Create the effect */
|
||||
joystick->hwdata->ffeffect = CreateRumbleEffectData(magnitude, duration_ms);
|
||||
if (!joystick->hwdata->ffeffect) {
|
||||
return SDL_OutOfMemory();
|
||||
}
|
||||
|
||||
result = IDirectInputDevice8_CreateEffect(joystick->hwdata->InputDevice, &GUID_Sine,
|
||||
joystick->hwdata->ffeffect, &joystick->hwdata->ffeffect_ref, NULL);
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::CreateEffect", result);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
/* Scale and average the two rumble strengths */
|
||||
Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
|
||||
|
||||
if (!(joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK)) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
if (joystick->hwdata->ff_initialized) {
|
||||
DIPERIODIC *periodic = ((DIPERIODIC *)joystick->hwdata->ffeffect->lpvTypeSpecificParams);
|
||||
joystick->hwdata->ffeffect->dwDuration = duration_ms * 1000; /* In microseconds. */
|
||||
periodic->dwMagnitude = CONVERT_MAGNITUDE(magnitude);
|
||||
|
||||
result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
|
||||
if (result == DIERR_INPUTLOST) {
|
||||
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
|
||||
if (SUCCEEDED(result)) {
|
||||
result = IDirectInputEffect_SetParameters(joystick->hwdata->ffeffect_ref, joystick->hwdata->ffeffect, (DIEP_DURATION | DIEP_TYPESPECIFICPARAMS));
|
||||
}
|
||||
}
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::SetParameters", result);
|
||||
}
|
||||
} else {
|
||||
if (SDL_DINPUT_JoystickInitRumble(joystick, magnitude, duration_ms) < 0) {
|
||||
return -1;
|
||||
}
|
||||
joystick->hwdata->ff_initialized = SDL_TRUE;
|
||||
}
|
||||
|
||||
result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
|
||||
if (result == DIERR_INPUTLOST || result == DIERR_NOTEXCLUSIVEACQUIRED) {
|
||||
result = IDirectInputDevice8_Acquire(joystick->hwdata->InputDevice);
|
||||
if (SUCCEEDED(result)) {
|
||||
result = IDirectInputEffect_Start(joystick->hwdata->ffeffect_ref, 1, 0);
|
||||
}
|
||||
}
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::Start", result);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Uint8
|
||||
TranslatePOV(DWORD value)
|
||||
{
|
||||
|
@ -933,8 +1085,17 @@ SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
|||
void
|
||||
SDL_DINPUT_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
if (joystick->hwdata->ffeffect_ref) {
|
||||
IDirectInputEffect_Unload(joystick->hwdata->ffeffect_ref);
|
||||
joystick->hwdata->ffeffect_ref = NULL;
|
||||
}
|
||||
if (joystick->hwdata->ffeffect) {
|
||||
FreeRumbleEffectData(joystick->hwdata->ffeffect);
|
||||
joystick->hwdata->ffeffect = NULL;
|
||||
}
|
||||
IDirectInputDevice8_Unacquire(joystick->hwdata->InputDevice);
|
||||
IDirectInputDevice8_Release(joystick->hwdata->InputDevice);
|
||||
joystick->hwdata->ff_initialized = SDL_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -972,6 +1133,12 @@ SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde
|
|||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
int
|
||||
SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
void
|
||||
SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
extern int SDL_DINPUT_JoystickInit(void);
|
||||
extern void SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext);
|
||||
extern int SDL_DINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice);
|
||||
extern int SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
extern void SDL_DINPUT_JoystickUpdate(SDL_Joystick * joystick);
|
||||
extern void SDL_DINPUT_JoystickClose(SDL_Joystick * joystick);
|
||||
extern void SDL_DINPUT_JoystickQuit(void);
|
||||
|
|
|
@ -61,7 +61,6 @@
|
|||
/* local variables */
|
||||
static SDL_bool s_bDeviceAdded = SDL_FALSE;
|
||||
static SDL_bool s_bDeviceRemoved = SDL_FALSE;
|
||||
static SDL_JoystickID s_nInstanceID = -1;
|
||||
static SDL_cond *s_condJoystickThread = NULL;
|
||||
static SDL_mutex *s_mutexJoyStickEnum = NULL;
|
||||
static SDL_Thread *s_threadJoystick = NULL;
|
||||
|
@ -271,30 +270,33 @@ SDL_JoystickThread(void *_data)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device)
|
||||
void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device)
|
||||
{
|
||||
device->send_add_event = SDL_TRUE;
|
||||
device->nInstanceID = ++s_nInstanceID;
|
||||
device->nInstanceID = SDL_GetNextJoystickInstanceID();
|
||||
device->pNext = SYS_Joystick;
|
||||
SYS_Joystick = device;
|
||||
|
||||
s_bDeviceAdded = SDL_TRUE;
|
||||
}
|
||||
|
||||
static void WINDOWS_JoystickDetect(void);
|
||||
static void WINDOWS_JoystickQuit(void);
|
||||
|
||||
/* Function to scan the system for joysticks.
|
||||
* Joystick 0 should be the system default joystick.
|
||||
* It should return 0, or -1 on an unrecoverable fatal error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickInit(void)
|
||||
static int
|
||||
WINDOWS_JoystickInit(void)
|
||||
{
|
||||
if (SDL_DINPUT_JoystickInit() < 0) {
|
||||
SDL_SYS_JoystickQuit();
|
||||
WINDOWS_JoystickQuit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SDL_XINPUT_JoystickInit() < 0) {
|
||||
SDL_SYS_JoystickQuit();
|
||||
WINDOWS_JoystickQuit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -302,19 +304,19 @@ SDL_SYS_JoystickInit(void)
|
|||
s_condJoystickThread = SDL_CreateCond();
|
||||
s_bDeviceAdded = SDL_TRUE; /* force a scan of the system for joysticks this first time */
|
||||
|
||||
SDL_SYS_JoystickDetect();
|
||||
WINDOWS_JoystickDetect();
|
||||
|
||||
if (!s_threadJoystick) {
|
||||
/* spin up the thread to detect hotplug of devices */
|
||||
s_bJoystickThreadQuit = SDL_FALSE;
|
||||
s_threadJoystick = SDL_CreateThreadInternal(SDL_JoystickThread, "SDL_joystick", 64 * 1024, NULL);
|
||||
}
|
||||
return SDL_SYS_NumJoysticks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return the number of joysticks that are connected right now */
|
||||
int
|
||||
SDL_SYS_NumJoysticks(void)
|
||||
static int
|
||||
WINDOWS_JoystickGetCount(void)
|
||||
{
|
||||
int nJoysticks = 0;
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
|
@ -327,8 +329,8 @@ SDL_SYS_NumJoysticks(void)
|
|||
}
|
||||
|
||||
/* detect any new joysticks being inserted into the system */
|
||||
void
|
||||
SDL_SYS_JoystickDetect(void)
|
||||
static void
|
||||
WINDOWS_JoystickDetect(void)
|
||||
{
|
||||
JoyStick_DeviceData *pCurList = NULL;
|
||||
|
||||
|
@ -383,7 +385,7 @@ SDL_SYS_JoystickDetect(void)
|
|||
SDL_DINPUT_MaybeAddDevice(&pNewJoystick->dxdevice);
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAdded(device_index);
|
||||
SDL_PrivateJoystickAdded(pNewJoystick->nInstanceID);
|
||||
|
||||
pNewJoystick->send_add_event = SDL_FALSE;
|
||||
}
|
||||
|
@ -394,8 +396,8 @@ SDL_SYS_JoystickDetect(void)
|
|||
}
|
||||
|
||||
/* Function to get the device-dependent name of a joystick */
|
||||
const char *
|
||||
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
||||
static const char *
|
||||
WINDOWS_JoystickGetDeviceName(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
|
||||
|
@ -405,9 +407,22 @@ SDL_SYS_JoystickNameForDeviceIndex(int device_index)
|
|||
return device->joystickname;
|
||||
}
|
||||
|
||||
/* return the stable device guid for this device index */
|
||||
static SDL_JoystickGUID
|
||||
WINDOWS_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
||||
for (index = device_index; index > 0; index--)
|
||||
device = device->pNext;
|
||||
|
||||
return device->guid;
|
||||
}
|
||||
|
||||
/* Function to perform the mapping between current device instance and this joysticks instance id */
|
||||
SDL_JoystickID
|
||||
SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
||||
static SDL_JoystickID
|
||||
WINDOWS_JoystickGetDeviceInstanceID(int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
@ -423,8 +438,8 @@ SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
|
|||
This should fill the nbuttons and naxes fields of the joystick structure.
|
||||
It returns 0, or -1 if there is an error.
|
||||
*/
|
||||
int
|
||||
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
static int
|
||||
WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
||||
{
|
||||
JoyStick_DeviceData *joystickdevice = SYS_Joystick;
|
||||
|
||||
|
@ -449,14 +464,24 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
|
|||
}
|
||||
|
||||
/* return true if this joystick is plugged in right now */
|
||||
SDL_bool
|
||||
SDL_SYS_JoystickAttached(SDL_Joystick * joystick)
|
||||
static SDL_bool
|
||||
WINDOWS_JoystickIsAttached(SDL_Joystick * joystick)
|
||||
{
|
||||
return joystick->hwdata && !joystick->hwdata->removed;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
static int
|
||||
WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
} else {
|
||||
return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
WINDOWS_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
if (!joystick->hwdata || joystick->hwdata->removed) {
|
||||
return;
|
||||
|
@ -474,8 +499,8 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
|
|||
}
|
||||
|
||||
/* Function to close a joystick after use */
|
||||
void
|
||||
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
||||
static void
|
||||
WINDOWS_JoystickClose(SDL_Joystick * joystick)
|
||||
{
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
SDL_XINPUT_JoystickClose(joystick);
|
||||
|
@ -487,8 +512,8 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
|
|||
}
|
||||
|
||||
/* Function to perform any system-specific joystick related cleanup */
|
||||
void
|
||||
SDL_SYS_JoystickQuit(void)
|
||||
static void
|
||||
WINDOWS_JoystickQuit(void)
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
|
||||
|
@ -524,24 +549,21 @@ SDL_SYS_JoystickQuit(void)
|
|||
s_bDeviceRemoved = SDL_FALSE;
|
||||
}
|
||||
|
||||
/* return the stable device guid for this device index */
|
||||
SDL_JoystickGUID
|
||||
SDL_SYS_JoystickGetDeviceGUID(int device_index)
|
||||
SDL_JoystickDriver SDL_WINDOWS_JoystickDriver =
|
||||
{
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
||||
for (index = device_index; index > 0; index--)
|
||||
device = device->pNext;
|
||||
|
||||
return device->guid;
|
||||
}
|
||||
|
||||
SDL_JoystickGUID
|
||||
SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
|
||||
{
|
||||
return joystick->hwdata->guid;
|
||||
}
|
||||
WINDOWS_JoystickInit,
|
||||
WINDOWS_JoystickGetCount,
|
||||
WINDOWS_JoystickDetect,
|
||||
WINDOWS_JoystickGetDeviceName,
|
||||
WINDOWS_JoystickGetDeviceGUID,
|
||||
WINDOWS_JoystickGetDeviceInstanceID,
|
||||
WINDOWS_JoystickOpen,
|
||||
WINDOWS_JoystickIsAttached,
|
||||
WINDOWS_JoystickRumble,
|
||||
WINDOWS_JoystickUpdate,
|
||||
WINDOWS_JoystickClose,
|
||||
WINDOWS_JoystickQuit,
|
||||
};
|
||||
|
||||
#endif /* SDL_JOYSTICK_DINPUT || SDL_JOYSTICK_XINPUT */
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ struct joystick_hwdata
|
|||
SDL_JoystickGUID guid;
|
||||
SDL_bool removed;
|
||||
SDL_bool send_remove_event;
|
||||
Uint32 rumble_expiration;
|
||||
|
||||
#if SDL_JOYSTICK_DINPUT
|
||||
LPDIRECTINPUTDEVICE8 InputDevice;
|
||||
|
@ -76,6 +77,9 @@ struct joystick_hwdata
|
|||
input_t Inputs[MAX_INPUTS];
|
||||
int NumInputs;
|
||||
int NumSliders;
|
||||
SDL_bool ff_initialized;
|
||||
DIEFFECT *ffeffect;
|
||||
LPDIRECTINPUTEFFECT ffeffect_ref;
|
||||
#endif
|
||||
|
||||
SDL_bool bXInputDevice; /* SDL_TRUE if this device supports using the xinput API rather than DirectInput */
|
||||
|
@ -88,6 +92,6 @@ struct joystick_hwdata
|
|||
extern const DIDATAFORMAT SDL_c_dfDIJoystick2;
|
||||
#endif
|
||||
|
||||
extern void SDL_SYS_AddJoystickDevice(JoyStick_DeviceData *device);
|
||||
extern void WINDOWS_AddJoystickDevice(JoyStick_DeviceData *device);
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -26,8 +26,10 @@
|
|||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_timer.h"
|
||||
#include "SDL_windowsjoystick_c.h"
|
||||
#include "SDL_xinputjoystick_c.h"
|
||||
#include "../hidapi/SDL_hidapijoystick_c.h"
|
||||
|
||||
/*
|
||||
* Internal stuff.
|
||||
|
@ -186,6 +188,9 @@ GuessXInputDevice(Uint8 userid, Uint16 *pVID, Uint16 *pPID, Uint16 *pVersion)
|
|||
static void
|
||||
AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext)
|
||||
{
|
||||
Uint16 vendor = 0;
|
||||
Uint16 product = 0;
|
||||
Uint16 version = 0;
|
||||
JoyStick_DeviceData *pPrevJoystick = NULL;
|
||||
JoyStick_DeviceData *pNewJoystick = *pContext;
|
||||
|
||||
|
@ -229,15 +234,11 @@ AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext)
|
|||
if (SDL_XInputUseOldJoystickMapping()) {
|
||||
SDL_zero(pNewJoystick->guid);
|
||||
} else {
|
||||
const Uint16 BUS_USB = 0x03;
|
||||
Uint16 vendor = 0;
|
||||
Uint16 product = 0;
|
||||
Uint16 version = 0;
|
||||
Uint16 *guid16 = (Uint16 *)pNewJoystick->guid.data;
|
||||
|
||||
GuessXInputDevice(userid, &vendor, &product, &version);
|
||||
|
||||
*guid16++ = SDL_SwapLE16(BUS_USB);
|
||||
*guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
|
||||
*guid16++ = 0;
|
||||
*guid16++ = SDL_SwapLE16(vendor);
|
||||
*guid16++ = 0;
|
||||
|
@ -253,12 +254,20 @@ AddXInputDevice(Uint8 userid, BYTE SubType, JoyStick_DeviceData **pContext)
|
|||
pNewJoystick->SubType = SubType;
|
||||
pNewJoystick->XInputUserId = userid;
|
||||
|
||||
if (SDL_ShouldIgnoreGameController(pNewJoystick->joystickname, pNewJoystick->guid)) {
|
||||
if (SDL_ShouldIgnoreJoystick(pNewJoystick->joystickname, pNewJoystick->guid)) {
|
||||
SDL_free(pNewJoystick);
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SYS_AddJoystickDevice(pNewJoystick);
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
if (HIDAPI_IsDevicePresent(vendor, product)) {
|
||||
/* The HIDAPI driver is taking care of this device */
|
||||
SDL_free(pNewJoystick);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
WINDOWS_AddJoystickDevice(pNewJoystick);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -384,12 +393,12 @@ UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState
|
|||
Uint8 button;
|
||||
Uint8 hat = SDL_HAT_CENTERED;
|
||||
|
||||
SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX);
|
||||
SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbLY)));
|
||||
SDL_PrivateJoystickAxis(joystick, 2, (Sint16)(((int)pXInputState->Gamepad.bLeftTrigger * 65535 / 255) - 32768));
|
||||
SDL_PrivateJoystickAxis(joystick, 3, (Sint16)pXInputState->Gamepad.sThumbRX);
|
||||
SDL_PrivateJoystickAxis(joystick, 4, (Sint16)(-SDL_max(-32767, pXInputState->Gamepad.sThumbRY)));
|
||||
SDL_PrivateJoystickAxis(joystick, 5, (Sint16)(((int)pXInputState->Gamepad.bRightTrigger * 65535 / 255) - 32768));
|
||||
SDL_PrivateJoystickAxis(joystick, 0, pXInputState->Gamepad.sThumbLX);
|
||||
SDL_PrivateJoystickAxis(joystick, 1, ~pXInputState->Gamepad.sThumbLY);
|
||||
SDL_PrivateJoystickAxis(joystick, 2, ((int)pXInputState->Gamepad.bLeftTrigger * 257) - 32768);
|
||||
SDL_PrivateJoystickAxis(joystick, 3, pXInputState->Gamepad.sThumbRX);
|
||||
SDL_PrivateJoystickAxis(joystick, 4, ~pXInputState->Gamepad.sThumbRY);
|
||||
SDL_PrivateJoystickAxis(joystick, 5, ((int)pXInputState->Gamepad.bRightTrigger * 257) - 32768);
|
||||
|
||||
for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) {
|
||||
SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED);
|
||||
|
@ -412,6 +421,29 @@ UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState
|
|||
UpdateXInputJoystickBatteryInformation(joystick, pBatteryInformation);
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
XINPUT_VIBRATION XVibration;
|
||||
|
||||
if (!XINPUTSETSTATE) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
XVibration.wLeftMotorSpeed = low_frequency_rumble;
|
||||
XVibration.wRightMotorSpeed = high_frequency_rumble;
|
||||
if (XINPUTSETSTATE(joystick->hwdata->userid, &XVibration) != ERROR_SUCCESS) {
|
||||
return SDL_SetError("XInputSetState() failed");
|
||||
}
|
||||
|
||||
if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
|
||||
joystick->hwdata->rumble_expiration = SDL_GetTicks() + duration_ms;
|
||||
} else {
|
||||
joystick->hwdata->rumble_expiration = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
|
@ -449,6 +481,13 @@ SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
|||
}
|
||||
joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber;
|
||||
}
|
||||
|
||||
if (joystick->hwdata->rumble_expiration) {
|
||||
Uint32 now = SDL_GetTicks();
|
||||
if (SDL_TICKS_PASSED(now, joystick->hwdata->rumble_expiration)) {
|
||||
SDL_XINPUT_JoystickRumble(joystick, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -490,6 +529,12 @@ SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde
|
|||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
int
|
||||
SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
void
|
||||
SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick)
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ extern SDL_bool SDL_XINPUT_Enabled(void);
|
|||
extern int SDL_XINPUT_JoystickInit(void);
|
||||
extern void SDL_XINPUT_JoystickDetect(JoyStick_DeviceData **pContext);
|
||||
extern int SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickdevice);
|
||||
extern int SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
|
||||
extern void SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick);
|
||||
extern void SDL_XINPUT_JoystickClose(SDL_Joystick * joystick);
|
||||
extern void SDL_XINPUT_JoystickQuit(void);
|
||||
|
|
|
@ -416,6 +416,17 @@ SDL_strlen(const char *string)
|
|||
#endif /* HAVE_STRLEN */
|
||||
}
|
||||
|
||||
wchar_t *
|
||||
SDL_wcsdup(const wchar_t *string)
|
||||
{
|
||||
size_t len = ((SDL_wcslen(string) + 1) * sizeof(wchar_t));
|
||||
wchar_t *newstr = (wchar_t *)SDL_malloc(len);
|
||||
if (newstr) {
|
||||
SDL_memcpy(newstr, string, len);
|
||||
}
|
||||
return newstr;
|
||||
}
|
||||
|
||||
size_t
|
||||
SDL_wcslen(const wchar_t * string)
|
||||
{
|
||||
|
@ -562,7 +573,7 @@ char *
|
|||
SDL_strdup(const char *string)
|
||||
{
|
||||
size_t len = SDL_strlen(string) + 1;
|
||||
char *newstr = SDL_malloc(len);
|
||||
char *newstr = (char *)SDL_malloc(len);
|
||||
if (newstr) {
|
||||
SDL_memcpy(newstr, string, len);
|
||||
}
|
||||
|
|
|
@ -114,6 +114,11 @@ loop(void *arg)
|
|||
case SDL_CONTROLLERBUTTONDOWN:
|
||||
case SDL_CONTROLLERBUTTONUP:
|
||||
SDL_Log("Controller button %s %s\n", SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button), event.cbutton.state ? "pressed" : "released");
|
||||
/* First button triggers a 0.5 second full strength rumble */
|
||||
if (event.type == SDL_CONTROLLERBUTTONDOWN &&
|
||||
event.cbutton.button == SDL_CONTROLLER_BUTTON_A) {
|
||||
SDL_GameControllerRumble(gamecontroller, 0xFFFF, 0xFFFF, 500);
|
||||
}
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.keysym.sym != SDLK_ESCAPE) {
|
||||
|
|
|
@ -90,6 +90,10 @@ loop(void *arg)
|
|||
case SDL_JOYBUTTONDOWN:
|
||||
SDL_Log("Joystick %d button %d down\n",
|
||||
event.jbutton.which, event.jbutton.button);
|
||||
/* First button triggers a 0.5 second full strength rumble */
|
||||
if (event.jbutton.button == 0) {
|
||||
SDL_JoystickRumble(joystick, 0xFFFF, 0xFFFF, 500);
|
||||
}
|
||||
break;
|
||||
case SDL_JOYBUTTONUP:
|
||||
SDL_Log("Joystick %d button %d up\n",
|
||||
|
|
Loading…
Reference in New Issue