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>
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.
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:
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.
20 // 2. Altered source versions must be plainly marked as such, and must not
21 // be misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source
26 //========================================================================
27 // Please use C89 style variable declarations in this file because VS 2010
28 //========================================================================
35 #define _GLFW_TYPE_AXIS 0
36 #define _GLFW_TYPE_SLIDER 1
37 #define _GLFW_TYPE_BUTTON 2
38 #define _GLFW_TYPE_POV 3
40 // Data produced with DirectInput device object enumeration
42 typedef struct _GLFWobjenumWin32
44 IDirectInputDevice8W* device;
45 _GLFWjoyobjectWin32* objects;
53 // Define local copies of the necessary GUIDs
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}};
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
84 // Object data array for our clone of c_dfDIJoystick
85 // Generated with https://github.com/elmindreda/c_dfDIJoystick2
87 static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
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 },
135 // Our clone of c_dfDIJoystick
137 static const DIDATAFORMAT _glfwDataFormat =
139 sizeof(DIDATAFORMAT),
140 sizeof(DIOBJECTDATAFORMAT),
143 sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
144 _glfwObjectDataFormats
147 // Returns a description fitting the specified XInput capabilities
149 static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
151 switch (xic->SubType)
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:
167 if (xic->Flags & XINPUT_CAPS_WIRELESS)
168 return "Wireless Xbox Controller";
170 return "Xbox Controller";
174 return "Unknown XInput Device";
177 // Lexically compare device objects
179 static int compareJoystickObjects(const void* first, const void* second)
181 const _GLFWjoyobjectWin32* fo = first;
182 const _GLFWjoyobjectWin32* so = second;
184 if (fo->type != so->type)
185 return fo->type - so->type;
187 return fo->offset - so->offset;
190 // Checks whether the specified device supports XInput
191 // Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
193 static GLFWbool supportsXInput(const GUID* guid)
196 RAWINPUTDEVICELIST* ridl;
197 GLFWbool result = GLFW_FALSE;
199 if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
202 ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
204 if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
210 for (i = 0; i < count; i++)
216 if (ridl[i].dwType != RIM_TYPEHID)
219 ZeroMemory(&rdi, sizeof(rdi));
220 rdi.cbSize = sizeof(rdi);
223 if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
230 if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
233 memset(name, 0, sizeof(name));
236 if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
243 name[sizeof(name) - 1] = '\0';
244 if (strstr(name, "IG_"))
255 // Frees all resources associated with the specified joystick
257 static void closeJoystick(_GLFWjoystick* js)
259 if (js->win32.device)
261 IDirectInputDevice8_Unacquire(js->win32.device);
262 IDirectInputDevice8_Release(js->win32.device);
265 free(js->win32.objects);
267 _glfwFreeJoystick(js);
268 _glfwInputJoystick(js, GLFW_DISCONNECTED);
271 // DirectInput device object enumeration callback
272 // Insights gleaned from SDL
274 static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
277 _GLFWobjenumWin32* data = user;
278 _GLFWjoyobjectWin32* object = data->objects + data->objectCount;
280 if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
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;
299 return DIENUM_CONTINUE;
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;
309 if (FAILED(IDirectInputDevice8_SetProperty(data->device,
313 return DIENUM_CONTINUE;
316 if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
318 object->type = _GLFW_TYPE_SLIDER;
323 object->type = _GLFW_TYPE_AXIS;
327 else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
329 object->offset = DIJOFS_BUTTON(data->buttonCount);
330 object->type = _GLFW_TYPE_BUTTON;
333 else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
335 object->offset = DIJOFS_POV(data->povCount);
336 object->type = _GLFW_TYPE_POV;
341 return DIENUM_CONTINUE;
344 // DirectInput device enumeration callback
346 static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
351 IDirectInputDevice8* device;
352 _GLFWobjenumWin32 data;
357 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
359 js = _glfw.joysticks + jid;
362 if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0)
363 return DIENUM_CONTINUE;
367 if (supportsXInput(&di->guidProduct))
368 return DIENUM_CONTINUE;
370 if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
375 _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device");
376 return DIENUM_CONTINUE;
379 if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
381 _glfwInputError(GLFW_PLATFORM_ERROR,
382 "Win32: Failed to set device data format");
384 IDirectInputDevice8_Release(device);
385 return DIENUM_CONTINUE;
388 ZeroMemory(&dc, sizeof(dc));
389 dc.dwSize = sizeof(dc);
391 if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
393 _glfwInputError(GLFW_PLATFORM_ERROR,
394 "Win32: Failed to query device capabilities");
396 IDirectInputDevice8_Release(device);
397 return DIENUM_CONTINUE;
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;
406 if (FAILED(IDirectInputDevice8_SetProperty(device,
410 _glfwInputError(GLFW_PLATFORM_ERROR,
411 "Win32: Failed to set device axis mode");
413 IDirectInputDevice8_Release(device);
414 return DIENUM_CONTINUE;
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));
422 if (FAILED(IDirectInputDevice8_EnumObjects(device,
423 deviceObjectCallback,
425 DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
427 _glfwInputError(GLFW_PLATFORM_ERROR,
428 "Win32: Failed to enumerate device objects");
430 IDirectInputDevice8_Release(device);
432 return DIENUM_CONTINUE;
435 qsort(data.objects, data.objectCount,
436 sizeof(_GLFWjoyobjectWin32),
437 compareJoystickObjects);
439 if (!WideCharToMultiByte(CP_UTF8, 0,
440 di->tszInstanceName, -1,
444 _glfwInputError(GLFW_PLATFORM_ERROR,
445 "Win32: Failed to convert joystick name to UTF-8");
447 IDirectInputDevice8_Release(device);
452 // Generate a joystick GUID that matches the SDL 2.0.5+ one
453 if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0)
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));
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]);
469 js = _glfwAllocJoystick(name, guid,
470 data.axisCount + data.sliderCount,
475 IDirectInputDevice8_Release(device);
480 js->win32.device = device;
481 js->win32.guid = di->guidInstance;
482 js->win32.objects = data.objects;
483 js->win32.objectCount = data.objectCount;
485 _glfwInputJoystick(js, GLFW_CONNECTED);
486 return DIENUM_CONTINUE;
490 //////////////////////////////////////////////////////////////////////////
491 ////// GLFW internal API //////
492 //////////////////////////////////////////////////////////////////////////
494 // Checks for new joysticks after DBT_DEVICEARRIVAL
496 void _glfwDetectJoystickConnectionWin32(void)
498 if (_glfw.win32.xinput.instance)
502 for (index = 0; index < XUSER_MAX_COUNT; index++)
506 XINPUT_CAPABILITIES xic;
509 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
511 if (_glfw.joysticks[jid].present &&
512 _glfw.joysticks[jid].win32.device == NULL &&
513 _glfw.joysticks[jid].win32.index == index)
519 if (jid <= GLFW_JOYSTICK_LAST)
522 if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
525 // Generate a joystick GUID that matches the SDL 2.0.5+ one
526 sprintf(guid, "78696e707574%02x000000000000000000",
529 js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1);
533 js->win32.index = index;
535 _glfwInputJoystick(js, GLFW_CONNECTED);
539 if (_glfw.win32.dinput8.api)
541 if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
542 DI8DEVCLASS_GAMECTRL,
547 _glfwInputError(GLFW_PLATFORM_ERROR,
548 "Failed to enumerate DirectInput8 devices");
554 // Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
556 void _glfwDetectJoystickDisconnectionWin32(void)
560 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
562 _GLFWjoystick* js = _glfw.joysticks + jid;
564 _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
569 //////////////////////////////////////////////////////////////////////////
570 ////// GLFW platform API //////
571 //////////////////////////////////////////////////////////////////////////
573 GLFWbool _glfwPlatformInitJoysticks(void)
575 if (_glfw.win32.dinput8.instance)
577 if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
580 (void**) &_glfw.win32.dinput8.api,
583 _glfwInputError(GLFW_PLATFORM_ERROR,
584 "Win32: Failed to create interface");
589 _glfwDetectJoystickConnectionWin32();
593 void _glfwPlatformTerminateJoysticks(void)
597 for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
598 closeJoystick(_glfw.joysticks + jid);
600 if (_glfw.win32.dinput8.api)
601 IDirectInput8_Release(_glfw.win32.dinput8.api);
604 int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode)
606 if (js->win32.device)
608 int i, ai = 0, bi = 0, pi = 0;
612 IDirectInputDevice8_Poll(js->win32.device);
613 result = IDirectInputDevice8_GetDeviceState(js->win32.device,
616 if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
618 IDirectInputDevice8_Acquire(js->win32.device);
619 IDirectInputDevice8_Poll(js->win32.device);
620 result = IDirectInputDevice8_GetDeviceState(js->win32.device,
631 if (mode == _GLFW_POLL_PRESENCE)
634 for (i = 0; i < js->win32.objectCount; i++)
636 const void* data = (char*) &state + js->win32.objects[i].offset;
638 switch (js->win32.objects[i].type)
640 case _GLFW_TYPE_AXIS:
641 case _GLFW_TYPE_SLIDER:
643 const float value = (*((LONG*) data) + 0.5f) / 32767.5f;
644 _glfwInputJoystickAxis(js, ai, value);
649 case _GLFW_TYPE_BUTTON:
651 const char value = (*((BYTE*) data) & 0x80) != 0;
652 _glfwInputJoystickButton(js, bi, value);
659 const int states[9] =
672 // Screams of horror are appropriate at this point
673 int stateIndex = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
674 if (stateIndex < 0 || stateIndex > 8)
677 _glfwInputJoystickHat(js, pi, states[stateIndex]);
689 const WORD buttons[10] =
695 XINPUT_GAMEPAD_LEFT_SHOULDER,
696 XINPUT_GAMEPAD_RIGHT_SHOULDER,
698 XINPUT_GAMEPAD_START,
699 XINPUT_GAMEPAD_LEFT_THUMB,
700 XINPUT_GAMEPAD_RIGHT_THUMB
703 result = XInputGetState(js->win32.index, &xis);
704 if (result != ERROR_SUCCESS)
706 if (result == ERROR_DEVICE_NOT_CONNECTED)
712 if (mode == _GLFW_POLL_PRESENCE)
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);
722 for (i = 0; i < 10; i++)
724 const char value = (xis.Gamepad.wButtons & buttons[i]) ? 1 : 0;
725 _glfwInputJoystickButton(js, i, value);
728 if (xis.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_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;
737 _glfwInputJoystickHat(js, 0, dpad);
743 void _glfwPlatformUpdateGamepadGUID(char* guid)
745 if (strcmp(guid + 20, "504944564944") == 0)
748 strncpy(original, guid, sizeof(original) - 1);
749 sprintf(guid, "03000000%.4s0000%.4s000000000000",
750 original, original + 4);