Skip to content
Permalink
Browse files
Merge pull request #10565 from AdmiralCurtiss/wgi-win7
Core/WGInput: Dynamically load winrt function addresses.
  • Loading branch information
AdmiralCurtiss committed Apr 8, 2022
2 parents e021940 + 5fda8ee commit 0c7f992
Showing 1 changed file with 114 additions and 11 deletions.
@@ -12,11 +12,17 @@
#include <windows.gaming.input.h>
#include <wrl.h>

#include "Common/DynamicLibrary.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"

#pragma comment(lib, "runtimeobject.lib")
using PIsApiSetImplemented = BOOL(APIENTRY*)(PCSTR Contract);
using PRoInitialize = decltype(&RoInitialize);
using PRoUninitialize = decltype(&RoUninitialize);
using PRoGetActivationFactory = decltype(&RoGetActivationFactory);
using PWindowsCreateStringReference = decltype(&WindowsCreateStringReference);
using PWindowsGetStringRawBuffer = decltype(&WindowsGetStringRawBuffer);

namespace WGI = ABI::Windows::Gaming::Input;
using ABI::Windows::Foundation::Collections::IVectorView;
@@ -26,6 +32,11 @@ namespace
{
bool g_runtime_initialized = false;
bool g_runtime_needs_deinit = false;
PRoInitialize g_RoInitialize_address = nullptr;
PRoUninitialize g_RoUninitialize_address = nullptr;
PRoGetActivationFactory g_RoGetActivationFactory_address = nullptr;
PWindowsCreateStringReference g_WindowsCreateStringReference_address = nullptr;
PWindowsGetStringRawBuffer g_WindowsGetStringRawBuffer_address = nullptr;
} // namespace

namespace ciface::WGInput
@@ -571,12 +582,77 @@ class Device : public Core::Device
ControlState m_battery_level = 0;
};

static bool LoadFunctionPointers()
{
static Common::DynamicLibrary winrt_l1_1_0_handle;
static Common::DynamicLibrary winrt_string_l1_1_0_handle;
if (!winrt_l1_1_0_handle.IsOpen() && !winrt_string_l1_1_0_handle.IsOpen())
{
Common::DynamicLibrary kernelBase("KernelBase.dll");
if (!kernelBase.IsOpen())
return false;

void* const IsApiSetImplemented_address = kernelBase.GetSymbolAddress("IsApiSetImplemented");
if (!IsApiSetImplemented_address)
return false;
if (!static_cast<PIsApiSetImplemented>(IsApiSetImplemented_address)(
"api-ms-win-core-winrt-l1-1-0"))
{
return false;
}
if (!static_cast<PIsApiSetImplemented>(IsApiSetImplemented_address)(
"api-ms-win-core-winrt-string-l1-1-0"))
{
return false;
}

winrt_l1_1_0_handle.Open("api-ms-win-core-winrt-l1-1-0.dll");
winrt_string_l1_1_0_handle.Open("api-ms-win-core-winrt-string-l1-1-0.dll");
}

if (!winrt_l1_1_0_handle.IsOpen() || !winrt_string_l1_1_0_handle.IsOpen())
return false;

g_RoInitialize_address =
static_cast<PRoInitialize>(winrt_l1_1_0_handle.GetSymbolAddress("RoInitialize"));
if (!g_RoInitialize_address)
return false;

g_RoUninitialize_address =
static_cast<PRoUninitialize>(winrt_l1_1_0_handle.GetSymbolAddress("RoUninitialize"));
if (!g_RoUninitialize_address)
return false;

g_RoGetActivationFactory_address = static_cast<PRoGetActivationFactory>(
winrt_l1_1_0_handle.GetSymbolAddress("RoGetActivationFactory"));
if (!g_RoGetActivationFactory_address)
return false;

g_WindowsCreateStringReference_address = static_cast<PWindowsCreateStringReference>(
winrt_string_l1_1_0_handle.GetSymbolAddress("WindowsCreateStringReference"));
if (!g_WindowsCreateStringReference_address)
return false;

g_WindowsGetStringRawBuffer_address = static_cast<PWindowsGetStringRawBuffer>(
winrt_string_l1_1_0_handle.GetSymbolAddress("WindowsGetStringRawBuffer"));
if (!g_WindowsGetStringRawBuffer_address)
return false;

return true;
}

