Reference

C++ API

Use the Adaptive Pad subsystem and trigger effect factories from C++.

Module dependency

Add the plugin module to your game's .Build.cs:

MyGame.Build.cs
PublicDependencyModuleNames.Add("AdaptivePad");

UDualSenseSubsystem

#include "UDualSenseSubsystem.h"

A UGameInstanceSubsystem that stores the output state of each controller and sends it. Get it from the Game Instance:

UDualSenseSubsystem* Pad = GetGameInstance()->GetSubsystem<UDualSenseSubsystem>();

The Blueprint nodes are thin wrappers around these functions, with the same behaviour: setters change the stored state, UpdateOutput sends it.

Output

void UpdateOutput(int32 ControllerId = 0);

void SetLightbarColor(int32 ControllerId, FLinearColor Color);
void DisableLightbar(int32 ControllerId);

void SetPlayerLeds(int32 ControllerId, EPlayerLedPreset Preset,
    ELedBrightness Brightness = ELedBrightness::High, bool bFade = false);
void SetPlayerLedsBitmask(int32 ControllerId, EPlayerLed Bitmask,
    ELedBrightness Brightness = ELedBrightness::High, bool bFade = false);
void SetMicLed(int32 ControllerId, EMicLed State);

void SetRumble(int32 ControllerId, float LeftIntensity, float RightIntensity);
void StopRumble(int32 ControllerId);

// Speaker and headphone jack volume, 0-1, for sound sent to a DualSense Speaker submix.
void SetAudioVolume(int32 ControllerId, float SpeakerVolume, float HeadphoneVolume);

void SetTriggerEffect(int32 ControllerId, EDSTriggerHand Hand, const FDS5TriggerEffect& Effect);
void StopTrigger(int32 ControllerId, EDSTriggerHand Hand);

void SetFullOutputState(int32 ControllerId, const FDS5OutputState& State);
void ResetOutputState(int32 ControllerId);

State and status

bool IsControllerConnected(int32 ControllerId = 0) const;
int32 GetConnectedControllerCount() const;

// The stored output state of a slot, or nullptr if nothing was set for it yet.
const FDS5OutputState* GetCachedState(int32 ControllerId) const;

// Gyroscope, accelerometer, gravity and tilt. False if the slot has no controller.
bool GetMotion(int32 ControllerId, FDSMotion& OutMotion) const;

// Gyroscope integrated since the last reset (what DS Get Orientation returns as a Rotator).
bool GetOrientation(int32 ControllerId, FQuat& OutOrientation) const;
void ResetOrientation(int32 ControllerId);

Touchpad, battery, headphones and trigger feedback are read with the static functions of UDualSenseFunctionLibrary (#include "UDualSenseFunctionLibrary.h"), the same ones behind the Blueprint nodes:

FDSTouchPoint Finger1, Finger2;
if (UDualSenseFunctionLibrary::GetTouchpad(this, Finger1, Finger2, 0) && Finger1.bTouching)
{
    const FVector2D Position = Finger1.Position; // 0-1, origin top-left
}

FDSBatteryInfo Battery;
UDualSenseFunctionLibrary::GetBattery(this, Battery, 0);
const bool bHeadphones = UDualSenseFunctionLibrary::AreHeadphonesConnected(this, 0);
UpdateOutput on a slot that was never set sends the default state: everything off.

FDS5TriggerEffect factories

#include "DS5States.h"

Static functions that build a trigger effect with the same parameters as the DS Make Trigger ... nodes:

static FDS5TriggerEffect MakeOff();
static FDS5TriggerEffect MakeFeedback(int32 Position, int32 Strength);
static FDS5TriggerEffect MakeWeapon(int32 StartPosition, int32 EndPosition, int32 Strength);
static FDS5TriggerEffect MakeVibration(int32 Position, int32 Amplitude, int32 Frequency);
static FDS5TriggerEffect MakeSlopeFeedback(int32 StartPosition, int32 EndPosition, int32 StartStrength, int32 EndStrength);
static FDS5TriggerEffect MakeMultiplePositionFeedback(const TArray<int32>& ZoneStrengths);
static FDS5TriggerEffect MakeMultiplePositionVibration(int32 Frequency, const TArray<int32>& ZoneAmplitudes);
static FDS5TriggerEffect MakeBow(int32 StartPosition, int32 EndPosition, int32 Strength, int32 SnapForce);
static FDS5TriggerEffect MakeGalloping(int32 StartPosition, int32 EndPosition, int32 FirstFoot, int32 SecondFoot, int32 Frequency);
static FDS5TriggerEffect MakeMachine(int32 StartPosition, int32 EndPosition, int32 AmplitudeA, int32 AmplitudeB, int32 Frequency, int32 Period);
static FDS5TriggerEffect MakeRaw(const TArray<uint8>& Bytes);

Example: a tool component

MyToolComponent.cpp
#include "UDualSenseSubsystem.h"

void UMyToolComponent::OnEquipped()
{
    if (UDualSenseSubsystem* Pad = GetWorld()->GetGameInstance()->GetSubsystem<UDualSenseSubsystem>())
    {
        Pad->SetTriggerEffect(0, EDSTriggerHand::Right, FDS5TriggerEffect::MakeWeapon(2, 5, 3));
        Pad->SetLightbarColor(0, FLinearColor(0.f, 0.8f, 0.6f));
        Pad->UpdateOutput(0);
    }
}

void UMyToolComponent::OnPutAway()
{
    if (UDualSenseSubsystem* Pad = GetWorld()->GetGameInstance()->GetSubsystem<UDualSenseSubsystem>())
    {
        Pad->StopTrigger(0, EDSTriggerHand::Right);
        Pad->DisableLightbar(0);
        Pad->UpdateOutput(0);
    }
}

Input keys

The extra keys are registered as FKeys named DualSense_PS, DualSense_Touchpad, DualSense_Mic, and for the touchpad fingers DualSense_Touch1, DualSense_Touch1_X, DualSense_Touch1_Y (and the same with Touch2). Motion uses Unreal's own EKeys::Tilt, EKeys::RotationRate, EKeys::Gravity and EKeys::Acceleration:

static const FKey PSButton(TEXT("DualSense_PS"));

if (PlayerController->WasInputKeyJustPressed(PSButton))
{
    OpenPauseMenu();
}

The other buttons use the standard EKeys::Gamepad_* keys. See Input.

Logging

The plugin logs to the LogDualSense category: connections, disconnections and failed writes to the controller.

© 2026 Adaptive Pad by Altercode. Blueprint graphs rendered with ueblueprint (MIT). 3D controller based on a model by AHarmlessPotato, CC BY 4.0: rigged, split into moving parts, Sony marks removed.

Not affiliated with or endorsed by Sony Interactive Entertainment. "DualSense" is a registered trademark or trademark of Sony Interactive Entertainment Inc., used here only to describe compatibility. "Unreal" and "Unreal Engine" are trademarks or registered trademarks of Epic Games, Inc.