SDL  2.0
SDL_rawinputjoystick.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 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 */
22 /*
23  RAWINPUT Joystick API for better handling XInput-capable devices on Windows.
24 
25  XInput is limited to 4 devices.
26  Windows.Gaming.Input does not get inputs from XBox One controllers when not in the foreground.
27  DirectInput does not get inputs from XBox One controllers when not in the foreground, nor rumble or accurate triggers.
28  RawInput does not get rumble or accurate triggers.
29 
30  So, combine them as best we can!
31 */
32 #include "../../SDL_internal.h"
33 
34 #if SDL_JOYSTICK_RAWINPUT
35 
36 #include "SDL_endian.h"
37 #include "SDL_events.h"
38 #include "SDL_hints.h"
39 #include "SDL_mutex.h"
40 #include "SDL_timer.h"
41 #include "../usb_ids.h"
42 #include "../SDL_sysjoystick.h"
43 #include "../../core/windows/SDL_windows.h"
44 #include "../../core/windows/SDL_hid.h"
45 #include "../hidapi/SDL_hidapijoystick_c.h"
46 
47 #define SDL_JOYSTICK_RAWINPUT_XINPUT
48 #ifdef SDL_WINDOWS10_SDK
49 #define SDL_JOYSTICK_RAWINPUT_WGI
50 #endif
51 
52 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
53 #include "../../core/windows/SDL_xinput.h"
54 #endif
55 
56 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
57 #include "../../core/windows/SDL_windows.h"
58 typedef struct WindowsGamingInputGamepadState WindowsGamingInputGamepadState;
59 #define GamepadButtons_GUIDE 0x40000000
60 #define COBJMACROS
61 #include "windows.gaming.input.h"
62 #endif
63 
64 #if defined(SDL_JOYSTICK_RAWINPUT_XINPUT) || defined(SDL_JOYSTICK_RAWINPUT_WGI)
65 #define SDL_JOYSTICK_RAWINPUT_MATCHING
66 #define SDL_JOYSTICK_RAWINPUT_MATCH_AXES
67 #endif
68 
69 /*#define DEBUG_RAWINPUT*/
70 
71 #ifndef RIDEV_EXINPUTSINK
72 #define RIDEV_EXINPUTSINK 0x00001000
73 #define RIDEV_DEVNOTIFY 0x00002000
74 #endif
75 
76 #ifndef WM_INPUT_DEVICE_CHANGE
77 #define WM_INPUT_DEVICE_CHANGE 0x00FE
78 #endif
79 #ifndef WM_INPUT
80 #define WM_INPUT 0x00FF
81 #endif
82 #ifndef GIDC_ARRIVAL
83 #define GIDC_ARRIVAL 1
84 #define GIDC_REMOVAL 2
85 #endif
86 
87 
88 static SDL_bool SDL_RAWINPUT_inited = SDL_FALSE;
89 static int SDL_RAWINPUT_numjoysticks = 0;
90 static SDL_mutex *SDL_RAWINPUT_mutex = NULL;
91 
92 static void RAWINPUT_JoystickClose(SDL_Joystick *joystick);
93 
94 typedef struct _SDL_RAWINPUT_Device
95 {
96  SDL_atomic_t refcount;
97  char *name;
98  Uint16 vendor_id;
99  Uint16 product_id;
100  Uint16 version;
101  SDL_JoystickGUID guid;
102  SDL_bool is_xinput;
103  PHIDP_PREPARSED_DATA preparsed_data;
104 
105  HANDLE hDevice;
106  SDL_Joystick *joystick;
107  SDL_JoystickID joystick_id;
108 
109  struct _SDL_RAWINPUT_Device *next;
110 } SDL_RAWINPUT_Device;
111 
112 struct joystick_hwdata
113 {
114  SDL_bool is_xinput;
115  PHIDP_PREPARSED_DATA preparsed_data;
116  ULONG max_data_length;
117  HIDP_DATA *data;
118  USHORT *button_indices;
119  USHORT *axis_indices;
120  USHORT *hat_indices;
121  SDL_bool guide_hack;
122  SDL_bool trigger_hack;
123  USHORT trigger_hack_index;
124 
125 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
126  Uint32 match_state; /* Low 16 bits for button states, high 16 for 4 4bit axes */
127  Uint32 last_state_packet;
128 #endif
129 
130 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
131  SDL_bool xinput_enabled;
132  SDL_bool xinput_correlated;
133  Uint8 xinput_correlation_id;
134  Uint8 xinput_correlation_count;
135  Uint8 xinput_uncorrelate_count;
136  Uint8 xinput_slot;
137 #endif
138 
139 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
140  SDL_bool wgi_correlated;
141  Uint8 wgi_correlation_id;
142  Uint8 wgi_correlation_count;
143  Uint8 wgi_uncorrelate_count;
144  WindowsGamingInputGamepadState *wgi_slot;
145 #endif
146 
147  SDL_RAWINPUT_Device *device;
148 };
149 typedef struct joystick_hwdata RAWINPUT_DeviceContext;
150 
151 SDL_RAWINPUT_Device *SDL_RAWINPUT_devices;
152 
153 static const Uint16 subscribed_devices[] = {
155  /* Don't need Joystick for any devices we're handling here (XInput-capable)
156  USB_USAGE_GENERIC_JOYSTICK,
157  USB_USAGE_GENERIC_MULTIAXISCONTROLLER,
158  */
159 };
160 
161 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
162 
163 static struct {
164  Uint32 last_state_packet;
165  SDL_Joystick *joystick;
166  SDL_Joystick *last_joystick;
167 } guide_button_candidate;
168 
169 typedef struct WindowsMatchState {
170 #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
171  SHORT match_axes[4];
172 #endif
173 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
174  WORD xinput_buttons;
175 #endif
176 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
177  Uint32 wgi_buttons;
178 #endif
179  SDL_bool any_data;
180 } WindowsMatchState;
181 
182 static void RAWINPUT_FillMatchState(WindowsMatchState *state, Uint32 match_state)
183 {
184 #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
185  int ii;
186 #endif
187 
188  state->any_data = SDL_FALSE;
189 #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
190  /* SHORT state->match_axes[4] = {
191  (match_state & 0x000F0000) >> 4,
192  (match_state & 0x00F00000) >> 8,
193  (match_state & 0x0F000000) >> 12,
194  (match_state & 0xF0000000) >> 16,
195  }; */
196  for (ii = 0; ii < 4; ii++) {
197  state->match_axes[ii] = (match_state & (0x000F0000 << (ii * 4))) >> (4 + ii * 4);
198  if ((Uint32)(state->match_axes[ii] + 0x1000) > 0x2000) { /* match_state bit is not 0xF, 0x1, or 0x2 */
199  state->any_data = SDL_TRUE;
200  }
201  }
202 #endif /* SDL_JOYSTICK_RAWINPUT_MATCH_AXES */
203 
204 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
205  /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
206 #define XInputAxesMatch(gamepad) (\
207  (Uint32)(gamepad.sThumbLX - state->match_axes[0] + 0x1000) <= 0x2fff && \
208  (Uint32)(~gamepad.sThumbLY - state->match_axes[1] + 0x1000) <= 0x2fff && \
209  (Uint32)(gamepad.sThumbRX - state->match_axes[2] + 0x1000) <= 0x2fff && \
210  (Uint32)(~gamepad.sThumbRY - state->match_axes[3] + 0x1000) <= 0x2fff)
211  /* Explicit
212 #define XInputAxesMatch(gamepad) (\
213  SDL_abs((Sint8)((gamepad.sThumbLX & 0xF000) >> 8) - ((match_state & 0x000F0000) >> 12)) <= 0x10 && \
214  SDL_abs((Sint8)((~gamepad.sThumbLY & 0xF000) >> 8) - ((match_state & 0x00F00000) >> 16)) <= 0x10 && \
215  SDL_abs((Sint8)((gamepad.sThumbRX & 0xF000) >> 8) - ((match_state & 0x0F000000) >> 20)) <= 0x10 && \
216  SDL_abs((Sint8)((~gamepad.sThumbRY & 0xF000) >> 8) - ((match_state & 0xF0000000) >> 24)) <= 0x10) */
217 
218  state->xinput_buttons =
219  /* Bitwise map .RLDUWVQTS.KYXBA -> YXBA..WVQTKSRLDU */
220  match_state << 12 | (match_state & 0x0780) >> 1 | (match_state & 0x0010) << 1 | (match_state & 0x0040) >> 2 | (match_state & 0x7800) >> 11;
221  /* Explicit
222  ((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? XINPUT_GAMEPAD_A : 0) |
223  ((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? XINPUT_GAMEPAD_B : 0) |
224  ((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? XINPUT_GAMEPAD_X : 0) |
225  ((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? XINPUT_GAMEPAD_Y : 0) |
226  ((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? XINPUT_GAMEPAD_BACK : 0) |
227  ((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? XINPUT_GAMEPAD_START : 0) |
228  ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? XINPUT_GAMEPAD_LEFT_THUMB : 0) |
229  ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? XINPUT_GAMEPAD_RIGHT_THUMB: 0) |
230  ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? XINPUT_GAMEPAD_LEFT_SHOULDER : 0) |
231  ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? XINPUT_GAMEPAD_RIGHT_SHOULDER : 0) |
232  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? XINPUT_GAMEPAD_DPAD_UP : 0) |
233  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? XINPUT_GAMEPAD_DPAD_DOWN : 0) |
234  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? XINPUT_GAMEPAD_DPAD_LEFT : 0) |
235  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? XINPUT_GAMEPAD_DPAD_RIGHT : 0);
236  */
237 
238  if (state->xinput_buttons)
239  state->any_data = SDL_TRUE;
240 #endif
241 
242 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
243  /* Match axes by checking if the distance between the high 4 bits of axis and the 4 bits from match_state is 1 or less */
244 #define WindowsGamingInputAxesMatch(gamepad) (\
245  (Uint16)(((Sint16)(gamepad.LeftThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[0] + 0x1000) <= 0x2fff && \
246  (Uint16)((~(Sint16)(gamepad.LeftThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[1] + 0x1000) <= 0x2fff && \
247  (Uint16)(((Sint16)(gamepad.RightThumbstickX * SDL_MAX_SINT16) & 0xF000) - state->match_axes[2] + 0x1000) <= 0x2fff && \
248  (Uint16)((~(Sint16)(gamepad.RightThumbstickY * SDL_MAX_SINT16) & 0xF000) - state->match_axes[3] + 0x1000) <= 0x2fff)
249 
250 
251  state->wgi_buttons =
252  /* Bitwise map .RLD UWVQ TS.K YXBA -> ..QT WVRL DUYX BAKS */
253  /* RStick/LStick (QT) RShould/LShould (WV) DPad R/L/D/U YXBA bac(K) (S)tart */
254  (match_state & 0x0180) << 5 | (match_state & 0x0600) << 1 | (match_state & 0x7800) >> 5 | (match_state & 0x000F) << 2 | (match_state & 0x0010) >> 3 | (match_state & 0x0040) >> 6;
255  /* Explicit
256  ((match_state & (1<<SDL_CONTROLLER_BUTTON_A)) ? GamepadButtons_A : 0) |
257  ((match_state & (1<<SDL_CONTROLLER_BUTTON_B)) ? GamepadButtons_B : 0) |
258  ((match_state & (1<<SDL_CONTROLLER_BUTTON_X)) ? GamepadButtons_X : 0) |
259  ((match_state & (1<<SDL_CONTROLLER_BUTTON_Y)) ? GamepadButtons_Y : 0) |
260  ((match_state & (1<<SDL_CONTROLLER_BUTTON_BACK)) ? GamepadButtons_View : 0) |
261  ((match_state & (1<<SDL_CONTROLLER_BUTTON_START)) ? GamepadButtons_Menu : 0) |
262  ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSTICK)) ? GamepadButtons_LeftThumbstick : 0) |
263  ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSTICK)) ? GamepadButtons_RightThumbstick: 0) |
264  ((match_state & (1<<SDL_CONTROLLER_BUTTON_LEFTSHOULDER)) ? GamepadButtons_LeftShoulder: 0) |
265  ((match_state & (1<<SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)) ? GamepadButtons_RightShoulder: 0) |
266  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_UP)) ? GamepadButtons_DPadUp : 0) |
267  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_DOWN)) ? GamepadButtons_DPadDown : 0) |
268  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_LEFT)) ? GamepadButtons_DPadLeft : 0) |
269  ((match_state & (1<<SDL_CONTROLLER_BUTTON_DPAD_RIGHT)) ? GamepadButtons_DPadRight : 0); */
270 
271  if (state->wgi_buttons)
272  state->any_data = SDL_TRUE;
273 #endif
274 
275 }
276 
277 #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
278 
279 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
280 
281 static struct {
282  XINPUT_STATE_EX state;
283  XINPUT_BATTERY_INFORMATION_EX battery;
284  SDL_bool connected; /* Currently has an active XInput device */
285  SDL_bool used; /* Is currently mapped to an SDL device */
286  Uint8 correlation_id;
287 } xinput_state[XUSER_MAX_COUNT];
288 static SDL_bool xinput_device_change = SDL_TRUE;
289 static SDL_bool xinput_state_dirty = SDL_TRUE;
290 
291 static void
292 RAWINPUT_UpdateXInput()
293 {
294  DWORD user_index;
295  if (xinput_device_change) {
296  for (user_index = 0; user_index < XUSER_MAX_COUNT; user_index++) {
297  XINPUT_CAPABILITIES capabilities;
298  xinput_state[user_index].connected = (XINPUTGETCAPABILITIES(user_index, XINPUT_FLAG_GAMEPAD, &capabilities) == ERROR_SUCCESS) ? SDL_TRUE : SDL_FALSE;
299  }
300  xinput_device_change = SDL_FALSE;
301  xinput_state_dirty = SDL_TRUE;
302  }
303  if (xinput_state_dirty) {
304  xinput_state_dirty = SDL_FALSE;
305  for (user_index = 0; user_index < SDL_arraysize(xinput_state); ++user_index) {
306  if (xinput_state[user_index].connected) {
307  if (XINPUTGETSTATE(user_index, &xinput_state[user_index].state) != ERROR_SUCCESS) {
308  xinput_state[user_index].connected = SDL_FALSE;
309  }
310  xinput_state[user_index].battery.BatteryType = BATTERY_TYPE_UNKNOWN;
311  XINPUTGETBATTERYINFORMATION(user_index, BATTERY_DEVTYPE_GAMEPAD, &xinput_state[user_index].battery);
312  }
313  }
314  }
315 }
316 
317 static void
318 RAWINPUT_MarkXInputSlotUsed(Uint8 xinput_slot)
319 {
320  if (xinput_slot != XUSER_INDEX_ANY) {
321  xinput_state[xinput_slot].used = SDL_TRUE;
322  }
323 }
324 
325 static void
326 RAWINPUT_MarkXInputSlotFree(Uint8 xinput_slot)
327 {
328  if (xinput_slot != XUSER_INDEX_ANY) {
329  xinput_state[xinput_slot].used = SDL_FALSE;
330  }
331 }
332 static SDL_bool
333 RAWINPUT_MissingXInputSlot()
334 {
335  int ii;
336  for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
337  if (xinput_state[ii].connected && !xinput_state[ii].used) {
338  return SDL_TRUE;
339  }
340  }
341  return SDL_FALSE;
342 }
343 
344 static SDL_bool
345 RAWINPUT_XInputSlotMatches(const WindowsMatchState *state, Uint8 slot_idx)
346 {
347  if (xinput_state[slot_idx].connected) {
348  WORD xinput_buttons = xinput_state[slot_idx].state.Gamepad.wButtons;
349  if ((xinput_buttons & ~XINPUT_GAMEPAD_GUIDE) == state->xinput_buttons
350 #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
351  && XInputAxesMatch(xinput_state[slot_idx].state.Gamepad)
352 #endif
353  ) {
354  return SDL_TRUE;
355  }
356  }
357  return SDL_FALSE;
358 }
359 
360 
361 static SDL_bool
362 RAWINPUT_GuessXInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, Uint8 *slot_idx)
363 {
364  int user_index;
365  int match_count;
366 
367  *slot_idx = 0;
368 
369  match_count = 0;
370  for (user_index = 0; user_index < XUSER_MAX_COUNT; ++user_index) {
371  if (!xinput_state[user_index].used && RAWINPUT_XInputSlotMatches(state, user_index)) {
372  ++match_count;
373  *slot_idx = (Uint8)user_index;
374  /* Incrementing correlation_id for any match, as negative evidence for others being correlated */
375  *correlation_id = ++xinput_state[user_index].correlation_id;
376  }
377  }
378  /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
379  Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
380  data. */
381  if (match_count == 1 && state->any_data) {
382  return SDL_TRUE;
383  }
384  return SDL_FALSE;
385 }
386 
387 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
388 
389 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
390 
391 typedef struct WindowsGamingInputGamepadState {
392  __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
393  struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading state;
394  RAWINPUT_DeviceContext *correlated_context;
395  SDL_bool used; /* Is currently mapped to an SDL device */
396  SDL_bool connected; /* Just used during update to track disconnected */
397  Uint8 correlation_id;
398  struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
399 } WindowsGamingInputGamepadState;
400 
401 static struct {
402  WindowsGamingInputGamepadState **per_gamepad;
403  int per_gamepad_count;
404  SDL_bool initialized;
405  SDL_bool dirty;
406  SDL_bool need_device_list_update;
407  int ref_count;
408  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
409 } wgi_state;
410 
411 static void
412 RAWINPUT_MarkWindowsGamingInputSlotUsed(WindowsGamingInputGamepadState *wgi_slot, RAWINPUT_DeviceContext *ctx)
413 {
414  wgi_slot->used = SDL_TRUE;
415  wgi_slot->correlated_context = ctx;
416 }
417 
418 static void
419 RAWINPUT_MarkWindowsGamingInputSlotFree(WindowsGamingInputGamepadState *wgi_slot)
420 {
421  wgi_slot->used = SDL_FALSE;
422  wgi_slot->correlated_context = NULL;
423 }
424 
425 static SDL_bool
426 RAWINPUT_MissingWindowsGamingInputSlot()
427 {
428  int ii;
429  for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
430  if (!wgi_state.per_gamepad[ii]->used) {
431  return SDL_TRUE;
432  }
433  }
434  return SDL_FALSE;
435 }
436 
437 static void
438 RAWINPUT_UpdateWindowsGamingInput()
439 {
440  int ii;
441  if (!wgi_state.gamepad_statics)
442  return;
443 
444  if (!wgi_state.dirty)
445  return;
446 
447  wgi_state.dirty = SDL_FALSE;
448 
449  if (wgi_state.need_device_list_update) {
450  wgi_state.need_device_list_update = SDL_FALSE;
451  for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
452  wgi_state.per_gamepad[ii]->connected = SDL_FALSE;
453  }
454  HRESULT hr;
455  __FIVectorView_1_Windows__CGaming__CInput__CGamepad *gamepads;
456 
457  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_get_Gamepads(wgi_state.gamepad_statics, &gamepads);
458  if (SUCCEEDED(hr)) {
459  unsigned int num_gamepads;
460 
461  hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_get_Size(gamepads, &num_gamepads);
462  if (SUCCEEDED(hr)) {
463  unsigned int i;
464  for (i = 0; i < num_gamepads; ++i) {
465  __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
466 
467  hr = __FIVectorView_1_Windows__CGaming__CInput__CGamepad_GetAt(gamepads, i, &gamepad);
468  if (SUCCEEDED(hr)) {
469  SDL_bool found = SDL_FALSE;
470  int jj;
471  for (jj = 0; jj < wgi_state.per_gamepad_count ; jj++) {
472  if (wgi_state.per_gamepad[jj]->gamepad == gamepad) {
473  found = SDL_TRUE;
474  wgi_state.per_gamepad[jj]->connected = SDL_TRUE;
475  break;
476  }
477  }
478  if (!found) {
479  /* New device, add it */
480  wgi_state.per_gamepad_count++;
481  wgi_state.per_gamepad = SDL_realloc(wgi_state.per_gamepad, sizeof(wgi_state.per_gamepad[0]) * wgi_state.per_gamepad_count);
482  if (!wgi_state.per_gamepad) {
483  SDL_OutOfMemory();
484  return;
485  }
486  WindowsGamingInputGamepadState *gamepad_state = SDL_calloc(1, sizeof(*gamepad_state));
487  if (!gamepad_state) {
488  SDL_OutOfMemory();
489  return;
490  }
491  wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1] = gamepad_state;
492  gamepad_state->gamepad = gamepad;
493  gamepad_state->connected = SDL_TRUE;
494  } else {
495  /* Already tracked */
496  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
497  }
498  }
499  }
500  for (ii = wgi_state.per_gamepad_count - 1; ii >= 0; ii--) {
501  WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
502  if (!gamepad_state->connected) {
503  /* Device missing, must be disconnected */
504  if (gamepad_state->correlated_context) {
505  gamepad_state->correlated_context->wgi_correlated = SDL_FALSE;
506  gamepad_state->correlated_context->wgi_slot = NULL;
507  }
508  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad_state->gamepad);
509  SDL_free(gamepad_state);
510  wgi_state.per_gamepad[ii] = wgi_state.per_gamepad[wgi_state.per_gamepad_count - 1];
511  --wgi_state.per_gamepad_count;
512  }
513  }
514  }
515  __FIVectorView_1_Windows__CGaming__CInput__CGamepad_Release(gamepads);
516  }
517  } /* need_device_list_update */
518 
519  for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
520  HRESULT hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_GetCurrentReading(wgi_state.per_gamepad[ii]->gamepad, &wgi_state.per_gamepad[ii]->state);
521  if (!SUCCEEDED(hr)) {
522  wgi_state.per_gamepad[ii]->connected = SDL_FALSE; /* Not used by anything, currently */
523  }
524  }
525 }
526 static void
527 RAWINPUT_InitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
528 {
529  wgi_state.need_device_list_update = SDL_TRUE;
530  wgi_state.ref_count++;
531  if (!wgi_state.initialized) {
532  /* I think this takes care of RoInitialize() in a way that is compatible with the rest of SDL */
533  if (FAILED(WIN_CoInitialize())) {
534  return;
535  }
536  wgi_state.initialized = SDL_TRUE;
537  wgi_state.dirty = SDL_TRUE;
538 
539  static const IID SDL_IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
540  HRESULT hr;
541  HMODULE hModule = LoadLibraryA("combase.dll");
542  if (hModule != NULL) {
543  typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string);
544  typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
545 
546  WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference");
547  RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
548  if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
549  LPTSTR pNamespace = L"Windows.Gaming.Input.Gamepad";
550  HSTRING_HEADER hNamespaceStringHeader;
551  HSTRING hNamespaceString;
552 
553  hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
554  if (SUCCEEDED(hr)) {
555  RoGetActivationFactoryFunc(hNamespaceString, &SDL_IID_IGamepadStatics, &wgi_state.gamepad_statics);
556  }
557  }
558  FreeLibrary(hModule);
559  }
560  }
561 }
562 
563 static SDL_bool
564 RAWINPUT_WindowsGamingInputSlotMatches(const WindowsMatchState *state, WindowsGamingInputGamepadState *slot)
565 {
566  Uint32 wgi_buttons = slot->state.Buttons;
567  if ((wgi_buttons & 0x3FFF) == state->wgi_buttons
568 #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
569  && WindowsGamingInputAxesMatch(slot->state)
570 #endif
571  ) {
572  return SDL_TRUE;
573  }
574  return SDL_FALSE;
575 }
576 
577 static SDL_bool
578 RAWINPUT_GuessWindowsGamingInputSlot(const WindowsMatchState *state, Uint8 *correlation_id, WindowsGamingInputGamepadState **slot)
579 {
580  int match_count, user_index;
581 
582  match_count = 0;
583  for (user_index = 0; user_index < wgi_state.per_gamepad_count; ++user_index) {
584  WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[user_index];
585  if (RAWINPUT_WindowsGamingInputSlotMatches(state, gamepad_state)) {
586  ++match_count;
587  *slot = gamepad_state;
588  /* Incrementing correlation_id for any match, as negative evidence for others being correlated */
589  *correlation_id = ++gamepad_state->correlation_id;
590  }
591  }
592  /* Only return a match if we match exactly one, and we have some non-zero data (buttons or axes) that matched.
593  Note that we're still invalidating *other* potential correlations if we have more than one match or we have no
594  data. */
595  if (match_count == 1 && state->any_data) {
596  return SDL_TRUE;
597  }
598  return SDL_FALSE;
599 }
600 
601 static void
602 RAWINPUT_QuitWindowsGamingInput(RAWINPUT_DeviceContext *ctx)
603 {
604  wgi_state.need_device_list_update = SDL_TRUE;
605  --wgi_state.ref_count;
606  if (!wgi_state.ref_count && wgi_state.initialized) {
607  int ii;
608  for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
609  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(wgi_state.per_gamepad[ii]->gamepad);
610  }
611  if (wgi_state.per_gamepad) {
612  SDL_free(wgi_state.per_gamepad);
613  wgi_state.per_gamepad = NULL;
614  }
615  wgi_state.per_gamepad_count = 0;
616  if (wgi_state.gamepad_statics) {
617  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi_state.gamepad_statics);
618  wgi_state.gamepad_statics = NULL;
619  }
621  wgi_state.initialized = SDL_FALSE;
622  }
623 }
624 
625 #endif /* SDL_JOYSTICK_RAWINPUT_WGI */
626 
627 
628 static SDL_RAWINPUT_Device *
629 RAWINPUT_AcquireDevice(SDL_RAWINPUT_Device *device)
630 {
631  SDL_AtomicIncRef(&device->refcount);
632  return device;
633 }
634 
635 static void
636 RAWINPUT_ReleaseDevice(SDL_RAWINPUT_Device *device)
637 {
638 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
639  if (device->joystick) {
640  RAWINPUT_DeviceContext *ctx = device->joystick->hwdata;
641 
642  if (ctx->xinput_enabled && ctx->xinput_correlated) {
643  RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot);
644  ctx->xinput_correlated = SDL_FALSE;
645  }
646  }
647 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
648 
649  if (SDL_AtomicDecRef(&device->refcount)) {
650  if (device->preparsed_data) {
651  SDL_HidD_FreePreparsedData(device->preparsed_data);
652  }
653  SDL_free(device->name);
654  SDL_free(device);
655  }
656 }
657 
658 static SDL_RAWINPUT_Device *
659 RAWINPUT_DeviceFromHandle(HANDLE hDevice)
660 {
661  SDL_RAWINPUT_Device *curr;
662 
663  for (curr = SDL_RAWINPUT_devices; curr; curr = curr->next) {
664  if (curr->hDevice == hDevice)
665  return curr;
666  }
667  return NULL;
668 }
669 
670 static void
671 RAWINPUT_AddDevice(HANDLE hDevice)
672 {
673 #define CHECK(exp) { if(!(exp)) goto err; }
674  SDL_RAWINPUT_Device *device = NULL;
675  SDL_RAWINPUT_Device *curr, *last;
676  RID_DEVICE_INFO rdi;
677  UINT rdi_size = sizeof(rdi);
678  char dev_name[MAX_PATH];
679  UINT name_size = SDL_arraysize(dev_name);
680  HANDLE hFile = INVALID_HANDLE_VALUE;
681 
682  /* Make sure we're not trying to add the same device twice */
683  if (RAWINPUT_DeviceFromHandle(hDevice)) {
684  return;
685  }
686 
687  /* Figure out what kind of device it is */
688  CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICEINFO, &rdi, &rdi_size) != (UINT)-1);
689  CHECK(rdi.dwType == RIM_TYPEHID);
690 
691  /* Get the device "name" (HID Path) */
692  CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, dev_name, &name_size) != (UINT)-1);
693  /* Only take XInput-capable devices */
694  CHECK(SDL_strstr(dev_name, "IG_") != NULL);
695 #ifdef SDL_JOYSTICK_HIDAPI
696  /* Don't take devices handled by HIDAPI */
697  CHECK(!HIDAPI_IsDevicePresent((Uint16)rdi.hid.dwVendorId, (Uint16)rdi.hid.dwProductId, (Uint16)rdi.hid.dwVersionNumber, ""));
698 #endif
699 
700  CHECK(device = (SDL_RAWINPUT_Device *)SDL_calloc(1, sizeof(SDL_RAWINPUT_Device)));
701  device->hDevice = hDevice;
702  device->vendor_id = (Uint16)rdi.hid.dwVendorId;
703  device->product_id = (Uint16)rdi.hid.dwProductId;
704  device->version = (Uint16)rdi.hid.dwVersionNumber;
705  device->is_xinput = SDL_TRUE;
706 
707  {
708  const Uint16 vendor = device->vendor_id;
709  const Uint16 product = device->product_id;
710  const Uint16 version = device->version;
711  Uint16 *guid16 = (Uint16 *)device->guid.data;
712 
713  *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
714  *guid16++ = 0;
715  *guid16++ = SDL_SwapLE16(vendor);
716  *guid16++ = 0;
717  *guid16++ = SDL_SwapLE16(product);
718  *guid16++ = 0;
719  *guid16++ = SDL_SwapLE16(version);
720  *guid16++ = 0;
721 
722  /* Note that this is a RAWINPUT device for special handling elsewhere */
723  device->guid.data[14] = 'r';
724  device->guid.data[15] = 0;
725  }
726 
727  hFile = CreateFileA(dev_name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
728  CHECK(hFile != INVALID_HANDLE_VALUE);
729 
730  {
731  char *manufacturer_string = NULL;
732  char *product_string = NULL;
733  WCHAR string[128];
734 
735  if (SDL_HidD_GetManufacturerString(hFile, string, sizeof(string))) {
736  manufacturer_string = WIN_StringToUTF8(string);
737  }
738  if (SDL_HidD_GetProductString(hFile, string, sizeof(string))) {
739  product_string = WIN_StringToUTF8(string);
740  }
741 
742  device->name = SDL_CreateJoystickName(device->vendor_id, device->product_id, manufacturer_string, product_string);
743 
744  if (manufacturer_string) {
745  SDL_free(manufacturer_string);
746  }
747  if (product_string) {
748  SDL_free(product_string);
749  }
750  }
751 
752  CHECK(SDL_HidD_GetPreparsedData(hFile, &device->preparsed_data));
753 
754  CloseHandle(hFile);
755  hFile = INVALID_HANDLE_VALUE;
756 
757  device->joystick_id = SDL_GetNextJoystickInstanceID();
758 
759 #ifdef DEBUG_RAWINPUT
760  SDL_Log("Adding RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle 0x%.8x\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice);
761 #endif
762 
763  /* Add it to the list */
764  RAWINPUT_AcquireDevice(device);
765  for (curr = SDL_RAWINPUT_devices, last = NULL; curr; last = curr, curr = curr->next) {
766  continue;
767  }
768  if (last) {
769  last->next = device;
770  } else {
771  SDL_RAWINPUT_devices = device;
772  }
773 
774  ++SDL_RAWINPUT_numjoysticks;
775 
776  SDL_PrivateJoystickAdded(device->joystick_id);
777 
778  return;
779 
780 err:
781  if (hFile != INVALID_HANDLE_VALUE) {
782  CloseHandle(hFile);
783  }
784  if (device) {
785  if (device->name)
786  SDL_free(device->name);
787  SDL_free(device);
788  }
789 #undef CHECK
790 }
791 
792 static void
793 RAWINPUT_DelDevice(SDL_RAWINPUT_Device *device, SDL_bool send_event)
794 {
795  SDL_RAWINPUT_Device *curr, *last;
796  for (curr = SDL_RAWINPUT_devices, last = NULL; curr; last = curr, curr = curr->next) {
797  if (curr == device) {
798  if (last) {
799  last->next = curr->next;
800  } else {
801  SDL_RAWINPUT_devices = curr->next;
802  }
803  --SDL_RAWINPUT_numjoysticks;
804 
805  SDL_PrivateJoystickRemoved(device->joystick_id);
806 
807 #ifdef DEBUG_RAWINPUT
808  SDL_Log("Removing RAWINPUT device '%s' VID 0x%.4x, PID 0x%.4x, version %d, handle %p\n", device->name, device->vendor_id, device->product_id, device->version, device->hDevice);
809 #endif
810  RAWINPUT_ReleaseDevice(device);
811  return;
812  }
813  }
814 }
815 
816 static int
817 RAWINPUT_JoystickInit(void)
818 {
819  UINT device_count = 0;
820 
821  SDL_assert(!SDL_RAWINPUT_inited);
822 
824  return -1;
825  }
826 
827  if (WIN_LoadHIDDLL() < 0) {
828  return -1;
829  }
830 
831  SDL_RAWINPUT_mutex = SDL_CreateMutex();
832  SDL_RAWINPUT_inited = SDL_TRUE;
833 
834  if ((GetRawInputDeviceList(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) != -1) && device_count > 0) {
835  PRAWINPUTDEVICELIST devices = NULL;
836  UINT i;
837 
838  devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * device_count);
839  if (devices) {
840  if (GetRawInputDeviceList(devices, &device_count, sizeof(RAWINPUTDEVICELIST)) != -1) {
841  for (i = 0; i < device_count; ++i) {
842  RAWINPUT_AddDevice(devices[i].hDevice);
843  }
844  }
845  SDL_free(devices);
846  }
847  }
848 
849  return 0;
850 }
851 
852 static int
853 RAWINPUT_JoystickGetCount(void)
854 {
855  return SDL_RAWINPUT_numjoysticks;
856 }
857 
858 SDL_bool
860 {
861  return SDL_RAWINPUT_inited;
862 }
863 
864 SDL_bool
865 RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
866 {
867  SDL_RAWINPUT_Device *device;
868 
869  /* If we're being asked about a device, that means another API just detected one, so rescan */
870 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
871  xinput_device_change = SDL_TRUE;
872 #endif
873 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
874  wgi_state.need_device_list_update = SDL_TRUE;
875 #endif
876 
877  device = SDL_RAWINPUT_devices;
878  while (device) {
879  if (vendor_id == device->vendor_id && product_id == device->product_id ) {
880  return SDL_TRUE;
881  }
882 
883  /* The Xbox 360 wireless controller shows up as product 0 in WGI */
884  if (vendor_id == device->vendor_id && product_id == 0 &&
885  name && SDL_strstr(device->name, name) != NULL) {
886  return SDL_TRUE;
887  }
888 
889  /* The Xbox One controller shows up as a hardcoded raw input VID/PID */
890  if (name && SDL_strcmp(name, "Xbox One Game Controller") == 0 &&
891  device->vendor_id == USB_VENDOR_MICROSOFT &&
893  return SDL_TRUE;
894  }
895 
896  device = device->next;
897  }
898  return SDL_FALSE;
899 }
900 
901 static void
902 RAWINPUT_PostUpdate(void)
903 {
904 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
905  SDL_bool unmapped_guide_pressed = SDL_FALSE;
906 
907 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
908  if (!wgi_state.dirty) {
909  int ii;
910  for (ii = 0; ii < wgi_state.per_gamepad_count; ii++) {
911  WindowsGamingInputGamepadState *gamepad_state = wgi_state.per_gamepad[ii];
912  if (!gamepad_state->used && (gamepad_state->state.Buttons & GamepadButtons_GUIDE)) {
913  unmapped_guide_pressed = SDL_TRUE;
914  break;
915  }
916  }
917  }
918  wgi_state.dirty = SDL_TRUE;
919 #endif
920 
921 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
922  if (!xinput_state_dirty) {
923  int ii;
924  for (ii = 0; ii < SDL_arraysize(xinput_state); ii++) {
925  if (xinput_state[ii].connected && !xinput_state[ii].used && (xinput_state[ii].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE)) {
926  unmapped_guide_pressed = SDL_TRUE;
927  break;
928  }
929  }
930  }
931  xinput_state_dirty = SDL_TRUE;
932 #endif
933 
934  if (unmapped_guide_pressed) {
935  if (guide_button_candidate.joystick && !guide_button_candidate.last_joystick) {
936  SDL_Joystick *joystick = guide_button_candidate.joystick;
937  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
938  if (ctx->guide_hack) {
939  int guide_button = joystick->nbuttons - 1;
940 
941  SDL_PrivateJoystickButton(guide_button_candidate.joystick, guide_button, SDL_PRESSED);
942  }
943  guide_button_candidate.last_joystick = guide_button_candidate.joystick;
944  }
945  } else if (guide_button_candidate.last_joystick) {
946  SDL_Joystick *joystick = guide_button_candidate.last_joystick;
947  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
948  if (ctx->guide_hack) {
949  int guide_button = joystick->nbuttons - 1;
950 
952  }
953  guide_button_candidate.last_joystick = NULL;
954  }
955  guide_button_candidate.joystick = NULL;
956 
957 #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
958 }
959 
960 static void
961 RAWINPUT_JoystickDetect(void)
962 {
963  RAWINPUT_PostUpdate();
964 }
965 
966 static SDL_RAWINPUT_Device *
967 RAWINPUT_GetDeviceByIndex(int device_index)
968 {
969  SDL_RAWINPUT_Device *device = SDL_RAWINPUT_devices;
970  while (device) {
971  if (device_index == 0) {
972  break;
973  }
974  --device_index;
975  device = device->next;
976  }
977  return device;
978 }
979 
980 static const char *
981 RAWINPUT_JoystickGetDeviceName(int device_index)
982 {
983  return RAWINPUT_GetDeviceByIndex(device_index)->name;
984 }
985 
986 static int
987 RAWINPUT_JoystickGetDevicePlayerIndex(int device_index)
988 {
989  return -1;
990 }
991 
992 static void
993 RAWINPUT_JoystickSetDevicePlayerIndex(int device_index, int player_index)
994 {
995 }
996 
997 
998 static SDL_JoystickGUID
999 RAWINPUT_JoystickGetDeviceGUID(int device_index)
1000 {
1001  return RAWINPUT_GetDeviceByIndex(device_index)->guid;
1002 }
1003 
1004 static SDL_JoystickID
1005 RAWINPUT_JoystickGetDeviceInstanceID(int device_index)
1006 {
1007  return RAWINPUT_GetDeviceByIndex(device_index)->joystick_id;
1008 }
1009 
1010 static int
1011 RAWINPUT_SortValueCaps(const void *A, const void *B)
1012 {
1013  HIDP_VALUE_CAPS *capsA = (HIDP_VALUE_CAPS *)A;
1014  HIDP_VALUE_CAPS *capsB = (HIDP_VALUE_CAPS *)B;
1015 
1016  /* Sort by Usage for single values, or UsageMax for range of values */
1017  return (int)capsA->NotRange.Usage - capsB->NotRange.Usage;
1018 }
1019 
1020 static int
1021 RAWINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
1022 {
1023  SDL_RAWINPUT_Device *device = RAWINPUT_GetDeviceByIndex(device_index);
1024  RAWINPUT_DeviceContext *ctx;
1025  HIDP_CAPS caps;
1026  HIDP_BUTTON_CAPS *button_caps;
1027  HIDP_VALUE_CAPS *value_caps;
1028  ULONG i;
1029 
1030  ctx = (RAWINPUT_DeviceContext *)SDL_calloc(1, sizeof(RAWINPUT_DeviceContext));
1031  if (!ctx) {
1032  return SDL_OutOfMemory();
1033  }
1034  joystick->hwdata = ctx;
1035 
1036  ctx->device = RAWINPUT_AcquireDevice(device);
1037  device->joystick = joystick;
1038 
1039  if (device->is_xinput) {
1040  /* We'll try to get guide button and trigger axes from XInput */
1041 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
1042  xinput_device_change = SDL_TRUE;
1044  if (ctx->xinput_enabled && (WIN_LoadXInputDLL() < 0 || !XINPUTGETSTATE)) {
1045  ctx->xinput_enabled = SDL_FALSE;
1046  }
1047  ctx->xinput_slot = XUSER_INDEX_ANY;
1048 #endif
1049 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
1050  RAWINPUT_InitWindowsGamingInput(ctx);
1051 #endif
1052  }
1053 
1054  ctx->is_xinput = device->is_xinput;
1055  ctx->preparsed_data = device->preparsed_data;
1056  ctx->max_data_length = SDL_HidP_MaxDataListLength(HidP_Input, ctx->preparsed_data);
1057  ctx->data = (HIDP_DATA *)SDL_malloc(ctx->max_data_length * sizeof(*ctx->data));
1058  if (!ctx->data) {
1059  RAWINPUT_JoystickClose(joystick);
1060  return SDL_OutOfMemory();
1061  }
1062 
1063  if (SDL_HidP_GetCaps(ctx->preparsed_data, &caps) != HIDP_STATUS_SUCCESS) {
1064  RAWINPUT_JoystickClose(joystick);
1065  return SDL_SetError("Couldn't get device capabilities");
1066  }
1067 
1069  if (SDL_HidP_GetButtonCaps(HidP_Input, button_caps, &caps.NumberInputButtonCaps, ctx->preparsed_data) != HIDP_STATUS_SUCCESS) {
1070  RAWINPUT_JoystickClose(joystick);
1071  return SDL_SetError("Couldn't get device button capabilities");
1072  }
1073 
1075  if (SDL_HidP_GetValueCaps(HidP_Input, value_caps, &caps.NumberInputValueCaps, ctx->preparsed_data) != HIDP_STATUS_SUCCESS) {
1076  RAWINPUT_JoystickClose(joystick);
1077  return SDL_SetError("Couldn't get device value capabilities");
1078  }
1079 
1080  /* Sort the axes by usage, so X comes before Y, etc. */
1081  SDL_qsort(value_caps, caps.NumberInputValueCaps, sizeof(*value_caps), RAWINPUT_SortValueCaps);
1082 
1083  for (i = 0; i < caps.NumberInputButtonCaps; ++i) {
1084  HIDP_BUTTON_CAPS *cap = &button_caps[i];
1085 
1086  if (cap->UsagePage == USB_USAGEPAGE_BUTTON) {
1087  int count;
1088 
1089  if (cap->IsRange) {
1090  count = 1 + (cap->Range.DataIndexMax - cap->Range.DataIndexMin);
1091  } else {
1092  count = 1;
1093  }
1094 
1095  joystick->nbuttons += count;
1096  }
1097  }
1098 
1099  if (joystick->nbuttons > 0) {
1100  int button_index = 0;
1101 
1102  ctx->button_indices = (USHORT *)SDL_malloc(joystick->nbuttons * sizeof(*ctx->button_indices));
1103  if (!ctx->button_indices) {
1104  RAWINPUT_JoystickClose(joystick);
1105  return SDL_OutOfMemory();
1106  }
1107 
1108  for (i = 0; i < caps.NumberInputButtonCaps; ++i) {
1109  HIDP_BUTTON_CAPS *cap = &button_caps[i];
1110 
1111  if (cap->UsagePage == USB_USAGEPAGE_BUTTON) {
1112  if (cap->IsRange) {
1113  int j, count = 1 + (cap->Range.DataIndexMax - cap->Range.DataIndexMin);
1114 
1115  for (j = 0; j < count; ++j) {
1116  ctx->button_indices[button_index++] = cap->Range.DataIndexMin + j;
1117  }
1118  } else {
1119  ctx->button_indices[button_index++] = cap->NotRange.DataIndex;
1120  }
1121  }
1122  }
1123  }
1124  if (ctx->is_xinput && joystick->nbuttons == 10) {
1125  ctx->guide_hack = SDL_TRUE;
1126  joystick->nbuttons += 1;
1127  }
1128 
1129  for (i = 0; i < caps.NumberInputValueCaps; ++i) {
1130  HIDP_VALUE_CAPS *cap = &value_caps[i];
1131 
1132  if (cap->IsRange) {
1133  continue;
1134  }
1135 
1136  if (ctx->trigger_hack && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) {
1137  continue;
1138  }
1139 
1140  if (cap->NotRange.Usage == USB_USAGE_GENERIC_HAT) {
1141  joystick->nhats += 1;
1142  continue;
1143  }
1144 
1145  if (ctx->is_xinput && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) {
1146  continue;
1147  }
1148 
1149  joystick->naxes += 1;
1150  }
1151 
1152  if (joystick->naxes > 0) {
1153  int axis_index = 0;
1154 
1155  ctx->axis_indices = (USHORT *)SDL_malloc(joystick->naxes * sizeof(*ctx->axis_indices));
1156  if (!ctx->axis_indices) {
1157  RAWINPUT_JoystickClose(joystick);
1158  return SDL_OutOfMemory();
1159  }
1160 
1161  for (i = 0; i < caps.NumberInputValueCaps; ++i) {
1162  HIDP_VALUE_CAPS *cap = &value_caps[i];
1163 
1164  if (cap->IsRange) {
1165  continue;
1166  }
1167 
1168  if (cap->NotRange.Usage == USB_USAGE_GENERIC_HAT) {
1169  continue;
1170  }
1171 
1172  if (ctx->is_xinput && cap->NotRange.Usage == USB_USAGE_GENERIC_Z) {
1173  ctx->trigger_hack = SDL_TRUE;
1174  ctx->trigger_hack_index = cap->NotRange.DataIndex;
1175  continue;
1176  }
1177 
1178  ctx->axis_indices[axis_index++] = cap->NotRange.DataIndex;
1179  }
1180  }
1181  if (ctx->trigger_hack) {
1182  joystick->naxes += 2;
1183  }
1184 
1185  if (joystick->nhats > 0) {
1186  int hat_index = 0;
1187 
1188  ctx->hat_indices = (USHORT *)SDL_malloc(joystick->nhats * sizeof(*ctx->hat_indices));
1189  if (!ctx->hat_indices) {
1190  RAWINPUT_JoystickClose(joystick);
1191  return SDL_OutOfMemory();
1192  }
1193 
1194  for (i = 0; i < caps.NumberInputValueCaps; ++i) {
1195  HIDP_VALUE_CAPS *cap = &value_caps[i];
1196 
1197  if (cap->IsRange) {
1198  continue;
1199  }
1200 
1201  if (cap->NotRange.Usage != USB_USAGE_GENERIC_HAT) {
1202  continue;
1203  }
1204 
1205  ctx->hat_indices[hat_index++] = cap->NotRange.DataIndex;
1206  }
1207  }
1208 
1210 
1211  return 0;
1212 }
1213 
1214 static int
1215 RAWINPUT_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1216 {
1217 #if defined(SDL_JOYSTICK_RAWINPUT_WGI) || defined(SDL_JOYSTICK_RAWINPUT_XINPUT)
1218  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
1219 #endif
1220 
1221  SDL_bool rumbled = SDL_FALSE;
1222 
1223 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
1224  if (!rumbled && ctx->wgi_correlated) {
1225  WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
1226  HRESULT hr;
1227  gamepad_state->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
1228  gamepad_state->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
1229  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
1230  if (SUCCEEDED(hr)) {
1231  rumbled = SDL_TRUE;
1232  }
1233  }
1234 #endif
1235 
1236 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
1237  if (!rumbled && ctx->xinput_correlated) {
1238  XINPUT_VIBRATION XVibration;
1239 
1240  if (!XINPUTSETSTATE) {
1241  return SDL_Unsupported();
1242  }
1243 
1244  XVibration.wLeftMotorSpeed = low_frequency_rumble;
1245  XVibration.wRightMotorSpeed = high_frequency_rumble;
1246  if (XINPUTSETSTATE(ctx->xinput_slot, &XVibration) == ERROR_SUCCESS) {
1247  rumbled = SDL_TRUE;
1248  } else {
1249  return SDL_SetError("XInputSetState() failed");
1250  }
1251  }
1252 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
1253 
1254  return 0;
1255 }
1256 
1257 static int
1258 RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1259 {
1260 #if defined(SDL_JOYSTICK_RAWINPUT_WGI)
1261  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
1262 
1263  if (ctx->wgi_correlated) {
1264  WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
1265  HRESULT hr;
1266  gamepad_state->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
1267  gamepad_state->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
1268  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(gamepad_state->gamepad, gamepad_state->vibration);
1269  if (!SUCCEEDED(hr)) {
1270  return SDL_SetError("Setting vibration failed: 0x%x\n", hr);
1271  }
1272  }
1273  return 0;
1274 #else
1275  return SDL_Unsupported();
1276 #endif
1277 }
1278 
1279 static SDL_bool
1280 RAWINPUT_JoystickHasLED(SDL_Joystick *joystick)
1281 {
1282  return SDL_FALSE;
1283 }
1284 
1285 static int
1286 RAWINPUT_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1287 {
1288  return SDL_Unsupported();
1289 }
1290 
1291 static int
1292 RAWINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
1293 {
1294  return SDL_Unsupported();
1295 }
1296 
1297 static HIDP_DATA *GetData(USHORT index, HIDP_DATA *data, ULONG length)
1298 {
1299  ULONG i;
1300 
1301  /* Check to see if the data is at the expected offset */
1302  if (index < length && data[index].DataIndex == index) {
1303  return &data[index];
1304  }
1305 
1306  /* Loop through the data to find it */
1307  for (i = 0; i < length; ++i) {
1308  if (data[i].DataIndex == index) {
1309  return &data[i];
1310  }
1311  }
1312  return NULL;
1313 }
1314 
1315 /* This is the packet format for Xbox 360 and Xbox One controllers on Windows,
1316  however with this interface there is no rumble support, no guide button,
1317  and the left and right triggers are tied together as a single axis.
1318 
1319  We use XInput and Windows.Gaming.Input to make up for these shortcomings.
1320  */
1321 static void
1322 RAWINPUT_HandleStatePacket(SDL_Joystick *joystick, Uint8 *data, int size)
1323 {
1324  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
1325 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
1326  /* Map new buttons and axes into game controller controls */
1327  static const int button_map[] = {
1338  };
1339 #define HAT_MASK ((1 << SDL_CONTROLLER_BUTTON_DPAD_UP) | (1 << SDL_CONTROLLER_BUTTON_DPAD_DOWN) | (1 << SDL_CONTROLLER_BUTTON_DPAD_LEFT) | (1 << SDL_CONTROLLER_BUTTON_DPAD_RIGHT))
1340  static const int hat_map[] = {
1341  0,
1350  };
1351  Uint32 match_state = ctx->match_state;
1352  /* Update match_state with button bit, then fall through */
1353 #define SDL_PrivateJoystickButton(joystick, button, state) if (button < SDL_arraysize(button_map)) { if (state) match_state |= 1 << button_map[button]; else match_state &= ~(1 << button_map[button]); } SDL_PrivateJoystickButton(joystick, button, state)
1354 #ifdef SDL_JOYSTICK_RAWINPUT_MATCH_AXES
1355  /* Grab high 4 bits of value, then fall through */
1356 #define SDL_PrivateJoystickAxis(joystick, axis, value) if (axis < 4) match_state = (match_state & ~(0xF << (4 * axis + 16))) | ((value) & 0xF000) << (4 * axis + 4); SDL_PrivateJoystickAxis(joystick, axis, value)
1357 #endif
1358 #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
1359 
1360  ULONG data_length = ctx->max_data_length;
1361  int i;
1362  int nbuttons = joystick->nbuttons - (ctx->guide_hack * 1);
1363  int naxes = joystick->naxes - (ctx->trigger_hack * 2);
1364  int nhats = joystick->nhats;
1365  Uint32 button_mask = 0;
1366 
1367  if (SDL_HidP_GetData(HidP_Input, ctx->data, &data_length, ctx->preparsed_data, (PCHAR)data, size) != HIDP_STATUS_SUCCESS) {
1368  return;
1369  }
1370 
1371  for (i = 0; i < nbuttons; ++i) {
1372  HIDP_DATA *item = GetData(ctx->button_indices[i], ctx->data, data_length);
1373  if (item && item->On) {
1374  button_mask |= (1 << i);
1375  }
1376  }
1377  for (i = 0; i < nbuttons; ++i) {
1378  SDL_PrivateJoystickButton(joystick, i, (button_mask & (1 << i)) ? SDL_PRESSED : SDL_RELEASED);
1379  }
1380 
1381  for (i = 0; i < naxes; ++i) {
1382  HIDP_DATA *item = GetData(ctx->axis_indices[i], ctx->data, data_length);
1383  if (item) {
1384  Sint16 axis = (int)(Uint16)item->RawValue - 0x8000;
1386  }
1387  }
1388 
1389  for (i = 0; i < nhats; ++i) {
1390  HIDP_DATA *item = GetData(ctx->hat_indices[i], ctx->data, data_length);
1391  if (item) {
1392  const Uint8 hat_states[] = {
1394  SDL_HAT_UP,
1396  SDL_HAT_RIGHT,
1398  SDL_HAT_DOWN,
1400  SDL_HAT_LEFT,
1402  };
1403  ULONG state = item->RawValue;
1404 
1405  if (state < SDL_arraysize(hat_states)) {
1406 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
1407  match_state = (match_state & ~HAT_MASK) | hat_map[state];
1408 #endif
1409  SDL_PrivateJoystickHat(joystick, i, hat_states[state]);
1410  }
1411  }
1412  }
1413 
1414 #ifdef SDL_PrivateJoystickButton
1415 #undef SDL_PrivateJoystickButton
1416 #endif
1417 #ifdef SDL_PrivateJoystickAxis
1418 #undef SDL_PrivateJoystickAxis
1419 #endif
1420 
1421  if (ctx->trigger_hack) {
1422  SDL_bool has_trigger_data = SDL_FALSE;
1423 
1424 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
1425  /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
1426  if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
1427  has_trigger_data = SDL_TRUE;
1428  }
1429 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
1430 
1431 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
1432  if (!has_trigger_data && ctx->wgi_correlated) {
1433  has_trigger_data = SDL_TRUE;
1434  }
1435 #endif /* SDL_JOYSTICK_RAWINPUT_WGI */
1436 
1437  if (!has_trigger_data) {
1438  HIDP_DATA *item = GetData(ctx->trigger_hack_index, ctx->data, data_length);
1439  if (item) {
1440  int left_trigger = joystick->naxes - 2;
1441  int right_trigger = joystick->naxes - 1;
1442  Sint16 value = (int)(Uint16)item->RawValue - 0x8000;
1443  if (value < 0) {
1444  value = -value * 2 - 32769;
1446  SDL_PrivateJoystickAxis(joystick, right_trigger, value);
1447  } else if (value > 0) {
1448  value = value * 2 - 32767;
1449  SDL_PrivateJoystickAxis(joystick, left_trigger, value);
1451  } else {
1454  }
1455  }
1456  }
1457  }
1458 
1459 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
1460  if (ctx->is_xinput) {
1461  ctx->match_state = match_state;
1462  ctx->last_state_packet = SDL_GetTicks();
1463  }
1464 #endif
1465 }
1466 
1467 static void
1468 RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
1469 {
1470 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
1471  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
1472  SDL_bool has_trigger_data = SDL_FALSE;
1473  SDL_bool correlated = SDL_FALSE;
1474  WindowsMatchState match_state_xinput;
1475  int guide_button = joystick->nbuttons - 1;
1476  int left_trigger = joystick->naxes - 2;
1477  int right_trigger = joystick->naxes - 1;
1478 
1479  RAWINPUT_FillMatchState(&match_state_xinput, ctx->match_state);
1480 
1481 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
1482  /* Parallel logic to WINDOWS_XINPUT below */
1483  RAWINPUT_UpdateWindowsGamingInput();
1484  if (ctx->wgi_correlated) {
1485  /* We have been previously correlated, ensure we are still matching, see comments in XINPUT section */
1486  if (RAWINPUT_WindowsGamingInputSlotMatches(&match_state_xinput, ctx->wgi_slot)) {
1487  ctx->wgi_uncorrelate_count = 0;
1488  } else {
1489  ++ctx->wgi_uncorrelate_count;
1490  /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event
1491  pumping can easily cause this to uncorrelate for a frame. 2 seemed reliable in my testing, but
1492  let's set it to 3 to be safe. An incorrect un-correlation will simply result in lower precision
1493  triggers for a frame. */
1494  if (ctx->wgi_uncorrelate_count >= 3) {
1495 #ifdef DEBUG_RAWINPUT
1496  SDL_Log("UN-Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, ctx->wgi_slot);
1497 #endif
1498  RAWINPUT_MarkWindowsGamingInputSlotFree(ctx->wgi_slot);
1499  ctx->wgi_correlated = SDL_FALSE;
1500  ctx->wgi_correlation_count = 0;
1501  /* Force release of Guide button, it can't possibly be down on this device now. */
1502  /* It gets left down if we were actually correlated incorrectly and it was released on the WindowsGamingInput
1503  device but we didn't get a state packet. */
1504  if (ctx->guide_hack) {
1506  }
1507  }
1508  }
1509  }
1510  if (!ctx->wgi_correlated) {
1511  SDL_bool new_correlation_count = 0;
1512  if (RAWINPUT_MissingWindowsGamingInputSlot()) {
1513  Uint8 correlation_id;
1514  WindowsGamingInputGamepadState *slot_idx;
1515  if (RAWINPUT_GuessWindowsGamingInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) {
1516  /* we match exactly one WindowsGamingInput device */
1517  /* Probably can do without wgi_correlation_count, just check and clear wgi_slot to NULL, unless we need
1518  even more frames to be sure. */
1519  if (ctx->wgi_correlation_count && ctx->wgi_slot == slot_idx) {
1520  /* was correlated previously, and still the same device */
1521  if (ctx->wgi_correlation_id + 1 == correlation_id) {
1522  /* no one else was correlated in the meantime */
1523  new_correlation_count = ctx->wgi_correlation_count + 1;
1524  if (new_correlation_count == 2) {
1525  /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
1526  ctx->wgi_correlated = SDL_TRUE;
1527 #ifdef DEBUG_RAWINPUT
1528  SDL_Log("Correlated joystick %d to WindowsGamingInput device #%d\n", joystick->instance_id, slot_idx);
1529 #endif
1530  correlated = SDL_TRUE;
1531  RAWINPUT_MarkWindowsGamingInputSlotUsed(ctx->wgi_slot, ctx);
1532  /* If the generalized Guide button was using us, it doesn't need to anymore */
1533  if (guide_button_candidate.joystick == joystick)
1534  guide_button_candidate.joystick = NULL;
1535  if (guide_button_candidate.last_joystick == joystick)
1536  guide_button_candidate.last_joystick = NULL;
1537  }
1538  } else {
1539  /* someone else also possibly correlated to this device, start over */
1540  new_correlation_count = 1;
1541  }
1542  } else {
1543  /* new possible correlation */
1544  new_correlation_count = 1;
1545  ctx->wgi_slot = slot_idx;
1546  }
1547  ctx->wgi_correlation_id = correlation_id;
1548  } else {
1549  /* Match multiple WindowsGamingInput devices, or none (possibly due to no buttons pressed) */
1550  }
1551  }
1552  ctx->wgi_correlation_count = new_correlation_count;
1553  } else {
1554  correlated = SDL_TRUE;
1555  }
1556 #endif /* SDL_JOYSTICK_RAWINPUT_WGI */
1557 
1558 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
1559  /* Parallel logic to WINDOWS_GAMING_INPUT above */
1560  if (ctx->xinput_enabled) {
1561  RAWINPUT_UpdateXInput();
1562  if (ctx->xinput_correlated) {
1563  /* We have been previously correlated, ensure we are still matching */
1564  /* This is required to deal with two (mostly) un-preventable mis-correlation situations:
1565  A) Since the HID data stream does not provide an initial state (but polling XInput does), if we open
1566  5 controllers (#1-4 XInput mapped, #5 is not), and controller 1 had the A button down (and we don't
1567  know), and the user presses A on controller #5, we'll see exactly 1 controller with A down (#5) and
1568  exactly 1 XInput device with A down (#1), and incorrectly correlate. This code will then un-correlate
1569  when A is released from either controller #1 or #5.
1570  B) Since the app may not open all controllers, we could have a similar situation where only controller #5
1571  is opened, and the user holds A on controllers #1 and #5 simultaneously - again we see only 1 controller
1572  with A down and 1 XInput device with A down, and incorrectly correlate. This should be very unusual
1573  (only when apps do not open all controllers, yet are listening to Guide button presses, yet
1574  for some reason want to ignore guide button presses on the un-opened controllers, yet users are
1575  pressing buttons on the unopened controllers), and will resolve itself when either button is released
1576  and we un-correlate. We could prevent this by processing the state packets for *all* controllers,
1577  even un-opened ones, as that would allow more precise correlation.
1578  */
1579  if (RAWINPUT_XInputSlotMatches(&match_state_xinput, ctx->xinput_slot)) {
1580  ctx->xinput_uncorrelate_count = 0;
1581  } else {
1582  ++ctx->xinput_uncorrelate_count;
1583  /* Only un-correlate if this is consistent over multiple Update() calls - the timing of polling/event
1584  pumping can easily cause this to uncorrelate for a frame. 2 seemed reliable in my testing, but
1585  let's set it to 3 to be safe. An incorrect un-correlation will simply result in lower precision
1586  triggers for a frame. */
1587  if (ctx->xinput_uncorrelate_count >= 3) {
1588 #ifdef DEBUG_RAWINPUT
1589  SDL_Log("UN-Correlated joystick %d to XInput device #%d\n", joystick->instance_id, ctx->xinput_slot);
1590 #endif
1591  RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot);
1592  ctx->xinput_correlated = SDL_FALSE;
1593  ctx->xinput_correlation_count = 0;
1594  /* Force release of Guide button, it can't possibly be down on this device now. */
1595  /* It gets left down if we were actually correlated incorrectly and it was released on the XInput
1596  device but we didn't get a state packet. */
1597  if (ctx->guide_hack) {
1599  }
1600  }
1601  }
1602  }
1603  if (!ctx->xinput_correlated) {
1604  Uint8 new_correlation_count = 0;
1605  if (RAWINPUT_MissingXInputSlot()) {
1606  Uint8 correlation_id = 0;
1607  Uint8 slot_idx = 0;
1608  if (RAWINPUT_GuessXInputSlot(&match_state_xinput, &correlation_id, &slot_idx)) {
1609  /* we match exactly one XInput device */
1610  /* Probably can do without xinput_correlation_count, just check and clear xinput_slot to ANY, unless
1611  we need even more frames to be sure */
1612  if (ctx->xinput_correlation_count && ctx->xinput_slot == slot_idx) {
1613  /* was correlated previously, and still the same device */
1614  if (ctx->xinput_correlation_id + 1 == correlation_id) {
1615  /* no one else was correlated in the meantime */
1616  new_correlation_count = ctx->xinput_correlation_count + 1;
1617  if (new_correlation_count == 2) {
1618  /* correlation stayed steady and uncontested across multiple frames, guaranteed match */
1619  ctx->xinput_correlated = SDL_TRUE;
1620 #ifdef DEBUG_RAWINPUT
1621  SDL_Log("Correlated joystick %d to XInput device #%d\n", joystick->instance_id, slot_idx);
1622 #endif
1623  correlated = SDL_TRUE;
1624  RAWINPUT_MarkXInputSlotUsed(ctx->xinput_slot);
1625  /* If the generalized Guide button was using us, it doesn't need to anymore */
1626  if (guide_button_candidate.joystick == joystick)
1627  guide_button_candidate.joystick = NULL;
1628  if (guide_button_candidate.last_joystick == joystick)
1629  guide_button_candidate.last_joystick = NULL;
1630  }
1631  } else {
1632  /* someone else also possibly correlated to this device, start over */
1633  new_correlation_count = 1;
1634  }
1635  } else {
1636  /* new possible correlation */
1637  new_correlation_count = 1;
1638  ctx->xinput_slot = slot_idx;
1639  }
1640  ctx->xinput_correlation_id = correlation_id;
1641  } else {
1642  /* Match multiple XInput devices, or none (possibly due to no buttons pressed) */
1643  }
1644  }
1645  ctx->xinput_correlation_count = new_correlation_count;
1646  } else {
1647  correlated = SDL_TRUE;
1648  }
1649  }
1650 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
1651 
1652  /* Poll for trigger data once (not per-state-packet) */
1653 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
1654  /* Prefer XInput over WindowsGamingInput, it continues to provide data in the background */
1655  if (!has_trigger_data && ctx->xinput_enabled && ctx->xinput_correlated) {
1656  RAWINPUT_UpdateXInput();
1657  if (xinput_state[ctx->xinput_slot].connected) {
1658  XINPUT_BATTERY_INFORMATION_EX *battery_info = &xinput_state[ctx->xinput_slot].battery;
1659 
1660  if (ctx->guide_hack) {
1661  SDL_PrivateJoystickButton(joystick, guide_button, (xinput_state[ctx->xinput_slot].state.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
1662  }
1663  if (ctx->trigger_hack) {
1664  SDL_PrivateJoystickAxis(joystick, left_trigger, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bLeftTrigger * 257) - 32768);
1665  SDL_PrivateJoystickAxis(joystick, right_trigger, ((int)xinput_state[ctx->xinput_slot].state.Gamepad.bRightTrigger * 257) - 32768);
1666  }
1667  has_trigger_data = SDL_TRUE;
1668 
1669  if (battery_info->BatteryType != BATTERY_TYPE_UNKNOWN) {
1671  if (battery_info->BatteryType == BATTERY_TYPE_WIRED) {
1672  ePowerLevel = SDL_JOYSTICK_POWER_WIRED;
1673  } else {
1674  switch (battery_info->BatteryLevel) {
1675  case BATTERY_LEVEL_EMPTY:
1676  ePowerLevel = SDL_JOYSTICK_POWER_EMPTY;
1677  break;
1678  case BATTERY_LEVEL_LOW:
1679  ePowerLevel = SDL_JOYSTICK_POWER_LOW;
1680  break;
1681  case BATTERY_LEVEL_MEDIUM:
1682  ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM;
1683  break;
1684  default:
1685  case BATTERY_LEVEL_FULL:
1686  ePowerLevel = SDL_JOYSTICK_POWER_FULL;
1687  break;
1688  }
1689  }
1691  }
1692  }
1693  }
1694 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
1695 
1696 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
1697  if (!has_trigger_data && ctx->wgi_correlated) {
1698  RAWINPUT_UpdateWindowsGamingInput(); /* May detect disconnect / cause uncorrelation */
1699  if (ctx->wgi_correlated) { /* Still connected */
1700  struct __x_ABI_CWindows_CGaming_CInput_CGamepadReading *state = &ctx->wgi_slot->state;
1701 
1702  if (ctx->guide_hack) {
1703  SDL_PrivateJoystickButton(joystick, guide_button, (state->Buttons & GamepadButtons_GUIDE) ? SDL_PRESSED : SDL_RELEASED);
1704  }
1705  if (ctx->trigger_hack) {
1706  SDL_PrivateJoystickAxis(joystick, left_trigger, ((int)(state->LeftTrigger * SDL_MAX_UINT16)) - 32768);
1707  SDL_PrivateJoystickAxis(joystick, right_trigger, ((int)(state->RightTrigger * SDL_MAX_UINT16)) - 32768);
1708  }
1709  has_trigger_data = SDL_TRUE;
1710  }
1711  }
1712 #endif /* SDL_JOYSTICK_RAWINPUT_WGI */
1713 
1714  if (!correlated) {
1715  if (!guide_button_candidate.joystick ||
1716  (ctx->last_state_packet && (
1717  !guide_button_candidate.last_state_packet ||
1718  SDL_TICKS_PASSED(ctx->last_state_packet, guide_button_candidate.last_state_packet)
1719  ))
1720  ) {
1721  guide_button_candidate.joystick = joystick;
1722  guide_button_candidate.last_state_packet = ctx->last_state_packet;
1723  }
1724  }
1725 #endif /* SDL_JOYSTICK_RAWINPUT_MATCHING */
1726 }
1727 
1728 static void
1729 RAWINPUT_JoystickUpdate(SDL_Joystick *joystick)
1730 {
1731  RAWINPUT_UpdateOtherAPIs(joystick);
1732 }
1733 
1734 static void
1735 RAWINPUT_JoystickClose(SDL_Joystick *joystick)
1736 {
1737  RAWINPUT_DeviceContext *ctx = joystick->hwdata;
1738 
1739 #ifdef SDL_JOYSTICK_RAWINPUT_MATCHING
1740  if (guide_button_candidate.joystick == joystick)
1741  guide_button_candidate.joystick = NULL;
1742  if (guide_button_candidate.last_joystick == joystick)
1743  guide_button_candidate.last_joystick = NULL;
1744 #endif
1745 
1746  if (ctx) {
1747  SDL_RAWINPUT_Device *device;
1748 
1749 #ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
1750  xinput_device_change = SDL_TRUE;
1751  if (ctx->xinput_enabled) {
1752  if (ctx->xinput_correlated) {
1753  RAWINPUT_MarkXInputSlotFree(ctx->xinput_slot);
1754  }
1755  WIN_UnloadXInputDLL();
1756  }
1757 #endif
1758 #ifdef SDL_JOYSTICK_RAWINPUT_WGI
1759  RAWINPUT_QuitWindowsGamingInput(ctx);
1760 #endif
1761 
1762  device = ctx->device;
1763  if (device) {
1764  SDL_assert(device->joystick == joystick);
1765  device->joystick = NULL;
1766  RAWINPUT_ReleaseDevice(device);
1767  }
1768 
1769  SDL_free(ctx->data);
1770  SDL_free(ctx->button_indices);
1771  SDL_free(ctx->axis_indices);
1772  SDL_free(ctx->hat_indices);
1773  SDL_free(ctx);
1774  joystick->hwdata = NULL;
1775  }
1776 }
1777 
1778 SDL_bool
1780 {
1781  RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
1782  int i;
1783 
1784  for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
1785  rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
1786  rid[i].usUsage = subscribed_devices[i];
1787  rid[i].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK; /* Receive messages when in background, including device add/remove */
1788  rid[i].hwndTarget = hWnd;
1789  }
1790 
1791  if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
1792  SDL_SetError("Couldn't register for raw input events");
1793  return SDL_FALSE;
1794  }
1795  return SDL_TRUE;
1796 }
1797 
1798 void
1800 {
1801  int i;
1802  RAWINPUTDEVICE rid[SDL_arraysize(subscribed_devices)];
1803 
1804  for (i = 0; i < SDL_arraysize(subscribed_devices); i++) {
1805  rid[i].usUsagePage = USB_USAGEPAGE_GENERIC_DESKTOP;
1806  rid[i].usUsage = subscribed_devices[i];
1807  rid[i].dwFlags = RIDEV_REMOVE;
1808  rid[i].hwndTarget = NULL;
1809  }
1810 
1811  if (!RegisterRawInputDevices(rid, SDL_arraysize(rid), sizeof(RAWINPUTDEVICE))) {
1812  SDL_SetError("Couldn't unregister for raw input events");
1813  return;
1814  }
1815 }
1816 
1817 LRESULT CALLBACK
1818 RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1819 {
1820  LRESULT result = -1;
1821 
1822  SDL_LockMutex(SDL_RAWINPUT_mutex);
1823 
1824  if (SDL_RAWINPUT_inited) {
1825  switch (msg) {
1826  case WM_INPUT_DEVICE_CHANGE:
1827  {
1828  HANDLE hDevice = (HANDLE)lParam;
1829  switch (wParam) {
1830  case GIDC_ARRIVAL:
1831  RAWINPUT_AddDevice(hDevice);
1832  break;
1833  case GIDC_REMOVAL:
1834  {
1835  SDL_RAWINPUT_Device *device;
1836  device = RAWINPUT_DeviceFromHandle(hDevice);
1837  if (device) {
1838  RAWINPUT_DelDevice(device, SDL_TRUE);
1839  }
1840  break;
1841  }
1842  default:
1843  break;
1844  }
1845  }
1846  result = 0;
1847  break;
1848 
1849  case WM_INPUT:
1850  {
1851  Uint8 data[sizeof(RAWINPUTHEADER) + sizeof(RAWHID) + USB_PACKET_LENGTH];
1852  UINT buffer_size = SDL_arraysize(data);
1853 
1854  if ((int)GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &buffer_size, sizeof(RAWINPUTHEADER)) > 0) {
1855  PRAWINPUT raw_input = (PRAWINPUT)data;
1856  SDL_RAWINPUT_Device *device = RAWINPUT_DeviceFromHandle(raw_input->header.hDevice);
1857  if (device) {
1858  SDL_Joystick *joystick = device->joystick;
1859  if (joystick) {
1860  RAWINPUT_HandleStatePacket(joystick, raw_input->data.hid.bRawData, raw_input->data.hid.dwSizeHid);
1861  }
1862  }
1863  }
1864  }
1865  result = 0;
1866  break;
1867  }
1868  }
1869 
1870  SDL_UnlockMutex(SDL_RAWINPUT_mutex);
1871 
1872  if (result >= 0) {
1873  return result;
1874  }
1875  return CallWindowProc(DefWindowProc, hWnd, msg, wParam, lParam);
1876 }
1877 
1878 static void
1879 RAWINPUT_JoystickQuit(void)
1880 {
1881  if (!SDL_RAWINPUT_inited) {
1882  return;
1883  }
1884 
1885  SDL_LockMutex(SDL_RAWINPUT_mutex);
1886 
1887  while (SDL_RAWINPUT_devices) {
1888  RAWINPUT_DelDevice(SDL_RAWINPUT_devices, SDL_FALSE);
1889  }
1890 
1891  WIN_UnloadHIDDLL();
1892 
1893  SDL_RAWINPUT_numjoysticks = 0;
1894 
1895  SDL_RAWINPUT_inited = SDL_FALSE;
1896 
1897  SDL_UnlockMutex(SDL_RAWINPUT_mutex);
1898  SDL_DestroyMutex(SDL_RAWINPUT_mutex);
1899  SDL_RAWINPUT_mutex = NULL;
1900 }
1901 
1902 static SDL_bool
1903 RAWINPUT_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
1904 {
1905  return SDL_FALSE;
1906 }
1907 
1909 {
1910  RAWINPUT_JoystickInit,
1911  RAWINPUT_JoystickGetCount,
1912  RAWINPUT_JoystickDetect,
1913  RAWINPUT_JoystickGetDeviceName,
1914  RAWINPUT_JoystickGetDevicePlayerIndex,
1915  RAWINPUT_JoystickSetDevicePlayerIndex,
1916  RAWINPUT_JoystickGetDeviceGUID,
1917  RAWINPUT_JoystickGetDeviceInstanceID,
1918  RAWINPUT_JoystickOpen,
1919  RAWINPUT_JoystickRumble,
1920  RAWINPUT_JoystickRumbleTriggers,
1921  RAWINPUT_JoystickHasLED,
1922  RAWINPUT_JoystickSetLED,
1923  RAWINPUT_JoystickSetSensorsEnabled,
1924  RAWINPUT_JoystickUpdate,
1925  RAWINPUT_JoystickClose,
1926  RAWINPUT_JoystickQuit,
1927  RAWINPUT_JoystickGetGamepadMapping
1928 };
1929 
1930 #endif /* SDL_JOYSTICK_RAWINPUT */
1931 
1932 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:171
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:262
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:252
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_SetError
#define SDL_qsort
#define SDL_wcslen
#define SDL_LockMutex
#define SDL_malloc
#define SDL_realloc
#define SDL_CreateMutex
#define SDL_free
#define SDL_strcmp
#define SDL_strstr
#define SDL_GetHintBoolean
#define SDL_DestroyMutex
#define SDL_Log
#define SDL_calloc
#define SDL_UnlockMutex
#define SDL_SwapLE16(X)
Definition: SDL_endian.h:235
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
#define SDL_Unsupported()
Definition: SDL_error.h:89
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDL_PRESSED
Definition: SDL_events.h:50
@ SDL_CONTROLLER_BUTTON_B
@ SDL_CONTROLLER_BUTTON_BACK
@ SDL_CONTROLLER_BUTTON_LEFTSTICK
@ SDL_CONTROLLER_BUTTON_START
@ SDL_CONTROLLER_BUTTON_DPAD_LEFT
@ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
@ SDL_CONTROLLER_BUTTON_DPAD_DOWN
@ SDL_CONTROLLER_BUTTON_DPAD_UP
@ SDL_CONTROLLER_BUTTON_LEFTSHOULDER
@ SDL_CONTROLLER_BUTTON_DPAD_RIGHT
@ SDL_CONTROLLER_BUTTON_X
@ SDL_CONTROLLER_BUTTON_RIGHTSTICK
@ SDL_CONTROLLER_BUTTON_Y
@ SDL_CONTROLLER_BUTTON_A
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
HidD_FreePreparsedData_t SDL_HidD_FreePreparsedData
Definition: SDL_hid.c:31
HidP_GetCaps_t SDL_HidP_GetCaps
Definition: SDL_hid.c:32
HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps
Definition: SDL_hid.c:33
HidD_GetString_t SDL_HidD_GetManufacturerString
Definition: SDL_hid.c:28
HidD_GetPreparsedData_t SDL_HidD_GetPreparsedData
Definition: SDL_hid.c:30
void WIN_UnloadHIDDLL(void)
Definition: SDL_hid.c:79
HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength
Definition: SDL_hid.c:35
HidP_GetValueCaps_t SDL_HidP_GetValueCaps
Definition: SDL_hid.c:34
HidP_GetData_t SDL_HidP_GetData
Definition: SDL_hid.c:36
int WIN_LoadHIDDLL(void)
Definition: SDL_hid.c:43
HidD_GetString_t SDL_HidD_GetProductString
Definition: SDL_hid.c:29
#define HIDP_STATUS_SUCCESS
Definition: SDL_hid.h:161
struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA
Definition: SDL_hid.h:32
@ HidP_Input
Definition: SDL_hid.h:43
#define USB_PACKET_LENGTH
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
#define SDL_HINT_JOYSTICK_HIDAPI_CORRELATE_XINPUT
A variable controlling whether the HIDAPI driver for XBox controllers on Windows should pull correlat...
Definition: SDL_hints.h:677
#define SDL_HINT_JOYSTICK_RAWINPUT
A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInpu...
Definition: SDL_hints.h:709
void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
int SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
SDL_JoystickID SDL_GetNextJoystickInstanceID()
Definition: SDL_joystick.c:262
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
char * SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
SDL_JoystickPowerLevel
Definition: SDL_joystick.h:98
@ SDL_JOYSTICK_POWER_FULL
Definition: SDL_joystick.h:103
@ SDL_JOYSTICK_POWER_MEDIUM
Definition: SDL_joystick.h:102
@ SDL_JOYSTICK_POWER_EMPTY
Definition: SDL_joystick.h:100
@ SDL_JOYSTICK_POWER_UNKNOWN
Definition: SDL_joystick.h:99
@ SDL_JOYSTICK_POWER_WIRED
Definition: SDL_joystick.h:104
@ SDL_JOYSTICK_POWER_LOW
Definition: SDL_joystick.h:101
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:390
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:388
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:389
#define SDL_HAT_UP
Definition: SDL_joystick.h:387
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:386
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLuint64EXT * result
GLuint index
GLuint const GLchar * name
GLsizeiptr size
GLuint GLsizei GLsizei * length
GLbyte green
GLsizei const GLfloat * value
GLenum cap
GLsizei const GLchar *const * string
SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
SDL_bool RAWINPUT_IsEnabled()
void RAWINPUT_UnregisterNotifications()
LRESULT CALLBACK RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
SDL_bool RAWINPUT_RegisterNotifications(HWND hWnd)
uint16_t Uint16
Definition: SDL_stdinc.h:197
int16_t Sint16
Definition: SDL_stdinc.h:191
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:360
uint8_t Uint8
Definition: SDL_stdinc.h:185
#define SDL_MAX_UINT16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:195
#define SDL_MIN_SINT16
Definition: SDL_stdinc.h:190
uint32_t Uint32
Definition: SDL_stdinc.h:209
#define SDL_HARDWARE_BUS_USB
SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.
Definition: SDL_timer.h:56
struct xkb_state * state
HRESULT WIN_CoInitialize(void)
void WIN_CoUninitialize(void)
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
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
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 int in j)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:163
EGLDeviceEXT * devices
Definition: eglext.h:621
EGLContext ctx
Definition: eglext.h:208
static SDL_AudioDeviceID device
Definition: loopwave.c:37
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 endif[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 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld_src SRC pixld MASK if DST_R else pixld DST_R endif if
USHORT NumberInputValueCaps
Definition: SDL_hid.h:141
USHORT NumberInputButtonCaps
Definition: SDL_hid.h:140
ULONG RawValue
Definition: SDL_hid.h:155
BOOLEAN On
Definition: SDL_hid.h:156
struct HIDP_VALUE_CAPS::@20::@23 NotRange
A type representing an atomic integer value. It is a struct so people don't accidentally use numeric ...
Definition: SDL_atomic.h:216
SDL_Joystick * joystick
SDL_Texture * axis
static SDL_Joystick * joystick
Definition: testjoystick.c:37
static NativeWindowFactory * factory
Definition: testnative.c:40
#define USB_USAGE_GENERIC_GAMEPAD
Definition: usb_ids.h:66
#define USB_USAGE_GENERIC_Z
Definition: usb_ids.h:72
#define USB_VENDOR_MICROSOFT
Definition: usb_ids.h:29
#define USB_USAGEPAGE_BUTTON
Definition: usb_ids.h:60
#define USB_PRODUCT_XBOX_ONE_RAW_INPUT_CONTROLLER
Definition: usb_ids.h:55
#define USB_USAGE_GENERIC_HAT
Definition: usb_ids.h:79
#define USB_USAGEPAGE_GENERIC_DESKTOP
Definition: usb_ids.h:59
typedef int(__stdcall *FARPROC)()