From a43078d08f98d0f8bc8cbc3dfd50d042119e930b Mon Sep 17 00:00:00 2001 From: rafaelvaloto Date: Sat, 26 Jul 2025 15:23:53 -0300 Subject: [PATCH 1/6] - Refactored accelerometer and gyroscope data parsing for improved clarity and accuracy. - Added support for DualSense Edge device (`0x0DF2`) in device detection. - Defined new constants for DualSense Edge function buttons and paddles in `DS5State.h`. - fix #19, #27, #29 --- .../include/DualSenseWindows/DS5State.h | 8 +++++++- .../src/DualSenseWindows/DS5_Input.cpp | 14 ++++++++------ .../DualSenseWindows/src/DualSenseWindows/IO.cpp | 4 ++-- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h index dd6a21c..9c04f2c 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h @@ -3,12 +3,18 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig Füchsl + 11.2020 Ludwig F�chsl Licensed under the MIT License (To be found in repository root directory) */ #pragma once +// Function Buttons DualSense Edge +#define DS5W_ISTATE_BTN_FN1 0x10 +#define DS5W_ISTATE_BTN_FN2 0x20 +#define DS5W_ISTATE_BTN_PADDLE_LEFT 0x40 +#define DS5W_ISTATE_BTN_PADDLE_RIGHT 0x80 + #define DS5W_ISTATE_BTX_SQUARE 0x10 #define DS5W_ISTATE_BTX_CROSS 0x20 #define DS5W_ISTATE_BTX_CIRCLE 0x40 diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp index 550a01c..8fa0b19 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp @@ -51,12 +51,14 @@ void __DS5W::Input::evaluateHidInputBuffer(unsigned char* hidInBuffer, DS5W::DS5 ptrInputState->buttonsAndDpad |= DS5W_ISTATE_DPAD_RIGHT | DS5W_ISTATE_DPAD_DOWN; break; } - - // Copy accelerometer readings - memcpy(&ptrInputState->accelerometer, &hidInBuffer[0x0F], 2 * 3); - - //TEMP: Copy gyro data (no processing currently done!) - memcpy(&ptrInputState->gyroscope, &hidInBuffer[0x15], 2 * 3); + + ptrInputState->gyroscope.x = static_cast((hidInBuffer[0x10]) | (hidInBuffer[0x11] << 8)); + ptrInputState->gyroscope.y = static_cast((hidInBuffer[0x12]) | (hidInBuffer[0x13] << 8)); + ptrInputState->gyroscope.z = static_cast((hidInBuffer[0x14]) | (hidInBuffer[0x15] << 8)); + + ptrInputState->accelerometer.x = static_cast((hidInBuffer[0x16]) | (hidInBuffer[0x17] << 8)); + ptrInputState->accelerometer.y = static_cast((hidInBuffer[0x18]) | (hidInBuffer[0x19] << 8)); + ptrInputState->accelerometer.z = static_cast((hidInBuffer[0x1A]) | (hidInBuffer[0x1B] << 8)); // Evaluate touch state 1 UINT32 touchpad1Raw = *(UINT32*)(&hidInBuffer[0x20]); diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp index 522d013..2b89d9e 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp @@ -3,7 +3,7 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig Füchsl + 11.2020 Ludwig F�chsl Licensed under the MIT License (To be found in repository root directory) */ @@ -88,7 +88,7 @@ DS5W_API DS5W_ReturnValue DS5W::enumDevices(void* ptrBuffer, unsigned int inArrL } // Check if ids match - if (vendorId == 0x054C && productId == 0x0CE6) { + if (vendorId == 0x054C && (productId == 0x0CE6 || productId == 0x0DF2)) { // Get pointer to target DS5W::DeviceEnumInfo* ptrInfo = nullptr; if (inputArrIndex < inArrLength) { From 3ab685a0475bf8508883e9ac7922b542b10abd50 Mon Sep 17 00:00:00 2001 From: rafaelvaloto Date: Sat, 26 Jul 2025 15:23:53 -0300 Subject: [PATCH 2/6] - Refactored accelerometer and gyroscope data parsing for improved clarity and accuracy. - Added support for DualSense Edge device (`0x0DF2`) in device detection. - Defined new constants for DualSense Edge function buttons and paddles in `DS5State.h`. - fix #19, #27, #29 --- .../include/DualSenseWindows/DS5State.h | 8 +++++++- .../src/DualSenseWindows/DS5_Input.cpp | 14 ++++++++------ .../src/DualSenseWindows/DS5_Input.h | 2 +- .../DualSenseWindows/src/DualSenseWindows/IO.cpp | 4 ++-- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h index dd6a21c..9c04f2c 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h @@ -3,12 +3,18 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig Füchsl + 11.2020 Ludwig F�chsl Licensed under the MIT License (To be found in repository root directory) */ #pragma once +// Function Buttons DualSense Edge +#define DS5W_ISTATE_BTN_FN1 0x10 +#define DS5W_ISTATE_BTN_FN2 0x20 +#define DS5W_ISTATE_BTN_PADDLE_LEFT 0x40 +#define DS5W_ISTATE_BTN_PADDLE_RIGHT 0x80 + #define DS5W_ISTATE_BTX_SQUARE 0x10 #define DS5W_ISTATE_BTX_CROSS 0x20 #define DS5W_ISTATE_BTX_CIRCLE 0x40 diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp index 550a01c..8fa0b19 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.cpp @@ -51,12 +51,14 @@ void __DS5W::Input::evaluateHidInputBuffer(unsigned char* hidInBuffer, DS5W::DS5 ptrInputState->buttonsAndDpad |= DS5W_ISTATE_DPAD_RIGHT | DS5W_ISTATE_DPAD_DOWN; break; } - - // Copy accelerometer readings - memcpy(&ptrInputState->accelerometer, &hidInBuffer[0x0F], 2 * 3); - - //TEMP: Copy gyro data (no processing currently done!) - memcpy(&ptrInputState->gyroscope, &hidInBuffer[0x15], 2 * 3); + + ptrInputState->gyroscope.x = static_cast((hidInBuffer[0x10]) | (hidInBuffer[0x11] << 8)); + ptrInputState->gyroscope.y = static_cast((hidInBuffer[0x12]) | (hidInBuffer[0x13] << 8)); + ptrInputState->gyroscope.z = static_cast((hidInBuffer[0x14]) | (hidInBuffer[0x15] << 8)); + + ptrInputState->accelerometer.x = static_cast((hidInBuffer[0x16]) | (hidInBuffer[0x17] << 8)); + ptrInputState->accelerometer.y = static_cast((hidInBuffer[0x18]) | (hidInBuffer[0x19] << 8)); + ptrInputState->accelerometer.z = static_cast((hidInBuffer[0x1A]) | (hidInBuffer[0x1B] << 8)); // Evaluate touch state 1 UINT32 touchpad1Raw = *(UINT32*)(&hidInBuffer[0x20]); diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.h b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.h index ebb3d04..109274e 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.h +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Input.h @@ -3,7 +3,7 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig Füchsl + 11.2020 Ludwig Füchsl Licensed under the MIT License (To be found in repository root directory) */ diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp index 522d013..447f071 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp @@ -3,7 +3,7 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig Füchsl + 11.2020 Ludwig Füchsl Licensed under the MIT License (To be found in repository root directory) */ @@ -88,7 +88,7 @@ DS5W_API DS5W_ReturnValue DS5W::enumDevices(void* ptrBuffer, unsigned int inArrL } // Check if ids match - if (vendorId == 0x054C && productId == 0x0CE6) { + if (vendorId == 0x054C && (productId == 0x0CE6 || productId == 0x0DF2)) { // Get pointer to target DS5W::DeviceEnumInfo* ptrInfo = nullptr; if (inputArrIndex < inArrLength) { From 797cab7443b2b603c3a728b7a6214eeed08d32ce Mon Sep 17 00:00:00 2001 From: rafaelvaloto Date: Sat, 26 Jul 2025 18:46:52 -0300 Subject: [PATCH 3/6] ROADMAP Features - Playing audio through all channels (somewhat related to haptic feedback) - Listening to the user with the integrated microphone - Controlling all that audio related stuff (Volume / Mute / ...) - Added rumble and audio configuration support to output state. - Enhanced HID output buffer generation to handle Bluetooth-specific behavior. - Updated device detection to include DualSense Edge device (`0x0DF2`). --- VS19_Solution/DS5W_Test/src/wWinMain.cpp | 7 +- .../include/DualSenseWindows/DS5State.h | 91 ++++++++++++++++++- .../include/DualSenseWindows/IO.h | 2 +- .../src/DualSenseWindows/DS5_Output.cpp | 45 ++++++++- .../src/DualSenseWindows/DS5_Output.h | 2 +- .../src/DualSenseWindows/IO.cpp | 12 +-- 6 files changed, 144 insertions(+), 15 deletions(-) diff --git a/VS19_Solution/DS5W_Test/src/wWinMain.cpp b/VS19_Solution/DS5W_Test/src/wWinMain.cpp index c9ec425..de23f32 100644 --- a/VS19_Solution/DS5W_Test/src/wWinMain.cpp +++ b/VS19_Solution/DS5W_Test/src/wWinMain.cpp @@ -6,6 +6,7 @@ #include #include #include +#include typedef std::wstringstream wstrBuilder; @@ -152,6 +153,10 @@ INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, lrmbl = max(lrmbl - 0x200 / btMul, 0); rrmbl = max(rrmbl - 0x100 / btMul, 0); + outState.rumble.Mode = static_cast(DS5W::RumbleMode::AdvancedRumble); + outState.rumble.Feature = static_cast(DS5W::FeatureMode::Advanced); + outState.rumble.SoftRumbleReduce = 0x10; + outState.leftRumble = (lrmbl & 0xFF00) >> 8UL; outState.rightRumble = (rrmbl & 0xFF00) >> 8UL; @@ -198,7 +203,7 @@ INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, // Right trigger is forcy outState.rightTriggerEffect.effectType = rType; outState.rightTriggerEffect.Continuous.force = 0xFF; - outState.rightTriggerEffect.Continuous.startPosition = 0x00; + outState.rightTriggerEffect.Continuous.startPosition = 0x00; DS5W::setDeviceOutputState(&con, &outState); } diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h index 9c04f2c..9b36a7d 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h @@ -3,7 +3,7 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig F�chsl + 11.2020 Ludwig Füchsl Licensed under the MIT License (To be found in repository root directory) */ @@ -77,7 +77,86 @@ namespace DS5W { unsigned char g; unsigned char b; } Color; + + typedef enum class _AudioMode : unsigned char{ + /// + /// Enable Audio Headset + /// + Headset = 0x05, + + /// + /// Enable Audio Speaker + /// + Speaker = 0x31, + + /// + /// Enable Audio Headset And Speaker + /// + HeadsetAndSpeaker = 0x21, + } AudioMode; + + typedef enum class _MicMode : unsigned char{ + /// + /// Enable Audio Speaker + /// + On = 0x00, + + /// + /// Mute Mic + /// + Mute = 0x10, + } MicMode; + + /// + /// Audio Settings + /// + typedef struct _AudioConfig { + unsigned char Mode = static_cast(AudioMode::Speaker); + unsigned char HeadsetVolume = 0x7C; + unsigned char SpeakerVolume = 0x7C; + unsigned char MicVolume = 0x7C; + unsigned char MicStatus = static_cast(MicMode::On); + } AudioConfig; + + /// + /// Rumble Mode + /// + typedef enum class _RumbleMode : unsigned char{ + /// + /// Default Rumble + /// + DefaultRumble = 0xFF, + + /// + /// Soft Rumble + /// + AdvancedRumble = 0xFC, + } RumbleMode; + + /// + /// Feature Mode + /// + typedef enum class _FeatureMode : unsigned char{ + /// + /// All Feature Mode + /// + All = 0xF7, + /// + /// Feature Advanced DualSense Vibrations + /// + Advanced = 0x57, + } FeatureMode; + + /// + /// Rumble Settings + /// + typedef struct _RumbleConfig { + unsigned char Mode = static_cast(RumbleMode::DefaultRumble); + unsigned char Feature = static_cast(FeatureMode::All); + unsigned char SoftRumbleReduce = 0x00; + } RumbleConfig; + /// /// Touchpad state /// @@ -386,6 +465,11 @@ namespace DS5W { } DS5InputState; typedef struct _DS5OutputState { + /// + /// Rumble Config + /// + RumbleConfig rumble; + /// /// Left / Hard rumbel motor /// @@ -396,6 +480,11 @@ namespace DS5W { /// unsigned char rightRumble; + /// + /// Audio Config + /// + AudioConfig audio; + /// /// State of the microphone led /// diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h index 0786c12..05a144c 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h @@ -4,7 +4,7 @@ MIT License - Copyright (c) 2020 Ludwig Füchsl + Copyright (c) 2020 Ludwig Füchsl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp index 4b9c013..1f6ef48 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp @@ -1,16 +1,52 @@ #include "DS5_Output.h" -void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState) { +void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState, DS5W::DeviceConnection Connection) { + bool bIsBluetooth = false; + if (Connection == DS5W::DeviceConnection::BT) + { + bIsBluetooth = true; + } + // Feature mask - hidOutBuffer[0x00] = 0xFF; - hidOutBuffer[0x01] = 0xF7; + hidOutBuffer[0x00] = bIsBluetooth ? 0xFF : ptrOutputState->rumble.Mode; + hidOutBuffer[0x01] = bIsBluetooth ? 0xF7 : ptrOutputState->rumble.Feature; // Rumbel motors hidOutBuffer[0x02] = ptrOutputState->rightRumble; hidOutBuffer[0x03] = ptrOutputState->leftRumble; + // Audio + if (!bIsBluetooth) + { + hidOutBuffer[0x04] = ptrOutputState->audio.HeadsetVolume; + hidOutBuffer[0x05] = ptrOutputState->audio.SpeakerVolume; + hidOutBuffer[0x06] = ptrOutputState->audio.MicVolume; + hidOutBuffer[0x07] = ptrOutputState->audio.Mode; + hidOutBuffer[0x09] = ptrOutputState->audio.MicStatus; + } // Mic led - hidOutBuffer[0x08] = (unsigned char)ptrOutputState->microphoneLed; + hidOutBuffer[0x08] = static_cast(ptrOutputState->microphoneLed); + + // Config Rumble + if (bIsBluetooth) + { + hidOutBuffer[0x24] = 0x03; + hidOutBuffer[0x26] = 0x2; + } + else + { + // Advanced Vibration Based On Audio and Soft Rumble Reduce + hidOutBuffer[0x24] = ((2 & 0x0F) << 4) | (ptrOutputState->rumble.SoftRumbleReduce & 0x0F); + hidOutBuffer[0x26] = 0x53; + if (ptrOutputState->rumble.SoftRumbleReduce > 0) + { + hidOutBuffer[0x26] |= (1 << 2); // 0x057 + } + else + { + hidOutBuffer[0x26] &= ~(0 << 2); // 0x53 + } + } // Player led hidOutBuffer[0x2B] = ptrOutputState->playerLeds.bitmask; @@ -22,7 +58,6 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS } // Player led brightness - hidOutBuffer[0x26] = 0x03; hidOutBuffer[0x29] = ptrOutputState->disableLeds ? 0x01 : 0x2; hidOutBuffer[0x2A] = ptrOutputState->playerLeds.brightness; diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h index 43ef086..e036391 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h @@ -22,7 +22,7 @@ namespace __DS5W { /// /// HID Output buffer /// Pointer to state to read from - void createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState); + void createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState, DS5W::DeviceConnection Connection); /// /// Process trigger diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp index d2c04ed..a822eec 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp @@ -88,7 +88,7 @@ DS5W_API DS5W_ReturnValue DS5W::enumDevices(void* ptrBuffer, unsigned int inArrL } // Check if ids match - if (vendorId == 0x054C && productId == 0x0CE6) { + if (vendorId == 0x054C && (productId == 0x0CE6 || productId == 0x0DF2)) { // Get pointer to target DS5W::DeviceEnumInfo* ptrInfo = nullptr; if (inputArrIndex < inArrLength) { @@ -322,12 +322,12 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon // Get otuput report length unsigned short outputReportLength = 0; if (ptrContext->_internal.connection == DS5W::DeviceConnection::BT) { - // The bluetooth input report is 547 Bytes long - outputReportLength = 547; + // The bluetooth input report is 78 Bytes long + outputReportLength = 78; } else { // The usb input report is 48 Bytes long - outputReportLength = 48; + outputReportLength = 74; } // Cleat all input data @@ -339,7 +339,7 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon // Report type ptrContext->_internal.hidBuffer[0x00] = 0x31; ptrContext->_internal.hidBuffer[0x01] = 0x02; - __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[2], ptrOutputState); + __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[2], ptrOutputState, ptrContext->_internal.connection); // Hash const UINT32 crcChecksum = __DS5W::CRC32::compute(ptrContext->_internal.hidBuffer, 74); @@ -355,7 +355,7 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon ptrContext->_internal.hidBuffer[0x00] = 0x02; // Else it is USB so call its evaluator - __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[1], ptrOutputState); + __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[1], ptrOutputState, ptrContext->_internal.connection); } // Write to controller From 15b7e4b27c94e150906ffd44187c903fe39291a3 Mon Sep 17 00:00:00 2001 From: rafaelvaloto Date: Sat, 26 Jul 2025 18:46:52 -0300 Subject: [PATCH 4/6] ROADMAP Features - Playing audio through all channels (somewhat related to haptic feedback) - Listening to the user with the integrated microphone - Controlling all that audio related stuff (Volume / Mute / ...) - Added rumble and audio configuration support to output state. - Enhanced HID output buffer generation to handle Bluetooth-specific behavior. - Updated device detection to include DualSense Edge device (`0x0DF2`). --- README.md | 62 +++++++++++++ VS19_Solution/DS5W_Test/src/wWinMain.cpp | 14 ++- .../include/DualSenseWindows/DS5State.h | 91 ++++++++++++++++++- .../include/DualSenseWindows/IO.h | 2 +- .../src/DualSenseWindows/DS5_Output.cpp | 45 ++++++++- .../src/DualSenseWindows/DS5_Output.h | 2 +- .../src/DualSenseWindows/IO.cpp | 12 +-- 7 files changed, 212 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8bd57bb..6ebe920 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,68 @@ int main(int argc, char** argv){ } ``` +## Usage of Structs for Output State Configuration + +The DS5 output state configuration relies on several structs to control features such as rumble effects. When preparing the output state, you set individual struct fields to adjust controller feedback and capabilities. + +### Example: Configuring Rumble +``` +outState.rumble.Mode = static_cast(DS5W::RumbleMode::DefaultRumble); +outState.rumble.Feature = static_cast(DS5W::FeatureMode::Advanced); + +// Maximum is 0x15 (hex) = 21 (decimal) +outState.rumble.SoftRumbleReduce = 18; +``` +### Description + +- **Mode: `AdvancedRumble`** + Set the `Mode` field using `DS5W::RumbleMode::AdvancedRumble` to activate advanced rumble behavior, which enables finer feedback control and integration with audio or other dynamic sources. + +- **Feature: `Advanced`** + Set the `Feature` field to `DS5W::FeatureMode::Advanced` to utilize extended feature sets provided by the controller, such as more complex vibration profiles based on audio cues. + +### Description of Fields + +- **Mode:** + Controls which audio output(s) are active. + - `AudioMode::Headset` – Output to the headset only + - `AudioMode::Speaker` – Output to the speaker only + - `AudioMode::HeadsetAndSpeaker` – Output to both headset and speaker + +- **HeadsetVolume:** + Sets the volume level for the headset output. The decimal range is typically `0` (min) to `124` (max). + +- **SpeakerVolume:** + Sets the volume level for the built-in speaker. The decimal range is typically `0` (min) to `124` (max). + +- **MicVolume:** + Defines the microphone volume. Higher decimal values represent higher sensitivity or input levels, with `124` being maximum. + +- **MicStatus:** + Controls the microphone state. + - `MicMode::On` – Microphone is enabled + - `MicMode::Mute` – Microphone is muted + +### Typical Usage Scenarios + +- Enable both headset and speaker output with maximum volumes and microphone muted: + ```cpp + outState.audio.Mode = static_cast(AudioMode::HeadsetAndSpeaker); + outState.audio.HeadsetVolume = 100; + outState.audio.SpeakerVolume = 100; + outState.audio.MicVolume = 100; + outState.audio.MicStatus = static_cast(MicMode::Mute); + ``` + +- Use only the headset output with microphone enabled: + ```cpp + outState.audio.Mode = static_cast(AudioMode::Headset); + outState.audio.HeadsetVolume = 100; + outState.audio.MicStatus = static_cast(MicMode::On); + ``` + +Adjust these settings according to your application's requirements to provide optimal audio feedback through the controller. + ## Known issues - When the controller being shut down while connected via Bluetooth (Holding the PS button). The lib will encounter a dead lock within `getDeviceInputState(...)` call. The function will return as soon as the controller is getting reconnected. Not encountering over USB, over USB the expected `DS5W_E_DEVICE_REMOVED` error is returned. diff --git a/VS19_Solution/DS5W_Test/src/wWinMain.cpp b/VS19_Solution/DS5W_Test/src/wWinMain.cpp index c9ec425..49b94d3 100644 --- a/VS19_Solution/DS5W_Test/src/wWinMain.cpp +++ b/VS19_Solution/DS5W_Test/src/wWinMain.cpp @@ -6,6 +6,7 @@ #include #include #include +#include typedef std::wstringstream wstrBuilder; @@ -109,7 +110,7 @@ INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, // Force DS5W::TriggerEffectType rType = DS5W::TriggerEffectType::NoResitance; - int btMul = con._internal.connection == DS5W::DeviceConnection::BT ? 10 : 1; + int btMul = con._internal.connection == DS5W::DeviceConnection::BT ? 10 : 5; // Application infinity loop while (!(inState.buttonsA & DS5W_ISTATE_BTN_A_LEFT_BUMPER && inState.buttonsA & DS5W_ISTATE_BTN_A_RIGHT_BUMPER)) { @@ -142,6 +143,11 @@ INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, builder << (inState.buttonsB & DS5W_ISTATE_BTN_B_PLAYSTATION_LOGO ? L"PLAYSTATION" : L"") << (inState.buttonsB & DS5W_ISTATE_BTN_B_MIC_BUTTON ? L"\tMIC" : L"") << std::endl;; + builder << L"Gyroscope: X:" << inState.gyroscope.x << " Y:" << inState.gyroscope.y << " Z:" << inState.gyroscope.z << std::endl << std::endl; + builder << L"Accelerometer: X:" << inState.accelerometer.x << " Y:" << inState.accelerometer.y << " Z:" << inState.accelerometer.z << std::endl << std::endl; + + builder << L"Gravity: " << inState.battery.level << (inState.battery.chargin ? L" Charging" : L"") << (inState.battery.fullyCharged ? L" Fully charged" : L"") << std::endl << std::endl; + // Ommited accel and gyro // Print to console @@ -152,6 +158,10 @@ INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, lrmbl = max(lrmbl - 0x200 / btMul, 0); rrmbl = max(rrmbl - 0x100 / btMul, 0); + outState.rumble.Mode = static_cast(DS5W::RumbleMode::DefaultRumble); + outState.rumble.Feature = static_cast(DS5W::FeatureMode::Advanced); + outState.rumble.SoftRumbleReduce = 0x10; + outState.leftRumble = (lrmbl & 0xFF00) >> 8UL; outState.rightRumble = (rrmbl & 0xFF00) >> 8UL; @@ -198,7 +208,7 @@ INT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, // Right trigger is forcy outState.rightTriggerEffect.effectType = rType; outState.rightTriggerEffect.Continuous.force = 0xFF; - outState.rightTriggerEffect.Continuous.startPosition = 0x00; + outState.rightTriggerEffect.Continuous.startPosition = 0x00; DS5W::setDeviceOutputState(&con, &outState); } diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h index 9c04f2c..9b36a7d 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h @@ -3,7 +3,7 @@ https://github.com/Ohjurot/DualSense-Windows Contributors of this file: - 11.2020 Ludwig F�chsl + 11.2020 Ludwig Füchsl Licensed under the MIT License (To be found in repository root directory) */ @@ -77,7 +77,86 @@ namespace DS5W { unsigned char g; unsigned char b; } Color; + + typedef enum class _AudioMode : unsigned char{ + /// + /// Enable Audio Headset + /// + Headset = 0x05, + + /// + /// Enable Audio Speaker + /// + Speaker = 0x31, + + /// + /// Enable Audio Headset And Speaker + /// + HeadsetAndSpeaker = 0x21, + } AudioMode; + + typedef enum class _MicMode : unsigned char{ + /// + /// Enable Audio Speaker + /// + On = 0x00, + + /// + /// Mute Mic + /// + Mute = 0x10, + } MicMode; + + /// + /// Audio Settings + /// + typedef struct _AudioConfig { + unsigned char Mode = static_cast(AudioMode::Speaker); + unsigned char HeadsetVolume = 0x7C; + unsigned char SpeakerVolume = 0x7C; + unsigned char MicVolume = 0x7C; + unsigned char MicStatus = static_cast(MicMode::On); + } AudioConfig; + + /// + /// Rumble Mode + /// + typedef enum class _RumbleMode : unsigned char{ + /// + /// Default Rumble + /// + DefaultRumble = 0xFF, + + /// + /// Soft Rumble + /// + AdvancedRumble = 0xFC, + } RumbleMode; + + /// + /// Feature Mode + /// + typedef enum class _FeatureMode : unsigned char{ + /// + /// All Feature Mode + /// + All = 0xF7, + /// + /// Feature Advanced DualSense Vibrations + /// + Advanced = 0x57, + } FeatureMode; + + /// + /// Rumble Settings + /// + typedef struct _RumbleConfig { + unsigned char Mode = static_cast(RumbleMode::DefaultRumble); + unsigned char Feature = static_cast(FeatureMode::All); + unsigned char SoftRumbleReduce = 0x00; + } RumbleConfig; + /// /// Touchpad state /// @@ -386,6 +465,11 @@ namespace DS5W { } DS5InputState; typedef struct _DS5OutputState { + /// + /// Rumble Config + /// + RumbleConfig rumble; + /// /// Left / Hard rumbel motor /// @@ -396,6 +480,11 @@ namespace DS5W { /// unsigned char rightRumble; + /// + /// Audio Config + /// + AudioConfig audio; + /// /// State of the microphone led /// diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h index 0786c12..05a144c 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/IO.h @@ -4,7 +4,7 @@ MIT License - Copyright (c) 2020 Ludwig Füchsl + Copyright (c) 2020 Ludwig Füchsl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp index 4b9c013..1f6ef48 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp @@ -1,16 +1,52 @@ #include "DS5_Output.h" -void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState) { +void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState, DS5W::DeviceConnection Connection) { + bool bIsBluetooth = false; + if (Connection == DS5W::DeviceConnection::BT) + { + bIsBluetooth = true; + } + // Feature mask - hidOutBuffer[0x00] = 0xFF; - hidOutBuffer[0x01] = 0xF7; + hidOutBuffer[0x00] = bIsBluetooth ? 0xFF : ptrOutputState->rumble.Mode; + hidOutBuffer[0x01] = bIsBluetooth ? 0xF7 : ptrOutputState->rumble.Feature; // Rumbel motors hidOutBuffer[0x02] = ptrOutputState->rightRumble; hidOutBuffer[0x03] = ptrOutputState->leftRumble; + // Audio + if (!bIsBluetooth) + { + hidOutBuffer[0x04] = ptrOutputState->audio.HeadsetVolume; + hidOutBuffer[0x05] = ptrOutputState->audio.SpeakerVolume; + hidOutBuffer[0x06] = ptrOutputState->audio.MicVolume; + hidOutBuffer[0x07] = ptrOutputState->audio.Mode; + hidOutBuffer[0x09] = ptrOutputState->audio.MicStatus; + } // Mic led - hidOutBuffer[0x08] = (unsigned char)ptrOutputState->microphoneLed; + hidOutBuffer[0x08] = static_cast(ptrOutputState->microphoneLed); + + // Config Rumble + if (bIsBluetooth) + { + hidOutBuffer[0x24] = 0x03; + hidOutBuffer[0x26] = 0x2; + } + else + { + // Advanced Vibration Based On Audio and Soft Rumble Reduce + hidOutBuffer[0x24] = ((2 & 0x0F) << 4) | (ptrOutputState->rumble.SoftRumbleReduce & 0x0F); + hidOutBuffer[0x26] = 0x53; + if (ptrOutputState->rumble.SoftRumbleReduce > 0) + { + hidOutBuffer[0x26] |= (1 << 2); // 0x057 + } + else + { + hidOutBuffer[0x26] &= ~(0 << 2); // 0x53 + } + } // Player led hidOutBuffer[0x2B] = ptrOutputState->playerLeds.bitmask; @@ -22,7 +58,6 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS } // Player led brightness - hidOutBuffer[0x26] = 0x03; hidOutBuffer[0x29] = ptrOutputState->disableLeds ? 0x01 : 0x2; hidOutBuffer[0x2A] = ptrOutputState->playerLeds.brightness; diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h index 43ef086..e036391 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.h @@ -22,7 +22,7 @@ namespace __DS5W { /// /// HID Output buffer /// Pointer to state to read from - void createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState); + void createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS5OutputState* ptrOutputState, DS5W::DeviceConnection Connection); /// /// Process trigger diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp index d2c04ed..a822eec 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/IO.cpp @@ -88,7 +88,7 @@ DS5W_API DS5W_ReturnValue DS5W::enumDevices(void* ptrBuffer, unsigned int inArrL } // Check if ids match - if (vendorId == 0x054C && productId == 0x0CE6) { + if (vendorId == 0x054C && (productId == 0x0CE6 || productId == 0x0DF2)) { // Get pointer to target DS5W::DeviceEnumInfo* ptrInfo = nullptr; if (inputArrIndex < inArrLength) { @@ -322,12 +322,12 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon // Get otuput report length unsigned short outputReportLength = 0; if (ptrContext->_internal.connection == DS5W::DeviceConnection::BT) { - // The bluetooth input report is 547 Bytes long - outputReportLength = 547; + // The bluetooth input report is 78 Bytes long + outputReportLength = 78; } else { // The usb input report is 48 Bytes long - outputReportLength = 48; + outputReportLength = 74; } // Cleat all input data @@ -339,7 +339,7 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon // Report type ptrContext->_internal.hidBuffer[0x00] = 0x31; ptrContext->_internal.hidBuffer[0x01] = 0x02; - __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[2], ptrOutputState); + __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[2], ptrOutputState, ptrContext->_internal.connection); // Hash const UINT32 crcChecksum = __DS5W::CRC32::compute(ptrContext->_internal.hidBuffer, 74); @@ -355,7 +355,7 @@ DS5W_API DS5W_ReturnValue DS5W::setDeviceOutputState(DS5W::DeviceContext* ptrCon ptrContext->_internal.hidBuffer[0x00] = 0x02; // Else it is USB so call its evaluator - __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[1], ptrOutputState); + __DS5W::Output::createHidOutputBuffer(&ptrContext->_internal.hidBuffer[1], ptrOutputState, ptrContext->_internal.connection); } // Write to controller From bdfd04390c801c83ea3d6241c9b76bd6b79844ac Mon Sep 17 00:00:00 2001 From: rafaelvaloto Date: Thu, 31 Jul 2025 12:50:07 -0300 Subject: [PATCH 5/6] Refactored HID output buffer generation to simplify rumble configuration and unify behavior across connection types. --- .../src/DualSenseWindows/DS5_Output.cpp | 25 +++---------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp index 1f6ef48..e7bec45 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp @@ -8,7 +8,7 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS } // Feature mask - hidOutBuffer[0x00] = bIsBluetooth ? 0xFF : ptrOutputState->rumble.Mode; + hidOutBuffer[0x00] = ptrOutputState->rumble.Mode; hidOutBuffer[0x01] = bIsBluetooth ? 0xF7 : ptrOutputState->rumble.Feature; // Rumbel motors @@ -27,26 +27,9 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS // Mic led hidOutBuffer[0x08] = static_cast(ptrOutputState->microphoneLed); - // Config Rumble - if (bIsBluetooth) - { - hidOutBuffer[0x24] = 0x03; - hidOutBuffer[0x26] = 0x2; - } - else - { - // Advanced Vibration Based On Audio and Soft Rumble Reduce - hidOutBuffer[0x24] = ((2 & 0x0F) << 4) | (ptrOutputState->rumble.SoftRumbleReduce & 0x0F); - hidOutBuffer[0x26] = 0x53; - if (ptrOutputState->rumble.SoftRumbleReduce > 0) - { - hidOutBuffer[0x26] |= (1 << 2); // 0x057 - } - else - { - hidOutBuffer[0x26] &= ~(0 << 2); // 0x53 - } - } + // Advanced Vibration Soft Rumble Reduce + hidOutBuffer[0x24] = ((2 & 0x0F) << 4) | (ptrOutputState->rumble.SoftRumbleReduce & 0x0F); + hidOutBuffer[0x26] = 0x04; // Player led hidOutBuffer[0x2B] = ptrOutputState->playerLeds.bitmask; From 04a90fd7df519f71d1584a1805939fcd3b522417 Mon Sep 17 00:00:00 2001 From: rafaelvaloto Date: Sun, 10 Aug 2025 22:59:39 -0300 Subject: [PATCH 6/6] Refactor rumble config and output buffer handling Removed FeatureMode from RumbleConfig and replaced 'Feature' with 'TriggerSoftnessLevel'. Renamed 'rumble' to 'rumbleSettings' in DS5OutputState. Updated output buffer logic to use new rumble settings and simplified feature mask handling. --- .../.idea.VS19_Solution/.idea/.gitignore | 13 +++++++++++++ .../.idea.VS19_Solution/.idea/encodings.xml | 4 ++++ .../.idea.VS19_Solution/.idea/indexLayout.xml | 8 ++++++++ .../.idea/.idea.VS19_Solution/.idea/vcs.xml | 7 +++++++ .../include/DualSenseWindows/DS5State.h | 19 ++----------------- .../src/DualSenseWindows/DS5_Output.cpp | 8 ++++---- 6 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 VS19_Solution/.idea/.idea.VS19_Solution/.idea/.gitignore create mode 100644 VS19_Solution/.idea/.idea.VS19_Solution/.idea/encodings.xml create mode 100644 VS19_Solution/.idea/.idea.VS19_Solution/.idea/indexLayout.xml create mode 100644 VS19_Solution/.idea/.idea.VS19_Solution/.idea/vcs.xml diff --git a/VS19_Solution/.idea/.idea.VS19_Solution/.idea/.gitignore b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/.gitignore new file mode 100644 index 0000000..f27ae99 --- /dev/null +++ b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/projectSettingsUpdater.xml +/modules.xml +/.idea.VS19_Solution.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/VS19_Solution/.idea/.idea.VS19_Solution/.idea/encodings.xml b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/VS19_Solution/.idea/.idea.VS19_Solution/.idea/indexLayout.xml b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/VS19_Solution/.idea/.idea.VS19_Solution/.idea/vcs.xml b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/vcs.xml new file mode 100644 index 0000000..62bd7a0 --- /dev/null +++ b/VS19_Solution/.idea/.idea.VS19_Solution/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h index 9b36a7d..be627e8 100644 --- a/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h +++ b/VS19_Solution/DualSenseWindows/include/DualSenseWindows/DS5State.h @@ -132,29 +132,14 @@ namespace DS5W { /// AdvancedRumble = 0xFC, } RumbleMode; - - /// - /// Feature Mode - /// - typedef enum class _FeatureMode : unsigned char{ - /// - /// All Feature Mode - /// - All = 0xF7, - - /// - /// Feature Advanced DualSense Vibrations - /// - Advanced = 0x57, - } FeatureMode; /// /// Rumble Settings /// typedef struct _RumbleConfig { unsigned char Mode = static_cast(RumbleMode::DefaultRumble); - unsigned char Feature = static_cast(FeatureMode::All); unsigned char SoftRumbleReduce = 0x00; + unsigned char TriggerSoftnessLevel = 0x00; } RumbleConfig; /// @@ -468,7 +453,7 @@ namespace DS5W { /// /// Rumble Config /// - RumbleConfig rumble; + RumbleConfig rumbleSettings; /// /// Left / Hard rumbel motor diff --git a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp index e7bec45..e25f8b6 100644 --- a/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp +++ b/VS19_Solution/DualSenseWindows/src/DualSenseWindows/DS5_Output.cpp @@ -8,8 +8,8 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS } // Feature mask - hidOutBuffer[0x00] = ptrOutputState->rumble.Mode; - hidOutBuffer[0x01] = bIsBluetooth ? 0xF7 : ptrOutputState->rumble.Feature; + hidOutBuffer[0x00] = ptrOutputState->rumbleSettings.Mode; + hidOutBuffer[0x01] = 0xF7; // Rumbel motors hidOutBuffer[0x02] = ptrOutputState->rightRumble; @@ -27,8 +27,8 @@ void __DS5W::Output::createHidOutputBuffer(unsigned char* hidOutBuffer, DS5W::DS // Mic led hidOutBuffer[0x08] = static_cast(ptrOutputState->microphoneLed); - // Advanced Vibration Soft Rumble Reduce - hidOutBuffer[0x24] = ((2 & 0x0F) << 4) | (ptrOutputState->rumble.SoftRumbleReduce & 0x0F); + // Advanced Trigger Softness Level and Vibration Soft Rumble Reduce + hidOutBuffer[0x24] = static_cast((ptrOutputState->rumbleSettings.TriggerSoftnessLevel << 4) | (ptrOutputState->rumbleSettings.SoftRumbleReduce & 0x0F)); hidOutBuffer[0x26] = 0x04; // Player led