SDL  2.0
SDL_hidapi_xboxone.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #ifdef SDL_JOYSTICK_HIDAPI
24 
25 #include "SDL_hints.h"
26 #include "SDL_log.h"
27 #include "SDL_events.h"
28 #include "SDL_timer.h"
29 #include "SDL_joystick.h"
30 #include "SDL_gamecontroller.h"
31 #include "../SDL_sysjoystick.h"
32 #include "SDL_hidapijoystick_c.h"
33 
34 
35 #ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
36 
37 #define USB_PACKET_LENGTH 64
38 
39 /*
40  * This packet is required for all Xbox One pads with 2015
41  * or later firmware installed (or present from the factory).
42  */
43 static const Uint8 xboxone_fw2015_init[] = {
44  0x05, 0x20, 0x00, 0x01, 0x00
45 };
46 
47 /*
48  * This packet is required for the Titanfall 2 Xbox One pads
49  * (0x0e6f:0x0165) to finish initialization and for Hori pads
50  * (0x0f0d:0x0067) to make the analog sticks work.
51  */
52 static const Uint8 xboxone_hori_init[] = {
53  0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
54  0x00, 0x00, 0x00, 0x80, 0x00
55 };
56 
57 /*
58  * This packet is required for some of the PDP pads to start
59  * sending input reports. These pads include: (0x0e6f:0x02ab),
60  * (0x0e6f:0x02a4).
61  */
62 static const Uint8 xboxone_pdp_init1[] = {
63  0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14
64 };
65 
66 /*
67  * This packet is required for some of the PDP pads to start
68  * sending input reports. These pads include: (0x0e6f:0x02ab),
69  * (0x0e6f:0x02a4).
70  */
71 static const Uint8 xboxone_pdp_init2[] = {
72  0x06, 0x20, 0x00, 0x02, 0x01, 0x00
73 };
74 
75 /*
76  * A specific rumble packet is required for some PowerA pads to start
77  * sending input reports. One of those pads is (0x24c6:0x543a).
78  */
79 static const Uint8 xboxone_rumblebegin_init[] = {
80  0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
81  0x1D, 0x1D, 0xFF, 0x00, 0x00
82 };
83 
84 /*
85  * A rumble packet with zero FF intensity will immediately
86  * terminate the rumbling required to init PowerA pads.
87  * This should happen fast enough that the motors don't
88  * spin up to enough speed to actually vibrate the gamepad.
89  */
90 static const Uint8 xboxone_rumbleend_init[] = {
91  0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00,
92  0x00, 0x00, 0x00, 0x00, 0x00
93 };
94 
95 /*
96  * This specifies the selection of init packets that a gamepad
97  * will be sent on init *and* the order in which they will be
98  * sent. The correct sequence number will be added when the
99  * packet is going to be sent.
100  */
101 typedef struct {
102  Uint16 vendor_id;
103  Uint16 product_id;
104  const Uint8 *data;
105  int size;
106 } SDL_DriverXboxOne_InitPacket;
107 
108 static const SDL_DriverXboxOne_InitPacket xboxone_init_packets[] = {
109  { 0x0e6f, 0x0165, xboxone_hori_init, sizeof(xboxone_hori_init) },
110  { 0x0f0d, 0x0067, xboxone_hori_init, sizeof(xboxone_hori_init) },
111  { 0x0000, 0x0000, xboxone_fw2015_init, sizeof(xboxone_fw2015_init) },
112  { 0x0e6f, 0x0246, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
113  { 0x0e6f, 0x0246, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
114  { 0x0e6f, 0x02ab, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
115  { 0x0e6f, 0x02ab, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
116  { 0x0e6f, 0x02a4, xboxone_pdp_init1, sizeof(xboxone_pdp_init1) },
117  { 0x0e6f, 0x02a4, xboxone_pdp_init2, sizeof(xboxone_pdp_init2) },
118  { 0x24c6, 0x541a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
119  { 0x24c6, 0x542a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
120  { 0x24c6, 0x543a, xboxone_rumblebegin_init, sizeof(xboxone_rumblebegin_init) },
121  { 0x24c6, 0x541a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
122  { 0x24c6, 0x542a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
123  { 0x24c6, 0x543a, xboxone_rumbleend_init, sizeof(xboxone_rumbleend_init) },
124 };
125 
126 typedef struct {
127  Uint8 sequence;
128  Uint8 last_state[USB_PACKET_LENGTH];
129  Uint32 rumble_expiration;
130 } SDL_DriverXboxOne_Context;
131 
132 
133 static SDL_bool
134 HIDAPI_DriverXboxOne_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
135 {
136  return SDL_IsJoystickXboxOne(vendor_id, product_id);
137 }
138 
139 static const char *
140 HIDAPI_DriverXboxOne_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
141 {
142  return HIDAPI_XboxControllerName(vendor_id, product_id);
143 }
144 
145 static SDL_bool
146 HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
147 {
148  SDL_DriverXboxOne_Context *ctx;
149  int i;
150  Uint8 init_packet[USB_PACKET_LENGTH];
151 
152  ctx = (SDL_DriverXboxOne_Context *)SDL_calloc(1, sizeof(*ctx));
153  if (!ctx) {
154  SDL_OutOfMemory();
155  return SDL_FALSE;
156  }
157  *context = ctx;
158 
159  /* Send the controller init data */
160  for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
161  const SDL_DriverXboxOne_InitPacket *packet = &xboxone_init_packets[i];
162  if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
163  SDL_memcpy(init_packet, packet->data, packet->size);
164  init_packet[2] = ctx->sequence++;
165  if (hid_write(dev, init_packet, packet->size) != packet->size) {
166  SDL_SetError("Couldn't write Xbox One initialization packet");
167  SDL_free(ctx);
168  return SDL_FALSE;
169  }
170  }
171  }
172 
173  /* Initialize the joystick capabilities */
174  joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
175  joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
176  joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
177 
178  return SDL_TRUE;
179 }
180 
181 static int
182 HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
183 {
184  SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
185  Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
186 
187  /* The Rock Candy Xbox One Controller limits the range of
188  low frequency rumble strength in the range of [0 - 0x99]
189  high frequency rumble strength in the range of [0 - 0x82]
190 
191  I think the valid range of rumble at the firmware level is [0 - 0x7F]
192  */
193  rumble_packet[2] = ctx->sequence++;
194  rumble_packet[8] = (low_frequency_rumble >> 9);
195  rumble_packet[9] = (high_frequency_rumble >> 9);
196 
197  if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
198  return SDL_SetError("Couldn't send rumble packet");
199  }
200 
201  if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
202  ctx->rumble_expiration = SDL_GetTicks() + duration_ms;
203  } else {
204  ctx->rumble_expiration = 0;
205  }
206  return 0;
207 }
208 
209 static void
210 HIDAPI_DriverXboxOne_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
211 {
212  Sint16 axis;
213 
214  if (ctx->last_state[4] != data[4]) {
221  }
222 
223  if (ctx->last_state[5] != data[5]) {
232  }
233 
234  axis = ((int)*(Sint16*)(&data[6]) * 64) - 32768;
235  if (axis == 32704) {
236  axis = 32767;
237  }
239  axis = ((int)*(Sint16*)(&data[8]) * 64) - 32768;
240  if (axis == 32704) {
241  axis = 32767;
242  }
244  axis = *(Sint16*)(&data[10]);
246  axis = *(Sint16*)(&data[12]);
248  axis = *(Sint16*)(&data[14]);
250  axis = *(Sint16*)(&data[16]);
252 
253  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
254 }
255 
256 static void
257 HIDAPI_DriverXboxOne_HandleModePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXboxOne_Context *ctx, Uint8 *data, int size)
258 {
259  if (data[1] == 0x30) {
260  /* The Xbox One S controller needs acks for mode reports */
261  const Uint8 seqnum = data[2];
262  const Uint8 ack[] = { 0x01, 0x20, seqnum, 0x09, 0x00, 0x07, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 };
263  hid_write(dev, ack, sizeof(ack));
264  }
265 
267 }
268 
269 static SDL_bool
270 HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
271 {
272  SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
273  Uint8 data[USB_PACKET_LENGTH];
274  int size;
275 
276  while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
277  switch (data[0]) {
278  case 0x20:
279  HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
280  break;
281  case 0x07:
282  HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
283  break;
284  default:
285 #ifdef DEBUG_JOYSTICK
286  SDL_Log("Unknown Xbox One packet: 0x%.2x\n", data[0]);
287 #endif
288  break;
289  }
290  }
291 
292  if (ctx->rumble_expiration) {
293  Uint32 now = SDL_GetTicks();
294  if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
295  HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
296  }
297  }
298 
299  return (size >= 0);
300 }
301 
302 static void
303 HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
304 {
305  SDL_free(context);
306 }
307 
308 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
309 {
311  SDL_TRUE,
312  HIDAPI_DriverXboxOne_IsSupportedDevice,
313  HIDAPI_DriverXboxOne_GetDeviceName,
314  HIDAPI_DriverXboxOne_Init,
315  HIDAPI_DriverXboxOne_Rumble,
316  HIDAPI_DriverXboxOne_Update,
317  HIDAPI_DriverXboxOne_Quit
318 };
319 
320 #endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
321 
322 #endif /* SDL_JOYSTICK_HIDAPI */
323 
324 /* vi: set ts=4 sw=4 expandtab: */
SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
Definition: SDL_gamecontroller.h:332
SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_RIGHTX
Definition: SDL_gamecontroller.h:277
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:203
SDL_events.h
hid_write
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
Write an Output report to a HID device.
SDL_timer.h
SDL_joystick.h
SDL_log.h
SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
Definition: SDL_gamecontroller.h:327
SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_LEFTX
Definition: SDL_gamecontroller.h:275
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
SDL_IsJoystickXboxOne
SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor, Uint16 product)
Definition: SDL_joystick.c:1196
ctx
EGLContext ctx
Definition: eglext.h:208
SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_B
Definition: SDL_gamecontroller.h:320
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_CONTROLLER_BUTTON_MAX
@ SDL_CONTROLLER_BUTTON_MAX
Definition: SDL_gamecontroller.h:334
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:833
SDL_hidapijoystick_c.h
SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_BACK
Definition: SDL_gamecontroller.h:323
SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
Definition: SDL_gamecontroller.h:328
SDL_PRESSED
#define SDL_PRESSED
Definition: SDL_events.h:50
Sint16
int16_t Sint16
Definition: SDL_stdinc.h:185
SDL_memcpy
#define SDL_memcpy
Definition: SDL_dynapi_overrides.h:387
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
context
static screen_context_t context
Definition: video.c:25
SDL_HINT_JOYSTICK_HIDAPI_XBOX
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX
A variable controlling whether the HIDAPI driver for XBox controllers should be used.
Definition: SDL_hints.h:566
HIDAPI_XboxControllerName
const char * HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
Definition: SDL_gamecontroller.h:279
SDL_Log
#define SDL_Log
Definition: SDL_dynapi_overrides.h:31
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
hid_read_timeout
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
SDL_JOYSTICK_POWER_WIRED
@ SDL_JOYSTICK_POWER_WIRED
Definition: SDL_joystick.h:104
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:966
SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_MAX
Definition: SDL_gamecontroller.h:281
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
SDL_GetTicks
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
SDL_min
#define SDL_min(x, y)
Definition: SDL_stdinc.h:406
SDL_gamecontroller.h
SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_START
Definition: SDL_gamecontroller.h:325
axis
SDL_Texture * axis
Definition: testgamecontroller.c:67
SDL_HIDAPI_DriverXboxOne
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:537
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
Definition: SDL_gamecontroller.h:329
SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_Y
Definition: SDL_gamecontroller.h:322
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_hints.h
SDL_CONTROLLER_AXIS_LEFTY
@ SDL_CONTROLLER_AXIS_LEFTY
Definition: SDL_gamecontroller.h:276
SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
Definition: SDL_gamecontroller.h:326
SDL_TICKS_PASSED
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
Definition: SDL_gamecontroller.h:331
SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_DPAD_UP
Definition: SDL_gamecontroller.h:330
SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
Definition: SDL_gamecontroller.h:280
hid_device
struct hid_device_ hid_device
Definition: hidapi.h:50
SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTY
Definition: SDL_gamecontroller.h:278
SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_X
Definition: SDL_gamecontroller.h:321
SDL_CONTROLLER_BUTTON_A
@ SDL_CONTROLLER_BUTTON_A
Definition: SDL_gamecontroller.h:319
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
Definition: SDL_gamecontroller.h:333
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161
SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_GUIDE
Definition: SDL_gamecontroller.h:324
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179