diff --git a/Externals/libretro-common/include/libretro.h b/Externals/libretro-common/include/libretro.h index b09129494cd7..970d5754cb0f 100644 --- a/Externals/libretro-common/include/libretro.h +++ b/Externals/libretro-common/include/libretro.h @@ -4868,6 +4868,42 @@ enum retro_sensor_action #define RETRO_SENSOR_ILLUMINANCE 6 /** @} */ +/** @defgroup RETRO_SENSOR_SUBDEVICE Sensor Sub-Device Index + * @{ + */ + +/** + * The number of bits that a sub-device index is shifted by within a sensor ID + * or a \c retro_sensor_action. + * + * Addresses more than one sensor of the same kind on a single port. + * Index 0 denotes the controller itself and encodes to the values already in + * use (RETRO_SENSOR_SUBDEVICE(0, id) == id). Index 1 and above denote + * sub-devices, in whatever order the device type implies. + * + * @note \c retro_sensor_action is an enum, so an encoded action must be cast at + * the call site. \c RETRO_SENSOR_DUMMY pins the underlying type to \c int, so + * the encoded value is in range. + * + * @see RETRO_SENSOR_ID + * @see retro_sensor_action + */ +#define RETRO_SENSOR_INDEX_SHIFT 8 + +/** Mask of the bits below the sub-device index. */ +#define RETRO_SENSOR_INDEX_MASK ((1u << RETRO_SENSOR_INDEX_SHIFT) - 1u) + +/** Returns the sub-device index encoded in \c id; 0 is the controller itself. */ +#define RETRO_SENSOR_INDEX(id) ((unsigned)(id) >> RETRO_SENSOR_INDEX_SHIFT) + +/** Returns the sensor ID or action in \c id, without its sub-device index. */ +#define RETRO_SENSOR_BASE(id) ((unsigned)(id) & RETRO_SENSOR_INDEX_MASK) + +/** Addresses sensor \c id on sub-device \c index of a port. */ +#define RETRO_SENSOR_SUBDEVICE(index, id) \ + ((unsigned)((((unsigned)(index)) << RETRO_SENSOR_INDEX_SHIFT) | ((unsigned)(id)))) +/** @} */ + /** * Adjusts the state of a sensor. * diff --git a/Source/Core/DolphinLibretro/Input.cpp b/Source/Core/DolphinLibretro/Input.cpp index 9b6360b60e71..d4d5cb727d28 100644 --- a/Source/Core/DolphinLibretro/Input.cpp +++ b/Source/Core/DolphinLibretro/Input.cpp @@ -92,6 +92,11 @@ typedef enum { SENSOR_COUNT } sensor_type_t; +/* Which sub-device of a Wii Remote's port the Nunchuk's accelerometer is. The + * remote itself is 0. A real Nunchuk has no gyroscope, so it is asked for an + * accelerometer and nothing else. */ +#define NUNCHUK_SENSOR_SUBDEVICE 1 + void retro_set_controller_port_device_gc(unsigned port, unsigned device); void retro_set_controller_port_device_wii(unsigned port, unsigned device); @@ -106,12 +111,12 @@ static struct retro_rumble_interface rumble{}; static unsigned input_types[8]; static bool g_init_wiimotes = false; static bool s_sensor_init_pending = false; -static bool sensor_enabled[NUM_CONTROLLERS_FOR_SENSORS][SENSOR_COUNT] = {}; +static bool sensor_enabled[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][SENSOR_COUNT] = {}; static int port_max; -double g_accel_pos[NUM_CONTROLLERS_FOR_SENSORS][3] = {}; // x, y, z -double g_accel_neg[NUM_CONTROLLERS_FOR_SENSORS][3] = {}; // x, y, z -double g_gyro_pos[NUM_CONTROLLERS_FOR_SENSORS][3] = {}; // x, y, z -double g_gyro_neg[NUM_CONTROLLERS_FOR_SENSORS][3] = {}; // x, y, z +double g_accel_pos[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3] = {}; // x, y, z +double g_accel_neg[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3] = {}; // x, y, z +double g_gyro_pos[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3] = {}; // x, y, z +double g_gyro_neg[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3] = {}; // x, y, z static struct retro_input_descriptor descGC[] = { {0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"}, @@ -660,18 +665,33 @@ void InitSensors() { if (sensor_interface.set_sensor_state) { - sensor_enabled[i][SENSOR_ACCELEROMETER] = sensor_interface.set_sensor_state(i, RETRO_SENSOR_ACCELEROMETER_ENABLE, 60); - sensor_enabled[i][SENSOR_GYRO] = sensor_interface.set_sensor_state(i, RETRO_SENSOR_GYROSCOPE_ENABLE, 60); - - if (sensor_enabled[i][SENSOR_ACCELEROMETER] || sensor_enabled[i][SENSOR_GYRO]) + for (unsigned s = 0; s < NUM_SENSOR_SUBDEVICES; s++) { - auto sensor = std::make_shared(i); - sensor->RegisterAll(); - g_controller_interface.AddDevice(sensor); - } + // The sub-device rides in the high bits of the action. A frontend + // that does not know about sub-devices returns false for anything but + // 0; the flag stays clear and nothing binds. + const retro_sensor_action accel_on = static_cast( + RETRO_SENSOR_SUBDEVICE(s, RETRO_SENSOR_ACCELEROMETER_ENABLE)); + sensor_enabled[i][s][SENSOR_ACCELEROMETER] = + sensor_interface.set_sensor_state(i, accel_on, 60); + + // Only the remote itself has a gyroscope to ask for; a Nunchuk has none. + if (s == 0) + { + sensor_enabled[i][s][SENSOR_GYRO] = + sensor_interface.set_sensor_state(i, RETRO_SENSOR_GYROSCOPE_ENABLE, 60); + } - INFO_LOG_FMT(BOOT, "Sensor interface: Port: {} ACCELEROMETER: {} GYROSCOPE: {}", i, - sensor_enabled[i][SENSOR_ACCELEROMETER], sensor_enabled[i][SENSOR_GYRO]); + if (sensor_enabled[i][s][SENSOR_ACCELEROMETER] || sensor_enabled[i][s][SENSOR_GYRO]) + { + auto sensor = std::make_shared(i, s); + sensor->RegisterAll(); + g_controller_interface.AddDevice(sensor); + } + + INFO_LOG_FMT(BOOT, "Sensor interface: Port: {} Sub-device: {} ACCELEROMETER: {} GYROSCOPE: {}", + i, s, sensor_enabled[i][s][SENSOR_ACCELEROMETER], sensor_enabled[i][s][SENSOR_GYRO]); + } } } @@ -698,15 +718,20 @@ void Shutdown() { Pad::ResetRumble(i); - // Was crossed over and hardcoded to port 0, leaving sensors running. - if (sensor_enabled[i][SENSOR_ACCELEROMETER]) - sensor_interface.set_sensor_state(i, RETRO_SENSOR_ACCELEROMETER_DISABLE, 0); + // Disable each sensor on the port it was enabled for. + for (unsigned s = 0; s < NUM_SENSOR_SUBDEVICES; s++) + { + if (sensor_enabled[i][s][SENSOR_ACCELEROMETER]) + sensor_interface.set_sensor_state(i, static_cast( + RETRO_SENSOR_SUBDEVICE(s, RETRO_SENSOR_ACCELEROMETER_DISABLE)), 0); - if (sensor_enabled[i][SENSOR_GYRO]) - sensor_interface.set_sensor_state(i, RETRO_SENSOR_GYROSCOPE_DISABLE, 0); + if (sensor_enabled[i][s][SENSOR_GYRO]) + sensor_interface.set_sensor_state(i, static_cast( + RETRO_SENSOR_SUBDEVICE(s, RETRO_SENSOR_GYROSCOPE_DISABLE)), 0); - sensor_enabled[i][SENSOR_ACCELEROMETER] = false; - sensor_enabled[i][SENSOR_GYRO] = false; + sensor_enabled[i][s][SENSOR_ACCELEROMETER] = false; + sensor_enabled[i][s][SENSOR_GYRO] = false; + } } Keyboard::Shutdown(); @@ -716,20 +741,24 @@ void Shutdown() rumble.set_rumble_state = nullptr; } -void UpdateAccelerometer(unsigned port) +void UpdateAccelerometer(unsigned port, unsigned subdevice) { - if (!sensor_enabled[port][SENSOR_ACCELEROMETER] || !sensor_interface.get_sensor_input) + if (!sensor_enabled[port][subdevice][SENSOR_ACCELEROMETER] || !sensor_interface.get_sensor_input) return; static const float G = 9.80665f; // read raw sensor values - float ax = sensor_interface.get_sensor_input(port, RETRO_SENSOR_ACCELEROMETER_X) * G; - float ay = sensor_interface.get_sensor_input(port, RETRO_SENSOR_ACCELEROMETER_Y) * G; - float az = sensor_interface.get_sensor_input(port, RETRO_SENSOR_ACCELEROMETER_Z) * G; - - // Collapsed, so a sideways remote with the dongle fitted still rotates. - if (wiimote_base_device(input_types[port]) == RETRO_DEVICE_WIIMOTE_SW) + float ax = sensor_interface.get_sensor_input( + port, RETRO_SENSOR_SUBDEVICE(subdevice, RETRO_SENSOR_ACCELEROMETER_X)) * G; + float ay = sensor_interface.get_sensor_input( + port, RETRO_SENSOR_SUBDEVICE(subdevice, RETRO_SENSOR_ACCELEROMETER_Y)) * G; + float az = sensor_interface.get_sensor_input( + port, RETRO_SENSOR_SUBDEVICE(subdevice, RETRO_SENSOR_ACCELEROMETER_Z)) * G; + + // Holding the remote sideways rotates what its sensors read. Sub-device 0 + // only: a Nunchuk is held the same way round regardless. + if (subdevice == 0 && wiimote_base_device(input_types[port]) == RETRO_DEVICE_WIIMOTE_SW) { float rx = -ay; // rotate 90° clockwise float ry = ax; @@ -738,19 +767,20 @@ void UpdateAccelerometer(unsigned port) } // write rotated values - g_accel_pos[port][0] = std::max(0.0f, ax); - g_accel_neg[port][0] = std::max(0.0f, -ax); + g_accel_pos[port][subdevice][0] = std::max(0.0f, ax); + g_accel_neg[port][subdevice][0] = std::max(0.0f, -ax); - g_accel_pos[port][1] = std::max(0.0f, ay); - g_accel_neg[port][1] = std::max(0.0f, -ay); + g_accel_pos[port][subdevice][1] = std::max(0.0f, ay); + g_accel_neg[port][subdevice][1] = std::max(0.0f, -ay); - g_accel_pos[port][2] = std::max(0.0f, az); - g_accel_neg[port][2] = std::max(0.0f, -az); + g_accel_pos[port][subdevice][2] = std::max(0.0f, az); + g_accel_neg[port][subdevice][2] = std::max(0.0f, -az); } void UpdateGyro(unsigned port) { - if (!sensor_enabled[port][SENSOR_GYRO] || !sensor_interface.get_sensor_input) + // Sub-device 0 only: the gyroscope is the remote's, by way of MotionPlus. + if (!sensor_enabled[port][0][SENSOR_GYRO] || !sensor_interface.get_sensor_input) return; // rad/s about the remote's own axes: +X left, +Y back, +Z up. @@ -766,16 +796,16 @@ void UpdateGyro(unsigned port) gy = ry; } - // Split across a one-sided pair; the expression parser clamps negatives away - // (see SensorDevice::RegisterAll). - g_gyro_pos[port][0] = std::max(0.0f, gx); - g_gyro_neg[port][0] = std::max(0.0f, -gx); + // Split each axis across a one-sided pair: the expression parser cannot + // carry a negative value (see SensorDevice::RegisterAll). + g_gyro_pos[port][0][0] = std::max(0.0f, gx); + g_gyro_neg[port][0][0] = std::max(0.0f, -gx); - g_gyro_pos[port][1] = std::max(0.0f, gy); - g_gyro_neg[port][1] = std::max(0.0f, -gy); + g_gyro_pos[port][0][1] = std::max(0.0f, gy); + g_gyro_neg[port][0][1] = std::max(0.0f, -gy); - g_gyro_pos[port][2] = std::max(0.0f, gz); - g_gyro_neg[port][2] = std::max(0.0f, -gz); + g_gyro_pos[port][0][2] = std::max(0.0f, gz); + g_gyro_neg[port][0][2] = std::max(0.0f, -gz); } void ResetControllers(const WiimoteUpdateFlags& f) @@ -848,7 +878,8 @@ void Update() for (int i = 0; i < port_max; ++i) { - UpdateAccelerometer(i); + for (unsigned s = 0; s < NUM_SENSOR_SUBDEVICES; ++s) + UpdateAccelerometer(i, s); UpdateGyro(i); } @@ -869,12 +900,12 @@ void Update() } } -static std::string GetQualifiedNameSensor(unsigned port) +static std::string GetQualifiedNameSensor(unsigned port, unsigned subdevice) { return ciface::Core::DeviceQualifier( std::string(Libretro::Input::source), static_cast(port), - std::string("Sensor") + Libretro::Input::SensorDeviceName(subdevice) ).ToString(); } @@ -1538,10 +1569,8 @@ void retro_set_controller_port_device_wii(unsigned port, unsigned device) ControllerEmu::ControlGroup* ncButtons = wm->GetNunchukGroup(NunchukGroup::Buttons); ControllerEmu::ControlGroup* ncStick = wm->GetNunchukGroup(NunchukGroup::Stick); ControllerEmu::ControlGroup* ncShake = wm->GetNunchukGroup(NunchukGroup::Shake); -#if 0 - ControllerEmu::ControlGroup* ncTilt = wm->GetNunchukGroup(NunchukGroup::Tilt); - ControllerEmu::ControlGroup* ncSwing = wm->GetNunchukGroup(NunchukGroup::Swing); -#endif + // Nunchuk Tilt and Swing stay unbound: its motion arrives below as a + // real accelerometer, and both sticks are already spoken for. ncButtons->SetControlExpression(0, "X"); // C ncButtons->SetControlExpression(1, "Y"); // Z ncStick->SetControlExpression(0, "`" + devAnalog + ":Y0-`"); // Up @@ -1578,58 +1607,86 @@ void retro_set_controller_port_device_wii(unsigned port, unsigned device) wmButtons->SetControlExpression(3, "A"); // 2 } - // Map accel data to tilt expressions - if (Libretro::Input::sensor_enabled[port][SENSOR_ACCELEROMETER] || - Libretro::Input::sensor_enabled[port][SENSOR_GYRO]) - { - std::string devSensor = Libretro::Input::GetQualifiedNameSensor(port); + wmButtons->SetControlExpression(4, "Select"); // - + wmButtons->SetControlExpression(5, "Start"); // + + } + + // Motion, for every remote configuration rather than only the ones with + // nothing on the expansion port. + if (Libretro::Input::sensor_enabled[port][0][SENSOR_ACCELEROMETER] || + Libretro::Input::sensor_enabled[port][0][SENSOR_GYRO]) + { + std::string devSensor = Libretro::Input::GetQualifiedNameSensor(port, 0); - if (Libretro::Input::sensor_enabled[port][SENSOR_ACCELEROMETER]) + if (Libretro::Input::sensor_enabled[port][0][SENSOR_ACCELEROMETER]) + { + // Accelerometer (6 inputs: Up, Down, Left, Right, Forward, Backward) + // Indices must match WiimoteEmu::LoadDefaults ordering (0..5) + auto* wmAccel = static_cast( + wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IMUAccelerometer)); + if (wmAccel) { - // Accelerometer (6 inputs: Up, Down, Left, Right, Forward, Backward) - // Indices must match WiimoteEmu::LoadDefaults ordering (0..5) - auto* wmAccel = static_cast( - wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IMUAccelerometer)); - if (wmAccel) - { - wmAccel->SetControlExpression(0, "`" + devSensor + ":AccelZ+`"); // Up - wmAccel->SetControlExpression(1, "`" + devSensor + ":AccelZ-`"); // Down - wmAccel->SetControlExpression(2, "`" + devSensor + ":AccelX+`"); // Left - wmAccel->SetControlExpression(3, "`" + devSensor + ":AccelX-`"); // Right - wmAccel->SetControlExpression(4, "`" + devSensor + ":AccelY-`"); // Forward - wmAccel->SetControlExpression(5, "`" + devSensor + ":AccelY+`"); // Backward - } + wmAccel->SetControlExpression(0, "`" + devSensor + ":AccelZ+`"); // Up + wmAccel->SetControlExpression(1, "`" + devSensor + ":AccelZ-`"); // Down + wmAccel->SetControlExpression(2, "`" + devSensor + ":AccelX+`"); // Left + wmAccel->SetControlExpression(3, "`" + devSensor + ":AccelX-`"); // Right + wmAccel->SetControlExpression(4, "`" + devSensor + ":AccelY-`"); // Forward + wmAccel->SetControlExpression(5, "`" + devSensor + ":AccelY+`"); // Backward } + } - // A sibling, not a child: nested, gyro-without-accelerometer bound neither. - if (Libretro::Input::sensor_enabled[port][SENSOR_GYRO]) + // A sibling of the accelerometer branch: gyro without accelerometer + // must still bind. + if (Libretro::Input::sensor_enabled[port][0][SENSOR_GYRO]) + { + // Gyroscope (6 inputs: PitchUp/Down, RollLeft/Right, YawLeft/Right) + auto* wmGyro = static_cast( + wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IMUGyroscope)); + if (wmGyro) { - // Gyroscope (6 inputs: PitchUp/Down, RollLeft/Right, YawLeft/Right) - auto* wmGyro = static_cast( - wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IMUGyroscope)); - if (wmGyro) - { - // Right-hand rule about +X left, +Y back, +Z up: +X is pitch down, - // +Y rolls the top left, +Z swings the nose left. GetRawState() - // reads these as [1]-[0], [2]-[3], [4]-[5]. - wmGyro->SetControlExpression(0, "`" + devSensor + ":GyroX-`"); // Pitch Up - wmGyro->SetControlExpression(1, "`" + devSensor + ":GyroX+`"); // Pitch Down - wmGyro->SetControlExpression(2, "`" + devSensor + ":GyroY+`"); // Roll Left - wmGyro->SetControlExpression(3, "`" + devSensor + ":GyroY-`"); // Roll Right - wmGyro->SetControlExpression(4, "`" + devSensor + ":GyroZ+`"); // Yaw Left - wmGyro->SetControlExpression(5, "`" + devSensor + ":GyroZ-`"); // Yaw Right - } + // Right-hand rule about the accelerometer's frame (+X left, +Y + // back, +Z up): +X is pitch down, +Y rolls the top left, +Z swings + // the nose left. GetRawState() reads [1]-[0], [2]-[3], [4]-[5]. + wmGyro->SetControlExpression(0, "`" + devSensor + ":GyroX-`"); // Pitch Up + wmGyro->SetControlExpression(1, "`" + devSensor + ":GyroX+`"); // Pitch Down + wmGyro->SetControlExpression(2, "`" + devSensor + ":GyroY+`"); // Roll Left + wmGyro->SetControlExpression(3, "`" + devSensor + ":GyroY-`"); // Roll Right + wmGyro->SetControlExpression(4, "`" + devSensor + ":GyroZ+`"); // Yaw Left + wmGyro->SetControlExpression(5, "`" + devSensor + ":GyroZ-`"); // Yaw Right } } - else + } + else + { + // No sensors, so tilt falls back to a stick -- the right one when a + // Nunchuk is fitted, since the left one is the Nunchuk's. + const std::string tiltAxis = (device == RETRO_DEVICE_WIIMOTE_NC) ? "1" : "0"; + wmTilt->SetControlExpression(0, "`" + devAnalog + ":Y" + tiltAxis + "-`"); // Forward + wmTilt->SetControlExpression(1, "`" + devAnalog + ":Y" + tiltAxis + "+`"); // Backward + wmTilt->SetControlExpression(2, "`" + devAnalog + ":X" + tiltAxis + "-`"); // Left + wmTilt->SetControlExpression(3, "`" + devAnalog + ":X" + tiltAxis + "+`"); // Right + } + + // The Nunchuk's own accelerometer. Additive: + // Nunchuk::BuildDesiredExtensionState composes this group with swing, tilt + // and shake, and substitutes a flat device when nothing is bound. + if (device == RETRO_DEVICE_WIIMOTE_NC && + Libretro::Input::sensor_enabled[port][NUNCHUK_SENSOR_SUBDEVICE][SENSOR_ACCELEROMETER]) + { + auto* ncAccel = static_cast( + wm->GetNunchukGroup(NunchukGroup::IMUAccelerometer)); + if (ncAccel) { - wmTilt->SetControlExpression(0, "`" + devAnalog + ":Y0-`"); // Forward - wmTilt->SetControlExpression(1, "`" + devAnalog + ":Y0+`"); // Backward - wmTilt->SetControlExpression(2, "`" + devAnalog + ":X0-`"); // Left - wmTilt->SetControlExpression(3, "`" + devAnalog + ":X0+`"); // Right + // Same six-index order and frame as the remote's above. + const std::string devNunchuk = + Libretro::Input::GetQualifiedNameSensor(port, NUNCHUK_SENSOR_SUBDEVICE); + ncAccel->SetControlExpression(0, "`" + devNunchuk + ":AccelZ+`"); // Up + ncAccel->SetControlExpression(1, "`" + devNunchuk + ":AccelZ-`"); // Down + ncAccel->SetControlExpression(2, "`" + devNunchuk + ":AccelX+`"); // Left + ncAccel->SetControlExpression(3, "`" + devNunchuk + ":AccelX-`"); // Right + ncAccel->SetControlExpression(4, "`" + devNunchuk + ":AccelY-`"); // Forward + ncAccel->SetControlExpression(5, "`" + devNunchuk + ":AccelY+`"); // Backward } - wmButtons->SetControlExpression(4, "Select"); // - - wmButtons->SetControlExpression(5, "Start"); // + } wmButtons->SetControlExpression(6, "R3"); // Home diff --git a/Source/Core/DolphinLibretro/Input.h b/Source/Core/DolphinLibretro/Input.h index fcebb3891b56..763632c4adc3 100644 --- a/Source/Core/DolphinLibretro/Input.h +++ b/Source/Core/DolphinLibretro/Input.h @@ -1,11 +1,17 @@ #pragma once +#include + #include #include "Common/WindowSystemInfo.h" // only 4 support sensors, but the array may be upto 8 if connected GC controllers #define NUM_CONTROLLERS_FOR_SENSORS 8 +// Sensors addressable on one port. Index 0 is the controller itself, index 1 +// whatever is plugged into it (for a Wii Remote, the Nunchuk). +#define NUM_SENSOR_SUBDEVICES 2 + struct WiimoteUpdateFlags { bool irMode = false; @@ -38,17 +44,24 @@ namespace Libretro namespace Input { constexpr std::string_view source = "Libretro"; -extern double g_accel_pos[NUM_CONTROLLERS_FOR_SENSORS][3]; -extern double g_accel_neg[NUM_CONTROLLERS_FOR_SENSORS][3]; -extern double g_gyro_pos[NUM_CONTROLLERS_FOR_SENSORS][3]; -extern double g_gyro_neg[NUM_CONTROLLERS_FOR_SENSORS][3]; +extern double g_accel_pos[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3]; +extern double g_accel_neg[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3]; +extern double g_gyro_pos[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3]; +extern double g_gyro_neg[NUM_CONTROLLERS_FOR_SENSORS][NUM_SENSOR_SUBDEVICES][3]; static retro_sensor_interface sensor_interface = {0}; +/// The ciface device name for one port's sub-device. Index 0 keeps the plain +/// "Sensor", so pre-existing control expressions still resolve. +inline std::string SensorDeviceName(unsigned subdevice) +{ + return subdevice == 0 ? std::string("Sensor") : "Sensor" + std::to_string(subdevice); +} + void Init(const WindowSystemInfo& wsi); void InitStage2(); void InitSensors(); -void UpdateAccelerometer(unsigned port); +void UpdateAccelerometer(unsigned port, unsigned subdevice); void UpdateGyro(unsigned port); void Update(); void Shutdown(); @@ -62,9 +75,14 @@ void UpdateGCMappings(const WiimoteUpdateFlags& f, unsigned port, unsigned devic class SensorDevice : public ciface::Core::Device { public: - explicit SensorDevice(unsigned port) : m_port(port) {} + /// `port` picks the player, `subdevice` the sensor on that port. + SensorDevice(unsigned port, unsigned subdevice) + : m_port(port), m_subdevice(subdevice), + m_name(Libretro::Input::SensorDeviceName(subdevice)) + { + } - std::string GetName() const override { return "Sensor"; } + std::string GetName() const override { return m_name; } std::string GetSource() const override { return std::string(Libretro::Input::source); } unsigned int GetPort() const { return m_port; } ciface::Core::DeviceRemoval UpdateInput() override { return ciface::Core::DeviceRemoval::Keep; } @@ -87,22 +105,24 @@ class SensorDevice : public ciface::Core::Device /// subtract one direction from the other, rebuilding the signed value. void RegisterAll() { - AddInput(new ScalarInput("GyroX+", &Libretro::Input::g_gyro_pos[m_port][0])); - AddInput(new ScalarInput("GyroX-", &Libretro::Input::g_gyro_neg[m_port][0])); - AddInput(new ScalarInput("GyroY+", &Libretro::Input::g_gyro_pos[m_port][1])); - AddInput(new ScalarInput("GyroY-", &Libretro::Input::g_gyro_neg[m_port][1])); - AddInput(new ScalarInput("GyroZ+", &Libretro::Input::g_gyro_pos[m_port][2])); - AddInput(new ScalarInput("GyroZ-", &Libretro::Input::g_gyro_neg[m_port][2])); - AddInput(new ScalarInput("AccelX+", &Libretro::Input::g_accel_pos[m_port][0])); - AddInput(new ScalarInput("AccelX-", &Libretro::Input::g_accel_neg[m_port][0])); - AddInput(new ScalarInput("AccelY+", &Libretro::Input::g_accel_pos[m_port][1])); - AddInput(new ScalarInput("AccelY-", &Libretro::Input::g_accel_neg[m_port][1])); - AddInput(new ScalarInput("AccelZ+", &Libretro::Input::g_accel_pos[m_port][2])); - AddInput(new ScalarInput("AccelZ-", &Libretro::Input::g_accel_neg[m_port][2])); + AddInput(new ScalarInput("GyroX+", &Libretro::Input::g_gyro_pos[m_port][m_subdevice][0])); + AddInput(new ScalarInput("GyroX-", &Libretro::Input::g_gyro_neg[m_port][m_subdevice][0])); + AddInput(new ScalarInput("GyroY+", &Libretro::Input::g_gyro_pos[m_port][m_subdevice][1])); + AddInput(new ScalarInput("GyroY-", &Libretro::Input::g_gyro_neg[m_port][m_subdevice][1])); + AddInput(new ScalarInput("GyroZ+", &Libretro::Input::g_gyro_pos[m_port][m_subdevice][2])); + AddInput(new ScalarInput("GyroZ-", &Libretro::Input::g_gyro_neg[m_port][m_subdevice][2])); + AddInput(new ScalarInput("AccelX+", &Libretro::Input::g_accel_pos[m_port][m_subdevice][0])); + AddInput(new ScalarInput("AccelX-", &Libretro::Input::g_accel_neg[m_port][m_subdevice][0])); + AddInput(new ScalarInput("AccelY+", &Libretro::Input::g_accel_pos[m_port][m_subdevice][1])); + AddInput(new ScalarInput("AccelY-", &Libretro::Input::g_accel_neg[m_port][m_subdevice][1])); + AddInput(new ScalarInput("AccelZ+", &Libretro::Input::g_accel_pos[m_port][m_subdevice][2])); + AddInput(new ScalarInput("AccelZ-", &Libretro::Input::g_accel_neg[m_port][m_subdevice][2])); } private: unsigned m_port; + unsigned m_subdevice; + std::string m_name; }; class GyroDevice : public ciface::Core::Device