summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_xinput.cpp
diff options
context:
space:
mode:
author Brad Hughes <bradhugh@outlook.com>2016-03-01 11:08:05 -0500
committer Brad Hughes <bradhugh@outlook.com>2016-03-01 11:08:05 -0500
commit630edadf9c351c5e1a4b36ea78167653848bd0fd (patch)
treeb512e78218145bdf16b591041b66483eb3ad6768 /src/osd/modules/input/input_xinput.cpp
parent3b0d8b1efb51663a55140d0b743f9d1b19c86d7b (diff)
Dynamically load xinput
Diffstat (limited to 'src/osd/modules/input/input_xinput.cpp')
-rw-r--r--src/osd/modules/input/input_xinput.cpp145
1 files changed, 141 insertions, 4 deletions
diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp
index 292f9ee5d35..588ac0a9e5f 100644
--- a/src/osd/modules/input/input_xinput.cpp
+++ b/src/osd/modules/input/input_xinput.cpp
@@ -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;