Skip to content

Commit

Permalink
Merge pull request #6 from jpflouret/master
Browse files Browse the repository at this point in the history
Support XInput 9.1.0 for Windows 7/8
  • Loading branch information
jpflouret authored Apr 22, 2020
2 parents 67175f8 + b1b3619 commit 2b467c2
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 9 deletions.
175 changes: 175 additions & 0 deletions RdpGamepadPlugin/DynamicXInput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#include "pch.h"

#include "DynamicXInput.h"

class CFunctionPtr
{
public:
explicit CFunctionPtr(FARPROC pFunction)
: mFunction(pFunction)
{}

template<typename FunctionType, typename = std::enable_if<std::is_function<FunctionType>::value>::type>
operator FunctionType*() const
{
return reinterpret_cast<FunctionType*>(mFunction);
}

private:
FARPROC mFunction;
};

class CDllHelper
{
public:
CDllHelper() = default;
~CDllHelper()
{
Unload();
}

bool Load(LPCWSTR pModuleName)
{
Unload();
mHandle = LoadLibraryW(pModuleName);
return mHandle != nullptr;
}

void Unload()
{
if (mHandle != nullptr)
{
FreeLibrary(mHandle);
mHandle = nullptr;
}
}

CFunctionPtr GetProc(LPCSTR pFunctionName)
{
return CFunctionPtr(GetProcAddress(mHandle, pFunctionName));
}

bool IsLoaded() const
{
return mHandle != nullptr;
}

private:
HMODULE mHandle = nullptr;
};

class CDynamicXInput
{
public:
CDynamicXInput() = default;
~CDynamicXInput()
{
Unload();
}

bool Load()
{
if (!mXInputDll.IsLoaded())
{
static LPCWSTR const dllNamesToTry[] = {L"xinput1_4.dll", L"xinput9_1_0.dll"};
for (LPCWSTR dll : dllNamesToTry)
{
if (mXInputDll.Load(dll))
{
mXInputGetState = mXInputDll.GetProc("XInputGetState");
mXInputSetState = mXInputDll.GetProc("XInputSetState");
mXInputGetCapabilities = mXInputDll.GetProc("XInputGetCapabilities");

if (mXInputGetState && mXInputSetState && mXInputGetCapabilities)
{
break;
}

mXInputDll.Unload();
}
}
}

if (!mXInputDll.IsLoaded())
{
SetLastError(ERROR_DELAY_LOAD_FAILED);
return FALSE;
}

return true;
}

void Unload()
{
mXInputGetState = nullptr;
mXInputSetState = nullptr;
mXInputGetCapabilities = nullptr;
mXInputDll.Unload();
}

DWORD GetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{
if (mXInputGetState)
{
return mXInputGetState(dwUserIndex, pState);
}

return ERROR_DELAY_LOAD_FAILED;
}

DWORD SetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
{
if (mXInputSetState)
{
return mXInputSetState(dwUserIndex, pVibration);
}

return ERROR_DELAY_LOAD_FAILED;
}

DWORD GetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
{
if (mXInputGetCapabilities)
{
return mXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
}

return ERROR_DELAY_LOAD_FAILED;
}

private:
CDllHelper mXInputDll;
decltype(XInputGetState)* mXInputGetState = nullptr;
decltype(XInputSetState)* mXInputSetState = nullptr;
decltype(XInputGetCapabilities)* mXInputGetCapabilities = nullptr;
};

static CDynamicXInput DynamicXInput;

bool LoadXInput()
{
return DynamicXInput.Load();
}

void UnloadXInput()
{
DynamicXInput.Unload();
}

DWORD ThunkXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{
return DynamicXInput.GetState(dwUserIndex, pState);
}

DWORD ThunkXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration)
{
return DynamicXInput.SetState(dwUserIndex, pVibration);
}

DWORD ThunkXInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
{
return DynamicXInput.GetCapabilities(dwUserIndex, dwFlags, pCapabilities);
}
11 changes: 11 additions & 0 deletions RdpGamepadPlugin/DynamicXInput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#pragma once

bool LoadXInput();
void UnloadXInput();

DWORD ThunkXInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState);
DWORD ThunkXInputSetState(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
DWORD ThunkXInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities);
7 changes: 4 additions & 3 deletions RdpGamepadPlugin/RdpGamepadPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "RdpGamepadPlugin.h"
#include "RdpGamepadProtocol.h"
#include "TimerManager.h"
#include "DynamicXInput.h"

