Skip to content

rafaelvaloto/Unreal-Dualsense

Repository files navigation

Middleware Unreal-Dualsense

Integrate all the features of Sony's DualSense™ and DualShock 4® controllers into your Unreal Engine project.

Report Bug · Suggest a Feature · Documentation

License Latest Release Unreal Engine 5.2+

Platform: Windows Platform: Linux Platform: macOS Platform: PlayStation

Getting StartedBasic UsageTutorialsExtend Middleware

Download the sample app on Steam, or watch the demonstration video on YouTube:

On Steam Watch YouTube


📖 About the Project

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.

✨ Features

  • 🏗️ 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.

🚀 Getting Started

Quick Installation

Go to the official page on the Unreal Engine Marketplace (FAB): Middleware Gold Edition - FAB

🔒 V2 Gold Version Access (Exclusive for Buyers)

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.

⚠️ Important: How to Request Access

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.

Manual Installation

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

💻 Basic Usage

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.


🎓 Hands-On Tutorial

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]


💉 Injecting Custom Device Logic (Custom DeviceManager)

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 for UForceFeedbackEffect assets.
    • SetLightColor / ResetLightColor: Controls the controller's LED.
    • SetDeviceProperty: Handles UInputDeviceProperty (e.g., Adaptive Triggers via Unreal 5.1+ system).
    • GetHapticDevice: Returns the IHapticDevice* interface (usually return this;).
    • IsGamepadAttached: Returns whether the device is currently connected.

Custom implementation example:

  1. 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 */
				);
			}
		}
	}

};
  1. 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" );
  1. 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" 
        });
    }
}

💉 Injecting Custom Platforms (e.g., PlayStation)

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.

  1. 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 */ }
    };
}
  1. 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");
  1. 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");
    }
}

⭐ Special Thanks

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).

⭐ Credits and Acknowledgments

The foundation of this Middleware was built upon the research and code from several amazing projects in the community:

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.


🤝 How to Contribute

Contributions are welcome! If you have ideas, suggestions, or bug fixes, feel free to open an Issue or submit a Pull Request.


⚖️ Disclaimer and Trademarks

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.

Sponsor this project

 

Packages

 
 
 

Contributors

Languages