Enhanced Raw Input 1.0
Enhanced Raw Input for Unreal Engine
Loading...
Searching...
No Matches
EnhancedRawInputWindows.h
1// (c) 2025 by Lemontree Softworks - All Rights Reserved.
2
3#pragma once
4
5// A little bit hacky but Unreal only defines WINVER with 0x0601 (Windows 7), but for cfgmgr32 (Hotplug detection) we need at leat Windows 8
6#if WINVER < 0x602 // Win8
7 #undef WINVER
8 #define WINVER 0x602
9#endif
10
11#include "Engine/Engine.h"
12#include "Modules/ModuleManager.h"
13#include "EnhancedRawInput.h"
14#include "EnhancedRawInputSettings.h"
15#include "Framework/Application/SlateApplication.h"
16#include "Windows/WindowsApplication.h"
17#include "hidsdi.h"
18#include "cfgmgr32.h"
19
21constexpr auto MaxHidDevices = 16;
22
24constexpr auto MaxHidPovSwitches = 4;
25
26// See https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
27constexpr auto HidUsagePage = 0x01;
28constexpr auto HardwareUsageJoystick = 0x04;
29constexpr auto HardwareUsageGamepad = 0x05;
30constexpr auto HidUsagePov = 0x39;
31
32DECLARE_DELEGATE_OneParam(FHidDeviceConnectedDelegate, FString /* InterfaceName */);
33
35struct FWindowsHidApi
36{
37public:
38 typedef BOOLEAN(*HidD_GetSerialNumberString_Type)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
39 typedef BOOLEAN(*HidD_GetManufacturerString_Type)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
40 typedef BOOLEAN(*HidD_GetProductString_Type)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
41 typedef NTSTATUS(*HidP_GetCaps_Type)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
42 typedef NTSTATUS(*HidP_GetButtonCaps_Type)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
43 typedef NTSTATUS(*HidP_GetValueCaps_Type)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
44 typedef NTSTATUS(*HidP_GetUsages_Type)(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
45 typedef NTSTATUS(*HidP_GetUsageValue_Type)(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, PULONG UsageValue,PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
46 typedef NTSTATUS(*HidP_GetData_Type)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
47
48 FWindowsHidApi();
49 ~FWindowsHidApi();
50
51 HANDLE DllHandle = nullptr;
52
53 HidD_GetSerialNumberString_Type HidD_GetSerialNumberString;
54 HidD_GetManufacturerString_Type HidD_GetManufacturerString;
55 HidD_GetProductString_Type HidD_GetProductString;
56 HidP_GetCaps_Type HidP_GetCaps;
57 HidP_GetButtonCaps_Type HidP_GetButtonCaps;
58 HidP_GetValueCaps_Type HidP_GetValueCaps;
59 HidP_GetUsages_Type HidP_GetUsages;
60 HidP_GetUsageValue_Type HidP_GetUsageValue;
61 HidP_GetData_Type HidP_GetData;
62};
63
65struct FHidAxis
66{
67 FHidAxis() :
68 Value(0.0f),
69 KeyName(NAME_None),
70 bIsEnabled(false),
71 OutputType(ERawInputAxisOutputType::Gamepad),
72 Min(-1),
73 Max(-1),
74 Offset(0.0f),
75 bIsInverted(false),
76 bHasChanged(false)
77 {}
78
80 int32 Value;
81
83 FName KeyName;
84
87
89 ERawInputAxisOutputType OutputType;
90
92 int32 Min;
93
95 int32 Max;
96
98 float Offset;
99
102
105
108 float GetValue() const;
109
112 bool HasValue() const;
113};
114
116struct FHidButton
117{
118 FHidButton() :
119 bState(false),
120 bHasChanged(false),
121 KeyName(NAME_None),
122 bIsEnabled(false)
123 {}
124
126 bool bState;
127
130
132 FName KeyName;
133
136};
137
139struct FHidPov : FHidAxis
140{
141 FHidPov() : DataIndex(0), PovOutputType(ERawInputPovOutputType::POV)
142 {
143 ButtonStates.Init(false, MaxHidPovSwitches);
144 ButtonKeyNames.Init(NAME_None, MaxHidPovSwitches);
145 }
146
148 uint16 DataIndex;
149
151 TArray<bool> ButtonStates;
152
154 TArray<FName> ButtonKeyNames;
155
157 ERawInputPovOutputType PovOutputType;
158
161 int32 GetPovValueDeg() const;
162
164 void UpdateButtonValues();
165
168 float GetAxisValue() const;
169
173 bool HasButtonValue(uint32 Index) const;
174
177 bool HasAxisValue() const;
178};
179
181struct FHidDevice
182{
183 FHidDevice() :
184 Handle(nullptr),
185 DeviceInfo(0),
186 ControllerId(0),
189 UserId(PLATFORMUSERID_NONE),
190 DeviceId(INPUTDEVICEID_NONE),
191 bIsActive(true),
192 ConnectionState(EInputDeviceConnectionState::Invalid)
193 {
194 }
195
197 HANDLE Handle;
198
200 RID_DEVICE_INFO DeviceInfo;
201
204
207
210
213
216
218 FString ProductName;
219
222
224 FPlatformUserId UserId;
225
227 FInputDeviceId DeviceId;
228
231
233 EInputDeviceConnectionState ConnectionState;
234
236 TArray<FHidButton> Buttons;
237
239 TMap<int32, FHidAxis> Axis;
240
242 TArray<FHidPov> PoVs;
243};
244
246class FEnhancedRawInputWindows : public IEnhancedRawInput, IWindowsMessageHandler
247{
248 friend class UEnhancedRawInputSettings;
249
250public:
251 FEnhancedRawInputWindows(const TSharedRef<FGenericApplicationMessageHandler>& InMessageHandler);
252 virtual ~FEnhancedRawInputWindows() override;
253
254 // Begin IEnhancedRawInput
255 virtual void SetBindings(const FString InterfaceName) override;
256 virtual void SetAxisBinding(const FString InterfaceName, const int32 AxisUsage, const FName KeyName) override;
257 virtual void SetButtonBinding(const FString InterfaceName, const int32 ButtonIndex, const FName KeyName) override;
258 virtual void SetPovAxisBinding(const FString InterfaceName, const int32 PovIndex, FName KeyName) override;
259 virtual void SetPovButtonBinding(const FString InterfaceName, const int32 PovIndex, TArray<FName> KeyNames) override;
260 // End IEnhancedRawInput
261
262 // Begin IInputDevice interface
263 virtual void SetChannelValue(int32 ControllerId, FForceFeedbackChannelType ChannelType, float Value) override {}
264 virtual void SetChannelValues(int32 ControllerId, const FForceFeedbackValues &Values) override {}
265 virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override { return false; }
266 virtual void SetMessageHandler(const TSharedRef<FGenericApplicationMessageHandler> &InMessageHandler) override;
267 virtual void Tick(float DeltaTime) override;
268 virtual void SendControllerEvents() override;
269 virtual bool SupportsForceFeedback(int32 ControllerId) override { return false; }
270 // End IInputDevice interface
271
272 // Begin IWindowsMessageHandler interface
273 virtual bool ProcessMessage(HWND Hwnd, uint32 Msg, WPARAM WParam, LPARAM LParam, int32& OutResult) override;
274 // End IWindowsMessageHandler interface
275
277 void EnumerateDevices();
278
281 TArray<FHidDevice> GetConnectedDevices();
282
287 FHidDevice *FindDeviceByUserAndDeviceId(const FPlatformUserId UserId, const FInputDeviceId DeviceId);
288
291 FHidDevice* FindDeviceByInterfaceName(const FString& InterfaceName);
292
296 TMap<int32, FHidAxis> GetAxisInfo(const FString& InterfaceName);
297
301 TArray<FHidPov> GetPovInfo(const FString& InterfaceName);
302
306 void SetDeviceActivity(const FString& InterfaceName, bool bIsActive);
307
311 DWORD NotificationCallback(CM_NOTIFY_ACTION Action);
312
314 FHidDeviceConnectedDelegate HidDeviceConnectedHandler;
315
317 FHidDeviceConnectedDelegate HidDeviceDisconnectedHandler;
318
319private:
320 FWindowsHidApi HidApi;
321 typedef CONFIGRET(*CM_Register_Notification_Type)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext);
322
323 CM_Register_Notification_Type CmRegisterNotification;
324 HANDLE Cfgmgr32DllHandle = nullptr;
325 HCMNOTIFICATION NotifyContext;
326
327 bool bRefreshDevices = false;
328 FDateTime DeviceRefreshStart;
329
330 bool bDeviceRegistered = false;
331
332 FHidDevice HidDevices[MaxHidDevices];
333 TArray<FString> ActualConnectedDevices;
334
335 bool QueryDevices();
336 void QueryDeviceCaps(FHidDevice &Device) const;
337
338 FHidDevice *FindDeviceByHandle(HANDLE Handle);
339
340 void ShowDebug(AHUD* HUD, UCanvas* Canvas, const FDebugDisplayInfo& DisplayInfo, float& YL, float& YPos);
341
342 static bool TryRegisterInputDevice();
343};
344
345typedef FEnhancedRawInputWindows FPlatformEnhancedRawInput;
Windows Implementation.
Definition EnhancedRawInputWindows.h:247
virtual void SetButtonBinding(const FString InterfaceName, const int32 ButtonIndex, const FName KeyName) override
Binds a controller button to a corresponding key.
Definition EnhancedRawInputWindows.cpp:547
FHidDevice * FindDeviceByInterfaceName(const FString &InterfaceName)
Finds a device by provided interface name.
Definition EnhancedRawInputWindows.cpp:1309
virtual void SetBindings(const FString InterfaceName) override
Applies the key binding settings to the specified controller.
Definition EnhancedRawInputWindows.cpp:292
FHidDeviceConnectedDelegate HidDeviceConnectedHandler
Event when a HID device is connected.
Definition EnhancedRawInputWindows.h:314
FHidDevice * FindDeviceByUserAndDeviceId(const FPlatformUserId UserId, const FInputDeviceId DeviceId)
Finds a device by provided user and device ID.
Definition EnhancedRawInputWindows.cpp:1260
TArray< FHidPov > GetPovInfo(const FString &InterfaceName)
Returns information about all PoVs / Hat switches / D-PADs for a specific device.
Definition EnhancedRawInputWindows.cpp:1289
void SetDeviceActivity(const FString &InterfaceName, bool bIsActive)
Sets the activity of the device.
Definition EnhancedRawInputWindows.cpp:1300
virtual void SetPovAxisBinding(const FString InterfaceName, const int32 PovIndex, FName KeyName) override
Binds a controller POV axis to a corresponding key.
Definition EnhancedRawInputWindows.cpp:566
TArray< FHidDevice > GetConnectedDevices()
Returns information about all currently connected devices.
Definition EnhancedRawInputWindows.cpp:1246
virtual void SetPovButtonBinding(const FString InterfaceName, const int32 PovIndex, TArray< FName > KeyNames) override
Binds a controller POV to a corresponding keys.
Definition EnhancedRawInputWindows.cpp:585
void EnumerateDevices()
Updates the list of all connected controllers. Notifies the engine of any new or removed controllers.
Definition EnhancedRawInputWindows.cpp:1070
TMap< int32, FHidAxis > GetAxisInfo(const FString &InterfaceName)
Returns information about all axis for a specific device.
Definition EnhancedRawInputWindows.cpp:1278
DWORD NotificationCallback(CM_NOTIFY_ACTION Action)
Internal callback for hotplug detection, not for public use.
Definition EnhancedRawInputWindows.cpp:631
FHidDeviceConnectedDelegate HidDeviceDisconnectedHandler
Event when a HID device is disconnected.
Definition EnhancedRawInputWindows.h:317
virtual void SetAxisBinding(const FString InterfaceName, const int32 AxisUsage, const FName KeyName) override
Binds a controller axis to a corresponding key.
Definition EnhancedRawInputWindows.cpp:527
float Offset
Axis offset as configured.
Definition EnhancedRawInputWindows.h:98
int32 Max
Maximal value, as reported from the driver.
Definition EnhancedRawInputWindows.h:95
FName KeyName
Bound Key name.
Definition EnhancedRawInputWindows.h:83
int32 Min
Minimal value, as reported from the driver.
Definition EnhancedRawInputWindows.h:92
ERawInputAxisOutputType OutputType
Configured output type.
Definition EnhancedRawInputWindows.h:89
bool bIsInverted
Whether is axis inverted (from Configuration)
Definition EnhancedRawInputWindows.h:101
float GetValue() const
Value of this axis, normalised, inverted and/or in specific format, according to configuration.
Definition EnhancedRawInputWindows.cpp:50
bool bIsEnabled
TRUE if axis is enabled in settings.
Definition EnhancedRawInputWindows.h:86
bool HasValue() const
Whether this axis has valid value.
Definition EnhancedRawInputWindows.cpp:74
bool bHasChanged
Whether value has changed since last HID event.
Definition EnhancedRawInputWindows.h:104
int32 Value
Current value of this axis.
Definition EnhancedRawInputWindows.h:80
bool bIsEnabled
TRUE if button is enabled in settings.
Definition EnhancedRawInputWindows.h:135
bool bState
TRUE if button is pressed.
Definition EnhancedRawInputWindows.h:126
FName KeyName
Bound Key name.
Definition EnhancedRawInputWindows.h:132
bool bHasChanged
Whether value has changed since last HID event.
Definition EnhancedRawInputWindows.h:129
Stores information and data about a HID Device.
Definition EnhancedRawInputWindows.h:182
uint32 ButtonUsageMin
Internally used.
Definition EnhancedRawInputWindows.h:221
int32 ControllerId
Internal unique controller ID.
Definition EnhancedRawInputWindows.h:203
FPlatformUserId UserId
Current User ID for this device, as reported from Unreal engine.
Definition EnhancedRawInputWindows.h:224
bool bIsActive
Whether the device is active and being handled.
Definition EnhancedRawInputWindows.h:230
EInputDeviceConnectionState ConnectionState
Connection state for this device.
Definition EnhancedRawInputWindows.h:233
FInputDeviceId DeviceId
Current Device ID for this device, as reported from Unreal engine.
Definition EnhancedRawInputWindows.h:227
FString InterfaceName
Interface name as reported from driver.
Definition EnhancedRawInputWindows.h:209
FString SerialNumber
Serial number as reported from driver, may be empty.
Definition EnhancedRawInputWindows.h:215
TArray< FHidPov > PoVs
Information about all PoVs for this device.
Definition EnhancedRawInputWindows.h:242
TArray< FHidButton > Buttons
Information about all buttons for this device.
Definition EnhancedRawInputWindows.h:236
int32 NumberInputValueCaps
Number of HID Value (Axis) capability's, internally used.
Definition EnhancedRawInputWindows.h:206
HANDLE Handle
Internal HID Handle.
Definition EnhancedRawInputWindows.h:197
FString ProductName
Product name as reported from driver, may be empty.
Definition EnhancedRawInputWindows.h:218
RID_DEVICE_INFO DeviceInfo
Device info from driver, see https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-r...
Definition EnhancedRawInputWindows.h:200
TMap< int32, FHidAxis > Axis
Information about all axis for this device.
Definition EnhancedRawInputWindows.h:239
FString Manufacturer
Manufacturer name as reported from driver, may be empty.
Definition EnhancedRawInputWindows.h:212
bool HasAxisValue() const
Checks if axis is configured and has valid value.
Definition EnhancedRawInputWindows.cpp:157
ERawInputPovOutputType PovOutputType
Output type as configured.
Definition EnhancedRawInputWindows.h:157
float GetAxisValue() const
Returns (normalised, depends on output type) value.
Definition EnhancedRawInputWindows.cpp:121
TArray< bool > ButtonStates
Sates of the virtual D-Pad Buttons.
Definition EnhancedRawInputWindows.h:151
void UpdateButtonValues()
Updates the virtual D-PAD buttons, internally used.
Definition EnhancedRawInputWindows.cpp:92
uint16 DataIndex
Data index, internally used.
Definition EnhancedRawInputWindows.h:148
int32 GetPovValueDeg() const
Get Value of this POV.
Definition EnhancedRawInputWindows.cpp:81
bool HasButtonValue(uint32 Index) const
Checks if a button is configured and has valid value.
Definition EnhancedRawInputWindows.cpp:152
TArray< FName > ButtonKeyNames
Keynames as configured.
Definition EnhancedRawInputWindows.h:154
Internal structure for function pointers to Windows APIs. Not for public use.
Definition EnhancedRawInputWindows.h:36