template <typename T, std::size_t N>
constexpr std::size_t array_size(T(&)[N]) { return N; }
Expand Down Expand Up @@ -137,7 +138,7 @@ HRESULT CRdpGamepadChannel::HandleSetState(const RdpGamepad::RdpProtocolPacket&
{
const auto& request = packet.mSetStateRequest;

DWORD result = XInputSetState(request.mUserIndex, const_cast<XINPUT_VIBRATION*>(&request.mVibration));
DWORD result = ThunkXInputSetState(request.mUserIndex, const_cast<XINPUT_VIBRATION*>(&request.mVibration));

auto response = RdpGamepad::RdpSetStateResponse::MakeResponse(request.mUserIndex, result);
return mChannel->Write(sizeof(response), reinterpret_cast<BYTE*>(&response), nullptr);
Expand All @@ -148,7 +149,7 @@ HRESULT CRdpGamepadChannel::HandleGetCapabilities(const RdpGamepad::RdpProtocolP
const auto& request = packet.mGetCapabilitiesRequest;

XINPUT_CAPABILITIES capabilities;
DWORD result = XInputGetCapabilities(request.mUserIndex, request.mFlags, &capabilities);
DWORD result = ThunkXInputGetCapabilities(request.mUserIndex, request.mFlags, &capabilities);

auto response = RdpGamepad::RdpGetCapabilitiesResponse::MakeResponse(request.mUserIndex, result, capabilities);
return mChannel->Write(sizeof(response), reinterpret_cast<BYTE*>(&response), nullptr);
Expand All @@ -157,7 +158,7 @@ HRESULT CRdpGamepadChannel::HandleGetCapabilities(const RdpGamepad::RdpProtocolP
HRESULT CRdpGamepadChannel::SendControllerState(DWORD dwUserIndex)
{
XINPUT_STATE state;
DWORD result = XInputGetState(dwUserIndex, &state);
DWORD result = ThunkXInputGetState(dwUserIndex, &state);

auto response = RdpGamepad::RdpGetStateResponse::MakeResponse(dwUserIndex, result, state);
return mChannel->Write(sizeof(response), reinterpret_cast<BYTE*>(&response), nullptr);
Expand Down
6 changes: 2 additions & 4 deletions RdpGamepadPlugin/RdpGamepadPlugin.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@
<SubSystem>Windows</SubSystem>
<ModuleDefinitionFile>.\RdpGamepadPlugin.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Xinput.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Bscmake />
</ItemDefinitionGroup>
Expand Down Expand Up @@ -155,7 +154,6 @@
<SubSystem>Windows</SubSystem>
<ModuleDefinitionFile>.\RdpGamepadPlugin.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Xinput.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Bscmake />
</ItemDefinitionGroup>
Expand Down Expand Up @@ -191,7 +189,6 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Xinput.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Bscmake />
</ItemDefinitionGroup>
Expand Down Expand Up @@ -226,11 +223,11 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Xinput.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Bscmake />
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="DynamicXInput.cpp" />
<ClCompile Include="RdpGamepadPlugin.cpp" />
<ClCompile Include="RdpGamepadPluginModule.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
Expand Down Expand Up @@ -268,6 +265,7 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DynamicXInput.h" />
<ClInclude Include="RdpGamepadPlugin.h" />
<ClInclude Include="RdpGamepadPluginModule.h" />
<ClInclude Include="RdpGamepadPlugin_i.h" />
Expand Down
6 changes: 6 additions & 0 deletions RdpGamepadPlugin/RdpGamepadPlugin.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
<ClCompile Include="RdpGamepadPlugin.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="DynamicXInput.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="targetver.h">
Expand All @@ -57,6 +60,9 @@
<ClInclude Include="TimerManager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="DynamicXInput.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="RdpGamepadPlugin.rc">
Expand Down
15 changes: 15 additions & 0 deletions RdpGamepadPlugin/RdpGamepadPluginModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,30 @@
// Licensed under the MIT License.

#include "pch.h"

#include "resource.h"
#include "RdpGamepadPlugin_i.h"
#include "RdpGamepadPluginModule.h"
#include "DynamicXInput.h"

CRdpGamepadPluginModule _AtlModule;

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
hInstance;

if (dwReason == DLL_PROCESS_ATTACH)
{
if (!LoadXInput())
{
return FALSE;
}
}
else if (dwReason == DLL_PROCESS_DETACH)
{
UnloadXInput();
}

return _AtlModule.DllMain(dwReason, lpReserved);
}

Expand Down
1 change: 1 addition & 0 deletions RdpGamepadPlugin/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@
#include <chrono>
#include <functional>
#include <map>
#include <type_traits>
#include <vector>
2 changes: 1 addition & 1 deletion Setup/RdpGamepadClientInstall.iss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#define MyAppPublisher "Microsoft Corporation"
#define MyAppPublisherURL "https://www.microsoft.com"
#define MyAppURL "https://github.com/Microsoft/RdpGamepad"
#define MyAppVersion "1.0.0"
#define MyAppVersion "1.0.1"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
Expand Down
2 changes: 1 addition & 1 deletion Setup/RdpGamepadReceiverInstall.iss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#define MyAppPublisher "Microsoft Corporation"
#define MyAppPublisherURL "https://www.microsoft.com"
#define MyAppURL "https://github.com/Microsoft/RdpGamepad"
#define MyAppVersion "1.0.0"
#define MyAppVersion "1.0.1"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
Expand Down

1 comment on commit 2b467c2

@piyushexe
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how to install rdp game pad for mac os

Please sign in to comment.