win32_joystick.c
Go to the documentation of this file.
1 //========================================================================
2 // GLFW 3.3 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2016 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 #include <stdio.h>
31 #include <math.h>
32 
33 #define _GLFW_TYPE_AXIS 0
34 #define _GLFW_TYPE_SLIDER 1
35 #define _GLFW_TYPE_BUTTON 2
36 #define _GLFW_TYPE_POV 3
37 
38 // Data produced with DirectInput device object enumeration
39 //
40 typedef struct _GLFWobjenumWin32
41 {
42  IDirectInputDevice8W* device;
45  int axisCount;
48  int povCount;
50 
51 // Define local copies of the necessary GUIDs
52 //
53 static const GUID _glfw_IID_IDirectInput8W =
54  {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}};
55 static const GUID _glfw_GUID_XAxis =
56  {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
57 static const GUID _glfw_GUID_YAxis =
58  {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
59 static const GUID _glfw_GUID_ZAxis =
60  {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
61 static const GUID _glfw_GUID_RxAxis =
62  {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
63 static const GUID _glfw_GUID_RyAxis =
64  {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
65 static const GUID _glfw_GUID_RzAxis =
66  {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
67 static const GUID _glfw_GUID_Slider =
68  {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
69 static const GUID _glfw_GUID_POV =
70  {0xa36d02f2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}};
71 
72 #define IID_IDirectInput8W _glfw_IID_IDirectInput8W
73 #define GUID_XAxis _glfw_GUID_XAxis
74 #define GUID_YAxis _glfw_GUID_YAxis
75 #define GUID_ZAxis _glfw_GUID_ZAxis
76 #define GUID_RxAxis _glfw_GUID_RxAxis
77 #define GUID_RyAxis _glfw_GUID_RyAxis
78 #define GUID_RzAxis _glfw_GUID_RzAxis
79 #define GUID_Slider _glfw_GUID_Slider
80 #define GUID_POV _glfw_GUID_POV
81 
82 // Object data array for our clone of c_dfDIJoystick
83 // Generated with https://github.com/elmindreda/c_dfDIJoystick2
84 //
85 static DIOBJECTDATAFORMAT _glfwObjectDataFormats[] =
86 {
87  { &GUID_XAxis,DIJOFS_X,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
88  { &GUID_YAxis,DIJOFS_Y,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
89  { &GUID_ZAxis,DIJOFS_Z,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
90  { &GUID_RxAxis,DIJOFS_RX,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
91  { &GUID_RyAxis,DIJOFS_RY,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
92  { &GUID_RzAxis,DIJOFS_RZ,DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
93  { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
94  { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_AXIS|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,DIDOI_ASPECTPOSITION },
95  { &GUID_POV,DIJOFS_POV(0),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
96  { &GUID_POV,DIJOFS_POV(1),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
97  { &GUID_POV,DIJOFS_POV(2),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
98  { &GUID_POV,DIJOFS_POV(3),DIDFT_POV|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
99  { NULL,DIJOFS_BUTTON(0),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
100  { NULL,DIJOFS_BUTTON(1),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
101  { NULL,DIJOFS_BUTTON(2),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
102  { NULL,DIJOFS_BUTTON(3),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
103  { NULL,DIJOFS_BUTTON(4),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
104  { NULL,DIJOFS_BUTTON(5),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
105  { NULL,DIJOFS_BUTTON(6),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
106  { NULL,DIJOFS_BUTTON(7),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
107  { NULL,DIJOFS_BUTTON(8),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
108  { NULL,DIJOFS_BUTTON(9),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
109  { NULL,DIJOFS_BUTTON(10),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
110  { NULL,DIJOFS_BUTTON(11),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
111  { NULL,DIJOFS_BUTTON(12),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
112  { NULL,DIJOFS_BUTTON(13),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
113  { NULL,DIJOFS_BUTTON(14),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
114  { NULL,DIJOFS_BUTTON(15),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
115  { NULL,DIJOFS_BUTTON(16),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
116  { NULL,DIJOFS_BUTTON(17),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
117  { NULL,DIJOFS_BUTTON(18),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
118  { NULL,DIJOFS_BUTTON(19),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
119  { NULL,DIJOFS_BUTTON(20),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
120  { NULL,DIJOFS_BUTTON(21),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
121  { NULL,DIJOFS_BUTTON(22),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
122  { NULL,DIJOFS_BUTTON(23),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
123  { NULL,DIJOFS_BUTTON(24),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
124  { NULL,DIJOFS_BUTTON(25),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
125  { NULL,DIJOFS_BUTTON(26),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
126  { NULL,DIJOFS_BUTTON(27),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
127  { NULL,DIJOFS_BUTTON(28),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
128  { NULL,DIJOFS_BUTTON(29),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
129  { NULL,DIJOFS_BUTTON(30),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
130  { NULL,DIJOFS_BUTTON(31),DIDFT_BUTTON|DIDFT_OPTIONAL|DIDFT_ANYINSTANCE,0 },
131 };
132 
133 // Our clone of c_dfDIJoystick
134 //
135 static const DIDATAFORMAT _glfwDataFormat =
136 {
137  sizeof(DIDATAFORMAT),
138  sizeof(DIOBJECTDATAFORMAT),
139  DIDFT_ABSAXIS,
140  sizeof(DIJOYSTATE),
141  sizeof(_glfwObjectDataFormats) / sizeof(DIOBJECTDATAFORMAT),
143 };
144 
145 // Returns a description fitting the specified XInput capabilities
146 //
147 static const char* getDeviceDescription(const XINPUT_CAPABILITIES* xic)
148 {
149  switch (xic->SubType)
150  {
152  return "XInput Wheel";
154  return "XInput Arcade Stick";
156  return "XInput Flight Stick";
158  return "XInput Dance Pad";
160  return "XInput Guitar";
162  return "XInput Drum Kit";
163  case XINPUT_DEVSUBTYPE_GAMEPAD:
164  {
165  if (xic->Flags & XINPUT_CAPS_WIRELESS)
166  return "Wireless Xbox Controller";
167  else
168  return "Xbox Controller";
169  }
170  }
171 
172  return "Unknown XInput Device";
173 }
174 
175 // Lexically compare device objects
176 //
177 static int compareJoystickObjects(const void* first, const void* second)
178 {
179  const _GLFWjoyobjectWin32* fo = first;
180  const _GLFWjoyobjectWin32* so = second;
181 
182  if (fo->type != so->type)
183  return fo->type - so->type;
184 
185  return fo->offset - so->offset;
186 }
187 
188 // Checks whether the specified device supports XInput
189 // Technique from FDInputJoystickManager::IsXInputDeviceFast in ZDoom
190 //
191 static GLFWbool supportsXInput(const GUID* guid)
192 {
193  UINT i, count = 0;
194  RAWINPUTDEVICELIST* ridl;
195  GLFWbool result = GLFW_FALSE;
196 
197  if (GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) != 0)
198  return GLFW_FALSE;
199 
200  ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
201 
202  if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
203  {
204  free(ridl);
205  return GLFW_FALSE;
206  }
207 
208  for (i = 0; i < count; i++)
209  {
210  RID_DEVICE_INFO rdi;
211  char name[256];
212  UINT size;
213 
214  if (ridl[i].dwType != RIM_TYPEHID)
215  continue;
216 
217  ZeroMemory(&rdi, sizeof(rdi));
218  rdi.cbSize = sizeof(rdi);
219  size = sizeof(rdi);
220 
221  if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
222  RIDI_DEVICEINFO,
223  &rdi, &size) == -1)
224  {
225  continue;
226  }
227 
228  if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
229  continue;
230 
231  memset(name, 0, sizeof(name));
232  size = sizeof(name);
233 
234  if ((INT) GetRawInputDeviceInfoA(ridl[i].hDevice,
235  RIDI_DEVICENAME,
236  name, &size) == -1)
237  {
238  break;
239  }
240 
241  name[sizeof(name) - 1] = '\0';
242  if (strstr(name, "IG_"))
243  {
244  result = GLFW_TRUE;
245  break;
246  }
247  }
248 
249  free(ridl);
250  return result;
251 }
252 
253 // Frees all resources associated with the specified joystick
254 //
255 static void closeJoystick(_GLFWjoystick* js)
256 {
257  if (js->win32.device)
258  {
259  IDirectInputDevice8_Unacquire(js->win32.device);
260  IDirectInputDevice8_Release(js->win32.device);
261  }
262 
263  free(js->win32.objects);
264 
265  _glfwFreeJoystick(js);
267 }
268 
269 // DirectInput device object enumeration callback
270 // Insights gleaned from SDL
271 //
272 static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW* doi,
273  void* user)
274 {
275  _GLFWobjenumWin32* data = user;
276  _GLFWjoyobjectWin32* object = data->objects + data->objectCount;
277 
278  if (DIDFT_GETTYPE(doi->dwType) & DIDFT_AXIS)
279  {
280  DIPROPRANGE dipr;
281 
282  if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
283  object->offset = DIJOFS_SLIDER(data->sliderCount);
284  else if (memcmp(&doi->guidType, &GUID_XAxis, sizeof(GUID)) == 0)
285  object->offset = DIJOFS_X;
286  else if (memcmp(&doi->guidType, &GUID_YAxis, sizeof(GUID)) == 0)
287  object->offset = DIJOFS_Y;
288  else if (memcmp(&doi->guidType, &GUID_ZAxis, sizeof(GUID)) == 0)
289  object->offset = DIJOFS_Z;
290  else if (memcmp(&doi->guidType, &GUID_RxAxis, sizeof(GUID)) == 0)
291  object->offset = DIJOFS_RX;
292  else if (memcmp(&doi->guidType, &GUID_RyAxis, sizeof(GUID)) == 0)
293  object->offset = DIJOFS_RY;
294  else if (memcmp(&doi->guidType, &GUID_RzAxis, sizeof(GUID)) == 0)
295  object->offset = DIJOFS_RZ;
296  else
297  return DIENUM_CONTINUE;
298 
299  ZeroMemory(&dipr, sizeof(dipr));
300  dipr.diph.dwSize = sizeof(dipr);
301  dipr.diph.dwHeaderSize = sizeof(dipr.diph);
302  dipr.diph.dwObj = doi->dwType;
303  dipr.diph.dwHow = DIPH_BYID;
304  dipr.lMin = -32768;
305  dipr.lMax = 32767;
306 
307  if (FAILED(IDirectInputDevice8_SetProperty(data->device,
308  DIPROP_RANGE,
309  &dipr.diph)))
310  {
311  return DIENUM_CONTINUE;
312  }
313 
314  if (memcmp(&doi->guidType, &GUID_Slider, sizeof(GUID)) == 0)
315  {
316  object->type = _GLFW_TYPE_SLIDER;
317  data->sliderCount++;
318  }
319  else
320  {
321  object->type = _GLFW_TYPE_AXIS;
322  data->axisCount++;
323  }
324  }
325  else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_BUTTON)
326  {
327  object->offset = DIJOFS_BUTTON(data->buttonCount);
328  object->type = _GLFW_TYPE_BUTTON;
329  data->buttonCount++;
330  }
331  else if (DIDFT_GETTYPE(doi->dwType) & DIDFT_POV)
332  {
333  object->offset = DIJOFS_POV(data->povCount);
334  object->type = _GLFW_TYPE_POV;
335  data->povCount++;
336  }
337 
338  data->objectCount++;
339  return DIENUM_CONTINUE;
340 }
341 
342 // DirectInput device enumeration callback
343 //
344 static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
345 {
346  int jid = 0;
347  DIDEVCAPS dc;
348  DIPROPDWORD dipd;
349  IDirectInputDevice8* device;
350  _GLFWobjenumWin32 data;
351  _GLFWjoystick* js;
352  char guid[33];
353  char name[256];
354 
355  for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
356  {
357  _GLFWjoystick* js = _glfw.joysticks + jid;
358  if (js->present)
359  {
360  if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0)
361  return DIENUM_CONTINUE;
362  }
363  }
364 
365  if (supportsXInput(&di->guidProduct))
366  return DIENUM_CONTINUE;
367 
368  if (FAILED(IDirectInput8_CreateDevice(_glfw.win32.dinput8.api,
369  &di->guidInstance,
370  &device,
371  NULL)))
372  {
373  _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create device");
374  return DIENUM_CONTINUE;
375  }
376 
377  if (FAILED(IDirectInputDevice8_SetDataFormat(device, &_glfwDataFormat)))
378  {
380  "Win32: Failed to set device data format");
381 
382  IDirectInputDevice8_Release(device);
383  return DIENUM_CONTINUE;
384  }
385 
386  ZeroMemory(&dc, sizeof(dc));
387  dc.dwSize = sizeof(dc);
388 
389  if (FAILED(IDirectInputDevice8_GetCapabilities(device, &dc)))
390  {
392  "Win32: Failed to query device capabilities");
393 
394  IDirectInputDevice8_Release(device);
395  return DIENUM_CONTINUE;
396  }
397 
398  ZeroMemory(&dipd, sizeof(dipd));
399  dipd.diph.dwSize = sizeof(dipd);
400  dipd.diph.dwHeaderSize = sizeof(dipd.diph);
401  dipd.diph.dwHow = DIPH_DEVICE;
402  dipd.dwData = DIPROPAXISMODE_ABS;
403 
404  if (FAILED(IDirectInputDevice8_SetProperty(device,
405  DIPROP_AXISMODE,
406  &dipd.diph)))
407  {
409  "Win32: Failed to set device axis mode");
410 
411  IDirectInputDevice8_Release(device);
412  return DIENUM_CONTINUE;
413  }
414 
415  memset(&data, 0, sizeof(data));
416  data.device = device;
417  data.objects = calloc(dc.dwAxes + dc.dwButtons + dc.dwPOVs,
418  sizeof(_GLFWjoyobjectWin32));
419 
420  if (FAILED(IDirectInputDevice8_EnumObjects(device,
422  &data,
423  DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV)))
424  {
426  "Win32: Failed to enumerate device objects");
427 
428  IDirectInputDevice8_Release(device);
429  free(data.objects);
430  return DIENUM_CONTINUE;
431  }
432 
433  qsort(data.objects, data.objectCount,
434  sizeof(_GLFWjoyobjectWin32),
436 
437  if (!WideCharToMultiByte(CP_UTF8, 0,
438  di->tszInstanceName, -1,
439  name, sizeof(name),
440  NULL, NULL))
441  {
443  "Win32: Failed to convert joystick name to UTF-8");
444 
445  IDirectInputDevice8_Release(device);
446  free(data.objects);
447  return DIENUM_STOP;
448  }
449 
450  // Generate a joystick GUID that matches the SDL 2.0.5+ one
451  if (memcmp(&di->guidProduct.Data4[2], "PIDVID", 6) == 0)
452  {
453  sprintf(guid, "03000000%02x%02x0000%02x%02x000000000000",
454  (uint8_t) di->guidProduct.Data1,
455  (uint8_t) (di->guidProduct.Data1 >> 8),
456  (uint8_t) (di->guidProduct.Data1 >> 16),
457  (uint8_t) (di->guidProduct.Data1 >> 24));
458  }
459  else
460  {
461  sprintf(guid, "05000000%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x00",
462  name[0], name[1], name[2], name[3],
463  name[4], name[5], name[6], name[7],
464  name[8], name[9], name[10]);
465  }
466 
467  js = _glfwAllocJoystick(name, guid,
468  data.axisCount + data.sliderCount,
469  data.buttonCount,
470  data.povCount);
471  if (!js)
472  {
473  IDirectInputDevice8_Release(device);
474  free(data.objects);
475  return DIENUM_STOP;
476  }
477 
478  js->win32.device = device;
479  js->win32.guid = di->guidInstance;
480  js->win32.objects = data.objects;
481  js->win32.objectCount = data.objectCount;
482 
484  return DIENUM_CONTINUE;
485 }
486 
487 
491 
492 // Initialize joystick interface
493 //
495 {
496  if (_glfw.win32.dinput8.instance)
497  {
498  if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
501  (void**) &_glfw.win32.dinput8.api,
502  NULL)))
503  {
505  "Win32: Failed to create interface");
506  }
507  }
508 
510 }
511 
512 // Close all opened joystick handles
513 //
515 {
516  int jid;
517 
518  for (jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; jid++)
520 
521  if (_glfw.win32.dinput8.api)
522  IDirectInput8_Release(_glfw.win32.dinput8.api);
523 }
524 
525 // Checks for new joysticks after DBT_DEVICEARRIVAL
526 //
528 {
529  if (_glfw.win32.xinput.instance)
530  {
531  DWORD index;
532 
533  for (index = 0; index < XUSER_MAX_COUNT; index++)
534  {
535  int jid;
536  char guid[33];
537  XINPUT_CAPABILITIES xic;
538  _GLFWjoystick* js;
539 
540  for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
541  {
542  if (_glfw.joysticks[jid].present &&
543  _glfw.joysticks[jid].win32.device == NULL &&
544  _glfw.joysticks[jid].win32.index == index)
545  {
546  break;
547  }
548  }
549 
550  if (jid <= GLFW_JOYSTICK_LAST)
551  continue;
552 
553  if (XInputGetCapabilities(index, 0, &xic) != ERROR_SUCCESS)
554  continue;
555 
556  // Generate a joystick GUID that matches the SDL 2.0.5+ one
557  sprintf(guid, "78696e707574%02x000000000000000000",
558  xic.SubType & 0xff);
559 
560  js = _glfwAllocJoystick(getDeviceDescription(&xic), guid, 6, 10, 1);
561  if (!js)
562  continue;
563 
564  js->win32.index = index;
565 
567  }
568  }
569 
570  if (_glfw.win32.dinput8.api)
571  {
572  if (FAILED(IDirectInput8_EnumDevices(_glfw.win32.dinput8.api,
573  DI8DEVCLASS_GAMECTRL,
575  NULL,
576  DIEDFL_ALLDEVICES)))
577  {
579  "Failed to enumerate DirectInput8 devices");
580  return;
581  }
582  }
583 }
584 
585 // Checks for joystick disconnection after DBT_DEVICEREMOVECOMPLETE
586 //
588 {
589  int jid;
590 
591  for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
592  {
593  _GLFWjoystick* js = _glfw.joysticks + jid;
594  if (js->present)
596  }
597 }
598 
599 
603 
605 {
606  if (js->win32.device)
607  {
608  int i, ai = 0, bi = 0, pi = 0;
609  HRESULT result;
610  DIJOYSTATE state;
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,
670  };
671 
672  // Screams of horror are appropriate at this point
673  int state = LOWORD(*(DWORD*) data) / (45 * DI_DEGREES);
674  if (state < 0 || state > 8)
675  state = 8;
676 
677  _glfwInputJoystickHat(js, pi, states[state]);
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  _glfwInputJoystickHat(js, 0, dpad);
738  }
739 
740  return GLFW_TRUE;
741 }
742 
744 {
745  if (strcmp(guid + 20, "504944564944") == 0)
746  {
747  char original[33];
748  strcpy(original, guid);
749  sprintf(guid, "03000000%.4s0000%.4s000000000000",
750  original, original + 4);
751  }
752 }
753 
#define DIRECTINPUT_VERSION
#define GLFW_HAT_LEFT
Definition: glfw3.h:325
static const GUID _glfw_GUID_XAxis
void _glfwInputJoystickButton(_GLFWjoystick *js, int button, char value)
Definition: input.c:385
static const GUID _glfw_IID_IDirectInput8W
static const DIDATAFORMAT _glfwDataFormat
static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE *di, void *user)
#define GLFW_HAT_UP
Definition: glfw3.h:322
void _glfwFreeJoystick(_GLFWjoystick *js)
Definition: input.c:447
unsigned char BYTE
#define GUID_Slider
void _glfwDetectJoystickConnectionWin32(void)
#define _GLFW_TYPE_AXIS
#define XINPUT_CAPS_WIRELESS
f
void _glfwTerminateJoysticksWin32(void)
void _glfwPlatformUpdateGamepadGUID(char *guid)
#define _GLFW_POLL_PRESENCE
Definition: internal.h:55
#define DIDFT_OPTIONAL
#define XINPUT_DEVSUBTYPE_FLIGHT_STICK
#define XInputGetCapabilities
#define GLFW_FALSE
Zero.
Definition: glfw3.h:287
_GLFWjoystick * _glfwAllocJoystick(const char *name, const char *guid, int axisCount, int buttonCount, int hatCount)
Definition: input.c:411
GLFWbool present
Definition: internal.h:479
int GLFWbool
Definition: internal.h:62
#define XINPUT_DEVSUBTYPE_DRUM_KIT
#define XINPUT_DEVSUBTYPE_WHEEL
void _glfwInputJoystick(_GLFWjoystick *js, int event)
Definition: input.c:368
#define IID_IDirectInput8W
#define _GLFW_TYPE_BUTTON
#define XINPUT_DEVSUBTYPE_DANCE_PAD
#define GLFW_DISCONNECTED
Definition: glfw3.h:1059
#define GLFW_HAT_RIGHT
Definition: glfw3.h:323
static const GUID _glfw_GUID_RzAxis
#define GLFW_CONNECTED
Definition: glfw3.h:1058
static int compareJoystickObjects(const void *first, const void *second)
#define GUID_ZAxis
#define DirectInput8Create
#define GLFW_PLATFORM_ERROR
A platform-specific error occurred that does not match any of the more specific categories.
Definition: glfw3.h:726
_GLFWlibrary _glfw
Definition: init.c:44
#define GLFW_HAT_LEFT_UP
Definition: glfw3.h:328
static const GUID _glfw_GUID_RxAxis
#define GUID_POV
#define GUID_RzAxis
static const GUID _glfw_GUID_Slider
#define XUSER_MAX_COUNT
#define GLFW_JOYSTICK_1
Definition: glfw3.h:558
#define GLFW_JOYSTICK_LAST
Definition: glfw3.h:574
char guid[33]
Definition: internal.h:488
#define GUID_YAxis
#define GLFW_HAT_RIGHT_DOWN
Definition: glfw3.h:327
void _glfwInputError(int code, const char *format,...)
Definition: init.c:153
#define GLFW_HAT_DOWN
Definition: glfw3.h:324
void _glfwInputJoystickHat(_GLFWjoystick *js, int hat, char value)
Definition: input.c:392
void _glfwInitJoysticksWin32(void)
_GLFWjoyobjectWin32 * objects
#define _GLFW_TYPE_SLIDER
static DIOBJECTDATAFORMAT _glfwObjectDataFormats[]
#define GLFW_HAT_RIGHT_UP
Definition: glfw3.h:326
static const GUID _glfw_GUID_YAxis
int _glfwPlatformPollJoystick(_GLFWjoystick *js, int mode)
IDirectInputDevice8W * device
void _glfwInputJoystickAxis(_GLFWjoystick *js, int axis, float value)
Definition: input.c:378
#define GLFW_TRUE
One.
Definition: glfw3.h:279
#define GUID_RxAxis
#define GLFW_HAT_LEFT_DOWN
Definition: glfw3.h:329
static const GUID _glfw_GUID_RyAxis
static const GUID _glfw_GUID_POV
static GLFWbool supportsXInput(const GUID *guid)
#define XInputGetState
#define GLFW_HAT_CENTERED
Definition: glfw3.h:321
void _glfwDetectJoystickDisconnectionWin32(void)
static const GUID _glfw_GUID_ZAxis
#define GUID_RyAxis
static void closeJoystick(_GLFWjoystick *js)
static const char * getDeviceDescription(const XINPUT_CAPABILITIES *xic)
#define GUID_XAxis
_GLFWjoystick joysticks[GLFW_JOYSTICK_LAST+1]
Definition: internal.h:532
static BOOL CALLBACK deviceObjectCallback(const DIDEVICEOBJECTINSTANCEW *doi, void *user)
struct _GLFWobjenumWin32 _GLFWobjenumWin32
#define _GLFW_TYPE_POV
#define XINPUT_DEVSUBTYPE_ARCADE_STICK
#define XINPUT_DEVSUBTYPE_GUITAR


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:21