summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/osd/modules/input/input_common.h28
-rw-r--r--src/osd/modules/input/input_dinput.cpp572
-rw-r--r--src/osd/modules/input/input_dinput.h177
-rw-r--r--src/osd/modules/input/input_winhybrid.cpp372
-rw-r--r--src/osd/modules/input/input_xinput.cpp406
-rw-r--r--src/osd/modules/input/input_xinput.h140
-rw-r--r--src/osd/modules/lib/osdobj_common.cpp1
7 files changed, 1117 insertions, 579 deletions
diff --git a/src/osd/modules/input/input_common.h b/src/osd/modules/input/input_common.h
index 7ea001dad4f..41a9d762838 100644
--- a/src/osd/modules/input/input_common.h
+++ b/src/osd/modules/input/input_common.h
@@ -352,19 +352,35 @@ public:
// allocate the device object
auto devinfo = std::make_unique<TActual>(machine, name, module);
- // Add the device to the machine
- devinfo->m_device = machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo.get());
+ return add_device_internal(machine, name, module, std::move(devinfo));
+ }
- // append us to the list
- m_list.push_back(std::move(devinfo));
+ template <typename TActual, typename TArg>
+ TActual* create_device1(running_machine &machine, const char *name, input_module &module, TArg arg1)
+ {
+ // allocate the device object
+ auto devinfo = std::make_unique<TActual>(machine, name, module, arg1);
- return (TActual*)m_list.back().get();
+ return add_device_internal(machine, name, module, std::move(devinfo));
}
template <class TActual>
TActual* at(int index)
{
- return (TActual*)m_list.at(index).get();
+ return static_cast<TActual*>(m_list.at(index).get());
+ }
+
+private:
+ template <typename TActual>
+ TActual* add_device_internal(running_machine &machine, const char *name, input_module &module, std::unique_ptr<TActual> allocated)
+ {
+ // Add the device to the machine
+ allocated->m_device = machine.input().device_class(allocated->deviceclass()).add_device(allocated->name(), allocated.get());
+
+ // append us to the list
+ m_list.push_back(std::move(allocated));
+
+ return static_cast<TActual*>(m_list.back().get());
}
};
diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp
index 1e4272e6317..ca3bad08026 100644
--- a/src/osd/modules/input/input_dinput.cpp
+++ b/src/osd/modules/input/input_dinput.cpp
@@ -14,6 +14,7 @@
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+#include <initguid.h>
#include <tchar.h>
#include <wrl/client.h>
@@ -31,17 +32,15 @@
#include "strconv.h"
// MAMEOS headers
-#include "winmain.h"
#include "window.h"
#include "winutil.h"
#include "input_common.h"
#include "input_windows.h"
+#include "input_dinput.h"
using namespace Microsoft::WRL;
-#define STRUCTSIZE(x) (m_dinput_version == 0x0300) ? sizeof(x##_DX3) : sizeof(x)
-
static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal);
//============================================================
@@ -58,255 +57,184 @@ static HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice> device, REFG
dipdw.diph.dwHow = how;
dipdw.dwData = value;
- return IDirectInputDevice_SetProperty(device.Get(), property_guid, &dipdw.diph);
+ return device->SetProperty(property_guid, &dipdw.diph);
}
//============================================================
// dinput_device - base directinput device
//============================================================
-// DirectInput-specific information about a device
-struct dinput_api_state
+dinput_device::dinput_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
+ : device_info(machine, name, deviceclass, module),
+ dinput({nullptr})
{
- ComPtr<IDirectInputDevice> device;
- ComPtr<IDirectInputDevice2> device2;
- DIDEVCAPS caps;
- LPCDIDATAFORMAT format;
-};
+}
-class dinput_device : public device_info
+dinput_device::~dinput_device()
{
-public:
- dinput_api_state dinput;
+ if (dinput.device != nullptr)
+ dinput.device.Reset();
+}
- dinput_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
- : device_info(machine, name, deviceclass, module),
- dinput({nullptr})
- {
- }
+HRESULT dinput_device::poll_dinput(LPVOID pState) const
+{
+ HRESULT result;
- virtual ~dinput_device()
- {
- if (dinput.device2 != nullptr)
- dinput.device2.Reset();
+ // first poll the device, then get the state
+ if (dinput.device2 != nullptr)
+ dinput.device2->Poll();
- if (dinput.device != nullptr)
- dinput.device.Reset();
- }
+ // GetDeviceState returns the immediate state
+ result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
-protected:
- HRESULT poll_dinput(LPVOID pState) const
+ // handle lost inputs here
+ if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
{
- HRESULT result;
-
- // first poll the device, then get the state
- if (dinput.device2 != nullptr)
- IDirectInputDevice2_Poll(dinput.device2.Get());
-
- // GetDeviceState returns the immediate state
- result = IDirectInputDevice_GetDeviceState(dinput.device.Get(), dinput.format->dwDataSize, pState);
-
- // handle lost inputs here
- if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
- {
- result = IDirectInputDevice_Acquire(dinput.device.Get());
- if (result == DI_OK)
- result = IDirectInputDevice_GetDeviceState(dinput.device.Get(), dinput.format->dwDataSize, pState);
- }
-
- return result;
+ result = dinput.device->Acquire();
+ if (result == DI_OK)
+ result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
}
-};
+
+ return result;
+}
//============================================================
// dinput_keyboard_device - directinput keyboard device
//============================================================
-class dinput_keyboard_device : public dinput_device
+dinput_keyboard_device::dinput_keyboard_device(running_machine &machine, const char *name, input_module &module)
+ : dinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
+ keyboard({{0}})
{
-private:
- std::mutex m_device_lock;
-
-public:
- keyboard_state keyboard;
-
- dinput_keyboard_device(running_machine &machine, const char *name, input_module &module)
- : dinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
- {
- }
+}
- // Polls the direct input immediate state
- void poll() override
- {
- std::lock_guard<std::mutex> scope_lock(m_device_lock);
+// Polls the direct input immediate state
+void dinput_keyboard_device::poll()
+{
+ std::lock_guard<std::mutex> scope_lock(m_device_lock);
- // Poll the state
- dinput_device::poll_dinput(&keyboard.state);
- }
+ // Poll the state
+ dinput_device::poll_dinput(&keyboard.state);
+}
- void reset() override
- {
- memset(&keyboard.state, 0, sizeof(keyboard.state));
- }
-};
+void dinput_keyboard_device::reset()
+{
+ memset(&keyboard.state, 0, sizeof(keyboard.state));
+}
//============================================================
-// dinput_module - base directinput module
+// dinput_api_helper - DirectInput API helper
//============================================================
-class dinput_module : public wininput_module
+dinput_api_helper::dinput_api_helper(int version)
+ : m_dinput(nullptr),
+ m_dinput_version(version),
+ m_pfn_DirectInputCreate("DirectInputCreateW", L"dinput.dll")
{
-private:
- ComPtr<IDirectInput> m_dinput;
- int m_dinput_version;
+}
-public:
- dinput_module(const char* type, const char* name)
- : wininput_module(type, name),
- m_dinput(nullptr),
- m_dinput_version(0)
- {
- }
+dinput_api_helper::~dinput_api_helper()
+{
+ m_dinput.Reset();
+}
- int init_internal() override
- {
- HRESULT result;
+int dinput_api_helper::initialize()
+{
+ HRESULT result;
-#if DIRECTINPUT_VERSION >= 0x800
- m_dinput_version = DIRECTINPUT_VERSION;
+ if (m_dinput_version >= 0x0800)
+ {
result = DirectInput8Create(GetModuleHandleUni(), m_dinput_version, IID_IDirectInput8, reinterpret_cast<void **>(m_dinput.GetAddressOf()), nullptr);
if (result != DI_OK)
{
m_dinput_version = 0;
return result;
}
-#else
- // first attempt to initialize DirectInput at the current version
- m_dinput_version = DIRECTINPUT_VERSION;
- result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
+ }
+ else
+ {
+ result = m_pfn_DirectInputCreate.initialize();
+ if (result != DI_OK)
+ return result;
+
+ // first attempt to initialize DirectInput at v7
+ m_dinput_version = 0x0700;
+ result = m_pfn_DirectInputCreate(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
if (result != DI_OK)
{
// if that fails, try version 5
m_dinput_version = 0x0500;
- result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
+ result = m_pfn_DirectInputCreate(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
if (result != DI_OK)
{
- // if that fails, try version 3
- m_dinput_version = 0x0300;
- result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
- if (result != DI_OK)
- {
- m_dinput_version = 0;
- return result;
- }
+ m_dinput_version = 0;
+ return result;
}
}
-#endif
-
- osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
- return 0;
}
- void exit() override
- {
- m_dinput.Reset();
- wininput_module::exit();
- }
+ osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
+ return 0;
+}
- virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
- struct dinput_callback_context
- {
- dinput_module * self;
- running_machine * machine;
- };
+HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const
+{
+ device_enum_interface::dinput_callback_context ctx;
+ ctx.self = enumerate_interface;
+ ctx.state = state;
- static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
- {
- auto context = static_cast<dinput_callback_context*>(ref);
- return context->self->device_enum_callback(instance, context->machine);
- }
+ return m_dinput->EnumDevices(devclass, device_enum_interface::enum_callback, &ctx, DIEDFL_ATTACHEDONLY);
+}
- void input_init(running_machine &machine) override
- {
- dinput_callback_context context = { this, &machine };
- HRESULT result = IDirectInput_EnumDevices(m_dinput.Get(), dinput_devclass(), enum_callback, &context, DIEDFL_ATTACHEDONLY);
- if (result != DI_OK)
- fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", static_cast<UINT32>(result));
- }
+//============================================================
+// dinput_module - base directinput module
+//============================================================
+class dinput_module : public wininput_module, public device_enum_interface
+{
protected:
- virtual int dinput_devclass() = 0;
+ std::unique_ptr<dinput_api_helper> m_dinput_helper;
- template <class TDevice>
- TDevice* create_dinput_device(
- running_machine &machine,
- LPCDIDEVICEINSTANCE instance,
- LPCDIDATAFORMAT format1,
- LPCDIDATAFORMAT format2,
- DWORD cooperative_level)
+public:
+ dinput_module(const char* type, const char* name)
+ : wininput_module(type, name),
+ m_dinput_helper(nullptr)
{
- HRESULT result;
-
- // convert instance name to utf8
- auto osd_deleter = [](void *ptr) { osd_free(ptr); };
- auto utf8_instance_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(instance->tszInstanceName), osd_deleter);
-
- // allocate memory for the device object
- TDevice* devinfo = devicelist()->create_device<TDevice>(machine, utf8_instance_name.get(), *this);
-
- // attempt to create a device
- result = IDirectInput_CreateDevice(m_dinput.Get(), WRAP_REFIID(instance->guidInstance), devinfo->dinput.device.GetAddressOf(), NULL);
- if (result != DI_OK)
- goto error;
+ }
- // try to get a version 2 device for it
- result = IDirectInputDevice_QueryInterface(devinfo->dinput.device.Get(), WRAP_REFIID(IID_IDirectInputDevice2), reinterpret_cast<void **>(devinfo->dinput.device2.GetAddressOf()));
- if (result != DI_OK)
- devinfo->dinput.device2 = nullptr;
+ int init_internal() override
+ {
+ m_dinput_helper = std::make_unique<dinput_api_helper>(DIRECTINPUT_VERSION);
+ int result = m_dinput_helper->initialize();
+ if (result != 0)
+ return result;
- // get the caps
- devinfo->dinput.caps.dwSize = STRUCTSIZE(DIDEVCAPS);
- result = IDirectInputDevice_GetCapabilities(devinfo->dinput.device.Get(), &devinfo->dinput.caps);
- if (result != DI_OK)
- goto error;
+ return 0;
+ }
- // attempt to set the data format
- devinfo->dinput.format = format1;
- result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device.Get(), devinfo->dinput.format);
- if (result != DI_OK)
- {
- // use the secondary format if available
- if (format2 != nullptr)
- {
- devinfo->dinput.format = format2;
- result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device.Get(), devinfo->dinput.format);
- }
- if (result != DI_OK)
- goto error;
- }
+ void exit() override
+ {
+ wininput_module::exit();
+ m_dinput_helper.reset();
+ }
- // set the cooperative level
- result = IDirectInputDevice_SetCooperativeLevel(devinfo->dinput.device.Get(), win_window_list->m_hwnd, cooperative_level);
+ void input_init(running_machine &machine) override
+ {
+ HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), this, &machine);
if (result != DI_OK)
- goto error;
- return devinfo;
-
- error:
- devicelist()->free_device(devinfo);
- return nullptr;
+ fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", static_cast<UINT32>(result));
}
- std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix) const
+ static std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix)
{
DIDEVICEOBJECTINSTANCE instance = { 0 };
HRESULT result;
// query the key name
- instance.dwSize = STRUCTSIZE(DIDEVICEOBJECTINSTANCE);
- result = IDirectInputDevice_GetObjectInfo(devinfo->dinput.device.Get(), &instance, offset, DIPH_BYOFFSET);
+ instance.dwSize = sizeof(instance);
+ result = devinfo->dinput.device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
// if we got an error and have no default string, just return NULL
if (result != DI_OK)
@@ -342,6 +270,9 @@ protected:
return std::string(combined.get());
}
+
+protected:
+ virtual int dinput_devclass() = 0;
};
class keyboard_input_dinput : public dinput_module
@@ -368,7 +299,7 @@ public:
int keynum;
// allocate and link in a new device
- devinfo = create_dinput_device<dinput_keyboard_device>(machine, instance, &c_dfDIKeyboard, nullptr, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
+ devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(machine, *this, instance, &c_dfDIKeyboard, nullptr, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (devinfo == nullptr)
goto exit;
@@ -392,33 +323,28 @@ public:
}
};
-class dinput_mouse_device : public dinput_device
-{
-public:
- mouse_state mouse;
- dinput_mouse_device(running_machine &machine, const char *name, input_module &module)
- : dinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
- mouse({0})
- {
- }
+dinput_mouse_device::dinput_mouse_device(running_machine &machine, const char *name, input_module &module)
+ : dinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
+ mouse({0})
+{
+}
- void poll() override
- {
- // poll
- dinput_device::poll_dinput(&mouse);
+void dinput_mouse_device::poll()
+{
+ // poll
+ dinput_device::poll_dinput(&mouse);
- // scale the axis data
- mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
- mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
- mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
- }
+ // scale the axis data
+ mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
+ mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
+ mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
+}
- void reset() override
- {
- memset(&mouse, 0, sizeof(mouse));
- }
-};
+void dinput_mouse_device::reset()
+{
+ memset(&mouse, 0, sizeof(mouse));
+}
class mouse_input_dinput : public dinput_module
{
@@ -445,7 +371,7 @@ public:
HRESULT result;
// allocate and link in a new device
- devinfo = create_dinput_device<dinput_mouse_device>(machine, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
+ devinfo = m_dinput_helper->create_device<dinput_mouse_device>(machine, *this, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (devinfo == nullptr)
goto exit;
@@ -489,46 +415,130 @@ public:
}
};
-// state information for a joystick; DirectInput state must be first element
-struct dinput_joystick_state
+dinput_joystick_device::dinput_joystick_device(running_machine &machine, const char *name, input_module &module)
+ : dinput_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
+ joystick({{0}})
{
- DIJOYSTATE state;
- LONG rangemin[8];
- LONG rangemax[8];
-};
+}
-class dinput_joystick_device : public dinput_device
+void dinput_joystick_device::reset()
{
-public:
- dinput_joystick_state joystick;
+ memset(&joystick.state, 0, sizeof(joystick.state));
+}
+
+void dinput_joystick_device::poll()
+{
+ int axisnum;
+
+ // poll the device first
+ if (dinput_device::poll_dinput(&joystick.state) != ERROR_SUCCESS)
+ return;
+
+ // normalize axis values
+ for (axisnum = 0; axisnum < 8; axisnum++)
+ {
+ LONG *axis = (&joystick.state.lX) + axisnum;
+ *axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
+ }
+}
+
+int dinput_joystick_device::configure()
+{
+ HRESULT result;
+ UINT32 axisnum, axiscount;
+
+ auto devicelist = static_cast<input_module_base&>(module()).devicelist();
+
+ // temporary approximation of index
+ int devindex = devicelist->size();
+
+ // set absolute mode
+ result = dinput_set_dword_property(dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_ABS);
+ if (result != DI_OK && result != DI_PROPNOEFFECT)
+ osd_printf_warning("DirectInput: Unable to set absolute mode for joystick %d (%s)\n", devindex, name());
+
+ // turn off deadzone; we do our own calculations
+ result = dinput_set_dword_property(dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
+ if (result != DI_OK && result != DI_PROPNOEFFECT)
+ osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %d (%s)\n", devindex, name());
- dinput_joystick_device(running_machine &machine, const char *name, input_module &module)
- : dinput_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}})
+ // turn off saturation; we do our own calculations
+ result = dinput_set_dword_property(dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
+ if (result != DI_OK && result != DI_PROPNOEFFECT)
+ osd_printf_warning("DirectInput: Unable to reset saturation for joystick %d (%s)\n", devindex, name());
+
+ // cap the number of axes, POVs, and buttons based on the format
+ dinput.caps.dwAxes = MIN(dinput.caps.dwAxes, 8);
+ dinput.caps.dwPOVs = MIN(dinput.caps.dwPOVs, 4);
+ dinput.caps.dwButtons = MIN(dinput.caps.dwButtons, 128);
+
+ // populate the axes
+ for (axisnum = axiscount = 0; axiscount < dinput.caps.dwAxes && axisnum < 8; axisnum++)
{
+ DIPROPRANGE dipr;
+ std::string name;
+
+ // fetch the range of this axis
+ dipr.diph.dwSize = sizeof(dipr);
+ dipr.diph.dwHeaderSize = sizeof(dipr.diph);
+ dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
+ dipr.diph.dwHow = DIPH_BYOFFSET;
+ result = dinput.device->GetProperty(DIPROP_RANGE, &dipr.diph);
+ if (result != DI_OK)
+ continue;
+
+ joystick.rangemin[axisnum] = dipr.lMin;
+ joystick.rangemax[axisnum] = dipr.lMax;
+
+ // populate the item description as well
+ name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr);
+ device()->add_item(name.c_str(), static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &joystick.state.lX + axisnum);
+
+ axiscount++;
}
- void reset() override
+ // populate the POVs
+ for (UINT32 povnum = 0; povnum < dinput.caps.dwPOVs; povnum++)
{
- memset(&joystick.state, 0, sizeof(joystick.state));
+ std::string name;
+
+ // left
+ name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L"));
+ device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_LEFT)));
+
+ // right
+ name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R"));
+ device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_RIGHT)));
+
+ // up
+ name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U"));
+ device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_UP)));
+
+ // down
+ name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D"));
+ device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_DOWN)));
}
- void poll() override
+ // populate the buttons
+ for (UINT32 butnum = 0; butnum < dinput.caps.dwButtons; butnum++)
{
- int axisnum;
+ FPTR offset = reinterpret_cast<FPTR>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
+ std::string name = dinput_module::device_item_name(this, offset, default_button_name(butnum), nullptr);
- // poll the device first
- if (dinput_device::poll_dinput(&joystick.state) != ERROR_SUCCESS)
- return;
+ input_item_id itemid;
- // normalize axis values
- for (axisnum = 0; axisnum < 8; axisnum++)
- {
- LONG *axis = (&joystick.state.lX) + axisnum;
- *axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
- }
+ if (butnum < INPUT_MAX_BUTTONS)
+ itemid = static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum);
+ else if (butnum < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
+ itemid = static_cast<input_item_id>(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
+ else
+ itemid = ITEM_ID_OTHER_SWITCH;
+
+ device()->add_item(name.c_str(), itemid, generic_button_get_state, &joystick.state.rgbButtons[butnum]);
}
-};
+
+ return 0;
+}
class joystick_input_dinput : public dinput_module
{
@@ -550,102 +560,22 @@ public:
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
{
DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
- int axisnum, axiscount, povnum, butnum;
running_machine &machine = *static_cast<running_machine *>(ref);
dinput_joystick_device *devinfo;
- HRESULT result;
+ int result = 0;
- if (win_window_list != nullptr && win_window_list->win_has_menu()) {
+ if (win_window_list != nullptr && win_window_list->win_has_menu())
cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
- }
+
// allocate and link in a new device
- devinfo = create_dinput_device<dinput_joystick_device>(machine, instance, &c_dfDIJoystick, nullptr, cooperative_level);
+ devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);
if (devinfo == nullptr)
goto exit;
- // set absolute mode
- result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_ABS);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- osd_printf_warning("DirectInput: Unable to set absolute mode for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
-
- // turn off deadzone; we do our own calculations
- result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
-
- // turn off saturation; we do our own calculations
- result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- osd_printf_warning("DirectInput: Unable to reset saturation for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
-
- // cap the number of axes, POVs, and buttons based on the format
- devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 8);
- devinfo->dinput.caps.dwPOVs = MIN(devinfo->dinput.caps.dwPOVs, 4);
- devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, 128);
-
- // populate the axes
- for (axisnum = axiscount = 0; axiscount < devinfo->dinput.caps.dwAxes && axisnum < 8; axisnum++)
+ result = devinfo->configure();
+ if (result != 0)
{
- DIPROPRANGE dipr;
- std::string name;
-
- // fetch the range of this axis
- dipr.diph.dwSize = sizeof(dipr);
- dipr.diph.dwHeaderSize = sizeof(dipr.diph);
- dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
- dipr.diph.dwHow = DIPH_BYOFFSET;
- result = IDirectInputDevice_GetProperty(devinfo->dinput.device.Get(), DIPROP_RANGE, &dipr.diph);
- if (result != DI_OK)
- continue;
-
- devinfo->joystick.rangemin[axisnum] = dipr.lMin;
- devinfo->joystick.rangemax[axisnum] = dipr.lMax;
-
- // populate the item description as well
- name = device_item_name(devinfo, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr);
- devinfo->device()->add_item(name.c_str(), static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->joystick.state.lX + axisnum);
-
- axiscount++;
- }
-
- // populate the POVs
- for (povnum = 0; povnum < devinfo->dinput.caps.dwPOVs; povnum++)
- {
- std::string name;
-
- // left
- name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L"));
- devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_LEFT)));
-
- // right
- name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R"));
- devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_RIGHT)));
-
- // up
- name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U"));
- devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_UP)));
-
- // down
- name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D"));
- devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, reinterpret_cast<void *>(static_cast<FPTR>(povnum * 4 + POVDIR_DOWN)));
- }
-
- // populate the buttons
- for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
- {
- FPTR offset = reinterpret_cast<FPTR>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
- std::string name = device_item_name(devinfo, offset, default_button_name(butnum), nullptr);
-
- input_item_id itemid;
-
- if (butnum < INPUT_MAX_BUTTONS)
- itemid = static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum);
- else if (butnum < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
- itemid = static_cast<input_item_id>(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
- else
- itemid = ITEM_ID_OTHER_SWITCH;
-
- devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->joystick.state.rgbButtons[butnum]);
+ osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
}
exit:
diff --git a/src/osd/modules/input/input_dinput.h b/src/osd/modules/input/input_dinput.h
new file mode 100644
index 00000000000..6dacf8ebd77
--- /dev/null
+++ b/src/osd/modules/input/input_dinput.h
@@ -0,0 +1,177 @@
+#ifndef INPUT_DINPUT_H_
+#define INPUT_DINPUT_H_
+
+#include "input_common.h"
+#include "winutil.h"
+
+//============================================================
+// dinput_device - base directinput device
+//============================================================
+
+// DirectInput-specific information about a device
+struct dinput_api_state
+{
+ Microsoft::WRL::ComPtr<IDirectInputDevice> device;
+ Microsoft::WRL::ComPtr<IDirectInputDevice2> device2;
+ DIDEVCAPS caps;
+ LPCDIDATAFORMAT format;
+};
+
+class device_enum_interface
+{
+public:
+ struct dinput_callback_context
+ {
+ device_enum_interface * self;
+ void * state;
+ };
+
+ virtual ~device_enum_interface()
+ {
+ }
+
+ static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
+ {
+ auto context = static_cast<dinput_callback_context*>(ref);
+ return context->self->device_enum_callback(instance, context->state);
+ }
+
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
+};
+
+typedef lazy_loaded_function_p4<HRESULT, HMODULE, int, IDirectInput **, LPUNKNOWN> pfn_dinput_create;
+
+class dinput_api_helper
+{
+private:
+ Microsoft::WRL::ComPtr<IDirectInput> m_dinput;
+ int m_dinput_version;
+ pfn_dinput_create m_pfn_DirectInputCreate;
+
+public:
+ dinput_api_helper(int version);
+ virtual ~dinput_api_helper();
+ int initialize();
+
+ template<class TDevice>
+ TDevice* create_device(
+ running_machine &machine,
+ input_module_base &module,
+ LPCDIDEVICEINSTANCE instance,
+ LPCDIDATAFORMAT format1,
+ LPCDIDATAFORMAT format2,
+ DWORD cooperative_level)
+ {
+ HRESULT result;
+
+ // convert instance name to utf8
+ auto osd_deleter = [](void *ptr) { osd_free(ptr); };
+ auto utf8_instance_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(instance->tszInstanceName), osd_deleter);
+
+ // allocate memory for the device object
+ TDevice* devinfo = module.devicelist()->create_device<TDevice>(machine, utf8_instance_name.get(), module);
+
+ // attempt to create a device
+ result = m_dinput->CreateDevice(instance->guidInstance, devinfo->dinput.device.GetAddressOf(), nullptr);
+ if (result != DI_OK)
+ goto error;
+
+ // try to get a version 2 device for it
+ result = devinfo->dinput.device.CopyTo(IID_IDirectInputDevice2, reinterpret_cast<void**>(devinfo->dinput.device2.GetAddressOf()));
+ if (result != DI_OK)
+ devinfo->dinput.device2 = nullptr;
+
+ // get the caps
+ devinfo->dinput.caps.dwSize = sizeof(devinfo->dinput.caps);
+ result = devinfo->dinput.device->GetCapabilities(&devinfo->dinput.caps);
+ if (result != DI_OK)
+ goto error;
+
+ // attempt to set the data format
+ devinfo->dinput.format = format1;
+ result = devinfo->dinput.device->SetDataFormat(devinfo->dinput.format);
+ if (result != DI_OK)
+ {
+ // use the secondary format if available
+ if (format2 != nullptr)
+ {
+ devinfo->dinput.format = format2;
+ result = devinfo->dinput.device->SetDataFormat(devinfo->dinput.format);
+ }
+ if (result != DI_OK)
+ goto error;
+ }
+
+ // set the cooperative level
+ result = devinfo->dinput.device->SetCooperativeLevel(win_window_list->m_hwnd, cooperative_level);
+ if (result != DI_OK)
+ goto error;
+
+ return devinfo;
+
+ error:
+ module.devicelist()->free_device(devinfo);
+ return nullptr;
+ }
+
+ HRESULT enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const;
+};
+
+class dinput_device : public device_info
+{
+public:
+ dinput_api_state dinput;
+
+ dinput_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module);
+ virtual ~dinput_device();
+
+protected:
+ HRESULT poll_dinput(LPVOID pState) const;
+};
+
+class dinput_keyboard_device : public dinput_device
+{
+private:
+ std::mutex m_device_lock;
+
+public:
+ keyboard_state keyboard;
+
+ dinput_keyboard_device(running_machine &machine, const char *name, input_module &module);
+
+ void poll() override;
+ void reset() override;
+};
+
+class dinput_mouse_device : public dinput_device
+{
+public:
+ mouse_state mouse;
+
+public:
+ dinput_mouse_device(running_machine &machine, const char *name, input_module &module);
+ void poll() override;
+ void reset() override;
+};
+
+// state information for a joystick; DirectInput state must be first element
+struct dinput_joystick_state
+{
+ DIJOYSTATE state;
+ LONG rangemin[8];
+ LONG rangemax[8];
+};
+
+class dinput_joystick_device : public dinput_device
+{
+public:
+ dinput_joystick_state joystick;
+public:
+ dinput_joystick_device(running_machine &machine, const char *name, input_module &module);
+ void reset() override;
+ void poll() override;
+ int configure();
+};
+
+
+#endif
diff --git a/src/osd/modules/input/input_winhybrid.cpp b/src/osd/modules/input/input_winhybrid.cpp
new file mode 100644
index 00000000000..cf0f095cdfc
--- /dev/null
+++ b/src/osd/modules/input/input_winhybrid.cpp
@@ -0,0 +1,372 @@
+// license:BSD-3-Clause
+// copyright-holders:Brad Hughes
+//============================================================
+//
+// input_winhybrid.cpp - Windows hybrid DirectInput/Xinput
+//
+//============================================================
+
+#include "input_module.h"
+#include "modules/osdmodule.h"
+#include <wbemcli.h>
+
+#if defined(OSD_WINDOWS)
+
+#include <list>
+
+// standard windows headers
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wrl/client.h>
+
+// XInput/DirectInput
+#include <xinput.h>
+#include <dinput.h>
+
+#undef interface
+
+// MAME headers
+#include "emu.h"
+#include "osdepend.h"
+
+// MAMEOS headers
+#include "strconv.h"
+#include "winutil.h"
+#include "winmain.h"
+
+#include "input_common.h"
+#include "input_windows.h"
+#include "input_xinput.h"
+#include "input_dinput.h"
+
+using namespace Microsoft::WRL;
+
+#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=nullptr; } }
+
+struct bstr_deleter
+{
+ void operator () (BSTR bstr) const
+ {
+ if (bstr != nullptr)
+ SysFreeString(bstr);
+ }
+};
+
+typedef std::unique_ptr<OLECHAR, bstr_deleter> bstr_ptr;
+
+//============================================================
+// winhybrid_joystick_module
+//============================================================
+
+class winhybrid_joystick_module : public wininput_module, public device_enum_interface
+{
+private:
+ std::shared_ptr<xinput_api_helper> m_xinput_helper;
+ std::unique_ptr<dinput_api_helper> m_dinput_helper;
+ std::list<DWORD> m_xinput_deviceids;
+ bool m_xinput_detect_failed;
+
+public:
+ winhybrid_joystick_module()
+ : wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "winhybrid"),
+ m_xinput_helper(nullptr),
+ m_dinput_helper(nullptr),
+ m_xinput_detect_failed(false)
+ {
+ }
+
+ bool probe() override
+ {
+ int status = init_helpers();
+ if (status != 0)
+ {
+ osd_printf_verbose("Hybrid joystick module isn't supported, falling back.\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ int init(const osd_options &options) override
+ {
+ // Call the base
+ int status = wininput_module::init(options);
+ if (status != 0)
+ return status;
+
+ // Create and initialize our helpers
+ status = init_helpers();
+ if (status != 0)
+ return status;
+
+ return 0;
+ }
+
+ BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ {
+ DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
+ running_machine &machine = *static_cast<running_machine *>(ref);
+ dinput_joystick_device *devinfo;
+ int result = 0;
+
+ // First check if this device is XInput Compatible. If so, don't add it here
+ // as it'll be picked up by Xinput
+ if (!m_xinput_detect_failed && is_xinput_device(&instance->guidProduct))
+ {
+ osd_printf_verbose("Skipping DirectInput for XInput compatible joystick %S.\n", instance->tszInstanceName);
+ goto exit;
+ }
+
+ if (win_window_list != nullptr && win_window_list->win_has_menu())
+ cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+
+ // allocate and link in a new device
+ devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);
+ if (devinfo == nullptr)
+ goto exit;
+
+ result = devinfo->configure();
+ if (result != 0)
+ {
+ osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
+ }
+
+ exit:
+ return DIENUM_CONTINUE;
+ }
+
+ void exit() override
+ {
+ m_xinput_helper.reset();
+ m_dinput_helper.reset();
+
+ wininput_module::exit();
+ }
+
+protected:
+ virtual void input_init(running_machine &machine) override
+ {
+ HRESULT result = get_xinput_devices(m_xinput_deviceids);
+ if (result != 0)
+ {
+ m_xinput_detect_failed = true;
+ osd_printf_warning("XInput device detection failed. XInput won't be used. Error: 0x%X\n", static_cast<unsigned int>(result));
+ }
+
+ // Enumerate all the directinput joysticks and add them if they aren't xinput compatible
+ result = m_dinput_helper->enum_attached_devices(DI8DEVCLASS_GAMECTRL, this, &machine);
+ if (result != DI_OK)
+ fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", static_cast<UINT32>(result));
+
+ xinput_joystick_device *devinfo;
+
+ // now add all xinput devices
+ if (!m_xinput_detect_failed)
+ {
+ // Loop through each gamepad to determine if they are connected
+ for (UINT i = 0; i < XUSER_MAX_COUNT; i++)
+ {
+ XINPUT_STATE state = { 0 };
+
+ if (m_xinput_helper->XInputGetState(i, &state) == ERROR_SUCCESS)
+ {
+ // allocate and link in a new device
+ devinfo = m_xinput_helper->create_xinput_device(machine, i, *this);
+ if (devinfo == nullptr)
+ continue;
+
+ // Configure each gamepad to add buttons and Axes, etc.
+ devinfo->configure();
+ }
+ }
+ }
+ }
+
+private:
+ int init_helpers()
+ {
+ int status = 0;
+
+ if (m_xinput_helper == nullptr)
+ {
+ m_xinput_helper = std::make_shared<xinput_api_helper>();
+ status = m_xinput_helper->initialize();
+ if (status != 0)
+ {
+ osd_printf_error("xinput_api_helper failed to initialize! Error: %u\n", static_cast<unsigned int>(status));
+ return -1;
+ }
+ }
+
+ if (m_dinput_helper == nullptr)
+ {
+ m_dinput_helper = std::make_unique<dinput_api_helper>(DIRECTINPUT_VERSION);
+ status = m_dinput_helper->initialize();
+ if (status != DI_OK)
+ {
+ osd_printf_error("dinput_api_helper failed to initialize! Error: %u\n", static_cast<unsigned int>(status));
+ return -1;
+ }
+ }
+
+ return status;
+ }
+
+ //-----------------------------------------------------------------------------
+ // Returns true if the DirectInput device is also an XInput device.
+ //-----------------------------------------------------------------------------
+ bool is_xinput_device(const GUID* pGuidProductFromDirectInput)
+ {
+ // Check each xinput device to see if this device's vid/pid matches
+ for (auto devid = m_xinput_deviceids.begin(); devid != m_xinput_deviceids.end(); ++devid)
+ {
+ if (*devid == pGuidProductFromDirectInput->Data1)
+ return true;
+ }
+
+ return false;
+ }
+
+ //-----------------------------------------------------------------------------
+ // Enum each PNP device using WMI and check each device ID to see if it contains
+ // "IG_" (ex. "VID_045E&PID_028E&IG_00"). If it does, then it’s an XInput device
+ // Unfortunately this information can not be found by just using DirectInput.
+ // Checking against a VID/PID of 0x028E/0x045E won't find 3rd party or future
+ // XInput devices.
+ //-----------------------------------------------------------------------------
+ HRESULT get_xinput_devices(std::list<DWORD> &xinput_id_list) const
+ {
+ ComPtr<IWbemServices> pIWbemServices;
+ ComPtr<IEnumWbemClassObject> pEnumDevices;
+ ComPtr<IWbemLocator> pIWbemLocator;
+ IWbemClassObject* pDevices[20];
+ bstr_ptr bstrDeviceID;
+ bstr_ptr bstrClassName;
+ bstr_ptr bstrNamespace;
+ DWORD uReturned = 0;
+ UINT iDevice = 0;
+ VARIANT var;
+ HRESULT hr;
+
+ // CoInit if needed
+ CoInitialize(nullptr);
+
+ // Create WMI
+ hr = CoCreateInstance(
+ __uuidof(WbemLocator),
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(IWbemLocator),
+ reinterpret_cast<void**>(pIWbemLocator.GetAddressOf()));
+
+ if (FAILED(hr) || pIWbemLocator == nullptr)
+ {
+ osd_printf_error("Creating WbemLocator failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
+ return hr;
+ }
+
+ // Create BSTRs for WMI
+ bstrNamespace = bstr_ptr(SysAllocString(L"\\\\.\\root\\cimv2"));
+ bstrDeviceID = bstr_ptr(SysAllocString(L"DeviceID"));
+ bstrClassName = bstr_ptr(SysAllocString(L"Win32_PNPEntity"));
+
+ // Connect to WMI
+ hr = pIWbemLocator->ConnectServer(
+ bstrNamespace.get(),
+ nullptr,
+ nullptr,
+ nullptr,
+ 0L,
+ nullptr,
+ nullptr,
+ pIWbemServices.GetAddressOf());
+
+ if (FAILED(hr) || pIWbemServices == nullptr)
+ {
+ osd_printf_error("Connecting to WMI Server failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
+ return hr;
+ }
+
+ // Switch security level to IMPERSONATE
+ (void)CoSetProxyBlanket(
+ pIWbemServices.Get(),
+ RPC_C_AUTHN_WINNT,
+ RPC_C_AUTHZ_NONE,
+ nullptr,
+ RPC_C_AUTHN_LEVEL_CALL,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ nullptr,
+ 0);
+
+ // Get list of Win32_PNPEntity devices
+ hr = pIWbemServices->CreateInstanceEnum(bstrClassName.get(), 0, nullptr, pEnumDevices.GetAddressOf());
+ if (FAILED(hr) || pEnumDevices == nullptr)
+ {
+ osd_printf_error("Getting list of Win32_PNPEntity devices failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
+ return hr;
+ }
+
+ // Loop over all devices
+ for (; ; )
+ {
+ // Get 20 at a time
+ hr = pEnumDevices->Next(10000, 20, pDevices, &uReturned);
+ if (FAILED(hr))
+ {
+ osd_printf_error("Enumerating WMI classes failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
+ goto cleanup;;
+ }
+
+ if (uReturned == 0)
+ break;
+
+ for (iDevice = 0; iDevice < uReturned; iDevice++)
+ {
+ if (!pDevices[iDevice])
+ continue;
+
+ // For each device, get its device ID
+ hr = pDevices[iDevice]->Get(bstrDeviceID.get(), 0L, &var, nullptr, nullptr);
+ if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != nullptr)
+ {
+ // Check if the device ID contains "IG_". If it does, then it’s an XInput device
+ // Unfortunately this information can not be found by just using DirectInput
+ if (wcsstr(var.bstrVal, L"IG_"))
+ {
+ // If it does, then get the VID/PID from var.bstrVal
+ DWORD dwPid = 0, dwVid = 0;
+ WCHAR* strVid = wcsstr(var.bstrVal, L"VID_");
+ if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1)
+ dwVid = 0;
+
+ WCHAR* strPid = wcsstr(var.bstrVal, L"PID_");
+ if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1)
+ dwPid = 0;
+
+ DWORD dwVidPid = MAKELONG(dwVid, dwPid);
+
+ // Add the VID/PID to a linked list
+ xinput_id_list.push_back(dwVidPid);
+ }
+ }
+ }
+ }
+
+ cleanup:
+ for (iDevice = 0; iDevice < 20; iDevice++)
+ {
+ SAFE_RELEASE(pDevices[iDevice]);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = S_OK;
+
+ return hr;
+ }
+};
+
+#else
+MODULE_NOT_SUPPORTED(winhybrid_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "winhybrid")
+#endif
+
+MODULE_DEFINITION(JOYSTICKINPUT_WINHYBRID, winhybrid_joystick_module)
diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp
index 8c7800c8c35..753fd49a729 100644
--- a/src/osd/modules/input/input_xinput.cpp
+++ b/src/osd/modules/input/input_xinput.cpp
@@ -23,224 +23,199 @@
// MAME headers
#include "emu.h"
#include "osdepend.h"
-#include "ui/ui.h"
// MAMEOS headers
#include "winutil.h"
#include "winmain.h"
-#include "window.h"
#include "input_common.h"
#include "input_windows.h"
+#include "input_xinput.h"
-#define XINPUT_MAX_POV 4
-#define XINPUT_MAX_BUTTONS 10
-#define XINPUT_MAX_AXIS 4
-#define XINPUT_AXIS_MINVALUE -32767
-#define XINPUT_AXIS_MAXVALUE 32767
-
-// default axis names
-static const char *const xinput_axis_name[] =
+xinput_api_helper::xinput_api_helper()
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ : XInputGetState("XInputGetState", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names))
+ , XInputGetCapabilities("XInputGetCapabilities", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names))
+#endif
{
- "LSX",
- "LSY",
- "RSX",
- "RSY"
-};
+}
-static const input_item_id xinput_axis_ids[] =
+int xinput_api_helper::initialize()
{
- ITEM_ID_XAXIS,
- ITEM_ID_YAXIS,
- ITEM_ID_RXAXIS,
- ITEM_ID_RYAXIS
-};
-
-static const USHORT xinput_pov_dir[] = {
- XINPUT_GAMEPAD_DPAD_UP,
- XINPUT_GAMEPAD_DPAD_DOWN,
- XINPUT_GAMEPAD_DPAD_LEFT,
- XINPUT_GAMEPAD_DPAD_RIGHT
-};
-
-static const char *const xinput_pov_names[] = {
- "DPAD Up",
- "DPAD Down",
- "DPAD Left",
- "DPAD Right"
-};
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ int status;
+ status = XInputGetState.initialize();
+ if (status != 0)
+ {
+ osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetState.name(), status);
+ return -1;
+ }
-static const USHORT xinput_buttons[] = {
- XINPUT_GAMEPAD_A,
- XINPUT_GAMEPAD_B,
- XINPUT_GAMEPAD_X,
- XINPUT_GAMEPAD_Y,
- XINPUT_GAMEPAD_LEFT_SHOULDER,
- XINPUT_GAMEPAD_RIGHT_SHOULDER,
- XINPUT_GAMEPAD_START,
- XINPUT_GAMEPAD_BACK,
- XINPUT_GAMEPAD_LEFT_THUMB,
- XINPUT_GAMEPAD_RIGHT_THUMB,
-};
+ status = XInputGetCapabilities.initialize();
+ if (status != 0)
+ {
+ osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetCapabilities.name(), status);
+ return -1;
+ }
+#endif
-static const char *const xinput_button_names[] = {
- "A",
- "B",
- "X",
- "Y",
- "Left Shoulder",
- "Right Shoulder",
- "Start",
- "Back",
- "Left Thumb",
- "Right Thumb"
-};
+ return 0;
+}
-struct gamepad_state
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+// Pass-through functions for Universal Windows
+inline DWORD xinput_api_helper::XInputGetState(DWORD dwUserindex, XINPUT_STATE *pState)
{
- BYTE rgbButtons[XINPUT_MAX_BUTTONS];
- BYTE rgbPov[XINPUT_MAX_POV];
- BYTE bLeftTrigger;
- BYTE bRightTrigger;
- LONG sThumbLX;
- LONG sThumbLY;
- LONG sThumbRX;
- LONG sThumbRY;
-};
+ return ::XInputGetState(dwUserindex, pState);
+}
-// state information for a gamepad; state must be first element
-struct xinput_api_state
+inline DWORD xinput_api_helper::XInputGetCapabilities(DWORD dwUserindex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities)
{
- UINT32 playerIndex;
- XINPUT_STATE xstate;
- XINPUT_CAPABILITIES caps;
-};
+ return ::XInputGetCapabilities(dwUserindex, dwFlags, pCapabilities);
+}
+#endif
-// Typedef for pointers to XInput Functions
-typedef lazy_loaded_function_p2<DWORD, DWORD, XINPUT_STATE*> xinput_get_state_fn;
-typedef lazy_loaded_function_p3<DWORD, DWORD, DWORD, XINPUT_CAPABILITIES*> xinput_get_caps_fn;
+//============================================================
+// create_xinput_device
+//============================================================
-class xinput_interface
+xinput_joystick_device * xinput_api_helper::create_xinput_device(running_machine &machine, UINT index, wininput_module &module)
{
-private:
- const wchar_t* xinput_dll_names[2] = { L"xinput1_4.dll", L"xinput9_1_0.dll" };
+ xinput_joystick_device *devinfo;
-public:
- xinput_get_state_fn XInputGetState;
- xinput_get_caps_fn XInputGetCapabilities;
-
-private:
- xinput_interface()
- : XInputGetState("XInputGetState", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names)),
- XInputGetCapabilities("XInputGetCapabilities", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names))
+ XINPUT_CAPABILITIES caps = { 0 };
+ if (FAILED(XInputGetCapabilities(index, 0, &caps)))
{
+ // If we can't get the capabilities skip this device
+ return nullptr;
}
- int initialize()
- {
- int status;
- status = XInputGetState.initialize();
- if (status != 0)
- {
- osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetState.name(), status);
- return -1;
- }
+ char device_name[16];
+ snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1);
- status = XInputGetCapabilities.initialize();
- if (status != 0)
- {
- osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetCapabilities.name(), status);
- return -1;
- }
+ // allocate the device object
+ devinfo = module.devicelist()->create_device1<xinput_joystick_device>(machine, device_name, module, shared_from_this());
- return 0;
- }
+ // Set the player ID
+ devinfo->xinput_state.playerIndex = index;
-public:
- static DWORD get_interface(xinput_interface **ppinterface)
- {
- static xinput_interface s_instance;
- DWORD error = s_instance.initialize();
- if (error == 0)
- {
- *ppinterface = &s_instance;
- }
+ // Assign the caps we captured earlier
+ devinfo->xinput_state.caps = caps;
- return error;
- }
-};
+ return devinfo;
+}
//============================================================
// xinput_joystick_device
//============================================================
-class xinput_joystick_device : public device_info
+xinput_joystick_device::xinput_joystick_device(running_machine &machine, const char *name, input_module &module, std::shared_ptr<xinput_api_helper> helper)
+ : device_info(machine, name, DEVICE_CLASS_JOYSTICK, module),
+ gamepad({{0}}),
+ xinput_state({0}),
+ m_xinput_helper(helper),
+ m_configured(false)
{
-public:
- gamepad_state gamepad;
- xinput_api_state xinput_state;
+}
-private:
- xinput_interface* xinput_api;
+void xinput_joystick_device::poll()
+{
+ if (!m_configured)
+ return;
-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}),
- xinput_api(nullptr)
+ // poll the device first
+ HRESULT result = m_xinput_helper->XInputGetState(xinput_state.playerIndex, &xinput_state.xstate);
+
+ // If we can't poll the device, skip
+ if (FAILED(result))
+ return;
+
+ // Copy the XState into State
+ // Start with the POV (DPAD)
+ for (int povindex = 0; povindex < XINPUT_MAX_POV; povindex++)
{
- // Attempt to get the xinput interface
- xinput_interface::get_interface(&xinput_api);
+ int currentPov = xinput_pov_dir[povindex];
+ gamepad.rgbPov[currentPov] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0;
}
- void poll() override
+ // Now do the buttons
+ for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++)
{
- // Nothing we can do if for some reason the API couldn't be loaded
- if (xinput_api == nullptr)
- return;
+ int currentButton = xinput_buttons[buttonindex];
+ gamepad.rgbButtons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0;
+ }
- // poll the device first
- HRESULT result = xinput_api->XInputGetState(xinput_state.playerIndex, &xinput_state.xstate);
+ // Now grab the axis values
+ // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick
+ // However, the Y axis values are inverted from what MAME expects, so multiply by -1 first
+ gamepad.sThumbLX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ gamepad.sThumbLY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ gamepad.sThumbRX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ gamepad.sThumbRY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- // If we can't poll the device, skip
- if (FAILED(result))
- return;
+ // Now the triggers
+ gamepad.bLeftTrigger = xinput_state.xstate.Gamepad.bLeftTrigger;
+ gamepad.bRightTrigger = xinput_state.xstate.Gamepad.bRightTrigger;
+}
- // Copy the XState into State
- // Start with the POV (DPAD)
- for (int povindex = 0; povindex < XINPUT_MAX_POV; povindex++)
- {
- int currentPov = xinput_pov_dir[povindex];
- gamepad.rgbPov[currentPov] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0;
- }
+void xinput_joystick_device::reset()
+{
+ memset(&gamepad, 0, sizeof(gamepad));
+}
- // Now do the buttons
- for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++)
- {
- int currentButton = xinput_buttons[buttonindex];
- gamepad.rgbButtons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0;
- }
+void xinput_joystick_device::configure()
+{
+ std::lock_guard<std::mutex> scope_lock(m_device_lock);
+
+ if (m_configured)
+ return;
- // Now grab the axis values
- // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick
- // However, the Y axis values are inverted from what MAME expects, so multiply by -1 first
- gamepad.sThumbLX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.sThumbLY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.sThumbRX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.sThumbRY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
-
- // Now the triggers
- gamepad.bLeftTrigger = xinput_state.xstate.Gamepad.bLeftTrigger;
- gamepad.bRightTrigger = xinput_state.xstate.Gamepad.bRightTrigger;
+ // Add the axes
+ for (int axisnum = 0; axisnum < XINPUT_MAX_AXIS; axisnum++)
+ {
+ device()->add_item(
+ xinput_axis_name[axisnum],
+ xinput_axis_ids[axisnum],
+ generic_axis_get_state,
+ &gamepad.sThumbLX + axisnum);
}
- void reset() override
+ // Populate the POVs
+ // For XBOX, we treat the DPAD as a hat switch
+ for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++)
{
- memset(&gamepad, 0, sizeof(gamepad));
+ device()->add_item(
+ xinput_pov_names[povnum],
+ ITEM_ID_OTHER_SWITCH,
+ generic_button_get_state,
+ &gamepad.rgbPov[povnum]);
}
-};
+
+ // populate the buttons
+ for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++)
+ {
+ device()->add_item(
+ xinput_button_names[butnum],
+ static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state,
+ &gamepad.rgbButtons[butnum]);
+ }
+
+ device()->add_item(
+ "Left Trigger",
+ static_cast<input_item_id>(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS),
+ generic_button_get_state,
+ &gamepad.bLeftTrigger);
+
+ device()->add_item(
+ "Right Trigger",
+ static_cast<input_item_id>(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS + 1),
+ generic_button_get_state,
+ &gamepad.bRightTrigger);
+
+ m_configured = true;
+}
//============================================================
// xinput_joystick_module
@@ -249,12 +224,12 @@ public:
class xinput_joystick_module : public wininput_module
{
private:
- xinput_interface* xinput_api;
+ std::shared_ptr<xinput_api_helper> m_xinput_helper;
public:
xinput_joystick_module()
: wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput"),
- xinput_api(nullptr)
+ m_xinput_helper(nullptr)
{
}
@@ -265,11 +240,12 @@ public:
if (status != 0)
return status;
- // Make sure we can get the xinput API
- status = xinput_interface::get_interface(&xinput_api);
+ // Create and initialize our helper
+ m_xinput_helper = std::make_shared<xinput_api_helper>();
+ status = m_xinput_helper->initialize();
if (status != 0)
{
- osd_printf_error("xinput_joystick_module failed to get XInput interface! Error: %u\n", (unsigned int)status);
+ osd_printf_error("xinput_joystick_module failed to get XInput interface! Error: %u\n", static_cast<unsigned int>(status));
return -1;
}
@@ -279,9 +255,6 @@ public:
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
@@ -289,93 +262,22 @@ protected:
{
XINPUT_STATE state = {0};
- if (xinput_api->XInputGetState(i, &state) == ERROR_SUCCESS)
+ if (m_xinput_helper->XInputGetState(i, &state) == ERROR_SUCCESS)
{
// allocate and link in a new device
- devinfo = create_xinput_device(machine, i);
+ devinfo = m_xinput_helper->create_xinput_device(machine, i, *this);
if (devinfo == nullptr)
continue;
- // Add the axes
- for (int axisnum = 0; axisnum < XINPUT_MAX_AXIS; axisnum++)
- {
- devinfo->device()->add_item(
- xinput_axis_name[axisnum],
- xinput_axis_ids[axisnum],
- generic_axis_get_state,
- &devinfo->gamepad.sThumbLX + axisnum);
- }
-
- // Populate the POVs
- // For XBOX, we treat the DPAD as a hat switch
- for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++)
- {
- devinfo->device()->add_item(
- xinput_pov_names[povnum],
- ITEM_ID_OTHER_SWITCH,
- generic_button_get_state,
- &devinfo->gamepad.rgbPov[povnum]);
- }
-
- // populate the buttons
- for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++)
- {
- devinfo->device()->add_item(
- xinput_button_names[butnum],
- (input_item_id)(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state,
- &devinfo->gamepad.rgbButtons[butnum]);
- }
-
- devinfo->device()->add_item(
- "Left Trigger",
- (input_item_id)(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS),
- generic_button_get_state,
- &devinfo->gamepad.bLeftTrigger);
-
- devinfo->device()->add_item(
- "Right Trigger",
- (input_item_id)(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS + 1),
- generic_button_get_state,
- &devinfo->gamepad.bRightTrigger);
+ // Configure each gamepad to add buttons and Axes, etc.
+ devinfo->configure();
}
}
}
-
- private:
- //============================================================
- // create_xinput_device
- //============================================================
-
- xinput_joystick_device * create_xinput_device(running_machine &machine, UINT index)
- {
- xinput_joystick_device *devinfo;
-
- XINPUT_CAPABILITIES caps = {0};
- if (FAILED(xinput_api->XInputGetCapabilities(index, 0, &caps)))
- {
- // If we can't get the capabilities skip this device
- return nullptr;
- }
-
- char device_name[16];
- snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1);
-
- // allocate the device object
- devinfo = devicelist()->create_device<xinput_joystick_device>(machine, device_name, *this);
-
- // Set the player ID
- devinfo->xinput_state.playerIndex = index;
-
- // Assign the caps we captured earlier
- devinfo->xinput_state.caps = caps;
-
- return devinfo;
- }
};
#else
-MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_KEYBOARDINPUT_PROVIDER, "xinput")
+MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "xinput")
#endif
MODULE_DEFINITION(JOYSTICKINPUT_XINPUT, xinput_joystick_module)
diff --git a/src/osd/modules/input/input_xinput.h b/src/osd/modules/input/input_xinput.h
new file mode 100644
index 00000000000..0a0e4ed0266
--- /dev/null
+++ b/src/osd/modules/input/input_xinput.h
@@ -0,0 +1,140 @@
+#ifndef INPUT_XINPUT_H_
+#define INPUT_XINPUT_H_
+
+#include <mutex>
+
+#define XINPUT_MAX_POV 4
+#define XINPUT_MAX_BUTTONS 10
+#define XINPUT_MAX_AXIS 4
+
+#define XINPUT_AXIS_MINVALUE -32767
+#define XINPUT_AXIS_MAXVALUE 32767
+
+class xinput_joystick_device;
+// default axis names
+static const char *const xinput_axis_name[] =
+{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY"
+};
+
+static const input_item_id xinput_axis_ids[] =
+{
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_RXAXIS,
+ ITEM_ID_RYAXIS
+};
+
+static const USHORT xinput_pov_dir[] = {
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+};
+
+static const char *const xinput_pov_names[] = {
+ "DPAD Up",
+ "DPAD Down",
+ "DPAD Left",
+ "DPAD Right"
+};
+
+static const USHORT xinput_buttons[] = {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+};
+
+static const char *const xinput_button_names[] = {
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Left Shoulder",
+ "Right Shoulder",
+ "Start",
+ "Back",
+ "Left Thumb",
+ "Right Thumb"
+};
+
+struct gamepad_state
+{
+ BYTE rgbButtons[XINPUT_MAX_BUTTONS];
+ BYTE rgbPov[XINPUT_MAX_POV];
+ BYTE bLeftTrigger;
+ BYTE bRightTrigger;
+ LONG sThumbLX;
+ LONG sThumbLY;
+ LONG sThumbRX;
+ LONG sThumbRY;
+};
+
+// state information for a gamepad; state must be first element
+struct xinput_api_state
+{
+ UINT32 playerIndex;
+ XINPUT_STATE xstate;
+ XINPUT_CAPABILITIES caps;
+};
+
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+// Typedef for pointers to XInput Functions
+typedef lazy_loaded_function_p2<DWORD, DWORD, XINPUT_STATE*> xinput_get_state_fn;
+typedef lazy_loaded_function_p3<DWORD, DWORD, DWORD, XINPUT_CAPABILITIES*> xinput_get_caps_fn;
+#endif
+
+class xinput_api_helper : public std::enable_shared_from_this<xinput_api_helper>
+{
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+private:
+ const wchar_t* xinput_dll_names[2] = { L"xinput1_4.dll", L"xinput9_1_0.dll" };
+
+public:
+ xinput_get_state_fn XInputGetState;
+ xinput_get_caps_fn XInputGetCapabilities;
+#endif
+
+public:
+ xinput_api_helper();
+
+ int initialize();
+ xinput_joystick_device * create_xinput_device(running_machine &machine, UINT index, wininput_module &module);
+
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ // Pass-through functions for Universal Windows
+ inline DWORD XInputGetState(DWORD dwUserindex, XINPUT_STATE *pState);
+ inline DWORD XInputGetCapabilities(DWORD dwUserindex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities);
+#endif
+};
+
+class xinput_joystick_device : public device_info
+{
+public:
+ gamepad_state gamepad;
+ xinput_api_state xinput_state;
+
+private:
+ std::shared_ptr<xinput_api_helper> m_xinput_helper;
+ std::mutex m_device_lock;
+ bool m_configured;
+
+public:
+ xinput_joystick_device(running_machine &machine, const char *name, input_module &module, std::shared_ptr<xinput_api_helper> helper);
+
+ void poll() override;
+ void reset() override;
+ void configure();
+};
+
+#endif
diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp
index b4c0d68915e..04eb1f6da68 100644
--- a/src/osd/modules/lib/osdobj_common.cpp
+++ b/src/osd/modules/lib/osdobj_common.cpp
@@ -241,6 +241,7 @@ void osd_common_t::register_options()
REGISTER_MODULE(m_mod_man, LIGHTGUN_NONE);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL);
+ REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_WINHYBRID);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_XINPUT);
REGISTER_MODULE(m_mod_man, JOYSTICK_NONE);