Path: blob/master/thirdparty/sdl/core/windows/SDL_hid.c
9905 views
/*1Simple DirectMedia Layer2Copyright (C) 1997-2025 Sam Lantinga <[email protected]>34This software is provided 'as-is', without any express or implied5warranty. In no event will the authors be held liable for any damages6arising from the use of this software.78Permission is granted to anyone to use this software for any purpose,9including commercial applications, and to alter it and redistribute it10freely, subject to the following restrictions:11121. The origin of this software must not be misrepresented; you must not13claim that you wrote the original software. If you use this software14in a product, an acknowledgment in the product documentation would be15appreciated but is not required.162. Altered source versions must be plainly marked as such, and must not be17misrepresented as being the original software.183. This notice may not be removed or altered from any source distribution.19*/20#include "SDL_internal.h"2122#include "SDL_hid.h"2324HidD_GetAttributes_t SDL_HidD_GetAttributes;25HidD_GetString_t SDL_HidD_GetManufacturerString;26HidD_GetString_t SDL_HidD_GetProductString;27HidP_GetCaps_t SDL_HidP_GetCaps;28HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;29HidP_GetValueCaps_t SDL_HidP_GetValueCaps;30HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;31HidP_GetData_t SDL_HidP_GetData;3233static HMODULE s_pHIDDLL = 0;34static int s_HIDDLLRefCount = 0;353637bool WIN_LoadHIDDLL(void)38{39if (s_pHIDDLL) {40SDL_assert(s_HIDDLLRefCount > 0);41s_HIDDLLRefCount++;42return true; // already loaded43}4445s_pHIDDLL = LoadLibrary(TEXT("hid.dll"));46if (!s_pHIDDLL) {47return false;48}4950SDL_assert(s_HIDDLLRefCount == 0);51s_HIDDLLRefCount = 1;5253SDL_HidD_GetAttributes = (HidD_GetAttributes_t)GetProcAddress(s_pHIDDLL, "HidD_GetAttributes");54SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");55SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");56SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");57SDL_HidP_GetButtonCaps = (HidP_GetButtonCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetButtonCaps");58SDL_HidP_GetValueCaps = (HidP_GetValueCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetValueCaps");59SDL_HidP_MaxDataListLength = (HidP_MaxDataListLength_t)GetProcAddress(s_pHIDDLL, "HidP_MaxDataListLength");60SDL_HidP_GetData = (HidP_GetData_t)GetProcAddress(s_pHIDDLL, "HidP_GetData");61if (!SDL_HidD_GetManufacturerString || !SDL_HidD_GetProductString ||62!SDL_HidP_GetCaps || !SDL_HidP_GetButtonCaps ||63!SDL_HidP_GetValueCaps || !SDL_HidP_MaxDataListLength || !SDL_HidP_GetData) {64WIN_UnloadHIDDLL();65return false;66}6768return true;69}7071void WIN_UnloadHIDDLL(void)72{73if (s_pHIDDLL) {74SDL_assert(s_HIDDLLRefCount > 0);75if (--s_HIDDLLRefCount == 0) {76FreeLibrary(s_pHIDDLL);77s_pHIDDLL = NULL;78}79} else {80SDL_assert(s_HIDDLLRefCount == 0);81}82}8384#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)8586// CM_Register_Notification definitions8788#define CR_SUCCESS 08990DECLARE_HANDLE(HCMNOTIFICATION);91typedef HCMNOTIFICATION *PHCMNOTIFICATION;9293typedef enum _CM_NOTIFY_FILTER_TYPE94{95CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0,96CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE,97CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE,98CM_NOTIFY_FILTER_TYPE_MAX99} CM_NOTIFY_FILTER_TYPE, *PCM_NOTIFY_FILTER_TYPE;100101typedef struct _CM_NOTIFY_FILTER102{103DWORD cbSize;104DWORD Flags;105CM_NOTIFY_FILTER_TYPE FilterType;106DWORD Reserved;107union108{109struct110{111GUID ClassGuid;112} DeviceInterface;113struct114{115HANDLE hTarget;116} DeviceHandle;117struct118{119WCHAR InstanceId[200];120} DeviceInstance;121} u;122} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER;123124typedef enum _CM_NOTIFY_ACTION125{126CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0,127CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL,128CM_NOTIFY_ACTION_DEVICEQUERYREMOVE,129CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED,130CM_NOTIFY_ACTION_DEVICEREMOVEPENDING,131CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE,132CM_NOTIFY_ACTION_DEVICECUSTOMEVENT,133CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED,134CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED,135CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED,136CM_NOTIFY_ACTION_MAX137} CM_NOTIFY_ACTION, *PCM_NOTIFY_ACTION;138139typedef struct _CM_NOTIFY_EVENT_DATA140{141CM_NOTIFY_FILTER_TYPE FilterType;142DWORD Reserved;143union144{145struct146{147GUID ClassGuid;148WCHAR SymbolicLink[ANYSIZE_ARRAY];149} DeviceInterface;150struct151{152GUID EventGuid;153LONG NameOffset;154DWORD DataSize;155BYTE Data[ANYSIZE_ARRAY];156} DeviceHandle;157struct158{159WCHAR InstanceId[ANYSIZE_ARRAY];160} DeviceInstance;161} u;162} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA;163164typedef DWORD (CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize);165166typedef DWORD (WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext);167typedef DWORD (WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext);168169static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };170171static int s_DeviceNotificationsRequested;172static HMODULE cfgmgr32_lib_handle;173static CM_Register_NotificationFunc CM_Register_Notification;174static CM_Unregister_NotificationFunc CM_Unregister_Notification;175static HCMNOTIFICATION s_DeviceNotificationFuncHandle;176static Uint64 s_LastDeviceNotification = 1;177178static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size)179{180if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL ||181action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) {182s_LastDeviceNotification = SDL_GetTicksNS();183}184return ERROR_SUCCESS;185}186187void WIN_InitDeviceNotification(void)188{189++s_DeviceNotificationsRequested;190if (s_DeviceNotificationsRequested > 1) {191return;192}193194cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");195if (cfgmgr32_lib_handle) {196CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification");197CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification");198if (CM_Register_Notification && CM_Unregister_Notification) {199CM_NOTIFY_FILTER notify_filter;200201SDL_zero(notify_filter);202notify_filter.cbSize = sizeof(notify_filter);203notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;204notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID;205if (CM_Register_Notification(¬ify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) {206return;207}208}209}210211// FIXME: Should we log errors?212}213214Uint64 WIN_GetLastDeviceNotification(void)215{216return s_LastDeviceNotification;217}218219void WIN_QuitDeviceNotification(void)220{221if (--s_DeviceNotificationsRequested > 0) {222return;223}224// Make sure we have balanced calls to init/quit225SDL_assert(s_DeviceNotificationsRequested == 0);226227if (cfgmgr32_lib_handle) {228if (s_DeviceNotificationFuncHandle && CM_Unregister_Notification) {229CM_Unregister_Notification(s_DeviceNotificationFuncHandle);230s_DeviceNotificationFuncHandle = NULL;231}232233FreeLibrary(cfgmgr32_lib_handle);234cfgmgr32_lib_handle = NULL;235}236}237238#else239240void WIN_InitDeviceNotification(void)241{242}243244Uint64 WIN_GetLastDeviceNotification( void )245{246return 0;247}248249void WIN_QuitDeviceNotification(void)250{251}252253#endif // !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES254255256