mirror of
https://github.com/libretro/parallel-gx1.git
synced 2026-11-07 12:37:59 -10:00
1899 lines
78 KiB
C++
1899 lines
78 KiB
C++
#include <algorithm>
|
||
#include <array>
|
||
#include <cassert>
|
||
#include <libretro.h>
|
||
|
||
#include "Common/Common.h"
|
||
#include "Common/CommonPaths.h"
|
||
#include "Common/CommonTypes.h"
|
||
#include "Common/FileUtil.h"
|
||
#include "Common/IniFile.h"
|
||
#include "Common/Logging/Log.h"
|
||
#include "Core/Config/MainSettings.h"
|
||
#include "Core/Config/WiimoteSettings.h"
|
||
#include "Core/ConfigManager.h"
|
||
#include "Core/FreeLookManager.h"
|
||
#include "Core/HW/EXI/EXI.h"
|
||
#include "Core/HW/EXI/EXI_Device.h"
|
||
#include "Core/HW/EXI/EXI_DeviceMic.h"
|
||
#include "Core/HW/GBAPad.h"
|
||
#include "Core/HW/GCKeyboard.h"
|
||
#include "Core/HW/GCPad.h"
|
||
#include "Core/HW/GCPadEmu.h"
|
||
#include "Core/HW/Wiimote.h"
|
||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||
#include "Core/HW/SI/SI.h"
|
||
#include "Core/HW/SI/SI_Device.h"
|
||
#include "Core/IOS/USB/Bluetooth/BTReal.h"
|
||
#include "Core/Host.h"
|
||
#include "Core/System.h"
|
||
#include "Core/WiiUtils.h"
|
||
#include "DolphinLibretro/Input.h"
|
||
#include "DolphinLibretro/Common/Globals.h"
|
||
#include "DolphinLibretro/Common/Options.h"
|
||
#include "DolphinLibretro/VR.h"
|
||
#ifdef CIFACE_USE_DUALSHOCKUDPCLIENT
|
||
#include "InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.h"
|
||
#endif
|
||
#include "InputCommon/ControlReference/ControlReference.h"
|
||
#include "InputCommon/ControlReference/ExpressionParser.h"
|
||
#include "InputCommon/ControllerEmu/Control/Control.h"
|
||
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||
#include "InputCommon/ControllerEmu/ControlGroup/IRPassthrough.h"
|
||
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||
#include "InputCommon/GCAdapter.h"
|
||
#include "InputCommon/GCPadStatus.h"
|
||
#include "InputCommon/InputConfig.h"
|
||
#include "InputCommon/InputProfile.h"
|
||
|
||
#define RETRO_DEVICE_WIIMOTE RETRO_DEVICE_JOYPAD
|
||
#define RETRO_DEVICE_WIIMOTE_SW ((2 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_NC ((3 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_CC ((4 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_CC_PRO ((5 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_GC_ON_WII ((6 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_REAL_WIIMOTE ((6 << 8) | RETRO_DEVICE_NONE)
|
||
#define RETRO_DEVICE_WIIMOTE_MP ((7 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_MP_SW ((8 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_MP_NC ((9 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_MP_CC ((10 << 8) | RETRO_DEVICE_JOYPAD)
|
||
#define RETRO_DEVICE_WIIMOTE_MP_CC_PRO ((11 << 8) | RETRO_DEVICE_JOYPAD)
|
||
|
||
/// The same remote with the dongle taken off, so everything downstream stays
|
||
/// written against the five original ids.
|
||
static inline unsigned wiimote_base_device(unsigned device)
|
||
{
|
||
switch (device)
|
||
{
|
||
case RETRO_DEVICE_WIIMOTE_MP:
|
||
return RETRO_DEVICE_WIIMOTE;
|
||
case RETRO_DEVICE_WIIMOTE_MP_SW:
|
||
return RETRO_DEVICE_WIIMOTE_SW;
|
||
case RETRO_DEVICE_WIIMOTE_MP_NC:
|
||
return RETRO_DEVICE_WIIMOTE_NC;
|
||
case RETRO_DEVICE_WIIMOTE_MP_CC:
|
||
return RETRO_DEVICE_WIIMOTE_CC;
|
||
case RETRO_DEVICE_WIIMOTE_MP_CC_PRO:
|
||
return RETRO_DEVICE_WIIMOTE_CC_PRO;
|
||
default:
|
||
return device;
|
||
}
|
||
}
|
||
|
||
/// True when this device id carries a MotionPlus dongle.
|
||
static inline bool wiimote_has_motion_plus(unsigned device)
|
||
{
|
||
return wiimote_base_device(device) != device;
|
||
}
|
||
|
||
typedef enum {
|
||
SENSOR_ACCELEROMETER = 0,
|
||
SENSOR_GYRO,
|
||
SENSOR_COUNT
|
||
} sensor_type_t;
|
||
|
||
void retro_set_controller_port_device_gc(unsigned port, unsigned device);
|
||
void retro_set_controller_port_device_wii(unsigned port, unsigned device);
|
||
|
||
namespace Libretro
|
||
{
|
||
extern retro_environment_t environ_cb;
|
||
namespace Input
|
||
{
|
||
static retro_input_poll_t poll_cb = nullptr;
|
||
static retro_input_state_t input_cb = nullptr;
|
||
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 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_point[NUM_CONTROLLERS_FOR_SENSORS][4] = {}; // right, left, down, up
|
||
// Player 1's Wiimote is driven by the right VR controller (VR Mode on at boot).
|
||
static bool s_vr_motion = false;
|
||
|
||
static struct retro_input_descriptor descGC[] = {
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L-Analog"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R-Analog"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "Z"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "Triforce - Test"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Triforce - Coin"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Control Stick X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Control Stick Y"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"C Buttons X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"C Buttons Y"},
|
||
{0},
|
||
};
|
||
|
||
static struct retro_input_descriptor descWiimoteCC[] = {
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "ZL"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "ZR"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Home"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "+"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "-"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Left Stick X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Left Stick Y"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Right Stick X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Right Stick Y"},
|
||
{0},
|
||
};
|
||
|
||
static struct retro_input_descriptor descWiimoteCCPro[] = {
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "ZL"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "ZR"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Home"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "+"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "-"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Left Stick X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Left Stick Y"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Right Stick X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Right Stick Y"},
|
||
{0},
|
||
};
|
||
|
||
static struct retro_input_descriptor descWiimote[] = {
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "1"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "2"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Shake Wiimote"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "+"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "-"},
|
||
//{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Sideways Toggle"}, // see: HOTKEY_SIDEWAYS_TOGGLE
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Home"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Tilt Left/Right"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Tilt Forward/Backward"},
|
||
{0},
|
||
};
|
||
|
||
static struct retro_input_descriptor descWiimoteSideways[] = {
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "1"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "2"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "A"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "B"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Shake Wiimote"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "+"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "-"},
|
||
//{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Sideways Toggle"}, // see: HOTKEY_SIDEWAYS_TOGGLE
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Home"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Tilt Left/Right"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Tilt Forward/Backward"},
|
||
{0},
|
||
};
|
||
|
||
static struct retro_input_descriptor descWiimoteNunchuk[] = {
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "Left"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "Up"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "Down"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "B"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "A"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "C"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Z"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "-"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "+"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "Shake Wiimote"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "Shake Nunchuk"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "1"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "2"},
|
||
//{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "Sideways Toggle"},
|
||
{0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Home"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Nunchuk Stick X"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Nunchuk Stick Y"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X,
|
||
"Tilt Left/Right"},
|
||
{0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y,
|
||
"Tilt Forward/Backward"},
|
||
{0},
|
||
};
|
||
|
||
static std::string GetDeviceName(unsigned device)
|
||
{
|
||
switch (device)
|
||
{
|
||
case RETRO_DEVICE_JOYPAD:
|
||
return "Joypad";
|
||
case RETRO_DEVICE_ANALOG:
|
||
return "Analog";
|
||
case RETRO_DEVICE_MOUSE:
|
||
return "Mouse";
|
||
case RETRO_DEVICE_POINTER:
|
||
return "Pointer";
|
||
case RETRO_DEVICE_KEYBOARD:
|
||
return "Keyboard";
|
||
case RETRO_DEVICE_LIGHTGUN:
|
||
return "Lightgun";
|
||
}
|
||
return "Unknown";
|
||
}
|
||
|
||
static std::string GetQualifiedName(unsigned port, unsigned device)
|
||
{
|
||
return ciface::Core::DeviceQualifier(
|
||
std::string(source),
|
||
static_cast<int>(port),
|
||
GetDeviceName(device)
|
||
).ToString();
|
||
}
|
||
|
||
class Device : public ciface::Core::Device
|
||
{
|
||
private:
|
||
class Button : public ciface::Core::Device::Input
|
||
{
|
||
public:
|
||
Button(unsigned port, unsigned device, unsigned index, unsigned id, const char* name)
|
||
: m_port(port), m_device(device), m_index(index), m_id(id), m_name(name)
|
||
{
|
||
}
|
||
std::string GetName() const override { return m_name; }
|
||
ControlState GetState() const override { return input_cb(m_port, m_device, m_index, m_id); }
|
||
|
||
private:
|
||
const unsigned m_port;
|
||
const unsigned m_device;
|
||
const unsigned m_index;
|
||
const unsigned m_id;
|
||
const char* m_name;
|
||
};
|
||
|
||
class Axis : public ciface::Core::Device::Input
|
||
{
|
||
public:
|
||
Axis(unsigned port, unsigned device, unsigned index, unsigned id, s16 range, const char* name)
|
||
: m_port(port), m_device(device), m_index(index), m_id(id), m_range(range), m_name(name)
|
||
{
|
||
}
|
||
std::string GetName() const override { return m_name; }
|
||
ControlState GetState() const override
|
||
{
|
||
return std::max(0.0, input_cb(m_port, m_device, m_index, m_id) / m_range);
|
||
}
|
||
|
||
private:
|
||
const unsigned m_port;
|
||
const unsigned m_device;
|
||
const unsigned m_index;
|
||
const unsigned m_id;
|
||
const ControlState m_range;
|
||
const char* m_name;
|
||
};
|
||
|
||
class Motor : public ciface::Core::Device::Output
|
||
{
|
||
public:
|
||
Motor(u8 port) : m_port(port) {}
|
||
std::string GetName() const override { return "Rumble"; }
|
||
void SetState(ControlState state) override
|
||
{
|
||
u16 str = std::min(std::max(0.0, state), 1.0) * 0xFFFF;
|
||
|
||
if (rumble.set_rumble_state)
|
||
{
|
||
rumble.set_rumble_state(m_port, RETRO_RUMBLE_WEAK, str);
|
||
rumble.set_rumble_state(m_port, RETRO_RUMBLE_STRONG, str);
|
||
}
|
||
}
|
||
|
||
private:
|
||
const u8 m_port;
|
||
};
|
||
void AddButton(unsigned id, const char* name, unsigned index = 0)
|
||
{
|
||
AddInput(new Button(m_port, m_device, index, id, name));
|
||
}
|
||
void AddAxis(unsigned id, s16 range, const char* name, unsigned index = 0)
|
||
{
|
||
AddInput(new Axis(m_port, m_device, index, id, range, name));
|
||
}
|
||
void AddMotor() { AddOutput(new Motor(m_port)); }
|
||
|
||
public:
|
||
Device(unsigned device, unsigned port);
|
||
ciface::Core::DeviceRemoval UpdateInput() override
|
||
{
|
||
#if 0
|
||
if (!Libretro::Input::poll_cb)
|
||
{
|
||
return ciface::Core::DeviceRemoval::Keep;
|
||
}
|
||
|
||
Libretro::Input::poll_cb();
|
||
#endif
|
||
return ciface::Core::DeviceRemoval::Keep;
|
||
}
|
||
std::string GetName() const override { return GetDeviceName(m_device); }
|
||
std::string GetSource() const override { return std::string(source); }
|
||
unsigned int GetPort() const { return m_port; }
|
||
|
||
private:
|
||
unsigned m_device;
|
||
unsigned m_port;
|
||
};
|
||
|
||
Device::Device(unsigned device, unsigned p) : m_device(device), m_port(p)
|
||
{
|
||
switch (device)
|
||
{
|
||
case RETRO_DEVICE_JOYPAD:
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_B, "B");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_Y, "Y");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_SELECT, "Select");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_START, "Start");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_UP, "Up");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_DOWN, "Down");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_LEFT, "Left");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_RIGHT, "Right");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_A, "A");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_X, "X");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_L, "L");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_R, "R");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_L2, "L2");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_R2, "R2");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_L3, "L3");
|
||
AddButton(RETRO_DEVICE_ID_JOYPAD_R3, "R3");
|
||
AddMotor();
|
||
return;
|
||
case RETRO_DEVICE_ANALOG:
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_X, -0x8000, "X0-", RETRO_DEVICE_INDEX_ANALOG_LEFT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_X, 0x7FFF, "X0+", RETRO_DEVICE_INDEX_ANALOG_LEFT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_Y, -0x8000, "Y0-", RETRO_DEVICE_INDEX_ANALOG_LEFT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_Y, 0x7FFF, "Y0+", RETRO_DEVICE_INDEX_ANALOG_LEFT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_X, -0x8000, "X1-", RETRO_DEVICE_INDEX_ANALOG_RIGHT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_X, 0x7FFF, "X1+", RETRO_DEVICE_INDEX_ANALOG_RIGHT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_Y, -0x8000, "Y1-", RETRO_DEVICE_INDEX_ANALOG_RIGHT);
|
||
AddAxis(RETRO_DEVICE_ID_ANALOG_Y, 0x7FFF, "Y1+", RETRO_DEVICE_INDEX_ANALOG_RIGHT);
|
||
AddAxis(RETRO_DEVICE_ID_JOYPAD_L2, 0x7FFF, "Trigger0+", RETRO_DEVICE_INDEX_ANALOG_BUTTON);
|
||
AddAxis(RETRO_DEVICE_ID_JOYPAD_R2, 0x7FFF, "Trigger1+", RETRO_DEVICE_INDEX_ANALOG_BUTTON);
|
||
return;
|
||
case RETRO_DEVICE_MOUSE:
|
||
// TODO: handle last poll_cb relative coordinates correctly.
|
||
AddAxis(RETRO_DEVICE_ID_MOUSE_X, -0x8000, "X-");
|
||
AddAxis(RETRO_DEVICE_ID_MOUSE_X, 0x7FFF, "X+");
|
||
AddAxis(RETRO_DEVICE_ID_MOUSE_Y, -0x8000, "Y-");
|
||
AddAxis(RETRO_DEVICE_ID_MOUSE_Y, 0x7FFF, "Y+");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_LEFT, "Left");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_RIGHT, "Right");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_WHEELUP, "WheelUp");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_WHEELDOWN, "WheelDown");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_MIDDLE, "Middle");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP, "HorizWheelUp");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN, "HorizWheelDown");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_BUTTON_4, "Button4");
|
||
AddButton(RETRO_DEVICE_ID_MOUSE_BUTTON_5, "Button5");
|
||
return;
|
||
case RETRO_DEVICE_POINTER:
|
||
// Four touch indices, one per IR object. Index 0 keeps its old names.
|
||
{
|
||
static const char* const kPressed[] = { "Pressed0", "Pressed1", "Pressed2", "Pressed3" };
|
||
static const char* const kXNeg[] = { "X0-", "X1-", "X2-", "X3-" };
|
||
static const char* const kXPos[] = { "X0+", "X1+", "X2+", "X3+" };
|
||
static const char* const kYNeg[] = { "Y0-", "Y1-", "Y2-", "Y3-" };
|
||
static const char* const kYPos[] = { "Y0+", "Y1+", "Y2+", "Y3+" };
|
||
for (unsigned i = 0; i < 4; ++i)
|
||
{
|
||
AddButton(RETRO_DEVICE_ID_POINTER_PRESSED, kPressed[i], i);
|
||
AddAxis(RETRO_DEVICE_ID_POINTER_X, -0x8000, kXNeg[i], i);
|
||
AddAxis(RETRO_DEVICE_ID_POINTER_X, 0x7FFF, kXPos[i], i);
|
||
AddAxis(RETRO_DEVICE_ID_POINTER_Y, -0x8000, kYNeg[i], i);
|
||
AddAxis(RETRO_DEVICE_ID_POINTER_Y, 0x7FFF, kYPos[i], i);
|
||
}
|
||
}
|
||
return;
|
||
case RETRO_DEVICE_KEYBOARD:
|
||
return;
|
||
case RETRO_DEVICE_LIGHTGUN:
|
||
// TODO: handle absolute coordinates correctly.
|
||
AddAxis(RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X, -320, "X-");
|
||
AddAxis(RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X, 320, "X+");
|
||
AddAxis(RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y, -264, "Y-");
|
||
AddAxis(RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y, 264, "Y+");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN, "Offscreen");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_TRIGGER, "Trigger");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_RELOAD, "Reload");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_AUX_A, "A");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_AUX_B, "B");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_START, "Start");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_SELECT, "Select");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_AUX_C, "C");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP, "Up");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN, "Down");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT, "Left");
|
||
AddButton(RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT, "Right");
|
||
return;
|
||
}
|
||
}
|
||
|
||
static void AddDevicesForPort(unsigned port)
|
||
{
|
||
g_controller_interface.AddDevice(std::make_shared<Device>(RETRO_DEVICE_JOYPAD, port));
|
||
g_controller_interface.AddDevice(std::make_shared<Device>(RETRO_DEVICE_ANALOG, port));
|
||
g_controller_interface.AddDevice(std::make_shared<Device>(RETRO_DEVICE_MOUSE, port));
|
||
g_controller_interface.AddDevice(std::make_shared<Device>(RETRO_DEVICE_POINTER, port));
|
||
}
|
||
|
||
#if 0
|
||
/* Disabled as it messes with the controllers index, so player 2 may end up controlling player 3, etc.
|
||
* if controllers are not plugged back in the correct order. */
|
||
static void RemoveDevicesForPort(unsigned port)
|
||
{
|
||
g_controller_interface.RemoveDevice([&port](const auto& device) {
|
||
return device->GetSource() == source &&
|
||
(device->GetName() == GetDeviceName(RETRO_DEVICE_ANALOG) ||
|
||
device->GetName() == GetDeviceName(RETRO_DEVICE_JOYPAD) ||
|
||
device->GetName() == GetDeviceName(RETRO_DEVICE_MOUSE) ||
|
||
device->GetName() == GetDeviceName(RETRO_DEVICE_POINTER)) &&
|
||
dynamic_cast<const Device*>(device)->GetPort() == port;
|
||
});
|
||
}
|
||
#endif
|
||
|
||
void Init(const WindowSystemInfo& wsi)
|
||
{
|
||
if (!environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble))
|
||
{
|
||
WARN_LOG_FMT(BOOT, "RetroArch does not support RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE.");
|
||
}
|
||
|
||
if (!environ_cb(RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE, &sensor_interface))
|
||
{
|
||
WARN_LOG_FMT(BOOT, "RetroArch does not support RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE.");
|
||
}
|
||
|
||
retro_microphone_interface mic_iface{RETRO_MICROPHONE_INTERFACE_VERSION};
|
||
|
||
if (environ_cb(RETRO_ENVIRONMENT_GET_MICROPHONE_INTERFACE, &mic_iface) &&
|
||
mic_iface.interface_version == RETRO_MICROPHONE_INTERFACE_VERSION)
|
||
{
|
||
Libretro::Input::g_microphone_interface = mic_iface;
|
||
Libretro::Input::g_has_microphone_support = true;
|
||
|
||
bool gcMicEnable = Libretro::Options::GetCached<bool>(
|
||
Libretro::Options::sysconf_gc::ENABLE_GAMECUBE_MIC);
|
||
|
||
if (!Core::System::GetInstance().IsWii() && gcMicEnable)
|
||
Config::SetCurrent(Config::MAIN_SLOT_B, ExpansionInterface::EXIDeviceType::Microphone);
|
||
}
|
||
else
|
||
{
|
||
WARN_LOG_FMT(BOOT, "Microphone interface NOT available");
|
||
}
|
||
|
||
g_controller_interface.Initialize(wsi);
|
||
g_controller_interface.AddDevice(std::make_shared<Device>(RETRO_DEVICE_KEYBOARD, 0));
|
||
|
||
GCAdapter::Init();
|
||
Pad::Initialize();
|
||
Pad::InitializeGBA();
|
||
Keyboard::Initialize();
|
||
FreeLook::Initialize();
|
||
|
||
port_max = (Core::System::GetInstance().IsWii() &&
|
||
Libretro::Options::GetCached<int>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII)) ? 8 : 4;
|
||
for (int i = 0; i < port_max; i++)
|
||
Libretro::Input::AddDevicesForPort(i);
|
||
|
||
g_init_wiimotes = true;
|
||
s_sensor_init_pending = true;
|
||
|
||
Wiimote::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
|
||
}
|
||
|
||
void InitStage2()
|
||
{
|
||
static const struct retro_controller_description gcpad_desc[] = {
|
||
{"GameCube Controller", RETRO_DEVICE_JOYPAD},
|
||
};
|
||
|
||
if (Core::System::GetInstance().IsWii() && !Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
|
||
{
|
||
// Wii devices listed in ports 1-4, GC controllers in ports 5-8
|
||
if (Libretro::Options::GetCached<int>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII))
|
||
{
|
||
static struct retro_controller_description wiimote_desc[] = {
|
||
{"WiiMote (upright)", RETRO_DEVICE_WIIMOTE},
|
||
{"WiiMote (sideways)", RETRO_DEVICE_WIIMOTE_SW},
|
||
{"WiiMote + Nunchuk", RETRO_DEVICE_WIIMOTE_NC},
|
||
{"WiiMote + Classic Controller", RETRO_DEVICE_WIIMOTE_CC},
|
||
{"WiiMote + Classic Controller Pro", RETRO_DEVICE_WIIMOTE_CC_PRO},
|
||
{"WiiMote + MotionPlus", RETRO_DEVICE_WIIMOTE_MP},
|
||
{"WiiMote + MotionPlus (sideways)", RETRO_DEVICE_WIIMOTE_MP_SW},
|
||
{"WiiMote + MotionPlus + Nunchuk", RETRO_DEVICE_WIIMOTE_MP_NC},
|
||
{"WiiMote + MotionPlus + Classic Controller", RETRO_DEVICE_WIIMOTE_MP_CC},
|
||
{"WiiMote + MotionPlus + Classic Controller Pro", RETRO_DEVICE_WIIMOTE_MP_CC_PRO},
|
||
{"Real WiiMote", RETRO_DEVICE_REAL_WIIMOTE},
|
||
};
|
||
|
||
const struct retro_controller_info ports[] = {
|
||
{wiimote_desc, sizeof(wiimote_desc) / sizeof(*wiimote_desc)},
|
||
{wiimote_desc, sizeof(wiimote_desc) / sizeof(*wiimote_desc)},
|
||
{wiimote_desc, sizeof(wiimote_desc) / sizeof(*wiimote_desc)},
|
||
{wiimote_desc, sizeof(wiimote_desc) / sizeof(*wiimote_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{0},
|
||
};
|
||
|
||
if (!environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports))
|
||
WARN_LOG_FMT(BOOT, "RetroArch does not support RETRO_ENVIRONMENT_SET_CONTROLLER_INFO.");
|
||
}
|
||
else // Both Wii devices and GC controllers listed in ports 1-4, ports 5-8 are unused
|
||
{
|
||
static struct retro_controller_description wii_and_gc_desc[] = {
|
||
{"WiiMote (upright)", RETRO_DEVICE_WIIMOTE},
|
||
{"WiiMote (sideways)", RETRO_DEVICE_WIIMOTE_SW},
|
||
{"WiiMote + Nunchuk", RETRO_DEVICE_WIIMOTE_NC},
|
||
{"WiiMote + Classic Controller", RETRO_DEVICE_WIIMOTE_CC},
|
||
{"WiiMote + Classic Controller Pro", RETRO_DEVICE_WIIMOTE_CC_PRO},
|
||
{"WiiMote + MotionPlus", RETRO_DEVICE_WIIMOTE_MP},
|
||
{"WiiMote + MotionPlus (sideways)", RETRO_DEVICE_WIIMOTE_MP_SW},
|
||
{"WiiMote + MotionPlus + Nunchuk", RETRO_DEVICE_WIIMOTE_MP_NC},
|
||
{"WiiMote + MotionPlus + Classic Controller", RETRO_DEVICE_WIIMOTE_MP_CC},
|
||
{"WiiMote + MotionPlus + Classic Controller Pro", RETRO_DEVICE_WIIMOTE_MP_CC_PRO},
|
||
{"Real WiiMote", RETRO_DEVICE_REAL_WIIMOTE},
|
||
{"GameCube Controller", RETRO_DEVICE_GC_ON_WII},
|
||
};
|
||
|
||
const struct retro_controller_info ports[] = {
|
||
{wii_and_gc_desc, sizeof(wii_and_gc_desc) / sizeof(*wii_and_gc_desc)},
|
||
{wii_and_gc_desc, sizeof(wii_and_gc_desc) / sizeof(*wii_and_gc_desc)},
|
||
{wii_and_gc_desc, sizeof(wii_and_gc_desc) / sizeof(*wii_and_gc_desc)},
|
||
{wii_and_gc_desc, sizeof(wii_and_gc_desc) / sizeof(*wii_and_gc_desc)},
|
||
{0},
|
||
};
|
||
|
||
if (!environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports))
|
||
WARN_LOG_FMT(BOOT, "RetroArch does not support RETRO_ENVIRONMENT_SET_CONTROLLER_INFO.");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
static const struct retro_controller_info ports[] = {
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{gcpad_desc, sizeof(gcpad_desc) / sizeof(*gcpad_desc)},
|
||
{0},
|
||
};
|
||
|
||
if (!environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports))
|
||
WARN_LOG_FMT(BOOT, "RetroArch does not support RETRO_ENVIRONMENT_SET_CONTROLLER_INFO.");
|
||
}
|
||
}
|
||
|
||
void InitSensors()
|
||
{
|
||
if (!s_sensor_init_pending)
|
||
return;
|
||
|
||
s_sensor_init_pending = false;
|
||
|
||
// sensors do not apply bluetooth passthrough
|
||
if (Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
|
||
return;
|
||
|
||
if (Core::System::GetInstance().IsWii())
|
||
{
|
||
port_max = (Core::System::GetInstance().IsWii() &&
|
||
Libretro::Options::GetCached<int>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII)) ? 8 : 4;
|
||
|
||
// In VR the right controller moves player 1's Wiimote.
|
||
s_vr_motion = Libretro::VR::IsEnabled();
|
||
|
||
for (int i = 0; i < port_max; i++)
|
||
{
|
||
if (s_vr_motion && i == 0)
|
||
{
|
||
sensor_enabled[i][SENSOR_ACCELEROMETER] = true;
|
||
sensor_enabled[i][SENSOR_GYRO] = true;
|
||
// At rest until the controller is seen: gravity reads as up.
|
||
g_accel_pos[i][2] = 9.80665;
|
||
INFO_LOG_FMT(BOOT, "Sensor interface: Port: {} driven by the right VR controller", i);
|
||
}
|
||
else 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);
|
||
|
||
INFO_LOG_FMT(BOOT, "Sensor interface: Port: {} ACCELEROMETER: {} GYROSCOPE: {}", i,
|
||
sensor_enabled[i][SENSOR_ACCELEROMETER], sensor_enabled[i][SENSOR_GYRO]);
|
||
}
|
||
|
||
if (sensor_enabled[i][SENSOR_ACCELEROMETER] || sensor_enabled[i][SENSOR_GYRO])
|
||
{
|
||
auto sensor = std::make_shared<SensorDevice>(i);
|
||
sensor->RegisterAll();
|
||
g_controller_interface.AddDevice(sensor);
|
||
}
|
||
}
|
||
}
|
||
|
||
ResetControllers(WiimoteUpdateFlags{});
|
||
}
|
||
|
||
void Shutdown()
|
||
{
|
||
if (g_init_wiimotes)
|
||
{
|
||
Wiimote::ResetAllWiimotes();
|
||
Wiimote::Shutdown();
|
||
g_init_wiimotes = false;
|
||
}
|
||
|
||
s_sensor_init_pending = false;
|
||
|
||
#if defined(__LIBUSB__)
|
||
GCAdapter::ResetRumble();
|
||
#endif
|
||
for (int i = 0; i < port_max; ++i)
|
||
{
|
||
Pad::ResetRumble(i);
|
||
|
||
// Was crossed over and hardcoded to port 0, leaving sensors running.
|
||
// A port driven by a VR controller never turned the frontend's sensors on.
|
||
if (!UsesVRMotion(i))
|
||
{
|
||
if (sensor_enabled[i][SENSOR_ACCELEROMETER])
|
||
sensor_interface.set_sensor_state(i, RETRO_SENSOR_ACCELEROMETER_DISABLE, 0);
|
||
|
||
if (sensor_enabled[i][SENSOR_GYRO])
|
||
sensor_interface.set_sensor_state(i, RETRO_SENSOR_GYROSCOPE_DISABLE, 0);
|
||
}
|
||
|
||
sensor_enabled[i][SENSOR_ACCELEROMETER] = false;
|
||
sensor_enabled[i][SENSOR_GYRO] = false;
|
||
}
|
||
s_vr_motion = false;
|
||
|
||
Keyboard::Shutdown();
|
||
Pad::Shutdown();
|
||
g_controller_interface.Shutdown();
|
||
|
||
rumble.set_rumble_state = nullptr;
|
||
}
|
||
|
||
bool UsesVRMotion(unsigned port)
|
||
{
|
||
return s_vr_motion && port == 0;
|
||
}
|
||
|
||
void SetVRMotion(unsigned port, const float accel[3], const float gyro[3], const float point[2])
|
||
{
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
g_accel_pos[port][i] = std::max(0.0f, accel[i]);
|
||
g_accel_neg[port][i] = std::max(0.0f, -accel[i]);
|
||
g_gyro_pos[port][i] = std::max(0.0f, gyro[i]);
|
||
g_gyro_neg[port][i] = std::max(0.0f, -gyro[i]);
|
||
}
|
||
g_point[port][0] = std::max(0.0f, point[0]);
|
||
g_point[port][1] = std::max(0.0f, -point[0]);
|
||
g_point[port][2] = std::max(0.0f, -point[1]);
|
||
g_point[port][3] = std::max(0.0f, point[1]);
|
||
}
|
||
|
||
void UpdateAccelerometer(unsigned port)
|
||
{
|
||
if (!sensor_enabled[port][SENSOR_ACCELEROMETER] || !sensor_interface.get_sensor_input ||
|
||
UsesVRMotion(port))
|
||
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 rx = -ay; // rotate 90° clockwise
|
||
float ry = ax;
|
||
ax = rx;
|
||
ay = ry;
|
||
}
|
||
|
||
// 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][1] = std::max(0.0f, ay);
|
||
g_accel_neg[port][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);
|
||
}
|
||
|
||
void UpdateGyro(unsigned port)
|
||
{
|
||
if (!sensor_enabled[port][SENSOR_GYRO] || !sensor_interface.get_sensor_input ||
|
||
UsesVRMotion(port))
|
||
return;
|
||
|
||
// rad/s about the remote's own axes: +X left, +Y back, +Z up.
|
||
float gx = sensor_interface.get_sensor_input(port, RETRO_SENSOR_GYROSCOPE_X);
|
||
float gy = sensor_interface.get_sensor_input(port, RETRO_SENSOR_GYROSCOPE_Y);
|
||
float gz = sensor_interface.get_sensor_input(port, RETRO_SENSOR_GYROSCOPE_Z);
|
||
|
||
if (wiimote_base_device(input_types[port]) == RETRO_DEVICE_WIIMOTE_SW)
|
||
{
|
||
float rx = -gy; // rotate 90° clockwise
|
||
float ry = gx;
|
||
gx = rx;
|
||
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);
|
||
|
||
g_gyro_pos[port][1] = std::max(0.0f, gy);
|
||
g_gyro_neg[port][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);
|
||
}
|
||
|
||
void ResetControllers(const WiimoteUpdateFlags& f)
|
||
{
|
||
// only update what has changed
|
||
if (f.any())
|
||
{
|
||
auto& system = Core::System::GetInstance();
|
||
if (!system.IsWii())
|
||
{
|
||
for (int port = 0; port < 4; port++)
|
||
UpdateGCMappings(f, port, input_types[port]);
|
||
return;
|
||
}
|
||
|
||
for (int port = 0; port < 4; port++)
|
||
UpdateWiimoteMappings(f, port, input_types[port]);
|
||
return;
|
||
}
|
||
|
||
for (int port = 0; port < port_max; port++)
|
||
retro_set_controller_port_device(port, input_types[port]);
|
||
|
||
UpdateInputDescriptors();
|
||
}
|
||
|
||
void BluetoothPassthroughBind()
|
||
{
|
||
static bool was_pressed = false;
|
||
bool sync = Libretro::Input::input_cb(0, RETRO_DEVICE_KEYBOARD, 0, RETROK_F12);
|
||
|
||
if (sync && !was_pressed)
|
||
{
|
||
auto bt_real = WiiUtils::GetBluetoothRealDevice();
|
||
if (bt_real)
|
||
bt_real->TriggerSyncButtonPressedEvent();
|
||
}
|
||
|
||
was_pressed = sync;
|
||
}
|
||
|
||
static int GetRetroButtonId(const std::string& name)
|
||
{
|
||
if (name == "A") return RETRO_DEVICE_ID_JOYPAD_A;
|
||
if (name == "B") return RETRO_DEVICE_ID_JOYPAD_B;
|
||
if (name == "X") return RETRO_DEVICE_ID_JOYPAD_X;
|
||
if (name == "Y") return RETRO_DEVICE_ID_JOYPAD_Y;
|
||
if (name == "L") return RETRO_DEVICE_ID_JOYPAD_L2;
|
||
if (name == "R") return RETRO_DEVICE_ID_JOYPAD_R2;
|
||
if (name == "L2") return RETRO_DEVICE_ID_JOYPAD_L;
|
||
if (name == "R2") return RETRO_DEVICE_ID_JOYPAD_R;
|
||
if (name == "L3") return RETRO_DEVICE_ID_JOYPAD_L3;
|
||
if (name == "R3") return RETRO_DEVICE_ID_JOYPAD_R3;
|
||
if (name == "Start") return RETRO_DEVICE_ID_JOYPAD_START;
|
||
if (name == "Select") return RETRO_DEVICE_ID_JOYPAD_SELECT;
|
||
return -1;
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
if (poll_cb)
|
||
poll_cb();
|
||
#ifdef __ANDROID__
|
||
/* Android doesn't support input polling on all threads by default
|
||
* this will force the poll for this frame to happen in the main thread
|
||
* in case the frontend is doing late-polling */
|
||
if (input_cb)
|
||
input_cb(0, 0, 0, 0);
|
||
#endif
|
||
|
||
for (int i = 0; i < port_max; ++i)
|
||
{
|
||
UpdateAccelerometer(i);
|
||
UpdateGyro(i);
|
||
}
|
||
|
||
auto& system = Core::System::GetInstance();
|
||
bool gcMicEnable = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf_gc::ENABLE_GAMECUBE_MIC);
|
||
|
||
if (!system.IsWii() && Libretro::Input::g_has_microphone_support && gcMicEnable)
|
||
{
|
||
std::string micHotkey = Libretro::Options::GetCached<std::string>(
|
||
Libretro::Options::sysconf_gc::HOTKEY_ACTIVATE_MICROPHONE);
|
||
int micButtonId = GetRetroButtonId(micHotkey);
|
||
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
g_gc_mic_button[i] = (micButtonId >= 0) ?
|
||
(input_cb(i, RETRO_DEVICE_JOYPAD, 0, micButtonId) != 0) : false;
|
||
}
|
||
}
|
||
|
||
bool dsu_enabled = Libretro::Options::GetCached<bool>(
|
||
Libretro::Options::wiimote_dsu::DSU_ENABLED, false);
|
||
|
||
if (dsu_enabled)
|
||
g_controller_interface.UpdateInput();
|
||
}
|
||
|
||
static std::string GetQualifiedNameSensor(unsigned port)
|
||
{
|
||
return ciface::Core::DeviceQualifier(
|
||
std::string(Libretro::Input::source),
|
||
static_cast<int>(port),
|
||
std::string("Sensor")
|
||
).ToString();
|
||
}
|
||
|
||
// can be called from retro_run, do not reset all settings because one thing changed
|
||
void UpdateWiimoteMappings(const WiimoteUpdateFlags& f, unsigned port, unsigned device)
|
||
{
|
||
// ResetControllers passes input_types[port] verbatim, dongle id and all.
|
||
device = wiimote_base_device(device);
|
||
|
||
if (!f.any() || device == RETRO_DEVICE_REAL_WIIMOTE || device == RETRO_DEVICE_WIIMOTE_CC ||
|
||
device == RETRO_DEVICE_WIIMOTE_CC_PRO)
|
||
return;
|
||
|
||
auto& system = Core::System::GetInstance();
|
||
bool altGCPorts = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII);
|
||
|
||
if (((!system.IsWii() || !altGCPorts) && port > 3) || port > 7)
|
||
return;
|
||
|
||
// modifier wrapper
|
||
auto wrap = [](const std::string& mod, const std::string& expr) {
|
||
if (mod == MODIFIER_NO_MODIFIER || mod.empty())
|
||
return expr; // no modifier - always active
|
||
return mod + " & " + expr; // modifier held - active
|
||
};
|
||
|
||
WiimoteEmu::Wiimote* wm = (WiimoteEmu::Wiimote*)Wiimote::GetConfig()->GetController(port);
|
||
|
||
// IR‑related updates
|
||
if (f.irModifier ||
|
||
f.irMode ||
|
||
f.irOffset ||
|
||
f.irYaw ||
|
||
f.irPitch ||
|
||
f.irDeadzone ||
|
||
f.swingModifier)
|
||
{
|
||
ControllerEmu::ControlGroup* wmIR = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Point);
|
||
const int irMode = Libretro::Options::GetCached<int>(Libretro::Options::wiimote::IR_MODE);
|
||
|
||
if (f.irOffset)
|
||
{
|
||
const int irCenter = Libretro::Options::GetCached<int>(Libretro::Options::wiimote::IR_OFFSET);
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmIR->numeric_settings[1].get())
|
||
->SetValue(irCenter); // IR Vertical Offset
|
||
}
|
||
|
||
if (f.irYaw)
|
||
{
|
||
const int irWidth = Libretro::Options::GetCached<int>(Libretro::Options::wiimote::IR_YAW);
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmIR->numeric_settings[2].get())
|
||
->SetValue(irWidth); // IR Total Yaw
|
||
}
|
||
|
||
if (f.irPitch)
|
||
{
|
||
const int irHeight = Libretro::Options::GetCached<int>(Libretro::Options::wiimote::IR_PITCH);
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmIR->numeric_settings[3].get())
|
||
->SetValue(irHeight); // IR Total Pitch
|
||
}
|
||
|
||
|
||
if (f.irMode || f.irModifier || f.swingModifier)
|
||
{
|
||
std::string devAnalog = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_ANALOG);
|
||
std::string devPointer = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_POINTER);
|
||
|
||
// In VR the right controller aims the cursor too, alongside the thumbstick or mouse.
|
||
const bool vr_aim = Libretro::Input::UsesVRMotion(port) && irMode != 0;
|
||
const std::string devSensor = GetQualifiedNameSensor(port);
|
||
auto aim = [&](const std::string& expr, const char* direction) {
|
||
return vr_aim ? "(" + expr + ") | `" + devSensor + ":" + direction + "`" : expr;
|
||
};
|
||
|
||
if (irMode == 0 || irMode == 1)
|
||
{
|
||
// Set right stick to control the IR
|
||
std::string irMod = Libretro::Options::GetCached<std::string>(Libretro::Options::wiimote::IR_MODIFIER);
|
||
wmIR->SetControlExpression(0, aim(wrap(irMod, "`" + devAnalog + ":Y1-`"), "PointUp")); // Up
|
||
wmIR->SetControlExpression(1, aim(wrap(irMod, "`" + devAnalog + ":Y1+`"), "PointDown")); // Down
|
||
wmIR->SetControlExpression(2, aim(wrap(irMod, "`" + devAnalog + ":X1-`"), "PointLeft")); // Left
|
||
wmIR->SetControlExpression(3, aim(wrap(irMod, "`" + devAnalog + ":X1+`"), "PointRight")); // Right
|
||
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmIR->numeric_settings[4].get())
|
||
->SetValue(irMode == 0); // Relative input
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmIR->numeric_settings[5].get())
|
||
->SetValue(!vr_aim); // Auto hide
|
||
|
||
// Swing‑related updates
|
||
ControllerEmu::ControlGroup* wmSwing = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Swing);
|
||
|
||
// modifier controls swing plus analog
|
||
std::string swingModifier = Libretro::Options::GetCached<std::string>(Libretro::Options::wiimote::SWING_MODIFIER);
|
||
|
||
if (swingModifier != MODIFIER_DISABLED_CONTROL)
|
||
{
|
||
// we don't want whatever the irMod is set to (e.g. L3) to interfere with swinging
|
||
if (swingModifier == MODIFIER_NO_MODIFIER && irMod != swingModifier)
|
||
swingModifier = "!" + irMod;
|
||
|
||
wmSwing->SetControlExpression(0, wrap(swingModifier, "`" + devAnalog + ":Y1-`")); // Up
|
||
wmSwing->SetControlExpression(1, wrap(swingModifier, "`" + devAnalog + ":Y1+`")); // Down
|
||
wmSwing->SetControlExpression(2, wrap(swingModifier, "`" + devAnalog + ":X1-`")); // Left
|
||
wmSwing->SetControlExpression(3, wrap(swingModifier, "`" + devAnalog + ":X1+`")); // Right
|
||
}
|
||
else
|
||
{
|
||
wmSwing->SetControlExpression(0, "");
|
||
wmSwing->SetControlExpression(1, "");
|
||
wmSwing->SetControlExpression(2, "");
|
||
wmSwing->SetControlExpression(3, "");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Mouse controls IR
|
||
wmIR->SetControlExpression(0, aim("`" + devPointer + ":Y0-`", "PointUp")); // Up
|
||
wmIR->SetControlExpression(1, aim("`" + devPointer + ":Y0+`", "PointDown")); // Down
|
||
wmIR->SetControlExpression(2, aim("`" + devPointer + ":X0-`", "PointLeft")); // Left
|
||
wmIR->SetControlExpression(3, aim("`" + devPointer + ":X0+`", "PointRight")); // Right
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmIR->numeric_settings[4].get())
|
||
->SetValue(false); // Relative input
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmIR->numeric_settings[5].get())
|
||
->SetValue(false); // Auto hide
|
||
}
|
||
|
||
if (f.irMode && device == RETRO_DEVICE_WIIMOTE_NC)
|
||
{
|
||
// mouse
|
||
if (irMode != 0 && irMode != 1)
|
||
{
|
||
ControllerEmu::ControlGroup* wmTilt = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Tilt);
|
||
wmTilt->SetControlExpression(0, "`" + devAnalog + ":Y1-`"); // Forward
|
||
wmTilt->SetControlExpression(1, "`" + devAnalog + ":Y1+`"); // Backward
|
||
wmTilt->SetControlExpression(2, "`" + devAnalog + ":X1-`"); // Left
|
||
wmTilt->SetControlExpression(3, "`" + devAnalog + ":X1+`"); // Right
|
||
}
|
||
}
|
||
}
|
||
|
||
if (f.irDeadzone)
|
||
{
|
||
const int irDeadzone = Libretro::Options::GetCached<int>(Libretro::Options::wiimote::IR_DEADZONE);
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmIR->numeric_settings[0].get())
|
||
->SetValue(irDeadzone); // IR DeadZone
|
||
}
|
||
}
|
||
|
||
// Raw IR: the frontend supplies the camera's view directly, bypassing the
|
||
// Point group and Total Yaw/Pitch. Objects arrive on pointer indices 0-3,
|
||
// X/Y over the camera's 0..1 field, PRESSED marking the object visible.
|
||
// Size is a constant; games only read it to reject noise.
|
||
if (f.irPassthrough)
|
||
{
|
||
auto* wmIRPass = static_cast<ControllerEmu::IRPassthrough*>(
|
||
wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IRPassthrough));
|
||
const bool passthrough =
|
||
Libretro::Options::GetCached<bool>(Libretro::Options::wiimote::IR_PASSTHROUGH);
|
||
|
||
if (wmIRPass)
|
||
{
|
||
const std::string devPointer =
|
||
Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_POINTER);
|
||
wmIRPass->enabled.SetValue(passthrough);
|
||
static const char* const kObj[] = { "0", "1", "2", "3" };
|
||
for (int i = 0; i < 4; ++i)
|
||
{
|
||
// Cleared when off; AreInputsBound() is half of what selects this path.
|
||
const std::string idx = kObj[i];
|
||
wmIRPass->SetControlExpression(i * 3 + 0,
|
||
passthrough ? "`" + devPointer + ":X" + idx + "+`" : "");
|
||
wmIRPass->SetControlExpression(i * 3 + 1,
|
||
passthrough ? "`" + devPointer + ":Y" + idx + "+`" : "");
|
||
wmIRPass->SetControlExpression(i * 3 + 2,
|
||
passthrough ? "`" + devPointer + ":Pressed" + idx + "` * 0.2" : "");
|
||
}
|
||
}
|
||
}
|
||
|
||
if (f.swingAngle)
|
||
{
|
||
ControllerEmu::ControlGroup* wmSwing = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Swing);
|
||
|
||
const int swingAngle = Libretro::Options::GetCached<int>(Libretro::Options::wiimote::SWING_ANGLE);
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmSwing->numeric_settings[0].get())
|
||
->SetValue(swingAngle); // Swing/Angle
|
||
}
|
||
|
||
ControllerEmu::ControlGroup* wmHotkeys = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Hotkeys);
|
||
|
||
// Sideways toggle
|
||
if (wmHotkeys && f.sideways)
|
||
{
|
||
std::string sidewaysToggle =
|
||
Libretro::Options::GetCached<std::string>(Libretro::Options::wiimote::HOTKEY_SIDEWAYS_TOGGLE);
|
||
|
||
wmHotkeys->SetControlExpression(0,
|
||
sidewaysToggle != MODIFIER_DISABLED_CONTROL ? sidewaysToggle : ""); // Sideways Toggle (L3 default)
|
||
}
|
||
|
||
// Upright toggle
|
||
if (wmHotkeys && f.upright)
|
||
{
|
||
std::string uprightToggle =
|
||
Libretro::Options::GetCached<std::string>(Libretro::Options::wiimote::HOTKEY_UPRIGHT_TOGGLE);
|
||
|
||
wmHotkeys->SetControlExpression(1,
|
||
uprightToggle != MODIFIER_DISABLED_CONTROL ? uprightToggle : ""); // Upright Toggle
|
||
}
|
||
#if 0
|
||
wmHotkeys->SetControlExpression(2, ""); // Sideways Hold
|
||
wmHotkeys->SetControlExpression(3, ""); // Upright Hold
|
||
#endif
|
||
|
||
// Rumble
|
||
if (f.rumble)
|
||
{
|
||
ControllerEmu::ControlGroup* wmRumble = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Rumble);
|
||
bool enableRumble = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ENABLE_RUMBLE);
|
||
if (enableRumble)
|
||
wmRumble->SetControlExpression(0, "Rumble");
|
||
}
|
||
|
||
if (f.any())
|
||
{
|
||
wm->UpdateReferences(g_controller_interface);
|
||
|
||
bool saveOrLoad = Libretro::Options::GetCached<bool>(Libretro::Options::retroarch_core::SAVE_LOAD_SETTINGS);
|
||
if (!saveOrLoad)
|
||
::Wiimote::GetConfig()->SaveConfig();
|
||
}
|
||
}
|
||
|
||
void UpdateGCMappings(const WiimoteUpdateFlags& f, unsigned port, unsigned device)
|
||
{
|
||
if (!f.any())
|
||
return;
|
||
|
||
auto& system = Core::System::GetInstance();
|
||
|
||
if (system.IsWii())
|
||
return;
|
||
|
||
if (f.gcMicBtn && Libretro::Input::g_has_microphone_support)
|
||
{
|
||
GCPad* gcPad = (GCPad*)Pad::GetConfig()->GetController(port > 3 ? port - 4 : port);
|
||
ControllerEmu::ControlGroup* gcMic = gcPad->GetGroup(PadGroup::Mic);
|
||
std::string gcMicButton = Libretro::Options::GetCached<std::string>
|
||
(Libretro::Options::sysconf_gc::HOTKEY_ACTIVATE_MICROPHONE);
|
||
|
||
if (!gcMicButton.empty())
|
||
gcMic->SetControlExpression(0, gcMicButton);
|
||
}
|
||
}
|
||
|
||
} // namespace Input
|
||
} // namespace Libretro
|
||
|
||
void retro_set_input_poll(retro_input_poll_t cb)
|
||
{
|
||
Libretro::Input::poll_cb = cb;
|
||
}
|
||
|
||
void retro_set_input_state(retro_input_state_t cb)
|
||
{
|
||
Libretro::Input::input_cb = cb;
|
||
}
|
||
|
||
void retro_set_controller_port_device(unsigned port, unsigned device)
|
||
{
|
||
auto& system = Core::System::GetInstance();
|
||
bool altGCPorts = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII);
|
||
|
||
if (((!system.IsWii() || !altGCPorts) && port > 3) || port > 7)
|
||
return;
|
||
|
||
Libretro::Input::input_types[port] = device;
|
||
auto& si = Core::System::GetInstance().GetSerialInterface();
|
||
|
||
if (device == RETRO_DEVICE_NONE)
|
||
{
|
||
if (system.IsWii() && port < 4)
|
||
{
|
||
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::None);
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::None);
|
||
}
|
||
|
||
if (!system.IsWii() || !altGCPorts)
|
||
{
|
||
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(port), SerialInterface::SIDEVICE_NONE);
|
||
si.ChangeDevice(Config::Get(Config::GetInfoForSIDevice(port)), port);
|
||
}
|
||
else if (port > 3)
|
||
{
|
||
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(port - 4), SerialInterface::SIDEVICE_NONE);
|
||
si.ChangeDevice(Config::Get(Config::GetInfoForSIDevice(port - 4)), port - 4);
|
||
}
|
||
}
|
||
else if (!system.IsWii() || device == RETRO_DEVICE_GC_ON_WII || port > 3)
|
||
{
|
||
retro_set_controller_port_device_gc(port, device);
|
||
}
|
||
else if (!Config::Get(Config::MAIN_BLUETOOTH_PASSTHROUGH_ENABLED))
|
||
{
|
||
retro_set_controller_port_device_wii(port, device);
|
||
}
|
||
}
|
||
|
||
void UpdateInputDescriptors()
|
||
{
|
||
auto& system = Core::System::GetInstance();
|
||
bool altGCPorts = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII);
|
||
|
||
std::vector<retro_input_descriptor> all_descs;
|
||
|
||
int port_max = (system.IsWii() && altGCPorts) ? 8 : 4;
|
||
|
||
for (int i = 0; i < port_max; i++)
|
||
{
|
||
retro_input_descriptor* desc;
|
||
|
||
// The dongle adds no buttons, so a MotionPlus id wants its twin's descriptors.
|
||
switch (wiimote_base_device(Libretro::Input::input_types[i]))
|
||
{
|
||
case RETRO_DEVICE_WIIMOTE_SW:
|
||
desc = Libretro::Input::descWiimoteSideways;
|
||
break;
|
||
|
||
case RETRO_DEVICE_WIIMOTE_NC:
|
||
desc = Libretro::Input::descWiimoteNunchuk;
|
||
break;
|
||
|
||
case RETRO_DEVICE_WIIMOTE_CC:
|
||
desc = Libretro::Input::descWiimoteCC;
|
||
break;
|
||
|
||
case RETRO_DEVICE_WIIMOTE_CC_PRO:
|
||
desc = Libretro::Input::descWiimoteCCPro;
|
||
break;
|
||
|
||
case RETRO_DEVICE_REAL_WIIMOTE:
|
||
case RETRO_DEVICE_NONE:
|
||
continue;
|
||
|
||
case RETRO_DEVICE_GC_ON_WII:
|
||
desc = Libretro::Input::descGC;
|
||
break;
|
||
|
||
default:
|
||
if (!system.IsWii() || i > 3)
|
||
{
|
||
desc = Libretro::Input::descGC;
|
||
}
|
||
else
|
||
{
|
||
desc = Libretro::Input::descWiimote;
|
||
}
|
||
break;
|
||
}
|
||
|
||
for (int j = 0; desc[j].description != NULL; j++)
|
||
{
|
||
retro_input_descriptor new_desc = desc[j];
|
||
new_desc.port = i;
|
||
all_descs.push_back(new_desc);
|
||
}
|
||
}
|
||
|
||
all_descs.push_back({0});
|
||
|
||
if(!Libretro::environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, &all_descs[0]))
|
||
{
|
||
WARN_LOG_FMT(COMMON, "RetroArch does not support RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS.");
|
||
}
|
||
}
|
||
|
||
void refresh_all_wiimote_flags(unsigned port, unsigned device)
|
||
{
|
||
WiimoteUpdateFlags f;
|
||
f.sideways = true;
|
||
f.upright = true;
|
||
f.irModifier = true;
|
||
f.swingModifier = true;
|
||
f.irMode = true;
|
||
f.irOffset = true;
|
||
f.irYaw = true;
|
||
f.irPitch = true;
|
||
f.irDeadzone = true;
|
||
f.swingAngle = true;
|
||
f.rumble = true;
|
||
Libretro::Input::UpdateWiimoteMappings(f, port, device);
|
||
}
|
||
|
||
// Mirror InputConfig::LoadConfig() for a single port.
|
||
// 1) game-specific input profile (game ini [Controls] WiimoteProfile{n}),
|
||
// 2) WiimoteNew.ini [Wiimote{n}] section,
|
||
// Returns the configured Wiimote pointer if a saved config was found and loaded,
|
||
// nullptr if the caller should apply hard-coded defaults instead.
|
||
// SetDefaultDevice is always called before UpdateReferences so profiles without
|
||
// a Device= line still bind to the correct libretro joypad.
|
||
static WiimoteEmu::Wiimote* load_saved_controller_config(unsigned port, unsigned device)
|
||
{
|
||
bool saveOrLoad = Libretro::Options::GetCached<bool>(Libretro::Options::retroarch_core::SAVE_LOAD_SETTINGS);
|
||
if (!saveOrLoad)
|
||
return nullptr;
|
||
|
||
WiimoteEmu::Wiimote* wm =
|
||
(WiimoteEmu::Wiimote*)Wiimote::GetConfig()->GetController(port);
|
||
|
||
// Rebuild devJoypad here so SetDefaultDevice is always called inside this
|
||
// function, before UpdateReferences, regardless of which load path fires.
|
||
const std::string devJoypad = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_JOYPAD);
|
||
|
||
const std::string profile_directory = ::Wiimote::GetConfig()->GetUserProfileDirectoryPath();
|
||
const std::string profile_key =
|
||
fmt::format("{}Profile{}", ::Wiimote::GetConfig()->GetProfileKey(), port + 1);
|
||
|
||
// Step 1: game ini [Controls] WiimoteProfile{n} -> Profiles/Wiimote/<name>.ini [Profile]
|
||
// LoadGameIni() already resolves the priority chain: S.ini, SOE.ini, SOUE01.ini, SOUE01r{n}.ini
|
||
Common::IniFile game_ini = SConfig::GetInstance().LoadGameIni();
|
||
const auto* control_section = game_ini.GetOrCreateSection("Controls");
|
||
std::string profile_setting;
|
||
if (control_section->Get(profile_key, &profile_setting))
|
||
{
|
||
const auto profiles = InputProfile::GetProfilesFromSetting(profile_setting, profile_directory);
|
||
if (!profiles.empty())
|
||
{
|
||
Common::IniFile profile_ini;
|
||
if (profile_ini.Load(profiles[0]))
|
||
{
|
||
Common::IniFile::Section* profile_sec = profile_ini.GetOrCreateSection("Profile");
|
||
wm->LoadConfig(profile_sec);
|
||
wm->SetDefaultDevice(devJoypad);
|
||
wm->UpdateReferences(g_controller_interface);
|
||
refresh_all_wiimote_flags(port, device);
|
||
::Wiimote::GetConfig()->SaveConfig();
|
||
return wm; // Per-game profile loaded
|
||
}
|
||
}
|
||
}
|
||
|
||
// Step 2: WiimoteNew.ini [Wiimote{n}] - GetSection not GetOrCreateSection so a
|
||
// missing section doesn't silently bypass the hard-coded defaults in the caller.
|
||
const std::string wiimote_ini_path =
|
||
File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini";
|
||
Common::IniFile wiimote_new_ini;
|
||
if (wiimote_new_ini.Load(wiimote_ini_path))
|
||
{
|
||
Common::IniFile::Section* wm_sec = wiimote_new_ini.GetSection(wm->GetName());
|
||
if (wm_sec)
|
||
{
|
||
wm->LoadConfig(wm_sec);
|
||
wm->SetDefaultDevice(devJoypad);
|
||
wm->UpdateReferences(g_controller_interface);
|
||
refresh_all_wiimote_flags(port, device);
|
||
::Wiimote::GetConfig()->SaveConfig();
|
||
return wm; // WiimoteNew.ini loaded
|
||
}
|
||
}
|
||
|
||
return nullptr; // nothing found, applies hard-coded defaults
|
||
}
|
||
|
||
// returns retropad_expr on its own, with additional mouse bindings
|
||
static std::string bindMouse(const std::string& retropad_expr, const std::string& mouse_target)
|
||
{
|
||
static const bool enable_default_mouse_bindings =
|
||
Libretro::Options::GetCached<bool>(Libretro::Options::retroarch_core::ENABLE_DEFAULT_MOUSE_BINDINGS, /*def=*/true);
|
||
|
||
if (!enable_default_mouse_bindings)
|
||
return retropad_expr;
|
||
|
||
return retropad_expr + " | `" + mouse_target + "`";
|
||
}
|
||
|
||
void retro_set_controller_port_device_gc(unsigned port, unsigned device)
|
||
{
|
||
std::string devJoypad = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_JOYPAD);
|
||
std::string devAnalog = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_ANALOG);
|
||
std::string devMouse = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_MOUSE);
|
||
std::string devPointer = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_POINTER);
|
||
#if 0
|
||
std::string devKeyboard = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_KEYBOARD);
|
||
std::string devLightgun = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_LIGHTGUN);
|
||
#endif
|
||
auto& si = Core::System::GetInstance().GetSerialInterface();
|
||
|
||
if (device == RETRO_DEVICE_GC_ON_WII) // Disconnect Wii device if we're using GC controller as device type to avoid conflict
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::None);
|
||
|
||
Core::System& system = Core::System::GetInstance();
|
||
|
||
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(port > 3 ? port - 4 : port),
|
||
system.IsTriforce() ? SerialInterface::SIDEVICE_AM_BASEBOARD : SerialInterface::SIDEVICE_GC_CONTROLLER);
|
||
si.ChangeDevice(Config::Get(Config::GetInfoForSIDevice(port > 3 ? port - 4 : port)), port > 3 ? port - 4 : port);
|
||
|
||
GCPad* gcPad = (GCPad*)Pad::GetConfig()->GetController(port > 3 ? port - 4 : port);
|
||
// load an empty inifile section, clears everything
|
||
Common::IniFile::Section sec;
|
||
gcPad->LoadConfig(&sec);
|
||
gcPad->SetDefaultDevice(devJoypad);
|
||
|
||
ControllerEmu::ControlGroup* gcButtons = gcPad->GetGroup(PadGroup::Buttons);
|
||
ControllerEmu::ControlGroup* gcMainStick = gcPad->GetGroup(PadGroup::MainStick);
|
||
ControllerEmu::ControlGroup* gcCStick = gcPad->GetGroup(PadGroup::CStick);
|
||
ControllerEmu::ControlGroup* gcDPad = gcPad->GetGroup(PadGroup::DPad);
|
||
ControllerEmu::ControlGroup* gcTriggers = gcPad->GetGroup(PadGroup::Triggers);
|
||
ControllerEmu::ControlGroup* gcRumble = gcPad->GetGroup(PadGroup::Rumble);
|
||
ControllerEmu::ControlGroup* gcOptions = gcPad->GetGroup(PadGroup::Options);
|
||
ControllerEmu::ControlGroup* gcTriforce = gcPad->GetGroup(PadGroup::Triforce);
|
||
|
||
if (Libretro::Input::g_has_microphone_support)
|
||
{
|
||
WiimoteUpdateFlags f;
|
||
f.gcMicBtn = true;
|
||
Libretro::Input::UpdateGCMappings(f, port, device);
|
||
}
|
||
|
||
gcButtons->SetControlExpression(0, "A"); // A
|
||
gcButtons->SetControlExpression(1, "B"); // B
|
||
gcButtons->SetControlExpression(2, "X"); // X
|
||
gcButtons->SetControlExpression(3, "Y"); // Y
|
||
gcButtons->SetControlExpression(4, "R"); // Z
|
||
gcButtons->SetControlExpression(5, "Start"); // Start
|
||
gcMainStick->SetControlExpression(0, "`" + devAnalog + ":Y0-`"); // Up
|
||
gcMainStick->SetControlExpression(1, "`" + devAnalog + ":Y0+`"); // Down
|
||
gcMainStick->SetControlExpression(2, "`" + devAnalog + ":X0-`"); // Left
|
||
gcMainStick->SetControlExpression(3, "`" + devAnalog + ":X0+`"); // Right
|
||
gcCStick->SetControlExpression(0, "`" + devAnalog + ":Y1-`"); // Up
|
||
gcCStick->SetControlExpression(1, "`" + devAnalog + ":Y1+`"); // Down
|
||
gcCStick->SetControlExpression(2, "`" + devAnalog + ":X1-`"); // Left
|
||
gcCStick->SetControlExpression(3, "`" + devAnalog + ":X1+`"); // Right
|
||
gcDPad->SetControlExpression(0, "Up"); // Up
|
||
gcDPad->SetControlExpression(1, "Down"); // Down
|
||
gcDPad->SetControlExpression(2, "Left"); // Left
|
||
gcDPad->SetControlExpression(3, "Right"); // Right
|
||
gcTriggers->SetControlExpression(0, "`" + devAnalog + ":Trigger0+`|(L2&!`" + devAnalog +
|
||
":Trigger0+`)"); // L-trigger Full Press
|
||
gcTriggers->SetControlExpression(1, "`" + devAnalog + ":Trigger1+`|(R2&!`" + devAnalog +
|
||
":Trigger1+`)"); // R-trigger Full Press
|
||
gcTriggers->SetControlExpression(2,
|
||
"`" + devAnalog + ":Trigger0+`|L3"); // L-trigger Soft Press
|
||
gcTriggers->SetControlExpression(3,
|
||
"`" + devAnalog + ":Trigger1+`|R3"); // R-trigger Soft Press
|
||
gcTriforce->SetControlExpression(0, "L"); // Test
|
||
gcTriforce->SetControlExpression(1, "L3&R3"); // Service
|
||
gcTriforce->SetControlExpression(2, "Select"); // Coin
|
||
|
||
bool enableRumble = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ENABLE_RUMBLE);
|
||
if (enableRumble)
|
||
gcRumble->SetControlExpression(0, "Rumble");
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(gcOptions->numeric_settings[0].get())
|
||
->SetValue(true); // Always Connected
|
||
|
||
gcPad->UpdateReferences(g_controller_interface);
|
||
|
||
bool saveOrLoad = Libretro::Options::GetCached<bool>(Libretro::Options::retroarch_core::SAVE_LOAD_SETTINGS);
|
||
if (!saveOrLoad)
|
||
return Pad::GetConfig()->SaveConfig();
|
||
}
|
||
|
||
void retro_set_controller_port_device_wii(unsigned port, unsigned device)
|
||
{
|
||
std::string devJoypad = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_JOYPAD);
|
||
std::string devAnalog = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_ANALOG);
|
||
std::string devMouse = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_MOUSE);
|
||
std::string devPointer = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_POINTER);
|
||
#if 0
|
||
std::string devKeyboard = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_KEYBOARD);
|
||
std::string devLightgun = Libretro::Input::GetQualifiedName(port, RETRO_DEVICE_LIGHTGUN);
|
||
#endif
|
||
auto& si = Core::System::GetInstance().GetSerialInterface();
|
||
|
||
// Take the dongle off the id and remember it, so the branches below only see
|
||
// the remotes they were written for.
|
||
const bool wantMotionPlus = wiimote_has_motion_plus(device);
|
||
device = wiimote_base_device(device);
|
||
|
||
if (Wiimote::GetConfig()->ControllersNeedToBeCreated())
|
||
{
|
||
WARN_LOG_FMT(COMMON, "No controllers have been created yet");
|
||
return;
|
||
}
|
||
|
||
bool altGCPorts = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ALT_GC_PORTS_ON_WII);
|
||
if (!altGCPorts) // Disconnect GC controller to avoid conflict with Wii device
|
||
{
|
||
Config::SetBaseOrCurrent(Config::GetInfoForSIDevice(port), SerialInterface::SIDEVICE_NONE);
|
||
si.ChangeDevice(Config::Get(Config::GetInfoForSIDevice(port)), port);
|
||
}
|
||
|
||
WiimoteEmu::Wiimote* wm = load_saved_controller_config(port, device);
|
||
|
||
// defaults already found, so don't overwrite
|
||
if (wm)
|
||
return;
|
||
|
||
// nothing found — start fresh and apply hard-coded defaults
|
||
wm = (WiimoteEmu::Wiimote*)Wiimote::GetConfig()->GetController(port);
|
||
|
||
// load an empty inifile section, clears everything
|
||
Common::IniFile::Section sec;
|
||
wm->LoadConfig(&sec);
|
||
|
||
bool dsu_enabled = Libretro::Options::GetCached<bool>(
|
||
Libretro::Options::wiimote_dsu::DSU_ENABLED, false);
|
||
|
||
std::string devDSU;
|
||
if (dsu_enabled)
|
||
{
|
||
devDSU = ciface::Core::DeviceQualifier(
|
||
std::string("DSUClient"),
|
||
static_cast<int>(port),
|
||
std::string("DS4")).ToString();
|
||
//devDSU = "DSUClient/DS4/" + std::to_string(port);
|
||
|
||
wm->SetDefaultDevice(devDSU);
|
||
}
|
||
else
|
||
{
|
||
wm->SetDefaultDevice(devJoypad);
|
||
}
|
||
|
||
WiimoteUpdateFlags f;
|
||
|
||
using namespace WiimoteEmu;
|
||
if (device == RETRO_DEVICE_WIIMOTE_CC || device == RETRO_DEVICE_WIIMOTE_CC_PRO)
|
||
{
|
||
ControllerEmu::ControlGroup* ccButtons = wm->GetClassicGroup(ClassicGroup::Buttons);
|
||
ControllerEmu::ControlGroup* ccTriggers = wm->GetClassicGroup(ClassicGroup::Triggers);
|
||
ControllerEmu::ControlGroup* ccDpad = wm->GetClassicGroup(ClassicGroup::DPad);
|
||
ControllerEmu::ControlGroup* ccLeftStick = wm->GetClassicGroup(ClassicGroup::LeftStick);
|
||
ControllerEmu::ControlGroup* ccRightStick = wm->GetClassicGroup(ClassicGroup::RightStick);
|
||
|
||
if (dsu_enabled)
|
||
{
|
||
ccButtons->SetControlExpression(0, "`" + devDSU + ":Cross`"); // A
|
||
ccButtons->SetControlExpression(1, "`" + devDSU + ":Circle`"); // B
|
||
ccButtons->SetControlExpression(2, "`" + devDSU + ":Square`"); // X
|
||
ccButtons->SetControlExpression(3, "`" + devDSU + ":Triangle`"); // Y
|
||
ccButtons->SetControlExpression(6, "`" + devDSU + ":Share`"); // -
|
||
ccButtons->SetControlExpression(7, "`" + devDSU + ":Options`"); // +
|
||
ccButtons->SetControlExpression(8, "`" + devDSU + ":PS`"); // Home
|
||
}
|
||
else
|
||
{
|
||
ccButtons->SetControlExpression(0, "A"); // A
|
||
ccButtons->SetControlExpression(1, "B"); // B
|
||
ccButtons->SetControlExpression(2, "X"); // X
|
||
ccButtons->SetControlExpression(3, "Y"); // Y
|
||
ccButtons->SetControlExpression(6, "Select"); // -
|
||
ccButtons->SetControlExpression(7, "Start"); // +
|
||
ccButtons->SetControlExpression(8, "R3"); // Home
|
||
}
|
||
if (device == RETRO_DEVICE_WIIMOTE_CC)
|
||
{
|
||
if (dsu_enabled)
|
||
{
|
||
ccButtons->SetControlExpression(4, "`" + devDSU + ":L1`"); // ZL
|
||
ccButtons->SetControlExpression(5, "`" + devDSU + ":R1`"); // ZR
|
||
ccTriggers->SetControlExpression(0, "`" + devDSU + ":L2`"); // L-trigger
|
||
ccTriggers->SetControlExpression(1, "`" + devDSU + ":R2`"); // R-trigger
|
||
ccTriggers->SetControlExpression(2, "`" + devDSU + ":L2`"); // L-trigger Analog
|
||
ccTriggers->SetControlExpression(3, "`" + devDSU + ":R2`"); // R-trigger Analog
|
||
}
|
||
else
|
||
{
|
||
ccButtons->SetControlExpression(4, "L"); // ZL
|
||
ccButtons->SetControlExpression(5, "R"); // ZR
|
||
ccTriggers->SetControlExpression(0, "`" + devAnalog + ":Trigger0+`"); // L-trigger
|
||
ccTriggers->SetControlExpression(1, "`" + devAnalog + ":Trigger1+`"); // R-trigger
|
||
ccTriggers->SetControlExpression(2, "`" + devAnalog + ":Trigger0+`"); // L-trigger Analog
|
||
ccTriggers->SetControlExpression(3, "`" + devAnalog + ":Trigger1+`"); // R-trigger Analog
|
||
}
|
||
}
|
||
else // Classic Controller Pro doesn't have analog triggers and L/R should be swapped with ZL/ZR
|
||
{
|
||
ccButtons->SetControlExpression(4, dsu_enabled ? "`" + devDSU + ":L2`" : "L2"); // ZL
|
||
ccButtons->SetControlExpression(5, dsu_enabled ? "`" + devDSU + ":R2`" : "R2"); // ZR
|
||
ccTriggers->SetControlExpression(0, dsu_enabled ? "`" + devDSU + ":L1`" : "L"); // L
|
||
ccTriggers->SetControlExpression(1, dsu_enabled ? "`" + devDSU + ":R1`" : "R"); // R
|
||
}
|
||
|
||
ccDpad->SetControlExpression(0, dsu_enabled ? "`" + devDSU + ":Pad N`" : "Up"); // Up
|
||
ccDpad->SetControlExpression(1, dsu_enabled ? "`" + devDSU + ":Pad S`" : "Down"); // Down
|
||
ccDpad->SetControlExpression(2, dsu_enabled ? "`" + devDSU + ":Pad W`" : "Left"); // Left
|
||
ccDpad->SetControlExpression(3, dsu_enabled ? "`" + devDSU + ":Pad E`" : "Right"); // Right
|
||
|
||
if (dsu_enabled)
|
||
{
|
||
ccLeftStick->SetControlExpression(0, "`" + devDSU + ":Left Y-`"); // Up
|
||
ccLeftStick->SetControlExpression(1, "`" + devDSU + ":Left Y+`"); // Down
|
||
ccLeftStick->SetControlExpression(2, "`" + devDSU + ":Left X-`"); // Left
|
||
ccLeftStick->SetControlExpression(3, "`" + devDSU + ":Left X+`"); // Right
|
||
|
||
ccRightStick->SetControlExpression(0, "`" + devDSU + ":Right Y-`"); // Up
|
||
ccRightStick->SetControlExpression(1, "`" + devDSU + ":Right Y+`"); // Down
|
||
ccRightStick->SetControlExpression(2, "`" + devDSU + ":Right X-`"); // Left
|
||
ccRightStick->SetControlExpression(3, "`" + devDSU + ":Right X+`"); // Right
|
||
}
|
||
else
|
||
{
|
||
ccLeftStick->SetControlExpression(0, "`" + devAnalog + ":Y0-`"); // Up
|
||
ccLeftStick->SetControlExpression(1, "`" + devAnalog + ":Y0+`"); // Down
|
||
ccLeftStick->SetControlExpression(2, "`" + devAnalog + ":X0-`"); // Left
|
||
ccLeftStick->SetControlExpression(3, "`" + devAnalog + ":X0+`"); // Right
|
||
ccRightStick->SetControlExpression(0, "`" + devAnalog + ":Y1-`"); // Up
|
||
ccRightStick->SetControlExpression(1, "`" + devAnalog + ":Y1+`"); // Down
|
||
ccRightStick->SetControlExpression(2, "`" + devAnalog + ":X1-`"); // Left
|
||
ccRightStick->SetControlExpression(3, "`" + devAnalog + ":X1+`"); // Right
|
||
}
|
||
}
|
||
else if (device != RETRO_DEVICE_REAL_WIIMOTE)
|
||
{
|
||
ControllerEmu::ControlGroup* wmButtons = wm->GetWiimoteGroup(WiimoteGroup::Buttons);
|
||
ControllerEmu::ControlGroup* wmDPad = wm->GetWiimoteGroup(WiimoteGroup::DPad);
|
||
ControllerEmu::ControlGroup* wmShake = wm->GetWiimoteGroup(WiimoteGroup::Shake);
|
||
ControllerEmu::ControlGroup* wmTilt = wm->GetWiimoteGroup(WiimoteGroup::Tilt);
|
||
|
||
f.irOffset = true;
|
||
f.irYaw = true;
|
||
f.irPitch = true;
|
||
f.irDeadzone = true;
|
||
f.swingAngle = true;
|
||
|
||
if (device == RETRO_DEVICE_WIIMOTE_NC)
|
||
{
|
||
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
|
||
ncButtons->SetControlExpression(0, "X"); // C
|
||
ncButtons->SetControlExpression(1, "Y"); // Z
|
||
ncStick->SetControlExpression(0, "`" + devAnalog + ":Y0-`"); // Up
|
||
ncStick->SetControlExpression(1, "`" + devAnalog + ":Y0+`"); // Down
|
||
ncStick->SetControlExpression(2, "`" + devAnalog + ":X0-`"); // Left
|
||
ncStick->SetControlExpression(3, "`" + devAnalog + ":X0+`"); // Right
|
||
ncShake->SetControlExpression(0, bindMouse("L2", devMouse + ":Middle")); // Nunchuk shake X
|
||
ncShake->SetControlExpression(1, bindMouse("L2", devMouse + ":Middle")); // Nunchuk shake Y
|
||
ncShake->SetControlExpression(2, bindMouse("L2", devMouse + ":Middle")); // Nunchuk shake Z
|
||
|
||
wmButtons->SetControlExpression(0, bindMouse("A", devMouse + ":Left")); // A
|
||
wmButtons->SetControlExpression(1, bindMouse("B", devMouse + ":Right")); // B
|
||
wmButtons->SetControlExpression(2, "Start"); // 1
|
||
wmButtons->SetControlExpression(3, "Select"); // 2
|
||
wmButtons->SetControlExpression(4, "L"); // -
|
||
wmButtons->SetControlExpression(5, "R"); // +
|
||
|
||
f.irMode = true;
|
||
}
|
||
else
|
||
{
|
||
if (device == RETRO_DEVICE_WIIMOTE)
|
||
{
|
||
wmButtons->SetControlExpression(0, bindMouse("A", devMouse + ":Left")); // A
|
||
wmButtons->SetControlExpression(1, bindMouse("B", devMouse + ":Right")); // B
|
||
wmButtons->SetControlExpression(2, "X"); // 1
|
||
wmButtons->SetControlExpression(3, "Y"); // 2
|
||
}
|
||
else
|
||
{
|
||
wmButtons->SetControlExpression(0, "X"); // A
|
||
wmButtons->SetControlExpression(1, "Y"); // B
|
||
wmButtons->SetControlExpression(2, "B"); // 1
|
||
wmButtons->SetControlExpression(3, "A"); // 2
|
||
}
|
||
|
||
if (dsu_enabled)
|
||
{
|
||
auto* wmAccel = static_cast<ControllerEmu::IMUAccelerometer*>(
|
||
wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IMUAccelerometer));
|
||
if (wmAccel)
|
||
{
|
||
// Input names are from DualShockUDPClient.cpp Device constructor.
|
||
// The DSU device already converts to m/s² via accel_scale so units match.
|
||
wmAccel->SetControlExpression(0, "`" + devDSU + ":Accel Up`"); // Up
|
||
wmAccel->SetControlExpression(1, "`" + devDSU + ":Accel Down`"); // Down
|
||
wmAccel->SetControlExpression(2, "`" + devDSU + ":Accel Left`"); // Left
|
||
wmAccel->SetControlExpression(3, "`" + devDSU + ":Accel Right`"); // Right
|
||
wmAccel->SetControlExpression(4, "`" + devDSU + ":Accel Forward`"); // Forward
|
||
wmAccel->SetControlExpression(5, "`" + devDSU + ":Accel Backward`"); // Backward
|
||
}
|
||
|
||
auto* wmGyro = static_cast<ControllerEmu::IMUGyroscope*>(
|
||
wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::IMUGyroscope));
|
||
if (wmGyro)
|
||
{
|
||
wmGyro->SetControlExpression(0, "`" + devDSU + ":Gyro Pitch Up`"); // Pitch Up
|
||
wmGyro->SetControlExpression(1, "`" + devDSU + ":Gyro Pitch Down`"); // Pitch Down
|
||
wmGyro->SetControlExpression(2, "`" + devDSU + ":Gyro Roll Left`"); // Roll Left
|
||
wmGyro->SetControlExpression(3, "`" + devDSU + ":Gyro Roll Right`"); // Roll Right
|
||
wmGyro->SetControlExpression(4, "`" + devDSU + ":Gyro Yaw Left`"); // Yaw Left
|
||
wmGyro->SetControlExpression(5, "`" + devDSU + ":Gyro Yaw Right`"); // Yaw Right
|
||
}
|
||
}
|
||
else if (Libretro::Input::sensor_enabled[port][SENSOR_ACCELEROMETER] ||
|
||
Libretro::Input::sensor_enabled[port][SENSOR_GYRO])
|
||
{
|
||
std::string devSensor = Libretro::Input::GetQualifiedNameSensor(port);
|
||
|
||
if (Libretro::Input::sensor_enabled[port][SENSOR_ACCELEROMETER])
|
||
{
|
||
// Accelerometer (6 inputs: Up, Down, Left, Right, Forward, Backward)
|
||
// Indices must match WiimoteEmu::LoadDefaults ordering (0..5)
|
||
auto* wmAccel = static_cast<ControllerEmu::IMUAccelerometer*>(
|
||
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
|
||
}
|
||
}
|
||
|
||
// A sibling, not a child: nested, gyro-without-accelerometer bound neither.
|
||
if (Libretro::Input::sensor_enabled[port][SENSOR_GYRO])
|
||
{
|
||
// Gyroscope (6 inputs: PitchUp/Down, RollLeft/Right, YawLeft/Right)
|
||
auto* wmGyro = static_cast<ControllerEmu::IMUGyroscope*>(
|
||
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
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
wmTilt->SetControlExpression(0, "`" + devAnalog + ":Y0-`"); // Forward
|
||
wmTilt->SetControlExpression(1, "`" + devAnalog + ":Y0+`"); // Backward
|
||
wmTilt->SetControlExpression(2, "`" + devAnalog + ":X0-`"); // Left
|
||
wmTilt->SetControlExpression(3, "`" + devAnalog + ":X0+`"); // Right
|
||
}
|
||
wmButtons->SetControlExpression(4, "Select"); // -
|
||
wmButtons->SetControlExpression(5, "Start"); // +
|
||
}
|
||
|
||
wmButtons->SetControlExpression(6, "R3"); // Home
|
||
wmDPad->SetControlExpression(0, "Up"); // Up
|
||
wmDPad->SetControlExpression(1, "Down"); // Down
|
||
wmDPad->SetControlExpression(2, "Left"); // Left
|
||
wmDPad->SetControlExpression(3, "Right"); // Right
|
||
|
||
f.irModifier = true;
|
||
f.swingModifier = true;
|
||
f.sideways = true;
|
||
f.upright = true;
|
||
// Raised at setup so the option applies on a cold boot.
|
||
f.irPassthrough = true;
|
||
Libretro::Input::UpdateWiimoteMappings(f, port, device);
|
||
|
||
wmShake->SetControlExpression(0, bindMouse("R2", devMouse + ":Middle")); // Wiimote shake X
|
||
wmShake->SetControlExpression(1, bindMouse("R2", devMouse + ":Middle")); // Wiimote shake Y
|
||
wmShake->SetControlExpression(2, bindMouse("R2", devMouse + ":Middle")); // Wiimote shake Z
|
||
}
|
||
|
||
ControllerEmu::ControlGroup* wmOptions = wm->GetWiimoteGroup(WiimoteGroup::Options);
|
||
ControllerEmu::Attachments* wmExtension =
|
||
(ControllerEmu::Attachments*)wm->GetWiimoteGroup(WiimoteGroup::Attachments);
|
||
|
||
// Index 0 is "Attach MotionPlus", the only numeric setting here (the
|
||
// attachment selector is kept out of that list). Written on both paths since
|
||
// Dolphin defaults it to true.
|
||
if (!wmExtension->numeric_settings.empty())
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmExtension->numeric_settings[0].get())
|
||
->SetValue(wantMotionPlus);
|
||
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmOptions->numeric_settings[0].get())
|
||
->SetValue(0); // Speaker Pan [-100, 100]
|
||
static_cast<ControllerEmu::NumericSetting<double>*>(wmOptions->numeric_settings[1].get())
|
||
->SetValue(95); // Battery [0, 100]
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmOptions->numeric_settings[2].get())
|
||
->SetValue(false); // Upright Wiimote
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmOptions->numeric_settings[3].get())
|
||
->SetValue(false); // Sideways Wiimote
|
||
|
||
ControllerEmu::ControlGroup* wmRumble = wm->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Rumble);
|
||
bool enableRumble = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::ENABLE_RUMBLE);
|
||
if (enableRumble)
|
||
wmRumble->SetControlExpression(0, "Rumble");
|
||
|
||
switch (device)
|
||
{
|
||
case RETRO_DEVICE_WIIMOTE:
|
||
wmExtension->SetSelectedAttachment(ExtensionNumber::NONE);
|
||
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::Emulated);
|
||
break;
|
||
|
||
case RETRO_DEVICE_WIIMOTE_SW:
|
||
wmExtension->SetSelectedAttachment(ExtensionNumber::NONE);
|
||
static_cast<ControllerEmu::NumericSetting<bool>*>(wmOptions->numeric_settings[3].get())
|
||
->SetValue(true); // Sideways Wiimote
|
||
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::Emulated);
|
||
break;
|
||
|
||
case RETRO_DEVICE_WIIMOTE_NC:
|
||
wmExtension->SetSelectedAttachment(ExtensionNumber::NUNCHUK);
|
||
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::Emulated);
|
||
break;
|
||
|
||
case RETRO_DEVICE_WIIMOTE_CC:
|
||
case RETRO_DEVICE_WIIMOTE_CC_PRO:
|
||
wmExtension->SetSelectedAttachment(ExtensionNumber::CLASSIC);
|
||
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Emulated);
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::Emulated);
|
||
break;
|
||
|
||
case RETRO_DEVICE_REAL_WIIMOTE:
|
||
Config::SetBaseOrCurrent(Config::GetInfoForWiimoteSource(port), WiimoteSource::Real);
|
||
WiimoteCommon::OnSourceChanged(port, WiimoteSource::Real);
|
||
break;
|
||
}
|
||
|
||
wm->UpdateReferences(g_controller_interface);
|
||
bool saveOrLoad = Libretro::Options::GetCached<bool>(Libretro::Options::retroarch_core::SAVE_LOAD_SETTINGS);
|
||
if (!saveOrLoad)
|
||
::Wiimote::GetConfig()->SaveConfig();
|
||
}
|
||
|
||
void poll_microphone()
|
||
{
|
||
static bool s_wii_speak_enabled = false;
|
||
static bool s_logi_microphone_enabled = false;
|
||
static bool s_gc_mic_enabled = false;
|
||
|
||
if (Libretro::Options::IsUpdated(Libretro::Options::sysconf::WII_SPEAK_ENABLE))
|
||
s_wii_speak_enabled = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::WII_SPEAK_ENABLE);
|
||
|
||
if (Libretro::Options::IsUpdated(Libretro::Options::sysconf::WII_LOGI_MICROPHONE_ENABLE))
|
||
s_logi_microphone_enabled = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf::WII_LOGI_MICROPHONE_ENABLE);
|
||
|
||
if (Libretro::Options::IsUpdated(Libretro::Options::sysconf_gc::ENABLE_GAMECUBE_MIC))
|
||
s_gc_mic_enabled = Libretro::Options::GetCached<bool>(Libretro::Options::sysconf_gc::ENABLE_GAMECUBE_MIC);
|
||
|
||
Core::System& system = Core::System::GetInstance();
|
||
|
||
if (system.IsWii() && (s_wii_speak_enabled || s_logi_microphone_enabled))
|
||
{
|
||
for (auto* mic : Libretro::Input::g_active_microphones)
|
||
mic->PollRetroArchMic();
|
||
}
|
||
else if(s_gc_mic_enabled)
|
||
{
|
||
// Poll GC mic
|
||
auto* exi_device = system.GetExpansionInterface().GetDevice(ExpansionInterface::Slot::B);
|
||
if (exi_device && Config::Get(Config::GetInfoForEXIDevice(ExpansionInterface::Slot::B))
|
||
== ExpansionInterface::EXIDeviceType::Microphone)
|
||
{
|
||
auto* gc_mic = static_cast<ExpansionInterface::CEXIMic*>(exi_device);
|
||
gc_mic->PollLibretroMic();
|
||
}
|
||
}
|
||
}
|