Skip to content

Commit

Permalink
XInput emulation now bypasses the system GameInput.dll for systems th…
Browse files Browse the repository at this point in the history
…at do not have this DLL
  • Loading branch information
Kaldaien committed Dec 1, 2024
1 parent 245e0c0 commit 1db2756
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 24 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
24.12.1.1
24.12.1.3
=========
+ XInput emulation now bypasses GameInput.dll for systems that do not have
this DLL.

24.12.1.1
=========
+ Allow Starfield to read Windows.Gaming.Input and write XInput

Expand Down
2 changes: 2 additions & 0 deletions SpecialK.def
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ RegisterRawInputDevices_Override = RegisterRawInputDevices_Detour PRI
GetRawInputData_Override = GetRawInputData_Detour PRIVATE
HidP_GetData_Override = HidP_GetData_Detour PRIVATE

GameInputCreate = GameInputCreate_BypassSystemDLL

SK_Input_GetDI8Keyboard = SK_Input_GetDI8Keyboard
SK_Input_GetDI8Mouse = SK_Input_GetDI8Mouse
SK_XInput_PollController = SK_XInput_PollController
Expand Down
4 changes: 2 additions & 2 deletions include/SpecialK/DLL_VERSION.H
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#define SK_YEAR 24
#define SK_MONTH 12
#define SK_DATE 1
#define SK_REV_N 1
#define SK_REV 1
#define SK_REV_N 3
#define SK_REV 3

#ifndef _A2
#define _A2(a) #a
Expand Down
2 changes: 1 addition & 1 deletion include/SpecialK/input/game_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class SK_IGameInputDevice : IGameInputDevice
{
public:
SK_IGameInputDevice (IGameInputDevice *pGameInputDevice) : pReal (pGameInputDevice),
ver_ (0)
ver_ (0)
{
if (pGameInputDevice == nullptr)
return;
Expand Down
1 change: 1 addition & 0 deletions include/SpecialK/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ struct SK_HID_PlayStationDevice
volatile ULONG right;
ULONG last_left;
ULONG last_right;
bool used; // Flagged the first time a game sets trigger vibration
} trigger;

volatile ULONG max_val = 0;
Expand Down
5 changes: 3 additions & 2 deletions src/control_panel/cfg_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,8 @@ SK::ControlPanel::Input::Draw (void)
ImGui::Separator ( );
}

SK_HID_PlayStationDevice *pNewestInput = nullptr;

