SDL_windows_gaming_input.c (32550B)
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; 51 SDL_JoystickType type; 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; 176 SDL_JoystickType type = SDL_JOYSTICK_TYPE_UNKNOWN; 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) { 218 type = SDL_JOYSTICK_TYPE_GAMECONTROLLER; 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) { 221 type = SDL_JOYSTICK_TYPE_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) { 224 type = SDL_JOYSTICK_TYPE_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) { 227 type = SDL_JOYSTICK_TYPE_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]; 278 SDL_JoystickID joystickID = SDL_GetNextJoystickInstanceID(); 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; 518 joystick->epowerlevel = wireless ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED; 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, ×tamp); 659 if (SUCCEEDED(hr) && timestamp != hwdata->timestamp) { 660 UINT32 i; 661 662 for (i = 0; i < nbuttons; ++i) { 663 SDL_PrivateJoystickButton(joystick, i, buttons[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 674 SDL_stack_free(buttons); 675 SDL_stack_free(hats); 676 SDL_stack_free(axes); 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 741 WIN_CoUninitialize(); 742 } 743 744 static SDL_bool 745 WGI_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) 746 { 747 return SDL_FALSE; 748 } 749 750 SDL_JoystickDriver SDL_WGI_JoystickDriver = 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: */