diff options
Diffstat (limited to 'src/osd/modules/input/input_xinput.cpp')
-rw-r--r-- | src/osd/modules/input/input_xinput.cpp | 406 |
1 files changed, 154 insertions, 252 deletions
diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp index 8c7800c8c35..753fd49a729 100644 --- a/src/osd/modules/input/input_xinput.cpp +++ b/src/osd/modules/input/input_xinput.cpp @@ -23,224 +23,199 @@ // MAME headers #include "emu.h" #include "osdepend.h" -#include "ui/ui.h" // MAMEOS headers #include "winutil.h" #include "winmain.h" -#include "window.h" #include "input_common.h" #include "input_windows.h" +#include "input_xinput.h" -#define XINPUT_MAX_POV 4 -#define XINPUT_MAX_BUTTONS 10 -#define XINPUT_MAX_AXIS 4 -#define XINPUT_AXIS_MINVALUE -32767 -#define XINPUT_AXIS_MAXVALUE 32767 - -// default axis names -static const char *const xinput_axis_name[] = +xinput_api_helper::xinput_api_helper() +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + : XInputGetState("XInputGetState", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names)) + , XInputGetCapabilities("XInputGetCapabilities", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names)) +#endif { - "LSX", - "LSY", - "RSX", - "RSY" -}; +} -static const input_item_id xinput_axis_ids[] = +int xinput_api_helper::initialize() { - ITEM_ID_XAXIS, - ITEM_ID_YAXIS, - ITEM_ID_RXAXIS, - ITEM_ID_RYAXIS -}; - -static const USHORT xinput_pov_dir[] = { - XINPUT_GAMEPAD_DPAD_UP, - XINPUT_GAMEPAD_DPAD_DOWN, - XINPUT_GAMEPAD_DPAD_LEFT, - XINPUT_GAMEPAD_DPAD_RIGHT -}; - -static const char *const xinput_pov_names[] = { - "DPAD Up", - "DPAD Down", - "DPAD Left", - "DPAD Right" -}; +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + int status; + status = XInputGetState.initialize(); + if (status != 0) + { + osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetState.name(), status); + return -1; + } -static const USHORT xinput_buttons[] = { - XINPUT_GAMEPAD_A, - XINPUT_GAMEPAD_B, - XINPUT_GAMEPAD_X, - XINPUT_GAMEPAD_Y, - XINPUT_GAMEPAD_LEFT_SHOULDER, - XINPUT_GAMEPAD_RIGHT_SHOULDER, - XINPUT_GAMEPAD_START, - XINPUT_GAMEPAD_BACK, - XINPUT_GAMEPAD_LEFT_THUMB, - XINPUT_GAMEPAD_RIGHT_THUMB, -}; + status = XInputGetCapabilities.initialize(); + if (status != 0) + { + osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetCapabilities.name(), status); + return -1; + } +#endif -static const char *const xinput_button_names[] = { - "A", - "B", - "X", - "Y", - "Left Shoulder", - "Right Shoulder", - "Start", - "Back", - "Left Thumb", - "Right Thumb" -}; + return 0; +} -struct gamepad_state +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +// Pass-through functions for Universal Windows +inline DWORD xinput_api_helper::XInputGetState(DWORD dwUserindex, XINPUT_STATE *pState) { - BYTE rgbButtons[XINPUT_MAX_BUTTONS]; - BYTE rgbPov[XINPUT_MAX_POV]; - BYTE bLeftTrigger; - BYTE bRightTrigger; - LONG sThumbLX; - LONG sThumbLY; - LONG sThumbRX; - LONG sThumbRY; -}; + return ::XInputGetState(dwUserindex, pState); +} -// state information for a gamepad; state must be first element -struct xinput_api_state +inline DWORD xinput_api_helper::XInputGetCapabilities(DWORD dwUserindex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities) { - UINT32 playerIndex; - XINPUT_STATE xstate; - XINPUT_CAPABILITIES caps; -}; + return ::XInputGetCapabilities(dwUserindex, dwFlags, pCapabilities); +} +#endif -// Typedef for pointers to XInput Functions -typedef lazy_loaded_function_p2<DWORD, DWORD, XINPUT_STATE*> xinput_get_state_fn; -typedef lazy_loaded_function_p3<DWORD, DWORD, DWORD, XINPUT_CAPABILITIES*> xinput_get_caps_fn; +//============================================================ +// create_xinput_device +//============================================================ -class xinput_interface +xinput_joystick_device * xinput_api_helper::create_xinput_device(running_machine &machine, UINT index, wininput_module &module) { -private: - const wchar_t* xinput_dll_names[2] = { L"xinput1_4.dll", L"xinput9_1_0.dll" }; + xinput_joystick_device *devinfo; -public: - xinput_get_state_fn XInputGetState; - xinput_get_caps_fn XInputGetCapabilities; - -private: - xinput_interface() - : XInputGetState("XInputGetState", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names)), - XInputGetCapabilities("XInputGetCapabilities", xinput_dll_names, ARRAY_LENGTH(xinput_dll_names)) + XINPUT_CAPABILITIES caps = { 0 }; + if (FAILED(XInputGetCapabilities(index, 0, &caps))) { + // If we can't get the capabilities skip this device + return nullptr; } - int initialize() - { - int status; - status = XInputGetState.initialize(); - if (status != 0) - { - osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetState.name(), status); - return -1; - } + char device_name[16]; + snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1); - status = XInputGetCapabilities.initialize(); - if (status != 0) - { - osd_printf_error("Failed to initialize function pointer for %s. Error: %d\n", XInputGetCapabilities.name(), status); - return -1; - } + // allocate the device object + devinfo = module.devicelist()->create_device1<xinput_joystick_device>(machine, device_name, module, shared_from_this()); - return 0; - } + // Set the player ID + devinfo->xinput_state.playerIndex = index; -public: - static DWORD get_interface(xinput_interface **ppinterface) - { - static xinput_interface s_instance; - DWORD error = s_instance.initialize(); - if (error == 0) - { - *ppinterface = &s_instance; - } + // Assign the caps we captured earlier + devinfo->xinput_state.caps = caps; - return error; - } -}; + return devinfo; +} //============================================================ // xinput_joystick_device //============================================================ -class xinput_joystick_device : public device_info +xinput_joystick_device::xinput_joystick_device(running_machine &machine, const char *name, input_module &module, std::shared_ptr<xinput_api_helper> helper) + : device_info(machine, name, DEVICE_CLASS_JOYSTICK, module), + gamepad({{0}}), + xinput_state({0}), + m_xinput_helper(helper), + m_configured(false) { -public: - gamepad_state gamepad; - xinput_api_state xinput_state; +} -private: - xinput_interface* xinput_api; +void xinput_joystick_device::poll() +{ + if (!m_configured) + return; -public: - xinput_joystick_device(running_machine &machine, const char *name, input_module &module) - : device_info(machine, name, DEVICE_CLASS_JOYSTICK, module), - gamepad({{0}}), - xinput_state({0}), - xinput_api(nullptr) + // poll the device first + HRESULT result = m_xinput_helper->XInputGetState(xinput_state.playerIndex, &xinput_state.xstate); + + // If we can't poll the device, skip + if (FAILED(result)) + return; + + // Copy the XState into State + // Start with the POV (DPAD) + for (int povindex = 0; povindex < XINPUT_MAX_POV; povindex++) { - // Attempt to get the xinput interface - xinput_interface::get_interface(&xinput_api); + int currentPov = xinput_pov_dir[povindex]; + gamepad.rgbPov[currentPov] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0; } - void poll() override + // Now do the buttons + for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++) { - // Nothing we can do if for some reason the API couldn't be loaded - if (xinput_api == nullptr) - return; + int currentButton = xinput_buttons[buttonindex]; + gamepad.rgbButtons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0; + } - // poll the device first - HRESULT result = xinput_api->XInputGetState(xinput_state.playerIndex, &xinput_state.xstate); + // Now grab the axis values + // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick + // However, the Y axis values are inverted from what MAME expects, so multiply by -1 first + gamepad.sThumbLX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + gamepad.sThumbLY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + gamepad.sThumbRX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + gamepad.sThumbRY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); - // If we can't poll the device, skip - if (FAILED(result)) - return; + // Now the triggers + gamepad.bLeftTrigger = xinput_state.xstate.Gamepad.bLeftTrigger; + gamepad.bRightTrigger = xinput_state.xstate.Gamepad.bRightTrigger; +} - // Copy the XState into State - // Start with the POV (DPAD) - for (int povindex = 0; povindex < XINPUT_MAX_POV; povindex++) - { - int currentPov = xinput_pov_dir[povindex]; - gamepad.rgbPov[currentPov] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0; - } +void xinput_joystick_device::reset() +{ + memset(&gamepad, 0, sizeof(gamepad)); +} - // Now do the buttons - for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++) - { - int currentButton = xinput_buttons[buttonindex]; - gamepad.rgbButtons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0; - } +void xinput_joystick_device::configure() +{ + std::lock_guard<std::mutex> scope_lock(m_device_lock); + + if (m_configured) + return; - // Now grab the axis values - // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick - // However, the Y axis values are inverted from what MAME expects, so multiply by -1 first - gamepad.sThumbLX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); - gamepad.sThumbLY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); - gamepad.sThumbRX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); - gamepad.sThumbRY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); - - // Now the triggers - gamepad.bLeftTrigger = xinput_state.xstate.Gamepad.bLeftTrigger; - gamepad.bRightTrigger = xinput_state.xstate.Gamepad.bRightTrigger; + // Add the axes + for (int axisnum = 0; axisnum < XINPUT_MAX_AXIS; axisnum++) + { + device()->add_item( + xinput_axis_name[axisnum], + xinput_axis_ids[axisnum], + generic_axis_get_state, + &gamepad.sThumbLX + axisnum); } - void reset() override + // Populate the POVs + // For XBOX, we treat the DPAD as a hat switch + for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++) { - memset(&gamepad, 0, sizeof(gamepad)); + device()->add_item( + xinput_pov_names[povnum], + ITEM_ID_OTHER_SWITCH, + generic_button_get_state, + &gamepad.rgbPov[povnum]); } -}; + + // populate the buttons + for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++) + { + device()->add_item( + xinput_button_names[butnum], + static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum), + generic_button_get_state, + &gamepad.rgbButtons[butnum]); + } + + device()->add_item( + "Left Trigger", + static_cast<input_item_id>(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS), + generic_button_get_state, + &gamepad.bLeftTrigger); + + device()->add_item( + "Right Trigger", + static_cast<input_item_id>(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS + 1), + generic_button_get_state, + &gamepad.bRightTrigger); + + m_configured = true; +} //============================================================ // xinput_joystick_module @@ -249,12 +224,12 @@ public: class xinput_joystick_module : public wininput_module { private: - xinput_interface* xinput_api; + std::shared_ptr<xinput_api_helper> m_xinput_helper; public: xinput_joystick_module() : wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput"), - xinput_api(nullptr) + m_xinput_helper(nullptr) { } @@ -265,11 +240,12 @@ public: if (status != 0) return status; - // Make sure we can get the xinput API - status = xinput_interface::get_interface(&xinput_api); + // Create and initialize our helper + m_xinput_helper = std::make_shared<xinput_api_helper>(); + status = m_xinput_helper->initialize(); if (status != 0) { - osd_printf_error("xinput_joystick_module failed to get XInput interface! Error: %u\n", (unsigned int)status); + osd_printf_error("xinput_joystick_module failed to get XInput interface! Error: %u\n", static_cast<unsigned int>(status)); return -1; } @@ -279,9 +255,6 @@ public: protected: virtual void input_init(running_machine &machine) override { - // The Xinput API should have been obtained already - assert(xinput_api != nullptr); - xinput_joystick_device *devinfo; // Loop through each gamepad to determine if they are connected @@ -289,93 +262,22 @@ protected: { XINPUT_STATE state = {0}; - if (xinput_api->XInputGetState(i, &state) == ERROR_SUCCESS) + if (m_xinput_helper->XInputGetState(i, &state) == ERROR_SUCCESS) { // allocate and link in a new device - devinfo = create_xinput_device(machine, i); + devinfo = m_xinput_helper->create_xinput_device(machine, i, *this); if (devinfo == nullptr) continue; - // Add the axes - for (int axisnum = 0; axisnum < XINPUT_MAX_AXIS; axisnum++) - { - devinfo->device()->add_item( - xinput_axis_name[axisnum], - xinput_axis_ids[axisnum], - generic_axis_get_state, - &devinfo->gamepad.sThumbLX + axisnum); - } - - // Populate the POVs - // For XBOX, we treat the DPAD as a hat switch - for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++) - { - devinfo->device()->add_item( - xinput_pov_names[povnum], - ITEM_ID_OTHER_SWITCH, - generic_button_get_state, - &devinfo->gamepad.rgbPov[povnum]); - } - - // populate the buttons - for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++) - { - devinfo->device()->add_item( - xinput_button_names[butnum], - (input_item_id)(ITEM_ID_BUTTON1 + butnum), - generic_button_get_state, - &devinfo->gamepad.rgbButtons[butnum]); - } - - devinfo->device()->add_item( - "Left Trigger", - (input_item_id)(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS), - generic_button_get_state, - &devinfo->gamepad.bLeftTrigger); - - devinfo->device()->add_item( - "Right Trigger", - (input_item_id)(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS + 1), - generic_button_get_state, - &devinfo->gamepad.bRightTrigger); + // Configure each gamepad to add buttons and Axes, etc. + devinfo->configure(); } } } - - private: - //============================================================ - // create_xinput_device - //============================================================ - - xinput_joystick_device * create_xinput_device(running_machine &machine, UINT index) - { - xinput_joystick_device *devinfo; - - XINPUT_CAPABILITIES caps = {0}; - if (FAILED(xinput_api->XInputGetCapabilities(index, 0, &caps))) - { - // If we can't get the capabilities skip this device - return nullptr; - } - - char device_name[16]; - snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1); - - // allocate the device object - devinfo = devicelist()->create_device<xinput_joystick_device>(machine, device_name, *this); - - // Set the player ID - devinfo->xinput_state.playerIndex = index; - - // Assign the caps we captured earlier - devinfo->xinput_state.caps = caps; - - return devinfo; - } }; #else -MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_KEYBOARDINPUT_PROVIDER, "xinput") +MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "xinput") #endif MODULE_DEFINITION(JOYSTICKINPUT_XINPUT, xinput_joystick_module) |