summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_dinput.cpp
diff options
context:
space:
mode:
author ImJezze <jezze@gmx.net>2016-03-02 21:49:49 +0100
committer ImJezze <jezze@gmx.net>2016-03-02 21:49:49 +0100
commit9fe9f6d93e672bcd926f9e7461774bc9cc22e094 (patch)
tree3911b611dd010a4108b90fb8b8c82116eec21117 /src/osd/modules/input/input_dinput.cpp
parentdbdf21ee465acadf3e643d62d6bedfcc297ada85 (diff)
parent1914702e6fae052668df5b068a502bca57c9a3b0 (diff)
Merge remote-tracking branch 'refs/remotes/mamedev/master'
# Resolved Conflicts: # src/osd/modules/render/d3d/d3dhlsl.cpp # src/osd/windows/winmain.cpp
Diffstat (limited to 'src/osd/modules/input/input_dinput.cpp')
-rw-r--r--src/osd/modules/input/input_dinput.cpp683
1 files changed, 683 insertions, 0 deletions
diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp
new file mode 100644
index 00000000000..a80eb4c994d
--- /dev/null
+++ b/src/osd/modules/input/input_dinput.cpp
@@ -0,0 +1,683 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, Brad Hughes
+//============================================================
+//
+// input_dinput.cpp - Windows DirectInput support
+//
+//============================================================
+
+#include "input_module.h"
+#include "modules/osdmodule.h"
+
+#if defined(OSD_WINDOWS)
+
+// standard windows headers
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winioctl.h>
+#include <tchar.h>
+
+// undef WINNT for dinput.h to prevent duplicate definition
+#undef WINNT
+#include <dinput.h>
+#undef interface
+
+#include <mutex>
+#include <thread>
+
+// MAME headers
+#include "emu.h"
+#include "osdepend.h"
+#include "ui/ui.h"
+#include "strconv.h"
+
+// MAMEOS headers
+#include "winmain.h"
+#include "window.h"
+#include "winutil.h"
+
+#include "input_common.h"
+#include "input_windows.h"
+
+#define STRUCTSIZE(x) (m_dinput_version == 0x0300) ? sizeof(x##_DX3) : sizeof(x)
+
+static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal);
+
+//============================================================
+// dinput_set_dword_property
+//============================================================
+
+static HRESULT dinput_set_dword_property(LPDIRECTINPUTDEVICE device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
+{
+ 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 IDirectInputDevice_SetProperty(device, property_guid, &dipdw.diph);
+}
+
+//============================================================
+// dinput_device - base directinput device
+//============================================================
+
+// DirectInput-specific information about a device
+struct dinput_api_state
+{
+ LPDIRECTINPUTDEVICE device;
+ LPDIRECTINPUTDEVICE2 device2;
+ DIDEVCAPS caps;
+ LPCDIDATAFORMAT format;
+};
+
+class dinput_device : public device_info
+{
+public:
+ dinput_api_state dinput;
+
+ dinput_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
+ : device_info(machine, name, deviceclass, module),
+ dinput({0})
+ {
+ }
+
+protected:
+ HRESULT poll_dinput(LPVOID pState)
+ {
+ HRESULT result;
+
+ // first poll the device, then get the state
+ if (dinput.device2 != NULL)
+ IDirectInputDevice2_Poll(dinput.device2);
+
+ // GetDeviceState returns the immediate state
+ result = IDirectInputDevice_GetDeviceState(dinput.device, dinput.format->dwDataSize, pState);
+
+ // handle lost inputs here
+ if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
+ {
+ result = IDirectInputDevice_Acquire(dinput.device);
+ if (result == DI_OK)
+ result = IDirectInputDevice_GetDeviceState(dinput.device, dinput.format->dwDataSize, pState);
+ }
+
+ return result;
+ }
+};
+
+//============================================================
+// dinput_keyboard_device - directinput keyboard device
+//============================================================
+
+class dinput_keyboard_device : public dinput_device
+{
+private:
+ HANDLE m_dataEvent;
+ HANDLE m_exitEvent;
+ std::mutex m_device_lock;
+
+public:
+ keyboard_state keyboard;
+
+ dinput_keyboard_device(running_machine &machine, const char *name, input_module &module)
+ : dinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
+ keyboard({0})
+ {
+ }
+
+ // Polls the direct input immediate state
+ void poll() override
+ {
+ std::lock_guard<std::mutex> scope_lock(m_device_lock);
+
+ // Poll the state
+ dinput_device::poll_dinput(&keyboard.state);
+ }
+
+ void reset() override
+ {
+ memset(&keyboard, 0, sizeof(keyboard));
+ }
+};
+
+//============================================================
+// dinput_module - base directinput module
+//============================================================
+
+class dinput_module : public wininput_module
+{
+private:
+ LPDIRECTINPUT m_dinput;
+ int m_dinput_version;
+ int didevtype_keyboard;
+ int didevtype_mouse;
+
+public:
+ dinput_module(const char* type, const char* name)
+ : wininput_module(type, name)
+ {
+ }
+
+ int init_internal() override
+ {
+ HRESULT result = S_OK;
+
+#if DIRECTINPUT_VERSION >= 0x800
+ m_dinput_version = DIRECTINPUT_VERSION;
+ result = DirectInput8Create(GetModuleHandleUni(), m_dinput_version, IID_IDirectInput8, (void **)&m_dinput, NULL);
+ if (result != DI_OK)
+ {
+ m_dinput_version = 0;
+ return result;
+ }
+#else
+ // first attempt to initialize DirectInput at the current version
+ m_dinput_version = DIRECTINPUT_VERSION;
+ result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
+ if (result != DI_OK)
+ {
+ // if that fails, try version 5
+ m_dinput_version = 0x0500;
+ result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
+ if (result != DI_OK)
+ {
+ // if that fails, try version 3
+ m_dinput_version = 0x0300;
+ result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
+ if (result != DI_OK)
+ {
+ m_dinput_version = 0;
+ return result;
+ }
+ }
+ }
+#endif
+
+ osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
+ return 0;
+ }
+
+ void exit() override
+ {
+ wininput_module::exit();
+ }
+
+ virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
+
+ struct dinput_callback_context
+ {
+ dinput_module * self;
+ running_machine * machine;
+ };
+
+ static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
+ {
+ return ((dinput_callback_context*)ref)->self->device_enum_callback(instance, ((dinput_callback_context*)ref)->machine);
+ }
+ void input_init(running_machine &machine) override
+ {
+ dinput_callback_context context = { this, &machine };
+
+ HRESULT result = IDirectInput_EnumDevices(m_dinput, dinput_devclass(), enum_callback, &context, DIEDFL_ATTACHEDONLY);
+ if (result != DI_OK)
+ fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", (UINT32)result);
+ }
+
+protected:
+ virtual int dinput_devclass() = 0;
+
+ template <class TDevice>
+ TDevice* create_dinput_device(
+ running_machine &machine,
+ LPCDIDEVICEINSTANCE instance,
+ LPCDIDATAFORMAT format1,
+ LPCDIDATAFORMAT format2,
+ DWORD cooperative_level)
+ {
+ HRESULT result;
+
+ // convert instance name to utf8
+ auto osd_deleter = [](void *ptr) { osd_free(ptr); };
+ auto utf8_instance_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(instance->tszInstanceName), osd_deleter);
+
+ // allocate memory for the device object
+ TDevice* devinfo = devicelist()->create_device<TDevice>(machine, utf8_instance_name.get(), *this);
+
+ // attempt to create a device
+ result = IDirectInput_CreateDevice(m_dinput, WRAP_REFIID(instance->guidInstance), &devinfo->dinput.device, NULL);
+ if (result != DI_OK)
+ goto error;
+
+ // try to get a version 2 device for it
+ result = IDirectInputDevice_QueryInterface(devinfo->dinput.device, WRAP_REFIID(IID_IDirectInputDevice2), (void **)&devinfo->dinput.device2);
+ if (result != DI_OK)
+ devinfo->dinput.device2 = NULL;
+
+ // get the caps
+ devinfo->dinput.caps.dwSize = STRUCTSIZE(DIDEVCAPS);
+ result = IDirectInputDevice_GetCapabilities(devinfo->dinput.device, &devinfo->dinput.caps);
+ if (result != DI_OK)
+ goto error;
+
+ // attempt to set the data format
+ devinfo->dinput.format = format1;
+ result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device, devinfo->dinput.format);
+ if (result != DI_OK)
+ {
+ // use the secondary format if available
+ if (format2 != NULL)
+ {
+ devinfo->dinput.format = format2;
+ result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device, devinfo->dinput.format);
+ }
+ if (result != DI_OK)
+ goto error;
+ }
+
+ // set the cooperative level
+ result = IDirectInputDevice_SetCooperativeLevel(devinfo->dinput.device, win_window_list->m_hwnd, cooperative_level);
+ if (result != DI_OK)
+ goto error;
+ return devinfo;
+
+ error:
+ devicelist()->free_device(devinfo);
+ return NULL;
+ }
+
+ std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix)
+ {
+ DIDEVICEOBJECTINSTANCE instance = { 0 };
+ HRESULT result;
+
+ // query the key name
+ instance.dwSize = STRUCTSIZE(DIDEVICEOBJECTINSTANCE);
+ result = IDirectInputDevice_GetObjectInfo(devinfo->dinput.device, &instance, offset, DIPH_BYOFFSET);
+
+ // if we got an error and have no default string, just return NULL
+ if (result != DI_OK)
+ {
+ if (defstring == nullptr)
+ return nullptr;
+
+ // Return the default value
+ return std::string(defstring);
+ }
+
+ auto osd_free_deleter = [](char *p) { osd_free(p); };
+
+ // convert the name to utf8
+ auto namestring = std::unique_ptr<char, decltype(osd_free_deleter)>(utf8_from_tstring(instance.tszName), osd_free_deleter);
+
+ // if no suffix, return as-is
+ if (suffix == nullptr)
+ {
+ return std::string(namestring.get());
+ }
+
+ // otherwise, allocate space to add the suffix
+ auto combined = std::make_unique<char[]>(strlen(namestring.get()) + 1 + _tcslen(suffix) + 1);
+
+ // convert the suffix to utf8
+ auto suffix_utf8 = std::unique_ptr<char, decltype(osd_free_deleter)>(utf8_from_tstring(suffix), osd_free_deleter);
+
+ // Concat the name and suffix
+ strcpy(combined.get(), namestring.get());
+ strcat(combined.get(), " ");
+ strcat(combined.get(), suffix_utf8.get());
+
+ return std::string(combined.get());
+ }
+};
+
+class keyboard_input_dinput : public dinput_module
+{
+public:
+ keyboard_input_dinput() :
+ dinput_module(OSD_KEYBOARDINPUT_PROVIDER, "dinput")
+ {
+ }
+
+ int dinput_devclass() override
+ {
+#if DIRECTINPUT_VERSION >= 0x800
+ return DI8DEVCLASS_KEYBOARD;
+#else
+ return DIDEVTYPE_KEYBOARD;
+#endif
+ }
+
+ BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ {
+ running_machine &machine = *(running_machine *)ref;
+ dinput_keyboard_device *devinfo;
+ int keynum;
+
+ // allocate and link in a new device
+ devinfo = create_dinput_device<dinput_keyboard_device>(machine, instance, &c_dfDIKeyboard, NULL, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
+ if (devinfo == NULL)
+ 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, NULL);
+
+ // add the item to the device
+ devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
+ }
+
+ exit:
+ return DIENUM_CONTINUE;
+ }
+};
+
+class dinput_mouse_device : public dinput_device
+{
+public:
+ mouse_state mouse;
+
+ dinput_mouse_device(running_machine &machine, const char *name, input_module &module)
+ : dinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
+ mouse({0})
+ {
+ }
+
+ void poll() override
+ {
+ // 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 reset() override
+ {
+ memset(&mouse, 0, sizeof(mouse));
+ }
+};
+
+class mouse_input_dinput : public dinput_module
+{
+public:
+ mouse_input_dinput() :
+ dinput_module(OSD_MOUSEINPUT_PROVIDER, "dinput")
+ {
+ }
+
+ int dinput_devclass() override
+ {
+#if DIRECTINPUT_VERSION >= 0x800
+ return DI8DEVCLASS_POINTER;
+#else
+ return DIDEVTYPE_MOUSE;
+#endif
+ }
+
+ BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ {
+ dinput_mouse_device *devinfo = NULL;
+ running_machine &machine = *(running_machine *)ref;
+ int axisnum, butnum;
+ HRESULT result;
+
+ // allocate and link in a new device
+ devinfo = create_dinput_device<dinput_mouse_device>(machine, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
+ if (devinfo == NULL)
+ 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 %d (%s)\n", devicelist()->size(), devinfo->name());
+ goto error;
+ }
+
+ // cap the number of axes and buttons based on the format
+ devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 3);
+ devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, (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], NULL);
+ devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
+ }
+
+ // populate the buttons
+ for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
+ {
+ FPTR offset = (FPTR)(&((DIMOUSESTATE *)NULL)->rgbButtons[butnum]);
+
+ // add to the mouse device
+ std::string name = device_item_name(devinfo, offset, default_button_name(butnum), NULL);
+ devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
+ }
+
+ exit:
+ return DIENUM_CONTINUE;
+
+ error:
+ if (devinfo != NULL)
+ devicelist()->free_device(devinfo);
+ goto exit;
+ }
+};
+
+// state information for a joystick; DirectInput state must be first element
+struct dinput_joystick_state
+{
+ DIJOYSTATE state;
+ LONG rangemin[8];
+ LONG rangemax[8];
+};
+
+class dinput_joystick_device : public dinput_device
+{
+public:
+ dinput_joystick_state joystick;
+
+ dinput_joystick_device(running_machine &machine, const char *name, input_module &module)
+ : dinput_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
+ joystick({0})
+ {
+ }
+
+ void reset() override
+ {
+ memset(&joystick, 0, sizeof(joystick));
+ }
+
+ void poll() override
+ {
+ int axisnum;
+
+ // poll the device first
+ dinput_device::poll_dinput(&joystick.state);
+
+ // normalize axis values
+ for (axisnum = 0; axisnum < 8; axisnum++)
+ {
+ LONG *axis = (&joystick.state.lX) + axisnum;
+ *axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
+ }
+ }
+};
+
+class joystick_input_dinput : public dinput_module
+{
+public:
+ joystick_input_dinput() :
+ dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
+ {
+ }
+
+ int dinput_devclass() override
+ {
+#if DIRECTINPUT_VERSION >= 0x800
+ return DI8DEVCLASS_GAMECTRL;
+#else
+ return DIDEVTYPE_JOYSTICK;
+#endif
+ }
+
+ BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
+ {
+ DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
+ int axisnum, axiscount, povnum, butnum;
+ running_machine &machine = *(running_machine *)ref;
+ dinput_joystick_device *devinfo;
+ HRESULT result;
+
+ if (win_window_list != NULL && win_window_list->win_has_menu()) {
+ cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
+ }
+ // allocate and link in a new device
+ devinfo = create_dinput_device<dinput_joystick_device>(machine, instance, &c_dfDIJoystick, NULL, cooperative_level);
+ if (devinfo == NULL)
+ goto exit;
+
+ // set absolute mode
+ result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_ABS);
+ if (result != DI_OK && result != DI_PROPNOEFFECT)
+ osd_printf_warning("DirectInput: Unable to set absolute mode for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
+
+ // turn off deadzone; we do our own calculations
+ result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
+ if (result != DI_OK && result != DI_PROPNOEFFECT)
+ osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
+
+ // turn off saturation; we do our own calculations
+ result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
+ if (result != DI_OK && result != DI_PROPNOEFFECT)
+ osd_printf_warning("DirectInput: Unable to reset saturation for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
+
+ // cap the number of axes, POVs, and buttons based on the format
+ devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 8);
+ devinfo->dinput.caps.dwPOVs = MIN(devinfo->dinput.caps.dwPOVs, 4);
+ devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, 128);
+
+ // populate the axes
+ for (axisnum = axiscount = 0; axiscount < devinfo->dinput.caps.dwAxes && axisnum < 8; axisnum++)
+ {
+ DIPROPRANGE dipr;
+ std::string name;
+
+ // fetch the range of this axis
+ dipr.diph.dwSize = sizeof(dipr);
+ dipr.diph.dwHeaderSize = sizeof(dipr.diph);
+ dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
+ dipr.diph.dwHow = DIPH_BYOFFSET;
+ result = IDirectInputDevice_GetProperty(devinfo->dinput.device, DIPROP_RANGE, &dipr.diph);
+ if (result != DI_OK)
+ continue;
+
+ devinfo->joystick.rangemin[axisnum] = dipr.lMin;
+ devinfo->joystick.rangemax[axisnum] = dipr.lMax;
+
+ // populate the item description as well
+ name = device_item_name(devinfo, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL);
+ devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->joystick.state.lX + axisnum);
+
+ axiscount++;
+ }
+
+ // populate the POVs
+ for (povnum = 0; povnum < devinfo->dinput.caps.dwPOVs; povnum++)
+ {
+ std::string name;
+
+ // left
+ name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L"));
+ devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_LEFT));
+
+ // right
+ name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R"));
+ devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_RIGHT));
+
+ // up
+ name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U"));
+ devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_UP));
+
+ // down
+ name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D"));
+ devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_DOWN));
+ }
+
+ // populate the buttons
+ for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
+ {
+ FPTR offset = (FPTR)(&((DIJOYSTATE2 *)NULL)->rgbButtons[butnum]);
+ std::string name = device_item_name(devinfo, offset, default_button_name(butnum), NULL);
+
+ input_item_id itemid;
+
+ if (butnum < INPUT_MAX_BUTTONS)
+ itemid = (input_item_id)(ITEM_ID_BUTTON1 + butnum);
+ else if (butnum < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
+ itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
+ else
+ itemid = ITEM_ID_OTHER_SWITCH;
+
+ devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->joystick.state.rgbButtons[butnum]);
+ }
+
+ exit:
+ return DIENUM_CONTINUE;
+ }
+};
+
+//============================================================
+// dinput_joystick_pov_get_state
+//============================================================
+
+static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
+{
+ dinput_joystick_device *devinfo = (dinput_joystick_device *)device_internal;
+ int povnum = (FPTR)item_internal / 4;
+ int povdir = (FPTR)item_internal % 4;
+ INT32 result = 0;
+ DWORD pov;
+
+ // get the current state
+ devinfo->module().poll_if_necessary(devinfo->machine());
+ 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;
+}
+
+#else
+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) \ No newline at end of file