minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

win32_joystick.c (26711B)


      1 //========================================================================
      2 // GLFW 3.4 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 
     28 #include "internal.h"
     29 
     30 #if defined(_GLFW_WIN32)
     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 = _glfw_calloc(count, sizeof(RAWINPUTDEVICELIST));
    203 
    204     if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
    205     {
    206         _glfw_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     _glfw_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     _glfwInputJoystick(js, GLFW_DISCONNECTED);
    260 
    261     if (js->win32.device)
    262     {
    263         IDirectInputDevice8_Unacquire(js->win32.device);
    264         IDirectInputDevice8_Release(js->win32.device);
    265     }
    266 
    267     _glfw_free(js->win32.objects);
    268     _glfwFreeJoystick(js);
    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         js = _glfw.joysticks + jid;
    360         if (js->connected)
    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 = _glfw_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         _glfw_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         _glfw_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         _glfw_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 // Checks for new joysticks after DBT_DEVICEARRIVAL
    495 //
    496 void _glfwDetectJoystickConnectionWin32(void)
    497 {
    498     if (_glfw.win32.xinput.instance)
    499     {
    500         DWORD index;
    501 
    502         for (index = 0;  index < XUSER_MAX_COUNT;  index++)
    503         {
    504             int jid;
    505             char guid[33];
    506             XINPUT_CAPABILITIES xic;
    507             _GLFWjoystick* js;
    508 
    509             for (jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    510             {
    511                 if (_glfw.joysticks[jid].connected &&
    512                     _glfw.joysticks[jid].win32.device == NULL &&
    513                     _glfw.joysticks[jid].win32.index == index)
    514                 {
    515                     break;
    516                 }
    517             }
    518 
    519             if (jid <= GLFW_JOYSTICK_LAST)
    520                 continue;
    521 
    522             if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
    523                 continue;
    524 
    525             // Generate a joystick GUID that matches the SDL 2.0.5+ one
    526             sprintf(guid, "78696e707574%02x000000000000000000",
    527                     xic.SubType & 0xff);
    528 
    529             js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1);
    530             if (!js)
    531                 continue;
    532 
    533             js->win32.index = index;
    534 
    535             _glfwInputJoystick(js, GLFW_CONNECTED);
    536         }
    537     }
    538 
    539     if (_glfw.win32.dinput8.api)
    540     {
    541         if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
    542                                              DI8DEVCLASS_GAMECTRL,
    543                                              deviceCallback,
    544                                              NULL,
    545                                              DIEDFL_ALLDEVICES)))
    546         {
    547             _glfwInputError(GLFW_PLATFORM_ERROR,
    548                             "Failed to enumerate DirectInput8 devices");
    549             return;
    550         }
    551     }
    552 }
    553 
    554 // Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
    555 //
    556 void _glfwDetectJoystickDisconnectionWin32(void)
    557 {
    558     int jid;
    559 
    560     for (jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    561     {
    562         _GLFWjoystick* js = _glfw.joysticks + jid;
    563         if (js->connected)
    564             _glfwPollJoystickWin32(js, _GLFW_POLL_PRESENCE);
    565     }
    566 }
    567 
    568 
    569 //////////////////////////////////////////////////////////////////////////
    570 //////                       GLFW platform API                      //////
    571 //////////////////////////////////////////////////////////////////////////
    572 
    573 GLFWbool _glfwInitJoysticksWin32(void)
    574 {
    575     if (_glfw.win32.dinput8.instance)
    576     {
    577         if (FAILED(DirectInput8Create(_glfw.win32.instance,
    578                                       DIRECTINPUT_VERSION,
    579                                       &IID_IDirectInput8W,
    580                                       (void**) &_glfw.win32.dinput8.api,
    581                                       NULL)))
    582         {
    583             _glfwInputError(GLFW_PLATFORM_ERROR,
    584                             "Win32: Failed to create interface");
    585             return GLFW_FALSE;
    586         }
    587     }
    588 
    589     _glfwDetectJoystickConnectionWin32();
    590     return GLFW_TRUE;
    591 }
    592 
    593 void _glfwTerminateJoysticksWin32(void)
    594 {
    595     int jid;
    596 
    597     for (jid = GLFW_JOYSTICK_1;  jid <= GLFW_JOYSTICK_LAST;  jid++)
    598         closeJoystick(_glfw.joysticks + jid);
    599 
    600     if (_glfw.win32.dinput8.api)
    601         IDirectInput8_Release(_glfw.win32.dinput8.api);
    602 }
    603 
    604 GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode)
    605 {
    606     if (js->win32.device)
    607     {
    608         int i, ai = 0, bi = 0, pi = 0;
    609         HRESULT result;
    610         DIJOYSTATE state = {0};
    611 
    612         IDirectInputDevice8_Poll(js->win32.device);
    613         result = IDirectInputDevice8_GetDeviceState(js->win32.device,
    614                                                     sizeof(state),
    615                                                     &state);
    616         if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
    617         {
    618             IDirectInputDevice8_Acquire(js->win32.device);
    619             IDirectInputDevice8_Poll(js->win32.device);
    620             result = IDirectInputDevice8_GetDeviceState(js->win32.device,
    621                                                         sizeof(state),
    622                                                         &state);
    623         }
    624 
    625         if (FAILED(result))
    626         {
    627             closeJoystick(js);
    628             return GLFW_FALSE;
    629         }
    630 
    631         if (mode == _GLFW_POLL_PRESENCE)
    632             return GLFW_TRUE;
    633 
    634         for (i = 0;  i < js->win32.objectCount;  i++)
    635         {
    636             const void* data = (char*) &state + js->win32.objects[i].offset;
    637 
    638             switch (js->win32.objects[i].type)
    639             {
    640                 case _GLFW_TYPE_AXIS:
    641                 case _GLFW_TYPE_SLIDER:
    642                 {
    643                     const float value = (*((LONG*) data) + 0.5f) / 32767.5f;
    644                     _glfwInputJoystickAxis(js, ai, value);
    645                     ai++;
    646                     break;
    647                 }
    648 
    649                 case _GLFW_TYPE_BUTTON:
    650                 {
    651                     const char value = (*((BYTE*) data) & 0x80) != 0;
    652                     _glfwInputJoystickButton(js, bi, value);
    653                     bi++;
    654                     break;
    655                 }
    656 
    657                 case _GLFW_TYPE_POV:
    658                 {
    659                     const int states[9] =
    660                     {
    661                         GLFW_HAT_UP,
    662                         GLFW_HAT_RIGHT_UP,
    663                         GLFW_HAT_RIGHT,
    664                         GLFW_HAT_RIGHT_DOWN,
    665                         GLFW_HAT_DOWN,
    666                         GLFW_HAT_LEFT_DOWN,
    667                         GLFW_HAT_LEFT,
    668                         GLFW_HAT_LEFT_UP,
    669                         GLFW_HAT_CENTERED
    670                     };
    671 
    672                     // Screams of horror are appropriate at this point
    673                     int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
    674                     if (stateIndex < 0 || stateIndex > 8)
    675                         stateIndex = 8;
    676 
    677                     _glfwInputJoystickHat(js, pi, states[stateIndex]);
    678                     pi++;
    679                     break;
    680                 }
    681             }
    682         }
    683     }
    684     else
    685     {
    686         int i, dpad = 0;
    687         DWORD result;
    688         XINPUT_STATE xis;
    689         const WORD buttons[10] =
    690         {
    691             XINPUT_GAMEPAD_A,
    692             XINPUT_GAMEPAD_B,
    693             XINPUT_GAMEPAD_X,
    694             XINPUT_GAMEPAD_Y,
    695             XINPUT_GAMEPAD_LEFT_SHOULDER,
    696             XINPUT_GAMEPAD_RIGHT_SHOULDER,
    697             XINPUT_GAMEPAD_BACK,
    698             XINPUT_GAMEPAD_START,
    699             XINPUT_GAMEPAD_LEFT_THUMB,
    700             XINPUT_GAMEPAD_RIGHT_THUMB
    701         };
    702 
    703         result = XInputGetState(js->win32.index, &xis);
    704         if (result != ERROR_SUCCESS)
    705         {
    706             if (result == ERROR_DEVICE_NOT_CONNECTED)
    707                 closeJoystick(js);
    708 
    709             return GLFW_FALSE;
    710         }
    711 
    712         if (mode == _GLFW_POLL_PRESENCE)
    713             return GLFW_TRUE;
    714 
    715         _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f);
    716         _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f);
    717         _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f);
    718         _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f);
    719         _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f);
    720         _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f);
    721 
    722         for (i = 0;  i < 10;  i++)
    723         {
    724             const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
    725             _glfwInputJoystickButton(js, i, value);
    726         }
    727 
    728         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
    729             dpad |= GLFW_HAT_UP;
    730         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
    731             dpad |= GLFW_HAT_RIGHT;
    732         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
    733             dpad |= GLFW_HAT_DOWN;
    734         if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
    735             dpad |= GLFW_HAT_LEFT;
    736 
    737         // Treat invalid combinations as neither being pressed
    738         // while preserving what data can be preserved
    739         if ((dpad & GLFW_HAT_RIGHT) && (dpad & GLFW_HAT_LEFT))
    740             dpad &= ~(GLFW_HAT_RIGHT | GLFW_HAT_LEFT);
    741         if ((dpad & GLFW_HAT_UP) && (dpad & GLFW_HAT_DOWN))
    742             dpad &= ~(GLFW_HAT_UP | GLFW_HAT_DOWN);
    743 
    744         _glfwInputJoystickHat(js, 0, dpad);
    745     }
    746 
    747     return GLFW_TRUE;
    748 }
    749 
    750 const char* _glfwGetMappingNameWin32(void)
    751 {
    752     return "Windows";
    753 }
    754 
    755 void _glfwUpdateGamepadGUIDWin32(char* guid)
    756 {
    757     if (strcmp(guid + 20, "504944564944") == 0)
    758     {
    759         char original[33];
    760         strncpy(original, guid, sizeof(original) - 1);
    761         sprintf(guid, "03000000%.4s0000%.4s000000000000",
    762                 original, original + 4);
    763     }
    764 }
    765 
    766 #endif // _GLFW_WIN32
    767