From 3efff581925870736e07247aea4c370f889787a4 Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Sat, 30 Nov 2024 13:52:50 -0500 Subject: [PATCH] Added Xbox Impulse Trigger->PlayStation Adaptive Trigger emulation for games using Windows.Gaming.Input (99.99% of games that support the feature) --- CHANGELOG.txt | 9 +- include/SpecialK/DLL_VERSION.H | 4 +- src/input/hid_reports/playstation.cpp | 12 +-- src/input/windows.gaming.input.cpp | 144 ++++++++++++++++++++------ 4 files changed, 125 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index abf49c93d..d736ac4e2 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,11 @@ -24.11.30.3 +24.11.30.4 +========== + + Added Xbox Impulse Trigger->PlayStation Adaptive Trigger emulation for games + using Windows.Gaming.Input (99.99% of games that support the feature). + + * Make sure Xbox Mode is enabled and restart if needed; off by default. + +24.11.30.3 ========== + Properly remove Adaptive Trigger force feedback when impulse vibration stops diff --git a/include/SpecialK/DLL_VERSION.H b/include/SpecialK/DLL_VERSION.H index 0b70d3750..9a6fb7ddf 100644 --- a/include/SpecialK/DLL_VERSION.H +++ b/include/SpecialK/DLL_VERSION.H @@ -3,8 +3,8 @@ #define SK_YEAR 24 #define SK_MONTH 11 #define SK_DATE 30 -#define SK_REV_N 3 -#define SK_REV 3 +#define SK_REV_N 4 +#define SK_REV 4 #ifndef _A2 #define _A2(a) #a diff --git a/src/input/hid_reports/playstation.cpp b/src/input/hid_reports/playstation.cpp index 35ea94fba..09d7970e6 100644 --- a/src/input/hid_reports/playstation.cpp +++ b/src/input/hid_reports/playstation.cpp @@ -2691,11 +2691,9 @@ SK_HID_PlayStationDevice::write_output_report (bool force) static_cast (std::clamp ( static_cast (dwLeftTrigger) * config.input.gamepad.impulse_strength_l, 0.0f, 1.0f) ); - pDevice->_vibration.trigger.last_left = dwLeftTrigger; } else { output->AllowLeftTriggerFFB = true; const auto trigger_effect = 0; memcpy (output->LeftTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect])); - pDevice->_vibration.trigger.last_left = dwLeftTrigger; } if (dwRightTrigger != 0) { output->AllowRightTriggerFFB = true; @@ -2705,12 +2703,12 @@ SK_HID_PlayStationDevice::write_output_report (bool force) static_cast (std::clamp ( static_cast (dwRightTrigger) * config.input.gamepad.impulse_strength_r, 0.0f, 1.0f) ); - pDevice->_vibration.trigger.last_right = dwRightTrigger; } else { output->AllowRightTriggerFFB = true; const auto trigger_effect = 0; memcpy (output->RightTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect])); - pDevice->_vibration.trigger.last_right = dwRightTrigger; } + pDevice->_vibration.trigger.last_right = dwRightTrigger; + pDevice->_vibration.trigger.last_left = dwLeftTrigger; } @@ -2870,11 +2868,9 @@ SK_HID_PlayStationDevice::write_output_report (bool force) static_cast (std::clamp ( static_cast (dwLeftTrigger) * config.input.gamepad.impulse_strength_l, 0.0f, 1.0f) ); - pDevice->_vibration.trigger.last_left = dwLeftTrigger; } else { output->AllowLeftTriggerFFB = true; const auto trigger_effect = 0; memcpy (output->LeftTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect])); - pDevice->_vibration.trigger.last_left = dwLeftTrigger; } if (dwRightTrigger != 0) { output->AllowRightTriggerFFB = true; @@ -2884,12 +2880,12 @@ SK_HID_PlayStationDevice::write_output_report (bool force) static_cast (std::clamp ( static_cast (dwRightTrigger) * config.input.gamepad.impulse_strength_r, 0.0f, 1.0f) ); - pDevice->_vibration.trigger.last_right = dwRightTrigger; } else { output->AllowRightTriggerFFB = true; const auto trigger_effect = 0; memcpy (output->RightTriggerFFB, effects [trigger_effect], sizeof (effects [trigger_effect])); - pDevice->_vibration.trigger.last_right = dwRightTrigger; } + pDevice->_vibration.trigger.last_right = dwRightTrigger; + pDevice->_vibration.trigger.last_left = dwLeftTrigger; } output->AllowMuteLight = true; diff --git a/src/input/windows.gaming.input.cpp b/src/input/windows.gaming.input.cpp index c6e7447d5..4c3cb34a2 100644 --- a/src/input/windows.gaming.input.cpp +++ b/src/input/windows.gaming.input.cpp @@ -75,6 +75,8 @@ using WGI_GamepadStatistics_get_Gamepads_pfn = HRESULT (STDMETHODCALLTYPE *)(ABI IVectorView **value); using WGI_Gamepad_GetCurrentReading_pfn = HRESULT (STDMETHODCALLTYPE *)(ABI::Windows::Gaming::Input::IGamepad *This, ABI::Windows::Gaming::Input::GamepadReading *value); +using WGI_Gamepad_put_Vibration_pfn = HRESULT (STDMETHODCALLTYPE *)(ABI::Windows::Gaming::Input::IGamepad *This, + ABI::Windows::Gaming::Input::GamepadVibration value); WGI_GamepadStatistics_get_Gamepads_pfn WGI_GamepadStatistics_get_Gamepads_Original = nullptr; @@ -82,6 +84,9 @@ WGI_GamepadStatistics_get_Gamepads_Original = nullptr; WGI_Gamepad_GetCurrentReading_pfn WGI_Gamepad_GetCurrentReading_Original = nullptr; +WGI_Gamepad_put_Vibration_pfn +WGI_Gamepad_put_Vibration_Original = nullptr; + using WGI_VectorView_Gamepads_GetAt_pfn = HRESULT (STDMETHODCALLTYPE *)(void *This, _In_ unsigned index, _Out_ void **item); using WGI_VectorView_Gamepads_get_Size_pfn = HRESULT (STDMETHODCALLTYPE *)(void *This, _Out_ unsigned *size); using WGI_VectorView_Gamepads_IndexOf_pfn = HRESULT (STDMETHODCALLTYPE *)(void *This, _In_opt_ void *value, _Out_ unsigned *index, _Out_ boolean *found); @@ -395,44 +400,56 @@ SK_HID_WGI_Gamepad : ABI::Windows::Gaming::Input::IGamepad { SK_LOG_FIRST_CALL - vibes = value; - - //SK_HID_PlayStationDevice *pNewestInputDevice = nullptr; + bool bRedirected = false; - bool bConnected = false; + SK_HID_PlayStationDevice *pNewestInputDevice = nullptr; for ( auto& ps_controller : SK_HID_PlayStationControllers ) { if (ps_controller.bConnected) { - ps_controller.setVibration ( - (std::min (255ui16, static_cast (vibes.LeftMotor * 255.0 + vibes.LeftTrigger * 255.0))), - (std::min (255ui16, static_cast (vibes.RightMotor * 255.0 + vibes.RightTrigger * 255.0))), 255ui16 - ); - - if ((ps_controller.bBluetooth && config.input.gamepad.bt_input_only)) + if (pNewestInputDevice == nullptr || + pNewestInputDevice->xinput.last_active < ps_controller.xinput.last_active) { + pNewestInputDevice = &ps_controller; } + } + } - else if ((! (ps_controller.bBluetooth && ps_controller.bSimpleMode)) || (vibes.LeftMotor > 0.0 || vibes.RightMotor > 0.0)) + if (pNewestInputDevice != nullptr) + { + if (! SK_ImGui_WantGamepadCapture ()) + { + pNewestInputDevice->setVibration ( + std::min (65535ui16, static_cast (value.LeftMotor * 65536.0)), + std::min (65535ui16, static_cast (value.RightMotor * 65536.0)), + std::min (65535ui16, static_cast (value.LeftTrigger * 65536.0)), + std::min (65535ui16, static_cast (value.RightTrigger * 65536.0)), + 65535ui16 + ); + + // Force an update + //if (pNewestInputDevice->write_output_report (true)) { - if (ps_controller.bBluetooth && (vibes.LeftMotor <= 0.0 && vibes.RightMotor <= 0.0)) - { - if (ps_controller.write_output_report ()) // Let the device decide whether to process this or not - bConnected = true; - } - else - { - // Force an update - if (ps_controller.write_output_report (true)) - bConnected = true; - } + vibes = value; + bRedirected = true; } } + + // Swallow vibration while capturing gamepad input + else + { + bRedirected = true; + } } - if (! bConnected) - SK_XInput_PulseController (0, (float)vibes.LeftMotor, (float)vibes.RightMotor); + // Forward the input to XInput because there was no PlayStation device + if (! bRedirected) + { + vibes = value; + SK_XInput_PulseController (0, static_cast (vibes.LeftMotor), + static_cast (vibes.RightMotor)); + } return S_OK; } @@ -599,6 +616,69 @@ WGI_GamepadStatistics_get_Gamepads_Override ( ABI::Windows::Gaming::Input::IGame bool SK_WGI_EmulatedPlayStation = false; +HRESULT +STDMETHODCALLTYPE +WGI_Gamepad_put_Vibration_Override (ABI::Windows::Gaming::Input::IGamepad *This, + ABI::Windows::Gaming::Input::GamepadVibration value) +{ + SK_LOG_FIRST_CALL + + std::ignore = This; + + bool bRedirected = false; + + SK_HID_PlayStationDevice *pNewestInputDevice = nullptr; + + for ( auto& ps_controller : SK_HID_PlayStationControllers ) + { + if (ps_controller.bConnected) + { + if (pNewestInputDevice == nullptr || + pNewestInputDevice->xinput.last_active < ps_controller.xinput.last_active) + { + pNewestInputDevice = &ps_controller; + } + } + } + + if (pNewestInputDevice != nullptr) + { + if (! SK_ImGui_WantGamepadCapture ()) + { + pNewestInputDevice->setVibration ( + std::min (65535ui16, static_cast (value.LeftMotor * 65536.0)), + std::min (65535ui16, static_cast (value.RightMotor * 65536.0)), + std::min (65535ui16, static_cast (value.LeftTrigger * 65536.0)), + std::min (65535ui16, static_cast (value.RightTrigger * 65536.0)), + 65535ui16 + ); + + // Force an update + //if (pNewestInputDevice->write_output_report (true)) + { + //vibes = value; + bRedirected = true; + } + } + + // Swallow vibration while capturing gamepad input + else + { + bRedirected = true; + } + } + + // Forward the input to XInput because there was no PlayStation device + if (! bRedirected) + { + //vibes = value; + SK_XInput_PulseController (0, static_cast (value.LeftMotor), + static_cast (value.RightMotor)); + } + + return S_OK; +} + HRESULT STDMETHODCALLTYPE WGI_Gamepad_GetCurrentReading_Override (ABI::Windows::Gaming::Input::IGamepad *This, @@ -742,7 +822,7 @@ WGI_Gamepad_GetCurrentReading_Override (ABI::Windows::Gaming::Input::IGamepad memcpy ( &xi_state, &hid_to_xi, sizeof (XINPUT_STATE) ); - value->Timestamp = SK_QueryPerf ().QuadPart; + value->Timestamp = pNewestInputDevice->xinput.last_active; value->Buttons = GamepadButtons::GamepadButtons_None; if ((xi_state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)) @@ -949,7 +1029,7 @@ RoGetActivationFactory_Detour ( _In_ HSTRING activatableClassId, // 9 remove_GamepadRemoved // 10 get_Gamepads - if (config.input.gamepad.xinput.emulate && SK_GetCurrentGameID () != SK_GAME_ID::ForzaHorizon5) + if (config.input.gamepad.xinput.emulate) { SK_RunOnce ({ WGI_VIRTUAL_HOOK ( &pGamepadStatsFactory, 10, @@ -993,19 +1073,17 @@ RoGetActivationFactory_Detour ( _In_ HSTRING activatableClassId, WGI_Gamepad_GetCurrentReading_Original, WGI_Gamepad_GetCurrentReading_pfn ); -/* - WGI_VIRTUAL_HOOK ( &pGamepad, 6, - "ABI::Windows::Gaming::Input::IGamepad::get_Vibration", - WGI_Gamepad_get_Vibration_Override, - WGI_Gamepad_get_Vibration_Original, - WGI_Gamepad_get_Vibration_pfn ); + //WGI_VIRTUAL_HOOK ( &pGamepad, 6, + // "ABI::Windows::Gaming::Input::IGamepad::get_Vibration", + // WGI_Gamepad_get_Vibration_Override, + // WGI_Gamepad_get_Vibration_Original, + // WGI_Gamepad_get_Vibration_pfn ); WGI_VIRTUAL_HOOK ( &pGamepad, 7, "ABI::Windows::Gaming::Input::IGamepad::put_Vibration", WGI_Gamepad_put_Vibration_Override, WGI_Gamepad_put_Vibration_Original, WGI_Gamepad_put_Vibration_pfn ); -*/ SK_ApplyQueuedHooks (); });