Dynamically load xinput

This commit is contained in:
Brad Hughes 2016-03-01 11:08:05 -05:00
parent 3b0d8b1efb
commit 630edadf9c
2 changed files with 141 additions and 5 deletions

View File

@ -46,7 +46,6 @@ function maintargetosdoptions(_target,_subtarget)
"comctl32",
"comdlg32",
"psapi",
"xinput",
}
end

View File

@ -116,6 +116,107 @@ struct xinput_api_state
XINPUT_CAPABILITIES caps;
};
// Typedef for pointers to XInput Functions
typedef DWORD(__stdcall* PFN_XINPUTGETSTATE)(DWORD, XINPUT_STATE*);
typedef DWORD(__stdcall* PFN_XINPUTGETCAPS)(DWORD, DWORD, XINPUT_CAPABILITIES*);
class xinput_interface
{
private:
HMODULE m_xinput_module;
PFN_XINPUTGETSTATE m_pfnXInputGetState;
PFN_XINPUTGETCAPS m_pfnXInputGetCapabilities;
bool m_initialized;
xinput_interface()
: m_xinput_module(NULL),
m_pfnXInputGetState(nullptr),
m_pfnXInputGetCapabilities(nullptr),
m_initialized(false)
{
}
int initialize()
{
if (m_initialized)
return 0;
m_xinput_module = load_xinput_library();
if (m_xinput_module == NULL)
{
osd_printf_error("Failed to load xinput library. Error: %u\n", (unsigned int)GetLastError());
return -1;
}
if (load_xinput_exports() != 0)
{
osd_printf_error("Failed to load exported XInput functions from library\n");
return -1;
}
m_initialized = true;
return 0;
}
DWORD load_xinput_exports()
{
m_pfnXInputGetState = (PFN_XINPUTGETSTATE)GetProcAddress(m_xinput_module, "XInputGetState");
m_pfnXInputGetCapabilities = (PFN_XINPUTGETCAPS)GetProcAddress(m_xinput_module, "XInputGetCapabilities");
if (m_pfnXInputGetState == nullptr
|| m_pfnXInputGetCapabilities == nullptr)
{
return ERROR_NOT_FOUND;
}
return 0;
}
static HMODULE load_xinput_library()
{
// Attempt to load the Windows 8/10 version of Xinput first
HMODULE module = LoadLibrary(L"xinput1_4.dll");
// Fall back to the one from DX SDK
if (module == NULL)
{
module = LoadLibrary(L"xinput9_1_0.dll");
}
// If we still didn't load it, fail
if (module == NULL)
{
osd_printf_warning("Could not load any verions of the XInput Library.\n");
SetLastError(ERROR_DLL_NOT_FOUND);
}
return module;
}
public:
inline DWORD XInputGetState(DWORD dwUserIndex, XINPUT_STATE* pState)
{
return m_pfnXInputGetState(dwUserIndex, pState);
}
inline DWORD XInputGetCapabilities(DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
{
return m_pfnXInputGetCapabilities(dwUserIndex, dwFlags, pCapabilities);
}
static DWORD get_interface(xinput_interface **ppinterface)
{
static xinput_interface s_instance;
DWORD error = s_instance.initialize();
if (error == 0)
{
*ppinterface = &s_instance;
}
return error;
}
};
//============================================================
// xinput_joystick_device
//============================================================
@ -126,17 +227,28 @@ public:
gamepad_state gamepad;
xinput_api_state xinput_state;
private:
xinput_interface* xinput_api;
public:
xinput_joystick_device(running_machine &machine, const char *name, input_module &module)
: device_info(machine, name, DEVICE_CLASS_JOYSTICK, module),
gamepad({0}),
xinput_state({0})
{
// Attempt to get the xinput interface
xinput_api = nullptr;
xinput_interface::get_interface(&xinput_api);
}
void poll() override
{
// Nothing we can do if for some reason the API couldn't be loaded
if (xinput_api == nullptr)
return;
// poll the device first
HRESULT result = XInputGetState(xinput_state.playerIndex, &xinput_state.xstate);
HRESULT result = xinput_api->XInputGetState(xinput_state.playerIndex, &xinput_state.xstate);
// If we can't poll the device, skip
if (FAILED(result))
@ -182,15 +294,40 @@ public:
class xinput_joystick_module : public wininput_module
{
private:
xinput_interface* xinput_api;
public:
xinput_joystick_module()
: wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput")
: wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput"),
xinput_api(nullptr)
{
}
int init(const osd_options &options) override
{
// Call the base
int status = wininput_module::init(options);
if (status != 0)
return status;
// Make sure we can get the xinput API
status = xinput_interface::get_interface(&xinput_api);
if (status != 0)
{
osd_printf_error("xinput_joystick_module failed to get XInput interface! Error: %u\n", (unsigned int)status);
return -1;
}
return 0;
}
protected:
virtual void input_init(running_machine &machine) override
{
// The Xinput API should have been obtained already
assert(xinput_api != nullptr);
xinput_joystick_device *devinfo;
// Loop through each gamepad to determine if they are connected
@ -198,7 +335,7 @@ protected:
{
XINPUT_STATE state = {0};
if (XInputGetState(i, &state) == ERROR_SUCCESS)
if (xinput_api->XInputGetState(i, &state) == ERROR_SUCCESS)
{
// allocate and link in a new device
devinfo = create_xinput_device(machine, i);
@ -261,7 +398,7 @@ protected:
xinput_joystick_device *devinfo;
XINPUT_CAPABILITIES caps = {0};
if (FAILED(XInputGetCapabilities(index, 0, &caps)))
if (FAILED(xinput_api->XInputGetCapabilities(index, 0, &caps)))
{
// If we can't get the capabilities skip this device
return nullptr;