SDL  2.0
SDL_windows_gaming_input.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_WGI
24 
25 #include "SDL_endian.h"
26 #include "SDL_events.h"
27 #include "../SDL_sysjoystick.h"
28 #include "../hidapi/SDL_hidapijoystick_c.h"
29 #include "SDL_rawinputjoystick_c.h"
30 
31 #include "../../core/windows/SDL_windows.h"
32 #define COBJMACROS
33 #include "windows.gaming.input.h"
34 
35 
36 struct joystick_hwdata
37 {
38  __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller;
39  __x_ABI_CWindows_CGaming_CInput_CIGameController *gamecontroller;
40  __x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo *battery;
41  __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
42  __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
43  UINT64 timestamp;
44 };
45 
46 typedef struct WindowsGamingInputControllerState {
47  SDL_JoystickID instance_id;
48  __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller;
49  char *name;
50  SDL_JoystickGUID guid;
52  int naxes;
53  int nhats;
54  int nbuttons;
55 } WindowsGamingInputControllerState;
56 
57 static struct {
58  __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics *statics;
59  __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics *arcade_stick_statics;
60  __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2 *arcade_stick_statics2;
61  __x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics *flight_stick_statics;
62  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics *gamepad_statics;
63  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2 *gamepad_statics2;
64  __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics *racing_wheel_statics;
65  __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2 *racing_wheel_statics2;
66  EventRegistrationToken controller_added_token;
67  EventRegistrationToken controller_removed_token;
68  int controller_count;
69  WindowsGamingInputControllerState *controllers;
70 } wgi;
71 
72 static const IID IID_IRawGameControllerStatics = { 0xEB8D0792, 0xE95A, 0x4B19, { 0xAF, 0xC7, 0x0A, 0x59, 0xF8, 0xBF, 0x75, 0x9E } };
73 static const IID IID_IRawGameController = { 0x7CAD6D91, 0xA7E1, 0x4F71, { 0x9A, 0x78, 0x33, 0xE9, 0xC5, 0xDF, 0xEA, 0x62 } };
74 static const IID IID_IRawGameController2 = { 0x43C0C035, 0xBB73, 0x4756, { 0xA7, 0x87, 0x3E, 0xD6, 0xBE, 0xA6, 0x17, 0xBD } };
75 static const IID IID_IEventHandler_RawGameController = { 0x00621c22, 0x42e8, 0x529f, { 0x92, 0x70, 0x83, 0x6b, 0x32, 0x93, 0x1d, 0x72 } };
76 static const IID IID_IGameController = { 0x1BAF6522, 0x5F64, 0x42C5, { 0x82, 0x67, 0xB9, 0xFE, 0x22, 0x15, 0xBF, 0xBD } };
77 static const IID IID_IGameControllerBatteryInfo = { 0xDCECC681, 0x3963, 0x4DA6, { 0x95, 0x5D, 0x55, 0x3F, 0x3B, 0x6F, 0x61, 0x61 } };
78 static const IID IID_IArcadeStickStatics = { 0x5C37B8C8, 0x37B1, 0x4AD8, { 0x94, 0x58, 0x20, 0x0F, 0x1A, 0x30, 0x01, 0x8E } };
79 static const IID IID_IArcadeStickStatics2 = { 0x52B5D744, 0xBB86, 0x445A, { 0xB5, 0x9C, 0x59, 0x6F, 0x0E, 0x2A, 0x49, 0xDF } };
80 static const IID IID_IArcadeStick = { 0xB14A539D, 0xBEFB, 0x4C81, { 0x80, 0x51, 0x15, 0xEC, 0xF3, 0xB1, 0x30, 0x36 } };
81 static const IID IID_IFlightStickStatics = { 0x5514924A, 0xFECC, 0x435E, { 0x83, 0xDC, 0x5C, 0xEC, 0x8A, 0x18, 0xA5, 0x20 } };
82 static const IID IID_IFlightStick = { 0xB4A2C01C, 0xB83B, 0x4459, { 0xA1, 0xA9, 0x97, 0xB0, 0x3C, 0x33, 0xDA, 0x7C } };
83 static const IID IID_IGamepadStatics = { 0x8BBCE529, 0xD49C, 0x39E9, { 0x95, 0x60, 0xE4, 0x7D, 0xDE, 0x96, 0xB7, 0xC8 } };
84 static const IID IID_IGamepadStatics2 = { 0x42676DC5, 0x0856, 0x47C4, { 0x92, 0x13, 0xB3, 0x95, 0x50, 0x4C, 0x3A, 0x3C } };
85 static const IID IID_IGamepad = { 0xBC7BB43C, 0x0A69, 0x3903, { 0x9E, 0x9D, 0xA5, 0x0F, 0x86, 0xA4, 0x5D, 0xE5 } };
86 static const IID IID_IRacingWheelStatics = { 0x3AC12CD5, 0x581B, 0x4936, { 0x9F, 0x94, 0x69, 0xF1, 0xE6, 0x51, 0x4C, 0x7D } };
87 static const IID IID_IRacingWheelStatics2 = { 0xE666BCAA, 0xEDFD, 0x4323, { 0xA9, 0xF6, 0x3C, 0x38, 0x40, 0x48, 0xD1, 0xED } };
88 static const IID IID_IRacingWheel = { 0xF546656F, 0xE106, 0x4C82, { 0xA9, 0x0F, 0x55, 0x40, 0x12, 0x90, 0x4B, 0x85 } };
89 
90 extern SDL_bool SDL_XINPUT_Enabled(void);
91 extern SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version);
92 
93 static SDL_bool
94 SDL_IsXInputDevice(Uint16 vendor, Uint16 product)
95 {
96  PRAWINPUTDEVICELIST raw_devices = NULL;
97  UINT i, raw_device_count = 0;
98  LONG vidpid = MAKELONG(vendor, product);
99 
100  if (!SDL_XINPUT_Enabled()) {
101  return SDL_FALSE;
102  }
103 
104  /* Go through RAWINPUT (WinXP and later) to find HID devices. */
105  if ((GetRawInputDeviceList(NULL, &raw_device_count, sizeof(RAWINPUTDEVICELIST)) == -1) || (!raw_device_count)) {
106  return SDL_FALSE; /* oh well. */
107  }
108 
109  raw_devices = (PRAWINPUTDEVICELIST)SDL_malloc(sizeof(RAWINPUTDEVICELIST) * raw_device_count);
110  if (raw_devices == NULL) {
111  SDL_OutOfMemory();
112  return SDL_FALSE;
113  }
114 
115  if (GetRawInputDeviceList(raw_devices, &raw_device_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
116  SDL_free(raw_devices);
117  raw_devices = NULL;
118  return SDL_FALSE; /* oh well. */
119  }
120 
121  for (i = 0; i < raw_device_count; i++) {
122  RID_DEVICE_INFO rdi;
123  char devName[MAX_PATH];
124  UINT rdiSize = sizeof(rdi);
125  UINT nameSize = SDL_arraysize(devName);
126 
127  rdi.cbSize = sizeof(rdi);
128  if ((raw_devices[i].dwType == RIM_TYPEHID) &&
129  (GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != ((UINT)-1)) &&
130  (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == vidpid) &&
131  (GetRawInputDeviceInfoA(raw_devices[i].hDevice, RIDI_DEVICENAME, devName, &nameSize) != ((UINT)-1)) &&
132  (SDL_strstr(devName, "IG_") != NULL)) {
133  return SDL_TRUE;
134  }
135  }
136 
137  return SDL_FALSE;
138 }
139 
140 static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_QueryInterface(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController * This, REFIID riid, void **ppvObject)
141 {
142  if (!ppvObject) {
143  return E_INVALIDARG;
144  }
145 
146  *ppvObject = NULL;
147  if (WIN_IsEqualIID(riid, &IID_IUnknown) || WIN_IsEqualIID(riid, &IID_IEventHandler_RawGameController)) {
148  *ppvObject = This;
149  return S_OK;
150  }
151  return E_NOINTERFACE;
152 }
153 
154 static ULONG STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_AddRef(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController * This)
155 {
156  return 1;
157 }
158 
159 static ULONG STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_Release(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController * This)
160 {
161  return 1;
162 }
163 
164 static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdded(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController * This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIRawGameController *e)
165 {
166  HRESULT hr;
167  __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL;
168 
169  hr = IUnknown_QueryInterface((IUnknown *)e, &IID_IRawGameController, (void **)&controller);
170  if (SUCCEEDED(hr)) {
171  char *name = NULL;
172  SDL_JoystickGUID guid;
173  Uint16 vendor = 0;
174  Uint16 product = 0;
175  Uint16 version = 0;
177  Uint16 *guid16 = (Uint16 *)guid.data;
178  __x_ABI_CWindows_CGaming_CInput_CIRawGameController2 *controller2 = NULL;
179  __x_ABI_CWindows_CGaming_CInput_CIGameController *gamecontroller = NULL;
180  SDL_bool ignore_joystick = SDL_FALSE;
181 
182  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_HardwareVendorId(controller, &vendor);
183  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_HardwareProductId(controller, &product);
184 
185  hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IRawGameController2, (void **)&controller2);
186  if (SUCCEEDED(hr)) {
187  HMODULE hModule = LoadLibraryA("combase.dll");
188  if (hModule != NULL) {
189  typedef PCWSTR (WINAPI *WindowsGetStringRawBuffer_t)(HSTRING string, UINT32 *length);
190  typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
191 
192  WindowsGetStringRawBuffer_t WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)GetProcAddress(hModule, "WindowsGetStringRawBuffer");
193  WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
194  if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) {
195  HSTRING hString;
196  hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_get_DisplayName(controller2, &hString);
197  if (SUCCEEDED(hr)) {
198  PCWSTR string = WindowsGetStringRawBufferFunc(hString, NULL);
199  if (string) {
200  name = WIN_StringToUTF8(string);
201  }
202  WindowsDeleteStringFunc(hString);
203  }
204  }
205  FreeLibrary(hModule);
206  }
207  __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2);
208  }
209 
210  hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IGameController, (void **)&gamecontroller);
211  if (SUCCEEDED(hr)) {
212  __x_ABI_CWindows_CGaming_CInput_CIArcadeStick *arcade_stick = NULL;
213  __x_ABI_CWindows_CGaming_CInput_CIFlightStick *flight_stick = NULL;
214  __x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad = NULL;
215  __x_ABI_CWindows_CGaming_CInput_CIRacingWheel *racing_wheel = NULL;
216 
217  if (wgi.gamepad_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, gamecontroller, &gamepad)) && gamepad) {
219  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(gamepad);
220  } else if (wgi.arcade_stick_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_FromGameController(wgi.arcade_stick_statics2, gamecontroller, &arcade_stick)) && arcade_stick) {
222  __x_ABI_CWindows_CGaming_CInput_CIArcadeStick_Release(arcade_stick);
223  } else if (wgi.flight_stick_statics && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_FromGameController(wgi.flight_stick_statics, gamecontroller, &flight_stick)) && flight_stick) {
225  __x_ABI_CWindows_CGaming_CInput_CIFlightStick_Release(flight_stick);
226  } else if (wgi.racing_wheel_statics2 && SUCCEEDED(__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_FromGameController(wgi.racing_wheel_statics2, gamecontroller, &racing_wheel)) && racing_wheel) {
228  __x_ABI_CWindows_CGaming_CInput_CIRacingWheel_Release(racing_wheel);
229  }
230  __x_ABI_CWindows_CGaming_CInput_CIGameController_Release(gamecontroller);
231  }
232 
233  /* FIXME: Is there any way to tell whether this is a Bluetooth device? */
234  *guid16++ = SDL_SwapLE16(SDL_HARDWARE_BUS_USB);
235  *guid16++ = 0;
236  *guid16++ = SDL_SwapLE16(vendor);
237  *guid16++ = 0;
238  *guid16++ = SDL_SwapLE16(product);
239  *guid16++ = 0;
240  *guid16++ = SDL_SwapLE16(version);
241  *guid16++ = 0;
242 
243  /* Note that this is a Windows Gaming Input device for special handling elsewhere */
244  guid.data[14] = 'w';
245  guid.data[15] = (Uint8)type;
246 
247 #ifdef SDL_JOYSTICK_HIDAPI
248  if (!ignore_joystick && HIDAPI_IsDevicePresent(vendor, product, version, name)) {
249  ignore_joystick = SDL_TRUE;
250  }
251 #endif
252 
253 #ifdef SDL_JOYSTICK_RAWINPUT
254  if (!ignore_joystick && RAWINPUT_IsDevicePresent(vendor, product, version, name)) {
255  ignore_joystick = SDL_TRUE;
256  }
257 #endif
258 
259  if (!ignore_joystick && SDL_DINPUT_JoystickPresent(vendor, product, version)) {
260  ignore_joystick = SDL_TRUE;
261  }
262 
263  if (!ignore_joystick && SDL_IsXInputDevice(vendor, product)) {
264  ignore_joystick = SDL_TRUE;
265  }
266 
267  if (!ignore_joystick && SDL_ShouldIgnoreJoystick(name, guid)) {
268  ignore_joystick = SDL_TRUE;
269  }
270 
271  if (ignore_joystick) {
272  SDL_free(name);
273  } else {
274  /* New device, add it */
275  WindowsGamingInputControllerState *controllers = SDL_realloc(wgi.controllers, sizeof(wgi.controllers[0]) * (wgi.controller_count + 1));
276  if (controllers) {
277  WindowsGamingInputControllerState *state = &controllers[wgi.controller_count];
279 
280  SDL_zerop(state);
281  state->instance_id = joystickID;
282  state->controller = controller;
283  state->name = name;
284  state->guid = guid;
285  state->type = type;
286 
287  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_ButtonCount(controller, &state->nbuttons);
288  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_AxisCount(controller, &state->naxes);
289  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_get_SwitchCount(controller, &state->nhats);
290 
291  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_AddRef(controller);
292 
293  ++wgi.controller_count;
294  wgi.controllers = controllers;
295 
296  SDL_PrivateJoystickAdded(joystickID);
297  }
298  }
299 
300  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller);
301  }
302  return S_OK;
303 }
304 
305 static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeRemoved(__FIEventHandler_1_Windows__CGaming__CInput__CRawGameController * This, IInspectable *sender, __x_ABI_CWindows_CGaming_CInput_CIRawGameController *e)
306 {
307  HRESULT hr;
308  __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL;
309 
310  hr = IUnknown_QueryInterface((IUnknown *)e, &IID_IRawGameController, (void **)&controller);
311  if (SUCCEEDED(hr)) {
312  int i;
313 
314  for (i = 0; i < wgi.controller_count ; i++) {
315  if (wgi.controllers[i].controller == controller) {
316  WindowsGamingInputControllerState *state = &wgi.controllers[i];
317  SDL_JoystickID joystickID = state->instance_id;
318 
319  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(state->controller);
320 
321  SDL_free(state->name);
322 
323  --wgi.controller_count;
324  if (i < wgi.controller_count) {
325  SDL_memmove(&wgi.controllers[i], &wgi.controllers[i + 1], (wgi.controller_count - i) * sizeof(wgi.controllers[i]));
326  }
327 
328  SDL_PrivateJoystickRemoved(joystickID);
329  break;
330  }
331  }
332 
333  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(controller);
334  }
335  return S_OK;
336 }
337 
338 static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameControllerVtbl controller_added_vtbl = {
339  IEventHandler_CRawGameControllerVtbl_QueryInterface,
340  IEventHandler_CRawGameControllerVtbl_AddRef,
341  IEventHandler_CRawGameControllerVtbl_Release,
342  IEventHandler_CRawGameControllerVtbl_InvokeAdded
343 };
344 static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController controller_added = {
345  &controller_added_vtbl
346 };
347 
348 static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameControllerVtbl controller_removed_vtbl = {
349  IEventHandler_CRawGameControllerVtbl_QueryInterface,
350  IEventHandler_CRawGameControllerVtbl_AddRef,
351  IEventHandler_CRawGameControllerVtbl_Release,
352  IEventHandler_CRawGameControllerVtbl_InvokeRemoved
353 };
354 static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController controller_removed = {
355  &controller_removed_vtbl
356 };
357 
358 static int
359 WGI_JoystickInit(void)
360 {
361  if (FAILED(WIN_CoInitialize())) {
362  return SDL_SetError("CoInitialize() failed");
363  }
364 
365  HRESULT hr;
366  HMODULE hModule = LoadLibraryA("combase.dll");
367  if (hModule != NULL) {
368  typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string);
369  typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
370  typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
371 
372  WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference");
373  RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
374  if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
375  LPTSTR pNamespace;
376  HSTRING_HEADER hNamespaceStringHeader;
377  HSTRING hNamespaceString;
378 
379  pNamespace = L"Windows.Gaming.Input.RawGameController";
380  hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
381  if (SUCCEEDED(hr)) {
382  hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, &wgi.statics);
383  if (!SUCCEEDED(hr)) {
384  SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%x", hr);
385  }
386  }
387 
388  pNamespace = L"Windows.Gaming.Input.ArcadeStick";
389  hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
390  if (SUCCEEDED(hr)) {
391  hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, &wgi.arcade_stick_statics);
392  if (SUCCEEDED(hr)) {
393  __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, &wgi.arcade_stick_statics2);
394  } else {
395  SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%x", hr);
396  }
397  }
398 
399  pNamespace = L"Windows.Gaming.Input.FlightStick";
400  hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
401  if (SUCCEEDED(hr)) {
402  hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, &wgi.flight_stick_statics);
403  if (!SUCCEEDED(hr)) {
404  SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%x", hr);
405  }
406  }
407 
408  pNamespace = L"Windows.Gaming.Input.Gamepad";
409  hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
410  if (SUCCEEDED(hr)) {
411  hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, &wgi.gamepad_statics);
412  if (SUCCEEDED(hr)) {
413  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, &wgi.gamepad_statics2);
414  } else {
415  SDL_SetError("Couldn't find IGamepadStatics: 0x%x", hr);
416  }
417  }
418 
419  pNamespace = L"Windows.Gaming.Input.RacingWheel";
420  hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
421  if (SUCCEEDED(hr)) {
422  hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, &wgi.racing_wheel_statics);
423  if (SUCCEEDED(hr)) {
424  __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, &wgi.racing_wheel_statics2);
425  } else {
426  SDL_SetError("Couldn't find IRacingWheelStatics: 0x%x", hr);
427  }
428  }
429  }
430  FreeLibrary(hModule);
431  }
432 
433  if (wgi.statics) {
434  hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_add_RawGameControllerAdded(wgi.statics, &controller_added, &wgi.controller_added_token);
435  if (!SUCCEEDED(hr)) {
436  SDL_SetError("add_RawGameControllerAdded() failed: 0x%x\n", hr);
437  }
438 
439  hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_add_RawGameControllerRemoved(wgi.statics, &controller_removed, &wgi.controller_removed_token);
440  if (!SUCCEEDED(hr)) {
441  SDL_SetError("add_RawGameControllerRemoved() failed: 0x%x\n", hr);
442  }
443  }
444 
445  return 0;
446 }
447 
448 static int
449 WGI_JoystickGetCount(void)
450 {
451  return wgi.controller_count;
452 }
453 
454 static void
455 WGI_JoystickDetect(void)
456 {
457 }
458 
459 static const char *
460 WGI_JoystickGetDeviceName(int device_index)
461 {
462  return wgi.controllers[device_index].name;
463 }
464 
465 static int
466 WGI_JoystickGetDevicePlayerIndex(int device_index)
467 {
468  return -1;
469 }
470 
471 static void
472 WGI_JoystickSetDevicePlayerIndex(int device_index, int player_index)
473 {
474 }
475 
476 static SDL_JoystickGUID
477 WGI_JoystickGetDeviceGUID(int device_index)
478 {
479  return wgi.controllers[device_index].guid;
480 }
481 
482 static SDL_JoystickID
483 WGI_JoystickGetDeviceInstanceID(int device_index)
484 {
485  return wgi.controllers[device_index].instance_id;
486 }
487 
488 static int
489 WGI_JoystickOpen(SDL_Joystick * joystick, int device_index)
490 {
491  WindowsGamingInputControllerState *state = &wgi.controllers[device_index];
492  struct joystick_hwdata *hwdata;
493  boolean wireless = SDL_FALSE;
494 
495  hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
496  if (!hwdata) {
497  return SDL_OutOfMemory();
498  }
499  joystick->hwdata = hwdata;
500 
501  hwdata->controller = state->controller;
502  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_AddRef(hwdata->controller);
503  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(hwdata->controller, &IID_IGameController, (void **)&hwdata->gamecontroller);
504  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(hwdata->controller, &IID_IGameControllerBatteryInfo, (void **)&hwdata->battery);
505 
506  if (wgi.gamepad_statics2) {
507  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_FromGameController(wgi.gamepad_statics2, hwdata->gamecontroller, &hwdata->gamepad);
508  }
509 
510  if (hwdata->gamecontroller) {
511  __x_ABI_CWindows_CGaming_CInput_CIGameController_get_IsWireless(hwdata->gamecontroller, &wireless);
512  }
513 
514  /* Initialize the joystick capabilities */
515  joystick->nbuttons = state->nbuttons;
516  joystick->naxes = state->naxes;
517  joystick->nhats = state->nhats;
519 
520  if (wireless && hwdata->battery) {
521  HRESULT hr;
522  __x_ABI_CWindows_CDevices_CPower_CIBatteryReport *report;
523 
524  hr = __x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo_TryGetBatteryReport(hwdata->battery, &report);
525  if (SUCCEEDED(hr) && report) {
526  int full_capacity = 0, curr_capacity = 0;
527  __FIReference_1_int *full_capacityP, *curr_capacityP;
528 
529  hr = __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_get_FullChargeCapacityInMilliwattHours(report, &full_capacityP);
530  if (SUCCEEDED(hr)) {
531  __FIReference_1_int_get_Value(full_capacityP, &full_capacity);
532  __FIReference_1_int_Release(full_capacityP);
533  }
534 
535  hr = __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_get_RemainingCapacityInMilliwattHours(report, &curr_capacityP);
536  if (SUCCEEDED(hr)) {
537  __FIReference_1_int_get_Value(curr_capacityP, &curr_capacity);
538  __FIReference_1_int_Release(curr_capacityP);
539  }
540 
541  if (full_capacity > 0) {
542  float ratio = (float)curr_capacity / full_capacity;
543 
544  if (ratio <= 0.05f) {
545  joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
546  } else if (ratio <= 0.20f) {
547  joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
548  } else if (ratio <= 0.70f) {
549  joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
550  } else {
551  joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
552  }
553  }
554  __x_ABI_CWindows_CDevices_CPower_CIBatteryReport_Release(report);
555  }
556  }
557  return 0;
558 }
559 
560 static int
561 WGI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
562 {
563  struct joystick_hwdata *hwdata = joystick->hwdata;
564 
565  if (hwdata->gamepad) {
566  HRESULT hr;
567 
568  hwdata->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
569  hwdata->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
570  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, hwdata->vibration);
571  if (SUCCEEDED(hr)) {
572  return 0;
573  } else {
574  return SDL_SetError("Setting vibration failed: 0x%x\n", hr);
575  }
576  } else {
577  return SDL_Unsupported();
578  }
579 }
580 
581 static int
582 WGI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
583 {
584  struct joystick_hwdata *hwdata = joystick->hwdata;
585 
586  if (hwdata->gamepad) {
587  HRESULT hr;
588 
589  hwdata->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
590  hwdata->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
591  hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, hwdata->vibration);
592  if (SUCCEEDED(hr)) {
593  return 0;
594  } else {
595  return SDL_SetError("Setting vibration failed: 0x%x\n", hr);
596  }
597  } else {
598  return SDL_Unsupported();
599  }
600 }
601 
602 static SDL_bool
603 WGI_JoystickHasLED(SDL_Joystick * joystick)
604 {
605  return SDL_FALSE;
606 }
607 
608 static int
609 WGI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue)
610 {
611  return SDL_Unsupported();
612 }
613 
614 static int
615 WGI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
616 {
617  return SDL_Unsupported();
618 }
619 
620 static Uint8
621 ConvertHatValue(__x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition value)
622 {
623  switch (value) {
624  case GameControllerSwitchPosition_Up:
625  return SDL_HAT_UP;
626  case GameControllerSwitchPosition_UpRight:
627  return SDL_HAT_RIGHTUP;
628  case GameControllerSwitchPosition_Right:
629  return SDL_HAT_RIGHT;
630  case GameControllerSwitchPosition_DownRight:
631  return SDL_HAT_RIGHTDOWN;
632  case GameControllerSwitchPosition_Down:
633  return SDL_HAT_DOWN;
634  case GameControllerSwitchPosition_DownLeft:
635  return SDL_HAT_LEFTDOWN;
636  case GameControllerSwitchPosition_Left:
637  return SDL_HAT_LEFT;
638  case GameControllerSwitchPosition_UpLeft:
639  return SDL_HAT_LEFTUP;
640  default:
641  return SDL_HAT_CENTERED;
642  }
643 }
644 
645 static void
646 WGI_JoystickUpdate(SDL_Joystick * joystick)
647 {
648  struct joystick_hwdata *hwdata = joystick->hwdata;
649  HRESULT hr;
650  UINT32 nbuttons = joystick->nbuttons;
651  boolean *buttons = SDL_stack_alloc(boolean, nbuttons);
652  UINT32 nhats = joystick->nhats;
653  __x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition *hats = SDL_stack_alloc(__x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition, nhats);
654  UINT32 naxes = joystick->naxes;
655  DOUBLE *axes = SDL_stack_alloc(DOUBLE, naxes);
656  UINT64 timestamp;
657 
658  hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_GetCurrentReading(hwdata->controller, nbuttons, buttons, nhats, hats, naxes, axes, &timestamp);
659  if (SUCCEEDED(hr) && timestamp != hwdata->timestamp) {
660  UINT32 i;
661 
662  for (i = 0; i < nbuttons; ++i) {
664  }
665  for (i = 0; i < nhats; ++i) {
666  SDL_PrivateJoystickHat(joystick, i, ConvertHatValue(hats[i]));
667  }
668  for (i = 0; i < naxes; ++i) {
669  SDL_PrivateJoystickAxis(joystick, i, (int)(axes[i] * 65535) - 32768);
670  }
671  hwdata->timestamp = timestamp;
672  }
673 
677 }
678 
679 static void
680 WGI_JoystickClose(SDL_Joystick * joystick)
681 {
682  struct joystick_hwdata *hwdata = joystick->hwdata;
683 
684  if (hwdata) {
685  if (hwdata->controller) {
686  __x_ABI_CWindows_CGaming_CInput_CIRawGameController_Release(hwdata->controller);
687  }
688  if (hwdata->gamecontroller) {
689  __x_ABI_CWindows_CGaming_CInput_CIGameController_Release(hwdata->gamecontroller);
690  }
691  if (hwdata->battery) {
692  __x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo_Release(hwdata->battery);
693  }
694  if (hwdata->gamepad) {
695  __x_ABI_CWindows_CGaming_CInput_CIGamepad_Release(hwdata->gamepad);
696  }
697  SDL_free(hwdata);
698  }
699  joystick->hwdata = NULL;
700 }
701 
702 static void
703 WGI_JoystickQuit(void)
704 {
705  if (wgi.statics) {
706  while (wgi.controller_count > 0) {
707  IEventHandler_CRawGameControllerVtbl_InvokeRemoved(&controller_removed, NULL, (__x_ABI_CWindows_CGaming_CInput_CIRawGameController *)wgi.controllers[wgi.controller_count - 1].controller);
708  }
709  if (wgi.controllers) {
710  SDL_free(wgi.controllers);
711  }
712 
713  if (wgi.arcade_stick_statics) {
714  __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_Release(wgi.arcade_stick_statics);
715  }
716  if (wgi.arcade_stick_statics2) {
717  __x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics2_Release(wgi.arcade_stick_statics2);
718  }
719  if (wgi.flight_stick_statics) {
720  __x_ABI_CWindows_CGaming_CInput_CIFlightStickStatics_Release(wgi.flight_stick_statics);
721  }
722  if (wgi.gamepad_statics) {
723  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_Release(wgi.gamepad_statics);
724  }
725  if (wgi.gamepad_statics2) {
726  __x_ABI_CWindows_CGaming_CInput_CIGamepadStatics2_Release(wgi.gamepad_statics2);
727  }
728  if (wgi.racing_wheel_statics) {
729  __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_Release(wgi.racing_wheel_statics);
730  }
731  if (wgi.racing_wheel_statics2) {
732  __x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics2_Release(wgi.racing_wheel_statics2);
733  }
734 
735  __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerAdded(wgi.statics, wgi.controller_added_token);
736  __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_remove_RawGameControllerRemoved(wgi.statics, wgi.controller_removed_token);
737  __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_Release(wgi.statics);
738  }
739  SDL_zero(wgi);
740 
742 }
743 
744 static SDL_bool
745 WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
746 {
747  return SDL_FALSE;
748 }
749 
751 {
752  WGI_JoystickInit,
753  WGI_JoystickGetCount,
754  WGI_JoystickDetect,
755  WGI_JoystickGetDeviceName,
756  WGI_JoystickGetDevicePlayerIndex,
757  WGI_JoystickSetDevicePlayerIndex,
758  WGI_JoystickGetDeviceGUID,
759  WGI_JoystickGetDeviceInstanceID,
760  WGI_JoystickOpen,
761  WGI_JoystickRumble,
762  WGI_JoystickRumbleTriggers,
763  WGI_JoystickHasLED,
764  WGI_JoystickSetLED,
765  WGI_JoystickSetSensorsEnabled,
766  WGI_JoystickUpdate,
767  WGI_JoystickClose,
768  WGI_JoystickQuit,
769  WGI_JoystickGetGamepadMapping
770 };
771 
772 #endif /* SDL_JOYSTICK_WGI */
773 
774 /* vi: set ts=4 sw=4 expandtab: */
SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16 version)
#define SUCCEEDED(x)
Definition: SDL_directx.h:51
#define S_OK
Definition: SDL_directx.h:47
#define E_NOINTERFACE
Definition: SDL_directx.h:61
#define E_INVALIDARG
Definition: SDL_directx.h:67
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_SetError
#define SDL_wcslen
#define SDL_malloc
#define SDL_realloc
#define SDL_free
#define SDL_strstr
#define SDL_memmove
#define SDL_calloc
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
#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
const GLubyte GLuint red
Definition: SDL_glfuncs.h:80
SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
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)
SDL_bool SDL_ShouldIgnoreJoystick(const char *name, SDL_JoystickGUID guid)
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)
SDL_JoystickType
Definition: SDL_joystick.h:84
@ SDL_JOYSTICK_TYPE_UNKNOWN
Definition: SDL_joystick.h:85
@ SDL_JOYSTICK_TYPE_ARCADE_STICK
Definition: SDL_joystick.h:88
@ SDL_JOYSTICK_TYPE_WHEEL
Definition: SDL_joystick.h:87
@ SDL_JOYSTICK_TYPE_FLIGHT_STICK
Definition: SDL_joystick.h:89
@ SDL_JOYSTICK_TYPE_GAMECONTROLLER
Definition: SDL_joystick.h:86
@ 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_LEFTDOWN
Definition: SDL_joystick.h:394
#define SDL_HAT_LEFT
Definition: SDL_joystick.h:390
#define SDL_HAT_RIGHT
Definition: SDL_joystick.h:388
#define SDL_HAT_RIGHTUP
Definition: SDL_joystick.h:391
#define SDL_HAT_LEFTUP
Definition: SDL_joystick.h:393
Sint32 SDL_JoystickID
Definition: SDL_joystick.h:81
#define SDL_HAT_DOWN
Definition: SDL_joystick.h:389
#define SDL_HAT_RIGHTDOWN
Definition: SDL_joystick.h:392
#define SDL_HAT_UP
Definition: SDL_joystick.h:387
#define SDL_HAT_CENTERED
Definition: SDL_joystick.h:386
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLbyte GLbyte blue
GLuint const GLchar * name
GLuint GLsizei GLsizei * length
GLbyte green
GLsizei const GLfloat * value
GLsizei const GLchar *const * string
SDL_bool RAWINPUT_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name)
uint16_t Uint16
Definition: SDL_stdinc.h:197
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
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_zerop(x)
Definition: SDL_stdinc.h:427
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:361
SDL_JoystickDriver SDL_WGI_JoystickDriver
#define SDL_HARDWARE_BUS_USB
struct xkb_state * state
HRESULT WIN_CoInitialize(void)
void WIN_CoUninitialize(void)
BOOL WIN_IsEqualIID(REFIID a, REFIID b)
#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
SDL_bool SDL_XINPUT_Enabled(void)
#define NULL
Definition: begin_code.h:163
Uint8 data[16]
Definition: SDL_joystick.h:71
GCController __unsafe_unretained * controller
SDL_GameController * gamecontroller
static SDL_Joystick * joystick
Definition: testjoystick.c:37
static NativeWindowFactory * factory
Definition: testnative.c:40