|
| 1 | +#include "gamepad.h" |
| 2 | +#include "common/io/io.h" |
| 3 | +#include "util/mallocHelper.h" |
| 4 | +#include "util/windows/unicode.h" |
| 5 | + |
| 6 | +#include <windows.h> |
| 7 | +#include <hidsdi.h> |
| 8 | + |
| 9 | +static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId) |
| 10 | +{ |
| 11 | + switch (vendorId) |
| 12 | + { |
| 13 | + // Nintendo |
| 14 | + case 0x057E: |
| 15 | + { |
| 16 | + switch (productId) |
| 17 | + { |
| 18 | + case 0x2006: return "Nintendo Switch Joycon L"; |
| 19 | + case 0x2007: return "Nintendo Switch Joycon R"; |
| 20 | + case 0x2009: return "Nintendo Switch Pro"; |
| 21 | + case 0x200E: return "Nintendo Switch Charging Grip"; |
| 22 | + case 0x2017: return "Nintendo Switch SNES Controller"; |
| 23 | + |
| 24 | + default: return NULL; |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + // Sony |
| 29 | + case 0x054C: |
| 30 | + { |
| 31 | + switch (productId) |
| 32 | + { |
| 33 | + case 0x0268: return "Sony Playstation 3 Controller"; |
| 34 | + |
| 35 | + case 0x05C4: return "Sony DualShock 4 Gen1"; |
| 36 | + case 0x09CC: return "Sony DualShock 4 Gen2"; |
| 37 | + case 0x0BA0: return "Sony PS4 Controller USB receiver"; |
| 38 | + |
| 39 | + case 0x0CE6: return "Sony DualSense"; |
| 40 | + |
| 41 | + default: return NULL; |
| 42 | + } |
| 43 | + } |
| 44 | + |
| 45 | + // Microsoft |
| 46 | + case 0x045E: |
| 47 | + { |
| 48 | + switch (productId) |
| 49 | + { |
| 50 | + case 0x02E0: return "Microsoft X-Box One S pad (Wireless)"; |
| 51 | + case 0x02FD: return "Microsoft X-Box One S pad (Wireless, 2016 FW)"; |
| 52 | + case 0x0B05: return "Microsoft X-Box One Elite Series 2 pad (Wireless)"; |
| 53 | + case 0x0B13: return "Microsoft X-Box Series X (Wireless)"; |
| 54 | + |
| 55 | + case 0x028E: return "Microsoft XBox 360"; |
| 56 | + case 0x028F: return "Microsoft XBox 360 v2"; |
| 57 | + case 0x02A1: return "Microsoft XBox 360"; |
| 58 | + case 0x0291: return "Microsoft XBox 360 USB receiver"; |
| 59 | + case 0x02A0: return "Microsoft XBox 360 Big Button IR"; |
| 60 | + case 0x02DD: return "Microsoft XBox One"; |
| 61 | + case 0xB326: return "Microsoft XBox One Firmware 2015"; |
| 62 | + case 0x02E3: return "Microsoft XBox One Elite"; |
| 63 | + case 0x02FF: return "Microsoft XBox One Elite"; |
| 64 | + case 0x02EA: return "Microsoft XBox One S"; |
| 65 | + |
| 66 | + default: return NULL; |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + // Logitech |
| 71 | + case 0x046D: |
| 72 | + { |
| 73 | + switch (productId) |
| 74 | + { |
| 75 | + case 0xC216: return "Logitech F310, DirectInput"; |
| 76 | + case 0xC218: return "Logitech F510, DirectInput"; |
| 77 | + case 0xC219: return "Logitech F710, DirectInput"; |
| 78 | + case 0xC21D: return "Logitech F310"; |
| 79 | + case 0xC21E: return "Logitech F510"; |
| 80 | + case 0xC21F: return "Logitech F710"; |
| 81 | + |
| 82 | + default: return NULL; |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + default: return NULL; |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +const char* ffDetectGamepad(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* devices /* List of FFGamepadDevice */) |
| 91 | +{ |
| 92 | + UINT nDevices = 0; |
| 93 | + if (GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST))) |
| 94 | + return "GetRawInputDeviceList(NULL) failed"; |
| 95 | + if (nDevices == 0) |
| 96 | + return "No HID devices found"; |
| 97 | + RAWINPUTDEVICELIST* FF_AUTO_FREE pRawInputDeviceList = (RAWINPUTDEVICELIST*) malloc(sizeof(RAWINPUTDEVICELIST) * nDevices); |
| 98 | + if ((nDevices = GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT) -1) |
| 99 | + return "GetRawInputDeviceList(pRawInputDeviceList) failed"; |
| 100 | + |
| 101 | + for (UINT i = 0; i < nDevices; ++i) { |
| 102 | + if (pRawInputDeviceList[i].dwType != 2) continue; |
| 103 | + |
| 104 | + HANDLE hDevice = pRawInputDeviceList[i].hDevice; |
| 105 | + |
| 106 | + RID_DEVICE_INFO rdi; |
| 107 | + UINT rdiSize = sizeof(rdi); |
| 108 | + if (GetRawInputDeviceInfoW(hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) == (UINT) -1) |
| 109 | + continue; |
| 110 | + |
| 111 | + if (rdi.hid.usUsagePage != 1 || rdi.hid.usUsage != 5) // Gamepad |
| 112 | + continue; |
| 113 | + |
| 114 | + WCHAR devName[MAX_PATH] = L""; |
| 115 | + UINT nameSize = MAX_PATH; |
| 116 | + if (GetRawInputDeviceInfoW(hDevice, RIDI_DEVICENAME, devName, &nameSize) == (UINT) -1) |
| 117 | + continue; |
| 118 | + |
| 119 | + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); |
| 120 | + ffStrbufInit(&device->identifier); |
| 121 | + ffStrbufSetWS(&device->identifier, devName); |
| 122 | + ffStrbufInit(&device->name); |
| 123 | + |
| 124 | + const char* knownGamepad = detectKnownGamepad(rdi.hid.dwVendorId, rdi.hid.dwProductId); |
| 125 | + if (knownGamepad) |
| 126 | + ffStrbufSetS(&device->name, knownGamepad); |
| 127 | + else |
| 128 | + { |
| 129 | + wchar_t displayName[126]; |
| 130 | + HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); |
| 131 | + if (hHidFile && HidD_GetProductString(hHidFile, displayName, sizeof(wchar_t) * 126)) |
| 132 | + ffStrbufSetWS(&device->name, displayName); |
| 133 | + else |
| 134 | + ffStrbufSetF(&device->name, "Unknown gamepad %4X-%4X", rdi.hid.dwVendorId, rdi.hid.dwProductId); |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + return NULL; |
| 139 | +} |
0 commit comments