Skip to content

rafaelvaloto/o3de-dualsense

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

12 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

o3de-dualsense

๐ŸŽฎ o3de-dualsense

Sony DualSense Controller Integration for O3DE
A prototype gem showcasing GamepadCore integration with the O3DE Input System

O3DE Gem Platform License Status


๐Ÿ“– Overview

o3de-dualsense is a prototype gem that demonstrates how to integrate Sony DualSense (PS5) controllers into O3DE using GamepadCore. This project serves as a starting point and reference implementation for developers looking to add custom gamepad support to their O3DE projects.

โš ๏ธ Note: This is a prototype for validating GamepadCore use cases. It provides a solid foundation but is not a production-ready implementation.


โœจ Features

Feature Status
๐Ÿ”Œ Plug & Play device detection โœ…
๐Ÿ•น๏ธ Face buttons (Cross, Circle, Square, Triangle) โœ…
๐ŸŽฏ Analog triggers (L2/R2) โœ…
๐Ÿ•น๏ธ Analog sticks (Left/Right) โœ…
๐Ÿ’ก Lightbar color control โœ…
๐Ÿ“ณ Haptic vibration โœ…
๐Ÿ”ซ Adaptive triggers โœ…
๐Ÿ–ฅ๏ธ Windows platform support โœ…
๐Ÿง Linux platform support ๐Ÿšง Planned

๐Ÿ—๏ธ Architecture

o3de-dualsense/
โ”œโ”€โ”€ Code/
โ”‚   โ”œโ”€โ”€ Include/                    # Public headers
โ”‚   โ”œโ”€โ”€ Source/
โ”‚   โ”‚   โ”œโ”€โ”€ Adapters/               # GamepadCore โ†” O3DE bridge
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ DeviceRegistry.h    # Device management & EBus integration
โ”‚   โ”‚   โ”œโ”€โ”€ Clients/                # System component implementation
โ”‚   โ”‚   โ”œโ”€โ”€ Devices/                # O3DE InputDevice implementation
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ DualSenseInputDevice.cpp
โ”‚   โ”‚   โ”œโ”€โ”€ Platforms/
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ Windows/            # Platform-specific policies
โ”‚   โ”‚   โ””โ”€โ”€ ThirdParty/
โ”‚   โ”‚       โ””โ”€โ”€ GamepadCore/        # GamepadCore library
โ”‚   โ””โ”€โ”€ Platform/                   # Platform build configs
โ””โ”€โ”€ Registry/                       # Asset processor settings

๐Ÿ”ง How It Works

The Input Pipeline

The gem creates a bridge between GamepadCore (low-level controller communication) and O3DE's Input System (high-level game input).

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  DualSense  โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ GamepadCore โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚  Adapter    โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ O3DE Input  โ”‚
โ”‚  Hardware   โ”‚     โ”‚  Library    โ”‚     โ”‚  Layer      โ”‚     โ”‚  System     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Processing Raw Input

The core of the input translation happens in DualSenseInputDevice::ProcessRawInput():

void DualSenseInputDevice::ProcessRawInput(FDeviceContext* Context) {
    if (!Context) return;

    const auto& state = Context->GetInputState();

    // Face Buttons โ†’ O3DE Digital Channels
    if (buttonCross) buttonCross->SimulateRawInput(state.bCross);
    if (buttonCircle) buttonCircle->SimulateRawInput(state.bCircle);
    if (buttonSquare) buttonSquare->SimulateRawInput(state.bSquare);
    if (buttonTriangle) buttonTriangle->SimulateRawInput(state.bTriangle);

    // Analog Triggers โ†’ O3DE Analog Channels
    if (L2) L2->SimulateRawInput(state.LeftTriggerAnalog);
    if (R2) R2->SimulateRawInput(state.RightTriggerAnalog);

    // Analog Sticks โ†’ O3DE Axis2D Channels
    AZ::Vector2 leftStick(state.LeftAnalog.X, state.LeftAnalog.Y);
    if (AnalogLeft) AnalogLeft->SimulateRawInput2D(leftStick.GetX(), leftStick.GetY());

    AZ::Vector2 rightStick(state.RightAnalog.X, state.RightAnalog.Y);
    if (AnalogRight) AnalogRight->SimulateRawInput2D(rightStick.GetX(), rightStick.GetY());
}

Key Points:

  • FDeviceContext provides the raw controller state from GamepadCore
  • SimulateRawInput() feeds values into O3DE's input channel system
  • Buttons map to standard gamepad buttons (A/B/X/Y)
  • Triggers provide analog 0.0-1.0 values
  • Sticks provide 2D axis values

Device Registry Pattern

The DeviceRegistry manages controller lifecycle using a policy-based design:

struct DeviceRegistryPolicy {
    using EngineIdType = AZ::u32;
    std::unordered_map<EngineIdType, std::unique_ptr<DualSenseInputDevice>> CustomDevicesMap;

