ScrapExplorer - win32_joystick.c
Home / ext / glfw / src Lines: 1 | Size: 26711 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1//======================================================================== 2// GLFW 3.5 Win32 - www.glfw.org 3//------------------------------------------------------------------------ 4// Copyright (c) 2002-2006 Marcus Geelnard 5// Copyright (c) 2006-2019 Camilla Löwy <[email protected]> 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// 42typedef 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// 55static const GUID _glfw_IID_IDirectInput8W = 56 {0xbf798031,0x483a,0x4da2,{0xaa,0x99,0x5d,0x64,0xed,0x36,0x97,0x00}}; 57static const GUID _glfw_GUID_XAxis = 58 {0xa36d02e0,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 59static const GUID _glfw_GUID_YAxis = 60 {0xa36d02e1,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 61static const GUID _glfw_GUID_ZAxis = 62 {0xa36d02e2,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 63static const GUID _glfw_GUID_RxAxis = 64 {0xa36d02f4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 65static const GUID _glfw_GUID_RyAxis = 66 {0xa36d02f5,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 67static const GUID _glfw_GUID_RzAxis = 68 {0xa36d02e3,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 69static const GUID _glfw_GUID_Slider = 70 {0xa36d02e4,0xc9f3,0x11cf,{0xbf,0xc7,0x44,0x45,0x53,0x54,0x00,0x00}}; 71static 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// 87static 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// 137static 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// 149static 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// 179static 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// 193static 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// 257static 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// 274static 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// 346static 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// 496void _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// 556void _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 573GLFWbool _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 593void _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 604GLFWbool _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 750const char* _glfwGetMappingNameWin32(void) 751{ 752 return "Windows"; 753} 754 755void _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 768[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.