osd/modules/input: Modernised interface for enumerating DirectInput devices.

Gets rid of some state in the winhybrid joystick module that's only used
during initialisation.
This commit is contained in:
Vas Crabb 2023-02-28 04:20:52 +11:00
parent b13a5d971f
commit deceecfbfb
4 changed files with 75 additions and 87 deletions

View File

@ -125,12 +125,6 @@ namespace osd {
namespace {
BOOL CALLBACK device_enum_interface_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
{
return static_cast<device_enum_interface *>(ref)->device_enum_callback(instance);
}
std::string guid_to_string(GUID const &guid)
{
// size of a GUID string with dashes plus NUL terminator
@ -307,11 +301,8 @@ void dinput_mouse_device::configure(input_device &device)
// dinput_module - base DirectInput module
//============================================================
class dinput_module : public input_module_impl<dinput_device, osd_common_t>, public device_enum_interface
class dinput_module : public input_module_impl<dinput_device, osd_common_t>
{
protected:
std::unique_ptr<dinput_api_helper> m_dinput_helper;
public:
dinput_module(const char* type, const char* name) :
input_module_impl<dinput_device, osd_common_t>(type, name),
@ -343,13 +334,18 @@ public:
{
input_module_impl<dinput_device, osd_common_t>::input_init(machine);
HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), *this);
HRESULT const result = m_dinput_helper->enum_attached_devices(
dinput_devclass(),
[this] (LPCDIDEVICEINSTANCE instance) { return device_enum_callback(instance); });
if (result != DI_OK)
fatalerror("DirectInput: Unable to enumerate devices (result=%08X)\n", uint32_t(result));
}
protected:
virtual int dinput_devclass() = 0;
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) = 0;
std::unique_ptr<dinput_api_helper> m_dinput_helper;
};
@ -361,6 +357,7 @@ public:
{
}
protected:
virtual int dinput_devclass() override
{
return DI8DEVCLASS_KEYBOARD;
@ -392,6 +389,7 @@ public:
{
}
protected:
virtual int dinput_devclass() override
{
return DI8DEVCLASS_POINTER;
@ -438,6 +436,7 @@ public:
{
}
protected:
virtual int dinput_devclass() override
{
return DI8DEVCLASS_GAMECTRL;
@ -1212,12 +1211,6 @@ int dinput_api_helper::initialize()
}
HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface &enumerate_interface) const
{
return m_dinput->EnumDevices(devclass, device_enum_interface_callback, &enumerate_interface, DIEDFL_ATTACHEDONLY);
}
std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_api_helper::open_device(
LPCDIDEVICEINSTANCE instance,
LPCDIDATAFORMAT format1,

View File

@ -37,14 +37,6 @@ namespace osd {
// dinput_device - base directinput device
//============================================================
class device_enum_interface
{
public:
virtual ~device_enum_interface() = default;
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) = 0;
};
enum class dinput_cooperative_level
{
FOREGROUND,
@ -92,7 +84,18 @@ public:
format);
}
HRESULT enum_attached_devices(int devclass, device_enum_interface &enumerate_interface) const;
template <typename T>
HRESULT enum_attached_devices(int devclass, T &&callback) const
{
return m_dinput->EnumDevices(
devclass,
[] (LPCDIDEVICEINSTANCE instance, LPVOID ref) -> BOOL
{
return (*reinterpret_cast<T *>(ref))(instance);
},
reinterpret_cast<LPVOID>(&callback),
DIEDFL_ATTACHEDONLY);
}
template <typename T>
static HRESULT set_dword_property(

View File

@ -121,12 +121,11 @@ typedef std::unique_ptr<OLECHAR, bstr_deleter> bstr_ptr;
// winhybrid_joystick_module
//============================================================
class winhybrid_joystick_module : public input_module_impl<device_info, osd_common_t>, public device_enum_interface
class winhybrid_joystick_module : public input_module_impl<device_info, osd_common_t>
{
private:
std::unique_ptr<xinput_api_helper> m_xinput_helper;
std::unique_ptr<dinput_api_helper> m_dinput_helper;
std::vector<DWORD> m_xinput_deviceids;
public:
winhybrid_joystick_module() :
@ -166,60 +165,65 @@ public:
return 0;
}
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
// First check if this device is XInput compatible.
// If so, don't add it here as it'll be picked up by Xinput.
if (is_xinput_device(instance->guidProduct))
{
osd_printf_verbose("Skipping DirectInput for XInput compatible joystick %S.\n", instance->tszInstanceName);
return DIENUM_CONTINUE;
}
// allocate and link in a new device
auto devinfo = m_dinput_helper->create_device<dinput_joystick_device>(
*this,
instance,
&c_dfDIJoystick,
nullptr,
background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
[] (auto const &device, auto const &format) -> bool
{
// set absolute mode
HRESULT const result = dinput_api_helper::set_dword_property(
device,
DIPROP_AXISMODE,
0,
DIPH_DEVICE,
DIPROPAXISMODE_ABS);
if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
{
osd_printf_error("DirectInput: Unable to set absolute mode for joystick.\n");
return false;
}
return true;
});
if (devinfo)
add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
return DIENUM_CONTINUE;
}
virtual void input_init(running_machine &machine) override
{
input_module_impl<device_info, osd_common_t>::input_init(machine);
bool xinput_detect_failed = false;
HRESULT result = get_xinput_devices();
std::vector<DWORD> xinput_deviceids;
HRESULT result = get_xinput_devices(xinput_deviceids);
if (result != 0)
{
xinput_detect_failed = true;
m_xinput_deviceids.clear();
xinput_deviceids.clear();
osd_printf_warning("XInput device detection failed. XInput won't be used. Error: 0x%X\n", uint32_t(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);
result = m_dinput_helper->enum_attached_devices(
DI8DEVCLASS_GAMECTRL,
[this, &xinput_deviceids] (LPCDIDEVICEINSTANCE instance)
{
// First check if this device is XInput compatible.
// If so, don't add it here as it'll be picked up by Xinput.
auto const found = std::find(
xinput_deviceids.begin(),
xinput_deviceids.end(),
instance->guidProduct.Data1);
if (xinput_deviceids.end() != found)
{
osd_printf_verbose("Skipping DirectInput for XInput compatible joystick %S.\n", instance->tszInstanceName);
return DIENUM_CONTINUE;
}
// allocate and link in a new device
auto devinfo = m_dinput_helper->create_device<dinput_joystick_device>(
*this,
instance,
&c_dfDIJoystick,
nullptr,
background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
[] (auto const &device, auto const &format) -> bool
{
// set absolute mode
HRESULT const result = dinput_api_helper::set_dword_property(
device,
DIPROP_AXISMODE,
0,
DIPH_DEVICE,
DIPROPAXISMODE_ABS);
if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
{
osd_printf_error("DirectInput: Unable to set absolute mode for joystick.\n");
return false;
}
return true;
});
if (devinfo)
add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
return DIENUM_CONTINUE;
});
if (result != DI_OK)
fatalerror("DirectInput: Unable to enumerate game controllers (result=%08X).\n", uint32_t(result));
@ -273,19 +277,6 @@ private:
return 0;
}
//-----------------------------------------------------------------------------
// Returns true if the DirectInput device is also an XInput device.
//-----------------------------------------------------------------------------
bool is_xinput_device(GUID const &pGuidProductFromDirectInput) const
{
// Check each xinput device to see if this device's vid/pid matches
auto const found = std::find(
m_xinput_deviceids.begin(),
m_xinput_deviceids.end(),
pGuidProductFromDirectInput.Data1);
return m_xinput_deviceids.end() != found;
}
//-----------------------------------------------------------------------------
// 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
@ -293,9 +284,9 @@ private:
// Checking against a VID/PID of 0x028E/0x045E won't find 3rd party or future
// XInput devices.
//-----------------------------------------------------------------------------
HRESULT get_xinput_devices()
HRESULT get_xinput_devices(std::vector<DWORD> &xinput_deviceids)
{
m_xinput_deviceids.clear();
xinput_deviceids.clear();
// CoInit if needed
class com_helper
@ -419,7 +410,7 @@ private:
dwPid = 0;
// Add the VID/PID to a list
m_xinput_deviceids.push_back(MAKELONG(dwVid, dwPid));
xinput_deviceids.push_back(MAKELONG(dwVid, dwPid));
}
}
}

View File

@ -435,12 +435,13 @@ HRESULT sound_direct_sound::dsound_init()
{
// make a format description for what we want
WAVEFORMATEX stream_format;
stream_format.wBitsPerSample = 16;
stream_format.wFormatTag = WAVE_FORMAT_PCM;
stream_format.nChannels = 2;
stream_format.nSamplesPerSec = m_sample_rate;
stream_format.wBitsPerSample = 16;
stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8;
stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign;
stream_format.cbSize = 0;
// compute the buffer size based on the output sample rate
int audio_latency = std::max(m_audio_latency, 1);