    void DispatchNewGamepad(EngineIdType GamepadId) {
        InputDeviceId deviceName(AZStd::string_view("dualsense"), GamepadId);
        auto DualInputDevice = std::make_unique<DualSenseInputDevice>(deviceName);
        CustomDevicesMap[GamepadId] = std::move(DualInputDevice);
        CustomDevicesMap[GamepadId]->SetConnected(true);
    }

    void DisconnectDevice(EngineIdType GamepadId) {
        CustomDevicesMap.erase(GamepadId);
    }
};

This pattern allows:

  • ๐Ÿ”„ Automatic device detection and registration
  • ๐ŸŽฎ Multiple controller support
  • ๐Ÿ”Œ Hot-plug/unplug handling
  • ๐Ÿ“ก O3DE EBus integration

Platform Abstraction

Platform-specific code is isolated using policy classes:

struct WindowsHardwarePolicy {
    void Read(FDeviceContext* Context) {
        WindowsDeviceInfo::Read(Context);
    }

    void Write(FDeviceContext* Context) {
        WindowsDeviceInfo::Write(Context);
    }

    void Detect(std::vector<FDeviceContext>& Devices) {
        WindowsDeviceInfo::Detect(Devices);
    }

    void ProcessAudioHaptic(FDeviceContext* Context) {
        WindowsDeviceInfo::ProcessAudioHapitc(Context);
    }
};

๐Ÿš€ Quick Start

1. Add the Gem to Your Project

Copy the gem to your O3DE project's Gems/ directory or register it globally.

2. Enable the Gem

Add to your project's project.json:

{
    "gem_dependencies": [
        "o3de-dualsense"
    ]
}

3. Build Your Project

cmake --build build/windows --target YourProject.GameLauncher --config profile

4. Connect Your DualSense

Plug in your DualSense controller via USB. The gem automatically detects and registers it.


๐ŸŽฎ Using the Input

Once connected, DualSense inputs are available through O3DE's standard input system:

DualSense Button O3DE Input Channel
โœ• Cross gamepad_button_a
โ—‹ Circle gamepad_button_b
โ–ก Square gamepad_button_x
โ–ณ Triangle gamepad_button_y
L2 gamepad_trigger_l2
R2 gamepad_trigger_r2
Left Stick gamepad_stick_l
Right Stick gamepad_stick_r

๐Ÿ’ก DualSense-Specific Features

Lightbar Control

gamepad->SetLightbar({255, 0, 0}); // Set to red

Haptic Vibration

gamepad->SetVibration(10, 30); // Left motor: 10, Right motor: 30

Adaptive Triggers

IGamepadTrigger* Trigger = gamepad->GetIGamepadTrigger();
// Bow effect on L2
Trigger->SetBow22(0xf8, 0x3f, EDSGamepadHand::Left);
// Machine gun effect on R2
Trigger->SetMachine27(0x80, 0x02, 0x03, 0x0f, 0x19, 0x02, EDSGamepadHand::Right);

๐Ÿ“ Project Structure

Directory Purpose
Code/Include/ Public API headers
Code/Source/Adapters/ GamepadCore โ†” O3DE bridge layer
Code/Source/Clients/ System component implementation
Code/Source/Devices/ O3DE InputDevice wrapper
Code/Source/Platforms/ Platform-specific implementations
Code/Source/ThirdParty/ GamepadCore library
Code/Platform/ CMake platform configurations

๐Ÿ› ๏ธ Extending This Prototype

This gem provides a solid foundation. Here's how to extend it:

Add More Buttons

  1. Add new InputChannel* members in DualSenseInputDevice.h
  2. Create and register them in the constructor
  3. Process them in ProcessRawInput()

Add Linux Support

  1. Create Source/Platforms/Linux/DualSenseLinuxPolicy.h
  2. Implement the policy interface using Linux input subsystem
  3. Register the policy in the system component

Add Bluetooth Support

  1. Extend WindowsDeviceInfo to detect Bluetooth connections
  2. Handle different report formats for USB vs Bluetooth

๐Ÿ“‹ Requirements

  • O3DE 23.10 or later
  • GamepadCore library (included in ThirdParty/)
  • Windows 10/11 (for Windows builds)
  • DualSense Controller (PS5 controller)

๐Ÿค Contributing

Contributions are welcome! This is a prototype meant to evolve.

  1. Fork the repository
  2. Create your feature branch
  3. Implement your changes
  4. Submit a pull request

๐Ÿ“„ License

This project is licensed under the MIT License - see the gem.json for details.


โš–๏ธ 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.

About

This Gem integrates the Sony DualSense (PS5) controller into the Open 3D Engine (O3DE). It implements the AzFramework::InputDevice interface, allowing the controller to work out-of-the-box with standard O3DE input bindings. Powered by the GamepadCore library.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors