PS5 DualSense Bluetooth HID Report Format Reference

Compiled by YzzSoft Studio (Langzhou Wanderer)

For developers who want to add PS5 controller Bluetooth support to their games

Based on global open-source community reverse engineering — not official Sony documentation


1. The Core Problem: Why Your Game Works on USB but Not Bluetooth

PS5 controller uses the same HID Report ID 0x01 for both USB and Bluetooth — but with completely different byte layouts. If you parse Bluetooth data using the USB layout, you'll get garbage for stick directions and button states.


2. Three HID Report Formats

FormatReport IDSizeConnectionCompleteness
USB 0x010x01~64 bytesUSB WiredComplete
BT 0x010x0178 bytesBluetooth (Simplified)Sticks+Buttons+Triggers Only
BT 0x310x3178 bytesBluetooth (Full)All Sensors+Battery
Key Discovery: BT 0x01 and USB 0x01 share the same Report ID but NOT the same layout!

3. Byte Layout Reference (Tri-Offset System)

3.1 Analog Sticks (consistent across all three formats)

FieldUSB 0x01BT 0x01BT 0x31
Left Stick Xdata[1]data[1]data[2]
Left Stick Ydata[2]data[2]data[3]
Right Stick Xdata[3]data[3]data[4]
Right Stick Ydata[4]data[4]data[5]
Range: 0x00~0xFF, center ~0x80. Left=0x00, Right=0xFF (X-axis); Up=0x00, Down=0xFF (Y-axis).

3.2 Triggers ⚠ BT 0x01 differs from USB

FieldUSB 0x01BT 0x01BT 0x31
L2 Analogdata[5]data[8]data[6]
R2 Analogdata[6]data[9]data[7]

3.3 Buttons ⚠ BT 0x01 differs from USB

FieldUSB 0x01BT 0x01BT 0x31
D-Pad + Face Buttonsdata[8]data[5]data[9]
Shoulders + Systemdata[9]data[6]data[10]
PS / Touchpad / Mutedata[10]data[7]data[11]

3.4 Button Bitmasks

Byte 1 (D-Pad + Face Buttons):

bits 3-0: D-Pad hat switch (0=Up,1=Up-Right,2=Right,3=Down-Right,4=Down,5=Down-Left,6=Left,7=Up-Left,8~15=Neutral)
bit 4: Square (□)
bit 5: Cross (✕)
bit 6: Circle (○)
bit 7: Triangle (△)

Byte 2 (Shoulders + System Buttons):

bit 0: L1
bit 1: R1
bit 2: L2 Button (digital)
bit 3: R2 Button (digital)
bit 4: Create (Share)
bit 5: Options
bit 6: L3 (Left Stick Click)
bit 7: R3 (Right Stick Click)

Byte 3 (PS + Touch + Mute):

bit 0: PS Button
bit 1: TouchPad Click
bit 2: Mute (Microphone)

4. How to Switch to BT 0x31 Full Mode

Bluetooth connection defaults to BT 0x01 simplified mode — no battery info, no sensor data, no multi-touch. Send a GET FEATURE REPORT to trigger the switch:

// Read calibration data (Feature Report 0x05) — triggers mode switch
BYTE calib[42] = {0};  // 41 bytes data + 1 byte Report ID
calib[0] = 0x05;
HidD_GetFeature(hDevice, calib, sizeof(calib));
// Controller automatically switches from BT 0x01 to BT 0x31
This method comes from Linux kernel hid-playstation.c and open-source community reverse engineering.

5. Power / Battery Info

Battery data only available in BT 0x31 full report:

data[54] (0x31 format only):
  bits 0-3: Battery level (0~10, 0=0%, 10=100%)
  bit 4:    Charging status (1=Charging, 0=Discharging)

BT 0x01 simplified report does NOT include battery data. USB 0x01 battery at data[53].


Note: Adaptive Triggers and Bluetooth HID

PS5 DualSense adaptive triggers are USB-only on PC. Sony restricts adaptive triggers and HD haptic feedback to USB in firmware. This is a product strategy decision, not a bandwidth limitation — Bluetooth 5.0 has more than enough bandwidth. Third-party tools (like DSX) partially restore this via virtual USB device workarounds, proving Bluetooth HID output channels can carry adaptive trigger data.


6. C++ Source Code Reference

// —— Tri-offset variables ——
int stickOfs = 0, trigOfs = 0, btnOfs = 0;

if (data[0] == 0x31 && size >= 78) {
    // BT 0x31 full mode: all fields offset +1
    stickOfs = trigOfs = btnOfs = 1;
} else if (data[0] == 0x01) {
    if (size >= 78) {
        // BT 0x01 simplified: sticks same, triggers & buttons swapped
        stickOfs = 0;
        trigOfs  = 3;   // triggers at data[8~9]
        btnOfs   = -3;  // buttons at data[5~7]
    }
    // else: USB 64-byte — all offsets 0, no processing needed
}

// —— Read data ——
leftStickX  = data[1 + stickOfs];
leftStickY  = data[2 + stickOfs];
rightStickX = data[3 + stickOfs];
rightStickY = data[4 + stickOfs];

leftTrigger  = data[5 + trigOfs];
rightTrigger = data[6 + trigOfs];

uint8_t btn0 = data[8 + btnOfs];  // D-Pad + face buttons
uint8_t btn1 = data[9 + btnOfs];  // shoulders + system
uint8_t btn2 = data[10 + btnOfs]; // PS/touchpad/mute

7. Sources & Acknowledgements

Core information sourced from the following open-source projects and communities:

SourceContribution
Linux Kernel hid-playstation.cComplete driver reference, by Roderick Colenbrander
nondebug/dualsense (GitHub)HID report descriptors, BT 0x01 10-byte mapping
controllers.fandom.comData structure docs, calibration switching
PS5 Developer WikiHID command set, touchpad protocol
dsremapReverse engineering docs, 0x01→0x31 switch
dsfm / brc-xyz (GitHub)GET FEATURE 0x05 method confirmation
J_0k3r (CSDN)PS5 Bluetooth traffic packet capture analysis

8. About YzzPadView

YzzPadView is a PS5 controller desktop button indicator developed by Langzhou Wanderer (YzzSoft Studio). Completely free, no registration, no activation. Supports Windows 10/11, DualSense standard and Edge Elite.

World premiere: June 27, 2026. Full tri-offset system and BT 0x01→0x31 calibration switching implemented as described in this document.

If this document helped your game development, please mention Langzhou Wanderer and YzzSoft Studio in your credits. This is the result of years of work by our global open-source community.