-
Notifications
You must be signed in to change notification settings - Fork 0
๐ Injecting Custom Device Logic (Custom DeviceManager)
rafaelvaloto edited this page Jun 17, 2026
·
2 revisions
You can also inject a custom implementation of the DeviceManager. This is useful if you want to implement your own input buffering, custom button mapping, or specialized haptic logic without modifying the middleware source.
Tip
To ensure that your custom implementation works with native Unreal Engine assets (like Haptic Feedback Effects, Force Feedback Assets, and Device Properties), your class must correctly implement or override the methods from IInputDevice and IHapticDevice.
If you want your custom manager to support native Unreal features, ensure it implements/overrides:
-
IHapticDevice: haptic assets.-
SetHapticFeedbackValues: Processes frequency and amplitude values from assets. -
GetHapticFrequencyRange: Determines the valid frequency range supported by the device. -
GetHapticAmplitudeScale: Returns the scaling factor for amplitude mapping.
-
-
IInputDevice: Required for standard vibration, light color, and properties.-
SetChannelValues/SetChannelValue: Essential forUForceFeedbackEffectassets. -
SetLightColor/ResetLightColor: Controls the controller's LED. -
SetDeviceProperty: HandlesUInputDeviceProperty(e.g., Adaptive Triggers via Unreal 5.1+ system). -
GetHapticDevice: Returns theIHapticDevice*interface (usuallyreturn this;). -
IsGamepadAttached: Returns whether the device is currently connected.
-
- Create your custom class inheriting from
DeviceManager:
#include "DeviceManager.h"
#include "Modules/ModuleManager.h"
#include "WindowsDualsense_ds5w.h"
using namespace GCDevice;
class FMyCustomDeviceManager : public DeviceManager
{
public:
using DeviceManager::DeviceManager;
/** * Map to track the previous frame's touch state per DeviceID.
* Marked as 'mutable' so it can be updated within const methods.
*/
mutable TMap<int32, bool> DeviceTouchStates;
virtual void TouchpadImpl(FDeviceContext* Context, FInputContext& FrameInput, const FPlatformUserId UserId,
const FInputDeviceId InputDeviceId, float DeltaTime) const override
{
// --- 1. Basic Touch Mapping (Unreal Message Handler) ---
if (Context->bEnableTouch)
{
bool& bWasTouchDown = DeviceTouchStates.FindOrAdd(InputDeviceId.GetId(), false);
if (FrameInput.bIsTouching && !bWasTouchDown)
{
MessageHandler->OnTouchStarted(nullptr, FVector2D(FrameInput.TouchPosition.X, FrameInput.TouchPosition.Y), 1.0f, FrameInput.TouchId, UserId, InputDeviceId);
}
else if (FrameInput.bIsTouching && bWasTouchDown)
{
MessageHandler->OnTouchMoved(FVector2D(FrameInput.TouchPosition.X, FrameInput.TouchPosition.Y), 1.0f, FrameInput.TouchId, UserId, InputDeviceId);
}
else if (!FrameInput.bIsTouching && bWasTouchDown)
{
MessageHandler->OnTouchEnded(FVector2D(FrameInput.TouchPosition.X, FrameInput.TouchPosition.Y), FrameInput.TouchId, UserId, InputDeviceId);
}
bWasTouchDown = FrameInput.bIsTouching;
}
// --- 2. Gesture Mapping (Two-Finger Scroll) ---
if (Context->bEnableGesture)
{
// Check if exactly 2 fingers are touching the pad
if (FrameInput.bIsTouching && FrameInput.TouchFingerCount == 2)
{
MessageHandler->OnTouchGesture(
EGestureEvent::Scroll,
ScrollDelta,
0.0f, /* Value / Total movement if needed */
false /* IsInverted */
);
}
}
}
};
- Register your custom factory in your Game Module:
class FMyProject : public FDefaultGameModuleImpl {
public:
virtual bool IsGameModule() const override { return true; }
virtual void StartupModule() override {
FWindowsDualsense_ds5wModule::SetCustomInputDeviceFactory([](const TSharedRef<FGenericApplicationMessageHandler>& InHandler)
{
UE_LOG(LogTemp, Log, TEXT("MyProject Game Module: Init FMyCustomDeviceManager."));
return MakeShared<FMyCustomDeviceManager>(InHandler);
});
}
};
IMPLEMENT_PRIMARY_GAME_MODULE( FMyProject, MyProject, "MyProject" );- Build Configuration Ensure your project's Build.cs includes the middleware module and enables C++20 support:
public class NewDeveloper : ModuleRules
{
public NewDeveloper(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
// Required for Concepts and Policy-Based architecture
CppStandard = CppStandardVersion.Cpp20;
PublicDependencyModuleNames.AddRange(new string[] {
...
"WindowsDualsense_ds5w"
});
}
}