Integrate all the features of Sony's DualSense™ and DualShock 4® controllers into your Unreal Engine project.
Report Bug
·
Suggest a Feature
·
Documentation
Getting Started •
Basic Usage •
Tutorials •
Extend Middleware
Download the sample app on Steam, or watch the demonstration video on YouTube:
Built with a cross-platform architecture, this Unreal Engine Middleware provides a unified solution for integrating DualSense™ (PlayStation 5) and DualShock 4® (PlayStation 4) controllers. It delivers native support on PC while being architected for easy compilation across other Unreal Engine platforms, including PlayStation®. This asset provides direct API access to the complete feature set of each controller, including the revolutionary Haptic Feedback and Adaptive Triggers of the DualSense™. All features are exposed through a clean and well-documented function library for both Blueprint and C++.
Designed to bridge the gap left by generic controller support, this asset empowers developers to implement the high-fidelity, immersive feedback that makes Sony's controllers unique.
- 🏗️ Extensible Multi-Platform Architecture: Its flexible design enables compilation across all Unreal Engine platforms. Supporting new hardware is as simple as implementing the connection interface.
- 🔌 Dynamic Connection (Hot-Swap): Automatically detects controller connection and disconnection, even during gameplay.
- ⚡ Optimized for Multiplayer: High-performance architecture with minimal impact on network games.
- 🎮 Seamless Input Integration: Coexists perfectly with Unreal Engine's native input managers (like Enhanced Input) and other gamepad Middlewares, preventing conflicts between devices.
- 🎧 Audio Haptics (USB & Wireless): Haptic feedback based on in-game audio.
- 🎯 Adaptive Triggers: Full control over resistance, effect, and vibration on R2/L2 triggers.
- 💡 Lightbar Control: Dynamically change the controller's LED color.
- 🎤 Smart Mute Detection — Automatic mute LED control, no coding required
- ⚙️ Force Feedback: Native integration with Unreal Engine's Force Feedback system for standard motor vibration.
- 🎮 Multi-Controller Support: Manage up to 4 controllers simultaneously.
Go to the official page on the Unreal Engine Marketplace (FAB): Middleware Gold Edition - FAB
If you have purchased the Gold version, your purchase verification grants you full access to the private GitHub repository, which includes:
- Full & Detailed Documentation: Comprehensive guides to get you started quickly.
- Practical Examples: Hands-on integration samples for features like high-fidelity audio and audio-based haptics (vibration) over both Bluetooth and USB.
Click the link below to provide your GitHub username and Order ID: 👉 Fill out the Access Form
- Already bought the Gold Edition? Just fill out the form with your Gold Order ID.
- Upgrading from Controller Support v2? If you purchased the v2 version on FAB up until May 16th, 2026, you are eligible for a free migration. Simply fill out the form using your v2 Order ID.
Access is usually granted within 24 hours. You will receive a GitHub invitation via email or directly in your platform notifications.
To ensure the Middleware compiles correctly within Unreal Engine, you must configure the GamepadCore submodule.
Please run the following commands in your terminal (Git Bash, PowerShell, or CMD):
# Clone the repository at version (tag)
git clone -b v2.1.0 --single-branch https://github.com/rafaelvaloto/Unreal-Dualsense.git# Clone the repository at master branch
git clone https://github.com/rafaelvaloto/Unreal-Dualsense.git
# Enter the repository folder
cd Unreal-Dualsense
# Init the submodule to the latest version
git submodule update --init
The Middleware exposes all functionality through static Blueprint function libraries, meaning you can call methods from anywhere without needing to add components.
📚 For the full documentation, please see the Wiki.
We've created a detailed, step-by-step tutorial that breaks down the entire implementation within the example project. It's the perfect guide to get you started.
-
🎯 Gyroscope Aiming: A complete tutorial on how to implement a precise and responsive Aim Down Sights (ADS) gyro aiming system using the Arena Shooter template. ➡️ [Read the Gyroscope Aiming Tutorial]
-
🔫 Arena Shooter: An example using the Arena Shooter template that implements adaptive triggers for automatic/semi-automatic weapons and haptic feedback for player damage. ➡️ [Read the Arena Shooter Tutorial]
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 plugin 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"
});
}
}The plugin features a decoupled architecture using Policy-Based Design, allowing developers to integrate other platform SDKs (such as the official Sony PlayStation® SDK) or custom HID wrappers directly from their Game Project.
The primary advantage is that you do not need to modify the plugin's source code. You can inject your implementation during the application startup.
- Implementation via Hardware Policy Low-level hardware communication is abstracted through a Template-Policy system. To add a new platform, you create a simple C++ struct in your project that implements the required hardware methods (Read, Write, Detect, etc.).
#pragma once
#include "CoreMinimal.h"
namespace SonyPlatformPolicy
{
struct FSonyHardware
{
FSonyHardware() = default;
// Implementation of the required Hardware Policy methods
void Read(FDeviceContext* Context) { /* Your SDK Read */ }
void Write(FDeviceContext* Context) { /* Your SDK Write */ }
void Detect(TArray<FDeviceContext>& Devices) { /* Your SDK Detect */ }
bool CreateHandle(FDeviceContext* Context) { return true; }
void InvalidateHandle(FDeviceContext* Context) { /* Cleanup */ }
void ProcessAudioHaptic(FDeviceContext* Context) { /* Haptics logic */ }
};
}- Injection via Game Module Instead of modifying a singleton inside the plugin, you "inject" your custom hardware platform during your Game Module's startup. This ensures your project-specific logic takes precedence over the default HID implementation. Example Implementation in your Game Module (NewDeveloper.cpp):
#include "NewDeveloper.h"
#include "Modules/ModuleManager.h"
#include "Implementations/Platforms/Others/GamepadHardwareBridge.h"
#include "Platforms/SonyPlatformPolicy.h"
#include <memory>
class FNewDeveloper : public FDefaultGameModuleImpl {
public:
virtual bool IsGameModule() const override { return true; }
virtual void StartupModule() override {
// Injecting the custom hardware platform into the Plugin Bridge
auto CustomPlatform = std::make_unique<SonyPlatformPolicy::FSonyHardware>();
FGamepadHardwareBridge::InjectHardwarePlatform(std::move(CustomPlatform));
UE_LOG(LogTemp, Log, TEXT("NewDeveloper Game Module: Custom Hardware Policy Injected."));
}
};
IMPLEMENT_PRIMARY_GAME_MODULE(FNewDeveloper, NewDeveloper, "NewDeveloper");- Build Configuration Ensure your project's Build.cs includes the plugin 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"
});
// Add your custom SDK libraries here
// PublicSystemLibraries.Add("MySDK.lib");
}
}A special thanks to the following contributors who help maintain and improve this repository:
- Marat Radchenko (slonopotamus) - For his invaluable help and dedication to maintaining this repository.
- yncat: For the extensive research and implementation logic regarding USB Audio Haptics, which was crucial for supporting high-fidelity haptics via USB (Issue #105).
The foundation of this Middleware was built upon the research and code from several amazing projects in the community:
- DualSense on Windows API - Initial DS5 implementation logic.
- SAxense - Base for Bluetooth Audio Haptics.
- Awalol/DS5Dongle - Reference Bluetooth Audio (Headset/Speaker) opus codec and buffer sizes.
- Ryochan7/DS4Windows - Industry standard for DualShock/DualSense on Windows.
- linux/drivers/hid/hid-playstation.c - Reference for calibration, gyroscope, and Linux driver standards.
A special thanks to the Unreal Engine team for providing the Arena Shooter templates, which served as an excellent foundation for the example project demonstrating this Middleware's features.
Contributions are welcome! If you have ideas, suggestions, or bug fixes, feel free to open an Issue or submit a Pull Request.
This software is an independent and unofficial project. It is not affiliated, associated, authorized, endorsed by, or in any way officially connected with Sony Interactive Entertainment Inc., Microsoft Corporation, Apple Inc., Epic Games, Unity Technologies, the Godot Engine project, or the Open 3D Foundation.
Trademarks belong to their respective owners:
- Sony: "PlayStation", "PlayStation Family Mark", "PS5 logo", "PS5", "DualSense", and "DualShock" are registered trademarks or trademarks of Sony Interactive Entertainment Inc. "SONY" is a registered trademark of Sony Corporation.
- Microsoft: "Windows" and "Xbox" are registered trademarks of Microsoft Corporation.
- Apple: "Mac" and "macOS" are registered trademarks of Apple Inc.
- Linux: "Linux" is the registered trademark of Linus Torvalds in the U.S. and other countries.
- Epic Games: "Unreal" and "Unreal Engine" are trademarks or registered trademarks of Epic Games, Inc. in the United States of America and elsewhere.
- Unity: "Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere.
- Godot: "Godot" and the Godot logo are trademarks of the Godot Engine project.
- O3DE: "O3DE" and the O3DE logo are trademarks of the Open 3D Foundation.