if (bHasPlayStation)
{
ImGui::PushStyleColor (ImGuiCol_Header, ImVec4 (0.90f, 0.40f, 0.40f, 0.45f));
Expand All @@ -1430,7 +1432,6 @@ SK::ControlPanel::Input::Draw (void)

ImGui::TreePop ();

SK_HID_PlayStationDevice *pNewestInput = nullptr;
UINT64 last_input = 0;

for ( auto& ps_controller : SK_HID_PlayStationControllers )
Expand Down Expand Up @@ -2080,7 +2081,7 @@ SK::ControlPanel::Input::Draw (void)
static bool has_gameinput =
GetModuleHandleW (L"GameInput.dll") != nullptr;

if (has_gameinput && SK_GameInput_Backend->reads [2] > 0)
if ((has_gameinput && SK_GameInput_Backend->reads [2] > 0) || (pNewestInput != nullptr && pNewestInput->_vibration.trigger.used))
{
ImGui::TreePush (""); bool changed =
ImGui::SliderFloat ("Left Trigger", &config.input.gamepad.impulse_strength_l, 0.0f, 1.5f, "%3.1fx Impulse Strength");
Expand Down
10 changes: 10 additions & 0 deletions src/diagnostics/load_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,11 @@ LoadLibrary_Marshal ( LPVOID lpRet,
if (lpFileName == nullptr)
return nullptr;

if (config.input.gamepad.xinput.emulate && StrStrIW (lpFileName, L"GameInput.dll"))
{
return SK_GetDLL ();
}

SK_LockDllLoader ();

HMODULE hModEarly = nullptr;
Expand Down Expand Up @@ -1167,6 +1172,11 @@ LoadLibraryEx_Marshal ( LPVOID lpRet, LPCWSTR lpFileName,
if (lpFileName == nullptr)
return nullptr;

if (config.input.gamepad.xinput.emulate && StrStrIW (lpFileName, L"GameInput.dll"))
{
return SK_GetDLL ();
}

wchar_t* compliant_path =
const_cast <wchar_t *> (lpFileName);

Expand Down
67 changes: 49 additions & 18 deletions src/input/game_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ SK_IWrapGameInput::QueryInterface (REFIID riid, void **ppvObject) noexcept
return S_OK;
}

if (! pReal)
return E_NOTIMPL;

HRESULT hr =
pReal->QueryInterface (riid, ppvObject);

Expand Down Expand Up @@ -145,7 +148,7 @@ SK_IWrapGameInput::AddRef (void) noexcept
InterlockedIncrement (&refs_);

return
pReal->AddRef ();
pReal != nullptr ? pReal->AddRef () : 1;
};

ULONG
Expand All @@ -154,7 +157,7 @@ SK_IWrapGameInput::Release (void) noexcept
{
ULONG xrefs =
InterlockedDecrement (&refs_),
refs = pReal->Release ();
refs = pReal != nullptr ? pReal->Release () : 1;

if (xrefs == 0)
{
Expand All @@ -179,7 +182,8 @@ SK_IWrapGameInput::GetCurrentTimestamp (void) noexcept
{
SK_LOG_FIRST_CALL

return pReal->GetCurrentTimestamp ();
return
pReal != nullptr ? pReal->GetCurrentTimestamp () : SK_QueryPerf ().QuadPart;
}

static concurrency::concurrent_unordered_map <IGameInputDevice*,concurrency::concurrent_unordered_map <GameInputKind,SK_ComPtr<IGameInputReading>>> _current_readings;
Expand Down Expand Up @@ -256,7 +260,7 @@ SK_IWrapGameInput::GetCurrentReading (_In_ GameInputKind inputKind
return S_OK;
}

else if (reading != nullptr)
else if (reading != nullptr && pReal != nullptr)
{
HRESULT hr =
pReal->GetCurrentReading (inputKind, device, reading);
Expand All @@ -267,7 +271,7 @@ SK_IWrapGameInput::GetCurrentReading (_In_ GameInputKind inputKind
}

return
pReal->GetCurrentReading (inputKind, device, reading);
pReal != nullptr ? pReal->GetCurrentReading (inputKind, device, reading) : E_NOTIMPL;
}

using IGameInputDevice_SetHapticMotorState_pfn = HRESULT (STDMETHODCALLTYPE *)(IGameInputDevice*,uint32_t,GameInputHapticFeedbackParams const*) noexcept;
Expand Down Expand Up @@ -622,7 +626,7 @@ SK_IWrapGameInput::RegisterDeviceCallback (_In_opt_ IGame
SK_LOG_FIRST_CALL

HRESULT hr =
pReal->RegisterDeviceCallback (device, inputKind, statusFilter, enumerationKind, context, callbackFunc, callbackToken);
pReal == nullptr ? S_OK : pReal->RegisterDeviceCallback (device, inputKind, statusFilter, enumerationKind, context, callbackFunc, callbackToken);

if (SUCCEEDED (hr) && inputKind == GameInputKindGamepad && (statusFilter & GameInputDeviceConnected) != 0 && (config.input.gamepad.xinput.emulate || ! SK_XInput_PollController (0)))
{
Expand All @@ -647,6 +651,7 @@ SK_IWrapGameInput::RegisterSystemButtonCallback (_In_opt_
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->RegisterSystemButtonCallback (device, buttonFilter, context, callbackFunc, callbackToken);
}

Expand All @@ -660,6 +665,7 @@ SK_IWrapGameInput::RegisterKeyboardLayoutCallback (_In_opt_
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->RegisterKeyboardLayoutCallback (device, context, callbackFunc, callbackToken);
}

Expand All @@ -669,8 +675,8 @@ SK_IWrapGameInput::StopCallback (_In_ GameInputCallbackToken callbackToken) noex
{
SK_LOG_FIRST_CALL

return
pReal->StopCallback (callbackToken);
if (pReal != nullptr)
pReal->StopCallback (callbackToken);
}

bool
Expand All @@ -681,6 +687,7 @@ SK_IWrapGameInput::UnregisterCallback (_In_ GameInputCallbackToken callbackToken
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->UnregisterCallback (callbackToken, timeoutInMicroseconds);
}

Expand All @@ -691,6 +698,7 @@ SK_IWrapGameInput::CreateDispatcher (_COM_Outptr_ IGameInputDispatcher **dispatc
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->CreateDispatcher (dispatcher);
}

Expand All @@ -702,6 +710,7 @@ SK_IWrapGameInput::CreateAggregateDevice (_In_ GameInputKind inputK
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->CreateAggregateDevice (inputKind, device);
}

Expand All @@ -713,6 +722,7 @@ SK_IWrapGameInput::FindDeviceFromId (_In_ APP_LOCAL_DEVICE_ID const *va
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->FindDeviceFromId (value, device);
}

Expand All @@ -724,6 +734,7 @@ SK_IWrapGameInput::FindDeviceFromObject (_In_ IUnknown *value,
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->FindDeviceFromObject (value, device);
}

Expand All @@ -735,6 +746,7 @@ SK_IWrapGameInput::FindDeviceFromPlatformHandle (_In_ HANDLE
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->FindDeviceFromPlatformHandle (value, device);
}

Expand All @@ -746,6 +758,7 @@ SK_IWrapGameInput::FindDeviceFromPlatformString (_In_ LPCWSTR
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->FindDeviceFromPlatformString (value, device);
}

Expand All @@ -759,6 +772,7 @@ SK_IWrapGameInput::EnableOemDeviceSupport (_In_ uint16_t vendorId,
SK_LOG_FIRST_CALL

return
pReal == nullptr ? S_OK :
pReal->EnableOemDeviceSupport (vendorId, productId, interfaceNumber, collectionNumber);
}

Expand All @@ -768,8 +782,8 @@ SK_IWrapGameInput::SetFocusPolicy (_In_ GameInputFocusPolicy policy) noexcept
{
SK_LOG_FIRST_CALL

return
pReal->SetFocusPolicy (policy);
if (pReal != nullptr)
pReal->SetFocusPolicy (policy);
}


Expand All @@ -784,9 +798,9 @@ GameInputCreate_Detour (IGameInput** gameInput)
HRESULT hr =
GameInputCreate_Original (&pReal);

if (SUCCEEDED (hr))
if (SUCCEEDED (hr) || config.input.gamepad.xinput.emulate)
{
if (gameInput != nullptr)
//if (gameInput != nullptr)
{
// Turn on XInput emulation by default on first-run for Unreal Engine.
//
Expand All @@ -805,13 +819,17 @@ GameInputCreate_Detour (IGameInput** gameInput)
}
}

*gameInput = (IGameInput *)new SK_IWrapGameInput (pReal);
if (config.input.gamepad.xinput.emulate)
{
*gameInput = (IGameInput *)new SK_IWrapGameInput (pReal);
return S_OK;
}
}

else
{
pReal->Release ();
}
//else
//{
// pReal->Release ();
//}
}

return hr;
Expand Down Expand Up @@ -1490,11 +1508,13 @@ SK_Input_HookGameInput (void)
if (! config.input.gamepad.hook_game_input)
return;

if (GetModuleHandleW (L"GameInput.dll") != nullptr)
if (GetModuleHandleW (L"GameInput.dll") != nullptr || config.input.gamepad.xinput.emulate)
{
static volatile LONG hooked = FALSE;
if (! InterlockedCompareExchange (&hooked, TRUE, FALSE))
{
if (config.input.gamepad.xinput.emulate)
SK_LoadLibraryW ( L"GameInput.dll");
SK_CreateDLLHook2 ( L"GameInput.dll",
"GameInputCreate",
GameInputCreate_Detour,
Expand Down Expand Up @@ -1915,4 +1935,15 @@ SK_IPlayStationGameInputReading::GetUiNavigationState (GameInputUiNavigationStat
SK_RunOnce (SK_LOGi0 (L"Stub"));

return false;
}


HRESULT
WINAPI
GameInputCreate_BypassSystemDLL (IGameInput** gameInput)
{
SK_LOG_FIRST_CALL

return
GameInputCreate_Detour (gameInput);
}
5 changes: 5 additions & 0 deletions src/input/hid_reports/playstation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,11 @@ SK_HID_PlayStationDevice::setVibration (
USHORT right_trigger,
USHORT max_val )
{
if (left_trigger + right_trigger != 0)
{
_vibration.trigger.used = true;
}

if (max_val == 0)
{
const auto last_max = ReadULongAcquire (&_vibration.max_val);
Expand Down

0 comments on commit 1db2756

Please sign in to comment.