summaryrefslogtreecommitdiff
path: root/SDL-3.2.8/src/core/windows/SDL_hid.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2026-03-06 13:26:57 -0800
committer3gg <3gg@shellblade.net>2026-03-06 13:26:57 -0800
commitf5c89b3bd5d74849757fd5b4d1a300068522a3ca (patch)
treed6f6e4c81745b393d7594b334710f30c0b2df3bd /SDL-3.2.8/src/core/windows/SDL_hid.c
Initial commitHEADmain
Diffstat (limited to 'SDL-3.2.8/src/core/windows/SDL_hid.c')
-rw-r--r--SDL-3.2.8/src/core/windows/SDL_hid.c254
1 files changed, 254 insertions, 0 deletions
diff --git a/SDL-3.2.8/src/core/windows/SDL_hid.c b/SDL-3.2.8/src/core/windows/SDL_hid.c
new file mode 100644
index 0000000..87e8735
--- /dev/null
+++ b/SDL-3.2.8/src/core/windows/SDL_hid.c
@@ -0,0 +1,254 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#include "SDL_hid.h"
24
25HidD_GetAttributes_t SDL_HidD_GetAttributes;
26HidD_GetString_t SDL_HidD_GetManufacturerString;
27HidD_GetString_t SDL_HidD_GetProductString;
28HidP_GetCaps_t SDL_HidP_GetCaps;
29HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
30HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
31HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
32HidP_GetData_t SDL_HidP_GetData;
33
34static HMODULE s_pHIDDLL = 0;
35static int s_HIDDLLRefCount = 0;
36
37
38bool WIN_LoadHIDDLL(void)
39{
40 if (s_pHIDDLL) {
41 SDL_assert(s_HIDDLLRefCount > 0);
42 s_HIDDLLRefCount++;
43 return true; // already loaded
44 }
45
46 s_pHIDDLL = LoadLibrary(TEXT("hid.dll"));
47 if (!s_pHIDDLL) {
48 return false;
49 }
50
51 SDL_assert(s_HIDDLLRefCount == 0);
52 s_HIDDLLRefCount = 1;
53
54 SDL_HidD_GetAttributes = (HidD_GetAttributes_t)GetProcAddress(s_pHIDDLL, "HidD_GetAttributes");
55 SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");
56 SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");
57 SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");
58 SDL_HidP_GetButtonCaps = (HidP_GetButtonCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetButtonCaps");
59 SDL_HidP_GetValueCaps = (HidP_GetValueCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetValueCaps");
60 SDL_HidP_MaxDataListLength = (HidP_MaxDataListLength_t)GetProcAddress(s_pHIDDLL, "HidP_MaxDataListLength");
61 SDL_HidP_GetData = (HidP_GetData_t)GetProcAddress(s_pHIDDLL, "HidP_GetData");
62 if (!SDL_HidD_GetManufacturerString || !SDL_HidD_GetProductString ||
63 !SDL_HidP_GetCaps || !SDL_HidP_GetButtonCaps ||
64 !SDL_HidP_GetValueCaps || !SDL_HidP_MaxDataListLength || !SDL_HidP_GetData) {
65 WIN_UnloadHIDDLL();
66 return false;
67 }
68
69 return true;
70}
71
72void WIN_UnloadHIDDLL(void)
73{
74 if (s_pHIDDLL) {
75 SDL_assert(s_HIDDLLRefCount > 0);
76 if (--s_HIDDLLRefCount == 0) {
77 FreeLibrary(s_pHIDDLL);
78 s_pHIDDLL = NULL;
79 }
80 } else {
81 SDL_assert(s_HIDDLLRefCount == 0);
82 }
83}
84
85#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
86
87// CM_Register_Notification definitions
88
89#define CR_SUCCESS 0
90
91DECLARE_HANDLE(HCMNOTIFICATION);
92typedef HCMNOTIFICATION *PHCMNOTIFICATION;
93
94typedef enum _CM_NOTIFY_FILTER_TYPE
95{
96 CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0,
97 CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE,
98 CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE,
99 CM_NOTIFY_FILTER_TYPE_MAX
100} CM_NOTIFY_FILTER_TYPE, *PCM_NOTIFY_FILTER_TYPE;
101
102typedef struct _CM_NOTIFY_FILTER
103{
104 DWORD cbSize;
105 DWORD Flags;
106 CM_NOTIFY_FILTER_TYPE FilterType;
107 DWORD Reserved;
108 union
109 {
110 struct
111 {
112 GUID ClassGuid;
113 } DeviceInterface;
114 struct
115 {
116 HANDLE hTarget;
117 } DeviceHandle;
118 struct
119 {
120 WCHAR InstanceId[200];
121 } DeviceInstance;
122 } u;
123} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER;
124
125typedef enum _CM_NOTIFY_ACTION
126{
127 CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0,
128 CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL,
129 CM_NOTIFY_ACTION_DEVICEQUERYREMOVE,
130 CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED,
131 CM_NOTIFY_ACTION_DEVICEREMOVEPENDING,
132 CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE,
133 CM_NOTIFY_ACTION_DEVICECUSTOMEVENT,
134 CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED,
135 CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED,
136 CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED,
137 CM_NOTIFY_ACTION_MAX
138} CM_NOTIFY_ACTION, *PCM_NOTIFY_ACTION;
139
140typedef struct _CM_NOTIFY_EVENT_DATA
141{
142 CM_NOTIFY_FILTER_TYPE FilterType;
143 DWORD Reserved;
144 union
145 {
146 struct
147 {
148 GUID ClassGuid;
149 WCHAR SymbolicLink[ANYSIZE_ARRAY];
150 } DeviceInterface;
151 struct
152 {
153 GUID EventGuid;
154 LONG NameOffset;
155 DWORD DataSize;
156 BYTE Data[ANYSIZE_ARRAY];
157 } DeviceHandle;
158 struct
159 {
160 WCHAR InstanceId[ANYSIZE_ARRAY];
161 } DeviceInstance;
162 } u;
163} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA;
164
165typedef DWORD (CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize);
166
167typedef DWORD (WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext);
168typedef DWORD (WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext);
169
170static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
171
172static int s_DeviceNotificationsRequested;
173static HMODULE cfgmgr32_lib_handle;
174static CM_Register_NotificationFunc CM_Register_Notification;
175static CM_Unregister_NotificationFunc CM_Unregister_Notification;
176static HCMNOTIFICATION s_DeviceNotificationFuncHandle;
177static Uint64 s_LastDeviceNotification = 1;
178
179static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size)
180{
181 if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL ||
182 action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) {
183 s_LastDeviceNotification = SDL_GetTicksNS();
184 }
185 return ERROR_SUCCESS;
186}
187
188void WIN_InitDeviceNotification(void)
189{
190 ++s_DeviceNotificationsRequested;
191 if (s_DeviceNotificationsRequested > 1) {
192 return;
193 }
194
195 cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
196 if (cfgmgr32_lib_handle) {
197 CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification");
198 CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification");
199 if (CM_Register_Notification && CM_Unregister_Notification) {
200 CM_NOTIFY_FILTER notify_filter;
201
202 SDL_zero(notify_filter);
203 notify_filter.cbSize = sizeof(notify_filter);
204 notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
205 notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID;
206 if (CM_Register_Notification(&notify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) {
207 return;
208 }
209 }
210 }
211
212 // FIXME: Should we log errors?
213}
214
215Uint64 WIN_GetLastDeviceNotification(void)
216{
217 return s_LastDeviceNotification;
218}
219
220void WIN_QuitDeviceNotification(void)
221{
222 if (--s_DeviceNotificationsRequested > 0) {
223 return;
224 }
225 // Make sure we have balanced calls to init/quit
226 SDL_assert(s_DeviceNotificationsRequested == 0);
227
228 if (cfgmgr32_lib_handle) {
229 if (s_DeviceNotificationFuncHandle && CM_Unregister_Notification) {
230 CM_Unregister_Notification(s_DeviceNotificationFuncHandle);
231 s_DeviceNotificationFuncHandle = NULL;
232 }
233
234 FreeLibrary(cfgmgr32_lib_handle);
235 cfgmgr32_lib_handle = NULL;
236 }
237}
238
239#else
240
241void WIN_InitDeviceNotification(void)
242{
243}
244
245Uint64 WIN_GetLastDeviceNotification( void )
246{
247 return 0;
248}
249
250void WIN_QuitDeviceNotification(void)
251{
252}
253
254#endif // !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES