twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

win32_joystick.c (26341B)


      1 //========================================================================
      2 // GLFW 3.3 Win32 - www.glfw.org
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
      6 //
      7 // This software is provided 'as-is', without any express or implied
      8 // warranty. In no event will the authors be held liable for any damages
      9 // arising from the use of this software.
     10 //
     11 // Permission is granted to anyone to use this software for any purpose,
     12 // including commercial applications, and to alter it and redistribute it
     13 // freely, subject to the following restrictions:
     14 //
     15 // 1. The origin of this software must not be misrepresented; you must not
     16 //    claim that you wrote the original software. If you use this software
     17 //    in a product, an acknowledgment in the product documentation would
     18 //    be appreciated but is not required.
     19 //
     20 // 2. Altered source versions must be plainly marked as such, and must not
     21 //    be misrepresented as being the original software.
     22 //
     23 // 3. This notice may not be removed or altered from any source
     24 //    distribution.
     25 //
     26 //========================================================================
     27 // Please use C89 style variable declarations in this file because VS 2010
     28 //========================================================================
     29 
     30 #include "internal.h"
     31 
     32 #include <stdio.h>
     33 #include <math.h>
     34 
     35 #define _GLFW_TYPE_AXIS     0
     36 #define _GLFW_TYPE_SLIDER   1
     37 #define _GLFW_TYPE_BUTTON   2
     38 #define _GLFW_TYPE_POV      3
     39 
     40 // Data produced with DirectInput device object enumeration
     41 //
     42 typedef struct _GLFWobjenumWin32
     43 {
     44     IDirectInputDevice8W*   device;
     45     _GLFWjoyobjectWin32*    objects;
     46     int                     objectCount;
     47     int                     axisCount;
     48     int                     sliderCount;
     49     int                     buttonCount;
     50     int                     povCount;
     51 } _GLFWobjenumWin32;
     52 
     53 // Define local copies of the necessary GUIDs
     54 //
     55 static const GUID _glfw_IID_IDirectInput8W =
     56     {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}};
     57 static const GUID _glfw_GUID_XAxis =
     58     {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     59 static const GUID _glfw_GUID_YAxis =
     60     {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     61 static const GUID _glfw_GUID_ZAxis =
     62     {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     63 static const GUID _glfw_GUID_RxAxis =
     64     {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     65 static const GUID _glfw_GUID_RyAxis =
     66     {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     67 static const GUID _glfw_GUID_RzAxis =
     68     {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     69 static const GUID _glfw_GUID_Slider =
     70     {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     71 static const GUID _glfw_GUID_POV =
     72     {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
     73 
     74 #define IID_IDirectInput8W _glfw_IID_IDirectInput8W
     75 #define GUID_XAxis _glfw_GUID_XAxis
     76 #define GUID_YAxis _glfw_GUID_YAxis
     77 #define GUID_ZAxis _glfw_GUID_ZAxis
     78 #define GUID_RxAxis _glfw_GUID_RxAxis
     79 #define GUID_RyAxis _glfw_GUID_RyAxis
     80 #define GUID_RzAxis _glfw_GUID_RzAxis
     81 #define GUID_Slider _glfw_GUID_Slider
     82 #define GUID_POV _glfw_GUID_POV
     83 
     84 // Object data array for our clone of c_dfDIJoystick
     85 // Generated with https://github.com/elmindreda/c_dfDIJoystick2
     86 //
     87 static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
     88 {
     89     { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     90     { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     91     { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     92     { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     93     { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     94     { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     95     { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     96     { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
     97     { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
     98     { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
     99     { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    100     { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    101     { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    102     { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    103     { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    104     { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    105     { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    106     { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    107     { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    108     { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    109     { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    110     { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    111     { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    112     { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    113     { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    114     { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    115     { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    116     { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    117     { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    118     { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    119     { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    120     { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    121     { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    122     { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    123     { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    124     { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    125     { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    126     { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    127     { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    128     { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    129     { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    130     { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    131     { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    132     { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
    133 };
    134 
    135 // Our clone of c_dfDIJoystick
    136 //
    137 static const DIDATAFORMAT _glfwDataFormat =
    138 {
    139     sizeof(DIDATAFORMAT),
    140     sizeof(DIOBJECTDATAFORMAT),
    141     DIDFT_ABSAXIS,
    142     sizeof(DIJOYSTATE),
    143     sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
    144     _glfwObjectDataFormats
    145 };
    146 
    147 // Returns a description fitting the specified XInput capabilities
    148 //
    149 static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
    150 {
    151     switch (xic->SubType)
    152     {
    153         case XINPUT_DEVSUBTYPE_WHEEL:
    154             return "XInput Wheel";
    155         case XINPUT_DEVSUBTYPE_ARCADE_STICK:
    156             return "XInput Arcade Stick";
    157         case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
    158             return "XInput Flight Stick";
    159         case XINPUT_DEVSUBTYPE_DANCE_PAD:
    160             return "XInput Dance Pad";
    161         case XINPUT_DEVSUBTYPE_GUITAR:
    162             return "XInput Guitar";
    163         case XINPUT_DEVSUBTYPE_DRUM_KIT:
    164             return "XInput Drum Kit";
    165         case XINPUT_DEVSUBTYPE_GAMEPAD:
    166         {
    167             if (xic->Flags & XINPUT_CAPS_WIRELESS)
    168                 return "Wireless Xbox Controller";
    169             else
    170                 return "Xbox Controller";
    171         }
    172     }
    173 
    174     return "Unknown XInput Device";
    175 }
    176 
    177 // Lexically compare device objects
    178 //
    179 static int compareJoystickObjects(const void* first, const void* second)
    180 {
    181     const _GLFWjoyobjectWin32* fo = first;
    182     const _GLFWjoyobjectWin32* so = second;
    183 
    184     if (fo->type != so->type)
    185         return fo->type - so->type;
    186 
    187     return fo->offset - so->offset;
    188 }
    189 
    190 // Checks whether the specified device supports XInput
    191 // Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
    192 //
    193 static GLFWbool supportsXInput(const GUID* guid)
    194 {
    195     UINT i, count = 0;
    196     RAWINPUTDEVICELIST* ridl;
    197     GLFWbool result = GLFW_FALSE;
    198 
    199     if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
    200         return GLFW_FALSE;
    201 
    202     ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
    203 
    204     if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
    205     {
    206         free(ridl);
    207         return GLFW_FALSE;
    208     }
    209 
    210     for (i = 0;  i < count;  i++)
    211     {
    212         RID_DEVICE_INFO rdi;
    213         char name[256];
    214         UINT size;
    215 
    216         if (ridl[i].dwType != RIM_TYPEHID)
    217             continue;
    218 
    219         ZeroMemory(&rdi, sizeof(rdi));
    220         rdi.cbSize = sizeof(rdi);
    221         size = sizeof(rdi);
    222 
    223         if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
    224                                          RIDI_DEVICEINFO,
    225                                          &rdi, &size) == -1)
    226         {
    227             continue;
    228         }
    229 
    230         if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
    231             continue;
    232 
    233         memset(name, 0, sizeof(name));
    234         size = sizeof(name);
    235 
    236         if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
    237                                          RIDI_DEVICENAME,
    238                                          name, &size) == -1)
    239         {
    240             break;
    241         }
    242 
    243         name[sizeof(name) - 1] = '\0';
    244         if (strstr(name, "IG_"))
    245         {
    246             result = GLFW_TRUE;
    247             break;
    248         }
    249     }
    250 
    251     free(ridl);
    252     return result;
    253 }
    254 
    255 // Frees all resources associated with the specified joystick
    256 //
    257 static void closeJoystick(_GLFWjoystick* js)
    258 {
    259     if (js->win32.device)
    260     {
    261         IDirectInputDevice8_Unacquire(js->win32.device);
    262         IDirectInputDevice8_Release(js->win32.device);
    263     }
    264 
    265     free(js->win32.objects);
    266 
    267     _glfwFreeJoystick(js);
    268     _glfwInputJoystick(js, GLFW_DISCONNECTED);
    269 }
    270 
    271 // DirectInput device object enumeration callback
    272 // Insights gleaned from SDL
    273 //
    274 static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
    275                                           void* user)
    276 {
    277     _GLFWobjenumWin32* data = user;
    278     _GLFWjoyobjectWin32* object = data->objects + data->objectCount;
    279 
    280     if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
    281     {
    282         DIPROPRANGE dipr;
    283 
    284         if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
    285             object->offset = DIJOFS_SLIDER(data->sliderCount);
    286         else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
    287             object->offset = DIJOFS_X;
    288         else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
    289             object->offset = DIJOFS_Y;
    290         else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
    291             object->offset = DIJOFS_Z;
    292         else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
    293             object->offset = DIJOFS_RX;
    294         else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
    295             object->offset = DIJOFS_RY;
    296         else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
    297             object->offset = DIJOFS_RZ;
    298         else
    299             return DIENUM_CONTINUE;
    300 
    301         ZeroMemory(&dipr, sizeof(dipr));
    302         dipr.diph.dwSize = sizeof(dipr);
    303         dipr.diph.dwHeaderSize = sizeof(dipr.diph);
    304         dipr.diph.dwObj = doi->dwType;
    305         dipr.diph.dwHow = DIPH_BYID;
    306         dipr.lMin = -32768;
    307         dipr.lMax =  32767;
    308 
    309         if (FAILED(IDirectInputDevice8_SetProperty(data->device,
    310                                                    DIPROP_RANGE,
    311                                                    &dipr.diph)))
    312         {
    313             return DIENUM_CONTINUE;
    314         }
    315 
    316         if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
    317         {
    318             object->type = _GLFW_TYPE_SLIDER;
    319             data->sliderCount++;
    320         }
    321         else
    322         {
    323             object->type = _GLFW_TYPE_AXIS;
    324             data->axisCount++;
    325         }
    326     }
    327     else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
    328     {
    329         object->offset = DIJOFS_BUTTON(data->buttonCount);
    330         object->type = _GLFW_TYPE_BUTTON;
    331         data->buttonCount++;
    332     }
    333     else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
    334     {
    335         object->offset = DIJOFS_POV(data->povCount);
    336         object->type = _GLFW_TYPE_POV;
    337         data->povCount++;
    338     }
    339 
    340     data->objectCount++;
    341     return DIENUM_CONTINUE;
    342 }
    343 
    344 // DirectInput device enumeration callback
    345 //
    346 static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
    347 {
    348     int jid = 0;
    349     DIDEVCAPS dc;
    350     DIPROPDWORD dipd;
    351     IDirectInputDevice8* device;
    352     _GLFWobjenumWin32 data;
    353     _GLFWjoystick* js;
    354     char guid[33];
    355     char name[256];
    356 
    357     for (jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    358     {
    359         _GLFWjoystick* js = _glfw.joysticks + jid;
    360         if (js->present)
    361         {
    362             if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0)
    363                 return DIENUM_CONTINUE;
    364         }
    365     }
    366 
    367     if (supportsXInput(&di->guidProduct))
    368         return DIENUM_CONTINUE;
    369 
    370     if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
    371                                           &di->guidInstance,
    372                                           &device,
    373                                           NULL)))
    374     {
    375         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device");
    376         return DIENUM_CONTINUE;
    377     }
    378 
    379     if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
    380     {
    381         _glfwInputError(GLFW_PLATFORM_ERROR,
    382                         "Win32: Failed to set device data format");
    383 
    384         IDirectInputDevice8_Release(device);
    385         return DIENUM_CONTINUE;
    386     }
    387 
    388     ZeroMemory(&dc, sizeof(dc));
    389     dc.dwSize = sizeof(dc);
    390 
    391     if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
    392     {
    393         _glfwInputError(GLFW_PLATFORM_ERROR,
    394                         "Win32: Failed to query device capabilities");
    395 
    396         IDirectInputDevice8_Release(device);
    397         return DIENUM_CONTINUE;
    398     }
    399 
    400     ZeroMemory(&dipd, sizeof(dipd));
    401     dipd.diph.dwSize = sizeof(dipd);
    402     dipd.diph.dwHeaderSize = sizeof(dipd.diph);
    403     dipd.diph.dwHow = DIPH_DEVICE;
    404     dipd.dwData = DIPROPAXISMODE_ABS;
    405 
    406     if (FAILED(IDirectInputDevice8_SetProperty(device,
    407                                                DIPROP_AXISMODE,
    408                                                &dipd.diph)))
    409     {
    410         _glfwInputError(GLFW_PLATFORM_ERROR,
    411                         "Win32: Failed to set device axis mode");
    412 
    413         IDirectInputDevice8_Release(device);
    414         return DIENUM_CONTINUE;
    415     }
    416 
    417     memset(&data, 0, sizeof(data));
    418     data.device = device;
    419     data.objects = calloc(dc.dwAxes + (size_t) dc.dwButtons + dc.dwPOVs,
    420                           sizeof(_GLFWjoyobjectWin32));
    421 
    422     if (FAILED(IDirectInputDevice8_EnumObjects(device,
    423                                                deviceObjectCallback,
    424                                                &data,
    425                                                DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
    426     {
    427         _glfwInputError(GLFW_PLATFORM_ERROR,
    428                         "Win32: Failed to enumerate device objects");
    429 
    430         IDirectInputDevice8_Release(device);
    431         free(data.objects);
    432         return DIENUM_CONTINUE;
    433     }
    434 
    435     qsort(data.objects, data.objectCount,
    436           sizeof(_GLFWjoyobjectWin32),
    437           compareJoystickObjects);
    438 
    439     if (!WideCharToMultiByte(CP_UTF8, 0,
    440                              di->tszInstanceName, -1,
    441                              name, sizeof(name),
    442                              NULL, NULL))
    443     {
    444         _glfwInputError(GLFW_PLATFORM_ERROR,
    445                         "Win32: Failed to convert joystick name to UTF-8");
    446 
    447         IDirectInputDevice8_Release(device);
    448         free(data.objects);
    449         return DIENUM_STOP;
    450     }
    451 
    452     // Generate a joystick GUID that matches the SDL 2.0.5+ one
    453     if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0)
    454     {
    455         sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000",
    456                 (uint8_t) di->guidProduct.Data1,
    457                 (uint8_t) (di->guidProduct.Data1 >> 8),
    458                 (uint8_t) (di->guidProduct.Data1 >> 16),
    459                 (uint8_t) (di->guidProduct.Data1 >> 24));
    460     }
    461     else
    462     {
    463         sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
    464                 name[0], name[1], name[2], name[3],
    465                 name[4], name[5], name[6], name[7],
    466                 name[8], name[9], name[10]);
    467     }
    468 
    469     js = _glfwAllocJoystick(name, guid,
    470                             data.axisCount + data.sliderCount,
    471                             data.buttonCount,
    472                             data.povCount);
    473     if (!js)
    474     {
    475         IDirectInputDevice8_Release(device);
    476         free(data.objects);
    477         return DIENUM_STOP;
    478     }
    479 
    480     js->win32.device = device;
    481     js->win32.guid = di->guidInstance;
    482     js->win32.objects = data.objects;
    483     js->win32.objectCount = data.objectCount;
    484 
    485     _glfwInputJoystick(js, GLFW_CONNECTED);
    486     return DIENUM_CONTINUE;
    487 }
    488 
    489 
    490 //////////////////////////////////////////////////////////////////////////
    491 //////                       GLFW internal API                      //////
    492 //////////////////////////////////////////////////////////////////////////
    493 
    494 // Initialize joystick interface
    495 //
    496 void _glfwInitJoysticksWin32(void)
    497 {
    498     if (_glfw.win32.dinput8.instance)
    499     {
    500         if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
    501                                       DIRECTINPUT_VERSION,
    502                                       &IID_IDirectInput8W,
    503                                       (void**) &_glfw.win32.dinput8.api,
    504                                       NULL)))
    505         {
    506             _glfwInputError(GLFW_PLATFORM_ERROR,
    507                             "Win32: Failed to create interface");
    508         }
    509     }
    510 
    511     _glfwDetectJoystickConnectionWin32();
    512 }
    513 
    514 // Close all opened joystick handles
    515 //
    516 void _glfwTerminateJoysticksWin32(void)
    517 {
    518     int jid;
    519 
    520     for (jid = GLFW_JOYSTICK_1;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    521         closeJoystick(_glfw.joysticks + jid);
    522 
    523     if (_glfw.win32.dinput8.api)
    524         IDirectInput8_Release(_glfw.win32.dinput8.api);
    525 }
    526 
    527 // Checks for new joysticks after DBT_DEVICEARRIVAL
    528 //
    529 void _glfwDetectJoystickConnectionWin32(void)
    530 {
    531     if (_glfw.win32.xinput.instance)
    532     {
    533         DWORD index;
    534 
    535         for (index = 0;  index < XUSER_MAX_COUNT;  index++)
    536         {
    537             int jid;
    538             char guid[33];
    539             XINPUT_CAPABILITIES xic;
    540             _GLFWjoystick* js;
    541 
    542             for (jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    543             {
    544                 if (_glfw.joysticks[jid].present &&
    545                     _glfw.joysticks[jid].win32.device == NULL &&
    546                     _glfw.joysticks[jid].win32.index == index)
    547                 {
    548                     break;
    549                 }
    550             }
    551 
    552             if (jid <= GLFW_JOYSTICK_LAST)
    553                 continue;
    554 
    555             if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
    556                 continue;
    557 
    558             // Generate a joystick GUID that matches the SDL 2.0.5+ one
    559             sprintf(guid, "78696e707574%02x000000000000000000",
    560                     xic.SubType & 0xff);
    561 
    562             js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1);
    563             if (!js)
    564                 continue;
    565 
    566             js->win32.index = index;
    567 
    568             _glfwInputJoystick(js, GLFW_CONNECTED);
    569         }
    570     }
    571 
    572     if (_glfw.win32.dinput8.api)
    573     {
    574         if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
    575                                              DI8DEVCLASS_GAMECTRL,
    576                                              deviceCallback,
    577                                              NULL,
    578                                              DIEDFL_ALLDEVICES)))
    579         {
    580             _glfwInputError(GLFW_PLATFORM_ERROR,
    581                             "Failed to enumerate DirectInput8 devices");
    582             return;
    583         }
    584     }
    585 }
    586 
    587 // Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
    588 //
    589 void _glfwDetectJoystickDisconnectionWin32(void)
    590 {
    591     int jid;
    592 
    593     for (jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    594     {
    595         _GLFWjoystick* js = _glfw.joysticks + jid;
    596         if (js->present)
    597             _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
    598     }
    599 }
    600 
    601 
    602 //////////////////////////////////////////////////////////////////////////
    603 //////                       GLFW platform API                      //////
    604 //////////////////////////////////////////////////////////////////////////
    605 
    606 int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
    607 {
    608     if (js->win32.device)
    609     {
    610         int i, ai = 0, bi = 0, pi = 0;
    611         HRESULT result;
    612         DIJOYSTATE state;
    613 
    614         IDirectInputDevice8_Poll(js->win32.device);
    615         result = IDirectInputDevice8_GetDeviceState(js->win32.device,
    616                                                     sizeof(state),
    617                                                     &state);
    618         if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
    619         {
    620             IDirectInputDevice8_Acquire(js->win32.device);
    621             IDirectInputDevice8_Poll(js->win32.device);
    622             result = IDirectInputDevice8_GetDeviceState(js->win32.device,
    623                                                         sizeof(state),
    624                                                         &state);
    625         }
    626 
    627         if (FAILED(result))
    628         {
    629             closeJoystick(js);
    630             return GLFW_FALSE;
    631         }
    632 
    633         if (mode == _GLFW_POLL_PRESENCE)
    634             return GLFW_TRUE;
    635 
    636         for (i = 0;  i < js->win32.objectCount;  i++)
    637         {
    638             const void* data = (char*) &state + js->win32.objects[i].offset;
    639 
    640             switch (js->win32.objects[i].type)
    641             {
    642                 case _GLFW_TYPE_AXIS:
    643                 case _GLFW_TYPE_SLIDER:
    644                 {
    645                     const float value = (*((LONG*) data) + 0.5f) / 32767.5f;
    646                     _glfwInputJoystickAxis(js, ai, value);
    647                     ai++;
    648                     break;
    649                 }
    650 
    651                 case _GLFW_TYPE_BUTTON:
    652                 {
    653                     const char value = (*((BYTE*) data) & 0x80) != 0;
    654                     _glfwInputJoystickButton(js, bi, value);
    655                     bi++;
    656                     break;
    657                 }
    658 
    659                 case _GLFW_TYPE_POV:
    660                 {
    661                     const int states[9] =
    662                     {
    663                         GLFW_HAT_UP,
    664                         GLFW_HAT_RIGHT_UP,
    665                         GLFW_HAT_RIGHT,
    666                         GLFW_HAT_RIGHT_DOWN,
    667                         GLFW_HAT_DOWN,
    668                         GLFW_HAT_LEFT_DOWN,
    669                         GLFW_HAT_LEFT,
    670                         GLFW_HAT_LEFT_UP,
    671                         GLFW_HAT_CENTERED
    672                     };
    673 
    674                     // Screams of horror are appropriate at this point
    675                     int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
    676                     if (state < 0 || state > 8)
    677                         state = 8;
    678 
    679                     _glfwInputJoystickHat(js, pi, states[state]);
    680                     pi++;
    681                     break;
    682                 }
    683             }
    684         }
    685     }
    686     else
    687     {
    688         int i, dpad = 0;
    689         DWORD result;
    690         XINPUT_STATE xis;
    691         const WORD buttons[10] =
    692         {
    693             XINPUT_GAMEPAD_A,
    694             XINPUT_GAMEPAD_B,
    695             XINPUT_GAMEPAD_X,
    696             XINPUT_GAMEPAD_Y,
    697             XINPUT_GAMEPAD_LEFT_SHOULDER,
    698             XINPUT_GAMEPAD_RIGHT_SHOULDER,
    699             XINPUT_GAMEPAD_BACK,
    700             XINPUT_GAMEPAD_START,
    701             XINPUT_GAMEPAD_LEFT_THUMB,
    702             XINPUT_GAMEPAD_RIGHT_THUMB
    703         };
    704 
    705         result = XInputGetState(js->win32.index, &xis);
    706         if (result != ERROR_SUCCESS)
    707         {
    708             if (result == ERROR_DEVICE_NOT_CONNECTED)
    709                 closeJoystick(js);
    710 
    711             return GLFW_FALSE;
    712         }
    713 
    714         if (mode == _GLFW_POLL_PRESENCE)
    715             return GLFW_TRUE;
    716 
    717         _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f);
    718         _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f);
    719         _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f);
    720         _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f);
    721         _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f);
    722         _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f);
    723 
    724         for (i = 0;  i < 10;  i++)
    725         {
    726             const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
    727             _glfwInputJoystickButton(js, i, value);
    728         }
    729 
    730         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
    731             dpad |= GLFW_HAT_UP;
    732         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
    733             dpad |= GLFW_HAT_RIGHT;
    734         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
    735             dpad |= GLFW_HAT_DOWN;
    736         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
    737             dpad |= GLFW_HAT_LEFT;
    738 
    739         _glfwInputJoystickHat(js, 0, dpad);
    740     }
    741 
    742     return GLFW_TRUE;
    743 }
    744 
    745 void _glfwPlatformUpdateGamepadGUID(char* guid)
    746 {
    747     if (strcmp(guid + 20, "504944564944") == 0)
    748     {
    749         char original[33];
    750         strncpy(original, guid, sizeof(original) - 1);
    751         sprintf(guid, "03000000%.4s0000%.4s000000000000",
    752                 original, original + 4);
    753     }
    754 }
    755