void Init()
{
if (g_runtime_initialized)
return;

const HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED);
if (!LoadFunctionPointers())
{
ERROR_LOG(CONTROLLERINTERFACE, "WGInput: System lacks support, skipping init.");
return;
}

const HRESULT hr = g_RoInitialize_address(RO_INIT_MULTITHREADED);
switch (hr)
{
case S_OK:
@@ -602,13 +678,21 @@ void DeInit()

if (g_runtime_needs_deinit)
{
RoUninitialize();
g_RoUninitialize_address();
g_runtime_needs_deinit = false;
}

g_runtime_initialized = false;
}

template <unsigned int size>
static HRESULT WindowsCreateStringReferenceAutoSizeWrapper(wchar_t const (&source_string)[size],
HSTRING_HEADER* hstring_header,
HSTRING* hstring)
{
return g_WindowsCreateStringReference_address(source_string, size - 1, hstring_header, hstring);
}

void PopulateDevices()
{
if (!g_runtime_initialized)
@@ -617,8 +701,6 @@ void PopulateDevices()
g_controller_interface.RemoveDevice(
[](const auto* dev) { return dev->GetSource() == SOURCE_NAME; });

using Microsoft::WRL::Wrappers::HStringReference;

// WGI Interfaces to potentially use:
// Gamepad: Buttons, 2x Sticks and 2x Triggers, 4x Vibration Motors
// RawGameController: Buttons, Switches (Hats), Axes, Haptics
@@ -628,18 +710,36 @@ void PopulateDevices()
// RacingWheel: Buttons, Clutch, Handbrake, PatternShifterGear, Throttle, Wheel, WheelMotor
// UINavigationController: Directions, Scrolling, etc.

HSTRING_HEADER header_raw_game_controller;
HSTRING hstr_raw_game_controller;
if (FAILED(WindowsCreateStringReferenceAutoSizeWrapper(L"Windows.Gaming.Input.RawGameController",
&header_raw_game_controller,
&hstr_raw_game_controller)))
{
ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to create string reference.");
return;
}

HSTRING_HEADER header_gamepad;
HSTRING hstr_gamepad;
if (FAILED(WindowsCreateStringReferenceAutoSizeWrapper(L"Windows.Gaming.Input.Gamepad",
&header_gamepad, &hstr_gamepad)))
{
ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to create string reference.");
return;
}

ComPtr<WGI::IRawGameControllerStatics> raw_stats;
if (FAILED(
RoGetActivationFactory(HStringReference(L"Windows.Gaming.Input.RawGameController").Get(),
__uuidof(WGI::IRawGameControllerStatics), &raw_stats)))
if (FAILED(g_RoGetActivationFactory_address(
hstr_raw_game_controller, __uuidof(WGI::IRawGameControllerStatics), &raw_stats)))
{
ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to get IRawGameControllerStatics.");
return;
}

ComPtr<WGI::IGamepadStatics2> gamepad_stats;
if (FAILED(RoGetActivationFactory(HStringReference(L"Windows.Gaming.Input.Gamepad").Get(),
__uuidof(WGI::IGamepadStatics2), &gamepad_stats)))
if (FAILED(g_RoGetActivationFactory_address(hstr_gamepad, __uuidof(WGI::IGamepadStatics2),
&gamepad_stats)))
{
ERROR_LOG(CONTROLLERINTERFACE, "WGInput: Failed to get IGamepadStatics2.");
return;
@@ -667,7 +767,10 @@ void PopulateDevices()
{
HSTRING hstr = {};
if (SUCCEEDED(rgc2->get_DisplayName(&hstr)) && hstr)
device_name = StripSpaces(WStringToUTF8(WindowsGetStringRawBuffer(hstr, nullptr)));
{
device_name =
StripSpaces(WStringToUTF8(g_WindowsGetStringRawBuffer_address(hstr, nullptr)));
}
}

if (device_name.empty())

0 comments on commit 0c7f992

Please sign in to comment.