Skip to content

Commit

Permalink
Improvements: ability to move left stick on pitch axis, change roll a…
Browse files Browse the repository at this point in the history
…nd yaw axis, display ds & ds4 battery charge on lighbar, also a separate reset button
  • Loading branch information
r57zone committed Jan 14, 2023
1 parent 556e841 commit 1dc4e13
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 39 deletions.
6 changes: 3 additions & 3 deletions README.RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
Для выхода из режима эмуляции стиков на тачпаде нужно переключиться на режим по умолчанию.


Нажимая на профиль по умолчанию, на DualSense, белые светодиоды отображают текущий статус заряда аккумулятора (1 - 0..25%, 2 - 26..50%, 3 - 51..75%, 4 - 76..100%). Также в программе для DualSense и DualShock 4 отображается текущий заряд.
Нажимая на профиль по умолчанию, на DualSense, белые светодиоды отображают текущий статус заряда аккумулятора (1 - 0..25%, 2 - 26..50%, 3 - 51..75%, 4 - 76..100%), также на DualSense и DualShock 4 показывается статус батареи на световую панель (зелёный - 100..30%, жёлтый - 29..10%, красный - 9..1%), можно отключить в конфиге, параметр `ShowBatteryStatusOnLightBar`. Для DualSense и DualShock 4 отображается текущий заряд в самой программе.


