sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

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, &timestamp);
    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: */