update SDL3 from 3.2.20 to 3.4.2
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -46,6 +46,7 @@ static const char *s_GamepadMappings[] = {
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_DINPUT
|
||||
"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,",
|
||||
"03000000c82d00001930000000000000,8BitDo 64 Bluetooth Controller,a:b0,b:b1,back:-a5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a2,misc1:b17,misc2:+a3,rightshoulder:b7,righttrigger:b9,start:b11,x:+a5,y:-a3,",
|
||||
"03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00001038000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000650000000000000,8BitDo M30 Gamepad,a:b0,b:b1,back:b10,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,",
|
||||
@@ -197,7 +198,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
|
||||
"03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,",
|
||||
"03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,",
|
||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -207,7 +207,8 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,",
|
||||
"030000005509000000b4000000000000,NVIDIA Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000004b120000014d000000000000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"03000000790000004318000000000000,Nintendo GameCube Controller,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000790000004318000000000000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000790000004418000000000000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
|
||||
@@ -242,6 +243,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000d62000002640000000000000,PowerA OPS v1 Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000d62000003340000000000000,PowerA OPS v3 Pro Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000d620000011a7000000000000,PowerA Wired GameCube Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -310,7 +312,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,",
|
||||
"03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000d620000011a7000000000000,Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000004f04000007d0000000000000,T Mini Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
|
||||
@@ -339,6 +340,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
|
||||
"03000000c0160000e105000000000000,Xin-Mo Dual Arcade,crc:2246,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
|
||||
"03000000790000004f18000000000000,ZD-T Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
"03000000073500000400000000000000,ZENAIM ARCADE CONTROLLER,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
@@ -347,6 +349,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
#endif
|
||||
#ifdef SDL_PLATFORM_MACOS
|
||||
"03000000c82d00001930000000000000,8BitDo 64 Bluetooth Controller,a:b0,b:b1,back:-a3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b17,misc2:+a2,misc3:b10,rightshoulder:b7,righttrigger:b9,start:b11,x:+a3,y:-a2,",
|
||||
"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000650000001000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a5,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@@ -413,13 +416,13 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000380700008433000000010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000380700008483000000010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,",
|
||||
"03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,",
|
||||
"03000000853200008906000000010000,NACON Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
|
||||
"03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
|
||||
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"03000000790000004418000000010000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,",
|
||||
"050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,",
|
||||
@@ -481,12 +484,15 @@ static const char *s_GamepadMappings[] = {
|
||||
"030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
|
||||
"03000000c0160000e105000000040000,Xin-Mo Dual Arcade,crc:82d5,a:b2,b:b4,back:b18,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b8,righttrigger:b10,start:b16,x:b0,y:b6,", /* Ultimate Atari Fight Stick */
|
||||
"03000000073500000400000000010000,ZENAIM ARCADE CONTROLLER,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,",
|
||||
#endif
|
||||
#if defined(SDL_JOYSTICK_LINUX) || defined(SDL_PLATFORM_OPENBSD)
|
||||
"03000000c82d00001930000011010000,8BitDo 64 Bluetooth Controller,a:b0,b:b1,back:-a3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b17,misc2:+a2,misc3:b10,rightshoulder:b7,righttrigger:a4,start:b11,x:+a3,y:-a2,",
|
||||
"05000000c82d00001930000001000000,8BitDo 64 Bluetooth Controller,a:b0,b:b1,back:-a3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b17,misc2:+a2,misc3:b10,rightshoulder:b7,righttrigger:a4,start:b11,x:+a3,y:-a2,",
|
||||
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@@ -498,16 +504,14 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000020000000000000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"06000000c82d00000020000006010000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000960000011010000,8BitDo Pro 3,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b16,paddle3:b2,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000102800000900000000010000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00003028000000010000,8BitDo SFC30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000003512000020ab000010010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"05000000c82d00001b30000001000000,8BitDo Ultimate 2C Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,", /* Bluetooth */
|
||||
@@ -524,9 +528,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,",
|
||||
"03000000050b00000579000011010000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"05000000050b00000679000000010000,ASUS ROG Kunai 3 Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"030000006f0e00003901000020060000,Afterglow Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006f0e00001302000000010000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,",
|
||||
@@ -537,7 +538,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,",
|
||||
"05000000503200000210000000000000,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
|
||||
"05000000503200000210000000000000128804098,Atari Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,",
|
||||
"030000005e0400008e02000047010000,Atari Xbox 360 Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000c62400001b89000011010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:,lefty:,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:,righty:,start:b9,x:b0,y:b3,",
|
||||
@@ -549,25 +549,21 @@ static const char *s_GamepadMappings[] = {
|
||||
"050000004c050000f20d000000010000,DualSense Edge Wireless Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000790000001100000010010000,Elecom Gamepad,crc:e86c,a:b2,b:b3,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b0,y:b1,",
|
||||
"0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"0500000047532067616d657061640000,GS Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,",
|
||||
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"0500000049190000020400001b010000,GameSir T4 Pro,crc:8283,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b23,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000373500009710000001020000,GameSir-K1 FLUX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",
|
||||
"03000000c01100000140000011010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000008f0e00000800000010010000,Gasia Co. Ltd PS(R) Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
"05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
"03000000280400000140000000010000,Gravis Gamepad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,",
|
||||
"030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",
|
||||
"030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
@@ -581,30 +577,23 @@ static const char *s_GamepadMappings[] = {
|
||||
"030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,",
|
||||
"030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f00008600000002010000,Hori Fighting Commander,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,",
|
||||
"03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,",
|
||||
"03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,",
|
||||
"05000000491900000204000000000000,Ipega PG-9087S,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,",
|
||||
"03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
|
||||
"03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
|
||||
"030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
|
||||
"030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,",
|
||||
"03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
@@ -616,24 +605,12 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000380700008433000011010000,Mad Catz FightStick TE S+ (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000380700008483000011010000,Mad Catz FightStick TE S+ (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,",
|
||||
"03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
|
||||
"03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
|
||||
"030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,",
|
||||
"030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
|
||||
"030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
|
||||
"030000005e0400008902000020010000,Microsoft Xbox Controller S,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
|
||||
"05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
|
||||
"030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,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,",
|
||||
"030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,",
|
||||
@@ -642,7 +619,9 @@ static const char *s_GamepadMappings[] = {
|
||||
"05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
|
||||
"030000004b120000014d000000010000,NYKO AIRFLO EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,",
|
||||
"03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"0300000085320000030c000011010000,Nacon GC100,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"03000000790000004318000010010000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"03000000790000004418000010010000,Nintendo GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,",
|
||||
"030000007e0500001920000011810000,Nintendo N64 Controller,crc:d670,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b3,start:b11,x:b4,y:b10,",
|
||||
"050000007e0500001920000001800000,Nintendo N64 Controller,crc:5e1c,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b3,start:b11,x:b4,y:b10,",
|
||||
"030000007e0500001e20000011810000,Nintendo SEGA Genesis Controller,crc:bb22,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,",
|
||||
@@ -654,7 +633,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"060000007e0500000820000000000000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000720000001800000,Nintendo Switch Joy-Con (R),a:b1,b:b2,guide:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000004c69632050726f20436f6e00,Nintendo Switch Pro Controller,crc:15b7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@@ -666,9 +644,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
|
||||
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
|
||||
"05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
|
||||
"030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,",
|
||||
"03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
|
||||
"03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -701,8 +677,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,",
|
||||
"030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
|
||||
"03000000c62400003a54000001010000,PowerA XBox One Controller,a:b0,b:b1,back:b6,dpdown:h0.7,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000d620000011a7000011010000,PowerA Wired GameCube Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,",
|
||||
"03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
@@ -711,25 +686,18 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000222c00000020000011010000,Qanba Drone Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
"050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
"0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
|
||||
"03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
"030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"03000000341a00000908000010010000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,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,",
|
||||
"03000000457500002211000010010000,SZMY-POWER PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -743,8 +711,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"03000000632500002305000010010000,ShanWan USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,",
|
||||
"03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
|
||||
"030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
"03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,",
|
||||
"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
|
||||
@@ -760,7 +726,6 @@ static const char *s_GamepadMappings[] = {
|
||||
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b6,leftstick:b13,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:+a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,",
|
||||
"0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,",
|
||||
"030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
@@ -781,23 +746,18 @@ static const char *s_GamepadMappings[] = {
|
||||
"030000006f0e00000702000011010000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"030000000d0f0000ab01000011010000,Wireless HORIPAD For Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,misc3:b16,misc4:b17,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"050000000d0f00009601000091000000,Wireless HORIPAD For Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc2:b2,misc3:b16,misc4:b17,paddle1:b19,paddle2:b18,paddle3:b15,paddle4:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",
|
||||
"0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
|
||||
"030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
"050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
|
||||
"050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,",
|
||||
"05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,",
|
||||
"03000000c0160000e105000010010000,Xin-Mo Dual Arcade,crc:82d5,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,", /* Ultimate Atari Fight Stick */
|
||||
"03000000073500000400000011010000,ZENAIM ARCADE CONTROLLER,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000120c0000182e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
|
||||
"03000000790000002201000011010000,ZhiXu GuliKit Controller D,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,",
|
||||
"03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,",
|
||||
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
"050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
|
||||
@@ -857,8 +817,8 @@ static const char *s_GamepadMappings[] = {
|
||||
"050000005e040000fd020000ff7f3f00,Xbox One S Controller,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,",
|
||||
"050000005e040000e00200000ffe3f80,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,",
|
||||
"050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,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,",
|
||||
"050000005e040000120b000000783f80,Xbox Series X Controller,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,",
|
||||
"050000005e040000130b0000ffff3f00,Xbox Series X Controller,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,",
|
||||
"050000005e040000120b000000783f80,Xbox Series X Controller,a:b0,b:b1,back:b4,misc1:b15,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,",
|
||||
"050000005e040000130b0000ffff3f00,Xbox Series X Controller,a:b0,b:b1,back:b4,misc1:b15,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,",
|
||||
"050000005e04000091020000ff073f80,Xbox Wireless Controller,a:b0,b:b1,back:b4,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,", /* The DPAD doesn't seem to work on this controller on Android TV? */
|
||||
"050000001727000044310000ffff3f80,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a4,righty:a5,start:b6,x:b2,y:b3,",
|
||||
"0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,",
|
||||
@@ -888,6 +848,8 @@ static const char *s_GamepadMappings[] = {
|
||||
"050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,",
|
||||
"050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,",
|
||||
"050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,",
|
||||
"05000000ac050000040000008e586d04,PlayStation VR2 Sense Controller (L),crc:9342,+leftx:+a3,+lefty:+a1,-leftx:+a2,-lefty:+a4,back:b2,leftstick:b4,lefttrigger:+a7,paddle2:b3,x:b0,y:b1,",
|
||||
"05000000ac050000040000000eb86d04,PlayStation VR2 Sense Controller (R),crc:334b,+rightx:+a3,+righty:+a1,-rightx:+a2,-righty:+a4,a:b0,b:b1,paddle1:b3,rightstick:b4,righttrigger:+a7,start:b2,",
|
||||
"05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,",
|
||||
"050000005e040000050b0000df070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,",
|
||||
"050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
@@ -897,7 +859,7 @@ static const char *s_GamepadMappings[] = {
|
||||
"050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,",
|
||||
#endif
|
||||
#ifdef 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,",
|
||||
"default,*,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,",
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_PS2
|
||||
"0000000050533220436f6e74726f6c00,PS2 Controller,crc:ed87,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -123,8 +123,175 @@ static bool SDL_joystick_being_added;
|
||||
static SDL_Joystick *SDL_joysticks SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static int SDL_joystick_player_count SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static SDL_JoystickID *SDL_joystick_players SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static SDL_HashTable *SDL_joystick_names SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static bool SDL_joystick_allows_background_events = false;
|
||||
|
||||
static Uint32 initial_old_xboxone_controllers[] = {
|
||||
MAKE_VIDPID(0x0000, 0x6686),
|
||||
MAKE_VIDPID(0x0079, 0x18a1),
|
||||
MAKE_VIDPID(0x0079, 0x18c2),
|
||||
MAKE_VIDPID(0x0079, 0x18c8),
|
||||
MAKE_VIDPID(0x0079, 0x18cf),
|
||||
MAKE_VIDPID(0x03f0, 0x0495),
|
||||
MAKE_VIDPID(0x045e, 0x02d1),
|
||||
MAKE_VIDPID(0x045e, 0x02dd),
|
||||
MAKE_VIDPID(0x045e, 0x02e0),
|
||||
MAKE_VIDPID(0x045e, 0x02e3),
|
||||
MAKE_VIDPID(0x045e, 0x02ea),
|
||||
MAKE_VIDPID(0x045e, 0x02fd),
|
||||
MAKE_VIDPID(0x045e, 0x02ff),
|
||||
MAKE_VIDPID(0x045e, 0x0867),
|
||||
MAKE_VIDPID(0x045e, 0x0b00),
|
||||
MAKE_VIDPID(0x045e, 0x0b05),
|
||||
MAKE_VIDPID(0x045e, 0x0b0a),
|
||||
MAKE_VIDPID(0x045e, 0x0b0c),
|
||||
MAKE_VIDPID(0x045e, 0x0b20),
|
||||
MAKE_VIDPID(0x045e, 0x0b21),
|
||||
MAKE_VIDPID(0x045e, 0x0b22),
|
||||
MAKE_VIDPID(0x046d, 0x0000),
|
||||
MAKE_VIDPID(0x046d, 0x1004),
|
||||
MAKE_VIDPID(0x046d, 0x1007),
|
||||
MAKE_VIDPID(0x046d, 0x1008),
|
||||
MAKE_VIDPID(0x046d, 0xf301),
|
||||
MAKE_VIDPID(0x0738, 0x02a0),
|
||||
MAKE_VIDPID(0x0738, 0x4a01),
|
||||
MAKE_VIDPID(0x0738, 0x7263),
|
||||
MAKE_VIDPID(0x0738, 0xb738),
|
||||
MAKE_VIDPID(0x0738, 0xcb29),
|
||||
MAKE_VIDPID(0x0738, 0xf401),
|
||||
MAKE_VIDPID(0x0c12, 0x0e17),
|
||||
MAKE_VIDPID(0x0c12, 0x0e1c),
|
||||
MAKE_VIDPID(0x0c12, 0x0e22),
|
||||
MAKE_VIDPID(0x0c12, 0x0e30),
|
||||
MAKE_VIDPID(0x0d62, 0x9a1a),
|
||||
MAKE_VIDPID(0x0d62, 0x9a1b),
|
||||
MAKE_VIDPID(0x0e00, 0x0e00),
|
||||
MAKE_VIDPID(0x0e6f, 0x012a),
|
||||
MAKE_VIDPID(0x0e6f, 0x0139),
|
||||
MAKE_VIDPID(0x0e6f, 0x013B),
|
||||
MAKE_VIDPID(0x0e6f, 0x013a),
|
||||
MAKE_VIDPID(0x0e6f, 0x0145),
|
||||
MAKE_VIDPID(0x0e6f, 0x0146),
|
||||
MAKE_VIDPID(0x0e6f, 0x0152),
|
||||
MAKE_VIDPID(0x0e6f, 0x015b),
|
||||
MAKE_VIDPID(0x0e6f, 0x015c),
|
||||
MAKE_VIDPID(0x0e6f, 0x015d),
|
||||
MAKE_VIDPID(0x0e6f, 0x015f),
|
||||
MAKE_VIDPID(0x0e6f, 0x0160),
|
||||
MAKE_VIDPID(0x0e6f, 0x0161),
|
||||
MAKE_VIDPID(0x0e6f, 0x0162),
|
||||
MAKE_VIDPID(0x0e6f, 0x0163),
|
||||
MAKE_VIDPID(0x0e6f, 0x0164),
|
||||
MAKE_VIDPID(0x0e6f, 0x0165),
|
||||
MAKE_VIDPID(0x0e6f, 0x0166),
|
||||
MAKE_VIDPID(0x0e6f, 0x0167),
|
||||
MAKE_VIDPID(0x0e6f, 0x0205),
|
||||
MAKE_VIDPID(0x0e6f, 0x0206),
|
||||
MAKE_VIDPID(0x0e6f, 0x0246),
|
||||
MAKE_VIDPID(0x0e6f, 0x0261),
|
||||
MAKE_VIDPID(0x0e6f, 0x0262),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a0),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a1),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a2),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a3),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a4),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a5),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a6),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a7),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a8),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a9),
|
||||
MAKE_VIDPID(0x0e6f, 0x02aa),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ab),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ac),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ad),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ae),
|
||||
MAKE_VIDPID(0x0e6f, 0x02af),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b0),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b1),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b2),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b3),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b5),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b6),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b8),
|
||||
MAKE_VIDPID(0x0e6f, 0x02bd),
|
||||
MAKE_VIDPID(0x0e6f, 0x02be),
|
||||
MAKE_VIDPID(0x0e6f, 0x02bf),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c0),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c1),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c2),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c3),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c4),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c5),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c6),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c7),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c8),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c9),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ca),
|
||||
MAKE_VIDPID(0x0e6f, 0x02cb),
|
||||
MAKE_VIDPID(0x0e6f, 0x02cd),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ce),
|
||||
MAKE_VIDPID(0x0e6f, 0x02cf),
|
||||
MAKE_VIDPID(0x0e6f, 0x02d5),
|
||||
MAKE_VIDPID(0x0e6f, 0x0346),
|
||||
MAKE_VIDPID(0x0e6f, 0x0446),
|
||||
MAKE_VIDPID(0x0e6f, 0xf501),
|
||||
MAKE_VIDPID(0x0f0d, 0x0063),
|
||||
MAKE_VIDPID(0x0f0d, 0x0067),
|
||||
MAKE_VIDPID(0x0f0d, 0x0078),
|
||||
MAKE_VIDPID(0x0f0d, 0x0097),
|
||||
MAKE_VIDPID(0x0f0d, 0x00ba),
|
||||
MAKE_VIDPID(0x0f0d, 0x00c0),
|
||||
MAKE_VIDPID(0x0f0d, 0x00c5),
|
||||
MAKE_VIDPID(0x0f0d, 0x00d8),
|
||||
MAKE_VIDPID(0x0f0d, 0x00ed),
|
||||
MAKE_VIDPID(0x0fff, 0x02a1),
|
||||
MAKE_VIDPID(0x12ab, 0x0304),
|
||||
MAKE_VIDPID(0x1430, 0x0291),
|
||||
MAKE_VIDPID(0x1430, 0x02a9),
|
||||
MAKE_VIDPID(0x1430, 0x070b),
|
||||
MAKE_VIDPID(0x1430, 0x0719),
|
||||
MAKE_VIDPID(0x146b, 0x0611),
|
||||
MAKE_VIDPID(0x1532, 0x0a00),
|
||||
MAKE_VIDPID(0x1532, 0x0a03),
|
||||
MAKE_VIDPID(0x1532, 0x0a14),
|
||||
MAKE_VIDPID(0x1532, 0x0a15),
|
||||
MAKE_VIDPID(0x16d0, 0x0f3f),
|
||||
MAKE_VIDPID(0x1bad, 0x028e),
|
||||
MAKE_VIDPID(0x1bad, 0x02a0),
|
||||
MAKE_VIDPID(0x1bad, 0x5500),
|
||||
MAKE_VIDPID(0x20ab, 0x55ef),
|
||||
MAKE_VIDPID(0x24c6, 0x541a),
|
||||
MAKE_VIDPID(0x24c6, 0x542a),
|
||||
MAKE_VIDPID(0x24c6, 0x543a),
|
||||
MAKE_VIDPID(0x24c6, 0x5509),
|
||||
MAKE_VIDPID(0x24c6, 0x551a),
|
||||
MAKE_VIDPID(0x24c6, 0x561a),
|
||||
MAKE_VIDPID(0x24c6, 0x581a),
|
||||
MAKE_VIDPID(0x24c6, 0x591a),
|
||||
MAKE_VIDPID(0x24c6, 0x592a),
|
||||
MAKE_VIDPID(0x24c6, 0x791a),
|
||||
MAKE_VIDPID(0x2516, 0x0069),
|
||||
MAKE_VIDPID(0x25b1, 0x0360),
|
||||
MAKE_VIDPID(0x2c22, 0x2203),
|
||||
MAKE_VIDPID(0x2e24, 0x0652),
|
||||
MAKE_VIDPID(0x2e24, 0x1618),
|
||||
MAKE_VIDPID(0x2e24, 0x1688),
|
||||
MAKE_VIDPID(0x2f24, 0x0011),
|
||||
MAKE_VIDPID(0x2f24, 0x002e),
|
||||
MAKE_VIDPID(0x2f24, 0x0050),
|
||||
MAKE_VIDPID(0x2f24, 0x0053),
|
||||
MAKE_VIDPID(0x2f24, 0x008f),
|
||||
MAKE_VIDPID(0x2f24, 0x0091),
|
||||
MAKE_VIDPID(0x2f24, 0x00b7),
|
||||
MAKE_VIDPID(0xd2d2, 0xd2d2),
|
||||
};
|
||||
static SDL_vidpid_list old_xboxone_controllers = {
|
||||
"SDL_JOYSTICK_OLD_XBOXONE_CONTROLLERS", 0, 0, NULL,
|
||||
"SDL_JOYSTICK_OLD_XBOXONE_CONTROLLERS_EXCLUDED", 0, 0, NULL,
|
||||
SDL_arraysize(initial_old_xboxone_controllers), initial_old_xboxone_controllers,
|
||||
false
|
||||
};
|
||||
|
||||
static Uint32 initial_arcadestick_devices[] = {
|
||||
MAKE_VIDPID(0x0079, 0x181a), // Venom Arcade Stick
|
||||
MAKE_VIDPID(0x0079, 0x181b), // Venom Arcade Stick
|
||||
@@ -273,11 +440,17 @@ static Uint32 initial_blacklist_devices[] = {
|
||||
MAKE_VIDPID(0x04d9, 0x8009), // OBINLB USB-HID Keyboard (Anne Pro II)
|
||||
MAKE_VIDPID(0x04d9, 0xa292), // OBINLB USB-HID Keyboard (Anne Pro II)
|
||||
MAKE_VIDPID(0x04d9, 0xa293), // OBINLB USB-HID Keyboard (Anne Pro II)
|
||||
MAKE_VIDPID(0x04f2, 0xa13c), // HP Deluxe Webcam KQ246AA
|
||||
MAKE_VIDPID(0x0e6f, 0x018a), // PDP REALMz Wireless Controller for Switch, USB charging
|
||||
MAKE_VIDPID(0x1532, 0x0266), // Razer Huntsman V2 Analog, non-functional DInput device
|
||||
MAKE_VIDPID(0x1532, 0x0282), // Razer Huntsman Mini Analog, non-functional DInput device
|
||||
MAKE_VIDPID(0x26ce, 0x01a2), // ASRock LED Controller
|
||||
MAKE_VIDPID(0x20d6, 0x0002), // PowerA Enhanced Wireless Controller for Nintendo Switch (charging port only)
|
||||
MAKE_VIDPID(0x31e3, 0x1310), // Wooting 60HE (ARM)
|
||||
MAKE_VIDPID(0x3297, 0x1969), // Moonlander MK1 Keyboard
|
||||
MAKE_VIDPID(0x3434, 0x0211), // Keychron K1 Pro System Control
|
||||
MAKE_VIDPID(0x3434, 0x0353), // Keychron V5 System Control
|
||||
MAKE_VIDPID(0x3434, 0xd030), // Keychron Link
|
||||
};
|
||||
static SDL_vidpid_list blacklist_devices = {
|
||||
SDL_HINT_JOYSTICK_BLACKLIST_DEVICES, 0, 0, NULL,
|
||||
@@ -313,7 +486,14 @@ static SDL_vidpid_list flightstick_devices = {
|
||||
};
|
||||
|
||||
static Uint32 initial_gamecube_devices[] = {
|
||||
MAKE_VIDPID(0x0079, 0x1843), // DragonRise GameCube Controller Adapter
|
||||
MAKE_VIDPID(0x0079, 0x1844), // DragonRise GameCube Controller Adapter
|
||||
MAKE_VIDPID(0x0079, 0x1846), // DragonRise GameCube Controller Adapter
|
||||
MAKE_VIDPID(0x057e, 0x0337), // Nintendo Wii U GameCube Controller Adapter
|
||||
MAKE_VIDPID(0x057e, 0x2073), // Nintendo Switch 2 NSO GameCube Controller
|
||||
MAKE_VIDPID(0x0926, 0x8888), // Cyber Gadget GameCube Controller
|
||||
MAKE_VIDPID(0x0e6f, 0x0185), // PDP Wired Fight Pad Pro for Nintendo Switch
|
||||
MAKE_VIDPID(0x1a34, 0xf705), // GameCube {HuiJia USB box}
|
||||
MAKE_VIDPID(0x20d6, 0xa711), // PowerA Wired Controller Nintendo GameCube Style
|
||||
};
|
||||
static SDL_vidpid_list gamecube_devices = {
|
||||
@@ -440,18 +620,18 @@ static SDL_vidpid_list zero_centered_devices = {
|
||||
false
|
||||
};
|
||||
|
||||
#define CHECK_JOYSTICK_MAGIC(joystick, result) \
|
||||
if (!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \
|
||||
SDL_InvalidParamError("joystick"); \
|
||||
SDL_UnlockJoysticks(); \
|
||||
return result; \
|
||||
#define CHECK_JOYSTICK_MAGIC(joystick, result) \
|
||||
CHECK_PARAM(!SDL_ObjectValid(joystick, SDL_OBJECT_TYPE_JOYSTICK)) { \
|
||||
SDL_InvalidParamError("joystick"); \
|
||||
SDL_UnlockJoysticks(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \
|
||||
if (!joystick->is_virtual) { \
|
||||
SDL_SetError("joystick isn't virtual"); \
|
||||
SDL_UnlockJoysticks(); \
|
||||
return result; \
|
||||
#define CHECK_JOYSTICK_VIRTUAL(joystick, result) \
|
||||
CHECK_PARAM(!joystick->is_virtual) { \
|
||||
SDL_SetError("joystick isn't virtual"); \
|
||||
SDL_UnlockJoysticks(); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
bool SDL_JoysticksInitialized(void)
|
||||
@@ -656,8 +836,9 @@ bool SDL_InitJoysticks(void)
|
||||
|
||||
SDL_joysticks_initialized = true;
|
||||
|
||||
SDL_InitGamepadMappings();
|
||||
SDL_joystick_names = SDL_CreateHashTable(0, false, SDL_HashID, SDL_KeyMatchID, SDL_DestroyHashValue, NULL);
|
||||
|
||||
SDL_LoadVIDPIDList(&old_xboxone_controllers);
|
||||
SDL_LoadVIDPIDList(&arcadestick_devices);
|
||||
SDL_LoadVIDPIDList(&blacklist_devices);
|
||||
SDL_LoadVIDPIDList(&flightstick_devices);
|
||||
@@ -667,6 +848,8 @@ bool SDL_InitJoysticks(void)
|
||||
SDL_LoadVIDPIDList(&wheel_devices);
|
||||
SDL_LoadVIDPIDList(&zero_centered_devices);
|
||||
|
||||
SDL_InitGamepadMappings();
|
||||
|
||||
// See if we should allow joystick events while in the background
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
|
||||
SDL_JoystickAllowBackgroundEventsChanged, NULL);
|
||||
@@ -802,20 +985,54 @@ const SDL_SteamVirtualGamepadInfo *SDL_GetJoystickVirtualGamepadInfoForID(SDL_Jo
|
||||
/*
|
||||
* Get the implementation dependent name of a joystick
|
||||
*/
|
||||
const char *SDL_GetJoystickNameForID(SDL_JoystickID instance_id)
|
||||
static const char *SDL_UpdateJoystickNameForID(SDL_JoystickID instance_id)
|
||||
{
|
||||
SDL_JoystickDriver *driver;
|
||||
int device_index;
|
||||
const char *name = NULL;
|
||||
const char *current_name = NULL;
|
||||
const SDL_SteamVirtualGamepadInfo *info;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id);
|
||||
if (info) {
|
||||
name = SDL_GetPersistentString(info->name);
|
||||
current_name = info->name;
|
||||
} else if (SDL_GetDriverAndJoystickIndex(instance_id, &driver, &device_index)) {
|
||||
name = SDL_GetPersistentString(driver->GetDeviceName(device_index));
|
||||
current_name = driver->GetDeviceName(device_index);
|
||||
}
|
||||
|
||||
if (!SDL_joystick_names) {
|
||||
return SDL_GetPersistentString(current_name);
|
||||
}
|
||||
|
||||
char *name = NULL;
|
||||
bool found = SDL_FindInHashTable(SDL_joystick_names, (const void *)(uintptr_t)instance_id, (const void **)&name);
|
||||
if (!current_name) {
|
||||
if (!found) {
|
||||
SDL_SetError("Joystick %" SDL_PRIu32 " not found", instance_id);
|
||||
return NULL;
|
||||
}
|
||||
if (!name) {
|
||||
// SDL_strdup() failed during insert
|
||||
SDL_OutOfMemory();
|
||||
return NULL;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
if (!name || SDL_strcmp(name, current_name) != 0) {
|
||||
name = SDL_strdup(current_name);
|
||||
SDL_InsertIntoHashTable(SDL_joystick_names, (const void *)(uintptr_t)instance_id, name, true);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *SDL_GetJoystickNameForID(SDL_JoystickID instance_id)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
name = SDL_UpdateJoystickNameForID(instance_id);
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return name;
|
||||
@@ -865,6 +1082,8 @@ static bool SDL_JoystickAxesCenteredAtZero(SDL_Joystick *joystick)
|
||||
{
|
||||
// printf("JOYSTICK '%s' VID/PID 0x%.4x/0x%.4x AXES: %d\n", joystick->name, vendor, product, joystick->naxes);
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
if (joystick->naxes == 2) {
|
||||
// Assume D-pad or thumbstick style axes are centered at 0
|
||||
return true;
|
||||
@@ -1144,8 +1363,6 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
|
||||
joystick->battery_percent = -1;
|
||||
#ifdef SDL_JOYSTICK_VIRTUAL
|
||||
joystick->is_virtual = (driver == &SDL_VIRTUAL_JoystickDriver);
|
||||
#else
|
||||
joystick->is_virtual = false;
|
||||
#endif
|
||||
|
||||
if (!driver->Open(joystick, device_index)) {
|
||||
@@ -1483,9 +1700,17 @@ int SDL_GetNumJoystickHats(SDL_Joystick *joystick)
|
||||
*/
|
||||
int SDL_GetNumJoystickBalls(SDL_Joystick *joystick)
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, -1);
|
||||
int result;
|
||||
|
||||
return joystick->nballs;
|
||||
SDL_LockJoysticks();
|
||||
{
|
||||
CHECK_JOYSTICK_MAGIC(joystick, -1);
|
||||
|
||||
result = joystick->nballs;
|
||||
}
|
||||
SDL_UnlockJoysticks();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2046,6 +2271,7 @@ void SDL_QuitJoysticks(void)
|
||||
SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,
|
||||
SDL_JoystickAllowBackgroundEventsChanged, NULL);
|
||||
|
||||
SDL_FreeVIDPIDList(&old_xboxone_controllers);
|
||||
SDL_FreeVIDPIDList(&arcadestick_devices);
|
||||
SDL_FreeVIDPIDList(&blacklist_devices);
|
||||
SDL_FreeVIDPIDList(&flightstick_devices);
|
||||
@@ -2057,6 +2283,11 @@ void SDL_QuitJoysticks(void)
|
||||
|
||||
SDL_QuitGamepadMappings();
|
||||
|
||||
if (SDL_joystick_names) {
|
||||
SDL_DestroyHashTable(SDL_joystick_names);
|
||||
SDL_joystick_names = NULL;
|
||||
}
|
||||
|
||||
SDL_joysticks_quitting = false;
|
||||
SDL_joysticks_initialized = false;
|
||||
|
||||
@@ -2166,6 +2397,8 @@ void SDL_PrivateJoystickAdded(SDL_JoystickID instance_id)
|
||||
SDL_SetJoystickIDForPlayerIndex(player_index, instance_id);
|
||||
}
|
||||
|
||||
SDL_UpdateJoystickNameForID(instance_id);
|
||||
|
||||
{
|
||||
SDL_Event event;
|
||||
|
||||
@@ -2459,6 +2692,8 @@ static void SendSteamHandleUpdateEvents(void)
|
||||
SDL_Joystick *joystick;
|
||||
const SDL_SteamVirtualGamepadInfo *info;
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
// Check to see if any Steam handles changed
|
||||
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
|
||||
bool changed = false;
|
||||
@@ -2499,7 +2734,7 @@ void SDL_UpdateJoysticks(void)
|
||||
Uint64 now;
|
||||
SDL_Joystick *joystick;
|
||||
|
||||
if (!SDL_WasInit(SDL_INIT_JOYSTICK)) {
|
||||
if (!SDL_joysticks_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2779,10 +3014,14 @@ SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, cons
|
||||
} else if (vendor == 0x0001 && product == 0x0001) {
|
||||
type = SDL_GAMEPAD_TYPE_STANDARD;
|
||||
|
||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) {
|
||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||
(product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT ||
|
||||
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT)) {
|
||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT;
|
||||
|
||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT) {
|
||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||
(product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT ||
|
||||
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT)) {
|
||||
if (name && SDL_strstr(name, "NES Controller") != NULL) {
|
||||
// We don't have a type for the Nintendo Online NES Controller
|
||||
type = SDL_GAMEPAD_TYPE_STANDARD;
|
||||
@@ -2797,12 +3036,13 @@ SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, cons
|
||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT;
|
||||
}
|
||||
|
||||
} else if (vendor == USB_VENDOR_NINTENDO && product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR) {
|
||||
} else if (vendor == USB_VENDOR_NINTENDO &&
|
||||
(product == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ||
|
||||
product == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR)) {
|
||||
type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||
|
||||
} else if (forUI && SDL_IsJoystickGameCube(vendor, product)) {
|
||||
// We don't have a type for the Nintendo GameCube controller
|
||||
type = SDL_GAMEPAD_TYPE_STANDARD;
|
||||
type = SDL_GAMEPAD_TYPE_GAMECUBE;
|
||||
|
||||
} else {
|
||||
switch (GuessControllerType(vendor, product)) {
|
||||
@@ -2904,78 +3144,12 @@ bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
|
||||
|
||||
bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_MICROSOFT) {
|
||||
if (product_id == USB_PRODUCT_XBOX_SERIES_X ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) {
|
||||
return true;
|
||||
}
|
||||
// Most new controllers have the share button, so we'll default to true and
|
||||
// have a list of older XBox One controllers that are known not to have it.
|
||||
if (SDL_VIDPIDInList(vendor_id, product_id, &old_xboxone_controllers)) {
|
||||
return false;
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_PDP) {
|
||||
if (product_id == USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_POWERA_ALT) {
|
||||
if ((product_id >= 0x2001 && product_id <= 0x201a) ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO4 ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO_WIRELESS_USB ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO_WIRELESS_DONGLE ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_MOGA_XP_ULTRA ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_HORI) {
|
||||
if (product_id == USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X ||
|
||||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X ||
|
||||
product_id == USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_HP) {
|
||||
if (product_id == USB_PRODUCT_XBOX_SERIES_X_HP_HYPERX ||
|
||||
product_id == USB_PRODUCT_XBOX_SERIES_X_HP_HYPERX_RGB) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_RAZER) {
|
||||
if (product_id == USB_PRODUCT_RAZER_WOLVERINE_V2 ||
|
||||
product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_CHROMA ||
|
||||
product_id == USB_PRODUCT_RAZER_WOLVERINE_V3_PRO) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_THRUSTMASTER) {
|
||||
if (product_id == USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_SERIES_X) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_TURTLE_BEACH) {
|
||||
if (product_id == USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R ||
|
||||
product_id == USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_8BITDO) {
|
||||
if (product_id == USB_PRODUCT_8BITDO_XBOX_CONTROLLER1 ||
|
||||
product_id == USB_PRODUCT_8BITDO_XBOX_CONTROLLER2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_GAMESIR) {
|
||||
if (product_id == USB_PRODUCT_GAMESIR_G7) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_ASUS) {
|
||||
if (product_id == USB_PRODUCT_ROG_RAIKIRI) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickBluetoothXboxOne(Uint16 vendor_id, Uint16 product_id)
|
||||
@@ -3054,7 +3228,9 @@ bool SDL_IsJoystickNintendoSwitchJoyConGrip(Uint16 vendor_id, Uint16 product_id)
|
||||
|
||||
bool SDL_IsJoystickNintendoSwitchJoyConPair(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||
return vendor_id == USB_VENDOR_NINTENDO &&
|
||||
(product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ||
|
||||
product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR);
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id)
|
||||
@@ -3100,12 +3276,47 @@ bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id)
|
||||
return vendor_id == USB_VENDOR_HORI && (product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER || product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT);
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickSInputController(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_RASPBERRYPI) {
|
||||
if (product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC ||
|
||||
product_id == USB_PRODUCT_HANDHELDLEGEND_PROGCC ||
|
||||
product_id == USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE ||
|
||||
product_id == USB_PRODUCT_BONZIRICHANNEL_FIREBIRD ||
|
||||
product_id == USB_PRODUCT_VOIDGAMING_PS4FIREBIRD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickFlydigiController(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_FLYDIGI_V1) {
|
||||
if (product_id == USB_PRODUCT_FLYDIGI_V1_GAMEPAD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_FLYDIGI_V2) {
|
||||
if (product_id == USB_PRODUCT_FLYDIGI_V2_APEX || product_id == USB_PRODUCT_FLYDIGI_V2_VADER) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
EControllerType eType = GuessControllerType(vendor_id, product_id);
|
||||
return eType == k_eControllerType_SteamControllerNeptune;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickSteamTriton(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
EControllerType eType = GuessControllerType(vendor_id, product_id);
|
||||
return eType == k_eControllerType_SteamControllerTriton;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickXInput(SDL_GUID guid)
|
||||
{
|
||||
return (guid.data[14] == 'x') ? true : false;
|
||||
@@ -3136,7 +3347,7 @@ bool SDL_IsJoystickVIRTUAL(SDL_GUID guid)
|
||||
return (guid.data[14] == 'v') ? true : false;
|
||||
}
|
||||
|
||||
static bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id)
|
||||
bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
return SDL_VIDPIDInList(vendor_id, product_id, &wheel_devices);
|
||||
}
|
||||
@@ -3672,9 +3883,7 @@ static void SDL_LoadVIDPIDListFromHint(const char *hint, int *num_entries, int *
|
||||
(*entries)[(*num_entries)++] = entry;
|
||||
}
|
||||
|
||||
if (file) {
|
||||
SDL_free(file);
|
||||
}
|
||||
SDL_free(file);
|
||||
}
|
||||
|
||||
void SDL_LoadVIDPIDListFromHints(SDL_vidpid_list *list, const char *included_list, const char *excluded_list)
|
||||
@@ -3752,9 +3961,15 @@ void SDL_LoadVIDPIDList(SDL_vidpid_list *list)
|
||||
|
||||
if (list->included_hint_name) {
|
||||
included_list = SDL_GetHint(list->included_hint_name);
|
||||
if (!included_list) {
|
||||
included_list = SDL_getenv_unsafe(list->included_hint_name);
|
||||
}
|
||||
}
|
||||
if (list->excluded_hint_name) {
|
||||
excluded_list = SDL_GetHint(list->excluded_hint_name);
|
||||
if (!excluded_list) {
|
||||
excluded_list = SDL_getenv_unsafe(list->excluded_hint_name);
|
||||
}
|
||||
}
|
||||
SDL_LoadVIDPIDListFromHints(list, included_list, excluded_list);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -135,9 +135,18 @@ extern bool SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id);
|
||||
// Function to return whether a joystick is a HORI Steam controller
|
||||
extern bool SDL_IsJoystickHoriSteamController(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick is an SInput (Open Format) controller
|
||||
extern bool SDL_IsJoystickSInputController(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick is a Flydigi controller
|
||||
extern bool SDL_IsJoystickFlydigiController(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick is a Steam Deck
|
||||
extern bool SDL_IsJoystickSteamDeck(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick is a Steam Triton
|
||||
extern bool SDL_IsJoystickSteamTriton(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick guid comes from the XInput driver
|
||||
extern bool SDL_IsJoystickXInput(SDL_GUID guid);
|
||||
|
||||
@@ -156,6 +165,9 @@ extern bool SDL_IsJoystickRAWINPUT(SDL_GUID guid);
|
||||
// Function to return whether a joystick guid comes from the Virtual driver
|
||||
extern bool SDL_IsJoystickVIRTUAL(SDL_GUID guid);
|
||||
|
||||
// Function to return whether a joystick is a wheel
|
||||
bool SDL_IsJoystickWheel(Uint16 vendor_id, Uint16 product_id);
|
||||
|
||||
// Function to return whether a joystick should be ignored
|
||||
extern bool SDL_ShouldIgnoreJoystick(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "SDL_joystick_c.h"
|
||||
#include "SDL_steam_virtual_gamepad.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_LINUX
|
||||
#include "../core/unix/SDL_appid.h"
|
||||
#endif
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
#include "../core/windows/SDL_windows.h"
|
||||
#else
|
||||
@@ -30,8 +33,6 @@
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#define SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE "SteamVirtualGamepadInfo"
|
||||
|
||||
static char *SDL_steam_virtual_gamepad_info_file SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
static Uint64 SDL_steam_virtual_gamepad_info_file_mtime SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
static Uint64 SDL_steam_virtual_gamepad_info_check_time SDL_GUARDED_BY(SDL_joystick_lock) = 0;
|
||||
@@ -132,8 +133,17 @@ void SDL_InitSteamVirtualGamepadInfo(void)
|
||||
return;
|
||||
}
|
||||
|
||||
file = SDL_GetHint(SDL_HINT_STEAM_VIRTUAL_GAMEPAD_INFO_FILE);
|
||||
file = SDL_getenv_unsafe("SteamVirtualGamepadInfo");
|
||||
if (file && *file) {
|
||||
#ifdef SDL_PLATFORM_LINUX
|
||||
// Older versions of Wine will blacklist the Steam Virtual Gamepad if
|
||||
// it appears to have the real controller's VID/PID, so ignore this.
|
||||
const char *exe = SDL_GetExeName();
|
||||
if (exe && SDL_strcmp(exe, "wine64-preloader") == 0) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Wine launched by Steam, ignoring SteamVirtualGamepadInfo");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SDL_steam_virtual_gamepad_info_file = SDL_strdup(file);
|
||||
}
|
||||
SDL_UpdateSteamVirtualGamepadInfo();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -106,7 +106,8 @@ static int keycode_to_SDL(int keycode)
|
||||
button = SDL_GAMEPAD_BUTTON_GUIDE;
|
||||
break;
|
||||
case AKEYCODE_BUTTON_L2:
|
||||
button = 15;
|
||||
case AKEYCODE_MEDIA_RECORD:
|
||||
button = SDL_GAMEPAD_BUTTON_MISC1;
|
||||
break;
|
||||
case AKEYCODE_BUTTON_R2:
|
||||
button = 16;
|
||||
@@ -305,7 +306,7 @@ bool Android_OnHat(int device_id, int hat_id, int x, int y)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble)
|
||||
void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble, bool has_rgb_led)
|
||||
{
|
||||
SDL_joylist_item *item;
|
||||
SDL_GUID guid;
|
||||
@@ -328,6 +329,10 @@ void Android_AddJoystick(int device_id, const char *name, const char *desc, int
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (SDL_ShouldIgnoreJoystick(vendor_id, product_id, 0, name)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_JOYSTICK
|
||||
SDL_Log("Joystick: %s, descriptor %s, vendor = 0x%.4x, product = 0x%.4x, %d axes, %d hats", name, desc, vendor_id, product_id, naxes, nhats);
|
||||
#endif
|
||||
@@ -376,6 +381,7 @@ void Android_AddJoystick(int device_id, const char *name, const char *desc, int
|
||||
item->naxes = naxes;
|
||||
item->nhats = nhats;
|
||||
item->can_rumble = can_rumble;
|
||||
item->has_rgb_led = has_rgb_led;
|
||||
item->device_instance = SDL_GetNextObjectID();
|
||||
if (!SDL_joylist_tail) {
|
||||
SDL_joylist = SDL_joylist_tail = item;
|
||||
@@ -577,6 +583,10 @@ static bool ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
|
||||
}
|
||||
|
||||
if (item->has_rgb_led) {
|
||||
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -603,7 +613,15 @@ static bool ANDROID_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_r
|
||||
|
||||
static bool ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
|
||||
if (!item) {
|
||||
return SDL_SetError("SetLED failed, device disconnected");
|
||||
}
|
||||
if (!item->has_rgb_led) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
Android_JNI_JoystickSetLED(item->device_id, red, green, blue);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -32,7 +32,7 @@ extern bool Android_OnPadDown(int device_id, int keycode);
|
||||
extern bool Android_OnPadUp(int device_id, int keycode);
|
||||
extern bool Android_OnJoy(int device_id, int axisnum, float value);
|
||||
extern bool Android_OnHat(int device_id, int hat_id, int x, int y);
|
||||
extern void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble);
|
||||
extern void Android_AddJoystick(int device_id, const char *name, const char *desc, int vendor_id, int product_id, int button_mask, int naxes, int axis_mask, int nhats, bool can_rumble, bool has_rgb_led);
|
||||
extern void Android_RemoveJoystick(int device_id);
|
||||
|
||||
// A linked list of available joysticks
|
||||
@@ -46,6 +46,7 @@ typedef struct SDL_joylist_item
|
||||
int nbuttons, naxes, nhats;
|
||||
int dpad_state;
|
||||
bool can_rumble;
|
||||
bool has_rgb_led;
|
||||
|
||||
struct SDL_joylist_item *next;
|
||||
} SDL_joylist_item;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -27,6 +27,10 @@
|
||||
#include "../usb_ids.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_UIKIT
|
||||
#include "../../video/uikit/SDL_uikitvideo.h"
|
||||
#endif
|
||||
|
||||
#include "SDL_mfijoystick_c.h"
|
||||
|
||||
|
||||
@@ -158,6 +162,13 @@ static bool IsControllerSwitchJoyConPair(GCController *controller)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static bool IsControllerNVIDIASHIELD(GCController *controller)
|
||||
{
|
||||
if ([controller.vendorName hasPrefix:@"NVIDIA Controller"]) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static bool IsControllerStadia(GCController *controller)
|
||||
{
|
||||
if ([controller.vendorName hasPrefix:@"Stadia"]) {
|
||||
@@ -302,6 +313,12 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
|
||||
if (controller.vendorName) {
|
||||
name = controller.vendorName.UTF8String;
|
||||
} else {
|
||||
if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
|
||||
if (controller.productCategory) {
|
||||
name = controller.productCategory.UTF8String;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
@@ -314,7 +331,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
NSLog(@"Product name: %@\n", controller.vendorName);
|
||||
NSLog(@"Product category: %@\n", controller.productCategory);
|
||||
NSLog(@"Elements available:\n");
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
||||
for (id key in controller.physicalInputProfile.buttons) {
|
||||
NSLog(@"\tButton: %@ (%s)\n", key, elements[key].analog ? "analog" : "digital");
|
||||
@@ -333,6 +350,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
device->is_ps5 = IsControllerPS5(controller);
|
||||
device->is_switch_pro = IsControllerSwitchPro(controller);
|
||||
device->is_switch_joycon_pair = IsControllerSwitchJoyConPair(controller);
|
||||
device->is_shield = IsControllerNVIDIASHIELD(controller);
|
||||
device->is_stadia = IsControllerStadia(controller);
|
||||
device->is_backbone_one = IsControllerBackboneOne(controller);
|
||||
device->is_switch_joyconL = IsControllerSwitchJoyConL(controller);
|
||||
@@ -344,9 +362,18 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
(device->is_ps5 && HIDAPI_IsDeviceTypePresent(SDL_GAMEPAD_TYPE_PS5)) ||
|
||||
(device->is_switch_pro && HIDAPI_IsDeviceTypePresent(SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO)) ||
|
||||
(device->is_switch_joycon_pair && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR, 0, "")) ||
|
||||
(device->is_shield && HIDAPI_IsDevicePresent(USB_VENDOR_NVIDIA, USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104, 0, "")) ||
|
||||
(device->is_stadia && HIDAPI_IsDevicePresent(USB_VENDOR_GOOGLE, USB_PRODUCT_GOOGLE_STADIA_CONTROLLER, 0, "")) ||
|
||||
(device->is_switch_joyconL && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT, 0, "")) ||
|
||||
(device->is_switch_joyconR && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT, 0, ""))) {
|
||||
(device->is_switch_joyconR && HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT, 0, "")) ||
|
||||
(SDL_strstr(name, "GameCube Controller Adapter") &&
|
||||
(HIDAPI_IsDevicePresent(USB_VENDOR_NINTENDO, USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER, 0, "") ||
|
||||
HIDAPI_IsDevicePresent(USB_VENDOR_DRAGONRISE, USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER1, 0, "") ||
|
||||
HIDAPI_IsDevicePresent(USB_VENDOR_DRAGONRISE, USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2, 0, "") ||
|
||||
HIDAPI_IsDevicePresent(USB_VENDOR_DRAGONRISE, USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER3, 0, ""))) ||
|
||||
(SDL_strcmp(name, "8Bitdo SN30 Pro") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_SN30_PRO_BT, 0, ""))) ||
|
||||
(SDL_strcmp(name, "8BitDo Pro 2") == 0 && (HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2, 0, "") || HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_PRO_2_BT, 0, ""))) ||
|
||||
(SDL_startswith(name, "8BitDo Ultimate 2 Wireless") && HIDAPI_IsDevicePresent(USB_VENDOR_8BITDO, USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS, 0, ""))) {
|
||||
// The HIDAPI driver is taking care of this device
|
||||
return false;
|
||||
}
|
||||
@@ -362,7 +389,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (controller.physicalInputProfile.buttons[GCInputDualShockTouchpadButton] != nil) {
|
||||
device->has_dualshock_touchpad = TRUE;
|
||||
}
|
||||
@@ -417,7 +444,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
} else if (device->is_switch_joyconR) {
|
||||
vendor = USB_VENDOR_NINTENDO;
|
||||
product = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT;
|
||||
} else if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
} else if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
vendor = USB_VENDOR_APPLE;
|
||||
product = 4;
|
||||
subtype = 4;
|
||||
@@ -440,7 +467,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
||||
|
||||
// Provide both axes and analog buttons as SDL axes
|
||||
@@ -480,7 +507,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
subtype = 4;
|
||||
|
||||
#ifdef DEBUG_CONTROLLER_PROFILE
|
||||
NSLog(@"Elements used:\n", controller.vendorName);
|
||||
NSLog(@"Elements used:\n");
|
||||
for (id key in device->buttons) {
|
||||
NSLog(@"\tButton: %@ (%s)\n", key, elements[key].analog ? "analog" : "digital");
|
||||
}
|
||||
@@ -571,7 +598,7 @@ static bool IOS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCControlle
|
||||
}
|
||||
|
||||
Uint16 signature;
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
signature = 0;
|
||||
signature = SDL_crc16(signature, device->name, SDL_strlen(device->name));
|
||||
for (id key in device->axes) {
|
||||
@@ -725,7 +752,7 @@ static bool IOS_JoystickInit(void)
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_MACOS
|
||||
if (@available(macOS 10.16, *)) {
|
||||
if (@available(macOS 11.0, *)) {
|
||||
// Continue with initialization on macOS 11+
|
||||
} else {
|
||||
return true;
|
||||
@@ -782,6 +809,10 @@ static bool IOS_JoystickInit(void)
|
||||
SDL_UnlockJoysticks();
|
||||
}];
|
||||
#endif // SDL_JOYSTICK_MFI
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_UIKIT
|
||||
UIKit_SetGameControllerInteraction(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -887,7 +918,7 @@ static bool IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
};
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = joystick->hwdata->controller;
|
||||
GCMotion *motion = controller.motion;
|
||||
if (motion && motion.hasRotationRate) {
|
||||
@@ -898,7 +929,7 @@ static bool IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = joystick->hwdata->controller;
|
||||
for (id key in controller.physicalInputProfile.buttons) {
|
||||
GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key];
|
||||
@@ -908,7 +939,7 @@ static bool IOS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = device->controller;
|
||||
if (controller.light) {
|
||||
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RGB_LED_BOOLEAN, true);
|
||||
@@ -969,7 +1000,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
#ifdef DEBUG_CONTROLLER_STATE
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (controller.physicalInputProfile) {
|
||||
for (id key in controller.physicalInputProfile.buttons) {
|
||||
GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key];
|
||||
@@ -995,7 +1026,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
}
|
||||
#endif // DEBUG_CONTROLLER_STATE
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
||||
NSDictionary<NSString *, GCControllerButtonInput *> *buttons = controller.physicalInputProfile.buttons;
|
||||
|
||||
@@ -1125,7 +1156,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (device->has_dualshock_touchpad) {
|
||||
GCControllerDirectionPad *dpad;
|
||||
|
||||
@@ -1145,7 +1176,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCMotion *motion = controller.motion;
|
||||
if (motion && motion.sensorsActive) {
|
||||
float data[3];
|
||||
@@ -1167,7 +1198,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCDeviceBattery *battery = controller.battery;
|
||||
if (battery) {
|
||||
SDL_PowerState state = SDL_POWERSTATE_UNKNOWN;
|
||||
@@ -1196,8 +1227,8 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
@interface SDL3_RumbleMotor : NSObject
|
||||
@property(nonatomic, strong) CHHapticEngine *engine API_AVAILABLE(macos(10.16), ios(13.0), tvos(14.0));
|
||||
@property(nonatomic, strong) id<CHHapticPatternPlayer> player API_AVAILABLE(macos(10.16), ios(13.0), tvos(14.0));
|
||||
@property(nonatomic, strong) CHHapticEngine *engine API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0));
|
||||
@property(nonatomic, strong) id<CHHapticPatternPlayer> player API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0));
|
||||
@property bool active;
|
||||
@end
|
||||
|
||||
@@ -1208,7 +1239,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
- (void)cleanup
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (self.player != nil) {
|
||||
[self.player cancelAndReturnError:nil];
|
||||
self.player = nil;
|
||||
@@ -1224,7 +1255,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
- (bool)setIntensity:(float)intensity
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
NSError *error = nil;
|
||||
CHHapticDynamicParameter *param;
|
||||
|
||||
@@ -1271,7 +1302,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
}
|
||||
}
|
||||
|
||||
- (id)initWithController:(GCController *)controller locality:(GCHapticsLocality)locality API_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0))
|
||||
- (id)initWithController:(GCController *)controller locality:(GCHapticsLocality)locality API_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0))
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSError *error;
|
||||
@@ -1373,7 +1404,7 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
|
||||
static SDL3_RumbleContext *IOS_JoystickInitRumble(GCController *controller)
|
||||
{
|
||||
@autoreleasepool {
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
SDL3_RumbleMotor *low_frequency_motor = [[SDL3_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityLeftHandle];
|
||||
SDL3_RumbleMotor *high_frequency_motor = [[SDL3_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityRightHandle];
|
||||
SDL3_RumbleMotor *left_trigger_motor = [[SDL3_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityLeftTrigger];
|
||||
@@ -1400,7 +1431,7 @@ static bool IOS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumb
|
||||
return SDL_SetError("Controller is no longer connected");
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (!device->rumble && device->controller && device->controller.haptics) {
|
||||
SDL3_RumbleContext *rumble = IOS_JoystickInitRumble(device->controller);
|
||||
if (rumble) {
|
||||
@@ -1426,7 +1457,7 @@ static bool IOS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumbl
|
||||
return SDL_SetError("Controller is no longer connected");
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (!device->rumble && device->controller && device->controller.haptics) {
|
||||
SDL3_RumbleContext *rumble = IOS_JoystickInitRumble(device->controller);
|
||||
if (rumble) {
|
||||
@@ -1452,7 +1483,7 @@ static bool IOS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, U
|
||||
return SDL_SetError("Controller is no longer connected");
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = device->controller;
|
||||
GCDeviceLight *light = controller.light;
|
||||
if (light) {
|
||||
@@ -1480,7 +1511,7 @@ static bool IOS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled)
|
||||
return SDL_SetError("Controller is no longer connected");
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = device->controller;
|
||||
GCMotion *motion = controller.motion;
|
||||
if (motion) {
|
||||
@@ -1531,7 +1562,7 @@ static void IOS_JoystickClose(SDL_Joystick *joystick)
|
||||
controller.controllerPausedHandler = nil;
|
||||
controller.playerIndex = -1;
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
for (id key in controller.physicalInputProfile.buttons) {
|
||||
GCControllerButtonInput *button = controller.physicalInputProfile.buttons[key];
|
||||
if ([button isBoundToSystemGesture]) {
|
||||
@@ -1573,6 +1604,10 @@ static void IOS_JoystickQuit(void)
|
||||
while (deviceList != NULL) {
|
||||
IOS_RemoveJoystickDevice(deviceList);
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_UIKIT
|
||||
UIKit_SetGameControllerInteraction(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
numjoysticks = 0;
|
||||
@@ -1585,7 +1620,7 @@ static bool IOS_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
int axis = 0;
|
||||
for (id key in device->axes) {
|
||||
if ([(NSString *)key isEqualToString:@"Left Thumbstick X Axis"] ||
|
||||
@@ -1722,7 +1757,7 @@ bool IOS_SupportedHIDDevice(IOHIDDeviceRef device)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (@available(macOS 10.16, *)) {
|
||||
if (@available(macOS 11.0, *)) {
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
||||
if ([GCController supportsHIDDevice:device]) {
|
||||
@@ -1741,7 +1776,7 @@ bool IOS_SupportedHIDDevice(IOHIDDeviceRef device)
|
||||
/* NOLINTNEXTLINE(readability-non-const-parameter): getCString takes a non-const char* */
|
||||
static void GetAppleSFSymbolsNameForElement(GCControllerElement *element, char *name)
|
||||
{
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (element) {
|
||||
[element.sfSymbolsName getCString:name maxLength:255 encoding:NSASCIIStringEncoding];
|
||||
}
|
||||
@@ -1750,7 +1785,7 @@ static void GetAppleSFSymbolsNameForElement(GCControllerElement *element, char *
|
||||
|
||||
static GCControllerDirectionPad *GetDirectionalPadForController(GCController *controller)
|
||||
{
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
return controller.physicalInputProfile.dpads[GCInputDirectionPad];
|
||||
}
|
||||
|
||||
@@ -1773,7 +1808,7 @@ const char *IOS_GetAppleSFSymbolsNameForButton(SDL_Gamepad *gamepad, SDL_Gamepad
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
if (gamepad && SDL_GetGamepadJoystick(gamepad)->driver == &SDL_IOS_JoystickDriver) {
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = SDL_GetGamepadJoystick(gamepad)->hwdata->controller;
|
||||
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
||||
switch (button) {
|
||||
@@ -1889,7 +1924,7 @@ const char *IOS_GetAppleSFSymbolsNameForAxis(SDL_Gamepad *gamepad, SDL_GamepadAx
|
||||
|
||||
#ifdef SDL_JOYSTICK_MFI
|
||||
if (gamepad && SDL_GetGamepadJoystick(gamepad)->driver == &SDL_IOS_JoystickDriver) {
|
||||
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
|
||||
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
|
||||
GCController *controller = SDL_GetGamepadJoystick(gamepad)->hwdata->controller;
|
||||
NSDictionary<NSString *, GCControllerElement *> *elements = controller.physicalInputProfile.elements;
|
||||
switch (axis) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -53,6 +53,7 @@ typedef struct joystick_hwdata
|
||||
bool is_switch_joycon_pair;
|
||||
bool is_switch_joyconL;
|
||||
bool is_switch_joyconR;
|
||||
bool is_shield;
|
||||
bool is_stadia;
|
||||
bool is_backbone_one;
|
||||
int is_siri_remote;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -710,10 +710,10 @@ static void BSD_JoystickUpdate(SDL_Joystick *joy)
|
||||
//default:
|
||||
// no-op
|
||||
}
|
||||
SDL_PrivateJoystickHat(joy, 0, (dpad[0] * HAT_UP) |
|
||||
(dpad[1] * HAT_DOWN) |
|
||||
(dpad[2] * HAT_RIGHT) |
|
||||
(dpad[3] * HAT_LEFT) );
|
||||
SDL_SendJoystickHat(timestamp, joy, 0, (dpad[0] * HAT_UP) |
|
||||
(dpad[1] * HAT_DOWN) |
|
||||
(dpad[2] * HAT_RIGHT) |
|
||||
(dpad[3] * HAT_LEFT) );
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -159,6 +159,8 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x100b ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x100c ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wireless)
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1012 ), k_eControllerType_PS5Controller, NULL }, // Razer Kitsune
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1024 ), k_eControllerType_PS5Controller, NULL }, // Razer Raiju V5 Pro (PS5 mode wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1026 ), k_eControllerType_PS5Controller, NULL }, // Razer Raiju V5 Pro (PS5 mode with dongle)
|
||||
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d18 ), k_eControllerType_PS5Controller, NULL }, // NACON Revolution 5 Pro (PS5 mode with dongle)
|
||||
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d19 ), k_eControllerType_PS5Controller, NULL }, // NACON Revolution 5 Pro (PS5 mode wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x358a, 0x0104 ), k_eControllerType_PS5Controller, NULL }, // Backbone One PlayStation Edition for iOS
|
||||
@@ -418,7 +420,7 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2012 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Cuphead EnWired Controller - Mugman
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2015 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Blue Hint
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2016 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Green Hint
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2017 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Cntroller - Arctic Camo
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2017 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Arctic Camo
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2018 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Arc Lightning
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2019 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Royal Purple
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x201a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Nebula
|
||||
@@ -435,14 +437,14 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x592a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Spectra Pro
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x791a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Fusion Fight Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x2002 ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate Wired Controller for Xbox
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x3106 ), k_eControllerType_XBoxOneController, NULL }, // 8Bitdo Ultimate Wired Controller. Windows, Android, Switch.
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x3106 ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate Wired Controller. Windows, Android, Switch.
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x310a ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate 2C Wireless Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2e24, 0x0652 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
|
||||
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1618 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
|
||||
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1688 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin X91
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0611 ), k_eControllerType_XBoxOneController, NULL }, // Xbox Controller Mode for NACON Revolution 3
|
||||
|
||||
// These have been added via Minidump for unrecognized Xinput controller assert
|
||||
{ MAKE_CONTROLLER_ID( 0x0000, 0x0000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a2 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller - Microsoft VID
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1414 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0159 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
@@ -468,7 +470,6 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0x0291 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d3 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00b1 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0001, 0x0001 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x188e ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x187c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x189c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
@@ -481,10 +482,8 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xed ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xc0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x152 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a7 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x46d, 0x1007 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x79, 0x18a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
|
||||
// Added from Minidumps 10-9-19
|
||||
@@ -525,14 +524,7 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe00, 0xe00 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x12a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a5 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2bd ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2bf ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2c0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2c6 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0x97 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xba ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xd8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
@@ -549,8 +541,11 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0002 ), k_eControllerType_AppleController, NULL }, // MFI Standard Gamepad (generic entry for iOS/tvOS)
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch Joy-Con (Left)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2067 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch 2 Joy-Con (Left)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch Joy-Con (Right)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2066 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch 2 Joy-Con (Right)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2008 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch Joy-Con (Left+Right Combined)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2068 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch 2 Joy-Con (Left+Right Combined)
|
||||
|
||||
// This same controller ID is spoofed by many 3rd-party Switch controllers.
|
||||
// The ones we currently know of are:
|
||||
@@ -559,6 +554,7 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
// * ZhiXu Gamepad Wireless
|
||||
// * Sunwaytek Wireless Motion Controller for Nintendo Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2009 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch Pro Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2069 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch 2 Pro Controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2017 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SNES Controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2019 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online N64 Controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x201e ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SEGA Genesis Controller
|
||||
@@ -583,6 +579,7 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0186 ), k_eControllerType_SwitchProController, NULL }, // PDP Afterglow Wireless Switch Controller - working gyro. USB is for charging only. Many later "Wireless" line devices w/ gyro also use this vid/pid
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0187 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Rockcandy Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0188 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Afterglow Wired Deluxe+ Audio Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x018c ), k_eControllerType_SwitchProController, "PDP REALMz Wireless Controller" }, // PDP REALMz Wireless Controller for Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00aa ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Real Arcade Pro V Hayabusa in Switch Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Wired Controller Plus/PowerA Wired Controller Nintendo GameCube Style
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa712 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Fight Pad
|
||||
@@ -591,9 +588,10 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa715 ), k_eControllerType_SwitchInputOnlyController, NULL }, // Power A Fusion Wireless Arcade Stick (USB Mode) Over BT is shows up as 057e 2009
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa716 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Pro Controller - USB requires toggling switch on back of device
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa718 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Nano Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0001 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Black
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0002 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch ??
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0003 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Red
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0001 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Black
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0002 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch ??
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0003 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Red
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00f0 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Taiko Controller For Switch
|
||||
|
||||
// Valve products
|
||||
{ MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch, NULL }, // Streaming mobile touch virtual controls
|
||||
@@ -606,4 +604,8 @@ static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1201 ), k_eControllerType_SteamControllerV2, NULL }, // Valve wired Steam Controller (HEADCRAB)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1202 ), k_eControllerType_SteamControllerV2, NULL }, // Valve Bluetooth Steam Controller (HEADCRAB)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1205 ), k_eControllerType_SteamControllerNeptune, NULL }, // Valve Steam Deck Builtin Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1302 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Triton Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1303 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Triton Controller (BLE)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1304 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Proteus Dongle (Proprietary)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1305 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Nereid Dongle (Proprietary)
|
||||
};
|
||||
|
||||
@@ -39,6 +39,8 @@ typedef enum
|
||||
k_eControllerType_SteamControllerV2 = 3,
|
||||
k_eControllerType_SteamControllerNeptune = 4,
|
||||
|
||||
k_eControllerType_SteamControllerTriton = 10,
|
||||
|
||||
// Other Controllers
|
||||
k_eControllerType_UnknownNonSteamController = 30,
|
||||
k_eControllerType_XBox360Controller = 31,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "SDL_sysjoystick_c.h"
|
||||
#include "../SDL_joystick_c.h"
|
||||
#include "../usb_ids.h"
|
||||
|
||||
static SDL_joylist_item *JoystickByIndex(int index);
|
||||
|
||||
@@ -34,10 +35,60 @@ static SDL_joylist_item *SDL_joylist = NULL;
|
||||
static SDL_joylist_item *SDL_joylist_tail = NULL;
|
||||
static int numjoysticks = 0;
|
||||
|
||||
EM_JS(int, SDL_GetEmscriptenJoystickVendor, (int device_index), {
|
||||
// Let's assume that if we're calling these function then the gamepad object definitely exists
|
||||
let gamepad = navigator['getGamepads']()[device_index];
|
||||
|
||||
// Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc)
|
||||
let vendor_str = 'Vendor: ';
|
||||
if (gamepad['id']['indexOf'](vendor_str) > 0) {
|
||||
let vendor_str_index = gamepad['id']['indexOf'](vendor_str) + vendor_str['length'];
|
||||
return parseInt(gamepad['id']['substr'](vendor_str_index, 4), 16);
|
||||
}
|
||||
|
||||
// Firefox, Safari: 046d-c216-Logitech Dual Action (or 46d-c216-Logicool Dual Action)
|
||||
let id_split = gamepad['id']['split']('-');
|
||||
if (id_split['length'] > 1 && !isNaN(parseInt(id_split[0], 16))) {
|
||||
return parseInt(id_split[0], 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
EM_JS(int, SDL_GetEmscriptenJoystickProduct, (int device_index), {
|
||||
let gamepad = navigator['getGamepads']()[device_index];
|
||||
|
||||
// Chrome, Edge, Opera: Wireless Controller (STANDARD GAMEPAD Vendor: 054c Product: 09cc)
|
||||
let product_str = 'Product: ';
|
||||
if (gamepad['id']['indexOf'](product_str) > 0) {
|
||||
let product_str_index = gamepad['id']['indexOf'](product_str) + product_str['length'];
|
||||
return parseInt(gamepad['id']['substr'](product_str_index, 4), 16);
|
||||
}
|
||||
|
||||
// Firefox, Safari: 046d-c216-Logitech Dual Action (or 46d-c216-Logicool Dual Action)
|
||||
let id_split = gamepad['id']['split']('-');
|
||||
if (id_split['length'] > 1 && !isNaN(parseInt(id_split[1], 16))) {
|
||||
return parseInt(id_split[1], 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
EM_JS(int, SDL_IsEmscriptenJoystickXInput, (int device_index), {
|
||||
let gamepad = navigator['getGamepads']()[device_index];
|
||||
|
||||
// Chrome, Edge, Opera: Xbox 360 Controller (XInput STANDARD GAMEPAD)
|
||||
// Firefox: xinput
|
||||
// TODO: Safari
|
||||
return gamepad['id']['toLowerCase']()['indexOf']('xinput') >= 0;
|
||||
});
|
||||
|
||||
static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
|
||||
{
|
||||
SDL_joylist_item *item;
|
||||
int i;
|
||||
Uint16 vendor, product;
|
||||
bool is_xinput;
|
||||
|
||||
SDL_LockJoysticks();
|
||||
|
||||
@@ -53,12 +104,32 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
||||
SDL_zerop(item);
|
||||
item->index = gamepadEvent->index;
|
||||
|
||||
item->name = SDL_CreateJoystickName(0, 0, NULL, gamepadEvent->id);
|
||||
vendor = SDL_GetEmscriptenJoystickVendor(gamepadEvent->index);
|
||||
product = SDL_GetEmscriptenJoystickProduct(gamepadEvent->index);
|
||||
is_xinput = SDL_IsEmscriptenJoystickXInput(gamepadEvent->index);
|
||||
|
||||
// Use a generic VID/PID representing an XInput controller
|
||||
if (!vendor && !product && is_xinput) {
|
||||
vendor = USB_VENDOR_MICROSOFT;
|
||||
product = USB_PRODUCT_XBOX360_XUSB_CONTROLLER;
|
||||
}
|
||||
|
||||
item->name = SDL_CreateJoystickName(vendor, product, NULL, gamepadEvent->id);
|
||||
if (!item->name) {
|
||||
SDL_free(item);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (vendor && product) {
|
||||
item->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_UNKNOWN, vendor, product, 0, NULL, item->name, 0, 0);
|
||||
} else {
|
||||
item->guid = SDL_CreateJoystickGUIDForName(item->name);
|
||||
}
|
||||
|
||||
if (is_xinput) {
|
||||
item->guid.data[14] = 'x'; // See SDL_IsJoystickXInput
|
||||
}
|
||||
|
||||
item->mapping = SDL_strdup(gamepadEvent->mapping);
|
||||
if (!item->mapping) {
|
||||
SDL_free(item->name);
|
||||
@@ -66,19 +137,74 @@ static EM_BOOL Emscripten_JoyStickConnected(int eventType, const EmscriptenGamep
|
||||
goto done;
|
||||
}
|
||||
|
||||
item->naxes = gamepadEvent->numAxes;
|
||||
item->nbuttons = gamepadEvent->numButtons;
|
||||
const int real_button_count = gamepadEvent->numButtons;
|
||||
const int real_axis_count = gamepadEvent->numAxes;
|
||||
int first_trigger_button = -1;
|
||||
int first_hat_button = -1;
|
||||
int num_buttons = gamepadEvent->numButtons;
|
||||
int num_axes = gamepadEvent->numAxes;
|
||||
bool triggers_are_buttons = false;
|
||||
if ((SDL_strcmp(gamepadEvent->mapping, "standard") == 0) && (num_buttons >= 16)) { // maps to a game console gamepad layout, turn the d-pad into a hat, treat triggers as analog.
|
||||
num_buttons -= 4; // 4 dpad buttons become a hat.
|
||||
first_hat_button = 12;
|
||||
|
||||
if (num_axes == 4) { // Chrome gives the triggers analog button values, Firefox exposes them as extra axes. Both have the digital buttons.
|
||||
num_axes += 2; // the two trigger "buttons"
|
||||
triggers_are_buttons = true;
|
||||
}
|
||||
|
||||
// dump the digital trigger buttons in any case.
|
||||
first_trigger_button = 6;
|
||||
num_buttons -= 2;
|
||||
}
|
||||
|
||||
item->first_hat_button = first_hat_button;
|
||||
item->first_trigger_button = first_trigger_button;
|
||||
item->triggers_are_buttons = triggers_are_buttons;
|
||||
item->nhats = (first_hat_button >= 0) ? 1 : 0;
|
||||
item->naxes = num_axes;
|
||||
item->nbuttons = num_buttons;
|
||||
item->device_instance = SDL_GetNextObjectID();
|
||||
|
||||
item->timestamp = gamepadEvent->timestamp;
|
||||
|
||||
for (i = 0; i < item->naxes; i++) {
|
||||
int buttonidx = 0;
|
||||
for (i = 0; i < real_button_count; i++, buttonidx++) {
|
||||
if (buttonidx == first_hat_button) {
|
||||
buttonidx += 4; // skip these buttons, we're treating them as hat input.
|
||||
} else if (buttonidx == first_trigger_button) {
|
||||
buttonidx += 2; // skip these buttons, we're treating them as axes.
|
||||
}
|
||||
item->analogButton[i] = gamepadEvent->analogButton[buttonidx];
|
||||
item->digitalButton[i] = gamepadEvent->digitalButton[buttonidx];
|
||||
}
|
||||
|
||||
for (i = 0; i < real_axis_count; i++) {
|
||||
item->axis[i] = gamepadEvent->axis[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < item->nbuttons; i++) {
|
||||
item->analogButton[i] = gamepadEvent->analogButton[i];
|
||||
item->digitalButton[i] = gamepadEvent->digitalButton[i];
|
||||
if (item->triggers_are_buttons) {
|
||||
item->axis[real_axis_count] = (gamepadEvent->analogButton[first_trigger_button] * 2.0f) - 1.0f;
|
||||
item->axis[real_axis_count+1] = (gamepadEvent->analogButton[first_trigger_button+1] * 2.0f) - 1.0f;
|
||||
}
|
||||
|
||||
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||
if (first_hat_button != -1) {
|
||||
Uint8 value = SDL_HAT_CENTERED;
|
||||
// this currently expects the first button to be up, then down, then left, then right.
|
||||
if (gamepadEvent->digitalButton[first_hat_button + 0]) {
|
||||
value |= SDL_HAT_UP;
|
||||
}
|
||||
if (gamepadEvent->digitalButton[first_hat_button + 1]) {
|
||||
value |= SDL_HAT_DOWN;
|
||||
}
|
||||
if (gamepadEvent->digitalButton[first_hat_button + 2]) {
|
||||
value |= SDL_HAT_LEFT;
|
||||
}
|
||||
if (gamepadEvent->digitalButton[first_hat_button + 3]) {
|
||||
value |= SDL_HAT_RIGHT;
|
||||
}
|
||||
item->hat = value;
|
||||
}
|
||||
|
||||
if (!SDL_joylist_tail) {
|
||||
@@ -305,6 +431,7 @@ static SDL_JoystickID EMSCRIPTEN_JoystickGetDeviceInstanceID(int device_index)
|
||||
static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
{
|
||||
SDL_joylist_item *item = JoystickByDeviceIndex(device_index);
|
||||
bool rumble_available = false;
|
||||
|
||||
if (!item) {
|
||||
return SDL_SetError("No such device");
|
||||
@@ -317,12 +444,27 @@ static bool EMSCRIPTEN_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
joystick->hwdata = (struct joystick_hwdata *)item;
|
||||
item->joystick = joystick;
|
||||
|
||||
// HTML5 Gamepad API doesn't say anything about these
|
||||
joystick->nhats = 0;
|
||||
|
||||
// HTML5 Gamepad API doesn't offer hats, but we can fake it from the d-pad buttons on the "standard" mapping.
|
||||
joystick->nhats = item->nhats;
|
||||
joystick->nbuttons = item->nbuttons;
|
||||
joystick->naxes = item->naxes;
|
||||
|
||||
rumble_available = MAIN_THREAD_EM_ASM_INT({
|
||||
let gamepads = navigator['getGamepads']();
|
||||
if (!gamepads) {
|
||||
return 0;
|
||||
}
|
||||
let gamepad = gamepads[$0];
|
||||
if (!gamepad || !gamepad['vibrationActuator']) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}, item->index);
|
||||
|
||||
if (rumble_available) {
|
||||
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -344,28 +486,65 @@ static void EMSCRIPTEN_JoystickUpdate(SDL_Joystick *joystick)
|
||||
result = emscripten_get_gamepad_status(item->index, &gamepadState);
|
||||
if (result == EMSCRIPTEN_RESULT_SUCCESS) {
|
||||
if (gamepadState.timestamp == 0 || gamepadState.timestamp != item->timestamp) {
|
||||
for (i = 0; i < item->nbuttons; i++) {
|
||||
if (item->digitalButton[i] != gamepadState.digitalButton[i]) {
|
||||
bool down = (gamepadState.digitalButton[i] != 0);
|
||||
const int first_hat_button = item->first_hat_button;
|
||||
const int first_trigger_button = item->first_trigger_button;
|
||||
const int real_button_count = gamepadState.numButtons;
|
||||
const int real_axis_count = gamepadState.numAxes;
|
||||
|
||||
int buttonidx = 0;
|
||||
for (i = 0; i < real_button_count; i++, buttonidx++) {
|
||||
if (buttonidx == first_hat_button) {
|
||||
buttonidx += 4; // skip these buttons, we're treating them as hat input.
|
||||
} else if (buttonidx == first_trigger_button) {
|
||||
buttonidx += 2; // skip these buttons, we're treating them as axes.
|
||||
}
|
||||
if (item->digitalButton[i] != gamepadState.digitalButton[buttonidx]) {
|
||||
const bool down = (gamepadState.digitalButton[buttonidx] != 0);
|
||||
SDL_SendJoystickButton(timestamp, item->joystick, i, down);
|
||||
}
|
||||
|
||||
// store values to compare them in the next update
|
||||
item->analogButton[i] = gamepadState.analogButton[i];
|
||||
item->digitalButton[i] = gamepadState.digitalButton[i];
|
||||
item->analogButton[i] = gamepadState.analogButton[buttonidx];
|
||||
item->digitalButton[i] = gamepadState.digitalButton[buttonidx];
|
||||
}
|
||||
|
||||
for (i = 0; i < item->naxes; i++) {
|
||||
for (i = 0; i < real_axis_count; i++) {
|
||||
if (item->axis[i] != gamepadState.axis[i]) {
|
||||
// do we need to do conversion?
|
||||
SDL_SendJoystickAxis(timestamp, item->joystick, i,
|
||||
(Sint16)(32767. * gamepadState.axis[i]));
|
||||
SDL_SendJoystickAxis(timestamp, item->joystick, i, (Sint16)(32767.0f * gamepadState.axis[i]));
|
||||
item->axis[i] = gamepadState.axis[i];
|
||||
}
|
||||
|
||||
// store to compare in next update
|
||||
item->axis[i] = gamepadState.axis[i];
|
||||
}
|
||||
|
||||
if (item->triggers_are_buttons) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (item->axis[real_axis_count+i] != gamepadState.analogButton[first_trigger_button+i]) {
|
||||
SDL_SendJoystickAxis(timestamp, item->joystick, real_axis_count+i, (Sint16)(32767.0f * ((gamepadState.analogButton[first_trigger_button+i] * 2.0f) - 1.0f)));
|
||||
item->axis[real_axis_count+i] = gamepadState.analogButton[first_trigger_button+i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_assert(item->nhats <= 1); // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||
if (item->nhats) {
|
||||
Uint8 value = SDL_HAT_CENTERED;
|
||||
// this currently expects the first button to be up, then down, then left, then right.
|
||||
if (gamepadState.digitalButton[first_hat_button + 0]) {
|
||||
value |= SDL_HAT_UP;
|
||||
} else if (gamepadState.digitalButton[first_hat_button + 1]) {
|
||||
value |= SDL_HAT_DOWN;
|
||||
}
|
||||
if (gamepadState.digitalButton[first_hat_button + 2]) {
|
||||
value |= SDL_HAT_LEFT;
|
||||
} else if (gamepadState.digitalButton[first_hat_button + 3]) {
|
||||
value |= SDL_HAT_RIGHT;
|
||||
}
|
||||
if (item->hat != value) {
|
||||
item->hat = value;
|
||||
SDL_SendJoystickHat(timestamp, item->joystick, 0, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
item->timestamp = gamepadState.timestamp;
|
||||
}
|
||||
}
|
||||
@@ -383,14 +562,34 @@ static void EMSCRIPTEN_JoystickClose(SDL_Joystick *joystick)
|
||||
|
||||
static SDL_GUID EMSCRIPTEN_JoystickGetDeviceGUID(int device_index)
|
||||
{
|
||||
// the GUID is just the name for now
|
||||
const char *name = EMSCRIPTEN_JoystickGetDeviceName(device_index);
|
||||
return SDL_CreateJoystickGUIDForName(name);
|
||||
return JoystickByDeviceIndex(device_index)->guid;
|
||||
}
|
||||
|
||||
static bool EMSCRIPTEN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
SDL_joylist_item *item = (SDL_joylist_item *)joystick->hwdata;
|
||||
|
||||
// clang-format off
|
||||
bool result = MAIN_THREAD_EM_ASM_INT({
|
||||
let gamepads = navigator['getGamepads']();
|
||||
if (!gamepads) {
|
||||
return 0;
|
||||
}
|
||||
let gamepad = gamepads[$0];
|
||||
if (!gamepad || !gamepad['vibrationActuator']) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gamepad['vibrationActuator']['playEffect']('dual-rumble', {
|
||||
'startDelay': 0,
|
||||
'duration': 3000,
|
||||
'weakMagnitude': $2 / 0xFFFF,
|
||||
'strongMagnitude': $1 / 0xFFFF,
|
||||
});
|
||||
return 1;
|
||||
}, item->index, low_frequency_rumble, high_frequency_rumble);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -34,12 +34,18 @@ typedef struct SDL_joylist_item
|
||||
char *mapping;
|
||||
SDL_JoystickID device_instance;
|
||||
SDL_Joystick *joystick;
|
||||
int first_hat_button;
|
||||
int first_trigger_button;
|
||||
bool triggers_are_buttons;
|
||||
int nhats;
|
||||
SDL_GUID guid;
|
||||
int nbuttons;
|
||||
int naxes;
|
||||
double timestamp;
|
||||
double axis[64];
|
||||
double axis[64]; // !!! FIXME: don't hardcode 64 on all of these.
|
||||
double analogButton[64];
|
||||
EM_BOOL digitalButton[64];
|
||||
Uint8 hat; // there is (currently) only ever one of these, faked from the d-pad buttons.
|
||||
|
||||
struct SDL_joylist_item *next;
|
||||
} SDL_joylist_item;
|
||||
|
||||
+126
-81
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "../usb_ids.h"
|
||||
#include "../../core/windows/SDL_windows.h"
|
||||
#include "../../core/windows/SDL_gameinput.h"
|
||||
|
||||
// Default value for SDL_HINT_JOYSTICK_GAMEINPUT
|
||||
@@ -33,6 +34,11 @@
|
||||
#define SDL_GAMEINPUT_DEFAULT false
|
||||
#endif
|
||||
|
||||
// Enable sensor support in GameInput 2.0, once we have a device that can be used for testing
|
||||
#if GAMEINPUT_API_VERSION >= 2
|
||||
//#define GAMEINPUT_SENSOR_SUPPORT
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_GAMEPAD_BUTTON_GAMEINPUT_SHARE = 11
|
||||
@@ -46,6 +52,7 @@ typedef struct GAMEINPUT_InternalDevice
|
||||
SDL_GUID guid; // generated by SDL
|
||||
SDL_JoystickID device_instance; // generated by SDL
|
||||
const GameInputDeviceInfo *info;
|
||||
int steam_virtual_gamepad_slot;
|
||||
bool isAdded;
|
||||
bool isDeleteRequested;
|
||||
} GAMEINPUT_InternalDevice;
|
||||
@@ -66,7 +73,7 @@ typedef struct joystick_hwdata
|
||||
|
||||
static GAMEINPUT_InternalList g_GameInputList = { NULL };
|
||||
static IGameInput *g_pGameInput = NULL;
|
||||
static GameInputCallbackToken g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE;
|
||||
static GameInputCallbackToken g_GameInputCallbackToken = 0;
|
||||
static Uint64 g_GameInputTimestampOffset;
|
||||
|
||||
static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info)
|
||||
@@ -77,6 +84,18 @@ static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
static int GetSteamVirtualGamepadSlot(const char *device_path)
|
||||
{
|
||||
int slot = -1;
|
||||
|
||||
// The format for the raw input device path is documented here:
|
||||
// https://partner.steamgames.com/doc/features/steam_controller/steam_input_gamepad_emulation_bestpractices
|
||||
(void)SDL_sscanf(device_path, "\\\\.\\pipe\\HID#VID_045E&PID_028E&IG_00#%*X&%*X&%*X#%d#%*u", &slot);
|
||||
return slot;
|
||||
}
|
||||
#endif // GAMEINPUT_API_VERSION >= 1
|
||||
|
||||
static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
|
||||
{
|
||||
GAMEINPUT_InternalDevice **devicelist = NULL;
|
||||
@@ -93,15 +112,22 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
info = IGameInputDevice_GetDeviceInfo(pDevice);
|
||||
if (info->capabilities & GameInputDeviceCapabilityWireless) {
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
HRESULT hr = pDevice->GetDeviceInfo(&info);
|
||||
if (FAILED(hr)) {
|
||||
return WIN_SetErrorFromHRESULT("IGameInputDevice::GetDeviceInfo", hr);
|
||||
}
|
||||
#else
|
||||
info = pDevice->GetDeviceInfo();
|
||||
#endif
|
||||
if (false /*info->capabilities & GameInputDeviceCapabilityWireless*/) {
|
||||
bus = SDL_HARDWARE_BUS_BLUETOOTH;
|
||||
} else {
|
||||
bus = SDL_HARDWARE_BUS_USB;
|
||||
}
|
||||
vendor = info->vendorId;
|
||||
product = info->productId;
|
||||
version = (info->firmwareVersion.major << 8) | info->firmwareVersion.minor;
|
||||
//version = (info->firmwareVersion.major << 8) | info->firmwareVersion.minor;
|
||||
|
||||
if (SDL_JoystickHandledByAnotherDriver(&SDL_GAMEINPUT_JoystickDriver, vendor, product, version, "")) {
|
||||
return true;
|
||||
@@ -130,23 +156,30 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice)
|
||||
// Generate a device path
|
||||
for (idx = 0; idx < APP_LOCAL_DEVICE_ID_SIZE; ++idx) {
|
||||
SDL_snprintf(tmp, SDL_arraysize(tmp), "%02hhX", info->deviceId.value[idx]);
|
||||
SDL_strlcat(elem->path, tmp, SDL_arraysize(tmp));
|
||||
}
|
||||
|
||||
if (info->deviceStrings) {
|
||||
// In theory we could get the manufacturer and product strings here, but they're NULL for all the controllers I've tested
|
||||
SDL_strlcat(elem->path, tmp, SDL_arraysize(elem->path));
|
||||
}
|
||||
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
if (info->displayName) {
|
||||
// This could give us a product string, but it's NULL for all the controllers I've tested
|
||||
product_string = info->displayName;
|
||||
}
|
||||
#else
|
||||
if (info->displayName) {
|
||||
product_string = info->displayName->data;
|
||||
}
|
||||
#endif
|
||||
|
||||
IGameInputDevice_AddRef(pDevice);
|
||||
pDevice->AddRef();
|
||||
elem->device = pDevice;
|
||||
elem->name = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string);
|
||||
elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, manufacturer_string, product_string, 'g', 0);
|
||||
elem->device_instance = SDL_GetNextObjectID();
|
||||
elem->info = info;
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
elem->steam_virtual_gamepad_slot = GetSteamVirtualGamepadSlot(info->pnpPath);
|
||||
#else
|
||||
elem->steam_virtual_gamepad_slot = -1;
|
||||
#endif
|
||||
|
||||
g_GameInputList.devices = devicelist;
|
||||
g_GameInputList.devices[g_GameInputList.count++] = elem;
|
||||
@@ -168,7 +201,7 @@ static bool GAMEINPUT_InternalRemoveByIndex(int idx)
|
||||
|
||||
elem = g_GameInputList.devices[idx];
|
||||
if (elem) {
|
||||
IGameInputDevice_Release(elem->device);
|
||||
elem->device->Release();
|
||||
SDL_free(elem->name);
|
||||
SDL_free(elem);
|
||||
}
|
||||
@@ -199,8 +232,8 @@ static GAMEINPUT_InternalDevice *GAMEINPUT_InternalFindByIndex(int idx)
|
||||
|
||||
static void CALLBACK GAMEINPUT_InternalJoystickDeviceCallback(
|
||||
_In_ GameInputCallbackToken callbackToken,
|
||||
_In_ void* context,
|
||||
_In_ IGameInputDevice* device,
|
||||
_In_ void *context,
|
||||
_In_ IGameInputDevice *device,
|
||||
_In_ uint64_t timestamp,
|
||||
_In_ GameInputDeviceStatus currentStatus,
|
||||
_In_ GameInputDeviceStatus previousStatus)
|
||||
@@ -232,10 +265,11 @@ static void CALLBACK GAMEINPUT_InternalJoystickDeviceCallback(
|
||||
}
|
||||
|
||||
static void GAMEINPUT_JoystickDetect(void);
|
||||
static void GAMEINPUT_JoystickQuit(void);
|
||||
|
||||
static bool GAMEINPUT_JoystickInit(void)
|
||||
{
|
||||
HRESULT hR;
|
||||
HRESULT hr;
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_GAMEINPUT, SDL_GAMEINPUT_DEFAULT)) {
|
||||
return true;
|
||||
@@ -245,21 +279,27 @@ static bool GAMEINPUT_JoystickInit(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
hR = IGameInput_RegisterDeviceCallback(g_pGameInput,
|
||||
NULL,
|
||||
#if GAMEINPUT_API_VERSION >= 2
|
||||
// Allow background controller input
|
||||
// SDL manages focus policy at a higher level, so we can set this unconditionally.
|
||||
g_pGameInput->SetFocusPolicy(GameInputEnableBackgroundInput | GameInputEnableBackgroundGuideButton | GameInputEnableBackgroundShareButton);
|
||||
#endif
|
||||
|
||||
hr = g_pGameInput->RegisterDeviceCallback(NULL,
|
||||
GameInputKindController,
|
||||
GameInputDeviceConnected,
|
||||
GameInputBlockingEnumeration,
|
||||
NULL,
|
||||
GAMEINPUT_InternalJoystickDeviceCallback,
|
||||
&g_GameInputCallbackToken);
|
||||
if (FAILED(hR)) {
|
||||
return SDL_SetError("IGameInput::RegisterDeviceCallback failure with HRESULT of %08lX", hR);
|
||||
if (FAILED(hr)) {
|
||||
GAMEINPUT_JoystickQuit();
|
||||
return WIN_SetErrorFromHRESULT("IGameInput::RegisterDeviceCallback", hr);
|
||||
}
|
||||
|
||||
// Calculate the relative offset between SDL timestamps and GameInput timestamps
|
||||
Uint64 now = SDL_GetTicksNS();
|
||||
uint64_t timestampUS = IGameInput_GetCurrentTimestamp(g_pGameInput);
|
||||
uint64_t timestampUS = g_pGameInput->GetCurrentTimestamp();
|
||||
g_GameInputTimestampOffset = (SDL_NS_TO_US(now) - timestampUS);
|
||||
|
||||
GAMEINPUT_JoystickDetect();
|
||||
@@ -292,7 +332,7 @@ static void GAMEINPUT_JoystickDetect(void)
|
||||
elem->isAdded = true;
|
||||
}
|
||||
|
||||
if (elem->isDeleteRequested || !(IGameInputDevice_GetDeviceStatus(elem->device) & GameInputDeviceConnected)) {
|
||||
if (elem->isDeleteRequested || !(elem->device->GetDeviceStatus() & GameInputDeviceConnected)) {
|
||||
SDL_PrivateJoystickRemoved(elem->device_instance);
|
||||
GAMEINPUT_InternalRemoveByIndex(idx--);
|
||||
}
|
||||
@@ -333,7 +373,7 @@ static const char *GAMEINPUT_JoystickGetDevicePath(int device_index)
|
||||
|
||||
static int GAMEINPUT_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
|
||||
{
|
||||
return -1;
|
||||
return GAMEINPUT_InternalFindByIndex(device_index)->steam_virtual_gamepad_slot;
|
||||
}
|
||||
|
||||
static int GAMEINPUT_JoystickGetDevicePlayerIndex(int device_index)
|
||||
@@ -357,6 +397,7 @@ static SDL_JoystickID GAMEINPUT_JoystickGetDeviceInstanceID(int device_index)
|
||||
|
||||
static void GAMEINPUT_UpdatePowerInfo(SDL_Joystick *joystick, IGameInputDevice *device)
|
||||
{
|
||||
#if 0
|
||||
GameInputBatteryState battery_state;
|
||||
SDL_PowerState state;
|
||||
int percent = 0;
|
||||
@@ -385,10 +426,10 @@ static void GAMEINPUT_UpdatePowerInfo(SDL_Joystick *joystick, IGameInputDevice *
|
||||
percent = (int)SDL_roundf((battery_state.remainingCapacity / battery_state.fullChargeCapacity) * 100.0f);
|
||||
}
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IGameInput_RegisterSystemButtonCallback
|
||||
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
static void CALLBACK GAMEINPUT_InternalSystemButtonCallback(
|
||||
_In_ GameInputCallbackToken callbackToken,
|
||||
_In_ void * context,
|
||||
@@ -415,8 +456,7 @@ static void CALLBACK GAMEINPUT_InternalSystemButtonCallback(
|
||||
SDL_UnlockJoysticks();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IGameInput_RegisterSystemButtonCallback
|
||||
#endif // GAMEINPUT_API_VERSION >= 1
|
||||
|
||||
static bool GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
{
|
||||
@@ -441,19 +481,15 @@ static bool GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
joystick->nbuttons = 11;
|
||||
joystick->nhats = 1;
|
||||
|
||||
#ifdef IGameInput_RegisterSystemButtonCallback
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
if (info->supportedSystemButtons != GameInputSystemButtonNone) {
|
||||
if (info->supportedSystemButtons & GameInputSystemButtonShare) {
|
||||
++joystick->nbuttons;
|
||||
}
|
||||
|
||||
#if 1 // The C macro in GameInput.h version 10.0.26100 refers to a focus policy which I guess has been removed from the final API?
|
||||
#undef IGameInput_RegisterSystemButtonCallback
|
||||
#define IGameInput_RegisterSystemButtonCallback(This, device, buttonFilter, context, callbackFunc, callbackToken) ((This)->lpVtbl->RegisterSystemButtonCallback(This, device, buttonFilter, context, callbackFunc, callbackToken))
|
||||
#endif
|
||||
IGameInput_RegisterSystemButtonCallback(g_pGameInput, elem->device, (GameInputSystemButtonGuide | GameInputSystemButtonShare), joystick, GAMEINPUT_InternalSystemButtonCallback, &hwdata->system_button_callback_token);
|
||||
g_pGameInput->RegisterSystemButtonCallback(elem->device, (GameInputSystemButtonGuide | GameInputSystemButtonShare), joystick, GAMEINPUT_InternalSystemButtonCallback, &hwdata->system_button_callback_token);
|
||||
}
|
||||
#endif // IGameInput_RegisterSystemButtonCallback
|
||||
#endif // GAMEINPUT_API_VERSION >= 1
|
||||
} else {
|
||||
joystick->naxes = info->controllerAxisCount;
|
||||
joystick->nbuttons = info->controllerButtonCount;
|
||||
@@ -467,21 +503,17 @@ static bool GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_TRIGGER_RUMBLE_BOOLEAN, true);
|
||||
}
|
||||
|
||||
if (info->supportedInput & GameInputKindTouch) {
|
||||
SDL_PrivateJoystickAddTouchpad(joystick, info->touchPointCount);
|
||||
}
|
||||
|
||||
if (info->supportedInput & GameInputKindMotion) {
|
||||
#ifdef GAMEINPUT_SENSOR_SUPPORT
|
||||
if (info->supportedInput & GameInputKindSensors) {
|
||||
// FIXME: What's the sensor update rate?
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
|
||||
}
|
||||
|
||||
if (info->capabilities & GameInputDeviceCapabilityWireless) {
|
||||
joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS;
|
||||
} else {
|
||||
joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED;
|
||||
if (info->sensorsInfo->supportedSensors & GameInputSensorsGyrometer) {
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
|
||||
}
|
||||
if (info->sensorsInfo->supportedSensors & GameInputSensorsAccelerometer) {
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -492,7 +524,7 @@ static bool GAMEINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequenc
|
||||
GameInputRumbleParams *params = &hwdata->rumbleParams;
|
||||
params->lowFrequency = (float)low_frequency_rumble / (float)SDL_MAX_UINT16;
|
||||
params->highFrequency = (float)high_frequency_rumble / (float)SDL_MAX_UINT16;
|
||||
IGameInputDevice_SetRumbleState(hwdata->devref->device, params);
|
||||
hwdata->devref->device->SetRumbleState(params);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -503,7 +535,7 @@ static bool GAMEINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left
|
||||
GameInputRumbleParams *params = &hwdata->rumbleParams;
|
||||
params->leftTrigger = (float)left_rumble / (float)SDL_MAX_UINT16;
|
||||
params->rightTrigger = (float)right_rumble / (float)SDL_MAX_UINT16;
|
||||
IGameInputDevice_SetRumbleState(hwdata->devref->device, params);
|
||||
hwdata->devref->device->SetRumbleState(params);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -531,15 +563,15 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||
IGameInputReading *reading = NULL;
|
||||
Uint64 timestamp;
|
||||
GameInputGamepadState state;
|
||||
HRESULT hR;
|
||||
HRESULT hr;
|
||||
|
||||
hR = IGameInput_GetCurrentReading(g_pGameInput, info->supportedInput, device, &reading);
|
||||
if (FAILED(hR)) {
|
||||
hr = g_pGameInput->GetCurrentReading(info->supportedInput, device, &reading);
|
||||
if (FAILED(hr)) {
|
||||
// don't SetError here since there can be a legitimate case when there's no reading avail
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp = SDL_US_TO_NS(IGameInputReading_GetTimestamp(reading) + g_GameInputTimestampOffset);
|
||||
timestamp = SDL_US_TO_NS(reading->GetTimestamp() + g_GameInputTimestampOffset);
|
||||
|
||||
if (GAMEINPUT_InternalIsGamepad(info)) {
|
||||
static WORD s_XInputButtons[] = {
|
||||
@@ -557,7 +589,7 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||
};
|
||||
Uint8 btnidx = 0, hat = 0;
|
||||
|
||||
if (IGameInputReading_GetGamepadState(reading, &state)) {
|
||||
if (reading->GetGamepadState(&state)) {
|
||||
for (btnidx = 0; btnidx < SDL_arraysize(s_XInputButtons); ++btnidx) {
|
||||
WORD button_mask = s_XInputButtons[btnidx];
|
||||
if (!button_mask) {
|
||||
@@ -599,7 +631,7 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||
|
||||
if (button_state) {
|
||||
uint32_t i;
|
||||
uint32_t button_count = IGameInputReading_GetControllerButtonState(reading, info->controllerButtonCount, button_state);
|
||||
uint32_t button_count = reading->GetControllerButtonState(info->controllerButtonCount, button_state);
|
||||
for (i = 0; i < button_count; ++i) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, (Uint8)i, button_state[i]);
|
||||
}
|
||||
@@ -609,7 +641,7 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||
#define CONVERT_AXIS(v) (Sint16)((v)*65535.0f - 32768.0f)
|
||||
if (axis_state) {
|
||||
uint32_t i;
|
||||
uint32_t axis_count = IGameInputReading_GetControllerAxisState(reading, info->controllerAxisCount, axis_state);
|
||||
uint32_t axis_count = reading->GetControllerAxisState(info->controllerAxisCount, axis_state);
|
||||
for (i = 0; i < axis_count; ++i) {
|
||||
SDL_SendJoystickAxis(timestamp, joystick, (Uint8)i, CONVERT_AXIS(axis_state[i]));
|
||||
}
|
||||
@@ -619,7 +651,7 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||
|
||||
if (switch_state) {
|
||||
uint32_t i;
|
||||
uint32_t switch_count = IGameInputReading_GetControllerSwitchState(reading, info->controllerSwitchCount, switch_state);
|
||||
uint32_t switch_count = reading->GetControllerSwitchState(info->controllerSwitchCount, switch_state);
|
||||
for (i = 0; i < switch_count; ++i) {
|
||||
Uint8 hat;
|
||||
switch (switch_state[i]) {
|
||||
@@ -658,40 +690,47 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
|
||||
}
|
||||
}
|
||||
|
||||
if (info->supportedInput & GameInputKindTouch) {
|
||||
GameInputTouchState *touch_state = SDL_stack_alloc(GameInputTouchState, info->touchPointCount);
|
||||
if (touch_state) {
|
||||
uint32_t i;
|
||||
uint32_t touch_count = IGameInputReading_GetTouchState(reading, info->touchPointCount, touch_state);
|
||||
for (i = 0; i < touch_count; ++i) {
|
||||
GameInputTouchState *touch = &touch_state[i];
|
||||
// FIXME: We should use touch->touchId to track fingers instead of using i below
|
||||
SDL_SendJoystickTouchpad(timestamp, joystick, 0, i, true, touch->positionX * info->touchSensorInfo[i].resolutionX, touch->positionY * info->touchSensorInfo[0].resolutionY, touch->pressure);
|
||||
}
|
||||
SDL_stack_free(touch_state);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GAMEINPUT_SENSOR_SUPPORT
|
||||
if (hwdata->report_sensors) {
|
||||
GameInputMotionState motion_state;
|
||||
GameInputSensorsState sensor_state;
|
||||
|
||||
if (IGameInputReading_GetMotionState(reading, &motion_state)) {
|
||||
// FIXME: How do we interpret the motion data?
|
||||
if (reading->GetSensorsState(&sensor_state)) {
|
||||
if ((info->sensorsInfo->supportedSensors & GameInputSensorsGyrometer) != 0) {
|
||||
float data[3] = {
|
||||
sensor_state.angularVelocityInRadPerSecX,
|
||||
sensor_state.angularVelocityInRadPerSecY,
|
||||
sensor_state.angularVelocityInRadPerSecZ
|
||||
};
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, timestamp, data, SDL_arraysize(data));
|
||||
}
|
||||
if ((info->sensorsInfo->supportedSensors & GameInputSensorsAccelerometer) != 0) {
|
||||
float data[3] = {
|
||||
sensor_state.accelerationInGX * SDL_STANDARD_GRAVITY,
|
||||
sensor_state.accelerationInGY * SDL_STANDARD_GRAVITY,
|
||||
sensor_state.accelerationInGZ * SDL_STANDARD_GRAVITY
|
||||
};
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, data, SDL_arraysize(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // GAMEINPUT_SENSOR_SUPPORT
|
||||
|
||||
IGameInputReading_Release(reading);
|
||||
reading->Release();
|
||||
|
||||
// FIXME: We can poll this at a much lower rate
|
||||
GAMEINPUT_UpdatePowerInfo(joystick, device);
|
||||
}
|
||||
|
||||
static void GAMEINPUT_JoystickClose(SDL_Joystick* joystick)
|
||||
static void GAMEINPUT_JoystickClose(SDL_Joystick *joystick)
|
||||
{
|
||||
GAMEINPUT_InternalJoystickHwdata *hwdata = joystick->hwdata;
|
||||
|
||||
if (hwdata->system_button_callback_token) {
|
||||
IGameInput_UnregisterCallback(g_pGameInput, hwdata->system_button_callback_token, 5000);
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
g_pGameInput->UnregisterCallback(hwdata->system_button_callback_token);
|
||||
#else
|
||||
g_pGameInput->UnregisterCallback(hwdata->system_button_callback_token, 10000);
|
||||
#endif
|
||||
}
|
||||
SDL_free(hwdata);
|
||||
|
||||
@@ -702,8 +741,14 @@ static void GAMEINPUT_JoystickQuit(void)
|
||||
{
|
||||
if (g_pGameInput) {
|
||||
// free the callback
|
||||
IGameInput_UnregisterCallback(g_pGameInput, g_GameInputCallbackToken, /*timeoutInUs:*/ 10000);
|
||||
g_GameInputCallbackToken = GAMEINPUT_INVALID_CALLBACK_TOKEN_VALUE;
|
||||
if (g_GameInputCallbackToken) {
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
g_pGameInput->UnregisterCallback(g_GameInputCallbackToken);
|
||||
#else
|
||||
g_pGameInput->UnregisterCallback(g_GameInputCallbackToken, 10000);
|
||||
#endif
|
||||
g_GameInputCallbackToken = 0;
|
||||
}
|
||||
|
||||
// free the list
|
||||
while (g_GameInputList.count > 0) {
|
||||
@@ -738,7 +783,7 @@ static bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
|
||||
out->back.kind = EMappingKind_Button;
|
||||
out->back.target = SDL_GAMEPAD_BUTTON_BACK;
|
||||
|
||||
#ifdef IGameInput_RegisterSystemButtonCallback
|
||||
#if GAMEINPUT_API_VERSION >= 1
|
||||
if (elem->info->supportedSystemButtons & GameInputSystemButtonGuide) {
|
||||
out->guide.kind = EMappingKind_Button;
|
||||
out->guide.target = SDL_GAMEPAD_BUTTON_GUIDE;
|
||||
@@ -748,7 +793,7 @@ static bool GAMEINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMap
|
||||
out->misc1.kind = EMappingKind_Button;
|
||||
out->misc1.target = SDL_GAMEPAD_BUTTON_GAMEINPUT_SHARE;
|
||||
}
|
||||
#endif
|
||||
#endif // GAMEINPUT_API_VERSION >= 1
|
||||
|
||||
out->start.kind = EMappingKind_Button;
|
||||
out->start.target = SDL_GAMEPAD_BUTTON_START;
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_8BITDO
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
#if 0
|
||||
#define DEBUG_8BITDO_PROTOCOL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_GAMEPAD_BUTTON_8BITDO_L4 = 11,
|
||||
SDL_GAMEPAD_BUTTON_8BITDO_R4,
|
||||
SDL_GAMEPAD_BUTTON_8BITDO_PL,
|
||||
SDL_GAMEPAD_BUTTON_8BITDO_PR,
|
||||
SDL_GAMEPAD_NUM_8BITDO_BUTTONS,
|
||||
};
|
||||
|
||||
#define SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID 0x06
|
||||
#define SDL_8BITDO_REPORTID_SDL_REPORTID 0x04
|
||||
#define SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID 0x03
|
||||
#define SDL_8BITDO_BT_REPORTID_SDL_REPORTID 0x01
|
||||
|
||||
#define SDL_8BITDO_SENSOR_TIMESTAMP_ENABLE 0xAA
|
||||
#define ABITDO_ACCEL_SCALE 4096.f
|
||||
#define ABITDO_GYRO_MAX_DEGREES_PER_SECOND 2000.f
|
||||
|
||||
|
||||
#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) | \
|
||||
(((Uint32)(B)) << 8) | \
|
||||
(((Uint32)(C)) << 16) | \
|
||||
(((Uint32)(D)) << 24))
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool sensors_supported;
|
||||
bool sensors_enabled;
|
||||
bool touchpad_01_supported;
|
||||
bool touchpad_02_supported;
|
||||
bool rumble_supported;
|
||||
bool rumble_type;
|
||||
bool rgb_supported;
|
||||
bool player_led_supported;
|
||||
bool powerstate_supported;
|
||||
bool sensor_timestamp_supported;
|
||||
Uint8 serial[6];
|
||||
Uint16 version;
|
||||
Uint16 version_beta;
|
||||
float accelScale;
|
||||
float gyroScale;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
Uint64 sensor_timestamp; // Nanoseconds. Simulate onboard clock. Different models have different rates vs different connection styles.
|
||||
Uint64 sensor_timestamp_interval;
|
||||
Uint32 last_tick;
|
||||
} SDL_Driver8BitDo_Context;
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
bool sensors_supported;
|
||||
bool touchpad_01_supported;
|
||||
bool touchpad_02_supported;
|
||||
bool rumble_supported;
|
||||
bool rumble_type;
|
||||
bool rgb_supported;
|
||||
Uint8 device_type;
|
||||
Uint8 serial[6];
|
||||
Uint16 version;
|
||||
Uint16 version_beta;
|
||||
Uint16 pid;
|
||||
} ABITDO_DEVICE_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Accelerometer values
|
||||
short sAccelX;
|
||||
short sAccelY;
|
||||
short sAccelZ;
|
||||
|
||||
// Gyroscope values
|
||||
short sGyroX;
|
||||
short sGyroY;
|
||||
short sGyroZ;
|
||||
} ABITDO_SENSORS;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
static void HIDAPI_Driver8BitDo_RegisterHints(SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, callback, userdata);
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_UnregisterHints(SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, callback, userdata);
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_IsEnabled(void)
|
||||
{
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_8BITDO, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
|
||||
}
|
||||
|
||||
static int ReadFeatureReport(SDL_hid_device *dev, Uint8 report_id, Uint8 *report, size_t length)
|
||||
{
|
||||
SDL_memset(report, 0, length);
|
||||
report[0] = report_id;
|
||||
return SDL_hid_get_feature_report(dev, report, length);
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_8BITDO) {
|
||||
switch (product_id) {
|
||||
case USB_PRODUCT_8BITDO_SF30_PRO:
|
||||
case USB_PRODUCT_8BITDO_SF30_PRO_BT:
|
||||
case USB_PRODUCT_8BITDO_SN30_PRO:
|
||||
case USB_PRODUCT_8BITDO_SN30_PRO_BT:
|
||||
case USB_PRODUCT_8BITDO_PRO_2:
|
||||
case USB_PRODUCT_8BITDO_PRO_2_BT:
|
||||
case USB_PRODUCT_8BITDO_PRO_3:
|
||||
case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
if (device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
||||
// The Ultimate 2 Wireless v1.02 firmware has 12 byte reports, v1.03 firmware has 34 byte reports
|
||||
const int ULTIMATE2_WIRELESS_V103_REPORT_SIZE = 34;
|
||||
const int MAX_ATTEMPTS = 3;
|
||||
|
||||
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 80);
|
||||
if (size == 0) {
|
||||
// Try again
|
||||
continue;
|
||||
}
|
||||
if (size >= ULTIMATE2_WIRELESS_V103_REPORT_SIZE) {
|
||||
ctx->sensors_supported = true;
|
||||
ctx->rumble_supported = true;
|
||||
ctx->powerstate_supported = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
const int MAX_ATTEMPTS = 5;
|
||||
for (int attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) {
|
||||
int size = ReadFeatureReport(device->dev, SDL_8BITDO_FEATURE_REPORTID_ENABLE_SDL_REPORTID, data, sizeof(data));
|
||||
if (size > 0) {
|
||||
#ifdef DEBUG_8BITDO_PROTOCOL
|
||||
HIDAPI_DumpPacket("8BitDo features packet: size = %d", data, size);
|
||||
#endif
|
||||
ctx->sensors_supported = true;
|
||||
ctx->rumble_supported = true;
|
||||
ctx->powerstate_supported = true;
|
||||
|
||||
if (size >= 14 && data[13] == SDL_8BITDO_SENSOR_TIMESTAMP_ENABLE) {
|
||||
ctx->sensor_timestamp_supported = true;
|
||||
}
|
||||
|
||||
// Set the serial number to the Bluetooth MAC address
|
||||
if (size >= 12 && data[10] != 0) {
|
||||
char serial[18];
|
||||
(void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[10], data[9], data[8], data[7], data[6], data[5]);
|
||||
HIDAPI_SetDeviceSerial(device, serial);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Try again
|
||||
SDL_Delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
if (device->product_id == USB_PRODUCT_8BITDO_SF30_PRO || device->product_id == USB_PRODUCT_8BITDO_SF30_PRO_BT) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo SF30 Pro");
|
||||
} else if (device->product_id == USB_PRODUCT_8BITDO_SN30_PRO || device->product_id == USB_PRODUCT_8BITDO_SN30_PRO_BT) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo SN30 Pro");
|
||||
} else if (device->product_id == USB_PRODUCT_8BITDO_PRO_2 || device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo Pro 2");
|
||||
} else if (device->product_id == USB_PRODUCT_8BITDO_PRO_3) {
|
||||
HIDAPI_SetDeviceName(device, "8BitDo Pro 3");
|
||||
}
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
static int HIDAPI_Driver8BitDo_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
static Uint64 HIDAPI_Driver8BitDo_GetIMURateForProductID(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
|
||||
|
||||
// TODO: If sensor time stamp is sent, these fixed settings from observation can be replaced
|
||||
switch (device->product_id) {
|
||||
case USB_PRODUCT_8BITDO_SF30_PRO:
|
||||
case USB_PRODUCT_8BITDO_SF30_PRO_BT:
|
||||
case USB_PRODUCT_8BITDO_SN30_PRO:
|
||||
case USB_PRODUCT_8BITDO_SN30_PRO_BT:
|
||||
if (device->is_bluetooth) {
|
||||
// Note, This is estimated by observation of Bluetooth packets received in the testcontroller tool
|
||||
return 70; // Observed to be anywhere between 60-90 hz. Possibly lossy in current state
|
||||
} else if (ctx->sensor_timestamp_supported) {
|
||||
// This firmware appears to update at 200 Hz over USB
|
||||
return 200;
|
||||
} else {
|
||||
// This firmware appears to update at 100 Hz over USB
|
||||
return 100;
|
||||
}
|
||||
case USB_PRODUCT_8BITDO_PRO_2:
|
||||
case USB_PRODUCT_8BITDO_PRO_2_BT: // Note, labeled as "BT" but appears this way when wired.
|
||||
case USB_PRODUCT_8BITDO_PRO_3:
|
||||
if (device->is_bluetooth) {
|
||||
// Note, This is estimated by observation of Bluetooth packets received in the testcontroller tool
|
||||
return 85; // Observed Bluetooth packet rate seems to be 80-90hz
|
||||
} else if (ctx->sensor_timestamp_supported) {
|
||||
// This firmware appears to update at 200 Hz over USB
|
||||
return 200;
|
||||
} else {
|
||||
// This firmware appears to update at 100 Hz over USB
|
||||
return 100;
|
||||
}
|
||||
case USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS:
|
||||
if (device->is_bluetooth) {
|
||||
// Note, This is estimated by observation of Bluetooth packets received in the testcontroller tool
|
||||
return 120; // Observed Bluetooth packet rate seems to be 120hz
|
||||
} else {
|
||||
// This firmware appears to update at 1000 Hz over USB dongle
|
||||
return 1000;
|
||||
}
|
||||
default:
|
||||
return 120;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DEG2RAD
|
||||
#define DEG2RAD(x) ((float)(x) * (float)(SDL_PI_F / 180.f))
|
||||
#endif
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
// Initialize the joystick capabilities
|
||||
if (device->product_id == USB_PRODUCT_8BITDO_PRO_2 ||
|
||||
device->product_id == USB_PRODUCT_8BITDO_PRO_2_BT ||
|
||||
device->product_id == USB_PRODUCT_8BITDO_PRO_3 ||
|
||||
device->product_id == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) {
|
||||
// This controller has additional buttons
|
||||
joystick->nbuttons = SDL_GAMEPAD_NUM_8BITDO_BUTTONS;
|
||||
} else {
|
||||
joystick->nbuttons = 11;
|
||||
}
|
||||
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
|
||||
joystick->nhats = 1;
|
||||
|
||||
if (ctx->sensors_supported) {
|
||||
|
||||
// Different 8Bitdo controllers in different connection modes have different polling rates.
|
||||
const Uint64 imu_polling_rate = HIDAPI_Driver8BitDo_GetIMURateForProductID(device);
|
||||
ctx->sensor_timestamp_interval = SDL_NS_PER_SECOND / imu_polling_rate;
|
||||
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, (float)imu_polling_rate);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, (float)imu_polling_rate);
|
||||
|
||||
ctx->accelScale = SDL_STANDARD_GRAVITY / ABITDO_ACCEL_SCALE;
|
||||
// Hardware senses +/- N Degrees per second mapped to +/- INT16_MAX
|
||||
ctx->gyroScale = DEG2RAD(ABITDO_GYRO_MAX_DEGREES_PER_SECOND) / INT16_MAX;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
|
||||
if (ctx->rumble_supported) {
|
||||
Uint8 rumble_packet[5] = { 0x05, 0x00, 0x00, 0x00, 0x00 };
|
||||
rumble_packet[1] = low_frequency_rumble >> 8;
|
||||
rumble_packet[2] = high_frequency_rumble >> 8;
|
||||
|
||||
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||
return SDL_SetError("Couldn't send rumble packet");
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static Uint32 HIDAPI_Driver8BitDo_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
|
||||
Uint32 caps = 0;
|
||||
if (ctx->rumble_supported) {
|
||||
caps |= SDL_JOYSTICK_CAP_RUMBLE;
|
||||
}
|
||||
if (ctx->rgb_supported) {
|
||||
caps |= SDL_JOYSTICK_CAP_RGB_LED;
|
||||
}
|
||||
return caps;
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
|
||||
if (ctx->sensors_supported) {
|
||||
ctx->sensors_enabled = enabled;
|
||||
return true;
|
||||
}
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_HandleOldStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->last_state[2] != data[2]) {
|
||||
Uint8 hat;
|
||||
|
||||
switch (data[2]) {
|
||||
case 0:
|
||||
hat = SDL_HAT_UP;
|
||||
break;
|
||||
case 1:
|
||||
hat = SDL_HAT_RIGHTUP;
|
||||
break;
|
||||
case 2:
|
||||
hat = SDL_HAT_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
hat = SDL_HAT_RIGHTDOWN;
|
||||
break;
|
||||
case 4:
|
||||
hat = SDL_HAT_DOWN;
|
||||
break;
|
||||
case 5:
|
||||
hat = SDL_HAT_LEFTDOWN;
|
||||
break;
|
||||
case 6:
|
||||
hat = SDL_HAT_LEFT;
|
||||
break;
|
||||
case 7:
|
||||
hat = SDL_HAT_LEFTUP;
|
||||
break;
|
||||
default:
|
||||
hat = SDL_HAT_CENTERED;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
}
|
||||
|
||||
if (ctx->last_state[0] != data[0]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x02) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x40) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x80) != 0));
|
||||
}
|
||||
|
||||
if (ctx->last_state[1] != data[1]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x04) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x20) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x40) != 0));
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[1] & 0x01) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[1] & 0x02) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
|
||||
}
|
||||
|
||||
#define READ_STICK_AXIS(offset) \
|
||||
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16))
|
||||
{
|
||||
axis = READ_STICK_AXIS(3);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = READ_STICK_AXIS(4);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
axis = READ_STICK_AXIS(5);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = READ_STICK_AXIS(6);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
}
|
||||
#undef READ_STICK_AXIS
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_HandleStatePacket(SDL_Joystick *joystick, SDL_Driver8BitDo_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
switch (data[0]) {
|
||||
case SDL_8BITDO_REPORTID_NOT_SUPPORTED_SDL_REPORTID: // Firmware without enhanced mode
|
||||
case SDL_8BITDO_REPORTID_SDL_REPORTID: // Enhanced mode USB report
|
||||
case SDL_8BITDO_BT_REPORTID_SDL_REPORTID: // Enhanced mode Bluetooth report
|
||||
break;
|
||||
default:
|
||||
// We don't know how to handle this report
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->last_state[1] != data[1]) {
|
||||
Uint8 hat;
|
||||
|
||||
switch (data[1]) {
|
||||
case 0:
|
||||
hat = SDL_HAT_UP;
|
||||
break;
|
||||
case 1:
|
||||
hat = SDL_HAT_RIGHTUP;
|
||||
break;
|
||||
case 2:
|
||||
hat = SDL_HAT_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
hat = SDL_HAT_RIGHTDOWN;
|
||||
break;
|
||||
case 4:
|
||||
hat = SDL_HAT_DOWN;
|
||||
break;
|
||||
case 5:
|
||||
hat = SDL_HAT_LEFTDOWN;
|
||||
break;
|
||||
case 6:
|
||||
hat = SDL_HAT_LEFT;
|
||||
break;
|
||||
case 7:
|
||||
hat = SDL_HAT_LEFTUP;
|
||||
break;
|
||||
default:
|
||||
hat = SDL_HAT_CENTERED;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
}
|
||||
|
||||
|
||||
if (ctx->last_state[8] != data[8]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[8] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[8] & 0x02) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[8] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[8] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[8] & 0x40) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[8] & 0x80) != 0));
|
||||
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_PL, ((data[8] & 0x20) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_PR, ((data[8] & 0x04) != 0));
|
||||
}
|
||||
|
||||
if (ctx->last_state[9] != data[9]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[9] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[9] & 0x04) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[9] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[9] & 0x20) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[9] & 0x40) != 0));
|
||||
}
|
||||
|
||||
if (size > 10 && ctx->last_state[10] != data[10]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_L4, ((data[10] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_8BITDO_R4, ((data[10] & 0x02) != 0));
|
||||
}
|
||||
|
||||
#define READ_STICK_AXIS(offset) \
|
||||
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16))
|
||||
{
|
||||
axis = READ_STICK_AXIS(2);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = READ_STICK_AXIS(3);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
axis = READ_STICK_AXIS(4);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = READ_STICK_AXIS(5);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
}
|
||||
#undef READ_STICK_AXIS
|
||||
|
||||
#define READ_TRIGGER_AXIS(offset) \
|
||||
(Sint16)(((int)data[offset] * 257) - 32768)
|
||||
{
|
||||
axis = READ_TRIGGER_AXIS(7);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||
axis = READ_TRIGGER_AXIS(6);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||
}
|
||||
#undef READ_TRIGGER_AXIS
|
||||
|
||||
if (ctx->powerstate_supported) {
|
||||
SDL_PowerState state;
|
||||
int percent;
|
||||
Uint8 status = data[14] >> 7;
|
||||
Uint8 level = (data[14] & 0x7f);
|
||||
if (level == 100) {
|
||||
status = 2;
|
||||
}
|
||||
switch (status) {
|
||||
case 0:
|
||||
state = SDL_POWERSTATE_ON_BATTERY;
|
||||
percent = level;
|
||||
break;
|
||||
case 1:
|
||||
state = SDL_POWERSTATE_CHARGING;
|
||||
percent = level;
|
||||
break;
|
||||
case 2:
|
||||
state = SDL_POWERSTATE_CHARGED;
|
||||
percent = 100;
|
||||
break;
|
||||
default:
|
||||
state = SDL_POWERSTATE_UNKNOWN;
|
||||
percent = 0;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
}
|
||||
|
||||
if (ctx->sensors_enabled) {
|
||||
Uint64 sensor_timestamp;
|
||||
float values[3];
|
||||
ABITDO_SENSORS *sensors = (ABITDO_SENSORS *)&data[15];
|
||||
|
||||
if (ctx->sensor_timestamp_supported) {
|
||||
Uint32 delta;
|
||||
Uint32 tick = LOAD32(data[27], data[28], data[29], data[30]);
|
||||
|
||||
if (ctx->last_tick) {
|
||||
if (ctx->last_tick < tick) {
|
||||
delta = (tick - ctx->last_tick);
|
||||
} else {
|
||||
delta = (SDL_MAX_UINT32 - ctx->last_tick + tick + 1);
|
||||
}
|
||||
// Sanity check the delta value
|
||||
if (delta < 100000) {
|
||||
ctx->sensor_timestamp_interval = SDL_US_TO_NS(delta);
|
||||
}
|
||||
}
|
||||
ctx->last_tick = tick;
|
||||
}
|
||||
|
||||
// Note: we cannot use the time stamp of the receiving computer due to packet delay creating "spiky" timings.
|
||||
// The imu time stamp is intended to be the sample time of the on-board hardware.
|
||||
// In the absence of time stamp data from the data[], we can simulate that by
|
||||
// advancing a time stamp by the observed/known imu clock rate. This is 8ms = 125 Hz
|
||||
sensor_timestamp = ctx->sensor_timestamp;
|
||||
ctx->sensor_timestamp += ctx->sensor_timestamp_interval;
|
||||
|
||||
// This device's IMU values are reported differently from SDL
|
||||
// Thus we perform a rotation of the coordinate system to match the SDL standard.
|
||||
|
||||
// By observation of this device:
|
||||
// Hardware x is reporting roll (rotation about the power jack's axis)
|
||||
// Hardware y is reporting pitch (rotation about the horizontal axis)
|
||||
// Hardware z is reporting yaw (rotation about the joysticks' center axis)
|
||||
values[0] = -sensors->sGyroY * ctx->gyroScale; // Rotation around pitch axis
|
||||
values[1] = sensors->sGyroZ * ctx->gyroScale; // Rotation around yaw axis
|
||||
values[2] = -sensors->sGyroX * ctx->gyroScale; // Rotation around roll axis
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, values, 3);
|
||||
|
||||
// By observation of this device:
|
||||
// Accelerometer X is positive when front of the controller points toward the sky.
|
||||
// Accelerometer y is positive when left side of the controller points toward the sky.
|
||||
// Accelerometer Z is positive when sticks point toward the sky.
|
||||
values[0] = -sensors->sAccelY * ctx->accelScale; // Acceleration along pitch axis
|
||||
values[1] = sensors->sAccelZ * ctx->accelScale; // Acceleration along yaw axis
|
||||
values[2] = -sensors->sAccelX * ctx->accelScale; // Acceleration along roll axis
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, values, 3);
|
||||
}
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static bool HIDAPI_Driver8BitDo_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_Driver8BitDo_Context *ctx = (SDL_Driver8BitDo_Context *)device->context;
|
||||
SDL_Joystick *joystick = NULL;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size = 0;
|
||||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
|
||||
#ifdef DEBUG_8BITDO_PROTOCOL
|
||||
HIDAPI_DumpPacket("8BitDo packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size == 9) {
|
||||
// Old firmware USB report for the SF30 Pro and SN30 Pro controllers
|
||||
HIDAPI_Driver8BitDo_HandleOldStatePacket(joystick, ctx, data, size);
|
||||
} else {
|
||||
HIDAPI_Driver8BitDo_HandleStatePacket(joystick, ctx, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
// Read error, device is disconnected
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
}
|
||||
|
||||
static void HIDAPI_Driver8BitDo_FreeDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_Driver8BitDo = {
|
||||
SDL_HINT_JOYSTICK_HIDAPI_8BITDO,
|
||||
true,
|
||||
HIDAPI_Driver8BitDo_RegisterHints,
|
||||
HIDAPI_Driver8BitDo_UnregisterHints,
|
||||
HIDAPI_Driver8BitDo_IsEnabled,
|
||||
HIDAPI_Driver8BitDo_IsSupportedDevice,
|
||||
HIDAPI_Driver8BitDo_InitDevice,
|
||||
HIDAPI_Driver8BitDo_GetDevicePlayerIndex,
|
||||
HIDAPI_Driver8BitDo_SetDevicePlayerIndex,
|
||||
HIDAPI_Driver8BitDo_UpdateDevice,
|
||||
HIDAPI_Driver8BitDo_OpenJoystick,
|
||||
HIDAPI_Driver8BitDo_RumbleJoystick,
|
||||
HIDAPI_Driver8BitDo_RumbleJoystickTriggers,
|
||||
HIDAPI_Driver8BitDo_GetJoystickCapabilities,
|
||||
HIDAPI_Driver8BitDo_SetJoystickLED,
|
||||
HIDAPI_Driver8BitDo_SendJoystickEffect,
|
||||
HIDAPI_Driver8BitDo_SetJoystickSensorsEnabled,
|
||||
HIDAPI_Driver8BitDo_CloseJoystick,
|
||||
HIDAPI_Driver8BitDo_FreeDevice,
|
||||
};
|
||||
|
||||
#endif // SDL_JOYSTICK_HIDAPI_8BITDO
|
||||
|
||||
#endif // SDL_JOYSTICK_HIDAPI
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -76,9 +76,7 @@ static bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Jo
|
||||
child = device->children[i];
|
||||
child->driver->CloseJoystick(child, joystick);
|
||||
}
|
||||
if (serial) {
|
||||
SDL_free(serial);
|
||||
}
|
||||
SDL_free(serial);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,9 +100,7 @@ static bool HIDAPI_DriverCombined_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Jo
|
||||
}
|
||||
|
||||
// Update the joystick with the combined serial numbers
|
||||
if (joystick->serial) {
|
||||
SDL_free(joystick->serial);
|
||||
}
|
||||
SDL_free(joystick->serial);
|
||||
joystick->serial = serial;
|
||||
|
||||
return true;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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.
|
||||
*/
|
||||
|
||||
// These are values used in the controller type byte of the controller GUID
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SDL_FLYDIGI_UNKNOWN,
|
||||
SDL_FLYDIGI_APEX2 = (1 << 0),
|
||||
SDL_FLYDIGI_APEX3,
|
||||
SDL_FLYDIGI_APEX4,
|
||||
SDL_FLYDIGI_APEX5,
|
||||
SDL_FLYDIGI_VADER2 = (1 << 4),
|
||||
SDL_FLYDIGI_VADER2_PRO,
|
||||
SDL_FLYDIGI_VADER3,
|
||||
SDL_FLYDIGI_VADER3_PRO,
|
||||
SDL_FLYDIGI_VADER4_PRO,
|
||||
SDL_FLYDIGI_VADER5_PRO,
|
||||
} SDL_FlyDigiControllerType;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -23,6 +23,7 @@
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
|
||||
#include "../../SDL_hints_c.h"
|
||||
#include "../../misc/SDL_libusb.h"
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
@@ -76,7 +77,8 @@ static bool HIDAPI_DriverGameCube_IsSupportedDevice(SDL_HIDAPI_Device *device, c
|
||||
}
|
||||
if (vendor_id == USB_VENDOR_DRAGONRISE &&
|
||||
(product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER1 ||
|
||||
product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2)) {
|
||||
product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2 ||
|
||||
product_id == USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER3)) {
|
||||
// EVORETRO GameCube Controller Adapter
|
||||
return true;
|
||||
}
|
||||
@@ -101,6 +103,83 @@ static void SDLCALL SDL_JoystickGameCubeRumbleBrakeHintChanged(void *userdata, c
|
||||
}
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverGameCube_EnableAdapter(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
#ifdef HAVE_LIBUSB
|
||||
// Need to close the device while sending USB commands to it
|
||||
SDL_hid_close(device->dev);
|
||||
|
||||
// This is needed to enable input for Nyko and EVORETRO GameCube adapters
|
||||
SDL_LibUSBContext *libusb_ctx;
|
||||
if (SDL_InitLibUSB(&libusb_ctx)) {
|
||||
libusb_context *context = NULL;
|
||||
libusb_device **devs = NULL;
|
||||
libusb_device_handle *handle = NULL;
|
||||
struct libusb_device_descriptor desc;
|
||||
ssize_t i, num_devs;
|
||||
bool kernel_detached = false;
|
||||
|
||||
if (libusb_ctx->init(&context) == 0) {
|
||||
num_devs = libusb_ctx->get_device_list(context, &devs);
|
||||
for (i = 0; i < num_devs; ++i) {
|
||||
if (libusb_ctx->get_device_descriptor(devs[i], &desc) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (desc.idVendor != USB_VENDOR_NINTENDO ||
|
||||
desc.idProduct != USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (libusb_ctx->open(devs[i], &handle) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (libusb_ctx->kernel_driver_active(handle, 0)) {
|
||||
if (libusb_ctx->detach_kernel_driver(handle, 0) == 0) {
|
||||
kernel_detached = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (libusb_ctx->claim_interface(handle, 0) == 0) {
|
||||
libusb_ctx->control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000);
|
||||
libusb_ctx->release_interface(handle, 0);
|
||||
}
|
||||
|
||||
if (kernel_detached) {
|
||||
libusb_ctx->attach_kernel_driver(handle, 0);
|
||||
}
|
||||
|
||||
libusb_ctx->close(handle);
|
||||
}
|
||||
|
||||
libusb_ctx->free_device_list(devs, 1);
|
||||
|
||||
libusb_ctx->exit(context);
|
||||
}
|
||||
SDL_QuitLibUSB();
|
||||
}
|
||||
|
||||
// Reopen the device now that we're done
|
||||
device->dev = SDL_hid_open_path(device->path);
|
||||
if (!device->dev) {
|
||||
return false;
|
||||
}
|
||||
#endif // HAVE_LIBUSB
|
||||
|
||||
Uint8 initMagic = 0x13;
|
||||
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the adapter to initialize
|
||||
SDL_Delay(10);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverGameCube_Context *ctx;
|
||||
@@ -108,13 +187,8 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
||||
Uint8 *curSlot;
|
||||
Uint8 i;
|
||||
int size;
|
||||
Uint8 initMagic = 0x13;
|
||||
Uint8 rumbleMagic = 0x11;
|
||||
|
||||
#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
|
||||
SDL_EnableGameCubeAdaptors();
|
||||
#endif
|
||||
|
||||
ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
return false;
|
||||
@@ -128,19 +202,21 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
|
||||
if (ctx->pc_mode) {
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
// We get a separate device for each slot
|
||||
ResetAxisRange(ctx, 0);
|
||||
HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
|
||||
#else
|
||||
for (i = 0; i < MAX_CONTROLLERS; ++i) {
|
||||
ResetAxisRange(ctx, i);
|
||||
HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// This is all that's needed to initialize the device. Really!
|
||||
if (SDL_hid_write(device->dev, &initMagic, sizeof(initMagic)) != sizeof(initMagic)) {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
|
||||
"HIDAPI_DriverGameCube_InitDevice(): Couldn't initialize WUP-028");
|
||||
if (!HIDAPI_DriverGameCube_EnableAdapter(device)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the adapter to initialize
|
||||
SDL_Delay(10);
|
||||
|
||||
// Add all the applicable joysticks
|
||||
while ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
|
||||
#ifdef DEBUG_GAMECUBE_PROTOCOL
|
||||
@@ -199,14 +275,25 @@ static void HIDAPI_DriverGameCube_SetDevicePlayerIndex(SDL_HIDAPI_Device *device
|
||||
{
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, const Uint8 *packet, bool invert_c_stick)
|
||||
static void HIDAPI_DriverGameCube_HandleJoystickPacket(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx, Uint8 slot, const Uint8 *packet, bool invert_c_stick)
|
||||
{
|
||||
SDL_Joystick *joystick;
|
||||
const Uint8 i = 0; // We have a separate context for each connected controller in PC mode, just use the first index
|
||||
Uint8 i;
|
||||
Uint8 v;
|
||||
Sint16 axis_value;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
// We get a separate device for each slot
|
||||
i = 0;
|
||||
#else
|
||||
i = slot;
|
||||
if (i >= MAX_CONTROLLERS) {
|
||||
// Invalid packet?
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
joystick = SDL_GetJoystickFromID(ctx->joysticks[i]);
|
||||
if (!joystick) {
|
||||
// Hasn't been opened yet, skip
|
||||
@@ -356,11 +443,11 @@ static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
// This is the older firmware
|
||||
// The first byte is the index of the connected controller
|
||||
// The C stick has an inverted value range compared to the left stick
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, &packet[1], true);
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet[0] - 1, &packet[1], true);
|
||||
} else if (size == 9) {
|
||||
// This is the newer firmware (version 0x7)
|
||||
// The C stick has the same value range compared to the left stick
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, packet, false);
|
||||
HIDAPI_DriverGameCube_HandleJoystickPacket(device, ctx, 0, packet, false);
|
||||
} else {
|
||||
// How do we handle this packet?
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -32,8 +32,6 @@
|
||||
// Define this if you want to log all packets from the controller
|
||||
// #define DEBUG_PS3_PROTOCOL
|
||||
|
||||
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
k_EPS3ReportIdState = 1,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -44,12 +44,6 @@
|
||||
|
||||
#define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
|
||||
|
||||
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
|
||||
#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) | \
|
||||
(((Uint32)(B)) << 8) | \
|
||||
(((Uint32)(C)) << 16) | \
|
||||
(((Uint32)(D)) << 24))
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_GAMEPAD_BUTTON_PS4_TOUCHPAD = 11
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -43,12 +43,6 @@
|
||||
#define ACCEL_RES_PER_G 8192.0f
|
||||
#define BLUETOOTH_DISCONNECT_TIMEOUT_MS 500
|
||||
|
||||
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
|
||||
#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) | \
|
||||
(((Uint32)(B)) << 8) | \
|
||||
(((Uint32)(C)) << 16) | \
|
||||
(((Uint32)(D)) << 24))
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_GAMEPAD_BUTTON_PS5_TOUCHPAD = 11,
|
||||
@@ -230,7 +224,7 @@ typedef struct
|
||||
{
|
||||
SDL_HIDAPI_Device *device;
|
||||
SDL_Joystick *joystick;
|
||||
bool is_nacon_dongle;
|
||||
bool is_dongle;
|
||||
bool use_alternate_report;
|
||||
bool sensors_supported;
|
||||
bool lightbar_supported;
|
||||
@@ -251,6 +245,7 @@ typedef struct
|
||||
Uint64 last_packet;
|
||||
int player_index;
|
||||
bool player_lights;
|
||||
bool enhanced_rumble;
|
||||
Uint8 rumble_left;
|
||||
Uint8 rumble_right;
|
||||
bool color_set;
|
||||
@@ -432,6 +427,14 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
}
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
if (device->product_id == USB_PRODUCT_SONY_DS5_EDGE ||
|
||||
ctx->firmware_version == 0 || // Assume that it's updated firmware over Bluetooth
|
||||
ctx->firmware_version >= 0x0224) {
|
||||
ctx->enhanced_rumble = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the device capabilities
|
||||
if (device->vendor_id == USB_VENDOR_SONY) {
|
||||
ctx->sensors_supported = true;
|
||||
@@ -506,8 +509,10 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
|
||||
ctx->touchpad_supported = true;
|
||||
ctx->use_alternate_report = true;
|
||||
} else if (device->vendor_id == USB_VENDOR_RAZER &&
|
||||
device->product_id == USB_PRODUCT_RAZER_KITSUNE) {
|
||||
// The Razer Kitsune doesn't respond to the detection protocol, but has a touchpad
|
||||
(device->product_id == USB_PRODUCT_RAZER_KITSUNE ||
|
||||
device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRED ||
|
||||
device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRELESS)) {
|
||||
// The Razer Kitsune and Raiju don't respond to the detection protocol, but have a touchpad
|
||||
joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
|
||||
ctx->touchpad_supported = true;
|
||||
ctx->use_alternate_report = true;
|
||||
@@ -515,9 +520,13 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported);
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_NACON_ALT &&
|
||||
device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS) {
|
||||
ctx->is_nacon_dongle = true;
|
||||
if ((device->vendor_id == USB_VENDOR_NACON_ALT &&
|
||||
device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS) ||
|
||||
(device->vendor_id == USB_VENDOR_RAZER &&
|
||||
(device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS ||
|
||||
device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS ||
|
||||
device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRELESS))) {
|
||||
ctx->is_dongle = true;
|
||||
}
|
||||
|
||||
device->joystick_type = joystick_type;
|
||||
@@ -531,7 +540,7 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
HIDAPI_SetDeviceSerial(device, serial);
|
||||
|
||||
if (ctx->is_nacon_dongle) {
|
||||
if (ctx->is_dongle) {
|
||||
// We don't know if this is connected yet, wait for reports
|
||||
return true;
|
||||
}
|
||||
@@ -684,17 +693,17 @@ static bool HIDAPI_DriverPS5_UpdateEffects(SDL_DriverPS5_Context *ctx, int effec
|
||||
|
||||
if (ctx->vibration_supported) {
|
||||
if (ctx->rumble_left || ctx->rumble_right) {
|
||||
if (ctx->firmware_version < 0x0224) {
|
||||
if (ctx->enhanced_rumble) {
|
||||
effects.ucEnableBits3 |= 0x04; // Enable improved rumble emulation on 2.24 firmware and newer
|
||||
|
||||
effects.ucRumbleLeft = ctx->rumble_left;
|
||||
effects.ucRumbleRight = ctx->rumble_right;
|
||||
} else {
|
||||
effects.ucEnableBits1 |= 0x01; // Enable rumble emulation
|
||||
|
||||
// Shift to reduce effective rumble strength to match Xbox controllers
|
||||
effects.ucRumbleLeft = ctx->rumble_left >> 1;
|
||||
effects.ucRumbleRight = ctx->rumble_right >> 1;
|
||||
} else {
|
||||
effects.ucEnableBits3 |= 0x04; // Enable improved rumble emulation on 2.24 firmware and newer
|
||||
|
||||
effects.ucRumbleLeft = ctx->rumble_left;
|
||||
effects.ucRumbleRight = ctx->rumble_right;
|
||||
}
|
||||
effects.ucEnableBits1 |= 0x02; // Disable audio haptics
|
||||
} else {
|
||||
@@ -814,7 +823,7 @@ static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx
|
||||
if (ctx->sensors_supported) {
|
||||
// Standard DualSense sensor update rate is 250 Hz over USB
|
||||
float update_rate = 250.0f;
|
||||
|
||||
|
||||
if (ctx->device->is_bluetooth) {
|
||||
// Bluetooth sensor update rate appears to be 1000 Hz
|
||||
update_rate = 1000.0f;
|
||||
@@ -955,6 +964,10 @@ static bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystic
|
||||
joystick->nhats = 1;
|
||||
joystick->firmware_version = ctx->firmware_version;
|
||||
|
||||
if (ctx->is_dongle) {
|
||||
joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS;
|
||||
}
|
||||
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_ENHANCED_REPORTS,
|
||||
SDL_PS5EnhancedReportsChanged, ctx);
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED,
|
||||
@@ -1038,6 +1051,9 @@ static bool HIDAPI_DriverPS5_InternalSendJoystickEffect(SDL_DriverPS5_Context *c
|
||||
if (!ctx->enhanced_mode) {
|
||||
if (application_usage) {
|
||||
HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx);
|
||||
|
||||
// Wait briefly before sending additional effects
|
||||
SDL_Delay(10);
|
||||
}
|
||||
|
||||
if (!ctx->enhanced_mode) {
|
||||
@@ -1050,10 +1066,11 @@ static bool HIDAPI_DriverPS5_InternalSendJoystickEffect(SDL_DriverPS5_Context *c
|
||||
|
||||
if (ctx->device->is_bluetooth) {
|
||||
data[0] = k_EPS5ReportIdBluetoothEffects;
|
||||
data[1] = 0x02; // Magic value
|
||||
data[1] = 0x00; // Tag and sequence
|
||||
data[2] = 0x10; // Magic value
|
||||
|
||||
report_size = 78;
|
||||
offset = 2;
|
||||
offset = 3;
|
||||
} else {
|
||||
data[0] = k_EPS5ReportIdUsbEffects;
|
||||
|
||||
@@ -1452,15 +1469,16 @@ static bool HIDAPI_DriverPS5_IsPacketValid(SDL_DriverPS5_Context *ctx, Uint8 *da
|
||||
{
|
||||
switch (data[0]) {
|
||||
case k_EPS5ReportIdState:
|
||||
if (ctx->is_nacon_dongle && size >= (1 + sizeof(PS5StatePacketAlt_t))) {
|
||||
if (ctx->is_dongle && size >= (1 + sizeof(PS5StatePacketAlt_t))) {
|
||||
// The report timestamp doesn't change when the controller isn't connected
|
||||
PS5StatePacketAlt_t *packet = (PS5StatePacketAlt_t *)&data[1];
|
||||
if (SDL_memcmp(packet->rgucPacketSequence, ctx->last_state.state.rgucPacketSequence, sizeof(packet->rgucPacketSequence)) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (ctx->last_state.alt_state.rgucAccelX[0] == 0 && ctx->last_state.alt_state.rgucAccelX[1] == 0 &&
|
||||
ctx->last_state.alt_state.rgucAccelY[0] == 0 && ctx->last_state.alt_state.rgucAccelY[1] == 0 &&
|
||||
ctx->last_state.alt_state.rgucAccelZ[0] == 0 && ctx->last_state.alt_state.rgucAccelZ[1] == 0) {
|
||||
if (ctx->last_state.state.rgucPacketSequence[0] == 0 &&
|
||||
ctx->last_state.state.rgucPacketSequence[1] == 0 &&
|
||||
ctx->last_state.state.rgucPacketSequence[2] == 0 &&
|
||||
ctx->last_state.state.rgucPacketSequence[3] == 0) {
|
||||
// We don't have any state to compare yet, go ahead and copy it
|
||||
SDL_memcpy(&ctx->last_state, &data[1], sizeof(PS5StatePacketAlt_t));
|
||||
return false;
|
||||
@@ -1559,7 +1577,7 @@ static bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->is_nacon_dongle) {
|
||||
if (ctx->is_dongle) {
|
||||
if (packet_count == 0) {
|
||||
if (device->num_joysticks > 0) {
|
||||
// Check to see if it looks like the device disconnected
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -28,7 +28,7 @@
|
||||
#ifdef SDL_THREAD_SAFETY_ANALYSIS
|
||||
extern SDL_Mutex *SDL_HIDAPI_rumble_lock;
|
||||
#endif
|
||||
bool SDL_HIDAPI_LockRumble(void) SDL_TRY_ACQUIRE(0, SDL_HIDAPI_rumble_lock);
|
||||
bool SDL_HIDAPI_LockRumble(void) SDL_TRY_ACQUIRE(true, SDL_HIDAPI_rumble_lock);
|
||||
bool SDL_HIDAPI_GetPendingRumbleLocked(SDL_HIDAPI_Device *device, Uint8 **data, int **size, int *maximum_size);
|
||||
int SDL_HIDAPI_SendRumbleAndUnlock(SDL_HIDAPI_Device *device, const Uint8 *data, int size) SDL_RELEASE(SDL_HIDAPI_rumble_lock);
|
||||
typedef void (*SDL_HIDAPI_RumbleSentCallback)(void *userdata);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -29,7 +29,9 @@
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SHIELD
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
// #define DEBUG_SHIELD_PROTOCOL
|
||||
#if 0
|
||||
#define DEBUG_SHIELD_PROTOCOL
|
||||
#endif
|
||||
|
||||
#define CMD_BATTERY_STATE 0x07
|
||||
#define CMD_RUMBLE 0x39
|
||||
@@ -138,6 +140,11 @@ static void HIDAPI_DriverShield_SetDevicePlayerIndex(SDL_HIDAPI_Device *device,
|
||||
|
||||
static bool HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd, const void *data, int size)
|
||||
{
|
||||
#ifdef SDL_PLATFORM_MACOS
|
||||
// We hang for several seconds when trying to send output reports on macOS
|
||||
return SDL_Unsupported();
|
||||
|
||||
#else
|
||||
SDL_DriverShield_Context *ctx = (SDL_DriverShield_Context *)device->context;
|
||||
ShieldCommandReport_t cmd_pkt;
|
||||
|
||||
@@ -166,6 +173,8 @@ static bool HIDAPI_DriverShield_SendCommand(SDL_HIDAPI_Device *device, Uint8 cmd
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#endif // MACOS
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverShield_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
@@ -289,6 +298,7 @@ static bool HIDAPI_DriverShield_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *dev
|
||||
static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
Sint16 axis;
|
||||
|
||||
if (ctx->last_state[3] != data[3]) {
|
||||
Uint8 hat;
|
||||
@@ -346,14 +356,20 @@ static void HIDAPI_DriverShield_HandleStatePacketV103(SDL_Joystick *joystick, SD
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[2] & 0x80) != 0));
|
||||
}
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[4]) - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[6]) - 0x8000);
|
||||
axis = LOAD16(data[4], data[5]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = LOAD16(data[6], data[7]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[8]) - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[10]) - 0x8000);
|
||||
axis = LOAD16(data[8], data[9]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = LOAD16(data[10], data[11]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[12]) - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[14]) - 0x8000);
|
||||
axis = LOAD16(data[12], data[13]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||
axis = LOAD16(data[14], data[15]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
@@ -379,6 +395,7 @@ static void HIDAPI_DriverShield_HandleTouchPacketV103(SDL_Joystick *joystick, SD
|
||||
static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SDL_DriverShield_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
Sint16 axis;
|
||||
|
||||
if (size < 23) {
|
||||
return;
|
||||
@@ -434,14 +451,20 @@ static void HIDAPI_DriverShield_HandleStatePacketV104(SDL_Joystick *joystick, SD
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[4] & 0x01) != 0));
|
||||
}
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, SDL_Swap16LE(*(Sint16 *)&data[9]) - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, SDL_Swap16LE(*(Sint16 *)&data[11]) - 0x8000);
|
||||
axis = LOAD16(data[9], data[10]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = LOAD16(data[11], data[12]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, SDL_Swap16LE(*(Sint16 *)&data[13]) - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, SDL_Swap16LE(*(Sint16 *)&data[15]) - 0x8000);
|
||||
axis = LOAD16(data[13], data[14]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = LOAD16(data[15], data[16]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[19]) - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, SDL_Swap16LE(*(Sint16 *)&data[21]) - 0x8000);
|
||||
axis = LOAD16(data[19], data[20]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||
axis = LOAD16(data[21], data[22]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||
|
||||
if (ctx->last_state[17] != data[17]) {
|
||||
//SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SHIELD_SHARE, ((data[17] & 0x01) != 0));
|
||||
@@ -482,13 +505,13 @@ static bool HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
#ifdef DEBUG_SHIELD_PROTOCOL
|
||||
HIDAPI_DumpPacket("NVIDIA SHIELD packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Byte 0 is HID report ID
|
||||
switch (data[0]) {
|
||||
case k_ShieldReportIdControllerState:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
if (size == 16) {
|
||||
HIDAPI_DriverShield_HandleStatePacketV103(joystick, ctx, data, size);
|
||||
} else {
|
||||
@@ -496,9 +519,6 @@ static bool HIDAPI_DriverShield_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
}
|
||||
break;
|
||||
case k_ShieldReportIdControllerTouch:
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverShield_HandleTouchPacketV103(joystick, ctx, data, size);
|
||||
break;
|
||||
case k_ShieldReportIdCommandResponse:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 2025 Mitchell Cairns <mitch.cairns@handheldlegend.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_ANALOGSTYLE_NONE,
|
||||
SINPUT_ANALOGSTYLE_LEFTONLY,
|
||||
SINPUT_ANALOGSTYLE_RIGHTONLY,
|
||||
SINPUT_ANALOGSTYLE_LEFTRIGHT,
|
||||
SINPUT_ANALOGSTYLE_MAX,
|
||||
} SInput_AnalogStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_BUMPERSTYLE_NONE,
|
||||
SINPUT_BUMPERSTYLE_ONE,
|
||||
SINPUT_BUMPERSTYLE_TWO,
|
||||
SINPUT_BUMPERSTYLE_MAX,
|
||||
} SInput_BumperStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_TRIGGERSTYLE_NONE,
|
||||
SINPUT_TRIGGERSTYLE_ANALOG,
|
||||
SINPUT_TRIGGERSTYLE_DIGITAL,
|
||||
SINPUT_TRIGGERSTYLE_DUALSTAGE,
|
||||
SINPUT_TRIGGERSTYLE_MAX,
|
||||
} SInput_TriggerStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_PADDLESTYLE_NONE,
|
||||
SINPUT_PADDLESTYLE_TWO,
|
||||
SINPUT_PADDLESTYLE_FOUR,
|
||||
SINPUT_PADDLESTYLE_MAX,
|
||||
} SInput_PaddleStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_METASTYLE_NONE,
|
||||
SINPUT_METASTYLE_BACK,
|
||||
SINPUT_METASTYLE_BACKGUIDE,
|
||||
SINPUT_METASTYLE_BACKGUIDESHARE,
|
||||
SINPUT_METASTYLE_MAX,
|
||||
} SInput_MetaStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_TOUCHSTYLE_NONE,
|
||||
SINPUT_TOUCHSTYLE_SINGLE,
|
||||
SINPUT_TOUCHSTYLE_DOUBLE,
|
||||
SINPUT_TOUCHSTYLE_MAX,
|
||||
} SInput_TouchStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_MISCSTYLE_NONE,
|
||||
SINPUT_MISCSTYLE_1,
|
||||
SINPUT_MISCSTYLE_2,
|
||||
SINPUT_MISCSTYLE_3,
|
||||
SINPUT_MISCSTYLE_4,
|
||||
SINPUT_MISCSTYLE_MAX,
|
||||
} SInput_MiscStyleType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint16 analog_style;
|
||||
Uint16 bumper_style;
|
||||
Uint16 trigger_style;
|
||||
Uint16 paddle_style;
|
||||
Uint16 meta_style;
|
||||
Uint16 touch_style;
|
||||
Uint16 misc_style;
|
||||
} SDL_SInputStyles_t;
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -221,7 +221,7 @@ static void hexdump(const uint8_t *ptr, int len)
|
||||
|
||||
static void ResetSteamControllerPacketAssembler(SteamControllerPacketAssembler *pAssembler)
|
||||
{
|
||||
SDL_memset(pAssembler->uBuffer, 0, sizeof(pAssembler->uBuffer));
|
||||
SDL_zeroa(pAssembler->uBuffer);
|
||||
pAssembler->nExpectedSegmentNumber = 0;
|
||||
}
|
||||
|
||||
@@ -320,7 +320,7 @@ static int SetFeatureReport(SDL_HIDAPI_Device *dev, const unsigned char uBuffer[
|
||||
nActualDataLen -= nBytesInPacket;
|
||||
|
||||
// Construct packet
|
||||
SDL_memset(uPacketBuffer, 0, sizeof(uPacketBuffer));
|
||||
SDL_zeroa(uPacketBuffer);
|
||||
uPacketBuffer[0] = BLE_REPORT_NUMBER;
|
||||
uPacketBuffer[1] = GetSegmentHeader(nSegmentNumber, nActualDataLen == 0);
|
||||
SDL_memcpy(&uPacketBuffer[2], pBufferPtr, nBytesInPacket);
|
||||
@@ -370,7 +370,7 @@ static int GetFeatureReport(SDL_HIDAPI_Device *dev, unsigned char uBuffer[65])
|
||||
#endif
|
||||
|
||||
while (nRetries < BLE_MAX_READ_RETRIES) {
|
||||
SDL_memset(uSegmentBuffer, 0, sizeof(uSegmentBuffer));
|
||||
SDL_zeroa(uSegmentBuffer);
|
||||
uSegmentBuffer[0] = BLE_REPORT_NUMBER;
|
||||
nRet = SDL_hid_get_feature_report(dev->dev, uSegmentBuffer, ucBytesToRead);
|
||||
|
||||
@@ -457,6 +457,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew
|
||||
|
||||
DPRINTF("ResetSteamController hid=%p\n", dev);
|
||||
|
||||
SDL_zero(buf);
|
||||
buf[0] = 0;
|
||||
buf[1] = ID_GET_ATTRIBUTES_VALUES;
|
||||
res = SetFeatureReport(dev, buf, 2);
|
||||
@@ -510,6 +511,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew
|
||||
}
|
||||
|
||||
// Clear digital button mappings
|
||||
SDL_zero(buf);
|
||||
buf[0] = 0;
|
||||
buf[1] = ID_CLEAR_DIGITAL_MAPPINGS;
|
||||
res = SetFeatureReport(dev, buf, 2);
|
||||
@@ -521,7 +523,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew
|
||||
}
|
||||
|
||||
// Reset the default settings
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_LOAD_DEFAULT_SETTINGS;
|
||||
buf[2] = 0;
|
||||
res = SetFeatureReport(dev, buf, 3);
|
||||
@@ -539,7 +541,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew
|
||||
buf[3 + nSettings * 3 + 2] = ((uint16_t)VALUE) >> 8; \
|
||||
++nSettings;
|
||||
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_SET_SETTINGS_VALUES;
|
||||
ADD_SETTING(SETTING_WIRELESS_PACKET_VERSION, 2);
|
||||
ADD_SETTING(SETTING_LEFT_TRACKPAD_MODE, TRACKPAD_NONE);
|
||||
@@ -567,7 +569,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew
|
||||
bool bMappingsCleared = false;
|
||||
int iRetry;
|
||||
for (iRetry = 0; iRetry < 2; ++iRetry) {
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_GET_DIGITAL_MAPPINGS;
|
||||
buf[2] = 1; // one byte - requesting from index 0
|
||||
buf[3] = 0;
|
||||
@@ -596,7 +598,7 @@ static bool ResetSteamController(SDL_HIDAPI_Device *dev, bool bSuppressErrorSpew
|
||||
}
|
||||
|
||||
// Set our new mappings
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_SET_DIGITAL_MAPPINGS;
|
||||
buf[2] = 6; // 2 settings x 3 bytes
|
||||
buf[3] = IO_DIGITAL_BUTTON_RIGHT_TRIGGER;
|
||||
@@ -634,7 +636,7 @@ static int ReadSteamController(SDL_hid_device *dev, uint8_t *pData, int nDataSiz
|
||||
static void SetPairingState(SDL_HIDAPI_Device *dev, bool bEnablePairing)
|
||||
{
|
||||
unsigned char buf[65];
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_ENABLE_PAIRING;
|
||||
buf[2] = 2; // 2 payload bytes: bool + timeout
|
||||
buf[3] = bEnablePairing ? 1 : 0;
|
||||
@@ -648,7 +650,7 @@ static void SetPairingState(SDL_HIDAPI_Device *dev, bool bEnablePairing)
|
||||
static void CommitPairing(SDL_HIDAPI_Device *dev)
|
||||
{
|
||||
unsigned char buf[65];
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_DONGLE_COMMIT_DEVICE;
|
||||
SetFeatureReport(dev, buf, 2);
|
||||
}
|
||||
@@ -663,18 +665,18 @@ static void CloseSteamController(SDL_HIDAPI_Device *dev)
|
||||
int nSettings = 0;
|
||||
|
||||
// Reset digital button mappings
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_SET_DEFAULT_DIGITAL_MAPPINGS;
|
||||
SetFeatureReport(dev, buf, 2);
|
||||
|
||||
// Reset the default settings
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_LOAD_DEFAULT_SETTINGS;
|
||||
buf[2] = 0;
|
||||
SetFeatureReport(dev, buf, 3);
|
||||
|
||||
// Reset mouse mode for lizard mode
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_SET_SETTINGS_VALUES;
|
||||
ADD_SETTING(SETTING_RIGHT_TRACKPAD_MODE, TRACKPAD_ABSOLUTE_MOUSE);
|
||||
buf[2] = (unsigned char)(nSettings * 3);
|
||||
@@ -706,13 +708,6 @@ static void RotatePad(int *pX, int *pY, float flAngleInRad)
|
||||
*pX = (int)(SDL_cosf(flAngleInRad) * origX - SDL_sinf(flAngleInRad) * origY);
|
||||
*pY = (int)(SDL_sinf(flAngleInRad) * origX + SDL_cosf(flAngleInRad) * origY);
|
||||
}
|
||||
static void RotatePadShort(short *pX, short *pY, float flAngleInRad)
|
||||
{
|
||||
int origX = *pX, origY = *pY;
|
||||
|
||||
*pX = (short)(SDL_cosf(flAngleInRad) * origX - SDL_sinf(flAngleInRad) * origY);
|
||||
*pY = (short)(SDL_sinf(flAngleInRad) * origX + SDL_cosf(flAngleInRad) * origY);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Format the first part of the state packet
|
||||
@@ -836,9 +831,16 @@ static void FormatStatePacketUntilGyro(SteamControllerStateInternal_t *pState, V
|
||||
//---------------------------------------------------------------------------
|
||||
static bool UpdateBLESteamControllerState(const uint8_t *pData, int nDataSize, SteamControllerStateInternal_t *pState)
|
||||
{
|
||||
const float flRotationAngle = 0.261799f;
|
||||
int nLeftPadX;
|
||||
int nLeftPadY;
|
||||
int nRightPadX;
|
||||
int nRightPadY;
|
||||
int nPadOffset;
|
||||
uint32_t ucOptionDataMask;
|
||||
|
||||
// 15 degrees in rad
|
||||
const float flRotationAngle = 0.261799f;
|
||||
|
||||
pState->unPacketNum++;
|
||||
ucOptionDataMask = (*pData++ & 0xF0);
|
||||
ucOptionDataMask |= (uint32_t)(*pData++) << 8;
|
||||
@@ -867,7 +869,6 @@ static bool UpdateBLESteamControllerState(const uint8_t *pData, int nDataSize, S
|
||||
}
|
||||
if (ucOptionDataMask & k_EBLELeftTrackpadChunk) {
|
||||
int nLength = sizeof(pState->sLeftPadX) + sizeof(pState->sLeftPadY);
|
||||
int nPadOffset;
|
||||
SDL_memcpy(&pState->sLeftPadX, pData, nLength);
|
||||
if (pState->ulButtons & STEAM_LEFTPAD_FINGERDOWN_MASK) {
|
||||
nPadOffset = 1000;
|
||||
@@ -875,14 +876,15 @@ static bool UpdateBLESteamControllerState(const uint8_t *pData, int nDataSize, S
|
||||
nPadOffset = 0;
|
||||
}
|
||||
|
||||
RotatePadShort(&pState->sLeftPadX, &pState->sLeftPadY, -flRotationAngle);
|
||||
pState->sLeftPadX = (short)clamp(pState->sLeftPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
pState->sLeftPadY = (short)clamp(pState->sLeftPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
nLeftPadX = pState->sLeftPadX;
|
||||
nLeftPadY = pState->sLeftPadY;
|
||||
RotatePad(&nLeftPadX, &nLeftPadY, -flRotationAngle);
|
||||
pState->sLeftPadX = (short)clamp(nLeftPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
pState->sLeftPadY = (short)clamp(nLeftPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
pData += nLength;
|
||||
}
|
||||
if (ucOptionDataMask & k_EBLERightTrackpadChunk) {
|
||||
int nLength = sizeof(pState->sRightPadX) + sizeof(pState->sRightPadY);
|
||||
int nPadOffset = 0;
|
||||
|
||||
SDL_memcpy(&pState->sRightPadX, pData, nLength);
|
||||
|
||||
@@ -892,9 +894,11 @@ static bool UpdateBLESteamControllerState(const uint8_t *pData, int nDataSize, S
|
||||
nPadOffset = 0;
|
||||
}
|
||||
|
||||
RotatePadShort(&pState->sRightPadX, &pState->sRightPadY, flRotationAngle);
|
||||
pState->sRightPadX = (short)clamp(pState->sRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
pState->sRightPadY = (short)clamp(pState->sRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
nRightPadX = pState->sRightPadX;
|
||||
nRightPadY = pState->sRightPadY;
|
||||
RotatePad(&nRightPadX, &nRightPadY, flRotationAngle);
|
||||
pState->sRightPadX = (short)clamp(nRightPadX + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
pState->sRightPadY = (short)clamp(nRightPadY + nPadOffset, SDL_MIN_SINT16, SDL_MAX_SINT16);
|
||||
pData += nLength;
|
||||
}
|
||||
if (ucOptionDataMask & k_EBLEIMUAccelChunk) {
|
||||
@@ -1038,6 +1042,11 @@ static bool HIDAPI_DriverSteam_IsSupportedDevice(SDL_HIDAPI_Device *device, cons
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!device) {
|
||||
// Might be supported by this driver, enumerate and find out
|
||||
return true;
|
||||
}
|
||||
|
||||
if (device->is_bluetooth) {
|
||||
return true;
|
||||
}
|
||||
@@ -1133,6 +1142,7 @@ static bool HIDAPI_DriverSteam_InitDevice(SDL_HIDAPI_Device *device)
|
||||
unsigned char buf[65];
|
||||
int res;
|
||||
|
||||
SDL_zero(buf);
|
||||
buf[0] = 0;
|
||||
buf[1] = ID_DONGLE_GET_WIRELESS_STATE;
|
||||
res = SetFeatureReport(device, buf, 2);
|
||||
@@ -1194,7 +1204,7 @@ static bool SetHomeLED(SDL_HIDAPI_Device *device, Uint8 value)
|
||||
unsigned char buf[65];
|
||||
int nSettings = 0;
|
||||
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_SET_SETTINGS_VALUES;
|
||||
ADD_SETTING(SETTING_LED_USER_BRIGHTNESS, value);
|
||||
buf[2] = (unsigned char)(nSettings * 3);
|
||||
@@ -1305,7 +1315,7 @@ static bool HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_
|
||||
unsigned char buf[65];
|
||||
int nSettings = 0;
|
||||
|
||||
SDL_memset(buf, 0, 65);
|
||||
SDL_zero(buf);
|
||||
buf[1] = ID_SET_SETTINGS_VALUES;
|
||||
if (enabled) {
|
||||
ADD_SETTING(SETTING_IMU_MODE, SETTING_GYRO_MODE_SEND_RAW_ACCEL | SETTING_GYRO_MODE_SEND_RAW_GYRO);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -32,8 +32,6 @@
|
||||
/* Define this if you want to log all packets from the controller */
|
||||
/*#define DEBUG_HORI_PROTOCOL*/
|
||||
|
||||
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_GAMEPAD_BUTTON_HORI_QAM = 11,
|
||||
@@ -51,6 +49,8 @@ typedef struct
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
Uint64 sensor_ticks;
|
||||
Uint32 last_tick;
|
||||
Uint64 simulated_sensor_step_ns;
|
||||
Uint64 simulated_sensor_time_stamp;
|
||||
bool wireless;
|
||||
bool serial_needs_init;
|
||||
} SDL_DriverSteamHori_Context;
|
||||
@@ -114,21 +114,25 @@ static bool HIDAPI_DriverSteamHori_OpenJoystick(SDL_HIDAPI_Device *device, SDL_J
|
||||
/* Initialize the joystick capabilities */
|
||||
joystick->nbuttons = SDL_GAMEPAD_NUM_HORI_BUTTONS;
|
||||
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
|
||||
joystick->nhats = 1;
|
||||
joystick->nhats = 1;
|
||||
|
||||
ctx->wireless = device->product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT;
|
||||
ctx->wireless = device->product_id == USB_PRODUCT_HORI_STEAM_CONTROLLER_BT;
|
||||
|
||||
if (ctx->wireless && device->serial) {
|
||||
joystick->serial = SDL_strdup(device->serial);
|
||||
ctx->serial_needs_init = false;
|
||||
} else if (!ctx->wireless) {
|
||||
// Need to actual read from the device to init the serial
|
||||
HIDAPI_DriverSteamHori_UpdateDevice(device);
|
||||
}
|
||||
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f);
|
||||
if (ctx->wireless && device->serial) {
|
||||
joystick->serial = SDL_strdup(device->serial);
|
||||
ctx->serial_needs_init = false;
|
||||
} else if (!ctx->wireless) {
|
||||
// Need to actual read from the device to init the serial
|
||||
HIDAPI_DriverSteamHori_UpdateDevice(device);
|
||||
}
|
||||
|
||||
const float sensorupdaterate = ctx->wireless ? 120.0f : 250.0f;
|
||||
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, sensorupdaterate);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, sensorupdaterate);
|
||||
|
||||
const Uint64 sensorupdatestep_ms = ctx->wireless ? 8333 : 4000; // Equivalent to 120hz / 250hz respectively
|
||||
ctx->simulated_sensor_step_ns = SDL_US_TO_NS(sensorupdatestep_ms);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -275,12 +279,13 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_HORI_FL, ((data[7] & 0x80) != 0));
|
||||
}
|
||||
|
||||
if (!ctx->wireless && ctx->serial_needs_init) {
|
||||
if (!ctx->wireless && ctx->serial_needs_init) {
|
||||
char serial[18];
|
||||
(void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[38], data[39], data[40], data[41], data[42], data[43]);
|
||||
(void)SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
|
||||
data[38], data[39], data[40], data[41], data[42], data[43]);
|
||||
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
SDL_AssertJoysticksLocked();
|
||||
joystick->serial = SDL_strdup(serial);
|
||||
ctx->serial_needs_init = false;
|
||||
}
|
||||
|
||||
@@ -312,7 +317,11 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
|
||||
ctx->sensor_ticks += delta;
|
||||
|
||||
/* Sensor timestamp is in 1us units, but there seems to be some issues with the values reported from the device */
|
||||
sensor_timestamp = timestamp; // if the values were good we woudl call SDL_US_TO_NS(ctx->sensor_ticks);
|
||||
// sensor_timestamp = timestamp; // if the values were good we would call SDL_US_TO_NS(ctx->sensor_ticks);
|
||||
|
||||
/* New approach - simulate a fixed rate of 250hz (from observation). This reduces stutter from dropped/racing bluetooth packets.*/
|
||||
ctx->simulated_sensor_time_stamp += ctx->simulated_sensor_step_ns;
|
||||
sensor_timestamp = ctx->simulated_sensor_time_stamp;
|
||||
|
||||
const float accelScale = SDL_STANDARD_GRAVITY * 8 / 32768.0f;
|
||||
const float gyroScale = DEG2RAD(2048);
|
||||
@@ -320,7 +329,6 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
|
||||
imu_data[1] = RemapValClamped(-1.0f * LOAD16(data[12], data[13]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale);
|
||||
imu_data[2] = RemapValClamped(-1.0f * LOAD16(data[14], data[15]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale);
|
||||
imu_data[0] = RemapValClamped(-1.0f * LOAD16(data[16], data[17]), INT16_MIN, INT16_MAX, -gyroScale, gyroScale);
|
||||
|
||||
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, sensor_timestamp, imu_data, 3);
|
||||
|
||||
@@ -334,8 +342,9 @@ static void HIDAPI_DriverSteamHori_HandleStatePacket(SDL_Joystick *joystick, SDL
|
||||
if (ctx->last_state[24] != data[24]) {
|
||||
bool bCharging = (data[24] & 0x10) != 0;
|
||||
int percent = (data[24] & 0xF) * 10;
|
||||
SDL_PowerState state;
|
||||
if (bCharging) {
|
||||
SDL_PowerState state;
|
||||
|
||||
if (bCharging) {
|
||||
state = SDL_POWERSTATE_CHARGING;
|
||||
} else if (ctx->wireless) {
|
||||
state = SDL_POWERSTATE_ON_BATTERY;
|
||||
|
||||
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 2023 Max Maisel <max.maisel@posteo.de>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_STEAM_TRITON
|
||||
|
||||
/*****************************************************************************************************/
|
||||
|
||||
#include "steam/controller_constants.h"
|
||||
#include "steam/controller_structs.h"
|
||||
|
||||
// Always 1kHz according to USB descriptor, but actually about 4 ms.
|
||||
#define TRITON_SENSOR_UPDATE_INTERVAL_US 4032
|
||||
|
||||
enum
|
||||
{
|
||||
SDL_GAMEPAD_BUTTON_STEAM_DECK_QAM = 11,
|
||||
SDL_GAMEPAD_BUTTON_STEAM_DECK_RIGHT_PADDLE1,
|
||||
SDL_GAMEPAD_BUTTON_STEAM_DECK_LEFT_PADDLE1,
|
||||
SDL_GAMEPAD_BUTTON_STEAM_DECK_RIGHT_PADDLE2,
|
||||
SDL_GAMEPAD_BUTTON_STEAM_DECK_LEFT_PADDLE2,
|
||||
SDL_GAMEPAD_NUM_TRITON_BUTTONS,
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
TRITON_LBUTTON_A = 0x00000001,
|
||||
TRITON_LBUTTON_B = 0x00000002,
|
||||
TRITON_LBUTTON_X = 0x00000004,
|
||||
TRITON_LBUTTON_Y = 0x00000008,
|
||||
|
||||
TRITON_HBUTTON_QAM = 0x00000010,
|
||||
TRITON_LBUTTON_R3 = 0x00000020,
|
||||
TRITON_LBUTTON_VIEW = 0x00000040,
|
||||
TRITON_HBUTTON_R4 = 0x00000080,
|
||||
|
||||
TRITON_LBUTTON_R5 = 0x00000100,
|
||||
TRITON_LBUTTON_R = 0x00000200,
|
||||
TRITON_LBUTTON_DPAD_DOWN = 0x00000400,
|
||||
TRITON_LBUTTON_DPAD_RIGHT = 0x00000800,
|
||||
|
||||
TRITON_LBUTTON_DPAD_LEFT = 0x00001000,
|
||||
TRITON_LBUTTON_DPAD_UP = 0x00002000,
|
||||
TRITON_LBUTTON_MENU = 0x00004000,
|
||||
TRITON_LBUTTON_L3 = 0x00008000,
|
||||
|
||||
TRITON_LBUTTON_STEAM = 0x00010000,
|
||||
TRITON_HBUTTON_L4 = 0x00020000,
|
||||
TRITON_LBUTTON_L5 = 0x00040000,
|
||||
TRITON_LBUTTON_L = 0x00080000,
|
||||
|
||||
/*
|
||||
STEAM_RIGHTSTICK_FINGERDOWN_MASK, // Right Stick Touch 0x00100000
|
||||
STEAM_RIGHTPAD_FINGERDOWN_MASK, // Right Pad Touch 0x00200000
|
||||
STEAM_BUTTON_RIGHTPAD_CLICKED_MASK, // Right Pressure Click 0x00400000
|
||||
STEAM_RIGHT_TRIGGER_MASK, // Right Trigger Click 0x00800000
|
||||
|
||||
STEAM_LEFTSTICK_FINGERDOWN_MASK, // Left Stick Touch 0x01000000
|
||||
STEAM_LEFTPAD_FINGERDOWN_MASK, // Left Pad Touch 0x02000000
|
||||
STEAM_BUTTON_LEFTPAD_CLICKED_MASK, // Left Pressure Click 0x04000000
|
||||
STEAM_LEFT_TRIGGER_MASK, // Left Trigger Click 0x08000000
|
||||
STEAM_RIGHT_AUX_MASK, // Right Pinky Touch 0x10000000
|
||||
STEAM_LEFT_AUX_MASK, // Left Pinky Touch 0x20000000
|
||||
*/
|
||||
} TritonButtons;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool connected;
|
||||
bool report_sensors;
|
||||
Uint32 last_sensor_tick;
|
||||
Uint64 sensor_timestamp_ns;
|
||||
Uint64 last_button_state;
|
||||
Uint64 last_lizard_update;
|
||||
} SDL_DriverSteamTriton_Context;
|
||||
|
||||
static bool IsProteusDongle(Uint16 product_id)
|
||||
{
|
||||
return (product_id == USB_PRODUCT_VALVE_STEAM_PROTEUS_DONGLE ||
|
||||
product_id == USB_PRODUCT_VALVE_STEAM_NEREID_DONGLE);
|
||||
}
|
||||
|
||||
static bool DisableSteamTritonLizardMode(SDL_hid_device *dev)
|
||||
{
|
||||
int rc;
|
||||
Uint8 buffer[HID_FEATURE_REPORT_BYTES] = { 1 };
|
||||
FeatureReportMsg *msg = (FeatureReportMsg *)(buffer + 1);
|
||||
|
||||
msg->header.type = ID_SET_SETTINGS_VALUES;
|
||||
msg->header.length = 1 * sizeof(ControllerSetting);
|
||||
msg->payload.setSettingsValues.settings[0].settingNum = SETTING_LIZARD_MODE;
|
||||
msg->payload.setSettingsValues.settings[0].settingValue = LIZARD_MODE_OFF;
|
||||
|
||||
rc = SDL_hid_send_feature_report(dev, buffer, sizeof(buffer));
|
||||
if (rc != sizeof(buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_HandleState(SDL_HIDAPI_Device *device,
|
||||
SDL_Joystick *joystick,
|
||||
TritonMTUFull_t *pTritonReport)
|
||||
{
|
||||
float values[3];
|
||||
SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (pTritonReport->uButtons != ctx->last_button_state) {
|
||||
Uint8 hat = 0;
|
||||
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_A) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_B) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_X) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_Y) != 0));
|
||||
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_L) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_R) != 0));
|
||||
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_MENU) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_VIEW) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_STEAM) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_QAM,
|
||||
((pTritonReport->uButtons & TRITON_HBUTTON_QAM) != 0));
|
||||
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_L3) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_R3) != 0));
|
||||
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_RIGHT_PADDLE1,
|
||||
((pTritonReport->uButtons & TRITON_HBUTTON_R4) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_LEFT_PADDLE1,
|
||||
((pTritonReport->uButtons & TRITON_HBUTTON_L4) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_RIGHT_PADDLE2,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_R5) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_STEAM_DECK_LEFT_PADDLE2,
|
||||
((pTritonReport->uButtons & TRITON_LBUTTON_L5) != 0));
|
||||
|
||||
if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_UP) {
|
||||
hat |= SDL_HAT_UP;
|
||||
}
|
||||
if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_DOWN) {
|
||||
hat |= SDL_HAT_DOWN;
|
||||
}
|
||||
if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_LEFT) {
|
||||
hat |= SDL_HAT_LEFT;
|
||||
}
|
||||
if (pTritonReport->uButtons & TRITON_LBUTTON_DPAD_RIGHT) {
|
||||
hat |= SDL_HAT_RIGHT;
|
||||
}
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
|
||||
ctx->last_button_state = pTritonReport->uButtons;
|
||||
}
|
||||
|
||||
// RKRK There're button bits for this if you so choose.
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER,
|
||||
(int)pTritonReport->sTriggerLeft * 2 - 32768);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER,
|
||||
(int)pTritonReport->sTriggerRight * 2 - 32768);
|
||||
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX,
|
||||
pTritonReport->sLeftStickX);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY,
|
||||
-pTritonReport->sLeftStickY);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX,
|
||||
pTritonReport->sRightStickX);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY,
|
||||
-pTritonReport->sRightStickY);
|
||||
|
||||
if (ctx->report_sensors && pTritonReport->imu.uTimestamp != ctx->last_sensor_tick) {
|
||||
Uint32 delta_us = (pTritonReport->imu.uTimestamp - ctx->last_sensor_tick);
|
||||
|
||||
ctx->sensor_timestamp_ns += SDL_US_TO_NS(delta_us);
|
||||
|
||||
values[0] = (pTritonReport->imu.sGyroX / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
|
||||
values[1] = (pTritonReport->imu.sGyroZ / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
|
||||
values[2] = (-pTritonReport->imu.sGyroY / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, ctx->sensor_timestamp_ns, values, 3);
|
||||
|
||||
values[0] = (pTritonReport->imu.sAccelX / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
|
||||
values[1] = (pTritonReport->imu.sAccelZ / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
|
||||
values[2] = (-pTritonReport->imu.sAccelY / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, ctx->sensor_timestamp_ns, values, 3);
|
||||
|
||||
ctx->last_sensor_tick = pTritonReport->imu.uTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_HandleBatteryStatus(SDL_HIDAPI_Device *device,
|
||||
SDL_Joystick *joystick,
|
||||
TritonBatteryStatus_t *pTritonBatteryStatus)
|
||||
{
|
||||
SDL_PowerState state;
|
||||
|
||||
switch (pTritonBatteryStatus->ucChargeState) {
|
||||
case k_EChargeStateDischarging:
|
||||
state = SDL_POWERSTATE_ON_BATTERY;
|
||||
break;
|
||||
case k_EChargeStateCharging:
|
||||
state = SDL_POWERSTATE_CHARGING;
|
||||
break;
|
||||
case k_EChargeStateChargingDone:
|
||||
state = SDL_POWERSTATE_CHARGED;
|
||||
break;
|
||||
default:
|
||||
// Error state?
|
||||
state = SDL_POWERSTATE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickPowerInfo(joystick, state, pTritonBatteryStatus->ucBatteryLevel);
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_SetControllerConnected(SDL_HIDAPI_Device *device, bool connected)
|
||||
{
|
||||
SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context;
|
||||
|
||||
if (ctx->connected != connected) {
|
||||
ctx->connected = connected;
|
||||
|
||||
if (connected) {
|
||||
SDL_JoystickID joystickID;
|
||||
if (!HIDAPI_JoystickConnected(device, &joystickID)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (device->num_joysticks > 0) {
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_HandleWirelessStatus(SDL_HIDAPI_Device *device,
|
||||
TritonWirelessStatus_t *pTritonWirelessStatus)
|
||||
{
|
||||
switch (pTritonWirelessStatus->state) {
|
||||
case k_ETritonWirelessStateConnect:
|
||||
HIDAPI_DriverSteamTriton_SetControllerConnected(device, true);
|
||||
break;
|
||||
case k_ETritonWirelessStateDisconnect:
|
||||
HIDAPI_DriverSteamTriton_SetControllerConnected(device, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************************************/
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_RegisterHints(SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM, callback, userdata);
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_UnregisterHints(SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM, callback, userdata);
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_IsEnabled(void)
|
||||
{
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_STEAM,
|
||||
SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_IsSupportedDevice(
|
||||
SDL_HIDAPI_Device *device,
|
||||
const char *name,
|
||||
SDL_GamepadType type,
|
||||
Uint16 vendor_id,
|
||||
Uint16 product_id,
|
||||
Uint16 version,
|
||||
int interface_number,
|
||||
int interface_class,
|
||||
int interface_subclass,
|
||||
int interface_protocol)
|
||||
{
|
||||
|
||||
if (IsProteusDongle(product_id)) {
|
||||
if (interface_number >= 2 && interface_number <= 5) {
|
||||
// The set of controller interfaces for Proteus & Nereid...currently
|
||||
return true;
|
||||
}
|
||||
} else if (SDL_IsJoystickSteamTriton(vendor_id, product_id)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverSteamTriton_Context *ctx;
|
||||
|
||||
ctx = (SDL_DriverSteamTriton_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
device->context = ctx;
|
||||
|
||||
HIDAPI_SetDeviceName(device, "Steam Controller");
|
||||
|
||||
if (IsProteusDongle(device->product_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wired controller, connected!
|
||||
return HIDAPI_DriverSteamTriton_SetControllerConnected(device, true);
|
||||
}
|
||||
|
||||
static int HIDAPI_DriverSteamTriton_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context;
|
||||
SDL_Joystick *joystick = NULL;
|
||||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||
}
|
||||
|
||||
if (ctx->connected && joystick) {
|
||||
Uint64 now = SDL_GetTicks();
|
||||
if (!ctx->last_lizard_update || (now - ctx->last_lizard_update) >= 3000) {
|
||||
DisableSteamTritonLizardMode(device->dev);
|
||||
ctx->last_lizard_update = now;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
uint8_t data[64];
|
||||
int r = SDL_hid_read(device->dev, data, sizeof(data));
|
||||
|
||||
if (r == 0) {
|
||||
return true;
|
||||
}
|
||||
if (r < 0) {
|
||||
// Failed to read from controller
|
||||
HIDAPI_DriverSteamTriton_SetControllerConnected(device, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (data[0]) {
|
||||
case ID_TRITON_CONTROLLER_STATE:
|
||||
case ID_TRITON_CONTROLLER_STATE_BLE:
|
||||
if (!joystick) {
|
||||
HIDAPI_DriverSteamTriton_SetControllerConnected(device, true);
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||
}
|
||||
}
|
||||
if (joystick && r >= (1 + sizeof(TritonMTUFull_t))) {
|
||||
TritonMTUFull_t *pTritonReport = (TritonMTUFull_t *)&data[1];
|
||||
HIDAPI_DriverSteamTriton_HandleState(device, joystick, pTritonReport);
|
||||
}
|
||||
break;
|
||||
case ID_TRITON_BATTERY_STATUS:
|
||||
if (joystick && r >= (1 + sizeof(TritonBatteryStatus_t))) {
|
||||
TritonBatteryStatus_t *pTritonBatteryStatus = (TritonBatteryStatus_t *)&data[1];
|
||||
HIDAPI_DriverSteamTriton_HandleBatteryStatus(device, joystick, pTritonBatteryStatus);
|
||||
}
|
||||
break;
|
||||
case ID_TRITON_WIRELESS_STATUS_X:
|
||||
case ID_TRITON_WIRELESS_STATUS:
|
||||
if (r >= (1 + sizeof(TritonWirelessStatus_t))) {
|
||||
TritonWirelessStatus_t *pTritonWirelessStatus = (TritonWirelessStatus_t *)&data[1];
|
||||
HIDAPI_DriverSteamTriton_HandleWirelessStatus(device, pTritonWirelessStatus);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
float update_rate_in_hz = 1000000.0f / TRITON_SENSOR_UPDATE_INTERVAL_US;
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
// Initialize the joystick capabilities
|
||||
joystick->nbuttons = SDL_GAMEPAD_NUM_TRITON_BUTTONS;
|
||||
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
|
||||
joystick->nhats = 1;
|
||||
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, update_rate_in_hz);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
int rc;
|
||||
|
||||
//RKRK Not sure about size. Probably 64+1 is OK for ORs
|
||||
Uint8 buffer[HID_RUMBLE_OUTPUT_REPORT_BYTES];
|
||||
OutputReportMsg *msg = (OutputReportMsg *)(buffer);
|
||||
|
||||
msg->report_id = ID_OUT_REPORT_HAPTIC_RUMBLE;
|
||||
msg->payload.hapticRumble.type = 0;
|
||||
msg->payload.hapticRumble.intensity = 0;
|
||||
msg->payload.hapticRumble.left.speed = low_frequency_rumble;
|
||||
msg->payload.hapticRumble.left.gain = 0;
|
||||
msg->payload.hapticRumble.right.speed = high_frequency_rumble;
|
||||
msg->payload.hapticRumble.right.gain = 0;
|
||||
|
||||
|
||||
rc = SDL_hid_write(device->dev, buffer, sizeof(buffer));
|
||||
if (rc != sizeof(buffer)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static Uint32 HIDAPI_DriverSteamTriton_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
return SDL_JOYSTICK_CAP_RUMBLE;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSteamTriton_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
|
||||
{
|
||||
SDL_DriverSteamTriton_Context *ctx = (SDL_DriverSteamTriton_Context *)device->context;
|
||||
int rc;
|
||||
Uint8 buffer[HID_FEATURE_REPORT_BYTES] = { 1 };
|
||||
FeatureReportMsg *msg = (FeatureReportMsg *)(buffer + 1);
|
||||
|
||||
msg->header.type = ID_SET_SETTINGS_VALUES;
|
||||
msg->header.length = 1 * sizeof(ControllerSetting);
|
||||
msg->payload.setSettingsValues.settings[0].settingNum = SETTING_IMU_MODE;
|
||||
if (enabled) {
|
||||
msg->payload.setSettingsValues.settings[0].settingValue = (SETTING_GYRO_MODE_SEND_RAW_ACCEL | SETTING_GYRO_MODE_SEND_RAW_GYRO);
|
||||
} else {
|
||||
msg->payload.setSettingsValues.settings[0].settingValue = SETTING_GYRO_MODE_OFF;
|
||||
}
|
||||
|
||||
rc = SDL_hid_send_feature_report(device->dev, buffer, sizeof(buffer));
|
||||
if (rc != sizeof(buffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx->report_sensors = enabled;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
// Lizard mode id automatically re-enabled by watchdog. Nothing to do here.
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverSteamTriton_FreeDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamTriton = {
|
||||
SDL_HINT_JOYSTICK_HIDAPI_STEAM,
|
||||
true,
|
||||
HIDAPI_DriverSteamTriton_RegisterHints,
|
||||
HIDAPI_DriverSteamTriton_UnregisterHints,
|
||||
HIDAPI_DriverSteamTriton_IsEnabled,
|
||||
HIDAPI_DriverSteamTriton_IsSupportedDevice,
|
||||
HIDAPI_DriverSteamTriton_InitDevice,
|
||||
HIDAPI_DriverSteamTriton_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverSteamTriton_SetDevicePlayerIndex,
|
||||
HIDAPI_DriverSteamTriton_UpdateDevice,
|
||||
HIDAPI_DriverSteamTriton_OpenJoystick,
|
||||
HIDAPI_DriverSteamTriton_RumbleJoystick,
|
||||
HIDAPI_DriverSteamTriton_RumbleJoystickTriggers,
|
||||
HIDAPI_DriverSteamTriton_GetJoystickCapabilities,
|
||||
HIDAPI_DriverSteamTriton_SetJoystickLED,
|
||||
HIDAPI_DriverSteamTriton_SendJoystickEffect,
|
||||
HIDAPI_DriverSteamTriton_SetSensorsEnabled,
|
||||
HIDAPI_DriverSteamTriton_CloseJoystick,
|
||||
HIDAPI_DriverSteamTriton_FreeDevice,
|
||||
};
|
||||
|
||||
#endif // SDL_JOYSTICK_HIDAPI_STEAM_TRITON
|
||||
|
||||
#endif // SDL_JOYSTICK_HIDAPI
|
||||
@@ -74,7 +74,7 @@ typedef enum
|
||||
typedef struct
|
||||
{
|
||||
Uint32 update_rate_us;
|
||||
Uint32 sensor_timestamp_us;
|
||||
Uint64 sensor_timestamp_ns;
|
||||
Uint64 last_button_state;
|
||||
Uint8 watchdog_counter;
|
||||
} SDL_DriverSteamDeck_Context;
|
||||
@@ -222,17 +222,29 @@ static void HIDAPI_DriverSteamDeck_HandleState(SDL_HIDAPI_Device *device,
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY,
|
||||
-pInReport->payload.deckState.sRightStickY);
|
||||
|
||||
ctx->sensor_timestamp_us += ctx->update_rate_us;
|
||||
ctx->sensor_timestamp_ns += SDL_US_TO_NS(ctx->update_rate_us);
|
||||
|
||||
values[0] = (pInReport->payload.deckState.sGyroX / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
|
||||
values[1] = (pInReport->payload.deckState.sGyroZ / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
|
||||
values[2] = (-pInReport->payload.deckState.sGyroY / 32768.0f) * (2000.0f * (SDL_PI_F / 180.0f));
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, ctx->sensor_timestamp_us, values, 3);
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, ctx->sensor_timestamp_ns, values, 3);
|
||||
|
||||
values[0] = (pInReport->payload.deckState.sAccelX / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
|
||||
values[1] = (pInReport->payload.deckState.sAccelZ / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
|
||||
values[2] = (-pInReport->payload.deckState.sAccelY / 32768.0f) * 2.0f * SDL_STANDARD_GRAVITY;
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, ctx->sensor_timestamp_us, values, 3);
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, ctx->sensor_timestamp_ns, values, 3);
|
||||
|
||||
SDL_SendJoystickTouchpad(timestamp, joystick, 0, 0,
|
||||
pInReport->payload.deckState.sPressurePadLeft > 0,
|
||||
pInReport->payload.deckState.sLeftPadX / 65536.0f + 0.5f,
|
||||
pInReport->payload.deckState.sLeftPadY / 65536.0f + 0.5f,
|
||||
pInReport->payload.deckState.sPressurePadLeft / 32768.0f);
|
||||
|
||||
SDL_SendJoystickTouchpad(timestamp, joystick, 1, 0,
|
||||
pInReport->payload.deckState.sPressurePadRight > 0,
|
||||
pInReport->payload.deckState.sRightPadX / 65536.0f + 0.5f,
|
||||
pInReport->payload.deckState.sRightPadY / 65536.0f + 0.5f,
|
||||
pInReport->payload.deckState.sPressurePadRight / 32768.0f);
|
||||
}
|
||||
|
||||
/*****************************************************************************************************/
|
||||
@@ -331,7 +343,7 @@ static bool HIDAPI_DriverSteamDeck_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_memset(data, 0, sizeof(data));
|
||||
SDL_zeroa(data);
|
||||
|
||||
do {
|
||||
r = SDL_hid_read(device->dev, data, sizeof(data));
|
||||
@@ -366,6 +378,9 @@ static bool HIDAPI_DriverSteamDeck_OpenJoystick(SDL_HIDAPI_Device *device, SDL_J
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, update_rate_in_hz);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
|
||||
|
||||
SDL_PrivateJoystickAddTouchpad(joystick, 1);
|
||||
SDL_PrivateJoystickAddTouchpad(joystick, 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -34,7 +34,9 @@
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
// #define DEBUG_SWITCH_PROTOCOL
|
||||
#if 0
|
||||
#define DEBUG_SWITCH_PROTOCOL
|
||||
#endif
|
||||
|
||||
// Define this to get log output for rumble logic
|
||||
// #define DEBUG_RUMBLE
|
||||
@@ -159,20 +161,21 @@ typedef struct
|
||||
Uint8 ucVibrationCode;
|
||||
} SwitchControllerStatePacket_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Sint16 sAccelX;
|
||||
Sint16 sAccelY;
|
||||
Sint16 sAccelZ;
|
||||
|
||||
Sint16 sGyroX;
|
||||
Sint16 sGyroY;
|
||||
Sint16 sGyroZ;
|
||||
} SwitchControllerIMUState_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SwitchControllerStatePacket_t controllerState;
|
||||
|
||||
struct
|
||||
{
|
||||
Sint16 sAccelX;
|
||||
Sint16 sAccelY;
|
||||
Sint16 sAccelZ;
|
||||
|
||||
Sint16 sGyroX;
|
||||
Sint16 sGyroY;
|
||||
Sint16 sGyroZ;
|
||||
} imuState[3];
|
||||
SwitchControllerIMUState_t imuState[3];
|
||||
} SwitchStatePacket_t;
|
||||
|
||||
typedef struct
|
||||
@@ -313,6 +316,8 @@ typedef struct
|
||||
Uint64 m_ulIMUUpdateIntervalNS;
|
||||
Uint64 m_ulTimestampNS;
|
||||
bool m_bVerticalMode;
|
||||
SDL_PowerState m_ePowerState;
|
||||
int m_nPowerPercent;
|
||||
|
||||
SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
|
||||
SwitchSimpleStatePacket_t m_lastSimpleState;
|
||||
@@ -388,7 +393,7 @@ static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int siz
|
||||
#endif // SWITCH_SYNCHRONOUS_WRITES
|
||||
}
|
||||
|
||||
static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
|
||||
static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID, const Uint8 *pBuf, Uint8 ucLen)
|
||||
{
|
||||
// Average response time for messages is ~30ms
|
||||
Uint64 endTicks = SDL_GetTicks() + 100;
|
||||
@@ -398,9 +403,17 @@ static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Conte
|
||||
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;
|
||||
if (reply->ucSubcommandID != expectedID || !(reply->ucSubcommandAck & 0x80)) {
|
||||
continue;
|
||||
}
|
||||
if (reply->ucSubcommandID == k_eSwitchSubcommandIDs_SPIFlashRead) {
|
||||
SDL_assert(ucLen == sizeof(reply->spiReadData.opData));
|
||||
if (SDL_memcmp(&reply->spiReadData.opData, pBuf, ucLen) != 0) {
|
||||
// This was a reply for another SPI read command
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
} else {
|
||||
SDL_Delay(1);
|
||||
@@ -437,7 +450,7 @@ static bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprieta
|
||||
|
||||
static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, const Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
|
||||
{
|
||||
SDL_memset(outPacket, 0, sizeof(*outPacket));
|
||||
SDL_zerop(outPacket);
|
||||
|
||||
outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
|
||||
outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber;
|
||||
@@ -487,7 +500,7 @@ static bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs
|
||||
continue;
|
||||
}
|
||||
|
||||
reply = ReadSubcommandReply(ctx, ucCommandID);
|
||||
reply = ReadSubcommandReply(ctx, ucCommandID, pBuf, ucLen);
|
||||
}
|
||||
|
||||
if (ppReply) {
|
||||
@@ -557,15 +570,33 @@ static Uint16 EncodeRumbleLowAmplitude(Uint16 amplitude)
|
||||
return lfa[100][1];
|
||||
}
|
||||
|
||||
static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
|
||||
static void SetNeutralRumble(SDL_HIDAPI_Device *device, SwitchRumbleData_t *pRumble)
|
||||
{
|
||||
pRumble->rgucData[0] = 0x00;
|
||||
pRumble->rgucData[1] = 0x01;
|
||||
pRumble->rgucData[2] = 0x40;
|
||||
pRumble->rgucData[3] = 0x40;
|
||||
bool bStandardNeutralValue;
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO &&
|
||||
device->product_id == USB_PRODUCT_NINTENDO_N64_CONTROLLER) {
|
||||
// The 8BitDo 64 Bluetooth Controller rumbles at startup with the standard neutral value,
|
||||
// so we'll use a 0 amplitude value instead.
|
||||
bStandardNeutralValue = false;
|
||||
} else {
|
||||
// The KingKong2 PRO Controller doesn't initialize correctly with a 0 amplitude value
|
||||
// over Bluetooth, so we'll use the standard value in all other cases.
|
||||
bStandardNeutralValue = true;
|
||||
}
|
||||
if (bStandardNeutralValue) {
|
||||
pRumble->rgucData[0] = 0x00;
|
||||
pRumble->rgucData[1] = 0x01;
|
||||
pRumble->rgucData[2] = 0x40;
|
||||
pRumble->rgucData[3] = 0x40;
|
||||
} else {
|
||||
pRumble->rgucData[0] = 0x00;
|
||||
pRumble->rgucData[1] = 0x00;
|
||||
pRumble->rgucData[2] = 0x01;
|
||||
pRumble->rgucData[3] = 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 ucHighFreqAmp, Uint8 ucLowFreq, Uint16 usLowFreqAmp)
|
||||
static void EncodeRumble(SDL_HIDAPI_Device *device, 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
|
||||
@@ -582,7 +613,7 @@ static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 u
|
||||
ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
|
||||
#endif
|
||||
} else {
|
||||
SetNeutralRumble(pRumble);
|
||||
SetNeutralRumble(device, pRumble);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,9 +778,10 @@ static void UpdateSlotLED(SDL_DriverSwitch_Context *ctx)
|
||||
{
|
||||
if (!ctx->m_bInputOnly) {
|
||||
Uint8 led_data = 0;
|
||||
const Uint8 player_pattern[] = { 0x1, 0x3, 0x7, 0xf, 0x9, 0x5, 0xd, 0x6 };
|
||||
|
||||
if (ctx->m_bPlayerLights && ctx->m_nPlayerIndex >= 0) {
|
||||
led_data = (1 << (ctx->m_nPlayerIndex % 4));
|
||||
led_data = player_pattern[ctx->m_nPlayerIndex % 8];
|
||||
}
|
||||
WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
|
||||
}
|
||||
@@ -957,7 +989,7 @@ static bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
|
||||
if (user_reply && user_reply->stickUserCalibration.rgucRightMagic[0] == 0xB2 && user_reply->stickUserCalibration.rgucRightMagic[1] == 0xA1) {
|
||||
userParamsReadSuccessCount += 1;
|
||||
pRightStickCal = user_reply->stickUserCalibration.rgucRightCalibration;
|
||||
}
|
||||
}
|
||||
|
||||
// Only read the factory calibration info if we failed to receive the correct magic bytes
|
||||
if (userParamsReadSuccessCount < 2) {
|
||||
@@ -1386,7 +1418,15 @@ static bool HIDAPI_DriverSwitch_IsSupportedDevice(SDL_HIDAPI_Device *device, con
|
||||
return false;
|
||||
}
|
||||
|
||||
return (type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO);
|
||||
if (type != SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The Nintendo Switch 2 Pro uses another driver
|
||||
if (vendor_id == USB_VENDOR_NINTENDO && product_id == USB_PRODUCT_NINTENDO_SWITCH2_PRO) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
@@ -1395,7 +1435,7 @@ static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device)
|
||||
|
||||
if (ctx->m_bInputOnly) {
|
||||
if (SDL_IsJoystickGameCube(device->vendor_id, device->product_id)) {
|
||||
device->type = SDL_GAMEPAD_TYPE_STANDARD;
|
||||
device->type = SDL_GAMEPAD_TYPE_GAMECUBE;
|
||||
}
|
||||
} else {
|
||||
char serial[18];
|
||||
@@ -1507,8 +1547,8 @@ static bool HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
|
||||
ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
|
||||
if (!ctx->m_bInputOnly) {
|
||||
// Initialize rumble data, important for reading device info on the MOBAPAD M073
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
|
||||
SetNeutralRumble(device, &ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(device, &ctx->m_RumblePacket.rumbleData[1]);
|
||||
|
||||
BReadDeviceInfo(ctx);
|
||||
}
|
||||
@@ -1562,8 +1602,8 @@ static bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
|
||||
ctx->m_nCurrentInputMode = ctx->m_nInitialInputMode;
|
||||
|
||||
// Initialize rumble data
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
|
||||
SetNeutralRumble(device, &ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(device, &ctx->m_RumblePacket.rumbleData[1]);
|
||||
|
||||
if (!device->is_bluetooth) {
|
||||
if (!BTrySetupUSB(ctx)) {
|
||||
@@ -1583,7 +1623,8 @@ static bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
|
||||
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_NESRight &&
|
||||
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_SNES &&
|
||||
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_N64 &&
|
||||
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_SEGA_Genesis) {
|
||||
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_SEGA_Genesis &&
|
||||
!(device->vendor_id == USB_VENDOR_PDP && device->product_id == USB_PRODUCT_PDP_REALMZ_WIRELESS)) {
|
||||
if (LoadIMUCalibration(ctx)) {
|
||||
ctx->m_bSensorsSupported = true;
|
||||
}
|
||||
@@ -1660,11 +1701,11 @@ static bool HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context
|
||||
const Uint16 k_usLowFreqAmp = EncodeRumbleLowAmplitude(low_frequency_rumble);
|
||||
|
||||
if (low_frequency_rumble || high_frequency_rumble) {
|
||||
EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
|
||||
EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
|
||||
EncodeRumble(ctx->device, &ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
|
||||
EncodeRumble(ctx->device, &ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
|
||||
} else {
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
|
||||
SetNeutralRumble(ctx->device, &ctx->m_RumblePacket.rumbleData[0]);
|
||||
SetNeutralRumble(ctx->device, &ctx->m_RumblePacket.rumbleData[1]);
|
||||
}
|
||||
|
||||
ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble);
|
||||
@@ -1771,16 +1812,29 @@ static Uint32 HIDAPI_DriverSwitch_GetJoystickCapabilities(SDL_HIDAPI_Device *dev
|
||||
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_ProController && !ctx->m_bInputOnly) {
|
||||
// Doesn't have an RGB LED, so don't return SDL_JOYSTICK_CAP_RGB_LED here
|
||||
result |= SDL_JOYSTICK_CAP_RUMBLE;
|
||||
// But has the HOME LED, so treat it like a mono LED
|
||||
result |= SDL_JOYSTICK_CAP_MONO_LED;
|
||||
} else if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft ||
|
||||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||
result |= SDL_JOYSTICK_CAP_RUMBLE;
|
||||
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||
result |= SDL_JOYSTICK_CAP_MONO_LED; // Right JoyCon also have the HOME LED
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
|
||||
|
||||
if (!(ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_ProController && !ctx->m_bInputOnly) &&
|
||||
ctx->m_eControllerType != k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
int value = (int)((SDL_max(red, SDL_max(green, blue)) / 255.0f) * 100.0f); // The colors are received between 0-255 and we need them to be 0-100
|
||||
return SetHomeLED(ctx, (Uint8)value);
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverSwitch_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
|
||||
@@ -2572,26 +2626,39 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
|
||||
* LSB of the battery nibble is used to report charging.
|
||||
* The battery level is reported from 0(empty)-8(full)
|
||||
*/
|
||||
SDL_PowerState state;
|
||||
int charging = (packet->controllerState.ucBatteryAndConnection & 0x10);
|
||||
int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
|
||||
int percent = (int)SDL_roundf((level / 8.0f) * 100.0f);
|
||||
|
||||
if (charging) {
|
||||
if (level == 8) {
|
||||
state = SDL_POWERSTATE_CHARGED;
|
||||
ctx->m_ePowerState = SDL_POWERSTATE_CHARGED;
|
||||
} else {
|
||||
state = SDL_POWERSTATE_CHARGING;
|
||||
ctx->m_ePowerState = SDL_POWERSTATE_CHARGING;
|
||||
}
|
||||
} else {
|
||||
state = SDL_POWERSTATE_ON_BATTERY;
|
||||
ctx->m_ePowerState = SDL_POWERSTATE_ON_BATTERY;
|
||||
}
|
||||
ctx->m_nPowerPercent = (int)SDL_roundf((level / 8.0f) * 100.0f);
|
||||
|
||||
if (!ctx->device->parent) {
|
||||
SDL_PowerState state = ctx->m_ePowerState;
|
||||
int percent = ctx->m_nPowerPercent;
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
} else if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||
SDL_DriverSwitch_Context *other = (SDL_DriverSwitch_Context *)ctx->device->parent->children[0]->context;
|
||||
SDL_PowerState state = (SDL_PowerState)SDL_min(ctx->m_ePowerState, other->m_ePowerState);
|
||||
int percent = SDL_min(ctx->m_nPowerPercent, other->m_nPowerPercent);
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
}
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
|
||||
if (ctx->m_bReportSensors) {
|
||||
bool bHasSensorData = (packet->imuState[0].sAccelZ != 0 ||
|
||||
packet->imuState[0].sAccelY != 0 ||
|
||||
packet->imuState[0].sAccelX != 0);
|
||||
// Need to copy the imuState to an aligned variable
|
||||
SwitchControllerIMUState_t imuState[3];
|
||||
SDL_COMPILE_TIME_ASSERT(imuState_size, sizeof(imuState) == sizeof(packet->imuState));
|
||||
SDL_memcpy(imuState, packet->imuState, sizeof(packet->imuState));
|
||||
|
||||
bool bHasSensorData = (imuState[0].sAccelZ != 0 ||
|
||||
imuState[0].sAccelY != 0 ||
|
||||
imuState[0].sAccelX != 0);
|
||||
if (bHasSensorData) {
|
||||
const Uint32 IMU_UPDATE_RATE_SAMPLE_FREQUENCY = 1000;
|
||||
Uint64 sensor_timestamp[3];
|
||||
@@ -2620,37 +2687,37 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
|
||||
|
||||
if (!ctx->device->parent ||
|
||||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO, sensor_timestamp[0], &packet->imuState[2].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL, sensor_timestamp[0], &packet->imuState[2].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO, sensor_timestamp[0], &imuState[2].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL, sensor_timestamp[0], &imuState[2].sAccelX);
|
||||
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO, sensor_timestamp[1], &packet->imuState[1].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL, sensor_timestamp[1], &packet->imuState[1].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO, sensor_timestamp[1], &imuState[1].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL, sensor_timestamp[1], &imuState[1].sAccelX);
|
||||
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO, sensor_timestamp[2], &packet->imuState[0].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL, sensor_timestamp[2], &packet->imuState[0].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO, sensor_timestamp[2], &imuState[0].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL, sensor_timestamp[2], &imuState[0].sAccelX);
|
||||
}
|
||||
|
||||
if (ctx->device->parent &&
|
||||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft) {
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_L, sensor_timestamp[0], &packet->imuState[2].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_L, sensor_timestamp[0], &packet->imuState[2].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_L, sensor_timestamp[0], &imuState[2].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_L, sensor_timestamp[0], &imuState[2].sAccelX);
|
||||
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_L, sensor_timestamp[1], &packet->imuState[1].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_L, sensor_timestamp[1], &packet->imuState[1].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_L, sensor_timestamp[1], &imuState[1].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_L, sensor_timestamp[1], &imuState[1].sAccelX);
|
||||
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_L, sensor_timestamp[2], &packet->imuState[0].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_L, sensor_timestamp[2], &packet->imuState[0].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_L, sensor_timestamp[2], &imuState[0].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_L, sensor_timestamp[2], &imuState[0].sAccelX);
|
||||
}
|
||||
if (ctx->device->parent &&
|
||||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_R, sensor_timestamp[0], &packet->imuState[2].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_R, sensor_timestamp[0], &packet->imuState[2].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_R, sensor_timestamp[0], &imuState[2].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_R, sensor_timestamp[0], &imuState[2].sAccelX);
|
||||
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_R, sensor_timestamp[1], &packet->imuState[1].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_R, sensor_timestamp[1], &packet->imuState[1].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_R, sensor_timestamp[1], &imuState[1].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_R, sensor_timestamp[1], &imuState[1].sAccelX);
|
||||
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_R, sensor_timestamp[2], &packet->imuState[0].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_R, sensor_timestamp[2], &packet->imuState[0].sAccelX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_GYRO_R, sensor_timestamp[2], &imuState[0].sGyroX);
|
||||
SendSensorUpdate(timestamp, joystick, ctx, SDL_SENSOR_ACCEL_R, sensor_timestamp[2], &imuState[0].sAccelX);
|
||||
}
|
||||
|
||||
} else if (ctx->m_bHasSensorData) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -512,6 +512,8 @@ static void UpdatePowerLevelWiiU(SDL_Joystick *joystick, Uint8 extensionBatteryB
|
||||
bool pluggedIn = !(extensionBatteryByte & 0x04);
|
||||
Uint8 batteryLevel = extensionBatteryByte >> 4;
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
if (pluggedIn) {
|
||||
joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED;
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
#include "SDL_report_descriptor.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
|
||||
@@ -33,7 +34,9 @@
|
||||
// #define DEBUG_JOYSTICK
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
// #define DEBUG_XBOX_PROTOCOL
|
||||
#if 0
|
||||
#define DEBUG_XBOX_PROTOCOL
|
||||
#endif
|
||||
|
||||
#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK)
|
||||
#define XBOX_ONE_DRIVER_ACTIVE 1
|
||||
@@ -132,6 +135,8 @@ typedef struct
|
||||
bool has_unmapped_state;
|
||||
bool has_trigger_rumble;
|
||||
bool has_share_button;
|
||||
bool has_separate_back_button;
|
||||
bool has_separate_guide_button;
|
||||
Uint8 last_paddle_state;
|
||||
Uint8 low_frequency_rumble;
|
||||
Uint8 high_frequency_rumble;
|
||||
@@ -140,6 +145,8 @@ typedef struct
|
||||
SDL_XboxOneRumbleState rumble_state;
|
||||
Uint64 rumble_time;
|
||||
bool rumble_pending;
|
||||
SDL_ReportDescriptor *descriptor;
|
||||
Uint32 last_buttons;
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
Uint8 *chunk_buffer;
|
||||
Uint32 chunk_length;
|
||||
@@ -266,8 +273,14 @@ static bool SendSerialRequest(SDL_DriverXboxOne_Context *ctx)
|
||||
|
||||
static bool ControllerSendsAnnouncement(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_PDP && product_id == 0x0246) {
|
||||
// The PDP Rock Candy (PID 0x0246) doesn't send the announce packet on Linux for some reason
|
||||
// The PDP Rock Candy (PID 0x0246) and PowerA Fusion Pro 4 (PID 0x400b)
|
||||
// don't send the announce packet on Linux for some reason.
|
||||
//
|
||||
// Just to be safe and cover future products, we'll always send the startup
|
||||
// protocol sequence for PDP and PowerA controllers
|
||||
if (vendor_id == USB_VENDOR_PDP ||
|
||||
vendor_id == USB_VENDOR_POWERA ||
|
||||
vendor_id == USB_VENDOR_POWERA_ALT) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -350,6 +363,10 @@ static bool HIDAPI_DriverXboxOne_IsEnabled(void)
|
||||
|
||||
static bool HIDAPI_DriverXboxOne_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
|
||||
{
|
||||
static const int LIBUSB_CLASS_VENDOR_SPEC = 0xFF;
|
||||
static const int XBONE_IFACE_SUBCLASS = 71;
|
||||
static const int XBONE_IFACE_PROTOCOL = 208;
|
||||
|
||||
#if defined(SDL_PLATFORM_MACOS) && defined(SDL_JOYSTICK_MFI)
|
||||
if (!SDL_IsJoystickBluetoothXboxOne(vendor_id, product_id)) {
|
||||
// On macOS we get a shortened version of the real report and
|
||||
@@ -358,6 +375,13 @@ static bool HIDAPI_DriverXboxOne_IsSupportedDevice(SDL_HIDAPI_Device *device, co
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (interface_class &&
|
||||
(interface_class != LIBUSB_CLASS_VENDOR_SPEC ||
|
||||
interface_subclass != XBONE_IFACE_SUBCLASS ||
|
||||
interface_protocol != XBONE_IFACE_PROTOCOL)) {
|
||||
// This isn't the Xbox gamepad interface
|
||||
return false;
|
||||
}
|
||||
return (type == SDL_GAMEPAD_TYPE_XBOXONE);
|
||||
}
|
||||
|
||||
@@ -373,6 +397,56 @@ static bool HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device)
|
||||
|
||||
device->context = ctx;
|
||||
|
||||
Uint8 descriptor[1024];
|
||||
int descriptor_len = SDL_hid_get_report_descriptor(device->dev, descriptor, sizeof(descriptor));
|
||||
if (descriptor_len > 0) {
|
||||
HIDAPI_DumpPacket("Xbox One report descriptor: size = %d", descriptor, descriptor_len);
|
||||
|
||||
ctx->descriptor = SDL_ParseReportDescriptor(descriptor, descriptor_len);
|
||||
if (ctx->descriptor) {
|
||||
// Collapse the buttons into a single field read
|
||||
int field_count = ctx->descriptor->field_count;
|
||||
DescriptorInputField *fields = ctx->descriptor->fields;
|
||||
int button_count = 0;
|
||||
for (int i = 0; i < field_count; ++i) {
|
||||
DescriptorInputField *field = &fields[i];
|
||||
if (field->usage == MAKE_USAGE(USB_USAGEPAGE_BUTTON, 1)) {
|
||||
Uint32 expected_usage = field->usage;
|
||||
int expected_offset = field->bit_offset;
|
||||
for (int j = i; j < field_count; ++j) {
|
||||
DescriptorInputField *other = &fields[j];
|
||||
if (other->usage != expected_usage ||
|
||||
other->bit_offset != expected_offset) {
|
||||
break;
|
||||
}
|
||||
|
||||
++button_count;
|
||||
++expected_usage;
|
||||
++expected_offset;
|
||||
}
|
||||
field->bit_size = button_count;
|
||||
|
||||
int next_field = i + button_count;
|
||||
int fields_left = (field_count - next_field);
|
||||
SDL_memmove(&fields[i+1], &fields[next_field], (fields_left * sizeof(fields[0])));
|
||||
ctx->descriptor->field_count -= (button_count - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!SDL_DescriptorHasUsage(ctx->descriptor, USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_X) ||
|
||||
!SDL_DescriptorHasUsage(ctx->descriptor, USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_Y) ||
|
||||
(button_count != 12 && button_count != 15)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Xbox report descriptor missing expected usages, ignoring");
|
||||
SDL_DestroyDescriptor(ctx->descriptor);
|
||||
ctx->descriptor = NULL;
|
||||
}
|
||||
} else {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Couldn't parse Xbox report descriptor: %s", SDL_GetError());
|
||||
}
|
||||
} else {
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "Xbox report descriptor not available");
|
||||
}
|
||||
|
||||
ctx->vendor_id = device->vendor_id;
|
||||
ctx->product_id = device->product_id;
|
||||
ctx->start_time = SDL_GetTicks();
|
||||
@@ -581,6 +655,310 @@ static bool HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *de
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverXboxOne_HandleBatteryState(SDL_Joystick *joystick, Uint32 flags)
|
||||
{
|
||||
bool on_usb = (((flags & 0x0C) >> 2) == 0);
|
||||
SDL_PowerState state;
|
||||
int percent = 0;
|
||||
|
||||
// Mapped percentage value from:
|
||||
// https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_getbatterystate
|
||||
switch (flags & 0x03) {
|
||||
case 0:
|
||||
percent = 10;
|
||||
break;
|
||||
case 1:
|
||||
percent = 40;
|
||||
break;
|
||||
case 2:
|
||||
percent = 70;
|
||||
break;
|
||||
case 3:
|
||||
percent = 100;
|
||||
break;
|
||||
}
|
||||
if (on_usb) {
|
||||
state = SDL_POWERSTATE_CHARGING;
|
||||
} else {
|
||||
state = SDL_POWERSTATE_ON_BATTERY;
|
||||
}
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
}
|
||||
|
||||
static void HandleDescriptorAxis(Uint64 timestamp, SDL_Joystick *joystick, SDL_GamepadAxis axis, Uint32 value)
|
||||
{
|
||||
Sint16 axis_value = (Sint16)((int)value - 0x8000);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, axis, axis_value);
|
||||
}
|
||||
|
||||
static void HandleDescriptorTrigger(Uint64 timestamp, SDL_Joystick *joystick, SDL_GamepadAxis axis, Uint32 value)
|
||||
{
|
||||
Sint16 axis_value = (Sint16)(((int)value * 64) - 32768);
|
||||
if (axis_value == 32704) {
|
||||
axis_value = 32767;
|
||||
}
|
||||
SDL_SendJoystickAxis(timestamp, joystick, axis, axis_value);
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverXboxOne_HandleDescriptorReport(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
const SDL_ReportDescriptor *descriptor = ctx->descriptor;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
// Skip the report ID
|
||||
const Uint8 report_id = *data;
|
||||
++data;
|
||||
--size;
|
||||
|
||||
for (int i = 0; i < descriptor->field_count; ++i) {
|
||||
DescriptorInputField *field = &descriptor->fields[i];
|
||||
if (field->report_id != report_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Uint32 value;
|
||||
if (!SDL_ReadReportData(data, size, field->bit_offset, field->bit_size, &value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (field->usage) {
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_X):
|
||||
{
|
||||
HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, value);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_Y):
|
||||
{
|
||||
HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, value);
|
||||
break;
|
||||
}
|
||||
// Some controllers use Z+RZ for the right thumbstick and BRAKE and ACCEL for the left and right triggers
|
||||
// and others use RX+RY for the right thumbstick and Z and RZ for the left and right triggers
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_Z):
|
||||
{
|
||||
if (field->bit_size == 16) {
|
||||
HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, value);
|
||||
} else if (field->bit_size == 10) {
|
||||
HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_RX):
|
||||
{
|
||||
HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, value);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_RY):
|
||||
{
|
||||
HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, value);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_RZ):
|
||||
{
|
||||
if (field->bit_size == 16) {
|
||||
HandleDescriptorAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, value);
|
||||
} else if (field->bit_size == 10) {
|
||||
HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_SIMULATION, USB_USAGE_SIMULATION_BRAKE):
|
||||
{
|
||||
HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, value);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_SIMULATION, USB_USAGE_SIMULATION_ACCELERATOR):
|
||||
{
|
||||
HandleDescriptorTrigger(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, value);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_GENERIC_DESKTOP, USB_USAGE_GENERIC_HAT):
|
||||
{
|
||||
Uint8 hat;
|
||||
|
||||
switch (value) {
|
||||
case 1:
|
||||
hat = SDL_HAT_UP;
|
||||
break;
|
||||
case 2:
|
||||
hat = SDL_HAT_RIGHTUP;
|
||||
break;
|
||||
case 3:
|
||||
hat = SDL_HAT_RIGHT;
|
||||
break;
|
||||
case 4:
|
||||
hat = SDL_HAT_RIGHTDOWN;
|
||||
break;
|
||||
case 5:
|
||||
hat = SDL_HAT_DOWN;
|
||||
break;
|
||||
case 6:
|
||||
hat = SDL_HAT_LEFTDOWN;
|
||||
break;
|
||||
case 7:
|
||||
hat = SDL_HAT_LEFT;
|
||||
break;
|
||||
case 8:
|
||||
hat = SDL_HAT_LEFTUP;
|
||||
break;
|
||||
default:
|
||||
hat = SDL_HAT_CENTERED;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_BUTTON, 1):
|
||||
{
|
||||
static const SDL_GamepadButton button_map_12[] = {
|
||||
// 0x0001
|
||||
SDL_GAMEPAD_BUTTON_SOUTH,
|
||||
// 0x0002
|
||||
SDL_GAMEPAD_BUTTON_EAST,
|
||||
// 0x0004
|
||||
SDL_GAMEPAD_BUTTON_WEST,
|
||||
// 0x0008
|
||||
SDL_GAMEPAD_BUTTON_NORTH,
|
||||
// 0x0010
|
||||
SDL_GAMEPAD_BUTTON_LEFT_SHOULDER,
|
||||
// 0x0020
|
||||
SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER,
|
||||
// 0x0040
|
||||
SDL_GAMEPAD_BUTTON_BACK,
|
||||
// 0x0080
|
||||
SDL_GAMEPAD_BUTTON_START,
|
||||
// 0x0100
|
||||
SDL_GAMEPAD_BUTTON_LEFT_STICK,
|
||||
// 0x0200
|
||||
SDL_GAMEPAD_BUTTON_RIGHT_STICK,
|
||||
// 0x0400
|
||||
SDL_GAMEPAD_BUTTON_GUIDE,
|
||||
// 0x0800
|
||||
SDL_GAMEPAD_BUTTON_INVALID,
|
||||
};
|
||||
static const SDL_GamepadButton button_map_15[] = {
|
||||
// 0x0001
|
||||
SDL_GAMEPAD_BUTTON_SOUTH,
|
||||
// 0x0002
|
||||
SDL_GAMEPAD_BUTTON_EAST,
|
||||
// 0x0004
|
||||
SDL_GAMEPAD_BUTTON_INVALID,
|
||||
// 0x0008
|
||||
SDL_GAMEPAD_BUTTON_WEST,
|
||||
// 0x0010
|
||||
SDL_GAMEPAD_BUTTON_NORTH,
|
||||
// 0x0020
|
||||
SDL_GAMEPAD_BUTTON_INVALID,
|
||||
// 0x0040
|
||||
SDL_GAMEPAD_BUTTON_LEFT_SHOULDER,
|
||||
// 0x0080
|
||||
SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER,
|
||||
// 0x0100
|
||||
SDL_GAMEPAD_BUTTON_INVALID,
|
||||
// 0x0200
|
||||
SDL_GAMEPAD_BUTTON_INVALID,
|
||||
// 0x0400
|
||||
SDL_GAMEPAD_BUTTON_BACK,
|
||||
// 0x0800
|
||||
SDL_GAMEPAD_BUTTON_START,
|
||||
// 0x1000
|
||||
SDL_GAMEPAD_BUTTON_GUIDE,
|
||||
// 0x2000
|
||||
SDL_GAMEPAD_BUTTON_LEFT_STICK,
|
||||
// 0x4000
|
||||
SDL_GAMEPAD_BUTTON_RIGHT_STICK,
|
||||
};
|
||||
|
||||
if (value == ctx->last_buttons) {
|
||||
break;
|
||||
}
|
||||
ctx->last_buttons = value;
|
||||
|
||||
const SDL_GamepadButton *button_map;
|
||||
if (field->bit_size == 12) {
|
||||
button_map = button_map_12;
|
||||
} else if (field->bit_size == 15) {
|
||||
button_map = button_map_15;
|
||||
} else {
|
||||
// Should never happen
|
||||
break;
|
||||
}
|
||||
for (int button_index = 0; button_index < field->bit_size; ++button_index, value >>= 1) {
|
||||
SDL_GamepadButton button = button_map[button_index];
|
||||
if (button == SDL_GAMEPAD_BUTTON_INVALID) {
|
||||
continue;
|
||||
}
|
||||
if (button == SDL_GAMEPAD_BUTTON_BACK && ctx->has_separate_back_button) {
|
||||
continue;
|
||||
}
|
||||
if (button == SDL_GAMEPAD_BUTTON_GUIDE && ctx->has_separate_guide_button) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool pressed = ((value & 1) != 0);
|
||||
SDL_SendJoystickButton(timestamp, joystick, button, pressed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_AC_BACK):
|
||||
{
|
||||
bool pressed = (value != 0);
|
||||
if (pressed) {
|
||||
ctx->has_separate_back_button = true;
|
||||
}
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, pressed);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_AC_HOME):
|
||||
{
|
||||
bool pressed = (value != 0);
|
||||
if (pressed) {
|
||||
ctx->has_separate_guide_button = true;
|
||||
}
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, pressed);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_RECORD):
|
||||
{
|
||||
if (ctx->has_share_button) {
|
||||
bool pressed = (value != 0);
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON, pressed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_ORDER_MOVIE):
|
||||
{
|
||||
// This value is the currently selected profile
|
||||
ctx->has_unmapped_state = (value == 0);
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_CONSUMER, USB_USAGE_CONSUMER_ASSIGN_SELECTION):
|
||||
{
|
||||
if (ctx->has_paddles) {
|
||||
if (!ctx->has_unmapped_state) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
Uint8 button = (Uint8)(SDL_GAMEPAD_BUTTON_XBOX_SHARE_BUTTON + ctx->has_share_button); // Next available button
|
||||
SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x1) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x2) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x4) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, button++, ((value & 0x8) != 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MAKE_USAGE(USB_USAGEPAGE_DEVICE_CONTROLS, USB_USAGE_DEVICE_CONTROLS_BATTERY_STRENGTH):
|
||||
{
|
||||
HIDAPI_DriverXboxOne_HandleBatteryState(joystick, value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Xbox One Elite controller with 5.13+ firmware sends the unmapped state in a separate packet.
|
||||
* We can use this to send the paddle state when they aren't mapped
|
||||
@@ -810,7 +1188,7 @@ static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_D
|
||||
}
|
||||
}
|
||||
|
||||
axis = ((int)SDL_Swap16LE(*(Sint16 *)(&data[2])) * 64) - 32768;
|
||||
axis = ((int)LOAD16(data[2], data[3]) * 64) - 32768;
|
||||
if (axis == 32704) {
|
||||
axis = 32767;
|
||||
}
|
||||
@@ -819,7 +1197,7 @@ static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_D
|
||||
}
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||
|
||||
axis = ((int)SDL_Swap16LE(*(Sint16 *)(&data[4])) * 64) - 32768;
|
||||
axis = ((int)LOAD16(data[4], data[5]) * 64) - 32768;
|
||||
if (axis == -32768 && size == 26 && (data[18] & 0x40)) {
|
||||
axis = 32767;
|
||||
}
|
||||
@@ -828,13 +1206,13 @@ static void HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, SDL_D
|
||||
}
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||
|
||||
axis = SDL_Swap16LE(*(Sint16 *)(&data[6]));
|
||||
axis = LOAD16(data[6], data[7]);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = SDL_Swap16LE(*(Sint16 *)(&data[8]));
|
||||
axis = LOAD16(data[8], data[9]);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, ~axis);
|
||||
axis = SDL_Swap16LE(*(Sint16 *)(&data[10]));
|
||||
axis = LOAD16(data[10], data[11]);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = SDL_Swap16LE(*(Sint16 *)(&data[12]));
|
||||
axis = LOAD16(data[12], data[13]);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, ~axis);
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
@@ -1030,25 +1408,25 @@ static void HIDAPI_DriverXboxOneBluetooth_HandleStatePacket(SDL_Joystick *joysti
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
}
|
||||
|
||||
axis = ((int)SDL_Swap16LE(*(Sint16 *)(&data[9])) * 64) - 32768;
|
||||
axis = ((int)LOAD16(data[9], data[10]) * 64) - 32768;
|
||||
if (axis == 32704) {
|
||||
axis = 32767;
|
||||
}
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, axis);
|
||||
|
||||
axis = ((int)SDL_Swap16LE(*(Sint16 *)(&data[11])) * 64) - 32768;
|
||||
axis = ((int)LOAD16(data[11], data[12]) * 64) - 32768;
|
||||
if (axis == 32704) {
|
||||
axis = 32767;
|
||||
}
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, axis);
|
||||
|
||||
axis = (int)SDL_Swap16LE(*(Uint16 *)(&data[1])) - 0x8000;
|
||||
axis = (int)(Uint16)LOAD16(data[1], data[2]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = (int)SDL_Swap16LE(*(Uint16 *)(&data[3])) - 0x8000;
|
||||
axis = (int)(Uint16)LOAD16(data[3], data[4]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
axis = (int)SDL_Swap16LE(*(Uint16 *)(&data[5])) - 0x8000;
|
||||
axis = (int)(Uint16)LOAD16(data[5], data[6]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = (int)SDL_Swap16LE(*(Uint16 *)(&data[7])) - 0x8000;
|
||||
axis = (int)(Uint16)LOAD16(data[7], data[8]) - 0x8000;
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
@@ -1064,33 +1442,7 @@ static void HIDAPI_DriverXboxOneBluetooth_HandleGuidePacket(SDL_Joystick *joysti
|
||||
|
||||
static void HIDAPI_DriverXboxOneBluetooth_HandleBatteryPacket(SDL_Joystick *joystick, SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size)
|
||||
{
|
||||
Uint8 flags = data[1];
|
||||
bool on_usb = (((flags & 0x0C) >> 2) == 0);
|
||||
SDL_PowerState state;
|
||||
int percent = 0;
|
||||
|
||||
// Mapped percentage value from:
|
||||
// https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/input/gameinput/interfaces/igameinputdevice/methods/igameinputdevice_getbatterystate
|
||||
switch (flags & 0x03) {
|
||||
case 0:
|
||||
percent = 10;
|
||||
break;
|
||||
case 1:
|
||||
percent = 40;
|
||||
break;
|
||||
case 2:
|
||||
percent = 70;
|
||||
break;
|
||||
case 3:
|
||||
percent = 100;
|
||||
break;
|
||||
}
|
||||
if (on_usb) {
|
||||
state = SDL_POWERSTATE_CHARGING;
|
||||
} else {
|
||||
state = SDL_POWERSTATE_ON_BATTERY;
|
||||
}
|
||||
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
||||
HIDAPI_DriverXboxOne_HandleBatteryState(joystick, data[1]);
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverXboxOne_HandleSerialIDPacket(SDL_DriverXboxOne_Context *ctx, const Uint8 *data, int size)
|
||||
@@ -1586,7 +1938,12 @@ static bool HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
#ifdef DEBUG_XBOX_PROTOCOL
|
||||
HIDAPI_DumpPacket("Xbox One packet: size = %d", data, size);
|
||||
#endif
|
||||
if (device->is_bluetooth) {
|
||||
if (ctx->descriptor) {
|
||||
if (!joystick) {
|
||||
break;
|
||||
}
|
||||
HIDAPI_DriverXboxOne_HandleDescriptorReport(joystick, ctx, data, size);
|
||||
} else if (device->is_bluetooth) {
|
||||
switch (data[0]) {
|
||||
case 0x01:
|
||||
if (!joystick) {
|
||||
@@ -1645,6 +2002,8 @@ static void HIDAPI_DriverXboxOne_FreeDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
|
||||
|
||||
SDL_DestroyDescriptor(ctx->descriptor);
|
||||
|
||||
HIDAPI_GIP_DestroyChunkBuffer(ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 2025 Zuiki Inc.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
|
||||
#include "../SDL_sysjoystick.h"
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_ZUIKI
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
#if 0
|
||||
#define DEBUG_ZUIKI_PROTOCOL
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
} SDL_DriverZUIKI_Context;
|
||||
|
||||
static void HIDAPI_DriverZUIKI_RegisterHints(SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, callback, userdata);
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverZUIKI_UnregisterHints(SDL_HintCallback callback, void *userdata)
|
||||
{
|
||||
SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, callback, userdata);
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_IsEnabled(void)
|
||||
{
|
||||
return SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_ZUIKI, SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI, SDL_HIDAPI_DEFAULT));
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_IsSupportedDevice(SDL_HIDAPI_Device *device, const char *name, SDL_GamepadType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
|
||||
{
|
||||
if (vendor_id == USB_VENDOR_ZUIKI) {
|
||||
switch (product_id) {
|
||||
case USB_PRODUCT_ZUIKI_MASCON_PRO:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_InitDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverZUIKI_Context *ctx = (SDL_DriverZUIKI_Context *)SDL_calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
return false;
|
||||
}
|
||||
device->context = ctx;
|
||||
|
||||
if (device->product_id == USB_PRODUCT_ZUIKI_MASCON_PRO) {
|
||||
HIDAPI_SetDeviceName(device, "ZUIKI MASCON PRO");
|
||||
}
|
||||
|
||||
return HIDAPI_JoystickConnected(device, NULL);
|
||||
}
|
||||
|
||||
static int HIDAPI_DriverZUIKI_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverZUIKI_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef DEG2RAD
|
||||
#define DEG2RAD(x) ((float)(x) * (float)(SDL_PI_F / 180.f))
|
||||
#endif
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_DriverZUIKI_Context *ctx = (SDL_DriverZUIKI_Context *)device->context;
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
joystick->nbuttons = 11;
|
||||
joystick->naxes = SDL_GAMEPAD_AXIS_COUNT;
|
||||
joystick->nhats = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
Uint8 rumble_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
rumble_packet[4] = low_frequency_rumble >> 8;
|
||||
rumble_packet[5] = high_frequency_rumble >> 8;
|
||||
if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
|
||||
return SDL_SetError("Couldn't send rumble packet");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static Uint32 HIDAPI_DriverZUIKI_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
Uint32 caps = 0;
|
||||
caps |= SDL_JOYSTICK_CAP_RUMBLE;
|
||||
return caps;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
|
||||
{
|
||||
if (SDL_HIDAPI_SendRumble(device, data, size) != size) {
|
||||
return SDL_SetError("Couldn't send rumble packet");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, bool enabled)
|
||||
{
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverZUIKI_HandleOldStatePacket(SDL_Joystick *joystick, SDL_DriverZUIKI_Context *ctx, Uint8 *data, int size)
|
||||
{
|
||||
Sint16 axis;
|
||||
Uint64 timestamp = SDL_GetTicksNS();
|
||||
|
||||
if (ctx->last_state[2] != data[2]) {
|
||||
Uint8 hat;
|
||||
|
||||
switch (data[2]) {
|
||||
case 0:
|
||||
hat = SDL_HAT_UP;
|
||||
break;
|
||||
case 1:
|
||||
hat = SDL_HAT_RIGHTUP;
|
||||
break;
|
||||
case 2:
|
||||
hat = SDL_HAT_RIGHT;
|
||||
break;
|
||||
case 3:
|
||||
hat = SDL_HAT_RIGHTDOWN;
|
||||
break;
|
||||
case 4:
|
||||
hat = SDL_HAT_DOWN;
|
||||
break;
|
||||
case 5:
|
||||
hat = SDL_HAT_LEFTDOWN;
|
||||
break;
|
||||
case 6:
|
||||
hat = SDL_HAT_LEFT;
|
||||
break;
|
||||
case 7:
|
||||
hat = SDL_HAT_LEFTUP;
|
||||
break;
|
||||
default:
|
||||
hat = SDL_HAT_CENTERED;
|
||||
break;
|
||||
}
|
||||
SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
||||
}
|
||||
|
||||
if (ctx->last_state[0] != data[0]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_NORTH, ((data[0] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_EAST, ((data[0] & 0x02) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SOUTH, ((data[0] & 0x04) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_WEST, ((data[0] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, ((data[0] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, ((data[0] & 0x20) != 0));
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, (data[0] & 0x40) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, (data[0] & 0x80) ? SDL_MAX_SINT16 : SDL_MIN_SINT16);
|
||||
}
|
||||
|
||||
if (ctx->last_state[1] != data[1]) {
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_BACK, ((data[1] & 0x01) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_START, ((data[1] & 0x02) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_LEFT_STICK, ((data[1] & 0x04) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_STICK, ((data[1] & 0x08) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data[1] & 0x10) != 0));
|
||||
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_MISC1, ((data[1] & 0x20) != 0));
|
||||
/* todo for switch C key */
|
||||
}
|
||||
|
||||
#define READ_STICK_AXIS(offset) \
|
||||
(data[offset] == 0x7f ? 0 : (Sint16)HIDAPI_RemapVal((float)((int)data[offset] - 0x7f), -0x7f, 0xff - 0x7f, SDL_MIN_SINT16, SDL_MAX_SINT16))
|
||||
{
|
||||
axis = READ_STICK_AXIS(3);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTX, axis);
|
||||
axis = READ_STICK_AXIS(4);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_LEFTY, axis);
|
||||
axis = READ_STICK_AXIS(5);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
|
||||
axis = READ_STICK_AXIS(6);
|
||||
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, axis);
|
||||
}
|
||||
#undef READ_STICK_AXIS
|
||||
|
||||
SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
|
||||
}
|
||||
|
||||
static bool HIDAPI_DriverZUIKI_UpdateDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverZUIKI_Context *ctx = (SDL_DriverZUIKI_Context *)device->context;
|
||||
SDL_Joystick *joystick = NULL;
|
||||
Uint8 data[USB_PACKET_LENGTH];
|
||||
int size = 0;
|
||||
|
||||
if (device->num_joysticks > 0) {
|
||||
joystick = SDL_GetJoystickFromID(device->joysticks[0]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
|
||||
#ifdef DEBUG_ZUIKI_PROTOCOL
|
||||
HIDAPI_DumpPacket("ZUIKI packet: size = %d", data, size);
|
||||
#endif
|
||||
if (!joystick) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size == 8) {
|
||||
HIDAPI_DriverZUIKI_HandleOldStatePacket(joystick, ctx, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
// Read error, device is disconnected
|
||||
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
|
||||
}
|
||||
return (size >= 0);
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverZUIKI_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
|
||||
{
|
||||
}
|
||||
|
||||
static void HIDAPI_DriverZUIKI_FreeDevice(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
}
|
||||
|
||||
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverZUIKI = {
|
||||
SDL_HINT_JOYSTICK_HIDAPI_ZUIKI,
|
||||
true,
|
||||
HIDAPI_DriverZUIKI_RegisterHints,
|
||||
HIDAPI_DriverZUIKI_UnregisterHints,
|
||||
HIDAPI_DriverZUIKI_IsEnabled,
|
||||
HIDAPI_DriverZUIKI_IsSupportedDevice,
|
||||
HIDAPI_DriverZUIKI_InitDevice,
|
||||
HIDAPI_DriverZUIKI_GetDevicePlayerIndex,
|
||||
HIDAPI_DriverZUIKI_SetDevicePlayerIndex,
|
||||
HIDAPI_DriverZUIKI_UpdateDevice,
|
||||
HIDAPI_DriverZUIKI_OpenJoystick,
|
||||
HIDAPI_DriverZUIKI_RumbleJoystick,
|
||||
HIDAPI_DriverZUIKI_RumbleJoystickTriggers,
|
||||
HIDAPI_DriverZUIKI_GetJoystickCapabilities,
|
||||
HIDAPI_DriverZUIKI_SetJoystickLED,
|
||||
HIDAPI_DriverZUIKI_SendJoystickEffect,
|
||||
HIDAPI_DriverZUIKI_SetJoystickSensorsEnabled,
|
||||
HIDAPI_DriverZUIKI_CloseJoystick,
|
||||
HIDAPI_DriverZUIKI_FreeDevice,
|
||||
};
|
||||
|
||||
#endif // SDL_JOYSTICK_HIDAPI_ZUIKI
|
||||
|
||||
#endif // SDL_JOYSTICK_HIDAPI
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -70,11 +70,17 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK
|
||||
&SDL_HIDAPI_DriverSteamDeck,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_STEAMDECK
|
||||
&SDL_HIDAPI_DriverSteamTriton,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
&SDL_HIDAPI_DriverNintendoClassic,
|
||||
&SDL_HIDAPI_DriverJoyCons,
|
||||
&SDL_HIDAPI_DriverSwitch,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SWITCH2
|
||||
&SDL_HIDAPI_DriverSwitch2,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_WII
|
||||
&SDL_HIDAPI_DriverWii,
|
||||
#endif
|
||||
@@ -82,9 +88,27 @@ static SDL_HIDAPI_DeviceDriver *SDL_HIDAPI_drivers[] = {
|
||||
&SDL_HIDAPI_DriverXbox360,
|
||||
&SDL_HIDAPI_DriverXbox360W,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_GIP
|
||||
&SDL_HIDAPI_DriverGIP,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
&SDL_HIDAPI_DriverXboxOne,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_LG4FF
|
||||
&SDL_HIDAPI_DriverLg4ff,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_8BITDO
|
||||
&SDL_HIDAPI_Driver8BitDo,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_FLYDIGI
|
||||
&SDL_HIDAPI_DriverFlydigi,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SINPUT
|
||||
&SDL_HIDAPI_DriverSInput,
|
||||
#endif
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_ZUIKI
|
||||
&SDL_HIDAPI_DriverZUIKI,
|
||||
#endif
|
||||
};
|
||||
static int SDL_HIDAPI_numdrivers = 0;
|
||||
static SDL_AtomicInt SDL_HIDAPI_updating_devices;
|
||||
@@ -133,7 +157,7 @@ void HIDAPI_DumpPacket(const char *prefix, const Uint8 *data, int size)
|
||||
current_len += SDL_snprintf(&buffer[current_len], length - current_len, " 0x%.2x", data[i]);
|
||||
}
|
||||
SDL_strlcat(buffer, "\n", length);
|
||||
SDL_Log("%s", buffer);
|
||||
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "%s", buffer);
|
||||
SDL_free(buffer);
|
||||
}
|
||||
|
||||
@@ -288,9 +312,13 @@ static SDL_GamepadType SDL_GetJoystickGameControllerProtocol(const char *name, U
|
||||
0x1532, // Razer
|
||||
0x20d6, // PowerA
|
||||
0x24c6, // PowerA
|
||||
0x294b, // Snakebyte
|
||||
0x2dc8, // 8BitDo
|
||||
0x2e24, // Hyperkin
|
||||
0x2e95, // SCUF
|
||||
0x3285, // Nacon
|
||||
0x3537, // GameSir
|
||||
0x366c, // ByoWave
|
||||
};
|
||||
|
||||
int i;
|
||||
@@ -338,7 +366,7 @@ static SDL_HIDAPI_DeviceDriver *HIDAPI_GetDeviceDriver(SDL_HIDAPI_Device *device
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (device->vendor_id != USB_VENDOR_VALVE) {
|
||||
if (device->vendor_id != USB_VENDOR_VALVE && device->vendor_id != USB_VENDOR_FLYDIGI_V1 && device->vendor_id != USB_VENDOR_FLYDIGI_V2) {
|
||||
if (device->usage_page && device->usage_page != USAGE_PAGE_GENERIC_DESKTOP) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -430,7 +458,9 @@ static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, bool *removed) S
|
||||
if (device->driver) {
|
||||
bool enabled;
|
||||
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO && device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR) {
|
||||
if (device->vendor_id == USB_VENDOR_NINTENDO &&
|
||||
(device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR ||
|
||||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR)) {
|
||||
enabled = SDL_HIDAPI_combine_joycons;
|
||||
} else {
|
||||
enabled = device->driver->enabled;
|
||||
@@ -1046,7 +1076,11 @@ static bool HIDAPI_CreateCombinedJoyCons(void)
|
||||
SDL_zero(info);
|
||||
info.path = "nintendo_joycons_combined";
|
||||
info.vendor_id = USB_VENDOR_NINTENDO;
|
||||
info.product_id = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||
if (joycons[0]->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT) {
|
||||
info.product_id = USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR;
|
||||
} else {
|
||||
info.product_id = USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR;
|
||||
}
|
||||
info.interface_number = -1;
|
||||
info.usage_page = USB_USAGEPAGE_GENERIC_DESKTOP;
|
||||
info.usage = USB_USAGE_GENERIC_GAMEPAD;
|
||||
@@ -1274,6 +1308,16 @@ bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version,
|
||||
*/
|
||||
SDL_LockJoysticks();
|
||||
for (device = SDL_HIDAPI_devices; device; device = device->next) {
|
||||
// The HIDAPI functionality will be available when the FlyDigi Space Station app has
|
||||
// enabled third party controller mapping, so the driver needs to be active to watch
|
||||
// for that change. Since this is dynamic and we don't have a way to re-trigger device
|
||||
// changes when that happens, we'll pretend the driver isn't available so the XInput
|
||||
// interface will always show up (but won't have any input when the controller is in
|
||||
// enhanced mode)
|
||||
if (device->vendor_id == USB_VENDOR_FLYDIGI_V2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (device->driver &&
|
||||
HIDAPI_IsEquivalentToDevice(vendor_id, product_id, device)) {
|
||||
result = true;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -35,11 +35,21 @@
|
||||
#define SDL_JOYSTICK_HIDAPI_STEAM
|
||||
#define SDL_JOYSTICK_HIDAPI_STEAMDECK
|
||||
#define SDL_JOYSTICK_HIDAPI_SWITCH
|
||||
#ifdef HAVE_LIBUSB
|
||||
#define SDL_JOYSTICK_HIDAPI_SWITCH2
|
||||
#endif
|
||||
#define SDL_JOYSTICK_HIDAPI_WII
|
||||
#define SDL_JOYSTICK_HIDAPI_XBOX360
|
||||
#define SDL_JOYSTICK_HIDAPI_XBOXONE
|
||||
#define SDL_JOYSTICK_HIDAPI_SHIELD
|
||||
#define SDL_JOYSTICK_HIDAPI_STEAM_HORI
|
||||
#define SDL_JOYSTICK_HIDAPI_STEAM_TRITON
|
||||
#define SDL_JOYSTICK_HIDAPI_LG4FF
|
||||
#define SDL_JOYSTICK_HIDAPI_8BITDO
|
||||
#define SDL_JOYSTICK_HIDAPI_FLYDIGI
|
||||
#define SDL_JOYSTICK_HIDAPI_GIP
|
||||
#define SDL_JOYSTICK_HIDAPI_SINPUT
|
||||
#define SDL_JOYSTICK_HIDAPI_ZUIKI
|
||||
|
||||
// Joystick capability definitions
|
||||
#define SDL_JOYSTICK_CAP_MONO_LED 0x00000001
|
||||
@@ -139,6 +149,7 @@ typedef struct SDL_HIDAPI_DeviceDriver
|
||||
// HIDAPI device support
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverCombined;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGIP;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverJoyCons;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverNintendoClassic;
|
||||
@@ -152,11 +163,24 @@ extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamDeck;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch2;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverWii;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamHori;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteamTriton;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLg4ff;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_Driver8BitDo;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverFlydigi;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSInput;
|
||||
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverZUIKI;
|
||||
|
||||
#define LOAD16(A, B) (Sint16)((Uint16)(A) | (((Uint16)(B)) << 8))
|
||||
#define LOAD32(A, B, C, D) ((((Uint32)(A)) << 0) | \
|
||||
(((Uint32)(B)) << 8) | \
|
||||
(((Uint32)(C)) << 16) | \
|
||||
(((Uint32)(D)) << 24))
|
||||
|
||||
// Return true if a HID device is present and supported as a joystick of the given type
|
||||
extern bool HIDAPI_IsDeviceTypePresent(SDL_GamepadType type);
|
||||
|
||||
@@ -0,0 +1,616 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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"
|
||||
|
||||
#include "SDL_report_descriptor.h"
|
||||
|
||||
// This is a very simple (and non-compliant!) report descriptor parser
|
||||
// used to quickly parse Xbox Bluetooth reports
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DescriptorItemTypeMain = 0,
|
||||
DescriptorItemTypeGlobal = 1,
|
||||
DescriptorItemTypeLocal = 2,
|
||||
DescriptorItemTypeReserved = 3,
|
||||
} ItemType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MainTagInput = 0x8,
|
||||
MainTagOutput = 0x9,
|
||||
MainTagFeature = 0xb,
|
||||
MainTagCollection = 0xa,
|
||||
MainTagEndCollection = 0xc,
|
||||
} MainTag;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MainFlagConstant = 0x0001,
|
||||
MainFlagVariable = 0x0002,
|
||||
MainFlagRelative = 0x0004,
|
||||
MainFlagWrap = 0x0008,
|
||||
MainFlagNonLinear = 0x0010,
|
||||
MainFlagNoPreferred = 0x0020,
|
||||
MainFlagNullState = 0x0040,
|
||||
MainFlagVolatile = 0x0080,
|
||||
MainFlagBufferedBytes = 0x0100,
|
||||
} MainFlag;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GlobalTagUsagePage = 0x0,
|
||||
GlobalTagLogicalMinimum = 0x1,
|
||||
GlobalTagLogicalMaximum = 0x2,
|
||||
GlobalTagPhysicalMinimum = 0x3,
|
||||
GlobalTagPhysicalMaximum = 0x4,
|
||||
GlobalTagUnitExponent = 0x5,
|
||||
GlobalTagUnit = 0x6,
|
||||
GlobalTagReportSize = 0x7,
|
||||
GlobalTagReportID = 0x8,
|
||||
GlobalTagReportCount = 0x9,
|
||||
GlobalTagPush = 0xa,
|
||||
GlobalTagPop = 0xb,
|
||||
} GlobalTag;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LocalTagUsage = 0x0,
|
||||
LocalTagUsageMinimum = 0x1,
|
||||
LocalTagUsageMaximum = 0x2,
|
||||
LocalTagDesignatorIndex = 0x3,
|
||||
LocalTagDesignatorMinimum = 0x4,
|
||||
LocalTagDesignatorMaximum = 0x5,
|
||||
LocalTagStringIndex = 0x7,
|
||||
LocalTagStringMinimum = 0x8,
|
||||
LocalTagStringMaximum = 0x9,
|
||||
LocalTagDelimiter = 0xa,
|
||||
} LocalTag;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint32 usage_page;
|
||||
Uint32 report_size;
|
||||
Uint32 report_count;
|
||||
Uint32 report_id;
|
||||
} DescriptorGlobalState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint32 usage_minimum;
|
||||
Uint32 usage_maximum;
|
||||
int usage_maxcount;
|
||||
int usage_count;
|
||||
Uint32 *usages;
|
||||
} DescriptorLocalState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int collection_depth;
|
||||
DescriptorGlobalState global;
|
||||
DescriptorLocalState local;
|
||||
int field_maxcount;
|
||||
int field_count;
|
||||
int field_offset;
|
||||
DescriptorInputField *fields;
|
||||
} DescriptorContext;
|
||||
|
||||
static void DebugDescriptor(DescriptorContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
#ifdef DEBUG_DESCRIPTOR
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
char *message = NULL;
|
||||
SDL_vasprintf(&message, fmt, ap);
|
||||
va_end(ap);
|
||||
if (ctx->collection_depth > 0) {
|
||||
size_t len = 4 * ctx->collection_depth + SDL_strlen(message) + 1;
|
||||
char *output = (char *)SDL_malloc(len);
|
||||
if (output) {
|
||||
SDL_memset(output, ' ', 4 * ctx->collection_depth);
|
||||
output[4 * ctx->collection_depth] = '\0';
|
||||
SDL_strlcat(output, message, len);
|
||||
SDL_free(message);
|
||||
message = output;
|
||||
}
|
||||
}
|
||||
SDL_Log("%s", message);
|
||||
SDL_free(message);
|
||||
#endif // DEBUG_DESCRIPTOR
|
||||
}
|
||||
|
||||
static void DebugMainTag(DescriptorContext *ctx, const char *tag, Uint32 flags)
|
||||
{
|
||||
#ifdef DEBUG_DESCRIPTOR
|
||||
char message[1024] = { 0 };
|
||||
|
||||
SDL_strlcat(message, tag, sizeof(message));
|
||||
SDL_strlcat(message, "(", sizeof(message));
|
||||
if (flags & MainFlagConstant) {
|
||||
SDL_strlcat(message, " Constant", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Data", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagVariable) {
|
||||
SDL_strlcat(message, " Variable", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Array", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagRelative) {
|
||||
SDL_strlcat(message, " Relative", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Absolute", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagWrap) {
|
||||
SDL_strlcat(message, " Wrap", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " No Wrap", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagNonLinear) {
|
||||
SDL_strlcat(message, " Non Linear", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Linear", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagNoPreferred) {
|
||||
SDL_strlcat(message, " No Preferred", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Preferred State", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagNullState) {
|
||||
SDL_strlcat(message, " Null State", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " No Null Position", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagVolatile) {
|
||||
SDL_strlcat(message, " Volatile", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Non Volatile", sizeof(message));
|
||||
}
|
||||
if (flags & MainFlagBufferedBytes) {
|
||||
SDL_strlcat(message, " Buffered Bytes", sizeof(message));
|
||||
} else {
|
||||
SDL_strlcat(message, " Bit Field", sizeof(message));
|
||||
}
|
||||
SDL_strlcat(message, " )", sizeof(message));
|
||||
|
||||
DebugDescriptor(ctx, "%s", message);
|
||||
|
||||
#endif // DEBUG_DESCRIPTOR
|
||||
}
|
||||
|
||||
static Uint32 ReadValue(const Uint8 *data, int size)
|
||||
{
|
||||
Uint32 value = 0;
|
||||
|
||||
int shift = 0;
|
||||
while (size--) {
|
||||
value |= ((Uint32)(*data++)) << shift;
|
||||
shift += 8;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static void ResetLocalState(DescriptorContext *ctx)
|
||||
{
|
||||
ctx->local.usage_minimum = 0;
|
||||
ctx->local.usage_maximum = 0;
|
||||
ctx->local.usage_count = 0;
|
||||
}
|
||||
|
||||
static bool AddUsage(DescriptorContext *ctx, Uint32 usage)
|
||||
{
|
||||
if (ctx->local.usage_count == ctx->local.usage_maxcount) {
|
||||
int usage_maxcount = ctx->local.usage_maxcount + 4;
|
||||
Uint32 *usages = (Uint32 *)SDL_realloc(ctx->local.usages, usage_maxcount * sizeof(*usages));
|
||||
if (!usages) {
|
||||
return false;
|
||||
}
|
||||
ctx->local.usages = usages;
|
||||
ctx->local.usage_maxcount = usage_maxcount;
|
||||
}
|
||||
|
||||
if (usage <= 0xFFFF) {
|
||||
usage |= (ctx->global.usage_page << 16);
|
||||
}
|
||||
ctx->local.usages[ctx->local.usage_count++] = usage;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AddInputField(DescriptorContext *ctx, Uint32 usage, int bit_size)
|
||||
{
|
||||
if (ctx->field_count == ctx->field_maxcount) {
|
||||
int field_maxcount = ctx->field_maxcount + 4;
|
||||
DescriptorInputField *fields = (DescriptorInputField *)SDL_realloc(ctx->fields, field_maxcount * sizeof(*fields));
|
||||
if (!fields) {
|
||||
return false;
|
||||
}
|
||||
ctx->fields = fields;
|
||||
ctx->field_maxcount = field_maxcount;
|
||||
}
|
||||
|
||||
DescriptorInputField *field = &ctx->fields[ctx->field_count++];
|
||||
field->report_id = (Uint8)ctx->global.report_id;
|
||||
field->usage = usage;
|
||||
field->bit_offset = ctx->field_offset;
|
||||
field->bit_size = bit_size;
|
||||
|
||||
DebugDescriptor(ctx, "Adding report %d field 0x%.8x size %d bits at bit offset %d", field->report_id, field->usage, field->bit_size, field->bit_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AddInputFields(DescriptorContext *ctx)
|
||||
{
|
||||
Uint32 usage = 0;
|
||||
|
||||
if (ctx->global.report_count == 0 || ctx->global.report_size == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ctx->local.usage_count == 0 &&
|
||||
ctx->local.usage_minimum > 0 &&
|
||||
ctx->local.usage_maximum >= ctx->local.usage_minimum) {
|
||||
for (usage = ctx->local.usage_minimum; usage <= ctx->local.usage_maximum; ++usage) {
|
||||
if (!AddUsage(ctx, usage)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int usage_index = 0;
|
||||
for (Uint32 i = 0; i < ctx->global.report_count; ++i) {
|
||||
if (usage_index < ctx->local.usage_count) {
|
||||
usage = ctx->local.usages[usage_index];
|
||||
if (usage_index < (ctx->local.usage_count - 1)) {
|
||||
++usage_index;
|
||||
}
|
||||
}
|
||||
|
||||
int size = (int)ctx->global.report_size;
|
||||
if (usage > 0) {
|
||||
if (!AddInputField(ctx, usage, size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ctx->field_offset += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseMainItem(DescriptorContext *ctx, int tag, int size, const Uint8 *data)
|
||||
{
|
||||
Uint32 flags;
|
||||
|
||||
switch (tag) {
|
||||
case MainTagInput:
|
||||
flags = ReadValue(data, size);
|
||||
DebugMainTag(ctx, "MainTagInput", flags);
|
||||
AddInputFields(ctx);
|
||||
break;
|
||||
case MainTagOutput:
|
||||
flags = ReadValue(data, size);
|
||||
DebugMainTag(ctx, "MainTagOutput", flags);
|
||||
break;
|
||||
case MainTagFeature:
|
||||
flags = ReadValue(data, size);
|
||||
DebugMainTag(ctx, "MainTagFeature", flags);
|
||||
break;
|
||||
case MainTagCollection:
|
||||
DebugDescriptor(ctx, "MainTagCollection");
|
||||
switch (*data) {
|
||||
case 0x00:
|
||||
DebugDescriptor(ctx, "Physical");
|
||||
break;
|
||||
case 0x01:
|
||||
DebugDescriptor(ctx, "Application");
|
||||
break;
|
||||
case 0x02:
|
||||
DebugDescriptor(ctx, "Logical");
|
||||
break;
|
||||
case 0x03:
|
||||
DebugDescriptor(ctx, "Report");
|
||||
break;
|
||||
case 0x04:
|
||||
DebugDescriptor(ctx, "Named Array");
|
||||
break;
|
||||
case 0x05:
|
||||
DebugDescriptor(ctx, "Usage Switch");
|
||||
break;
|
||||
case 0x06:
|
||||
DebugDescriptor(ctx, "Usage Modifier");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
++ctx->collection_depth;
|
||||
break;
|
||||
case MainTagEndCollection:
|
||||
if (ctx->collection_depth > 0) {
|
||||
--ctx->collection_depth;
|
||||
}
|
||||
DebugDescriptor(ctx, "MainTagEndCollection");
|
||||
break;
|
||||
default:
|
||||
DebugDescriptor(ctx, "Unknown main tag: %d", tag);
|
||||
break;
|
||||
}
|
||||
|
||||
ResetLocalState(ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseGlobalItem(DescriptorContext *ctx, int tag, int size, const Uint8 *data)
|
||||
{
|
||||
Uint32 value;
|
||||
|
||||
switch (tag) {
|
||||
case GlobalTagUsagePage:
|
||||
ctx->global.usage_page = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagUsagePage: 0x%.4x", ctx->global.usage_page);
|
||||
break;
|
||||
case GlobalTagLogicalMinimum:
|
||||
value = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagLogicalMinimum: %u", value);
|
||||
break;
|
||||
case GlobalTagLogicalMaximum:
|
||||
value = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagLogicalMaximum: %u", value);
|
||||
break;
|
||||
case GlobalTagPhysicalMinimum:
|
||||
value = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagPhysicalMinimum: %u", value);
|
||||
break;
|
||||
case GlobalTagPhysicalMaximum:
|
||||
value = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagPhysicalMaximum: %u", value);
|
||||
break;
|
||||
case GlobalTagUnitExponent:
|
||||
DebugDescriptor(ctx, "GlobalTagUnitExponent");
|
||||
break;
|
||||
case GlobalTagUnit:
|
||||
DebugDescriptor(ctx, "GlobalTagUnit");
|
||||
break;
|
||||
case GlobalTagReportSize:
|
||||
ctx->global.report_size = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagReportSize: %u", ctx->global.report_size);
|
||||
break;
|
||||
case GlobalTagReportID:
|
||||
ctx->global.report_id = ReadValue(data, size);
|
||||
ctx->field_offset = 0;
|
||||
DebugDescriptor(ctx, "GlobalTagReportID: %u", ctx->global.report_id);
|
||||
break;
|
||||
case GlobalTagReportCount:
|
||||
ctx->global.report_count = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "GlobalTagReportCount: %u", ctx->global.report_count);
|
||||
break;
|
||||
case GlobalTagPush:
|
||||
DebugDescriptor(ctx, "GlobalTagPush");
|
||||
break;
|
||||
case GlobalTagPop:
|
||||
DebugDescriptor(ctx, "GlobalTagPop");
|
||||
break;
|
||||
default:
|
||||
DebugDescriptor(ctx, "Unknown global tag");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseLocalItem(DescriptorContext *ctx, int tag, int size, const Uint8 *data)
|
||||
{
|
||||
Uint32 value;
|
||||
|
||||
switch (tag) {
|
||||
case LocalTagUsage:
|
||||
value = ReadValue(data, size);
|
||||
AddUsage(ctx, value);
|
||||
DebugDescriptor(ctx, "LocalTagUsage: 0x%.4x", value);
|
||||
break;
|
||||
case LocalTagUsageMinimum:
|
||||
ctx->local.usage_minimum = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "LocalTagUsageMinimum: 0x%.4x", ctx->local.usage_minimum);
|
||||
break;
|
||||
case LocalTagUsageMaximum:
|
||||
ctx->local.usage_maximum = ReadValue(data, size);
|
||||
DebugDescriptor(ctx, "LocalTagUsageMaximum: 0x%.4x", ctx->local.usage_maximum);
|
||||
break;
|
||||
case LocalTagDesignatorIndex:
|
||||
DebugDescriptor(ctx, "LocalTagDesignatorIndex");
|
||||
break;
|
||||
case LocalTagDesignatorMinimum:
|
||||
DebugDescriptor(ctx, "LocalTagDesignatorMinimum");
|
||||
break;
|
||||
case LocalTagDesignatorMaximum:
|
||||
DebugDescriptor(ctx, "LocalTagDesignatorMaximum");
|
||||
break;
|
||||
case LocalTagStringIndex:
|
||||
DebugDescriptor(ctx, "LocalTagStringIndex");
|
||||
break;
|
||||
case LocalTagStringMinimum:
|
||||
DebugDescriptor(ctx, "LocalTagStringMinimum");
|
||||
break;
|
||||
case LocalTagStringMaximum:
|
||||
DebugDescriptor(ctx, "LocalTagStringMaximum");
|
||||
break;
|
||||
case LocalTagDelimiter:
|
||||
DebugDescriptor(ctx, "LocalTagDelimiter");
|
||||
break;
|
||||
default:
|
||||
DebugDescriptor(ctx, "Unknown local tag");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseDescriptor(DescriptorContext *ctx, const Uint8 *descriptor, int descriptor_size)
|
||||
{
|
||||
SDL_zerop(ctx);
|
||||
|
||||
for (const Uint8 *here = descriptor; here < descriptor + descriptor_size; ) {
|
||||
static const int sizes[4] = { 0, 1, 2, 4 };
|
||||
Uint8 data = *here++;
|
||||
int size = sizes[(data & 0x3)];
|
||||
int type = ((data >> 2) & 0x3);
|
||||
int tag = (data >> 4);
|
||||
|
||||
if ((here + size) > (descriptor + descriptor_size)) {
|
||||
return SDL_SetError("Invalid descriptor");
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DESCRIPTOR
|
||||
SDL_Log("Data: 0x%.2x, size: %d, type: %d, tag: %d", data, size, type, tag);
|
||||
#endif
|
||||
switch (type) {
|
||||
case DescriptorItemTypeMain:
|
||||
if (!ParseMainItem(ctx, tag, size, here)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DescriptorItemTypeGlobal:
|
||||
if (!ParseGlobalItem(ctx, tag, size, here)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DescriptorItemTypeLocal:
|
||||
if (!ParseLocalItem(ctx, tag, size, here)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case DescriptorItemTypeReserved:
|
||||
// Long items are currently unsupported
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
here += size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CleanupContext(DescriptorContext *ctx)
|
||||
{
|
||||
SDL_free(ctx->local.usages);
|
||||
SDL_free(ctx->fields);
|
||||
}
|
||||
|
||||
SDL_ReportDescriptor *SDL_ParseReportDescriptor(const Uint8 *descriptor, int descriptor_size)
|
||||
{
|
||||
SDL_ReportDescriptor *result = NULL;
|
||||
|
||||
DescriptorContext ctx;
|
||||
if (ParseDescriptor(&ctx, descriptor, descriptor_size)) {
|
||||
result = (SDL_ReportDescriptor *)SDL_malloc(sizeof(*result));
|
||||
if (result) {
|
||||
result->field_count = ctx.field_count;
|
||||
result->fields = ctx.fields;
|
||||
ctx.fields = NULL;
|
||||
}
|
||||
}
|
||||
CleanupContext(&ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SDL_DescriptorHasUsage(SDL_ReportDescriptor *descriptor, Uint16 usage_page, Uint16 usage)
|
||||
{
|
||||
if (!descriptor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint32 full_usage = (((Uint32)usage_page << 16) | usage);
|
||||
for (int i = 0; i < descriptor->field_count; ++i) {
|
||||
if (descriptor->fields[i].usage == full_usage) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDL_DestroyDescriptor(SDL_ReportDescriptor *descriptor)
|
||||
{
|
||||
if (descriptor) {
|
||||
SDL_free(descriptor->fields);
|
||||
SDL_free(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
bool SDL_ReadReportData(const Uint8 *data, int size, int bit_offset, int bit_size, Uint32 *value)
|
||||
{
|
||||
int offset = (bit_offset / 8);
|
||||
if (offset >= size) {
|
||||
*value = 0;
|
||||
return SDL_SetError("Out of bounds reading report data");
|
||||
}
|
||||
|
||||
*value = ReadValue(data + offset, (bit_size + 7) / 8);
|
||||
|
||||
int shift = (bit_offset % 8);
|
||||
if (shift > 0) {
|
||||
*value >>= shift;
|
||||
}
|
||||
|
||||
switch (bit_size) {
|
||||
case 1:
|
||||
*value &= 0x1;
|
||||
break;
|
||||
case 4:
|
||||
*value &= 0xf;
|
||||
break;
|
||||
case 10:
|
||||
*value &= 0x3ff;
|
||||
break;
|
||||
case 15:
|
||||
*value &= 0x7fff;
|
||||
break;
|
||||
default:
|
||||
SDL_assert((bit_size % 8) == 0);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef TEST_MAIN
|
||||
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *file = argv[1];
|
||||
if (argc < 2) {
|
||||
SDL_Log("Usage: %s file", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t descriptor_size = 0;
|
||||
Uint8 *descriptor = SDL_LoadFile(argv[1], &descriptor_size);
|
||||
if (!descriptor) {
|
||||
SDL_Log("Couldn't load %s: %s", argv[1], SDL_GetError());
|
||||
return 2;
|
||||
}
|
||||
|
||||
DescriptorContext ctx;
|
||||
if (!ParseDescriptor(&ctx, descriptor, descriptor_size)) {
|
||||
SDL_Log("Couldn't parse %s: %s", argv[1], SDL_GetError());
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // TEST_MAIN
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 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"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint8 report_id;
|
||||
Uint32 usage;
|
||||
int bit_offset;
|
||||
int bit_size;
|
||||
} DescriptorInputField;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int field_count;
|
||||
DescriptorInputField *fields;
|
||||
} SDL_ReportDescriptor;
|
||||
|
||||
extern SDL_ReportDescriptor *SDL_ParseReportDescriptor(const Uint8 *descriptor, int descriptor_size);
|
||||
extern bool SDL_DescriptorHasUsage(SDL_ReportDescriptor *descriptor, Uint16 usage_page, Uint16 usage);
|
||||
extern void SDL_DestroyDescriptor(SDL_ReportDescriptor *descriptor);
|
||||
extern bool SDL_ReadReportData(const Uint8 *data, int size, int bit_offset, int bit_size, Uint32 *value);
|
||||
@@ -353,7 +353,7 @@ enum GamepadButtons
|
||||
// Mode adjust
|
||||
enum ModeAdjustModes
|
||||
{
|
||||
MODE_ADJUST_SENSITITY=1,
|
||||
MODE_ADJUST_SENSITIVITY=1,
|
||||
MODE_ADJUST_LEFT_PAD_SECONDARY_MODE,
|
||||
MODE_ADJUST_RIGHT_PAD_SECONDARY_MODE,
|
||||
MODE_ADJUST_COUNT
|
||||
@@ -364,8 +364,8 @@ typedef enum
|
||||
{
|
||||
ATTRIB_UNIQUE_ID,
|
||||
ATTRIB_PRODUCT_ID,
|
||||
ATTRIB_PRODUCT_REVISON, // deprecated
|
||||
ATTRIB_CAPABILITIES = ATTRIB_PRODUCT_REVISON, // intentional aliasing
|
||||
ATTRIB_PRODUCT_REVISION, // deprecated
|
||||
ATTRIB_CAPABILITIES = ATTRIB_PRODUCT_REVISION, // intentional aliasing
|
||||
ATTRIB_FIRMWARE_VERSION, // deprecated
|
||||
ATTRIB_FIRMWARE_BUILD_TIME,
|
||||
ATTRIB_RADIO_FIRMWARE_BUILD_TIME,
|
||||
@@ -411,6 +411,12 @@ typedef enum {
|
||||
TRACKPAD_NUM_MODES
|
||||
} TrackpadDPadMode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIZARD_MODE_OFF,
|
||||
LIZARD_MODE_ON,
|
||||
} LizardModeState_t;
|
||||
|
||||
// Read-write controller settings (only add to this enum and never change the order)
|
||||
typedef enum
|
||||
{
|
||||
@@ -423,7 +429,7 @@ typedef enum
|
||||
SETTING_USB_DEBUG_MODE,
|
||||
SETTING_LEFT_TRACKPAD_MODE,
|
||||
SETTING_RIGHT_TRACKPAD_MODE,
|
||||
SETTING_MOUSE_POINTER_ENABLED,
|
||||
SETTING_LIZARD_MODE,
|
||||
|
||||
// 10
|
||||
SETTING_DPAD_DEADZONE,
|
||||
|
||||
@@ -112,7 +112,7 @@ typedef struct {
|
||||
int16_t dur_ms; // Duration of tone / rumble (if applicable) (neg = infinite)
|
||||
|
||||
uint16_t noise_intensity;
|
||||
uint16_t lfo_freq; // Drives both tone and rumble geneators
|
||||
uint16_t lfo_freq; // Drives both tone and rumble generators
|
||||
uint8_t lfo_depth; // percentage, typically 100
|
||||
uint8_t rand_tone_gain; // Randomize each LFO cycle's gain
|
||||
uint8_t script_id; // Used w/ dBgain for scripted haptics
|
||||
@@ -154,6 +154,100 @@ typedef struct
|
||||
|
||||
} FeatureReportMsg;
|
||||
|
||||
// Triton and derivatives utilize output reports for haptic commands. This is a
|
||||
// snapshot from Nov 2024 -- things may change.
|
||||
|
||||
// Triton Output Report Lengths #defs include +1 for the OR ID
|
||||
|
||||
// Output Report Haptic Messages for Triton
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type;
|
||||
uint16_t intensity;
|
||||
struct
|
||||
{
|
||||
uint16_t speed;
|
||||
int8_t gain;
|
||||
} left, right;
|
||||
} MsgHapticRumble;
|
||||
#define HID_RUMBLE_OUTPUT_REPORT_BYTES 10
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t side;
|
||||
uint16_t on_us;
|
||||
uint16_t off_us;
|
||||
uint16_t repeat_count;
|
||||
uint16_t gain_db;
|
||||
} MsgHapticPulse;
|
||||
#define HID_HAPTIC_PULSE_OUTPUT_REPORT_BYTES 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t side;
|
||||
uint8_t command;
|
||||
int8_t gain_db;
|
||||
} MsgHapticCommand;
|
||||
#define HID_HAPTIC_COMMAND_REPORT_BYTES 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t side;
|
||||
int8_t gain_db;
|
||||
uint16_t frequency;
|
||||
uint16_t duration_ms;
|
||||
uint16_t lfo_freq;
|
||||
uint8_t lfo_depth;
|
||||
} MsgHapticLfoTone;
|
||||
#define HID_HAPTIC_LFO_TONE_REPORT_BYTES 10
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t side;
|
||||
int8_t gain_db;
|
||||
uint16_t duration_ms;
|
||||
struct
|
||||
{
|
||||
uint16_t frequency;
|
||||
} start, end;
|
||||
} MsgHapticLogSweep;
|
||||
#define HID_HAPTIC_LOG_SWEEP_REPORT_BYTES 9
|
||||
|
||||
typedef struct m
|
||||
{
|
||||
uint8_t side;
|
||||
uint8_t script_id;
|
||||
int8_t gain_db;
|
||||
} MsgHapticScript;
|
||||
#define HID_HAPTIC_SCRIPT_REPORT_BYTES 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ID_OUT_REPORT_HAPTIC_RUMBLE = 0x80,
|
||||
ID_OUT_REPORT_HAPTIC_PULSE = 0x81,
|
||||
ID_OUT_REPORT_HAPTIC_COMMAND = 0x82,
|
||||
ID_OUT_REPORT_HAPTIC_LFO_TONE = 0x83,
|
||||
ID_OUT_REPORT_HAPTIC_LOG_SWEEP = 0x85,
|
||||
ID_OUT_REPORT_HAPTIC_SCRIPT = 0x86,
|
||||
} ValveTritonOutReportMessageIDs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t report_id;
|
||||
union
|
||||
{
|
||||
MsgHapticRumble hapticRumble;
|
||||
MsgHapticPulse hapticPulse;
|
||||
MsgHapticCommand hapticCommand;
|
||||
MsgHapticLfoTone hapticLfoTone;
|
||||
MsgHapticLogSweep hapticLogSweep;
|
||||
MsgHapticScript hapticScript;
|
||||
} payload;
|
||||
|
||||
} OutputReportMsg;
|
||||
|
||||
|
||||
// Roll this version forward anytime that you are breaking compatibility of existing
|
||||
// message types within ValveInReport_t or the header itself. Hopefully this should
|
||||
// be super rare and instead you should just add new message payloads to the union,
|
||||
@@ -261,7 +355,7 @@ typedef struct
|
||||
short sRightPadX;
|
||||
short sRightPadY;
|
||||
|
||||
//This mimcs how the dongle reconstitutes HID packets, there will be 0-4 shorts depending on gyro mode
|
||||
//This mimics how the dongle reconstitutes HID packets, there will be 0-4 shorts depending on gyro mode
|
||||
unsigned char ucGyroDataType; //TODO could maybe find some unused bits in the button field for this info (is only 2bits)
|
||||
short sGyro[4];
|
||||
|
||||
@@ -413,51 +507,129 @@ typedef struct
|
||||
unsigned short sPressurePadRight;
|
||||
} SteamDeckStatePacket_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ValveInReportHeader_t header;
|
||||
|
||||
union
|
||||
{
|
||||
ValveControllerStatePacket_t controllerState;
|
||||
ValveControllerBLEStatePacket_t controllerBLEState;
|
||||
ValveControllerDebugPacket_t debugState;
|
||||
ValveControllerTrackpadImage_t padImage;
|
||||
ValveControllerRawTrackpadImage_t rawPadImage;
|
||||
SteamControllerWirelessEvent_t wirelessEvent;
|
||||
SteamControllerStatusEvent_t statusEvent;
|
||||
SteamDeckStatePacket_t deckState;
|
||||
} payload;
|
||||
|
||||
ValveInReportHeader_t header;
|
||||
|
||||
union
|
||||
{
|
||||
ValveControllerStatePacket_t controllerState;
|
||||
ValveControllerBLEStatePacket_t controllerBLEState;
|
||||
ValveControllerDebugPacket_t debugState;
|
||||
ValveControllerTrackpadImage_t padImage;
|
||||
ValveControllerRawTrackpadImage_t rawPadImage;
|
||||
SteamControllerWirelessEvent_t wirelessEvent;
|
||||
SteamControllerStatusEvent_t statusEvent;
|
||||
SteamDeckStatePacket_t deckState;
|
||||
} payload;
|
||||
|
||||
} ValveInReport_t;
|
||||
|
||||
|
||||
// Enumeration for BLE packet protocol
|
||||
enum EBLEPacketReportNums
|
||||
{
|
||||
// Skipping past 2-3 because they are escape characters in Uart protocol
|
||||
k_EBLEReportState = 4,
|
||||
k_EBLEReportStatus = 5,
|
||||
k_EBLEReportState = 4,
|
||||
k_EBLEReportStatus = 5,
|
||||
};
|
||||
|
||||
|
||||
// Enumeration of data chunks in BLE state packets
|
||||
enum EBLEOptionDataChunksBitmask
|
||||
{
|
||||
// First byte upper nibble
|
||||
k_EBLEButtonChunk1 = 0x10,
|
||||
k_EBLEButtonChunk2 = 0x20,
|
||||
k_EBLEButtonChunk3 = 0x40,
|
||||
k_EBLELeftJoystickChunk = 0x80,
|
||||
// First byte upper nibble
|
||||
k_EBLEButtonChunk1 = 0x10,
|
||||
k_EBLEButtonChunk2 = 0x20,
|
||||
k_EBLEButtonChunk3 = 0x40,
|
||||
k_EBLELeftJoystickChunk = 0x80,
|
||||
|
||||
// Second full byte
|
||||
k_EBLELeftTrackpadChunk = 0x100,
|
||||
k_EBLERightTrackpadChunk = 0x200,
|
||||
k_EBLEIMUAccelChunk = 0x400,
|
||||
k_EBLEIMUGyroChunk = 0x800,
|
||||
k_EBLEIMUQuatChunk = 0x1000,
|
||||
// Second full byte
|
||||
k_EBLELeftTrackpadChunk = 0x100,
|
||||
k_EBLERightTrackpadChunk = 0x200,
|
||||
k_EBLEIMUAccelChunk = 0x400,
|
||||
k_EBLEIMUGyroChunk = 0x800,
|
||||
k_EBLEIMUQuatChunk = 0x1000,
|
||||
};
|
||||
|
||||
// Triton and derivatives do not use the ValveInReport_t structure
|
||||
|
||||
enum ETritonReportIDTypes
|
||||
{
|
||||
ID_TRITON_CONTROLLER_STATE = 0x42,
|
||||
ID_TRITON_BATTERY_STATUS = 0x43,
|
||||
ID_TRITON_CONTROLLER_STATE_BLE = 0x45,
|
||||
ID_TRITON_WIRELESS_STATUS_X = 0x46,
|
||||
ID_TRITON_WIRELESS_STATUS = 0x79,
|
||||
};
|
||||
|
||||
enum ETritonWirelessState
|
||||
{
|
||||
k_ETritonWirelessStateDisconnect = 1,
|
||||
k_ETritonWirelessStateConnect = 2,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t uTimestamp;
|
||||
short sAccelX;
|
||||
short sAccelY;
|
||||
short sAccelZ;
|
||||
|
||||
short sGyroX;
|
||||
short sGyroY;
|
||||
short sGyroZ;
|
||||
|
||||
short sGyroQuatW;
|
||||
short sGyroQuatX;
|
||||
short sGyroQuatY;
|
||||
short sGyroQuatZ;
|
||||
} TritonMTUIMU_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cSeq_num;
|
||||
uint32_t uButtons;
|
||||
short sTriggerLeft;
|
||||
short sTriggerRight;
|
||||
|
||||
short sLeftStickX;
|
||||
short sLeftStickY;
|
||||
short sRightStickX;
|
||||
short sRightStickY;
|
||||
|
||||
short sLeftPadX;
|
||||
short sLeftPadY;
|
||||
unsigned short ucPressureLeft;
|
||||
|
||||
short sRightPadX;
|
||||
short sRightPadY;
|
||||
unsigned short ucPressureRight;
|
||||
TritonMTUIMU_t imu;
|
||||
} TritonMTUFull_t;
|
||||
|
||||
enum EChargeState
|
||||
{
|
||||
k_EChargeStateReset,
|
||||
k_EChargeStateDischarging,
|
||||
k_EChargeStateCharging,
|
||||
k_EChargeStateSrcValidate,
|
||||
k_EChargeStateChargingDone,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char ucChargeState; // EChargeState
|
||||
unsigned char ucBatteryLevel;
|
||||
unsigned short sBatteryVoltage;
|
||||
unsigned short sSystemVoltage;
|
||||
unsigned short sInputVoltage;
|
||||
unsigned short sCurrent;
|
||||
unsigned short sInputCurrent;
|
||||
unsigned short sTemperature;
|
||||
} TritonBatteryStatus_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char state;
|
||||
} TritonWirelessStatus_t;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif // _CONTROLLER_STRUCTS
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -75,6 +75,18 @@
|
||||
#ifndef BTN_DPAD_RIGHT
|
||||
#define BTN_DPAD_RIGHT 0x223
|
||||
#endif
|
||||
#ifndef BTN_GRIPL
|
||||
#define BTN_GRIPL 0x224
|
||||
#endif
|
||||
#ifndef BTN_GRIPR
|
||||
#define BTN_GRIPR 0x225
|
||||
#endif
|
||||
#ifndef BTN_GRIPL2
|
||||
#define BTN_GRIPL2 0x226
|
||||
#endif
|
||||
#ifndef BTN_GRIPR2
|
||||
#define BTN_GRIPR2 0x227
|
||||
#endif
|
||||
|
||||
#ifndef BTN_TRIGGER_HAPPY
|
||||
#define BTN_TRIGGER_HAPPY 0x2c0
|
||||
@@ -150,7 +162,10 @@ typedef struct SDL_joylist_item
|
||||
{
|
||||
SDL_JoystickID device_instance;
|
||||
char *path; // "/dev/input/event2" or whatever
|
||||
Uint16 vendor;
|
||||
Uint16 product;
|
||||
char *name; // "SideWinder 3D Pro" or whatever
|
||||
char *driver; // "xpad" or whatever
|
||||
SDL_GUID guid;
|
||||
dev_t devnum;
|
||||
int steam_virtual_gamepad_slot;
|
||||
@@ -274,19 +289,20 @@ static bool GuessIsSensor(int fd)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *vendor_return, Uint16 *product_return, SDL_GUID *guid)
|
||||
static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *vendor_return, Uint16 *product_return, SDL_GUID *guid, char **driver_return)
|
||||
{
|
||||
struct input_id inpid;
|
||||
char *name;
|
||||
char *name = NULL;
|
||||
char *driver = NULL;
|
||||
char product_string[128];
|
||||
int class = 0;
|
||||
|
||||
SDL_zero(inpid);
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
// Opening input devices can generate synchronous device I/O, so avoid it if we can
|
||||
if (SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class) &&
|
||||
if (SDL_UDEV_GetProductInfo(path, &inpid, &class, &driver) &&
|
||||
!(class & SDL_UDEV_DEVICE_JOYSTICK)) {
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -294,34 +310,33 @@ static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *ve
|
||||
*fd = open(path, O_RDONLY | O_CLOEXEC, 0);
|
||||
}
|
||||
if (!fd || *fd < 0) {
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(*fd, JSIOCGNAME(sizeof(product_string)), product_string) <= 0) {
|
||||
// When udev enumeration or classification, we only got joysticks here, so no need to test
|
||||
if (enumeration_method != ENUMERATION_LIBUDEV && !class && !GuessIsJoystick(*fd)) {
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Could have vendor and product already from udev, but should agree with evdev
|
||||
if (ioctl(*fd, EVIOCGID, &inpid) < 0) {
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ioctl(*fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
|
||||
if (!name) {
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) &&
|
||||
SDL_JoystickHandledByAnotherDriver(&SDL_LINUX_JoystickDriver, inpid.vendor, inpid.product, inpid.version, name)) {
|
||||
SDL_free(name);
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
|
||||
FixupDeviceInfoForMapping(*fd, &inpid);
|
||||
@@ -331,14 +346,19 @@ static bool IsJoystick(const char *path, int *fd, char **name_return, Uint16 *ve
|
||||
#endif
|
||||
|
||||
if (SDL_ShouldIgnoreJoystick(inpid.vendor, inpid.product, inpid.version, name)) {
|
||||
SDL_free(name);
|
||||
return false;
|
||||
goto error;
|
||||
}
|
||||
*name_return = name;
|
||||
*driver_return = driver;
|
||||
*vendor_return = inpid.vendor;
|
||||
*product_return = inpid.product;
|
||||
*guid = SDL_CreateJoystickGUID(inpid.bustype, inpid.vendor, inpid.product, inpid.version, NULL, product_string, 0, 0);
|
||||
return true;
|
||||
|
||||
error:
|
||||
SDL_free(driver);
|
||||
SDL_free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsSensor(const char *path, int *fd)
|
||||
@@ -349,7 +369,7 @@ static bool IsSensor(const char *path, int *fd)
|
||||
SDL_zero(inpid);
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
// Opening input devices can generate synchronous device I/O, so avoid it if we can
|
||||
if (SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class) &&
|
||||
if (SDL_UDEV_GetProductInfo(path, &inpid, &class, NULL) &&
|
||||
!(class & SDL_UDEV_DEVICE_ACCELEROMETER)) {
|
||||
return false;
|
||||
}
|
||||
@@ -422,6 +442,7 @@ static void FreeJoylistItem(SDL_joylist_item *item)
|
||||
SDL_free(item->mapping);
|
||||
SDL_free(item->path);
|
||||
SDL_free(item->name);
|
||||
SDL_free(item->driver);
|
||||
SDL_free(item);
|
||||
}
|
||||
|
||||
@@ -436,6 +457,7 @@ static void MaybeAddDevice(const char *path)
|
||||
struct stat sb;
|
||||
int fd = -1;
|
||||
char *name = NULL;
|
||||
char *driver = NULL;
|
||||
Uint16 vendor, product;
|
||||
SDL_GUID guid;
|
||||
SDL_joylist_item *item;
|
||||
@@ -473,7 +495,7 @@ static void MaybeAddDevice(const char *path)
|
||||
SDL_Log("Checking %s", path);
|
||||
#endif
|
||||
|
||||
if (IsJoystick(path, &fd, &name, &vendor, &product, &guid)) {
|
||||
if (IsJoystick(path, &fd, &name, &vendor, &product, &guid, &driver)) {
|
||||
#ifdef DEBUG_INPUT_EVENTS
|
||||
SDL_Log("found joystick: %s", path);
|
||||
#endif
|
||||
@@ -486,8 +508,11 @@ static void MaybeAddDevice(const char *path)
|
||||
item->devnum = sb.st_rdev;
|
||||
item->steam_virtual_gamepad_slot = -1;
|
||||
item->path = SDL_strdup(path);
|
||||
item->vendor = vendor;
|
||||
item->product = product;
|
||||
item->name = name;
|
||||
item->guid = guid;
|
||||
item->driver = driver;
|
||||
|
||||
if (vendor == USB_VENDOR_VALVE &&
|
||||
product == USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD) {
|
||||
@@ -861,7 +886,7 @@ static void LINUX_ScanSteamVirtualGamepads(void)
|
||||
// Opening input devices can generate synchronous device I/O, so avoid it if we can
|
||||
class = 0;
|
||||
SDL_zero(inpid);
|
||||
if (SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version, &class) &&
|
||||
if (SDL_UDEV_GetProductInfo(path, &inpid, &class, NULL) &&
|
||||
(inpid.vendor != USB_VENDOR_VALVE || inpid.product != USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD)) {
|
||||
free(entries[i]); // This should NOT be SDL_free()
|
||||
continue;
|
||||
@@ -948,7 +973,7 @@ static void LINUX_JoystickDetect(void)
|
||||
{
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
if (enumeration_method == ENUMERATION_LIBUDEV) {
|
||||
SDL_UDEV_Poll();
|
||||
// Polling will happen in the main event loop
|
||||
} else
|
||||
#endif
|
||||
#ifdef HAVE_INOTIFY
|
||||
@@ -1136,6 +1161,8 @@ static SDL_JoystickID LINUX_JoystickGetDeviceInstanceID(int device_index)
|
||||
|
||||
static bool allocate_balldata(SDL_Joystick *joystick)
|
||||
{
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
joystick->hwdata->balls =
|
||||
(struct hwdata_ball *)SDL_calloc(joystick->nballs, sizeof(struct hwdata_ball));
|
||||
if (joystick->hwdata->balls == NULL) {
|
||||
@@ -1512,7 +1539,7 @@ static SDL_sensorlist_item *GetSensor(SDL_joylist_item *item)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_memset(uniq_item, 0, sizeof(uniq_item));
|
||||
SDL_zeroa(uniq_item);
|
||||
fd_item = open(item->path, O_RDONLY | O_CLOEXEC, 0);
|
||||
if (fd_item < 0) {
|
||||
return NULL;
|
||||
@@ -1534,7 +1561,7 @@ static SDL_sensorlist_item *GetSensor(SDL_joylist_item *item)
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_memset(uniq_sensor, 0, sizeof(uniq_sensor));
|
||||
SDL_zeroa(uniq_sensor);
|
||||
fd_sensor = open(item_sensor->path, O_RDONLY | O_CLOEXEC, 0);
|
||||
if (fd_sensor < 0) {
|
||||
continue;
|
||||
@@ -1587,6 +1614,10 @@ static bool LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
item_sensor->hwdata = joystick->hwdata;
|
||||
}
|
||||
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
joystick->serial = SDL_UDEV_GetProductSerial(item->path);
|
||||
#endif
|
||||
|
||||
// mark joystick as fresh and ready
|
||||
joystick->hwdata->fresh = true;
|
||||
|
||||
@@ -1747,6 +1778,8 @@ static void HandleHat(Uint64 timestamp, SDL_Joystick *stick, int hatidx, int axi
|
||||
|
||||
static void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
|
||||
{
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
stick->hwdata->balls[ball].axis[axis] += value;
|
||||
}
|
||||
|
||||
@@ -1844,6 +1877,20 @@ static void PollAllValues(Uint64 timestamp, SDL_Joystick *joystick)
|
||||
// Joyballs are relative input, so there's no poll state. Events only!
|
||||
}
|
||||
|
||||
static void CorrectSensorData(struct joystick_hwdata *hwdata, float *values, float *data)
|
||||
{
|
||||
if (hwdata->item->vendor == USB_VENDOR_NINTENDO) {
|
||||
// The Nintendo driver uses a different axis order than SDL
|
||||
data[0] = -values[1];
|
||||
data[1] = values[2];
|
||||
data[2] = -values[0];
|
||||
} else {
|
||||
data[0] = values[0];
|
||||
data[1] = values[1];
|
||||
data[2] = values[2];
|
||||
}
|
||||
}
|
||||
|
||||
static void PollAllSensors(Uint64 timestamp, SDL_Joystick *joystick)
|
||||
{
|
||||
struct input_absinfo absinfo;
|
||||
@@ -1854,27 +1901,31 @@ static void PollAllSensors(Uint64 timestamp, SDL_Joystick *joystick)
|
||||
SDL_assert(joystick->hwdata->fd_sensor >= 0);
|
||||
|
||||
if (joystick->hwdata->has_gyro) {
|
||||
float data[3] = {0.0f, 0.0f, 0.0f};
|
||||
float values[3] = {0.0f, 0.0f, 0.0f};
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_RX + i), &absinfo) >= 0) {
|
||||
data[i] = absinfo.value * (SDL_PI_F / 180.f) / joystick->hwdata->gyro_scale[i];
|
||||
values[i] = absinfo.value * (SDL_PI_F / 180.f) / joystick->hwdata->gyro_scale[i];
|
||||
#ifdef DEBUG_INPUT_EVENTS
|
||||
SDL_Log("Joystick : Re-read Gyro (axis %d) val= %f", i, data[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
float data[3];
|
||||
CorrectSensorData(joystick->hwdata, values, data);
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO, SDL_US_TO_NS(joystick->hwdata->sensor_tick), data, 3);
|
||||
}
|
||||
if (joystick->hwdata->has_accelerometer) {
|
||||
float data[3] = {0.0f, 0.0f, 0.0f};
|
||||
float values[3] = {0.0f, 0.0f, 0.0f};
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (ioctl(joystick->hwdata->fd_sensor, EVIOCGABS(ABS_X + i), &absinfo) >= 0) {
|
||||
data[i] = absinfo.value * SDL_STANDARD_GRAVITY / joystick->hwdata->accelerometer_scale[i];
|
||||
values[i] = absinfo.value * SDL_STANDARD_GRAVITY / joystick->hwdata->accelerometer_scale[i];
|
||||
#ifdef DEBUG_INPUT_EVENTS
|
||||
SDL_Log("Joystick : Re-read Accelerometer (axis %d) val= %f", i, data[i]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
float data[3];
|
||||
CorrectSensorData(joystick->hwdata, values, data);
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, SDL_US_TO_NS(joystick->hwdata->sensor_tick), data, 3);
|
||||
}
|
||||
}
|
||||
@@ -2058,12 +2109,15 @@ static void HandleInputEvents(SDL_Joystick *joystick)
|
||||
PollAllSensors(SDL_GetTicksNS(), joystick); // try to sync up to current state now
|
||||
} else {
|
||||
Uint64 timestamp = SDL_EVDEV_GetEventTimestamp(event);
|
||||
float data[3];
|
||||
CorrectSensorData(joystick->hwdata, joystick->hwdata->gyro_data, data);
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_GYRO,
|
||||
SDL_US_TO_NS(joystick->hwdata->sensor_tick),
|
||||
joystick->hwdata->gyro_data, 3);
|
||||
data, 3);
|
||||
CorrectSensorData(joystick->hwdata, joystick->hwdata->accel_data, data);
|
||||
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL,
|
||||
SDL_US_TO_NS(joystick->hwdata->sensor_tick),
|
||||
joystick->hwdata->accel_data, 3);
|
||||
data, 3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -2244,6 +2298,12 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
|
||||
MAPPED_DPAD_LEFT = 0x4,
|
||||
MAPPED_DPAD_RIGHT = 0x8,
|
||||
MAPPED_DPAD_ALL = 0xF,
|
||||
|
||||
MAPPED_LEFT_PADDLE1 = 0x1,
|
||||
MAPPED_RIGHT_PADDLE1 = 0x2,
|
||||
MAPPED_LEFT_PADDLE2 = 0x4,
|
||||
MAPPED_RIGHT_PADDLE2 = 0x8,
|
||||
MAPPED_PADDLE_ALL = 0xF,
|
||||
};
|
||||
unsigned int mapped;
|
||||
bool result = false;
|
||||
@@ -2609,6 +2669,27 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
|
||||
SDL_Log("Mapped DPUP+DOWN to axis %d (ABS_HAT0Y)", out->dpup.target);
|
||||
SDL_Log("Mapped DPLEFT+RIGHT to axis %d (ABS_HAT0X)", out->dpleft.target);
|
||||
#endif
|
||||
} else if (item->driver && SDL_strcmp(item->driver, "xpad") == 0) {
|
||||
// xpad will sometimes map the D-Pad as BTN_TRIGGER_HAPPY1 - BTN_TRIGGER_HAPPY4
|
||||
if (joystick->hwdata->has_key[BTN_TRIGGER_HAPPY1] &&
|
||||
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY2] &&
|
||||
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY3] &&
|
||||
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY4]) {
|
||||
out->dpleft.kind = EMappingKind_Button;
|
||||
out->dpright.kind = EMappingKind_Button;
|
||||
out->dpup.kind = EMappingKind_Button;
|
||||
out->dpdown.kind = EMappingKind_Button;
|
||||
out->dpleft.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY1];
|
||||
out->dpright.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY2];
|
||||
out->dpup.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY3];
|
||||
out->dpdown.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY4];
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped DPLEFT to button %d (BTN_TRIGGER_HAPPY1)", out->dpleft.target);
|
||||
SDL_Log("Mapped DPRIGHT to button %d (BTN_TRIGGER_HAPPY2)", out->dpright.target);
|
||||
SDL_Log("Mapped DPUP to button %d (BTN_TRIGGER_HAPPY3)", out->dpup.target);
|
||||
SDL_Log("Mapped DPDOWN to button %d (BTN_TRIGGER_HAPPY4)", out->dpdown.target);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2653,8 +2734,44 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
|
||||
#endif
|
||||
}
|
||||
|
||||
if (SDL_GetJoystickVendor(joystick) == USB_VENDOR_MICROSOFT) {
|
||||
mapped = 0;
|
||||
|
||||
if (joystick->hwdata->has_key[BTN_GRIPR]) {
|
||||
out->right_paddle1.kind = EMappingKind_Button;
|
||||
out->right_paddle1.target = joystick->hwdata->key_map[BTN_GRIPR];
|
||||
mapped |= MAPPED_RIGHT_PADDLE1;
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped RIGHT_PADDLE1 to button %d (BTN_GRIPR)", out->right_paddle1.target);
|
||||
#endif
|
||||
}
|
||||
if (joystick->hwdata->has_key[BTN_GRIPL]) {
|
||||
out->left_paddle1.kind = EMappingKind_Button;
|
||||
out->left_paddle1.target = joystick->hwdata->key_map[BTN_GRIPL];
|
||||
mapped |= MAPPED_LEFT_PADDLE1;
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped LEFT_PADDLE1 to button %d (BTN_GRIPL)", out->left_paddle1.target);
|
||||
#endif
|
||||
}
|
||||
if (joystick->hwdata->has_key[BTN_GRIPR2]) {
|
||||
out->right_paddle2.kind = EMappingKind_Button;
|
||||
out->right_paddle2.target = joystick->hwdata->key_map[BTN_GRIPR2];
|
||||
mapped |= MAPPED_RIGHT_PADDLE2;
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped RIGHT_PADDLE2 to button %d (BTN_GRIPR)", out->right_paddle2.target);
|
||||
#endif
|
||||
}
|
||||
if (joystick->hwdata->has_key[BTN_GRIPL2]) {
|
||||
out->left_paddle2.kind = EMappingKind_Button;
|
||||
out->left_paddle2.target = joystick->hwdata->key_map[BTN_GRIPL2];
|
||||
mapped |= MAPPED_LEFT_PADDLE2;
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped LEFT_PADDLE2 to button %d (BTN_GRIPL2)", out->left_paddle2.target);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (mapped != MAPPED_PADDLE_ALL && SDL_GetJoystickVendor(joystick) == USB_VENDOR_MICROSOFT) {
|
||||
// The Xbox Elite controllers have the paddles as BTN_TRIGGER_HAPPY5 - BTN_TRIGGER_HAPPY8
|
||||
// in older drivers
|
||||
if (joystick->hwdata->has_key[BTN_TRIGGER_HAPPY5] &&
|
||||
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY6] &&
|
||||
joystick->hwdata->has_key[BTN_TRIGGER_HAPPY7] &&
|
||||
@@ -2667,6 +2784,7 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
|
||||
out->right_paddle2.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY6];
|
||||
out->left_paddle2.kind = EMappingKind_Button;
|
||||
out->left_paddle2.target = joystick->hwdata->key_map[BTN_TRIGGER_HAPPY8];
|
||||
mapped = MAPPED_PADDLE_ALL;
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped RIGHT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY5)", out->right_paddle1.target);
|
||||
SDL_Log("Mapped LEFT_PADDLE1 to button %d (BTN_TRIGGER_HAPPY7)", out->left_paddle1.target);
|
||||
@@ -2674,15 +2792,15 @@ static bool LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping
|
||||
SDL_Log("Mapped LEFT_PADDLE2 to button %d (BTN_TRIGGER_HAPPY8)", out->left_paddle2.target);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// The Xbox Series X controllers have the Share button as KEY_RECORD
|
||||
if (joystick->hwdata->has_key[KEY_RECORD]) {
|
||||
out->misc1.kind = EMappingKind_Button;
|
||||
out->misc1.target = joystick->hwdata->key_map[KEY_RECORD];
|
||||
// Xbox Series controllers have the Share button as KEY_RECORD
|
||||
if (joystick->hwdata->has_key[KEY_RECORD]) {
|
||||
out->misc1.kind = EMappingKind_Button;
|
||||
out->misc1.target = joystick->hwdata->key_map[KEY_RECORD];
|
||||
#ifdef DEBUG_GAMEPAD_MAPPING
|
||||
SDL_Log("Mapped MISC1 to button %d (KEY_RECORD)", out->misc1.target);
|
||||
SDL_Log("Mapped MISC1 to button %d (KEY_RECORD)", out->misc1.target);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the mapping for later
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -191,6 +191,66 @@ static SDL_JoystickID PS2_JoystickGetDeviceInstanceID(int device_index)
|
||||
return device_index + 1;
|
||||
}
|
||||
|
||||
static void PS2_WaitPadReady(int port, int slot)
|
||||
{
|
||||
int state = padGetState(port, slot);
|
||||
while ((state != PAD_STATE_STABLE) && (state != PAD_STATE_FINDCTP1)) {
|
||||
SDL_Delay(1);
|
||||
state = padGetState(port, slot);
|
||||
}
|
||||
}
|
||||
|
||||
static void PS2_InitializePad(int port, int slot)
|
||||
{
|
||||
int modes;
|
||||
int i;
|
||||
char actAlign[6];
|
||||
|
||||
PS2_WaitPadReady(port, slot);
|
||||
|
||||
// How many different modes can this device operate in?
|
||||
modes = padInfoMode(port, slot, PAD_MODETABLE, -1);
|
||||
|
||||
// Verify that the controller has a DUAL SHOCK mode
|
||||
for (i = 0; i < modes; i++) {
|
||||
if (padInfoMode(port, slot, PAD_MODETABLE, i) == PAD_TYPE_DUALSHOCK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= modes) {
|
||||
// This is no Dual Shock controller
|
||||
return;
|
||||
}
|
||||
|
||||
// If ExId != 0x0 => This controller has actuator engines
|
||||
// This check should always pass if the Dual Shock test above passed
|
||||
if (!padInfoMode(port, slot, PAD_MODECUREXID, 0)) {
|
||||
// This is no Dual Shock controller??
|
||||
return;
|
||||
}
|
||||
|
||||
// When using MMODE_LOCK, user cant change mode with Select button
|
||||
padSetMainMode(port, slot, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK);
|
||||
|
||||
PS2_WaitPadReady(port, slot);
|
||||
padEnterPressMode(port, slot);
|
||||
|
||||
PS2_WaitPadReady(port, slot);
|
||||
if (padInfoAct(port, slot, -1, 0)) {
|
||||
actAlign[0] = 0; // Enable small engine
|
||||
actAlign[1] = 1; // Enable big engine
|
||||
actAlign[2] = 0xff;
|
||||
actAlign[3] = 0xff;
|
||||
actAlign[4] = 0xff;
|
||||
actAlign[5] = 0xff;
|
||||
|
||||
PS2_WaitPadReady(port, slot);
|
||||
padSetActAlign(port, slot, actAlign);
|
||||
}
|
||||
|
||||
PS2_WaitPadReady(port, slot);
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@@ -208,6 +268,8 @@ static bool PS2_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
PS2_InitializePad(info->port, info->slot);
|
||||
|
||||
joystick->nbuttons = PS2_BUTTONS;
|
||||
joystick->naxes = PS2_TOTAL_AXIS;
|
||||
joystick->nhats = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -32,6 +32,8 @@
|
||||
#define USB_VENDOR_BACKBONE 0x358a
|
||||
#define USB_VENDOR_GAMESIR 0x3537
|
||||
#define USB_VENDOR_DRAGONRISE 0x0079
|
||||
#define USB_VENDOR_FLYDIGI_V1 0x04b4
|
||||
#define USB_VENDOR_FLYDIGI_V2 0x37d7
|
||||
#define USB_VENDOR_GOOGLE 0x18d1
|
||||
#define USB_VENDOR_HORI 0x0f0d
|
||||
#define USB_VENDOR_HP 0x03f0
|
||||
@@ -58,25 +60,36 @@
|
||||
#define USB_VENDOR_SWITCH 0x2563
|
||||
#define USB_VENDOR_VALVE 0x28de
|
||||
#define USB_VENDOR_ZEROPLUS 0x0c12
|
||||
#define USB_VENDOR_RASPBERRYPI 0x2e8a // Commercial hardware from various companies are registered under this VID
|
||||
#define USB_VENDOR_ZUIKI 0x33dd
|
||||
|
||||
#define USB_PRODUCT_8BITDO_XBOX_CONTROLLER1 0x2002 // Ultimate Wired Controller for Xbox
|
||||
#define USB_PRODUCT_8BITDO_XBOX_CONTROLLER2 0x3106 // Ultimate Wireless / Pro 2 Wired Controller
|
||||
#define USB_PRODUCT_8BITDO_SF30_PRO 0x6000 // B + START
|
||||
#define USB_PRODUCT_8BITDO_SF30_PRO_BT 0x6100 // B + START
|
||||
#define USB_PRODUCT_8BITDO_SN30_PRO 0x6001 // B + START
|
||||
#define USB_PRODUCT_8BITDO_SN30_PRO_BT 0x6101 // B + START
|
||||
#define USB_PRODUCT_8BITDO_PRO_2 0x6003 // mode switch to D
|
||||
#define USB_PRODUCT_8BITDO_PRO_2_BT 0x6006 // mode switch to D
|
||||
#define USB_PRODUCT_8BITDO_PRO_3 0x6009 // mode switch to D
|
||||
#define USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS 0x6012 // mode switch to BT
|
||||
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
|
||||
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
|
||||
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103
|
||||
#define USB_PRODUCT_BACKBONE_ONE_IOS_PS5 0x0104
|
||||
#define USB_PRODUCT_GAMESIR_G7 0x1001
|
||||
#define USB_PRODUCT_BDA_XB1_CLASSIC 0x581a
|
||||
#define USB_PRODUCT_BDA_XB1_FIGHTPAD 0x791a
|
||||
#define USB_PRODUCT_BDA_XB1_SPECTRA_PRO 0x592a
|
||||
#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER 0x9400
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER1 0x1843
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2 0x1846
|
||||
#define USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X 0x0150
|
||||
#define USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X 0x014f
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER2 0x1844
|
||||
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER3 0x1846
|
||||
#define USB_PRODUCT_FLYDIGI_V1_GAMEPAD 0x2412
|
||||
#define USB_PRODUCT_FLYDIGI_V2_APEX 0x2501
|
||||
#define USB_PRODUCT_FLYDIGI_V2_VADER 0x2401
|
||||
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4 0x011c
|
||||
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
|
||||
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
|
||||
#define USB_PRODUCT_HORI_STEAM_CONTROLLER 0x01AB
|
||||
#define USB_PRODUCT_HORI_STEAM_CONTROLLER_BT 0x0196
|
||||
#define USB_PRODUCT_HORI_TAIKO_DRUM_CONTROLLER 0x01b2
|
||||
#define USB_PRODUCT_LOGITECH_F310 0xc216
|
||||
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
|
||||
#define USB_PRODUCT_MADCATZ_SAITEK_SIDE_PANEL_CONTROL_DECK 0x2218
|
||||
@@ -94,15 +107,25 @@
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR 0x2008 // Used by joycond
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT 0x2007
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH_PRO 0x2009
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH2_GAMECUBE_CONTROLLER 0x2073
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_LEFT 0x2067
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_PAIR 0x2068
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH2_JOYCON_RIGHT 0x2066
|
||||
#define USB_PRODUCT_NINTENDO_SWITCH2_PRO 0x2069
|
||||
#define USB_PRODUCT_NINTENDO_WII_REMOTE 0x0306
|
||||
#define USB_PRODUCT_NINTENDO_WII_REMOTE2 0x0330
|
||||
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 0x7210
|
||||
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104 0x7214
|
||||
#define USB_PRODUCT_PDP_ROCK_CANDY 0x0246
|
||||
#define USB_PRODUCT_PDP_REALMZ_WIRELESS 0x018c
|
||||
#define USB_PRODUCT_POWERA_MINI 0x541a
|
||||
#define USB_PRODUCT_RAZER_ATROX 0x0a00
|
||||
#define USB_PRODUCT_RAZER_KITSUNE 0x1012
|
||||
#define USB_PRODUCT_RAZER_PANTHERA 0x0401
|
||||
#define USB_PRODUCT_RAZER_PANTHERA_EVO 0x1008
|
||||
#define USB_PRODUCT_RAZER_RAIJU 0x1000
|
||||
#define USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRED 0x1024
|
||||
#define USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRELESS 0x1026
|
||||
#define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_USB 0x1007
|
||||
#define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH 0x100a
|
||||
#define USB_PRODUCT_RAZER_ULTIMATE_EDITION_USB 0x1004
|
||||
@@ -114,7 +137,6 @@
|
||||
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRED 0x1010
|
||||
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRELESS 0x1011
|
||||
#define USB_PRODUCT_RAZER_WOLVERINE_V3_PRO 0x0a3f
|
||||
#define USB_PRODUCT_ROG_RAIKIRI 0x1a38
|
||||
#define USB_PRODUCT_SAITEK_CYBORG_V3 0xf622
|
||||
#define USB_PRODUCT_SHANWAN_DS3 0x0523
|
||||
#define USB_PRODUCT_SONY_DS3 0x0268
|
||||
@@ -124,12 +146,13 @@
|
||||
#define USB_PRODUCT_SONY_DS4_STRIKEPAD 0x05c5
|
||||
#define USB_PRODUCT_SONY_DS5 0x0ce6
|
||||
#define USB_PRODUCT_SONY_DS5_EDGE 0x0df2
|
||||
#define USB_PRODUCT_STEALTH_ULTRA_WIRED 0x7073
|
||||
#define USB_PRODUCT_SWITCH_RETROBIT_CONTROLLER 0x0575
|
||||
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_PS4 0xd00e
|
||||
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO_SERIES_X 0xd012
|
||||
#define USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R 0x7013
|
||||
#define USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON 0x7009
|
||||
#define USB_PRODUCT_THRUSTMASTER_T_FLIGHT_HOTAS_ONE 0xb68c
|
||||
#define USB_PRODUCT_VALVE_STEAM_CONTROLLER_DONGLE 0x1142
|
||||
#define USB_PRODUCT_VALVE_STEAM_PROTEUS_DONGLE 0x1304
|
||||
#define USB_PRODUCT_VALVE_STEAM_NEREID_DONGLE 0x1305
|
||||
#define USB_PRODUCT_VICTRIX_FS_PRO 0x0203
|
||||
#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207
|
||||
#define USB_PRODUCT_XBOX360_XUSB_CONTROLLER 0x02a1 // XUSB driver software PID
|
||||
@@ -150,23 +173,22 @@
|
||||
#define USB_PRODUCT_XBOX_ONE_S_REV2_BLE 0x0b20
|
||||
#define USB_PRODUCT_XBOX_SERIES_X 0x0b12
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_BLE 0x0b13
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_HP_HYPERX 0x08b6
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_HP_HYPERX_RGB 0x07a0
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW 0x02da
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE 0x02d9
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 0x4001
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO4 0x400b
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO_WIRELESS_USB 0x4014
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO_WIRELESS_DONGLE 0x4016
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_MOGA_XP_ULTRA 0x890b
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA 0x4002
|
||||
#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT 0x02d6
|
||||
#define USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER 0x02ff // XBOXGIP driver software PID
|
||||
#define USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD 0x11ff
|
||||
#define USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC 0x10c6
|
||||
#define USB_PRODUCT_HANDHELDLEGEND_PROGCC 0x10df
|
||||
#define USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE 0x10dd
|
||||
#define USB_PRODUCT_BONZIRICHANNEL_FIREBIRD 0x10e0
|
||||
#define USB_PRODUCT_ZUIKI_MASCON_PRO 0x0006
|
||||
#define USB_PRODUCT_VOIDGAMING_PS4FIREBIRD 0x10e5
|
||||
|
||||
// USB usage pages
|
||||
#define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001
|
||||
#define USB_USAGEPAGE_SIMULATION 0x0002
|
||||
#define USB_USAGEPAGE_DEVICE_CONTROLS 0x0006
|
||||
#define USB_USAGEPAGE_BUTTON 0x0009
|
||||
#define USB_USAGEPAGE_CONSUMER 0x000C
|
||||
#define USB_USAGEPAGE_VENDOR_FLYDIGI 0xFFA0
|
||||
|
||||
// USB usages for USAGE_PAGE_GENERIC_DESKTOP
|
||||
#define USB_USAGE_GENERIC_POINTER 0x0001
|
||||
@@ -187,6 +209,22 @@
|
||||
#define USB_USAGE_GENERIC_WHEEL 0x0038
|
||||
#define USB_USAGE_GENERIC_HAT 0x0039
|
||||
|
||||
// USB usages for USB_USAGEPAGE_SIMULATION
|
||||
#define USB_USAGE_SIMULATION_ACCELERATOR 0x00C4
|
||||
#define USB_USAGE_SIMULATION_BRAKE 0x00C5
|
||||
|
||||
// USB usages for USB_USAGEPAGE_DEVICE_CONTROLS
|
||||
#define USB_USAGE_DEVICE_CONTROLS_BATTERY_STRENGTH 0x0020
|
||||
|
||||
// USB usages for USB_USAGEPAGE_CONSUMER
|
||||
#define USB_USAGE_CONSUMER_ASSIGN_SELECTION 0x0081
|
||||
#define USB_USAGE_CONSUMER_ORDER_MOVIE 0x0085
|
||||
#define USB_USAGE_CONSUMER_RECORD 0x00B2
|
||||
#define USB_USAGE_CONSUMER_AC_HOME 0x0223
|
||||
#define USB_USAGE_CONSUMER_AC_BACK 0x0224
|
||||
|
||||
#define MAKE_USAGE(PAGE, USAGE) (((Uint32)PAGE) << 16 | USAGE)
|
||||
|
||||
/* Bluetooth SIG assigned Company Identifiers
|
||||
https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/ */
|
||||
#define BLUETOOTH_VENDOR_AMAZON 0x0171
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -138,11 +138,11 @@ SDL_JoystickID SDL_JoystickAttachVirtualInner(const SDL_VirtualJoystickDesc *des
|
||||
|
||||
SDL_AssertJoysticksLocked();
|
||||
|
||||
if (!desc) {
|
||||
CHECK_PARAM(!desc) {
|
||||
SDL_InvalidParamError("desc");
|
||||
return 0;
|
||||
}
|
||||
if (desc->version < sizeof(*desc)) {
|
||||
CHECK_PARAM(desc->version < sizeof(*desc)) {
|
||||
// Update this to handle older versions of this interface
|
||||
SDL_SetError("Invalid desc, should be initialized with SDL_INIT_INTERFACE()");
|
||||
return 0;
|
||||
@@ -471,7 +471,7 @@ bool SDL_SendJoystickVirtualSensorDataInner(SDL_Joystick *joystick, SDL_SensorTy
|
||||
return false;
|
||||
}
|
||||
hwdata->sensor_events = sensor_events;
|
||||
hwdata->max_sensor_events = hwdata->max_sensor_events;
|
||||
hwdata->max_sensor_events = new_max_sensor_events;
|
||||
}
|
||||
|
||||
VirtualSensorEvent *event = &hwdata->sensor_events[hwdata->num_sensor_events++];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -45,6 +45,7 @@ extern HWND SDL_HelperWindow;
|
||||
// local variables
|
||||
static bool coinitialized = false;
|
||||
static LPDIRECTINPUT8 dinput = NULL;
|
||||
static bool has_broken_EZFRD64DLL = false;
|
||||
|
||||
// Taken from Wine - Thanks!
|
||||
static DIOBJECTDATAFORMAT dfDIJoystick2[] = {
|
||||
@@ -289,7 +290,7 @@ static bool QueryDeviceName(LPDIRECTINPUTDEVICE8 device, Uint16 vendor_id, Uint1
|
||||
}
|
||||
|
||||
*manufacturer_string = NULL;
|
||||
*product_string = WIN_StringToUTF8(dipstr.wsz);
|
||||
*product_string = WIN_StringToUTF8W(dipstr.wsz);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -437,6 +438,29 @@ bool SDL_DINPUT_JoystickInit(void)
|
||||
dinput = NULL;
|
||||
return SetDIerror("IDirectInput::Initialize", result);
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
if (SDL_GetHintBoolean("SDL_JOYSTICK_CHECK_EZFRD64", true)) {
|
||||
// The 64-bit version of EZFRD64.DLL crashes after being loaded,
|
||||
// which happens implicitly when querying the device capabilities,
|
||||
// so make sure we don't do that if there's a possibility of crashing
|
||||
static const char *directories[] = {
|
||||
"C:/Windows/USB_Vibration",
|
||||
"C:/Windows/USB Vibration"
|
||||
};
|
||||
for (int i = 0; i < SDL_arraysize(directories) && !has_broken_EZFRD64DLL; ++i) {
|
||||
int count = 0;
|
||||
char **files = SDL_GlobDirectory(directories[i], "*/EZFRD64.DLL", SDL_GLOB_CASEINSENSITIVE, &count);
|
||||
if (count > 0) {
|
||||
has_broken_EZFRD64DLL = true;
|
||||
}
|
||||
SDL_free(files);
|
||||
}
|
||||
if (has_broken_EZFRD64DLL) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Broken EZFRD64.DLL detected, disabling DirectInput force feedback");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -778,12 +802,14 @@ bool SDL_DINPUT_JoystickOpen(SDL_Joystick *joystick, JoyStick_DeviceData *joysti
|
||||
return SetDIerror("IDirectInputDevice8::SetDataFormat", result);
|
||||
}
|
||||
|
||||
// Get device capabilities
|
||||
result =
|
||||
IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
|
||||
&joystick->hwdata->Capabilities);
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
|
||||
if (!has_broken_EZFRD64DLL) {
|
||||
// Get device capabilities to see if we are force feedback capable
|
||||
result =
|
||||
IDirectInputDevice8_GetCapabilities(joystick->hwdata->InputDevice,
|
||||
&joystick->hwdata->Capabilities);
|
||||
if (FAILED(result)) {
|
||||
return SetDIerror("IDirectInputDevice8::GetCapabilities", result);
|
||||
}
|
||||
}
|
||||
|
||||
// Force capable?
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 2026 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
|
||||
@@ -923,12 +923,8 @@ static void RAWINPUT_AddDevice(HANDLE hDevice)
|
||||
device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
|
||||
device->guid = SDL_CreateJoystickGUID(SDL_HARDWARE_BUS_USB, device->vendor_id, device->product_id, device->version, manufacturer_string, product_string, 'r', 0);
|
||||
|
||||
if (manufacturer_string) {
|
||||
SDL_free(manufacturer_string);
|
||||
}
|
||||
if (product_string) {
|
||||
SDL_free(product_string);
|
||||
}
|
||||
SDL_free(manufacturer_string);
|
||||
SDL_free(product_string);
|
||||
}
|
||||
|
||||
device->path = SDL_strdup(dev_name);
|
||||
@@ -963,12 +959,8 @@ err:
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
if (device) {
|
||||
if (device->name) {
|
||||
SDL_free(device->name);
|
||||
}
|
||||
if (device->path) {
|
||||
SDL_free(device->path);
|
||||
}
|
||||
SDL_free(device->name);
|
||||
SDL_free(device->path);
|
||||
SDL_free(device);
|
||||
}
|
||||
#undef CHECK
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -25,8 +25,8 @@
|
||||
extern bool RAWINPUT_IsEnabled(void);
|
||||
|
||||
// Registers for input events
|
||||
extern int RAWINPUT_RegisterNotifications(HWND hWnd);
|
||||
extern int RAWINPUT_UnregisterNotifications(void);
|
||||
extern bool RAWINPUT_RegisterNotifications(HWND hWnd);
|
||||
extern bool RAWINPUT_UnregisterNotifications(void);
|
||||
|
||||
// Returns 0 if message was handled
|
||||
extern LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -69,6 +69,7 @@ typedef PCWSTR(WINAPI *WindowsGetStringRawBuffer_t)(HSTRING string, UINT32 *leng
|
||||
|
||||
static struct
|
||||
{
|
||||
bool ro_initialized;
|
||||
CoIncrementMTAUsage_t CoIncrementMTAUsage;
|
||||
RoGetActivationFactory_t RoGetActivationFactory;
|
||||
WindowsCreateStringReference_t WindowsCreateStringReference;
|
||||
@@ -585,13 +586,14 @@ static bool WGI_JoystickInit(void)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, true)) {
|
||||
if (!SDL_GetHintBoolean(SDL_HINT_JOYSTICK_WGI, false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FAILED(WIN_RoInitialize())) {
|
||||
return SDL_SetError("RoInitialize() failed");
|
||||
}
|
||||
wgi.ro_initialized = true;
|
||||
|
||||
#define RESOLVE(x) wgi.x = (x##_t)WIN_LoadComBaseFunction(#x); if (!wgi.x) return WIN_SetError("GetProcAddress failed for " #x);
|
||||
RESOLVE(CoIncrementMTAUsage);
|
||||
@@ -971,9 +973,7 @@ static void WGI_JoystickQuit(void)
|
||||
while (wgi.controller_count > 0) {
|
||||
IEventHandler_CRawGameControllerVtbl_InvokeRemoved(&controller_removed.iface, NULL, wgi.controllers[wgi.controller_count - 1].controller);
|
||||
}
|
||||
if (wgi.controllers) {
|
||||
SDL_free(wgi.controllers);
|
||||
}
|
||||
SDL_free(wgi.controllers);
|
||||
|
||||
if (wgi.arcade_stick_statics) {
|
||||
__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_Release(wgi.arcade_stick_statics);
|
||||
@@ -1002,7 +1002,9 @@ static void WGI_JoystickQuit(void)
|
||||
__x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_Release(wgi.controller_statics);
|
||||
}
|
||||
|
||||
WIN_RoUninitialize();
|
||||
if (wgi.ro_initialized) {
|
||||
WIN_RoUninitialize();
|
||||
}
|
||||
|
||||
SDL_zero(wgi);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -416,11 +416,15 @@ void WINDOWS_JoystickDetect(void)
|
||||
while (pCurList) {
|
||||
JoyStick_DeviceData *pListNext = NULL;
|
||||
|
||||
if (!pCurList->bXInputDevice) {
|
||||
#ifdef SDL_HAPTIC_DINPUT
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (!pCurList->bXInputDevice) {
|
||||
SDL_DINPUT_HapticMaybeRemoveDevice(&pCurList->dxdevice);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
SDL_DINPUT_HapticMaybeRemoveDevice(&pCurList->dxdevice);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SDL_PrivateJoystickRemoved(pCurList->nInstanceID);
|
||||
|
||||
@@ -432,11 +436,15 @@ void WINDOWS_JoystickDetect(void)
|
||||
|
||||
for (pCurList = SYS_Joystick; pCurList; pCurList = pCurList->pNext) {
|
||||
if (pCurList->send_add_event) {
|
||||
if (!pCurList->bXInputDevice) {
|
||||
#ifdef SDL_HAPTIC_DINPUT
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (!pCurList->bXInputDevice) {
|
||||
SDL_DINPUT_HapticMaybeAddDevice(&pCurList->dxdevice);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
SDL_DINPUT_HapticMaybeAddDevice(&pCurList->dxdevice);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SDL_PrivateJoystickAdded(pCurList->nInstanceID);
|
||||
|
||||
@@ -489,16 +497,18 @@ static int WINDOWS_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index)
|
||||
device = device->pNext;
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (device->bXInputDevice) {
|
||||
// The slot for XInput devices can change as controllers are seated
|
||||
return SDL_XINPUT_GetSteamVirtualGamepadSlot(device->XInputUserId);
|
||||
} else {
|
||||
return device->steam_virtual_gamepad_slot;
|
||||
}
|
||||
#endif
|
||||
return device->steam_virtual_gamepad_slot;
|
||||
}
|
||||
|
||||
static int WINDOWS_JoystickGetDevicePlayerIndex(int device_index)
|
||||
{
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
JoyStick_DeviceData *device = SYS_Joystick;
|
||||
int index;
|
||||
|
||||
@@ -507,6 +517,9 @@ static int WINDOWS_JoystickGetDevicePlayerIndex(int device_index)
|
||||
}
|
||||
|
||||
return device->bXInputDevice ? (int)device->XInputUserId : -1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void WINDOWS_JoystickSetDevicePlayerIndex(int device_index, int player_index)
|
||||
@@ -560,20 +573,22 @@ static bool WINDOWS_JoystickOpen(SDL_Joystick *joystick, int device_index)
|
||||
}
|
||||
joystick->hwdata->guid = device->guid;
|
||||
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (device->bXInputDevice) {
|
||||
return SDL_XINPUT_JoystickOpen(joystick, device);
|
||||
} else {
|
||||
return SDL_DINPUT_JoystickOpen(joystick, device);
|
||||
}
|
||||
#endif
|
||||
return SDL_DINPUT_JoystickOpen(joystick, device);
|
||||
}
|
||||
|
||||
static bool WINDOWS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
|
||||
{
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
|
||||
} else {
|
||||
return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
|
||||
}
|
||||
#endif
|
||||
return SDL_DINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble);
|
||||
}
|
||||
|
||||
static bool WINDOWS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
|
||||
@@ -602,21 +617,27 @@ static void WINDOWS_JoystickUpdate(SDL_Joystick *joystick)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
SDL_XINPUT_JoystickUpdate(joystick);
|
||||
} else {
|
||||
SDL_DINPUT_JoystickUpdate(joystick);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SDL_DINPUT_JoystickUpdate(joystick);
|
||||
}
|
||||
|
||||
// Function to close a joystick after use
|
||||
static void WINDOWS_JoystickClose(SDL_Joystick *joystick)
|
||||
{
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
if (joystick->hwdata->bXInputDevice) {
|
||||
SDL_XINPUT_JoystickClose(joystick);
|
||||
} else {
|
||||
SDL_DINPUT_JoystickClose(joystick);
|
||||
}
|
||||
#else
|
||||
SDL_DINPUT_JoystickClose(joystick);
|
||||
#endif
|
||||
|
||||
SDL_free(joystick->hwdata);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
@@ -37,9 +37,11 @@ typedef struct JoyStick_DeviceData
|
||||
char *joystickname;
|
||||
Uint8 send_add_event;
|
||||
SDL_JoystickID nInstanceID;
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
bool bXInputDevice;
|
||||
BYTE SubType;
|
||||
Uint8 XInputUserId;
|
||||
#endif
|
||||
DIDEVICEINSTANCE dxdevice;
|
||||
char path[MAX_PATH];
|
||||
int steam_virtual_gamepad_slot;
|
||||
@@ -85,10 +87,12 @@ struct joystick_hwdata
|
||||
LPDIRECTINPUTEFFECT ffeffect_ref;
|
||||
#endif
|
||||
|
||||
#ifdef SDL_JOYSTICK_XINPUT
|
||||
bool bXInputDevice; // true if this device supports using the xinput API rather than DirectInput
|
||||
bool bXInputHaptic; // Supports force feedback via XInput.
|
||||
Uint8 userid; // XInput userid index for this joystick
|
||||
DWORD dwPacketNumber;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef SDL_JOYSTICK_DINPUT
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
Copyright (C) 1997-2026 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
|
||||
|
||||
Reference in New Issue
Block a user