SDL  2.0
SDL_hidapi_xbox360w.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #include "SDL_hidapi_rumble.h"
34 
35 
36 #ifdef SDL_JOYSTICK_HIDAPI_XBOX360
37 
38 
39 typedef struct {
40  SDL_bool connected;
41  Uint8 last_state[USB_PACKET_LENGTH];
42 } SDL_DriverXbox360W_Context;
43 
44 
45 static SDL_bool
46 HIDAPI_DriverXbox360W_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
47 {
48  const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
49 
50  if ((vendor_id == USB_VENDOR_MICROSOFT && (product_id == 0x0291 || product_id == 0x02a9 || product_id == 0x0719)) ||
51  (type == SDL_CONTROLLER_TYPE_XBOX360 && interface_protocol == XB360W_IFACE_PROTOCOL)) {
52  return SDL_TRUE;
53  }
54  return SDL_FALSE;
55 }
56 
57 static const char *
58 HIDAPI_DriverXbox360W_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
59 {
60  return "Xbox 360 Wireless Controller";
61 }
62 
63 static SDL_bool SetSlotLED(hid_device *dev, Uint8 slot)
64 {
65  Uint8 mode = 0x02 + slot;
66  const Uint8 led_packet[] = { 0x00, 0x00, 0x08, (0x40 + (mode % 0x0e)), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
67 
68  if (hid_write(dev, led_packet, sizeof(led_packet)) != sizeof(led_packet)) {
69  return SDL_FALSE;
70  }
71  return SDL_TRUE;
72 }
73 
74 static void
75 UpdatePowerLevel(SDL_Joystick *joystick, Uint8 level)
76 {
77  float normalized_level = (float)level / 255.0f;
78 
79  if (normalized_level <= 0.05f) {
80  joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
81  } else if (normalized_level <= 0.20f) {
82  joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
83  } else if (normalized_level <= 0.70f) {
84  joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
85  } else {
86  joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
87  }
88 }
89 
90 static SDL_bool
91 HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
92 {
93  SDL_DriverXbox360W_Context *ctx;
94 
95  /* Requests controller presence information from the wireless dongle */
96  const Uint8 init_packet[] = { 0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
97 
98  ctx = (SDL_DriverXbox360W_Context *)SDL_calloc(1, sizeof(*ctx));
99  if (!ctx) {
100  SDL_OutOfMemory();
101  return SDL_FALSE;
102  }
103 
104  device->dev = hid_open_path(device->path, 0);
105  if (!device->dev) {
106  SDL_free(ctx);
107  SDL_SetError("Couldn't open %s", device->path);
108  return SDL_FALSE;
109  }
110  device->context = ctx;
111 
112  if (hid_write(device->dev, init_packet, sizeof(init_packet)) != sizeof(init_packet)) {
113  SDL_SetError("Couldn't write init packet");
114  return SDL_FALSE;
115  }
116 
117  return SDL_TRUE;
118 }
119 
120 static int
121 HIDAPI_DriverXbox360W_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
122 {
123  return -1;
124 }
125 
126 static void
127 HIDAPI_DriverXbox360W_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
128 {
129  SetSlotLED(device->dev, (player_index % 4));
130 }
131 
132 static SDL_bool
133 HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
134 {
135  SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
136 
137  SDL_zeroa(ctx->last_state);
138 
139  /* Initialize the joystick capabilities */
140  joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
141  joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
142  joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
143 
144  return SDL_TRUE;
145 }
146 
147 static int
148 HIDAPI_DriverXbox360W_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
149 {
150  Uint8 rumble_packet[] = { 0x00, 0x01, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
151 
152  rumble_packet[5] = (low_frequency_rumble >> 8);
153  rumble_packet[6] = (high_frequency_rumble >> 8);
154 
155  if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
156  return SDL_SetError("Couldn't send rumble packet");
157  }
158  return 0;
159 }
160 
161 static void
162 HIDAPI_DriverXbox360W_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverXbox360W_Context *ctx, Uint8 *data, int size)
163 {
164  Sint16 axis;
165  const SDL_bool invert_y_axes = SDL_TRUE;
166 
167  if (ctx->last_state[2] != data[2]) {
176  }
177 
178  if (ctx->last_state[3] != data[3]) {
186  }
187 
188  axis = ((int)data[4] * 257) - 32768;
190  axis = ((int)data[5] * 257) - 32768;
192  axis = *(Sint16*)(&data[6]);
194  axis = *(Sint16*)(&data[8]);
195  if (invert_y_axes) {
196  axis = ~axis;
197  }
199  axis = *(Sint16*)(&data[10]);
201  axis = *(Sint16*)(&data[12]);
202  if (invert_y_axes) {
203  axis = ~axis;
204  }
206 
207  SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
208 }
209 
210 static SDL_bool
211 HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
212 {
213  SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context;
214  SDL_Joystick *joystick = NULL;
216  int size;
217 
218  if (device->num_joysticks > 0) {
219  joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
220  }
221 
222  while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
223  if (size == 2 && data[0] == 0x08) {
224  SDL_bool connected = (data[1] & 0x80) ? SDL_TRUE : SDL_FALSE;
225 #ifdef DEBUG_JOYSTICK
226  SDL_Log("Connected = %s\n", connected ? "TRUE" : "FALSE");
227 #endif
228  if (connected != ctx->connected) {
229  ctx->connected = connected;
230 
231  if (connected) {
232  SDL_JoystickID joystickID;
233 
234  HIDAPI_JoystickConnected(device, &joystickID);
235 
236  } else if (device->num_joysticks > 0) {
237  HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
238  }
239  }
240  } else if (size == 29 && data[0] == 0x00 && data[1] == 0x0f && data[2] == 0x00 && data[3] == 0xf0) {
241  /* Serial number is data[7-13] */
242 #ifdef DEBUG_JOYSTICK
243  SDL_Log("Battery status (initial): %d\n", data[17]);
244 #endif
245  if (joystick) {
246  UpdatePowerLevel(joystick, data[17]);
247  }
248  } else if (size == 29 && data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x13) {
249 #ifdef DEBUG_JOYSTICK
250  SDL_Log("Battery status: %d\n", data[4]);
251 #endif
252  if (joystick) {
253  UpdatePowerLevel(joystick, data[4]);
254  }
255  } else if (size == 29 && data[0] == 0x00 && (data[1] & 0x01) == 0x01) {
256  if (joystick) {
257  HIDAPI_DriverXbox360W_HandleStatePacket(joystick, device->dev, ctx, data+4, size-4);
258  }
259  }
260  }
261 
262  if (joystick) {
263  if (size < 0) {
264  /* Read error, device is disconnected */
265  HIDAPI_JoystickDisconnected(device, joystick->instance_id);
266  }
267  }
268  return (size >= 0);
269 }
270 
271 static void
272 HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
273 {
274 }
275 
276 static void
277 HIDAPI_DriverXbox360W_FreeDevice(SDL_HIDAPI_Device *device)
278 {
279  hid_close(device->dev);
280  device->dev = NULL;
281 
282  SDL_free(device->context);
283  device->context = NULL;
284 }
285 
287 {
289  SDL_TRUE,
290  HIDAPI_DriverXbox360W_IsSupportedDevice,
291  HIDAPI_DriverXbox360W_GetDeviceName,
292  HIDAPI_DriverXbox360W_InitDevice,
293  HIDAPI_DriverXbox360W_GetDevicePlayerIndex,
294  HIDAPI_DriverXbox360W_SetDevicePlayerIndex,
295  HIDAPI_DriverXbox360W_UpdateDevice,
296  HIDAPI_DriverXbox360W_OpenJoystick,
297  HIDAPI_DriverXbox360W_RumbleJoystick,
298  HIDAPI_DriverXbox360W_CloseJoystick,
299  HIDAPI_DriverXbox360W_FreeDevice
300 };
301 
302 #endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
303 
304 #endif /* SDL_JOYSTICK_HIDAPI */
305 
306 /* vi: set ts=4 sw=4 expandtab: */
SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
Definition: SDL_gamecontroller.h:362
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_CONTROLLER_AXIS_RIGHTX
@ SDL_CONTROLLER_AXIS_RIGHTX
Definition: SDL_gamecontroller.h:307
SDL_events.h
Uint16
uint16_t Uint16
Definition: SDL_stdinc.h:191
if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
Definition: pixman-arm-neon-asm.h:469
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.
NULL
#define NULL
Definition: begin_code.h:167
SDL_timer.h
HIDAPI_JoystickConnected
SDL_bool HIDAPI_JoystickConnected(SDL_HIDAPI_Device *device, SDL_JoystickID *pJoystickID)
SDL_joystick.h
SDL_JoystickID
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
mode
GLenum mode
Definition: SDL_opengl_glext.h:1125
hid_close
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
Close a HID device.
level
GLint level
Definition: SDL_opengl.h:1572
SDL_log.h
USB_VENDOR_MICROSOFT
#define USB_VENDOR_MICROSOFT
Definition: usb_ids.h:28
SDL_hidapi_rumble.h
SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
Definition: SDL_gamecontroller.h:357
SDL_JOYSTICK_POWER_LOW
@ SDL_JOYSTICK_POWER_LOW
Definition: SDL_joystick.h:101
SDL_CONTROLLER_AXIS_LEFTX
@ SDL_CONTROLLER_AXIS_LEFTX
Definition: SDL_gamecontroller.h:305
SDL_HIDAPI_Device
Definition: SDL_hidapijoystick_c.h:64
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
SDL_JOYSTICK_POWER_EMPTY
@ SDL_JOYSTICK_POWER_EMPTY
Definition: SDL_joystick.h:100
SDL_zeroa
#define SDL_zeroa(x)
Definition: SDL_stdinc.h:420
ctx
EGLContext ctx
Definition: eglext.h:208
SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_B
Definition: SDL_gamecontroller.h:350
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:364
SDL_PrivateJoystickAxis
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
Definition: SDL_joystick.c:1023
SDL_hidapijoystick_c.h
SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_BACK
Definition: SDL_gamecontroller.h:353
SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
Definition: SDL_gamecontroller.h:358
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_JOYSTICK_POWER_MEDIUM
@ SDL_JOYSTICK_POWER_MEDIUM
Definition: SDL_joystick.h:102
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:639
SDL_JOYSTICK_POWER_UNKNOWN
@ SDL_JOYSTICK_POWER_UNKNOWN
Definition: SDL_joystick.h:99
SDL_CONTROLLER_AXIS_TRIGGERLEFT
@ SDL_CONTROLLER_AXIS_TRIGGERLEFT
Definition: SDL_gamecontroller.h:309
SDL_Log
#define SDL_Log
Definition: SDL_dynapi_overrides.h:31
SDL_JoystickFromInstanceID
#define SDL_JoystickFromInstanceID
Definition: SDL_dynapi_overrides.h:595
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
f
GLfloat f
Definition: SDL_opengl_glext.h:1873
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.
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:663
SDL_HIDAPI_DeviceDriver
Definition: SDL_hidapijoystick_c.h:93
SDL_PrivateJoystickButton
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
Definition: SDL_joystick.c:1162
SDL_CONTROLLER_AXIS_MAX
@ SDL_CONTROLLER_AXIS_MAX
Definition: SDL_gamecontroller.h:311
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:355
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
hid_open_path
HID_API_EXPORT hid_device *HID_API_CALL hid_open_path(const char *path, int bExclusive)
Open a HID device by its path name.
axis
SDL_Texture * axis
Definition: testgamecontroller.c:67
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:540
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
Definition: SDL_gamecontroller.h:359
SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_Y
Definition: SDL_gamecontroller.h:352
HIDAPI_JoystickDisconnected
void HIDAPI_JoystickDisconnected(SDL_HIDAPI_Device *device, SDL_JoystickID joystickID)
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_GameControllerType
SDL_GameControllerType
Definition: SDL_gamecontroller.h:61
USB_PACKET_LENGTH
#define USB_PACKET_LENGTH
Definition: SDL_hidapijoystick_c.h:58
SDL_hints.h
SDL_JOYSTICK_POWER_FULL
@ SDL_JOYSTICK_POWER_FULL
Definition: SDL_joystick.h:103
SDL_CONTROLLER_AXIS_LEFTY
@ SDL_CONTROLLER_AXIS_LEFTY
Definition: SDL_gamecontroller.h:306
SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
Definition: SDL_gamecontroller.h:356
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:162
SDL_CONTROLLER_TYPE_XBOX360
@ SDL_CONTROLLER_TYPE_XBOX360
Definition: SDL_gamecontroller.h:63
SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
Definition: SDL_gamecontroller.h:361
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_DPAD_UP
Definition: SDL_gamecontroller.h:360
SDL_CONTROLLER_AXIS_TRIGGERRIGHT
@ SDL_CONTROLLER_AXIS_TRIGGERRIGHT
Definition: SDL_gamecontroller.h:310
hid_device
struct hid_device_ hid_device
Definition: hidapi.h:54
SDL_CONTROLLER_AXIS_RIGHTY
@ SDL_CONTROLLER_AXIS_RIGHTY
Definition: SDL_gamecontroller.h:308
SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_X
Definition: SDL_gamecontroller.h:351
device
static SDL_AudioDeviceID device
Definition: loopwave.c:37
SDL_CONTROLLER_BUTTON_A
@ SDL_CONTROLLER_BUTTON_A
Definition: SDL_gamecontroller.h:349
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
Definition: SDL_gamecontroller.h:363
SDL_CONTROLLER_BUTTON_GUIDE
@ SDL_CONTROLLER_BUTTON_GUIDE
Definition: SDL_gamecontroller.h:354
SDL_HIDAPI_DriverXbox360W
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W