Для изменения яркости 2 раза нажмите на область яркости. Если изменение яркости заблокировано, то подстветка будет выключаться по двойному клику.
Expand Down Expand Up @@ -67,11 +67,11 @@
**[Загрузить](https://github.com/r57zone/DSAdvance/releases)**

## Благодарности
* Sony за самые продвинутые геймпады и инвестирование в инновации, а также Nintendo за продвижение подобных инноваций в игры.
* Sony и Nintendo за самые продвинутые геймпады и инвестирование в инновации, а также за продвижение инноваций в игры.
* [ViGEm](https://github.com/ViGEm) за возможность эмуляции разных геймпадов.
* [HIDAPI library](https://github.com/signal11/hidapi), с [исправлениями](https://github.com/libusb/hidapi), за библиотеку для работы с USB устройства. В проекте используется этот [форк](https://github.com/r57zone/hidapi).
* [JoyShockLibrary](https://github.com/JibbSmart/JoyShockLibrary) за классную библиотеку геймпадов, позволяющую легко получить вращение контроллера. Также используется некоторый код из этой библиотеки.
* [Пользователям Reddit](https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/) за детальное описание выходного USB пакета.
* [Пользователям Reddit](https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/) за детальное описание выходного USB пакета DualSense.
* DS4Windows[[1]](https://github.com/Jays2Kings/DS4Windows)[[2]](https://github.com/Ryochan7/DS4Windows) за уровень заряда батареи.

## Обратная связь
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Several working modes are supported, they are switched by pressing the touchpad
To exit the stick emulation mode on the touchpad, need to switch to the default mode.


By clicking on the default profile on DualSense the white LEDs display the current battery status (1 - 0..25%, 2 - 26..50%, 3 - 51..75%, 4 - 76..100%). Also in the program for DualSense and DualShock 4 the current charge is displayed.
By clicking on the default profile on DualSense the white LEDs display the current battery status (1 - 0..25%, 2 - 26..50%, 3 - 51..75%, 4 - 76..100%), also on DualSense and DualShock 4 the battery status is shown on the lightbar (green - 100..30%, yellow - 29..10%, red - 9..1%), can be disabled in the config, parameter `ShowBatteryStatusOnLightBar`. For DualSense and DualShock 4 the current charge is displayed in the program itself.


The `PS` button opens the "Xbox Game Bar", `PS + □` - decrease the volume, `PS + ○` - increase the volume, `PS + △` - increases and then decreases aiming sensitivity (reset to `PS + R3`), `PS + X` - microphone button (screenshot / pressing configured keyboard button).
Expand Down Expand Up @@ -63,11 +63,11 @@ In some games, such as Max Payne or Crysis 2, this does not work, the reasons ar
**[Download](https://github.com/r57zone/DSAdvance/releases)**

## Credits
* Sony for the most advanced gamepads and investing in innovation, as well as Nintendo for promoting similar innovations in games.
* Sony and Nintendo for the most advanced gamepads and investment in innovation, and for driving innovation in games.
* [ViGEm](https://github.com/ViGEm) for the ability to emulate different gamepads.
* [HIDAPI library](https://github.com/signal11/hidapi) with [fixes](https://github.com/libusb/hidapi) for the library to work with a USB devices. The project uses this [fork](https://github.com/r57zone/hidapi).
* [JoyShockLibrary](https://github.com/JibbSmart/JoyShockLibrary) for a cool gamepad library that makes it easy to get controller rotation. Also some code from this library is used.
* For [Reddit users](https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/) for a detailed description of the USB output packet.
* For [Reddit users](https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/) for a detailed description of the DualSense USB output packet.
* DS4Windows[[1]](https://github.com/Jays2Kings/DS4Windows)[[2]](https://github.com/Ryochan7/DS4Windows) for the battery level.

## Feedback
Expand Down
81 changes: 49 additions & 32 deletions Source/DSAdvance/DSAdvance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,12 @@ void LoadKMProfile(std::string ProfileFile) {
KMJoySensY = IniFile.ReadFloat("MOUSE", "SensitivityY", 100) * 0.22;
}

std::string ResetKeyName;
void MainTextUpdate() {
system("cls");
if (AppStatus.ControllerCount < 1)
printf("\n Connect DualSense, DualShock 4, Pro controller or Joycons and reset.");
printf("\n Press \"CTRL\" + \"R\" to reset controllers.\n");
printf("\n Press \"CTRL\" + \"R\" or \"%s\" to reset controllers.\n", ResetKeyName.c_str());

if (AppStatus.ControllerCount > 0 && AppStatus.ShowBatteryStatus && (CurGamepad.ControllerType == SONY_DUALSENSE || CurGamepad.ControllerType == SONY_DUALSHOCK4)) {
printf(" Gamepad mode:");
Expand Down Expand Up @@ -433,19 +434,23 @@ void MainTextUpdate() {
printf(", press \"ALT\" + \"W\" or \"PS\" + \"Share\" to switch.\n");
printf(" Press \"ALT\" + \"B\" or \"PS\" + \"L1\" to turn the backlight on or off.\n");

printf(" Press \"ALT\" + \"F9\" to get the sticks dead zones.\n");
printf(" Press \"ALT\" + \"Escape\" to exit.\n");
}

int main(int argc, char **argv)
{
SetConsoleTitle("DSAdvance 0.8.3");
SetConsoleTitle("DSAdvance 0.8.4");
// Config parameters
CIniReader IniFile("Config.ini");

bool InvertLeftStickX = IniFile.ReadBoolean("Gamepad", "InvertLeftStickX", false);
bool InvertLeftStickY = IniFile.ReadBoolean("Gamepad", "InvertLeftStickY", false);
bool InvertRightStickX = IniFile.ReadBoolean("Gamepad", "InvertRightStickX", false);
bool InvertRightStickY = IniFile.ReadBoolean("Gamepad", "InvertRightStickY", false);
ResetKeyName = IniFile.ReadString("Gamepad", "ResetKey", "NONE");
int ResetKey = KeyNameToKeyCode(ResetKeyName);
bool ShowBatteryStatusOnLightBar = IniFile.ReadBoolean("Gamepad", "ShowBatteryStatusOnLightBar", true);
bool AutoReconnect = IniFile.ReadBoolean("Gamepad", "AutoReconnect", false);
int SleepTimeOut = IniFile.ReadInteger("Gamepad", "SleepTimeOut", 1);

Expand All @@ -467,6 +472,9 @@ int main(int argc, char **argv)

AppStatus.AimMode = IniFile.ReadBoolean("Motion", "AimMode", AimMouseMode);
float MotionWheelAngle = IniFile.ReadFloat("Motion", "WheelAngle", 150) / 2.0f;
bool MotionWheelPitch = IniFile.ReadBoolean("Motion", "WheelPitch", false);
bool MotionWheelRoll = IniFile.ReadBoolean("Motion", "WheelRoll", true);
int WheelInvertPitch = IniFile.ReadBoolean("Motion", "WheelInvertPitch", false) ? -1 : 1;
float MotionSensX = IniFile.ReadFloat("Motion", "MouseSensX", 3) / 10.0f;;
float MotionSensY = IniFile.ReadFloat("Motion", "MouseSensY", 3) / 10.0f;;
float JoySensX = IniFile.ReadFloat("Motion", "JoySensX", 3);
Expand Down Expand Up @@ -564,33 +572,38 @@ int main(int argc, char **argv)

while (! ( GetAsyncKeyState(VK_LMENU) & 0x8000 && GetAsyncKeyState(VK_ESCAPE) & 0x8000 ) )
{
// Reset
if ((((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0 && (GetAsyncKeyState('R') & 0x8000) != 0) || (GetAsyncKeyState(ResetKey) & 0x8000) != 0 && SkipPollCount == 0) || BTReset || ResetCounter == ResetControllersTimeOut)
{
AppStatus.ControllerCount = JslConnectDevices();
JslGetConnectedDeviceHandles(deviceID, AppStatus.ControllerCount);
GamepadSearch();
GamepadSetState(GamepadOutState);
BTReset = false;
MainTextUpdate();
SkipPollCount = SkipPollTimeOut;
}

// Dead zones
XUSB_REPORT_INIT(&report);
InputState = JslGetSimpleState(deviceID[0]);
MotionState = JslGetMotionState(deviceID[0]);
MotionAngles = QuaternionToEulerAngle(MotionState.quatW, MotionState.quatZ, MotionState.quatX, MotionState.quatY);

// Stick dead zones
if (((GetAsyncKeyState(VK_MENU) & 0x8000) != 0) && (GetAsyncKeyState(VK_F9) & 0x8000) != 0 && SkipPollCount == 0)
{
DeadZoneMode = !DeadZoneMode;
if (DeadZoneMode == false) MainTextUpdate();
SkipPollCount = SkipPollTimeOut;
}

if (DeadZoneMode) {
printf(" Left Stick X=%6.2f, ", abs(InputState.stickLX));
printf(" Left stick X=%6.2f, ", abs(InputState.stickLX));
printf("Y=%6.2f\t", abs(InputState.stickLY));
printf("Right Stick X=%6.2f ", abs(InputState.stickRX));
printf("Right stick X=%6.2f ", abs(InputState.stickRX));
printf("Y=%6.2f\n", abs(InputState.stickRY));
}

if ( ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0 && (GetAsyncKeyState('R') & 0x8000) != 0 && SkipPollCount == 0 ) || BTReset || ResetCounter == ResetControllersTimeOut)
{
AppStatus.ControllerCount = JslConnectDevices();
JslGetConnectedDeviceHandles(deviceID, AppStatus.ControllerCount);
GamepadSearch();
GamepadSetState(GamepadOutState);
BTReset = false;
MainTextUpdate();
SkipPollCount = SkipPollTimeOut;
}

// Switch emulation mode
if ((((GetAsyncKeyState(VK_MENU) & 0x8000) != 0 && (GetAsyncKeyState('Q') & 0x8000) != 0) || ((InputState.buttons & JSMASK_LEFT || InputState.buttons & JSMASK_RIGHT) && InputState.buttons & JSMASK_PS)) && SkipPollCount == 0) // Disable Xbox controller emulation for games that support DualSense, DualShock, Nintendo controllers or enable only driving & mouse aiming
{
int LastGamepadEmuMode = AppStatus.GamepadEmulationMode;
Expand All @@ -608,7 +621,7 @@ int main(int argc, char **argv)
ret = vigem_target_x360_register_notification(client, x360, &notification, nullptr);
}

SkipPollCount = 30; //SkipPollTimeOut; -- 15 is seems not enough to enable or disable Xbox virtual gamepad
SkipPollCount = 30; // 15 is seems not enough to enable or disable Xbox virtual gamepad

if (AppStatus.GamepadEmulationMode == EmuKeyboardAndMouse)
LoadKMProfile(KMProfiles[ProfileIndex]);
Expand All @@ -620,20 +633,23 @@ int main(int argc, char **argv)
MainTextUpdate();
}

// Switch aiming mode: mouse / joymouse
if ( ( ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0 && (GetAsyncKeyState('A') & 0x8000) != 0) || (InputState.buttons & JSMASK_PS && InputState.buttons & JSMASK_R) ) && SkipPollCount == 0)
{
AppStatus.AimMode = !AppStatus.AimMode;
MainTextUpdate();
SkipPollCount = SkipPollTimeOut;
}

// Switch modes by pressing or touching
if ( ((GetAsyncKeyState(VK_MENU) & 0x8000) != 0 && (GetAsyncKeyState('W') & 0x8000) != 0) || (InputState.buttons & JSMASK_PS && InputState.buttons & JSMASK_SHARE) && SkipPollCount == 0)
{
AppStatus.ChangeModesWithoutPress = !AppStatus.ChangeModesWithoutPress;
MainTextUpdate();
SkipPollCount = SkipPollTimeOut;
}

// Enable or disable lightbar
if ((((GetAsyncKeyState(VK_MENU) & 0x8000) != 0 && (GetAsyncKeyState('B') & 0x8000) != 0) || (InputState.buttons & JSMASK_PS && InputState.buttons & JSMASK_L)) && SkipPollCount == 0)
{
if (GamepadOutState.LEDBrightness == 255) GamepadOutState.LEDBrightness = DefaultLEDBrightness;
Expand All @@ -646,6 +662,7 @@ int main(int argc, char **argv)
SkipPollCount = SkipPollTimeOut;
}

// Switch keyboard and mouse profile
if (AppStatus.GamepadEmulationMode == EmuKeyboardAndMouse && SkipPollCount == 0)
if ( (InputState.buttons & JSMASK_PS && (InputState.buttons & JSMASK_UP || InputState.buttons & JSMASK_DOWN)) ||
( ( (GetAsyncKeyState(VK_MENU) & 0x8000) != 0 && ( (GetAsyncKeyState(VK_UP) & 0x8000) != 0 || (GetAsyncKeyState(VK_DOWN) & 0x8000) != 0) ) && GetConsoleWindow() == GetForegroundWindow()) )
Expand All @@ -658,12 +675,7 @@ int main(int argc, char **argv)
PlaySound(ChangeEmuModeWav, NULL, SND_ASYNC);
}

XUSB_REPORT_INIT(&report);

InputState = JslGetSimpleState(deviceID[0]);
MotionState = JslGetMotionState(deviceID[0]);
MotionAngles = QuaternionToEulerAngle(MotionState.quatW, MotionState.quatZ, MotionState.quatX, MotionState.quatY); // ?? correct?

// Switch modes by touchpad
if (JslGetControllerType(deviceID[0]) == JS_TYPE_DS || JslGetControllerType(deviceID[0]) == JS_TYPE_DS4) {

TouchState = JslGetTouchState(deviceID[0]);
Expand Down Expand Up @@ -697,14 +709,18 @@ int main(int argc, char **argv)

if (TouchState.t0Y > 0.1 && TouchState.t0Y < 0.7) { // Default mode
GamepadActionMode = GamepadDefaultMode;
GamepadOutState.LEDBlue = 255; GamepadOutState.LEDRed = 0; GamepadOutState.LEDGreen = 0;
// Show battery level
GetBatteryInfo(); BackOutStateCounter = 40; GamepadOutState.PlayersCount = CurGamepad.LEDBatteryLevel; GamepadSetState(GamepadOutState); // JslSetPlayerNumber(deviceID[0], 5);
GetBatteryInfo(); BackOutStateCounter = 40;
if (ShowBatteryStatusOnLightBar) {
if (CurGamepad.BatteryLevel >= 30) { GamepadOutState.LEDBlue = 0; GamepadOutState.LEDRed = 0; GamepadOutState.LEDGreen = 255; } // Battery fine 30%-100%
else if (CurGamepad.BatteryLevel >= 10) { GamepadOutState.LEDBlue = 0; GamepadOutState.LEDGreen = 255; GamepadOutState.LEDRed = 255; } // Battery attention 10..29%
else { GamepadOutState.LEDBlue = 0; GamepadOutState.LEDRed = 255; GamepadOutState.LEDGreen = 0; } // battery alarm 10%
}
GamepadOutState.PlayersCount = CurGamepad.LEDBatteryLevel; // JslSetPlayerNumber(deviceID[0], 5);
AppStatus.ShowBatteryStatus = true;
MainTextUpdate();
} else { // Touch sticks mode
GamepadActionMode = TouchpadSticksMode;
//JslSetRumble(0, 255, 255);
GamepadOutState.LEDBlue = 255; GamepadOutState.LEDRed = 255; GamepadOutState.LEDGreen = 0;
}

Expand Down Expand Up @@ -777,7 +793,7 @@ int main(int argc, char **argv)

// GameBar & multi keys
// PS without any keys
if (InputState.buttons == JSMASK_PS && PSReleasedCount == 0) { PSOnlyCheckCount = 15; PSOnlyPressed = true; }
if (InputState.buttons == JSMASK_PS && PSReleasedCount == 0) { PSOnlyCheckCount = 20; PSOnlyPressed = true; }
if (PSOnlyCheckCount > 0) {
if (PSOnlyCheckCount == 1 && PSOnlyPressed)
PSReleasedCount = PSReleasedTimeOut; // Timeout to release the PS button and don't execute commands
Expand All @@ -802,9 +818,10 @@ int main(int argc, char **argv)
if (InputState.buttons & JSMASK_PS && InputState.buttons & JSMASK_RCLICK) CustomMulSens = 1; //printf("%5.2f\n", CustomMulSens);

// Gamepad modes
if (GamepadActionMode == MotionDrivingMode) // Motion racing [O--]
report.sThumbLX = ToLeftStick(OffsetYPR(RadToDeg(MotionAngles.Roll), RadToDeg(AnglesOffset.Roll)) * -1, MotionWheelAngle);
else if (GamepadActionMode == MotionAimingMode || GamepadActionMode == MotionAimingModeOnlyPressed) { // Motion aiming [--X}]
if (GamepadActionMode == MotionDrivingMode) { // Motion racing [O--]
report.sThumbLX = MotionWheelRoll ? ToLeftStick(OffsetYPR(RadToDeg(MotionAngles.Roll), RadToDeg(AnglesOffset.Roll)) * -1, MotionWheelAngle) : report.sThumbLX = ToLeftStick(OffsetYPR(RadToDeg(MotionAngles.Yaw), RadToDeg(AnglesOffset.Yaw)) * -1, MotionWheelAngle);
if (MotionWheelPitch) report.sThumbLY = ToLeftStick(OffsetYPR(RadToDeg(MotionAngles.Pitch), RadToDeg(AnglesOffset.Pitch)) * WheelInvertPitch, MotionWheelAngle);
} else if (GamepadActionMode == MotionAimingMode || GamepadActionMode == MotionAimingModeOnlyPressed) { // Motion aiming [--X}]
float DeltaX = OffsetYPR(RadToDeg(MotionAngles.Yaw), RadToDeg(AnglesOffset.Yaw)) * -1;
float DeltaY = OffsetYPR(RadToDeg(MotionAngles.Pitch), RadToDeg(AnglesOffset.Pitch)) * -1;
if (GamepadActionMode == MotionAimingMode || (GamepadActionMode == MotionAimingModeOnlyPressed && InputState.lTrigger > 0) )
Expand Down Expand Up @@ -904,7 +921,7 @@ int main(int argc, char **argv)
}

// Battery level display
if (BackOutStateCounter > 0) { if (BackOutStateCounter == 1) { GamepadOutState.PlayersCount = 0; GamepadSetState(GamepadOutState); AppStatus.ShowBatteryStatus = false; MainTextUpdate(); } BackOutStateCounter--; }
if (BackOutStateCounter > 0) { if (BackOutStateCounter == 1) { GamepadOutState.LEDBlue = 255; GamepadOutState.LEDRed = 0; GamepadOutState.LEDGreen = 0; GamepadOutState.PlayersCount = 0; GamepadSetState(GamepadOutState); AppStatus.ShowBatteryStatus = false; MainTextUpdate(); } BackOutStateCounter--; }

if (AutoReconnect) { if (ResetCounter >= ResetControllersTimeOut) ResetCounter = 0; else ResetCounter++; } // Auto reconnect controllers & fix JoyShockLibrary bug with increase in CPU usage when the controller is turned off
//printf("%d \n", ResetCounter);
Expand Down
1 change: 0 additions & 1 deletion Source/Launcher/Unit1.pas
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ TMain = class(TForm)
CheckAppClosedTimer: TTimer;
XPManifest1: TXPManifest;
N5: TMenuItem;
N6: TMenuItem;
ProfilesBtn: TMenuItem;
HidHideBtn: TMenuItem;
procedure FormCreate(Sender: TObject);
Expand Down

0 comments on commit 1dc4e13

Please sign in to comment.