summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_xinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/input/input_xinput.cpp')
-rw-r--r--src/osd/modules/input/input_xinput.cpp723
1 files changed, 530 insertions, 193 deletions
diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp
index e7242a4e38a..fda2b9d8b23 100644
--- a/src/osd/modules/input/input_xinput.cpp
+++ b/src/osd/modules/input/input_xinput.cpp
@@ -5,6 +5,101 @@
// input_xinput.cpp - XInput API input support for Windows
//
//============================================================
+/*
+
+XInput is infamously inflexible. It currently only supports a single
+controller type (game controller) with a fixed report format. The
+report format includes:
+* 16-bit field for single-bit buttons and D-pad directions (two bits
+ undefined)
+* Two 8-bit axis values, used for triggers, pedals, buttons or throttle
+ and rudder controls, depending on the controller
+* Four 16-bit axis values, used for joysticks, steering wheels or hat
+ switches, depending on the controller
+
+Some button names have changed at various times:
+* Face buttons White and Black became shoulder buttons LB and RB,
+ respectively.
+* Navigation buttons Start and Back became Menu and View, respectively.
+
+Subtype Gamepad Wheel Arcade stick Arcade pad Flight stick Dance pad Guitar Drum kit
+
+D-pad D-pad D-pad Joystick D-pad Foot switch D-Pad/Strum D-pad
+L trigger Trigger Brake Button Button Rudder Pickup select^
+R trigger Trigger Accelerator Button Button Throttle ^
+L stick X Stick Wheel Roll
+L stick Y Stick Pitch
+R stick X Stick Hat left/right Whammy bar
+R stick Y Stick Hat up/down Orientation
+
+A Button Button Button Button Primary fire Foot switch Fret 1 Floor tom
+B Button Button Button Button Secondary fire Foot switch Fret 2 Snare
+X Button Button Button Button Button Foot switch Fret 4 Low tom
+Y Button Button Button Button Button Foot switch Fret 3 High tom
+LB Button Button Button^ Button Button^ Fret 5 Bass drum
+RB Button Button Button^ Button Button^ Button^ Button^
+LSB Button Button^ Button^ Button^ Button^ Fret mod^ Button^
+RSB Button Button^ Button^ Button^ Button^ Button^ Button^
+
+^ optional
+
+
+There are multiple physical button layouts for arcade sticks, for
+example:
+
+Gamester Xbox Arcade Stick, Hori Real Arcade Pro EX
+LT X Y LB
+RT A B RB
+
+PXN 0082 Arcade Stick
+LB X Y RB
+LT A B RT
+
+Mortal Kombat Tournament Edition Arcade Stick
+ X Y
+ RT
+LB A B
+
+Hori Fighting Stick EX2
+ B X Y
+A LT RT
+
+Hori Real Arcade Pro VX-SA Kai, Razer Atrox
+ B X Y LB
+A LT RT RB
+
+Hori Real Arcade Pro.V Kai, Mayflash F300, Mayflash F500
+ X Y RB LB
+A B RT LT
+
+Mad Catz Brawl Stick
+ X Y LB LT
+A B RB RT
+
+Arcade pads typically have six face buttons, and come with different
+layouts corresponding to the latter two arcade stick layouts, with the
+rightmost column on the shoulder buttons.
+
+
+Dance mats usually have this layout:
+BK ST
+B U A
+L R
+Y D X
+
+This layout seems somewhat unusual:
+BK ST
+A U B
+L R
+X D Y
+
+This layout is also available but rare:
+BK ST
+A U B
+L R
+Y D X
+
+*/
#include "modules/osdmodule.h"
@@ -17,83 +112,441 @@
// standard windows headers
#include <windows.h>
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <tuple>
+#include <utility>
+
#define XINPUT_LIBRARIES { "xinput1_4.dll", "xinput9_1_0.dll" }
-#define XINPUT_AXIS_MINVALUE -32767
-#define XINPUT_AXIS_MAXVALUE 32767
+#define XINPUT_AXIS_MINVALUE (-32'767)
+#define XINPUT_AXIS_MAXVALUE (32'767)
namespace {
-// default axis names
-const char *const xinput_axis_name[] =
+char const *const AXIS_NAMES_GAMEPAD[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "LT",
+ "RT" };
+
+char const *const AXIS_NAMES_WHEEL[]{
+ "Wheel",
+ "LSY",
+ "RSX",
+ "RSY",
+ "Brake",
+ "Accelerator" };
+
+char const *const AXIS_NAMES_FLIGHT_STICK[]{
+ "Joystick X",
+ "Joystick Y",
+ nullptr,
+ nullptr,
+ "Rudder",
+ "Throttle" };
+
+input_item_id const AXIS_IDS_GAMEPAD[]{
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_ZAXIS,
+ ITEM_ID_RZAXIS,
+ ITEM_ID_SLIDER1,
+ ITEM_ID_SLIDER2 };
+
+input_item_id const AXIS_IDS_FLIGHT_STICK[]{
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_INVALID,
+ ITEM_ID_INVALID,
+ ITEM_ID_RZAXIS,
+ ITEM_ID_ZAXIS };
+
+const char *const HAT_NAMES_GAMEPAD[]{
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "POV Hat Up",
+ "POV Hat Down",
+ "POV Hat Left",
+ "POV Hat Right" };
+
+const char *const HAT_NAMES_ARCADE_STICK[]{
+ "Joystick Up",
+ "Joystick Down",
+ "Joystick Left",
+ "Joystick Right",
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr };
+
+
+//============================================================
+// xinput_joystick_device
+//============================================================
+
+class xinput_joystick_device : public device_info
{
- "LSX",
- "LSY",
- "RSX",
- "RSY"
+public:
+ xinput_joystick_device(
+ running_machine &machine,
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ uint32_t player,
+ XINPUT_CAPABILITIES const &caps,
+ std::shared_ptr<xinput_api_helper> helper);
+
+ void poll() override;
+ void reset() override;
+ void configure();
+
+private:
+ static inline constexpr USHORT SWITCH_BITS[] =
+ {
+ XINPUT_GAMEPAD_A,
+ XINPUT_GAMEPAD_B,
+ XINPUT_GAMEPAD_X,
+ XINPUT_GAMEPAD_Y,
+ XINPUT_GAMEPAD_LEFT_SHOULDER,
+ XINPUT_GAMEPAD_RIGHT_SHOULDER,
+ XINPUT_GAMEPAD_LEFT_THUMB,
+ XINPUT_GAMEPAD_RIGHT_THUMB,
+ XINPUT_GAMEPAD_START,
+ XINPUT_GAMEPAD_BACK,
+
+ XINPUT_GAMEPAD_DPAD_UP,
+ XINPUT_GAMEPAD_DPAD_DOWN,
+ XINPUT_GAMEPAD_DPAD_LEFT,
+ XINPUT_GAMEPAD_DPAD_RIGHT
+ };
+
+ enum
+ {
+ SWITCH_A, // button bits
+ SWITCH_B,
+ SWITCH_X,
+ SWITCH_Y,
+ SWITCH_LB,
+ SWITCH_RB,
+ SWITCH_LSB,
+ SWITCH_RSB,
+ SWITCH_START,
+ SWITCH_BACK,
+
+ SWITCH_DPAD_UP, // D-pad bits
+ SWITCH_DPAD_DOWN,
+ SWITCH_DPAD_LEFT,
+ SWITCH_DPAD_RIGHT,
+
+ SWITCH_HAT_UP, // for flight stick with POV hat as right stick
+ SWITCH_HAT_DOWN,
+ SWITCH_HAT_LEFT,
+ SWITCH_HAT_RIGHT,
+
+ SWITCH_LT, // for arcade stick/pad with LT/RT buttons
+ SWITCH_RT,
+
+ SWITCH_TOTAL
+ };
+
+ enum
+ {
+ AXIS_LT, // half-axes for triggers
+ AXIS_RT,
+
+ AXIS_LSX, // full-precision axes
+ AXIS_LSY,
+ AXIS_RSX,
+ AXIS_RSY,
+
+ AXIS_RUDDER, // LT/RT mapped differently for flight sticks
+ AXIS_THROTTLE,
+
+ AXIS_TOTAL
+ };
+
+ uint32_t const m_player_index;
+ XINPUT_CAPABILITIES const m_capabilities;
+ XINPUT_STATE m_xinput_state;
+ uint8_t m_switches[SWITCH_TOTAL];
+ int32_t m_axes[AXIS_TOTAL];
+
+ std::shared_ptr<xinput_api_helper> m_xinput_helper;
};
-const input_item_id xinput_axis_ids[] =
+xinput_joystick_device::xinput_joystick_device(
+ running_machine &machine,
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ uint32_t player,
+ XINPUT_CAPABILITIES const &caps,
+ std::shared_ptr<xinput_api_helper> helper) :
+ device_info(machine, std::move(name), std::move(id), DEVICE_CLASS_JOYSTICK, module),
+ m_player_index(player),
+ m_capabilities(caps),
+ m_xinput_state{ 0 },
+ m_xinput_helper(helper)
{
- ITEM_ID_XAXIS,
- ITEM_ID_YAXIS,
- ITEM_ID_ZAXIS,
- ITEM_ID_RZAXIS
-};
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
-const USHORT xinput_pov_dir[] = {
- XINPUT_GAMEPAD_DPAD_UP,
- XINPUT_GAMEPAD_DPAD_DOWN,
- XINPUT_GAMEPAD_DPAD_LEFT,
- XINPUT_GAMEPAD_DPAD_RIGHT
-};
+void xinput_joystick_device::poll()
+{
+ // poll the device first
+ DWORD const prevpacket = m_xinput_state.dwPacketNumber;
+ HRESULT result = m_xinput_helper->xinput_get_state(m_player_index, &m_xinput_state);
-const char *const xinput_pov_names[] = {
- "DPAD Up",
- "DPAD Down",
- "DPAD Left",
- "DPAD Right"
-};
+ // if we can't poll the device or nothing changed, skip
+ if (FAILED(result) || (prevpacket == m_xinput_state.dwPacketNumber))
+ return;
-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_LEFT_THUMB,
- XINPUT_GAMEPAD_RIGHT_THUMB,
- XINPUT_GAMEPAD_START,
- XINPUT_GAMEPAD_BACK
-};
+ // translate button bits
+ for (unsigned i = 0; std::size(SWITCH_BITS) > i; ++i)
+ m_switches[SWITCH_A + i] = (m_xinput_state.Gamepad.wButtons & SWITCH_BITS[i]) ? 0xff : 0x00;
+
+ // translate the triggers onto the negative side of the axes
+ m_axes[AXIS_LT] = -normalize_absolute_axis(m_xinput_state.Gamepad.bLeftTrigger, -255, 255);
+ m_axes[AXIS_RT] = -normalize_absolute_axis(m_xinput_state.Gamepad.bRightTrigger, -255, 255);
+
+ // translate full-precision axes - Y direction is opposite to what MAME uses
+ m_axes[AXIS_LSX] = normalize_absolute_axis(m_xinput_state.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_LSY] = normalize_absolute_axis(-m_xinput_state.Gamepad.sThumbLY, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_RSX] = normalize_absolute_axis(m_xinput_state.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+ m_axes[AXIS_RSY] = normalize_absolute_axis(-m_xinput_state.Gamepad.sThumbRY, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
+
+ // translate LT/RT switches for arcade sticks/pads
+ m_switches[SWITCH_LT] = (0x80 <= m_xinput_state.Gamepad.bLeftTrigger) ? 0xff : 0x00;
+ m_switches[SWITCH_RT] = (0x80 <= m_xinput_state.Gamepad.bRightTrigger) ? 0xff : 0x00;
+
+ // translate POV hat for flight sticks
+ m_switches[SWITCH_HAT_UP] = (16'384 <= m_xinput_state.Gamepad.sThumbRY) ? 0xff : 0x00;
+ m_switches[SWITCH_HAT_DOWN] = (-16'384 >= m_xinput_state.Gamepad.sThumbRY) ? 0xff : 0x00;
+ m_switches[SWITCH_HAT_LEFT] = (-16'384 >= m_xinput_state.Gamepad.sThumbRX) ? 0xff : 0x00;
+ m_switches[SWITCH_HAT_RIGHT] = (16'384 <= m_xinput_state.Gamepad.sThumbRX) ? 0xff : 0x00;
+
+ // translate rudder and throttle for flight sticks
+ m_axes[AXIS_RUDDER] = normalize_absolute_axis(m_xinput_state.Gamepad.bLeftTrigger, 0, 255);
+ m_axes[AXIS_THROTTLE] = normalize_absolute_axis(m_xinput_state.Gamepad.bRightTrigger, 0, 255);
+}
-const char *const xinput_button_names[] = {
- "A",
- "B",
- "X",
- "Y",
- "LB",
- "RB",
- "LS",
- "RS",
- "Start",
- "Back"
-};
+void xinput_joystick_device::reset()
+{
+ std::fill(std::begin(m_switches), std::end(m_switches), 0);
+ std::fill(std::begin(m_axes), std::end(m_axes), 0);
+}
-const input_item_id xinput_button_ids[] = {
- ITEM_ID_BUTTON1,
- ITEM_ID_BUTTON2,
- ITEM_ID_BUTTON3,
- ITEM_ID_BUTTON4,
- ITEM_ID_BUTTON5,
- ITEM_ID_BUTTON6,
- ITEM_ID_BUTTON7,
- ITEM_ID_BUTTON8,
- ITEM_ID_START,
- ITEM_ID_SELECT
-};
+void xinput_joystick_device::configure()
+{
+ // TODO: don't add axes not present in capabilities
+ // TODO: proper support for dance mat, guitar and drum kit controllers
+
+ // default characteristics for a gamepad
+ char const *type_name = "unsupported";
+ char const *subtype_name = "unsupported";
+ bool lt_rt_button = false;
+ bool lt_rt_fullaxis = false;
+ bool rstick_hat = false;
+ char const *const *axis_names = AXIS_NAMES_GAMEPAD;
+ input_item_id const *axis_ids = AXIS_IDS_GAMEPAD;
+ char const *const *hat_names = HAT_NAMES_GAMEPAD;
+
+ // consider the device type to decide how to map controls
+ switch (m_capabilities.Type)
+ {
+ case XINPUT_DEVTYPE_GAMEPAD:
+ type_name = "game controller";
+ switch (m_capabilities.SubType)
+ {
+ case 0x00: // XINPUT_DEVSUBTYPE_UNKNOWN: work around MinGW header issues
+ subtype_name = "unknown";
+ break;
+ case XINPUT_DEVSUBTYPE_GAMEPAD:
+ subtype_name = "gamepad";
+ break;
+ case XINPUT_DEVSUBTYPE_WHEEL:
+ subtype_name = "wheel";
+ axis_names = AXIS_NAMES_WHEEL;
+ break;
+ case XINPUT_DEVSUBTYPE_ARCADE_STICK:
+ subtype_name = "arcade stick";
+ lt_rt_button = true;
+ hat_names = HAT_NAMES_ARCADE_STICK;
+ break;
+ case 0x04: // XINPUT_DEVSUBTYPE_FLIGHT_STICK: work around MinGW header issues
+ subtype_name = "flight stick";
+ lt_rt_fullaxis = true;
+ rstick_hat = true;
+ axis_names = AXIS_NAMES_FLIGHT_STICK;
+ axis_ids = AXIS_IDS_FLIGHT_STICK;
+ break;
+ case XINPUT_DEVSUBTYPE_DANCE_PAD:
+ subtype_name = "dance pad";
+ break;
+ case XINPUT_DEVSUBTYPE_GUITAR:
+ case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
+ case XINPUT_DEVSUBTYPE_GUITAR_BASS:
+ subtype_name = "guitar";
+ break;
+ case XINPUT_DEVSUBTYPE_DRUM_KIT:
+ subtype_name = "drum kit";
+ break;
+ case XINPUT_DEVSUBTYPE_ARCADE_PAD:
+ subtype_name = "arcade pad";
+ lt_rt_button = true;
+ break;
+ }
+ break;
+ }
+
+ // log some diagnostic information
+ osd_printf_verbose(
+ "Configuring XInput player %d type 0x%02X (%s) sub type 0x%02X (%s)\n",
+ m_player_index + 1,
+ m_capabilities.Type,
+ type_name,
+ m_capabilities.SubType,
+ subtype_name);
+ osd_printf_verbose(
+ "XInput switch capabilities A=%d B=%d X=%d Y=%d LB=%d RB=%d LSB=%d RSB=%d Start=%d Back=%d Up=%d Down=%d Left=%d Right=%d\n",
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_A) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_B) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_X) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_Y) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_START) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) ? 1 : 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) ? 1 : 0);
+ osd_printf_verbose(
+ "XInput axis capabilities LT=0x%02X (%d-bit) RT=0x%02X (%d-bit) LSX=0x%04X (%d-bit) LSY=0x%04X (%d-bit) RSX=0x%04X (%d-bit) RSY=0x%04X (%d-bit)\n",
+ m_capabilities.Gamepad.bLeftTrigger,
+ count_leading_ones_32(uint32_t(m_capabilities.Gamepad.bLeftTrigger) << 24),
+ m_capabilities.Gamepad.bRightTrigger,
+ count_leading_ones_32(uint32_t(m_capabilities.Gamepad.bRightTrigger) << 24),
+ m_capabilities.Gamepad.sThumbLX,
+ count_leading_ones_32(uint32_t(uint16_t(m_capabilities.Gamepad.sThumbLX)) << 16),
+ m_capabilities.Gamepad.sThumbLY,
+ count_leading_ones_32(uint32_t(uint16_t(m_capabilities.Gamepad.sThumbLY)) << 16),
+ m_capabilities.Gamepad.sThumbRX,
+ count_leading_ones_32(uint32_t(uint16_t(m_capabilities.Gamepad.sThumbRX)) << 16),
+ m_capabilities.Gamepad.sThumbRY,
+ count_leading_ones_32(uint32_t(uint16_t(m_capabilities.Gamepad.sThumbRY)) << 16));
+
+ // add full-precision axes
+ for (unsigned i = 0; ((rstick_hat ? AXIS_LSY : AXIS_RSY) - AXIS_LSX) >= i; ++i)
+ {
+ device()->add_item(
+ axis_names[i],
+ axis_ids[i],
+ generic_axis_get_state<int32_t>,
+ &m_axes[AXIS_LSX + i]);
+ }
+
+ // add extra axes for flight sticks
+ if (lt_rt_fullaxis)
+ {
+ for (unsigned i = 0; (AXIS_THROTTLE - AXIS_RUDDER) >= i; ++i)
+ {
+ device()->add_item(
+ axis_names[4 + i],
+ axis_ids[4 + i],
+ generic_axis_get_state<int32_t>,
+ &m_axes[AXIS_RUDDER + i]);
+ }
+ }
+
+ // add hats
+ bool const hat_caps[]{
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0,
+ (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0,
+ rstick_hat && m_capabilities.Gamepad.sThumbRY,
+ rstick_hat && m_capabilities.Gamepad.sThumbRY,
+ rstick_hat && m_capabilities.Gamepad.sThumbRX,
+ rstick_hat && m_capabilities.Gamepad.sThumbRX };
+ for (unsigned i = 0; (SWITCH_HAT_RIGHT - SWITCH_DPAD_UP) >= i; ++i)
+ {
+ if (hat_caps[i])
+ {
+ device()->add_item(
+ hat_names[i],
+ input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
+ generic_button_get_state<uint8_t>,
+ &m_switches[SWITCH_DPAD_UP + i]);
+ }
+ }
+
+ // add buttons
+ std::tuple<unsigned, char const *, bool> const button_caps[]{
+ { SWITCH_A, "A", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0 },
+ { SWITCH_B, "B", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0 },
+ { SWITCH_X, "X", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0 },
+ { SWITCH_Y, "Y", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0 },
+ { SWITCH_LT, "LT", lt_rt_button && m_capabilities.Gamepad.bLeftTrigger },
+ { SWITCH_RT, "RT", lt_rt_button && m_capabilities.Gamepad.bRightTrigger },
+ { SWITCH_LB, "LB", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0 },
+ { SWITCH_RB, "RB", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0 },
+ { SWITCH_LSB, "LSB", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0 },
+ { SWITCH_RSB, "RSB", (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0 } };
+ input_item_id button_id = ITEM_ID_BUTTON1;
+ for (auto [i, name, supported] : button_caps)
+ {
+ if (supported)
+ {
+ device()->add_item(
+ name,
+ button_id++,
+ generic_button_get_state<uint8_t>,
+ &m_switches[i]);
+ }
+ }
+
+ // add start/back
+ if (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_START)
+ {
+ device()->add_item(
+ "Start",
+ ITEM_ID_START,
+ generic_button_get_state<uint8_t>,
+ &m_switches[SWITCH_START]);
+ }
+ if (m_capabilities.Gamepad.wButtons & XINPUT_GAMEPAD_BACK)
+ {
+ device()->add_item(
+ "Back",
+ ITEM_ID_SELECT,
+ generic_button_get_state<uint8_t>,
+ &m_switches[SWITCH_BACK]);
+ }
+
+ // add triggers/pedals
+ if (!lt_rt_button && !lt_rt_fullaxis)
+ {
+ for (unsigned i = 0; (AXIS_RT - AXIS_LT) >= i; ++i)
+ {
+ device()->add_item(
+ axis_names[4 + i],
+ axis_ids[4 + i],
+ generic_axis_get_state<int32_t>,
+ &m_axes[AXIS_LT + i]);
+ }
+ }
+}
//============================================================
@@ -134,16 +587,9 @@ protected:
{
XINPUT_STATE state = {0};
+ // allocate and link in a new device
if (m_xinput_helper->xinput_get_state(i, &state) == ERROR_SUCCESS)
- {
- // allocate and link in a new device
- auto *devinfo = m_xinput_helper->create_xinput_device(machine, i, *this);
- if (!devinfo)
- continue;
-
- // Configure each gamepad to add buttons and Axes, etc.
- devinfo->configure();
- }
+ m_xinput_helper->create_xinput_device(machine, i, *this);
}
}
@@ -174,141 +620,32 @@ int xinput_api_helper::initialize()
// create_xinput_device
//============================================================
-xinput_joystick_device * xinput_api_helper::create_xinput_device(running_machine &machine, UINT index, wininput_module &module)
+device_info *xinput_api_helper::create_xinput_device(running_machine &machine, UINT index, wininput_module &module)
{
+ // If we can't get the capabilities skip this device
XINPUT_CAPABILITIES caps = { 0 };
if (FAILED(xinput_get_capabilities(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
- auto &devinfo = module.devicelist().create_device<xinput_joystick_device>(machine, device_name, device_name, module, shared_from_this());
-
- // Set the player ID
- devinfo.xinput_state.player_index = index;
-
- // Assign the caps we captured earlier
- devinfo.xinput_state.caps = caps;
+ auto &devinfo = module.devicelist().create_device<xinput_joystick_device>(
+ machine,
+ device_name,
+ device_name,
+ module,
+ index,
+ caps,
+ shared_from_this());
+
+ // configure each controller to add buttons, axes, etc.
+ devinfo.configure();
return &devinfo;
}
-//============================================================
-// xinput_joystick_device
-//============================================================
-
-xinput_joystick_device::xinput_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module, std::shared_ptr<xinput_api_helper> helper) :
- device_info(machine, std::string(name), std::string(id), DEVICE_CLASS_JOYSTICK, module),
- gamepad({ { 0 } }),
- xinput_state({ 0 }),
- m_xinput_helper(helper),
- m_configured(false)
-{
-}
-
-void xinput_joystick_device::poll()
-{
- if (!m_configured)
- return;
-
- // poll the device first
- HRESULT result = m_xinput_helper->xinput_get_state(xinput_state.player_index, &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++)
- {
- int currentPov = xinput_pov_dir[povindex];
- gamepad.povs[povindex] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0;
- }
-
- // Now do the buttons
- for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++)
- {
- int currentButton = xinput_buttons[buttonindex];
- gamepad.buttons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0;
- }
-
- // 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 negate the value
- gamepad.left_thumb_x = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.left_thumb_y = normalize_absolute_axis(-xinput_state.xstate.Gamepad.sThumbLY, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.right_thumb_x = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
- gamepad.right_thumb_y = normalize_absolute_axis(-xinput_state.xstate.Gamepad.sThumbRY, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE);
-
- // Now the triggers, place them on half-axes (negative side)
- gamepad.left_trigger = -normalize_absolute_axis(xinput_state.xstate.Gamepad.bLeftTrigger, -255, 255);
- gamepad.right_trigger = -normalize_absolute_axis(xinput_state.xstate.Gamepad.bRightTrigger, -255, 255);
-}
-
-void xinput_joystick_device::reset()
-{
- memset(&gamepad, 0, sizeof(gamepad));
-}
-
-void xinput_joystick_device::configure()
-{
- std::lock_guard<std::mutex> scope_lock(m_device_lock);
-
- if (m_configured)
- return;
-
- // 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<LONG>,
- &gamepad.left_thumb_x + axisnum);
- }
-
- // Populate the POVs
- // For XBOX, we treat the DPAD as a hat switch
- for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++)
- {
- device()->add_item(
- xinput_pov_names[povnum],
- input_item_id(ITEM_ID_HAT1UP + povnum), // matches up/down/left/right order
- generic_button_get_state<BYTE>,
- &gamepad.povs[povnum]);
- }
-
- // populate the buttons
- for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++)
- {
- device()->add_item(
- xinput_button_names[butnum],
- xinput_button_ids[butnum],
- generic_button_get_state<BYTE>,
- &gamepad.buttons[butnum]);
- }
-
- device()->add_item(
- "RT",
- ITEM_ID_ADD_ABSOLUTE1,
- generic_axis_get_state<LONG>,
- &gamepad.right_trigger);
-
- device()->add_item(
- "LT",
- ITEM_ID_ADD_ABSOLUTE2,
- generic_axis_get_state<LONG>,
- &gamepad.left_trigger);
-
- m_configured = true;
-}
-
#else // defined(OSD_WINDOWS)
#include "input_module.h"