summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_dinput.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-01-29 03:02:02 +1100
committer Vas Crabb <vas@vastheman.com>2023-01-29 03:16:14 +1100
commit68472d3d72ea4bbc545c0669348172b4e96c7b41 (patch)
treee34fca0f55c977624148d1c806ecc6c44a5edd11 /src/osd/modules/input/input_dinput.cpp
parent01fcb2e0decf670a4cdee3d37b6f7ebde9b8f02b (diff)
Various input and OSD refactoring:
osd: Supply OSD object to modules on initialisation. Encapsulated some event handling in the OSD objects rather than leaving it in free functions. Put various stuff in namespaces. osd/modules/input: Enabled dinput, xinput and winhybrid modules for Windows SDL builds, and enabled background input for dinput and xinput (and by extension winhybrid) modules. Also fixed some COM and X11 resource leaks. osd/modules/input/input_sdl.cpp: Flipped SDL mouse button order to match Windows, and exposed vertical and horizontal scroll as Z and rZ axes. Moved SDL UI event handling out of input devices into OSD object. osd/modules/input_rawinput.cpp: Changed lightgun Z axis token so it's correctly identified as a relative axis (it maps to the scroll wheel equivalent). osd: Added an option to choose the network provider module. Mostly useful if you build with both TUN/TAP and pcap support included, or if you want to disable emulated networking completely. emu/input.cpp: Use a better strategy for assembling input code names that uses fewer temporary strings and doesn't require use of the non-Unicode-aware space trimming function (fixes MT08552). osd/modules/input_dinput.cpp: Improved polling logic. osd: Made various parts of the input code less dependent on concrete emu objects, and reduced inappropriately passing around the machine object. Made input modules less dependent on OSD implementation. Encapsulated some stuff and got rid of some vestigial newui and SDL1 support code. Cleaned up some interfaces. Moved OSD options classes to their own files. Prepare to remove main.h from emu.h - it's mostly used to get the application name, which the vast majority of emulated devices don't need to do.
Diffstat (limited to 'src/osd/modules/input/input_dinput.cpp')
-rw-r--r--src/osd/modules/input/input_dinput.cpp710
1 files changed, 407 insertions, 303 deletions
diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp
index 3461f9aad24..375beb32df1 100644
--- a/src/osd/modules/input/input_dinput.cpp
+++ b/src/osd/modules/input/input_dinput.cpp
@@ -8,71 +8,39 @@
#include "modules/osdmodule.h"
-#if defined(OSD_WINDOWS)
+#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-#include "emu.h"
+// emu
+#include "emu.h" // put this here before Windows headers define interface as a macro
#include "input_dinput.h"
-#include "winutil.h"
+#include "windows/winutil.h"
+
+// lib/util
+#include "util/corestr.h"
+
+#ifdef SDLMAME_WIN32
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_syswm.h>
+#endif
-#include <mutex>
+#include <algorithm>
+#include <iterator>
+#include <memory>
// standard windows headers
#include <initguid.h>
#include <tchar.h>
-namespace {
-
-using namespace Microsoft::WRL;
-
-//============================================================
-// dinput_joystick_pov_get_state
-//============================================================
-
-int32_t dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
-{
- auto *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;
-
- // get the current state
- devinfo->module().poll_if_necessary(devinfo->machine());
- const DWORD pov = devinfo->joystick.state.rgdwPOV[povnum];
-
- // if invalid, return 0
- if ((pov & 0xffff) == 0xffff)
- return result;
-
- // 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;
- }
- return result;
-}
-
+namespace osd {
-//============================================================
-// dinput_set_dword_property
-//============================================================
+namespace {
-HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice8> device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
+BOOL CALLBACK device_enum_interface_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
{
- DIPROPDWORD dipdw;
-
- 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);
+ return static_cast<device_enum_interface *>(ref)->device_enum_callback(instance);
}
@@ -80,76 +48,52 @@ HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice8> device, REFGUID pr
// 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>, public device_enum_interface
{
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>();
- int result = m_dinput_helper->initialize();
- if (result != 0)
+ 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 devices (result=%08X)\n", uint32_t(result));
+ m_dinput_helper.reset();
}
- static std::string device_item_name(dinput_device *devinfo, int offset, const char *defstring, const char *suffix)
+ virtual void input_init(running_machine &machine) override
{
- DIDEVICEOBJECTINSTANCE instance = { 0 };
- HRESULT result;
+ input_module_impl<dinput_device, osd_common_t>::input_init(machine);
- // query the key name
- 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 nullptr
+ HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), *this);
if (result != DI_OK)
- {
- if (defstring == nullptr)
- return nullptr;
-
- // Return the default value
- std::string result(defstring);
- if (suffix)
- result.append(" ").append(suffix);
- return result;
- }
-
- // convert the name to utf8
- std::string namestring = osd::text::from_tstring(instance.tszName);
-
- // if no suffix, return as-is
- if (suffix)
- namestring.append(" ").append(suffix);
- return namestring;
+ fatalerror("DirectInput: Unable to enumerate devices (result=%08X)\n", uint32_t(result));
}
protected:
virtual int dinput_devclass() = 0;
};
+
class keyboard_input_dinput : public dinput_module
{
public:
@@ -158,42 +102,29 @@ public:
{
}
- int dinput_devclass() override
+ virtual int dinput_devclass() override
{
return DI8DEVCLASS_KEYBOARD;
}
- 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, std::size(defname), "Scan%03d", keynum);
- name = device_item_name(devinfo, keynum, defname, nullptr);
-
- // add the item to the device
- devinfo->device()->add_item(name, itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
- }
+ 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));
- exit:
return DIENUM_CONTINUE;
}
};
+
class mouse_input_dinput : public dinput_module
{
public:
@@ -202,68 +133,40 @@ public:
{
}
- int dinput_devclass() override
+ virtual int dinput_devclass() override
{
return DI8DEVCLASS_POINTER;
}
- 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)
- goto exit;
-
- // 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;
- }
-
- // 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,
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &devinfo->mouse.lX + axisnum);
- }
-
- // populate the buttons
- for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
- {
- auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
-
- // add to the mouse device
- std::string name = device_item_name(devinfo, offset, default_button_name(butnum).c_str(), nullptr);
- devinfo->device()->add_item(
- name,
- static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
- generic_button_get_state<BYTE>,
- &devinfo->mouse.rgbButtons[butnum]);
- }
+ 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));
- exit:
return DIENUM_CONTINUE;
-
- error:
- if (devinfo)
- devicelist().free_device(*devinfo);
- goto exit;
}
};
@@ -276,33 +179,39 @@ public:
{
}
- int dinput_devclass() override
+ virtual int dinput_devclass() override
{
return DI8DEVCLASS_GAMECTRL;
}
- BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) 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;
-
- if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
- cooperative_level = dinput_cooperative_level::BACKGROUND;
-
// 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));
- }
+ 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;
}
};
@@ -314,16 +223,18 @@ public:
// dinput_device - base directinput device
//============================================================
-dinput_device::dinput_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module) :
- device_info(machine, std::move(name), std::move(id), deviceclass, module),
- dinput({nullptr})
-{
-}
-
-dinput_device::~dinput_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)
{
- if (dinput.device)
- dinput.device.Reset();
}
HRESULT dinput_device::poll_dinput(LPVOID pState) const
@@ -331,45 +242,91 @@ HRESULT dinput_device::poll_dinput(LPVOID pState) const
HRESULT result;
// first poll the device, then get the state
- dinput.device->Poll();
-
- // GetDeviceState returns the immediate state
- result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
+ result = m_device->Poll();
// handle lost inputs here
- if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
+ if ((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
{
- result = dinput.device->Acquire();
- if (result == DI_OK)
- result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
+ 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
+{
+ // 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;
+}
+
//============================================================
// dinput_keyboard_device - directinput keyboard device
//============================================================
-dinput_keyboard_device::dinput_keyboard_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
- dinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+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 } })
{
}
-// Polls the direct input immediate state
void dinput_keyboard_device::poll()
{
+ // poll the DirectInput immediate state
std::lock_guard<std::mutex> scope_lock(m_device_lock);
-
- // Poll the state
- dinput_device::poll_dinput(&keyboard.state);
+ poll_dinput(&m_keyboard.state);
}
void dinput_keyboard_device::reset()
{
- memset(&keyboard.state, 0, sizeof(keyboard.state));
+ memset(&m_keyboard.state, 0, sizeof(m_keyboard.state));
+}
+
+void dinput_keyboard_device::configure(input_device &device)
+{
+ // populate it
+ char defname[20];
+ for (int keynum = 0; keynum < MAX_KEYS; keynum++)
+ {
+ 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),
+ itemid,
+ generic_button_get_state<std::uint8_t>,
+ &m_keyboard.state[keynum]);
+ }
}
@@ -377,26 +334,63 @@ void dinput_keyboard_device::reset()
// dinput_mouse_device - directinput mouse device
//============================================================
-dinput_mouse_device::dinput_mouse_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
- dinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_MOUSE, module),
- mouse({0})
+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})
{
+ // 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_mouse_device::poll()
{
// poll
- dinput_device::poll_dinput(&mouse);
-
- // scale the axis data
- mouse.lX *= osd::INPUT_RELATIVE_PER_PIXEL;
- mouse.lY *= osd::INPUT_RELATIVE_PER_PIXEL;
- mouse.lZ *= osd::INPUT_RELATIVE_PER_PIXEL;
+ if (poll_dinput(&m_mouse) == DI_OK)
+ {
+ // scale the axis data
+ m_mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
+ m_mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
+ m_mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
+ }
}
void dinput_mouse_device::reset()
{
- memset(&mouse, 0, sizeof(mouse));
+ memset(&m_mouse, 0, sizeof(m_mouse));
+}
+
+void dinput_mouse_device::configure(input_device &device)
+{
+ // populate the axes
+ for (int axisnum = 0; axisnum < m_caps.dwAxes; axisnum++)
+ {
+ // 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),
+ input_item_id(ITEM_ID_XAXIS + axisnum),
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX + axisnum);
+ }
+
+ // populate the buttons
+ for (int butnum = 0; butnum < m_caps.dwButtons; butnum++)
+ {
+ auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
+
+ // add to the mouse device
+ device.add_item(
+ item_name(offset, default_button_name(butnum), nullptr),
+ input_item_id(ITEM_ID_BUTTON1 + butnum),
+ generic_button_get_state<BYTE>,
+ &m_mouse.rgbButtons[butnum]);
+ }
}
@@ -404,64 +398,58 @@ void dinput_mouse_device::reset()
// dinput_joystick_device - directinput joystick device
//============================================================
-dinput_joystick_device::dinput_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
- dinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}})
+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 } })
{
+ // 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));
}
void dinput_joystick_device::reset()
{
- memset(&joystick.state, 0, sizeof(joystick.state));
- std::fill(std::begin(joystick.state.rgdwPOV), std::end(joystick.state.rgdwPOV), 0xffff);
+ memset(&m_joystick.state, 0, sizeof(m_joystick.state));
+ std::fill(std::begin(m_joystick.state.rgdwPOV), std::end(m_joystick.state.rgdwPOV), 0xffff);
}
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++)
+ 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++)
+ {
+ LONG *const axis = &m_joystick.state.lX + axisnum;
+ *axis = normalize_absolute_axis(*axis, m_joystick.rangemin[axisnum], m_joystick.rangemax[axisnum]);
+ }
}
}
-int dinput_joystick_device::configure()
+void dinput_joystick_device::configure(input_device &device)
{
HRESULT result;
- 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);
+ 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 %d (%s)\n", devindex, name());
+ 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);
+ 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 %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));
+ osd_printf_warning("DirectInput: Unable to reset saturation for joystick %s.\n", name());
// populate the axes
- for (uint32_t axisnum = 0, axiscount = 0; axiscount < dinput.caps.dwAxes && axisnum < 8; axisnum++)
+ for (uint32_t axisnum = 0, axiscount = 0; axiscount < m_caps.dwAxes && axisnum < 8; axisnum++)
{
// fetch the range of this axis
DIPROPRANGE dipr;
@@ -469,67 +457,62 @@ int dinput_joystick_device::configure()
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)
+ {
+ 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
- std::string name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr);
- device()->add_item(
- name,
- static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &joystick.state.lX + axisnum);
+ device.add_item(
+ item_name(offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
+ 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++)
+ for (uint32_t povnum = 0; povnum < m_caps.dwPOVs; povnum++)
{
- std::string name;
-
// left
- name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum).c_str(), "Left");
- device()->add_item(
- name,
+ device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Left"),
input_item_id(povnum * 4 + ITEM_ID_HAT1LEFT),
- dinput_joystick_pov_get_state,
+ &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).c_str(), "Right");
- device()->add_item(
- name,
+ device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Right"),
input_item_id(povnum * 4 + ITEM_ID_HAT1RIGHT),
- dinput_joystick_pov_get_state,
+ &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).c_str(), "Up");
- device()->add_item(
- name,
+ device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Up"),
input_item_id(povnum * 4 + ITEM_ID_HAT1UP),
- dinput_joystick_pov_get_state,
+ &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).c_str(), "Down");
- device()->add_item(
- name,
+ device.add_item(
+ item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Down"),
input_item_id(povnum * 4 + ITEM_ID_HAT1DOWN),
- dinput_joystick_pov_get_state,
+ &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++)
{
auto 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).c_str(), nullptr);
input_item_id itemid;
if (butnum < INPUT_MAX_BUTTONS)
@@ -539,7 +522,35 @@ int dinput_joystick_device::configure()
else
itemid = ITEM_ID_OTHER_SWITCH;
- device()->add_item(name, itemid, generic_button_get_state<BYTE>, &joystick.state.rgbButtons[butnum]);
+ device.add_item(
+ item_name(offset, default_button_name(butnum), nullptr),
+ itemid,
+ generic_button_get_state<BYTE>,
+ &m_joystick.state.rgbButtons[butnum]);
+ }
+}
+
+int32_t dinput_joystick_device::pov_get_state(void *device_internal, void *item_internal)
+{
+ 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();
+ DWORD const pov = devinfo->m_joystick.state.rgdwPOV[povnum];
+
+ // if invalid, return 0
+ if ((pov & 0xffff) == 0xffff)
+ return 0;
+
+ // return the current state
+ switch (povdir)
+ {
+ 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 0;
@@ -573,25 +584,118 @@ int dinput_api_helper::initialize()
}
-HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const
+HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface &enumerate_interface) const
{
- device_enum_interface::dinput_callback_context ctx;
- ctx.self = enumerate_interface;
- ctx.state = state;
+ return m_dinput->EnumDevices(devclass, device_enum_interface_callback, &enumerate_interface, DIEDFL_ATTACHEDONLY);
+}
+
- return m_dinput->EnumDevices(devclass, device_enum_interface::enum_callback, &ctx, DIEDFL_ATTACHEDONLY);
+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.GetAddressOf(), 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
+ HWND window_handle;
+ DWORD di_cooperative_level;
+#if defined(OSD_WINDOWS)
+ auto const window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front());
+ bool const standalone_window = window && !window->attached_mode();
+#elif defined(SDLMAME_WIN32)
+ auto const window = std::static_pointer_cast<sdl_window_info>(osd_common_t::s_window_list.front());
+ bool const standalone_window = bool(window);
+#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);
+ SDL_GetWindowWMInfo(sdlwindow, &info);
+ 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;
+ break;
+ default:
+ throw false;
+ }
+ }
+
+ // set the cooperative level
+ result = device->SetCooperativeLevel(window_handle, 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);
}
-#else // defined(OSD_WINDOWS)
+} // 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 // defined(OSD_WINDOWS)
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
-MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, keyboard_input_dinput)
-MODULE_DEFINITION(MOUSEINPUT_DINPUT, mouse_input_dinput)
-MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, joystick_input_dinput)
+MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, osd::keyboard_input_dinput)
+MODULE_DEFINITION(MOUSEINPUT_DINPUT, osd::mouse_input_dinput)
+MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, osd::joystick_input_dinput)