summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_dinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/input/input_dinput.cpp')
-rw-r--r--src/osd/modules/input/input_dinput.cpp1540
1 files changed, 1122 insertions, 418 deletions
diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp
index 0b5eb348dc0..6f539c2f7fc 100644
--- a/src/osd/modules/input/input_dinput.cpp
+++ b/src/osd/modules/input/input_dinput.cpp
@@ -1,281 +1,354 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles, Brad Hughes
+// copyright-holders:Aaron Giles, Brad Hughes, Vas Crabb
//============================================================
//
// input_dinput.cpp - Windows DirectInput support
//
//============================================================
+/*
+
+DirectInput joystick input is a bit of a mess. It gives eight axes
+called X, Y, Z, Rx, Ry, Rz, slider 0 and slider 1. The driver can
+assign arbitrary physical axes to these axes. Up to four hat switches
+are supported, giving a direction in hundredths of degrees. In theory,
+this supports dial-like controls with an arbitrary number of stops. In
+practice, it just makes dealing with 8-way hat switches more complicated
+and prevents contradictory inputs from being reported altogether.
+
+You may get a vague indication of the type of controller, and you can
+obtain usage information for HID controllers.
+
+The Windows HID driver supposedly uses the following mappings:
+
+0x01 Generic Desktop 0x30 X X
+0x01 Generic Desktop 0x31 Y Y
+0x01 Generic Desktop 0x32 Z Z
+0x01 Generic Desktop 0x33 Rx Rx
+0x01 Generic Desktop 0x34 Ry Ry
+0x01 Generic Desktop 0x35 Rz Rz
+0x01 Generic Desktop 0x36 Slider Slider
+0x01 Generic Desktop 0x37 Dial Slider
+0x01 Generic Desktop 0x39 Hat Switch POV Hat
+0x02 Simulation 0xBA Rudder Rz
+0x02 Simulation 0xBB Throttle Slider
+0x02 Simulation 0xC4 Accelerator Y
+0x02 Simulation 0xC5 Brake Rz
+0x02 Simulation 0xC8 Steering X
+
+Anything without an explicit mapping is treated as a button.
+
+The WinMM driver supposedly uses the following axis mappings:
+
+X X
+Y Y
+Z Slider
+R Rz
+U Slider
+V Slider
+
+The actual mapping used by various controllers doesn't match what you
+might expect from the HID mapping.
+
+Gamepads:
+
+Axis Logitech DS4 Xinput Switch
+X Left X Left X Left X Left X
+Y Left Y Left Y Left Y Left Y
+Z Right X Right X Triggers
+Rx Left trigger Right X Right X
+Ry Right trigger Right Y Right Y
+Rz Right Y Right Y
+
+Thrustmaster controllers:
+
+Axis HOTAS Side stick Throttle/Pedals Dual Throttles Triple Throttles Driving
+X Aileron Aileron Mini Stick X Left Throttle Right Brake Steering
+Y Elevator Elevator Mini stick Y Right Throttle Left Brake Brake
+Z Throttle Throttle Flaps Rudder
+Rx Right Brake Right Brake Right Brake Left Throttle
+Ry Left Brake Left Brake Left Brake Centre Throttle
+Rz Twist Rudder Rocker Air Brake Right Throttle Accelerator
+Slider 0 Rocker Throttle Antenna Rudder Clutch
+Slider 1 Rudder Rudder
+
+Logitech controllers:
+
+Axis Pro Wheels
+X Steering
+Y
+Z
+Rx Accelerator
+Ry Brake
+Rz Clutch
+Slider 0
+Slider 1
+
+MFG Crosswind pedals:
+
+X Left Brake
+Y Right Brake
+Rz Rudder
+
+*/
-#include "input_module.h"
#include "modules/osdmodule.h"
-#if defined(OSD_WINDOWS)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-// standard windows headers
-#include <windows.h>
-#include <initguid.h>
-#include <tchar.h>
-#include <wrl/client.h>
+#include "input_dinput.h"
-// undef WINNT for dinput.h to prevent duplicate definition
-#undef WINNT
-#include <dinput.h>
-#undef interface
+#include "interface/inputseq.h"
+#include "windows/winutil.h"
-#include <mutex>
+// emu
+#include "inpttype.h"
-// MAME headers
-#include "emu.h"
-#include "strconv.h"
+// lib/util
+#include "util/corestr.h"
-// MAMEOS headers
-#include "window.h"
-#include "winutil.h"
+#ifdef SDLMAME_WIN32
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_syswm.h>
+#endif
-#include "input_common.h"
-#include "input_windows.h"
-#include "input_dinput.h"
+#include <algorithm>
+#include <cmath>
+#include <iterator>
+#include <memory>
-using namespace Microsoft::WRL;
+// standard windows headers
+#include <initguid.h>
+#include <tchar.h>
-static int32_t dinput_joystick_pov_get_state(void *device_internal, void *item_internal);
-//============================================================
-// dinput_set_dword_property
-//============================================================
+namespace osd {
-#if DIRECTINPUT_VERSION >= 0x0800
-static HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice8> device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
-#else
-static HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice> device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
-#endif
+namespace {
+
+std::string guid_to_string(GUID const &guid)
{
- DIPROPDWORD dipdw;
+ // size of a GUID string with dashes plus NUL terminator
+ char guid_string[37];
+ snprintf(
+ guid_string, std::size(guid_string),
+ "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ guid.Data1, guid.Data2, guid.Data3,
+ guid.Data4[0], guid.Data4[1], guid.Data4[2],
+ guid.Data4[3], guid.Data4[4], guid.Data4[5],
+ guid.Data4[6], guid.Data4[7]);
+
+ return guid_string;
+}
- dipdw.diph.dwSize = sizeof(dipdw);
- dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
- dipdw.diph.dwObj = object;
- dipdw.diph.dwHow = how;
- dipdw.dwData = value;
- return device->SetProperty(property_guid, &dipdw.diph);
-}
//============================================================
-// dinput_device - base directinput device
+// dinput_keyboard_device - DirectInput keyboard device
//============================================================
-dinput_device::dinput_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module)
- : device_info(machine, name, id, deviceclass, module),
- dinput({nullptr})
+class dinput_keyboard_device : public dinput_device
{
-}
+public:
+ dinput_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format);
+
+ virtual void poll(bool relative_reset) override;
+ virtual void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ std::mutex m_device_lock;
+ keyboard_state m_keyboard;
+};
-dinput_device::~dinput_device()
+dinput_keyboard_device::dinput_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
+ m_keyboard({ { 0 } })
{
- if (dinput.device != nullptr)
- dinput.device.Reset();
}
-HRESULT dinput_device::poll_dinput(LPVOID pState) const
+void dinput_keyboard_device::poll(bool relative_reset)
{
- HRESULT result;
-
- // first poll the device, then get the state
-#if DIRECTINPUT_VERSION >= 0x0800
- dinput.device->Poll();
-#else
- if (dinput.device2 != nullptr)
- dinput.device2->Poll();
-#endif
+ // poll the DirectInput immediate state
+ std::lock_guard<std::mutex> scope_lock(m_device_lock);
+ poll_dinput(&m_keyboard.state);
+}
- // GetDeviceState returns the immediate state
- result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
+void dinput_keyboard_device::reset()
+{
+ memset(&m_keyboard.state, 0, sizeof(m_keyboard.state));
+}
- // handle lost inputs here
- if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
+void dinput_keyboard_device::configure(input_device &device)
+{
+ // populate it
+ char defname[20];
+ for (unsigned keynum = 0; keynum < MAX_KEYS; keynum++)
{
- result = dinput.device->Acquire();
- if (result == DI_OK)
- result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
+ input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
+
+ // generate/fetch the name
+ snprintf(defname, std::size(defname), "Scan%03d", keynum);
+
+ // add the item to the device
+ device.add_item(
+ item_name(keynum, defname, nullptr),
+ strmakeupper(defname),
+ itemid,
+ generic_button_get_state<uint8_t>,
+ &m_keyboard.state[keynum]);
}
-
- return result;
}
+
//============================================================
-// dinput_keyboard_device - directinput keyboard device
+// dinput_mouse_device - DirectInput mouse device
//============================================================
-dinput_keyboard_device::dinput_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : dinput_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+class dinput_mouse_device : public dinput_device
{
-}
+public:
+ dinput_mouse_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format);
+
+ void poll(bool relative_reset) override;
+ void reset() override;
+ virtual void configure(input_device &device) override;
+
+private:
+ DIMOUSESTATE2 m_mouse;
+};
-// Polls the direct input immediate state
-void dinput_keyboard_device::poll()
+dinput_mouse_device::dinput_mouse_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
+ m_mouse({0})
{
- std::lock_guard<std::mutex> scope_lock(m_device_lock);
-
- // Poll the state
- dinput_device::poll_dinput(&keyboard.state);
+ // cap the number of axes and buttons based on the format
+ m_caps.dwAxes = std::min(m_caps.dwAxes, DWORD(3));
+ m_caps.dwButtons = std::min(m_caps.dwButtons, DWORD((m_format == &c_dfDIMouse) ? 4 : 8));
}
-void dinput_keyboard_device::reset()
-{
- memset(&keyboard.state, 0, sizeof(keyboard.state));
-}
-
-//============================================================
-// dinput_api_helper - DirectInput API helper
-//============================================================
-
-dinput_api_helper::dinput_api_helper(int version)
- : m_dinput(nullptr),
- m_dinput_version(version),
- m_dinput_create_prt(nullptr)
+void dinput_mouse_device::poll(bool relative_reset)
{
+ // poll
+ if (relative_reset && (poll_dinput(&m_mouse) == DI_OK))
+ {
+ // scale the axis data
+ m_mouse.lX *= input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lY *= input_device::RELATIVE_PER_PIXEL;
+ m_mouse.lZ *= input_device::RELATIVE_PER_PIXEL;
+ }
}
-dinput_api_helper::~dinput_api_helper()
+void dinput_mouse_device::reset()
{
- m_dinput.Reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
}
-int dinput_api_helper::initialize()
+void dinput_mouse_device::configure(input_device &device)
{
- HRESULT result;
-
-#if DIRECTINPUT_VERSION >= 0x0800
- if (m_dinput_version >= 0x0800)
+ // populate the axes
+ for (int axisnum = 0; axisnum < m_caps.dwAxes; axisnum++)
{
- 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;
- }
+ // add to the mouse device and optionally to the gun device as well
+ device.add_item(
+ item_name(offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
+ std::string_view(),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX + axisnum);
}
- else
-#endif
- {
- m_dinput_dll = osd::dynamic_module::open({ "dinput.dll" });
- m_dinput_create_prt = m_dinput_dll->bind<dinput_create_fn>("DirectInputCreateW");
- if (m_dinput_create_prt == nullptr)
- {
- osd_printf_verbose("Legacy DirectInput library dinput.dll is not available\n");
- return ERROR_DLL_NOT_FOUND;
- }
+ // populate the buttons
+ for (int butnum = 0; butnum < m_caps.dwButtons; butnum++)
+ {
+ auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
- // first attempt to initialize DirectInput at v7
- m_dinput_version = 0x0700;
- result = (*m_dinput_create_prt)(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
- if (result != DI_OK)
- {
- // if that fails, try version 5
- m_dinput_version = 0x0500;
- result = (*m_dinput_create_prt)(GetModuleHandleUni(), m_dinput_version, m_dinput.GetAddressOf(), nullptr);
- if (result != DI_OK)
- {
- m_dinput_version = 0;
- return result;
- }
- }
+ // add to the mouse device
+ device.add_item(
+ item_name(offset, default_button_name(butnum), nullptr),
+ std::string_view(),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_mouse.rgbButtons[butnum]);
}
-
- osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
- return 0;
-}
-
-
-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;
-
- return m_dinput->EnumDevices(devclass, device_enum_interface::enum_callback, &ctx, DIEDFL_ATTACHEDONLY);
}
//============================================================
-// dinput_module - base directinput module
+// dinput_module - base DirectInput module
//============================================================
-class dinput_module : public wininput_module, 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)
- : wininput_module(type, name),
- m_dinput_helper(nullptr)
+ dinput_module(const char* type, const char* name) :
+ input_module_impl<dinput_device, osd_common_t>(type, name),
+ m_dinput_helper(nullptr)
{
}
- int init_internal() override
+ virtual int init(osd_interface &osd, osd_options const &options) override
{
- m_dinput_helper = std::make_unique<dinput_api_helper>(DIRECTINPUT_VERSION);
- int result = m_dinput_helper->initialize();
- if (result != 0)
+ m_dinput_helper = std::make_unique<dinput_api_helper>();
+ int const result = m_dinput_helper->initialize();
+ if (result)
+ {
+ m_dinput_helper.reset();
return result;
+ }
- return 0;
+ return input_module_impl<dinput_device, osd_common_t>::init(osd, options);
}
- void exit() override
+ virtual void exit() override
{
- wininput_module::exit();
- m_dinput_helper.reset();
- }
+ input_module_impl<dinput_device, osd_common_t>::exit();
- void input_init(running_machine &machine) override
- {
- HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), this, &machine);
- if (result != DI_OK)
- fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", static_cast<uint32_t>(result));
+ m_dinput_helper.reset();
}
- static std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix)
+ virtual void input_init(running_machine &machine) override
{
- DIDEVICEOBJECTINSTANCE instance = { 0 };
- HRESULT result;
-
- // query the key name
- instance.dwSize = sizeof(instance);
- result = devinfo->dinput.device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
+ input_module_impl<dinput_device, osd_common_t>::input_init(machine);
- // if we got an error and have no default string, just return nullptr
+ HRESULT const result = m_dinput_helper->enum_attached_devices(
+ dinput_devclass(),
+ [this] (LPCDIDEVICEINSTANCE instance) { return device_enum_callback(instance); });
if (result != DI_OK)
- {
- if (defstring == nullptr)
- return nullptr;
-
- // Return the default value
- return std::string(defstring);
- }
-
- // convert the name to utf8
- std::string namestring = osd::text::from_tstring(instance.tszName);
-
- // if no suffix, return as-is
- if (suffix == nullptr)
- return namestring;
-
- // convert the suffix to utf8
- std::string suffix_utf8 = osd::text::from_tstring(suffix);
-
- // Concat the name and suffix
- return namestring + " " + suffix_utf8;
+ 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;
};
+
class keyboard_input_dinput : public dinput_module
{
public:
@@ -284,69 +357,30 @@ public:
{
}
- int dinput_devclass() override
+protected:
+ virtual int dinput_devclass() override
{
-#if DIRECTINPUT_VERSION >= 0x0800
return DI8DEVCLASS_KEYBOARD;
-#else
- return DIDEVTYPE_KEYBOARD;
-#endif
}
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
- running_machine &machine = *static_cast<running_machine *>(ref);
- dinput_keyboard_device *devinfo;
- int keynum;
-
// allocate and link in a new device
- devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(machine, *this, instance, &c_dfDIKeyboard, nullptr, dinput_cooperative_level::FOREGROUND);
- if (devinfo == nullptr)
- goto exit;
-
- // populate it
- for (keynum = 0; keynum < MAX_KEYS; keynum++)
- {
- input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
- char defname[20];
- std::string name;
-
- // generate/fetch the name
- snprintf(defname, ARRAY_LENGTH(defname), "Scan%03d", keynum);
- name = device_item_name(devinfo, keynum, defname, nullptr);
+ auto devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(
+ *this,
+ instance,
+ &c_dfDIKeyboard,
+ nullptr,
+ background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
+ [] (auto...) { return true; });
+ if (devinfo)
+ add_device(DEVICE_CLASS_KEYBOARD, std::move(devinfo));
- // add the item to the device
- devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
- }
-
- exit:
return DIENUM_CONTINUE;
}
};
-dinput_mouse_device::dinput_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : dinput_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- mouse({0})
-{
-}
-
-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;
-}
-
-void dinput_mouse_device::reset()
-{
- memset(&mouse, 0, sizeof(mouse));
-}
-
class mouse_input_dinput : public dinput_module
{
public:
@@ -355,284 +389,954 @@ public:
{
}
- int dinput_devclass() override
+protected:
+ virtual int dinput_devclass() override
{
-#if DIRECTINPUT_VERSION >= 0x0800
return DI8DEVCLASS_POINTER;
-#else
- return DIDEVTYPE_MOUSE;
-#endif
}
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
- dinput_mouse_device *devinfo = nullptr;
- running_machine &machine = *static_cast<running_machine *>(ref);
- int axisnum, butnum;
- HRESULT result;
-
// allocate and link in a new device
- devinfo = m_dinput_helper->create_device<dinput_mouse_device>(machine, *this, instance, &c_dfDIMouse2, &c_dfDIMouse, dinput_cooperative_level::FOREGROUND);
- if (devinfo == nullptr)
- goto exit;
+ auto devinfo = m_dinput_helper->create_device<dinput_mouse_device>(
+ *this,
+ instance,
+ &c_dfDIMouse2,
+ &c_dfDIMouse,
+ background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
+ [] (auto const &device, auto const &format) -> bool
+ {
+ // set relative mode
+ HRESULT const result = dinput_api_helper::set_dword_property(
+ device,
+ DIPROP_AXISMODE,
+ 0,
+ DIPH_DEVICE,
+ DIPROPAXISMODE_REL);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ {
+ osd_printf_error("DirectInput: Unable to set relative mode for mouse.\n");
+ return false;
+ }
+ return true;
+ });
+ if (devinfo)
+ add_device(DEVICE_CLASS_MOUSE, std::move(devinfo));
- // set relative mode on the mouse device
- result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_REL);
- if (result != DI_OK && result != DI_PROPNOEFFECT)
- {
- osd_printf_error("DirectInput: Unable to set relative mode for mouse %u (%s)\n", static_cast<unsigned int>(devicelist()->size()), devinfo->name());
- goto error;
- }
+ return DIENUM_CONTINUE;
+ }
+};
- // cap the number of axes and buttons based on the format
- devinfo->dinput.caps.dwAxes = std::min(devinfo->dinput.caps.dwAxes, DWORD(3));
- devinfo->dinput.caps.dwButtons = std::min(devinfo->dinput.caps.dwButtons, DWORD((devinfo->dinput.format == &c_dfDIMouse) ? 4 : 8));
- // populate the axes
- for (axisnum = 0; axisnum < devinfo->dinput.caps.dwAxes; axisnum++)
- {
- // add to the mouse device and optionally to the gun device as well
- std::string name = device_item_name(devinfo, offsetof(DIMOUSESTATE, 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<LONG>,
- &devinfo->mouse.lX + axisnum);
- }
+class joystick_input_dinput : public dinput_module
+{
+public:
+ joystick_input_dinput() :
+ dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
+ {
+ }
- // populate the buttons
- for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
- {
- uintptr_t offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
+protected:
+ virtual int dinput_devclass() override
+ {
+ return DI8DEVCLASS_GAMECTRL;
+ }
- // add to the mouse device
- std::string name = device_item_name(devinfo, offset, default_button_name(butnum), nullptr);
- devinfo->device()->add_item(
- name.c_str(),
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->mouse.rgbButtons[butnum]);
- }
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
+ {
+ // 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));
- exit:
return DIENUM_CONTINUE;
-
- error:
- if (devinfo != nullptr)
- devicelist()->free_device(devinfo);
- goto exit;
}
};
-dinput_joystick_device::dinput_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : dinput_device(machine, name, id, DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}})
+} // anonymous namespace
+
+
+//============================================================
+// dinput_device - base DirectInput device
+//============================================================
+
+dinput_device::dinput_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ device_info(std::move(name), std::move(id), module),
+ m_device(std::move(device)),
+ m_caps(caps),
+ m_format(format)
{
}
-void dinput_joystick_device::reset()
+HRESULT dinput_device::poll_dinput(LPVOID pState) const
+{
+ HRESULT result;
+
+ // first poll the device, then get the state
+ result = m_device->Poll();
+
+ // handle lost inputs here
+ if ((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
+ {
+ result = m_device->Acquire();
+ if ((result == DI_OK) || (result == S_FALSE))
+ result = m_device->Poll();
+ }
+
+ // GetDeviceState returns the immediate state
+ if ((result == DI_OK) || (result == DI_NOEFFECT))
+ result = m_device->GetDeviceState(m_format->dwDataSize, pState);
+
+ return result;
+}
+
+std::string dinput_device::item_name(int offset, std::string_view defstring, const char *suffix) const
{
- memset(&joystick.state, 0, sizeof(joystick.state));
+ // query the key name
+ DIDEVICEOBJECTINSTANCE instance = { 0 };
+ instance.dwSize = sizeof(instance);
+ HRESULT const result = m_device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
+
+ // use the default value if it failed
+ std::string name;
+ if (result != DI_OK)
+ name = defstring;
+ else
+ name = text::from_tstring(instance.tszName);
+
+ // if no suffix, return as-is
+ if (suffix)
+ name.append(" ").append(suffix);
+
+ return name;
}
-void dinput_joystick_device::poll()
+
+//============================================================
+// dinput_joystick_device - directinput joystick device
+//============================================================
+
+dinput_joystick_device::dinput_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
+ DIDEVCAPS const &caps,
+ LPCDIDATAFORMAT format) :
+ dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
+ m_joystick({ { 0 } })
{
- int axisnum;
+ // cap the number of axes, POVs, and buttons based on the format
+ m_caps.dwAxes = std::min(m_caps.dwAxes, DWORD(8));
+ m_caps.dwPOVs = std::min(m_caps.dwPOVs, DWORD(4));
+ m_caps.dwButtons = std::min(m_caps.dwButtons, DWORD(128));
+}
- // poll the device first
- if (dinput_device::poll_dinput(&joystick.state) != ERROR_SUCCESS)
- return;
+void dinput_joystick_device::reset()
+{
+ memset(&m_joystick.state, 0, sizeof(m_joystick.state));
+ std::fill(std::begin(m_joystick.state.rgdwPOV), std::end(m_joystick.state.rgdwPOV), 0xffff);
+}
- // normalize axis values
- for (axisnum = 0; axisnum < 8; axisnum++)
+void dinput_joystick_device::poll(bool relative_reset)
+{
+ // poll the device first
+ if (dinput_device::poll_dinput(&m_joystick.state) == DI_OK)
{
- LONG *axis = (&joystick.state.lX) + axisnum;
- *axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
+ // normalize axis values
+ for (int axisnum = 0; axisnum < 8; axisnum++)
+ {
+ auto const range = m_joystick.rangemax[axisnum] - m_joystick.rangemin[axisnum];
+ if (range)
+ {
+ // assumes output range is symmetrical
+ LONG *const axis = &m_joystick.state.lX + axisnum;
+ double const offset = *axis - m_joystick.rangemin[axisnum];
+ double const scaled = offset * double(input_device::ABSOLUTE_MAX - input_device::ABSOLUTE_MIN) / double(range);
+ *axis = lround(std::clamp<double>(scaled + input_device::ABSOLUTE_MIN, input_device::ABSOLUTE_MIN, input_device::ABSOLUTE_MAX));
+ }
+ }
}
}
-int dinput_joystick_device::configure()
+void dinput_joystick_device::configure(input_device &device)
{
+ input_device::assignment_vector assignments;
HRESULT result;
- uint32_t 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());
+ // get device information - it gives clues about axis usage
+ DIDEVICEINSTANCE info;
+ info.dwSize = sizeof(info);
+ result = m_device->GetDeviceInfo(&info);
+ bool hid = false;
+ uint8_t type = DI8DEVTYPE_DEVICE;
+ uint8_t subtype = 0;
+ if (result == DI_OK)
+ {
+ hid = (info.dwDevType & DIDEVTYPE_HID) != 0;
+ type = info.dwDevType & 0x00ff;
+ subtype = (info.dwDevType >> 8) & 0x00ff;
+ osd_printf_verbose(
+ "DirectInput: Device type=0x%02X subtype=0x%02X HID=%u\n",
+ type,
+ subtype,
+ hid ? "yes" : "no");
+ }
// 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());
+ result = dinput_api_helper::set_dword_property(m_device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %s.\n", name());
// 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 = std::min(dinput.caps.dwAxes, DWORD(8));
- dinput.caps.dwPOVs = std::min(dinput.caps.dwPOVs, DWORD(4));
- dinput.caps.dwButtons = std::min(dinput.caps.dwButtons, DWORD(128));
+ result = dinput_api_helper::set_dword_property(m_device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
+ if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
+ osd_printf_warning("DirectInput: Unable to reset saturation for joystick %s.\n", name());
// populate the axes
- for (axisnum = axiscount = 0; axiscount < dinput.caps.dwAxes && axisnum < 8; axisnum++)
+ input_item_id axisitems[8];
+ std::fill(std::begin(axisitems), std::end(axisitems), ITEM_ID_INVALID);
+ for (uint32_t axisnum = 0, axiscount = 0; (axiscount < m_caps.dwAxes) && (axisnum < 8); axisnum++)
{
- DIPROPRANGE dipr;
- std::string name;
-
// fetch the range of this axis
+ DIPROPRANGE dipr;
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);
+ result = m_device->GetProperty(DIPROP_RANGE, &dipr.diph);
if (result != DI_OK)
+ {
+ // this is normal when axes are skipped, e.g. X/Y/Z present, rX/rY absent, rZ present
+ osd_printf_verbose("DirectInput: Unable to get properties for joystick %s axis %u.\n", name(), axisnum);
continue;
+ }
- joystick.rangemin[axisnum] = dipr.lMin;
- joystick.rangemax[axisnum] = dipr.lMax;
+ m_joystick.rangemin[axisnum] = dipr.lMin;
+ m_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<LONG>,
- &joystick.state.lX + axisnum);
+ axisitems[axisnum] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
+ std::string_view(),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_joystick.state.lX + axisnum);
axiscount++;
}
- // populate the POVs
- for (uint32_t povnum = 0; povnum < dinput.caps.dwPOVs; povnum++)
+ // take a guess at which axes might be pedals depending on type and remap onto negative half of range
+ input_item_id pedalitems[3] = { ITEM_ID_INVALID, ITEM_ID_INVALID, ITEM_ID_INVALID };
+ if (DI8DEVTYPE_FLIGHT == type)
{
- std::string name;
+ // Rx/Ry are often used for brakes
+ bool const rxpedal = (ITEM_ID_INVALID != axisitems[3]) && !m_joystick.rangemin[3] && (0 < m_joystick.rangemax[3]);
+ bool const rypedal = (ITEM_ID_INVALID != axisitems[4]) && !m_joystick.rangemin[4] && (0 < m_joystick.rangemax[4]);
+ if (rxpedal && rypedal)
+ {
+ pedalitems[0] = axisitems[3];
+ m_joystick.rangemin[3] = m_joystick.rangemax[3];
+ m_joystick.rangemax[3] = -m_joystick.rangemax[3];
+ pedalitems[1] = axisitems[4];
+ m_joystick.rangemin[4] = m_joystick.rangemax[4];
+ m_joystick.rangemax[4] = -m_joystick.rangemax[4];
+ }
+ }
+ else if (DI8DEVTYPE_DRIVING == type)
+ {
+ bool const ypedal = (ITEM_ID_INVALID != axisitems[1]) && !m_joystick.rangemin[1] && (0 < m_joystick.rangemax[1]);
+ bool const rxpedal = (ITEM_ID_INVALID != axisitems[3]) && !m_joystick.rangemin[3] && (0 < m_joystick.rangemax[3]);
+ bool const rypedal = (ITEM_ID_INVALID != axisitems[4]) && !m_joystick.rangemin[4] && (0 < m_joystick.rangemax[4]);
+ bool const rzpedal = (ITEM_ID_INVALID != axisitems[5]) && !m_joystick.rangemin[5] && (0 < m_joystick.rangemax[5]);
+ bool const s0pedal = (ITEM_ID_INVALID != axisitems[6]) && !m_joystick.rangemin[6] && (0 < m_joystick.rangemax[6]);
+ if (DI8DEVTYPEDRIVING_DUALPEDALS == subtype)
+ {
+ // dual pedals are usually Y and Rz
+ if (ypedal && rzpedal)
+ {
+ pedalitems[0] = axisitems[1];
+ m_joystick.rangemin[1] = m_joystick.rangemax[1];
+ m_joystick.rangemax[1] = -m_joystick.rangemax[1];
+
+ pedalitems[1] = axisitems[5];
+ m_joystick.rangemin[5] = m_joystick.rangemax[5];
+ m_joystick.rangemax[5] = -m_joystick.rangemax[5];
+ }
+ }
+ else if (DI8DEVTYPEDRIVING_THREEPEDALS == subtype)
+ {
+ // triple pedals may be Y, Rz and slider 0, or Rx, Ry and Rz
+ if (ypedal && rzpedal && s0pedal)
+ {
+ pedalitems[0] = axisitems[1];
+ m_joystick.rangemin[1] = m_joystick.rangemax[1];
+ m_joystick.rangemax[1] = -m_joystick.rangemax[1];
+
+ pedalitems[1] = axisitems[5];
+ m_joystick.rangemin[5] = m_joystick.rangemax[5];
+ m_joystick.rangemax[5] = -m_joystick.rangemax[5];
+
+ pedalitems[2] = axisitems[6];
+ m_joystick.rangemin[6] = m_joystick.rangemax[6];
+ m_joystick.rangemax[6] = -m_joystick.rangemax[6];
+ }
+ else if (rxpedal && rypedal && rzpedal)
+ {
+ pedalitems[0] = axisitems[3];
+ m_joystick.rangemin[3] = m_joystick.rangemax[3];
+ m_joystick.rangemax[3] = -m_joystick.rangemax[3];
+
+ pedalitems[1] = axisitems[4];
+ m_joystick.rangemin[4] = m_joystick.rangemax[4];
+ m_joystick.rangemax[4] = -m_joystick.rangemax[4];
+
+ pedalitems[2] = axisitems[5];
+ m_joystick.rangemin[5] = m_joystick.rangemax[5];
+ m_joystick.rangemax[5] = -m_joystick.rangemax[5];
+ }
+ }
+ }
+
+ // populate the POV hats
+ input_item_id povitems[4][4];
+ for (auto &pov : povitems)
+ std::fill(std::begin(pov), std::end(pov), ITEM_ID_INVALID);
+ for (uint32_t povnum = 0; povnum < m_caps.dwPOVs; povnum++)
+ {
// 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<uintptr_t>(povnum * 4 + POVDIR_LEFT)));
+ povitems[povnum][0] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Left"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1LEFT),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(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<uintptr_t>(povnum * 4 + POVDIR_RIGHT)));
+ povitems[povnum][1] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Right"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1RIGHT),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(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<uintptr_t>(povnum * 4 + POVDIR_UP)));
+ povitems[povnum][2] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Up"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1UP),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(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<uintptr_t>(povnum * 4 + POVDIR_DOWN)));
+ povitems[povnum][3] = device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Down"),
+ std::string_view(),
+ input_item_id((povnum * 4) + ITEM_ID_HAT1DOWN),
+ &dinput_joystick_device::pov_get_state,
+ reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_DOWN)));
}
// populate the buttons
- for (uint32_t butnum = 0; butnum < dinput.caps.dwButtons; butnum++)
+ for (uint32_t butnum = 0; butnum < m_caps.dwButtons; butnum++)
{
- uintptr_t offset = reinterpret_cast<uintptr_t>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
- std::string name = dinput_module::device_item_name(this, offset, default_button_name(butnum), nullptr);
+ auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
input_item_id itemid;
-
if (butnum < INPUT_MAX_BUTTONS)
- itemid = static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum);
+ itemid = 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);
+ itemid = 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<BYTE>, &joystick.state.rgbButtons[butnum]);
- }
+ input_item_id const actual = device.add_item(
+ item_name(offset, default_button_name(butnum), nullptr),
+ std::string_view(),
+ itemid,
+ generic_button_get_state<BYTE>,
+ &m_joystick.state.rgbButtons[butnum]);
- return 0;
-}
+ // there are sixteen action button types
+ if (butnum < 16)
+ {
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, actual));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + butnum), SEQ_TYPE_STANDARD, seq);
-class joystick_input_dinput : public dinput_module
-{
-public:
- joystick_input_dinput() :
- dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
- {
+ // assign the first few buttons to UI actions and pedals
+ // TODO: don't map pedals for driving controls that have them present
+ switch (butnum)
+ {
+ case 0:
+ assignments.emplace_back(IPT_PEDAL, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_SELECT, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 1:
+ assignments.emplace_back(IPT_PEDAL2, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back((3 > m_caps.dwButtons) ? IPT_UI_CLEAR : IPT_UI_BACK, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 2:
+ assignments.emplace_back(IPT_PEDAL3, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_CLEAR, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 3:
+ assignments.emplace_back(IPT_UI_HELP, SEQ_TYPE_STANDARD, seq);
+ break;
+ }
+ }
}
- int dinput_devclass() override
+ // add default assignments depending on type
+ if (DI8DEVTYPE_FLIGHT == type)
{
-#if DIRECTINPUT_VERSION >= 0x0800
- return DI8DEVCLASS_GAMECTRL;
-#else
- return DIDEVTYPE_JOYSTICK;
-#endif
- }
+ if (((ITEM_ID_INVALID == axisitems[0]) || (ITEM_ID_INVALID == axisitems[1])) && (1 <= m_caps.dwPOVs))
+ {
+ // X or Y missing, fall back to using POV hat for navigation
+ add_directional_assignments(
+ assignments,
+ axisitems[0],
+ axisitems[1],
+ povitems[0][0],
+ povitems[0][1],
+ povitems[0][2],
+ povitems[0][3]);
+
+ // try using throttle for zoom/focus
+ if (ITEM_ID_INVALID != axisitems[2])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[2]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[2]));
+ if (ITEM_ID_INVALID != axisitems[5])
+ {
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, posseq);
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, negseq);
+ }
+ }
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
- {
- dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
- running_machine &machine = *static_cast<running_machine *>(ref);
- dinput_joystick_device *devinfo;
- int result = 0;
+ // try using twist/rudder for next/previous group
+ if (ITEM_ID_INVALID != axisitems[5])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[5]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[5]));
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, posseq);
+ }
+ }
+ else
+ {
+ // only use stick for primary navigation/movement
+ add_directional_assignments(
+ assignments,
+ axisitems[0],
+ axisitems[1],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+
+ // try using hat for secondary navigation functions
+ if (1 <= m_caps.dwPOVs)
+ {
+ input_seq const leftseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][0]));
+ input_seq const rightseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][1]));
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][2]));
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, povitems[0][3]));
+ if ((ITEM_ID_INVALID != axisitems[2]) || (ITEM_ID_INVALID != axisitems[5]))
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, rightseq);
+ assignments.emplace_back(IPT_UI_PAGE_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_PAGE_DOWN, SEQ_TYPE_STANDARD, downseq);
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, rightseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, leftseq);
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, rightseq);
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, downseq);
+ }
+ }
- if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
- cooperative_level = dinput_cooperative_level::BACKGROUND;
+ // try using throttle for zoom
+ if (ITEM_ID_INVALID != axisitems[2])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[2]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[2]));
+ if ((1 <= m_caps.dwPOVs) || (ITEM_ID_INVALID != axisitems[5]))
+ {
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, negseq);
+ if ((1 > m_caps.dwPOVs) || (ITEM_ID_INVALID == axisitems[5]))
+ {
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, posseq);
+ }
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, negseq);
+ }
+ }
- // 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;
+ // try using twist/rudder for focus next/previous
+ if (ITEM_ID_INVALID != axisitems[5])
+ {
+ input_seq const negseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[5]));
+ input_seq const posseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[5]));
+ if (1 <= m_caps.dwPOVs)
+ {
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, posseq);
+ if (ITEM_ID_INVALID == axisitems[2])
+ {
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, posseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, negseq);
+ }
+ }
+ else
+ {
+ assignments.emplace_back(IPT_UI_PREV_GROUP, SEQ_TYPE_STANDARD, negseq);
+ assignments.emplace_back(IPT_UI_NEXT_GROUP, SEQ_TYPE_STANDARD, posseq);
+ }
+ }
+ }
- result = devinfo->configure();
- if (result != 0)
+ // Z or slider 0 is usually the throttle - use one of them for joystick Z
+ add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { axisitems[2], axisitems[6] });
+
+ // use Z for the first two pedals if present
+ if (ITEM_ID_INVALID != axisitems[2])
{
- osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
+ // TODO: use Rx/Ry as well if they appear to be brakes
+ input_seq const pedal1seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, axisitems[2]));
+ input_seq const pedal2seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, axisitems[2]));
+ assignments.emplace_back(IPT_PEDAL, SEQ_TYPE_STANDARD, pedal1seq);
+ assignments.emplace_back(IPT_PEDAL2, SEQ_TYPE_STANDARD, pedal2seq);
+ }
+ }
+ else if (DI8DEVTYPE_DRIVING == type)
+ {
+ // use the wheel and D-pad for navigation and directional controls
+ add_directional_assignments(
+ assignments,
+ axisitems[0],
+ ITEM_ID_INVALID,
+ povitems[0][0],
+ povitems[0][1],
+ povitems[0][2],
+ povitems[0][3]);
+
+ // check subtype to determine how pedals should be assigned
+ if (DI8DEVTYPEDRIVING_COMBINEDPEDALS == subtype)
+ {
+ if (ITEM_ID_INVALID != axisitems[1])
+ {
+ // put first two pedals on opposite sides of Y axis
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, axisitems[1])));
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, axisitems[1])));
+
+ // use for previous/next group as well
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisitems[1])));
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisitems[1])));
+ }
+ }
+ else
+ {
+ // see if we have individual pedals
+ if (ITEM_ID_INVALID != pedalitems[0])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitems[0])));
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalitems[0])));
+ }
+ if (ITEM_ID_INVALID != pedalitems[1])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitems[1])));
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalitems[1])));
+ }
+ if (ITEM_ID_INVALID != pedalitems[2])
+ {
+ assignments.emplace_back(
+ IPT_PEDAL3,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitems[2])));
+ assignments.emplace_back(
+ IPT_UI_FOCUS_NEXT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalitems[2])));
+ }
+ }
+ }
+ else
+ {
+ // assume this is a gamepad - see if it looks like it has dual analog sticks
+ input_item_id stickaxes[2][2] = {
+ { axisitems[0], axisitems[1] },
+ { ITEM_ID_INVALID, ITEM_ID_INVALID } };
+ input_item_id pedalaxis = ITEM_ID_INVALID;
+ if ((ITEM_ID_INVALID != axisitems[2]) && (ITEM_ID_INVALID != axisitems[5]))
+ {
+ // assume Z/Rz are right stick
+ stickaxes[1][0] = axisitems[2];
+ stickaxes[1][1] = axisitems[5];
+ add_twin_stick_assignments(
+ assignments,
+ stickaxes[0][0],
+ stickaxes[0][1],
+ stickaxes[1][0],
+ stickaxes[1][1],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+ }
+ else if ((ITEM_ID_INVALID != axisitems[3]) && (ITEM_ID_INVALID != axisitems[4]))
+ {
+ // assume Rx/Ry are right stick and Z is triggers if present
+ stickaxes[1][0] = axisitems[3];
+ stickaxes[1][1] = axisitems[4];
+ pedalaxis = axisitems[2];
+ add_twin_stick_assignments(
+ assignments,
+ stickaxes[0][0],
+ stickaxes[0][1],
+ stickaxes[1][0],
+ stickaxes[1][1],
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID);
+ }
+ else
+ {
+ // if Z is present, use it as secondary Y
+ stickaxes[1][1] = axisitems[2];
}
- exit:
- return DIENUM_CONTINUE;
+ // try to find a "complete" stick for primary movement controls
+ input_item_id diraxis[2][2];
+ choose_primary_stick(diraxis, stickaxes[0][0], stickaxes[0][1], stickaxes[1][0], stickaxes[1][1]);
+ add_directional_assignments(
+ assignments,
+ diraxis[0][0],
+ diraxis[0][1],
+ povitems[0][0],
+ povitems[0][1],
+ povitems[0][2],
+ povitems[0][3]);
+
+ // assign a secondary stick axis to joystick Z
+ add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { diraxis[1][1], diraxis[1][0] });
+
+ // try to find a suitable axis to use for the first two pedals
+ add_assignment(
+ assignments,
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NEG,
+ { pedalaxis, diraxis[1][1], diraxis[0][1] });
+ add_assignment(
+ assignments,
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_POS,
+ { pedalaxis, diraxis[1][1], diraxis[0][1] });
+
+ // try to choose an axis for previous/next group
+ if (ITEM_ID_INVALID != pedalaxis)
+ {
+ // this is reversed because right trigger is negative direction
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, pedalaxis)));
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, pedalaxis)));
+ pedalaxis = ITEM_ID_INVALID;
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][0]))
+ {
+ // took secondary X
+ }
+
+ // use secondary Y for page up/down if available
+ consume_axis_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, diraxis[1][1]);
+
+ // put focus previous/next and zoom on secondary X if available
+ add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, diraxis[1][0]);
+ add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, diraxis[1][0]);
}
-};
-//============================================================
-// dinput_joystick_pov_get_state
-//============================================================
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+}
-static int32_t dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
+int32_t dinput_joystick_device::pov_get_state(void *device_internal, void *item_internal)
{
- dinput_joystick_device *devinfo = static_cast<dinput_joystick_device *>(device_internal);
- int povnum = reinterpret_cast<uintptr_t>(item_internal) / 4;
- int povdir = reinterpret_cast<uintptr_t>(item_internal) % 4;
- int32_t result = 0;
- DWORD pov;
+ auto *const devinfo = static_cast<dinput_joystick_device *>(device_internal);
+ int const povnum = uintptr_t(item_internal) / 4;
+ int const povdir = uintptr_t(item_internal) % 4;
// get the current state
- devinfo->module().poll_if_necessary(devinfo->machine());
- pov = devinfo->joystick.state.rgdwPOV[povnum];
+ DWORD const pov = devinfo->m_joystick.state.rgdwPOV[povnum];
// if invalid, return 0
if ((pov & 0xffff) == 0xffff)
- return result;
+ return 0;
// return the current state
switch (povdir)
{
- case POVDIR_LEFT: result = (pov >= 22500 && pov <= 31500); break;
- case POVDIR_RIGHT: result = (pov >= 4500 && pov <= 13500); break;
- case POVDIR_UP: result = (pov >= 31500 || pov <= 4500); break;
- case POVDIR_DOWN: result = (pov >= 13500 && pov <= 22500); break;
+ case POVDIR_LEFT: return (pov >= 22500) && (pov <= 31500);
+ case POVDIR_RIGHT: return (pov >= 4500) && (pov <= 13500);
+ case POVDIR_UP: return (pov >= 31500) || (pov <= 4500);
+ case POVDIR_DOWN: return (pov >= 13500) && (pov <= 22500);
}
- return result;
+
+ return 0;
+}
+
+
+//============================================================
+// dinput_api_helper - DirectInput API helper
+//============================================================
+
+dinput_api_helper::dinput_api_helper()
+{
+}
+
+dinput_api_helper::~dinput_api_helper()
+{
+}
+
+int dinput_api_helper::initialize()
+{
+ HRESULT result = DirectInput8Create(GetModuleHandleUni(), DIRECTINPUT_VERSION, IID_IDirectInput8, &m_dinput, nullptr);
+ if (result != DI_OK)
+ {
+ return result;
+ }
+
+ osd_printf_verbose("DirectInput: Using DirectInput %d\n", DIRECTINPUT_VERSION >> 8);
+ return 0;
+}
+
+
+std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_api_helper::open_device(
+ LPCDIDEVICEINSTANCE instance,
+ LPCDIDATAFORMAT format1,
+ LPCDIDATAFORMAT format2,
+ dinput_cooperative_level cooperative_level)
+{
+ HRESULT result;
+
+ // attempt to create a device
+ Microsoft::WRL::ComPtr<IDirectInputDevice8> device;
+ result = m_dinput->CreateDevice(instance->guidInstance, &device, nullptr);
+ if (result != DI_OK)
+ {
+ osd_printf_error("DirectInput: Unable to create device.\n");
+ return std::make_pair(nullptr, nullptr);
+ }
+
+ // attempt to set the data format
+ LPCDIDATAFORMAT format = format1;
+ result = device->SetDataFormat(format);
+ if ((result != DI_OK) && format2)
+ {
+ // use the secondary format if available
+ osd_printf_verbose("DirectInput: Error setting primary data format, trying secondary format.\n");
+ format = format2;
+ result = device->SetDataFormat(format);
+ }
+ if (result != DI_OK)
+ {
+ osd_printf_error("DirectInput: Unable to set data format.\n");
+ return std::make_pair(nullptr, nullptr);
+ }
+
+ // default window to the first window in the list
+ // For now, we always use the desktop window due to multiple issues:
+ // * MAME recreates windows on toggling fullscreen. DirectInput really doesn't like this.
+ // * DirectInput doesn't like the window used for D3D fullscreen exclusive mode.
+ // * With multiple windows, the first window needs to have focus when using foreground mode.
+ // This makes it impossible to use force feedback as that requires foreground exclusive mode.
+ // The only way to get around this would be to reopen devices on focus changes.
+ [[maybe_unused]] HWND window_handle;
+ DWORD di_cooperative_level;
+#if defined(OSD_WINDOWS)
+ auto const &window = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front());
+ bool const standalone_window = !window.attached_mode();
+#elif defined(SDLMAME_WIN32)
+ auto const &window = dynamic_cast<sdl_window_info &>(*osd_common_t::window_list().front());
+ bool const standalone_window = true;
+#endif
+ if (!standalone_window)
+ {
+ // in attached mode we have to ignore the caller and hook up to the desktop window
+ window_handle = GetDesktopWindow();
+ di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ }
+ else
+ {
+#if defined(OSD_WINDOWS)
+ window_handle = window.platform_window();
+#elif defined(SDLMAME_WIN32)
+ auto const sdlwindow = window.platform_window();
+ SDL_SysWMinfo info;
+ SDL_VERSION(&info.version);
+ if (!SDL_GetWindowWMInfo(sdlwindow, &info))
+ return std::make_pair(nullptr, nullptr);
+ window_handle = info.info.win.window;
+#endif
+ switch (cooperative_level)
+ {
+ case dinput_cooperative_level::BACKGROUND:
+ di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ break;
+ case dinput_cooperative_level::FOREGROUND:
+ //di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
+ di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ break;
+ default:
+ throw false;
+ }
+ }
+
+ // set the cooperative level
+ result = device->SetCooperativeLevel(GetDesktopWindow(), di_cooperative_level);
+ if (result != DI_OK)
+ {
+ osd_printf_error("DirectInput: Unable to set cooperative level.\n");
+ return std::make_pair(nullptr, nullptr);
+ }
+
+ // return new device
+ return std::make_pair(std::move(device), format);
+}
+
+
+std::string dinput_api_helper::make_id(LPCDIDEVICEINSTANCE instance)
+{
+ // use name, product GUID and instance GUID as identifier
+ return
+ text::from_tstring(instance->tszInstanceName) +
+ " product_" +
+ guid_to_string(instance->guidProduct) +
+ " instance_" +
+ guid_to_string(instance->guidInstance);
}
-#else
+} // namespace osd
+
+
+#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+#include "input_module.h"
+
+namespace osd {
+
+namespace {
+
MODULE_NOT_SUPPORTED(keyboard_input_dinput, OSD_KEYBOARDINPUT_PROVIDER, "dinput")
MODULE_NOT_SUPPORTED(mouse_input_dinput, OSD_MOUSEINPUT_PROVIDER, "dinput")
MODULE_NOT_SUPPORTED(joystick_input_dinput, OSD_JOYSTICKINPUT_PROVIDER, "dinput")
-#endif
-MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, keyboard_input_dinput)
-MODULE_DEFINITION(MOUSEINPUT_DINPUT, mouse_input_dinput)
-MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, joystick_input_dinput)
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
+
+MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, osd::keyboard_input_dinput)
+MODULE_DEFINITION(MOUSEINPUT_DINPUT, osd::mouse_input_dinput)
+MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, osd::joystick_input_dinput)