Skip to content

Commit

Permalink
Dynamically load latest version of XInput instead of static linking
Browse files Browse the repository at this point in the history
  • Loading branch information
noorus committed Nov 16, 2014
1 parent 9f53138 commit 54a359e
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 41 deletions.
3 changes: 3 additions & 0 deletions include/nil.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ namespace Nil {
Logitech::GKeySDK* mLogitechGKeys; //!< External module for Logitech G-Keys
Logitech::LedSDK* mLogitechLEDs; //!< External module for Logitech LEDs
SystemListener* mListener; //!< Our single event listener
XInput* mXInput; //!< XInput module handler
const Cooperation mCooperation; //!< Cooperation mode
void initializeDevices();
void refreshDevices();
Expand Down Expand Up @@ -138,6 +139,8 @@ namespace Nil {
//! \return null if it fails, else the Logitech LED SDK object.
Logitech::LedSDK* getLogitechLEDs();

XInput* getXInput();

//! Query if this System is initializing.
//! \return true if initializing, false if not.
const bool isInitializing() const;
Expand Down
1 change: 0 additions & 1 deletion include/nilCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include "nilException.h"
#include "nilPnP.h"
#include "nilHID.h"
#include "nilLogitech.h"

namespace Nil {

Expand Down
35 changes: 1 addition & 34 deletions include/nilLogitech.h
Original file line number Diff line number Diff line change
@@ -1,41 +1,8 @@
#pragma once
#include "nil.h"
#include "nilWindows.h"

namespace Nil {

//! \addtogroup Nil
//! @{

//! \class ExternalModule
//! Base class for an external, optional module supported by the system.
class ExternalModule
{
protected:
HMODULE mModule; //!< The module handle
bool mInitialized; //!< Whether the module is initialized
public:
ExternalModule();

//! Possible initialization call return values.
enum InitReturn: unsigned int {
Initialization_OK = 0, //!< Module initialized OK
Initialization_ModuleNotFound, //!< Module was not found
Initialization_MissingExports, //!< Module was missing expected exports
Initialization_Unavailable //!< Module was unavailable for use
};

//! Initializes this ExternalModule.
virtual InitReturn initialize() = 0;

//! Shuts down this ExternalModule and frees any resources it is using.
virtual void shutdown() = 0;

//! Query whether the module is initialized or not.
virtual bool isInitialized() const;
};

//! @}

namespace Logitech {

// Logitech G-Key SDK (1.02.004) implementation
Expand Down
57 changes: 56 additions & 1 deletion include/nilWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "nilException.h"
#include "nilPnP.h"
#include "nilHID.h"
#include "nilLogitech.h"
#include "nilCommon.h"

namespace Nil {

Expand All @@ -19,6 +19,34 @@ namespace Nil {
class Keyboard;
class Controller;

//! \class ExternalModule
//! Base class for an external, optional module supported by the system.
class ExternalModule
{
protected:
HMODULE mModule; //!< The module handle
bool mInitialized; //!< Whether the module is initialized
public:
ExternalModule();

//! Possible initialization call return values.
enum InitReturn: unsigned int {
Initialization_OK = 0, //!< Module initialized OK
Initialization_ModuleNotFound, //!< Module was not found
Initialization_MissingExports, //!< Module was missing expected exports
Initialization_Unavailable //!< Module was unavailable for use
};

//! Initializes this ExternalModule.
virtual InitReturn initialize() = 0;

//! Shuts down this ExternalModule and frees any resources it is using.
virtual void shutdown() = 0;

//! Query whether the module is initialized or not.
virtual bool isInitialized() const;
};

class RawInputDeviceInfo
{
protected:
Expand Down Expand Up @@ -79,6 +107,33 @@ namespace Nil {
virtual const GUID getInstanceID() const;
};

typedef DWORD( WINAPI *fnXInputGetState )( DWORD dwUserIndex, XINPUT_STATE* pState );
typedef DWORD( WINAPI *fnXInputSetState )( DWORD dwUserIndex, XINPUT_VIBRATION* pVibration );
typedef DWORD( WINAPI *fnXInputGetCapabilities )( DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities );

//! \class XInput
//! XInput dynamic module loader.
//! \sa ExternalModule
class XInput: public ExternalModule {
public:
enum Version {
Version_None = 0,
Version_910,
Version_13,
Version_14
} mVersion;
struct Functions {
fnXInputGetState pfnXInputGetState;
fnXInputSetState pfnXInputSetState;
fnXInputGetCapabilities pfnXInputGetCapabilities;
Functions();
} mFunctions;
XInput();
virtual InitReturn initialize();
virtual void shutdown();
~XInput();
};

//! \class XInputDevice
//! Device abstraction base class for XInput devices.
//! \sa Device
Expand Down
1 change: 1 addition & 0 deletions nil.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@
<ClCompile Include="src\System.cpp" />
<ClCompile Include="src\Types.cpp" />
<ClCompile Include="src\Utilities.cpp" />
<ClCompile Include="src\XInput.cpp" />
<ClCompile Include="src\XInputController.cpp" />
<ClCompile Include="src\XInputDevice.cpp" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions nil.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,8 @@
<ClCompile Include="src\LogitechGkeySDK.cpp">
<Filter>Source Files\Windows\Logitech</Filter>
</ClCompile>
<ClCompile Include="src\XInput.cpp">
<Filter>Source Files\Windows</Filter>
</ClCompile>
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/ExternalModule.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "nil.h"
#include "nilLogitech.h"
#include "nilWindows.h"

namespace Nil {

Expand Down
13 changes: 11 additions & 2 deletions src/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Nil {
mMonitor( nullptr ), mIDPool( 0 ), mInitializing( true ),
mHIDManager( nullptr ), mLogitechGKeys( nullptr ), mLogitechLEDs( nullptr ),
mListener( listener ), mMouseIndexPool( 0 ), mKeyboardIndexPool( 0 ),
mControllerIndexPool( 0 )
mControllerIndexPool( 0 ), mXInput( nullptr )
{
assert( mListener );

Expand All @@ -21,6 +21,10 @@ namespace Nil {
mLogitechGKeys = new Logitech::GKeySDK();
mLogitechLEDs = new Logitech::LedSDK();

mXInput = new XInput();
if ( mXInput->initialize() != ExternalModule::Initialization_OK )
NIL_EXCEPT( "Loading XInput failed" );

// Create DirectInput instance
auto hr = DirectInput8Create( mInstance, DIRECTINPUT_VERSION,
IID_IDirectInput8W, (LPVOID*)&mDirectInput, NULL );
Expand Down Expand Up @@ -203,7 +207,7 @@ namespace Nil {
if ( device->getHandler() == Device::Handler_XInput )
{
auto xDevice = static_cast<XInputDevice*>( device );
auto status = XInputGetState( xDevice->getXInputID(), &state );
auto status = mXInput->mFunctions.pfnXInputGetState( xDevice->getXInputID(), &state );
if ( status == ERROR_DEVICE_NOT_CONNECTED )
{
if ( xDevice->getStatus() == Device::Status_Connected )
Expand Down Expand Up @@ -366,6 +370,11 @@ namespace Nil {
return mLogitechLEDs;
}

XInput* System::getXInput()
{
return mXInput;
}

System::~System()
{
for ( Device* device : mDevices )
Expand Down
67 changes: 67 additions & 0 deletions src/XInput.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "nil.h"
#include "nilUtil.h"
#include "nilWindows.h"

# define NIL_LOAD_EXTERNAL_FUNC(x) mFunctions.pfn##x##=(fn##x##)GetProcAddress(mModule,#x)

namespace Nil {

XInput::Functions::Functions(): pfnXInputGetState( nullptr ),
pfnXInputSetState( nullptr ), pfnXInputGetCapabilities( nullptr )
{
}

XInput::XInput(): mVersion( Version_None )
{
}

XInput::InitReturn XInput::initialize()
{
mModule = LoadLibraryW( L"xinput1_4.dll" );
if ( mModule )
mVersion = Version_14;
else
{
mModule = LoadLibraryW( L"xinput1_3.dll" );
if ( mModule )
mVersion = Version_13;
else
{
mModule = LoadLibraryW( L"xinput9_1_0.dll" );
if ( mModule )
mVersion = Version_910;
else
return Initialization_ModuleNotFound;
}
}

NIL_LOAD_EXTERNAL_FUNC( XInputGetState );
NIL_LOAD_EXTERNAL_FUNC( XInputSetState );
NIL_LOAD_EXTERNAL_FUNC( XInputGetCapabilities );

if ( !mFunctions.pfnXInputGetState
|| !mFunctions.pfnXInputSetState
|| !mFunctions.pfnXInputGetCapabilities )
return Initialization_MissingExports;

mInitialized = true;

return Initialization_OK;
}

void XInput::shutdown()
{
if ( mModule )
{
FreeLibrary( mModule );
mModule = NULL;
}
mInitialized = false;
}

XInput::~XInput()
{
shutdown();
}

}
2 changes: 1 addition & 1 deletion src/XInputController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ namespace Nil {
{
XInputDevice* xDevice = dynamic_cast<XInputDevice*>( mDevice );

DWORD ret = XInputGetState( xDevice->getXInputID(), &mXInputState );
DWORD ret = mSystem->getXInput()->mFunctions.pfnXInputGetState( xDevice->getXInputID(), &mXInputState );
if ( ret == ERROR_DEVICE_NOT_CONNECTED )
{
xDevice->flagDisconnected();
Expand Down
2 changes: 1 addition & 1 deletion src/XInputDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace Nil {

void XInputDevice::identify()
{
if ( XInputGetCapabilities( mXInputID, 0, &mCapabilities ) != ERROR_SUCCESS )
if ( mSystem->getXInput()->mFunctions.pfnXInputGetCapabilities( mXInputID, 0, &mCapabilities ) != ERROR_SUCCESS )
return;

for ( int i = 0; i < cMaxXInputModels; i++ ) {
Expand Down

0 comments on commit 54a359e

Please sign in to comment.