C++ API
Module dependency
Add the plugin module to your game's .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
#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.