mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #8352 from rlnilsen/motion-controller-support-via-cemuhook-protocol
Support for motion controllers like the DualShock 4
This commit is contained in:
@@ -85,6 +85,7 @@
|
||||
#define GFX_CONFIG "GFX.ini"
|
||||
#define DEBUGGER_CONFIG "Debugger.ini"
|
||||
#define LOGGER_CONFIG "Logger.ini"
|
||||
#define DUALSHOCKUDPCLIENT_CONFIG "DSUClient.ini"
|
||||
|
||||
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
|
||||
#define MAIN_LOG "dolphin.log"
|
||||
|
||||
@@ -133,9 +133,15 @@ void ClearCurrentRunLayer()
|
||||
}
|
||||
|
||||
static const std::map<System, std::string> system_to_name = {
|
||||
{System::Main, "Dolphin"}, {System::GCPad, "GCPad"}, {System::WiiPad, "Wiimote"},
|
||||
{System::GCKeyboard, "GCKeyboard"}, {System::GFX, "Graphics"}, {System::Logger, "Logger"},
|
||||
{System::Debugger, "Debugger"}, {System::SYSCONF, "SYSCONF"}};
|
||||
{System::Main, "Dolphin"},
|
||||
{System::GCPad, "GCPad"},
|
||||
{System::WiiPad, "Wiimote"},
|
||||
{System::GCKeyboard, "GCKeyboard"},
|
||||
{System::GFX, "Graphics"},
|
||||
{System::Logger, "Logger"},
|
||||
{System::Debugger, "Debugger"},
|
||||
{System::SYSCONF, "SYSCONF"},
|
||||
{System::DualShockUDPClient, "DualShockUDPClient"}};
|
||||
|
||||
const std::string& GetSystemName(System system)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@ enum class System
|
||||
GFX,
|
||||
Logger,
|
||||
Debugger,
|
||||
DualShockUDPClient,
|
||||
};
|
||||
|
||||
constexpr std::array<LayerType, 7> SEARCH_ORDER{{
|
||||
|
||||
@@ -794,6 +794,8 @@ static void RebuildUserDirectories(unsigned int dir_index)
|
||||
s_user_paths[F_GFXCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + GFX_CONFIG;
|
||||
s_user_paths[F_DEBUGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
s_user_paths[F_LOGGERCONFIG_IDX] = s_user_paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
s_user_paths[F_DUALSHOCKUDPCLIENTCONFIG_IDX] =
|
||||
s_user_paths[D_CONFIG_IDX] + DUALSHOCKUDPCLIENT_CONFIG;
|
||||
s_user_paths[F_MAINLOG_IDX] = s_user_paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
s_user_paths[F_MEM1DUMP_IDX] = s_user_paths[D_DUMP_IDX] + MEM1_DUMP;
|
||||
s_user_paths[F_MEM2DUMP_IDX] = s_user_paths[D_DUMP_IDX] + MEM2_DUMP;
|
||||
|
||||
@@ -70,6 +70,7 @@ enum
|
||||
F_MEMORYWATCHERLOCATIONS_IDX,
|
||||
F_MEMORYWATCHERSOCKET_IDX,
|
||||
F_WIISDCARD_IDX,
|
||||
F_DUALSHOCKUDPCLIENTCONFIG_IDX,
|
||||
NUM_PATH_INDICES
|
||||
};
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ const std::map<Config::System, int> system_to_ini = {
|
||||
{Config::System::GFX, F_GFXCONFIG_IDX},
|
||||
{Config::System::Logger, F_LOGGERCONFIG_IDX},
|
||||
{Config::System::Debugger, F_DEBUGGERCONFIG_IDX},
|
||||
{Config::System::DualShockUDPClient, F_DUALSHOCKUDPCLIENTCONFIG_IDX},
|
||||
};
|
||||
|
||||
// INI layer configuration loader
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace ConfigLoaders
|
||||
{
|
||||
bool IsSettingSaveable(const Config::ConfigLocation& config_location)
|
||||
{
|
||||
if (config_location.system == Config::System::DualShockUDPClient)
|
||||
return true;
|
||||
|
||||
if (config_location.system == Config::System::Logger)
|
||||
return true;
|
||||
|
||||
|
||||
@@ -629,4 +629,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1661,8 +1661,11 @@
|
||||
<ClInclude Include="HW\AddressSpace.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HW\WiimoteEmu\Constants.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\Wiimote\Emu</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUAccelerometer.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
|
||||
namespace
|
||||
@@ -268,6 +271,90 @@ void ApproachAngleWithAccel(RotationalState* state, const Common::Vec3& angle_ta
|
||||
}
|
||||
}
|
||||
|
||||
static Common::Vec3 NormalizeAngle(Common::Vec3 angle)
|
||||
{
|
||||
// TODO: There must be a more elegant way to do this
|
||||
angle.x = fmod(angle.x, float(MathUtil::TAU));
|
||||
angle.y = fmod(angle.y, float(MathUtil::TAU));
|
||||
angle.z = fmod(angle.z, float(MathUtil::TAU));
|
||||
angle.x += angle.x < 0 ? float(MathUtil::TAU) : 0;
|
||||
angle.y += angle.y < 0 ? float(MathUtil::TAU) : 0;
|
||||
angle.z += angle.z < 0 ? float(MathUtil::TAU) : 0;
|
||||
return angle;
|
||||
}
|
||||
|
||||
static Common::Vec3 ComplementaryFilter(const Common::Vec3& angle,
|
||||
const Common::Vec3& accelerometer,
|
||||
const Common::Vec3& gyroscope, float time_elapsed)
|
||||
{
|
||||
Common::Vec3 gyroangle = angle + gyroscope * time_elapsed;
|
||||
gyroangle = NormalizeAngle(gyroangle);
|
||||
|
||||
// Calculate accelerometer tilt angles
|
||||
Common::Vec3 accangle = gyroangle;
|
||||
if ((accelerometer.x != 0 && accelerometer.y != 0) || accelerometer.z != 0)
|
||||
{
|
||||
float accpitch = -atan2(accelerometer.y, -accelerometer.z) + float(MathUtil::PI);
|
||||
float accroll = atan2(accelerometer.x, -accelerometer.z) + float(MathUtil::PI);
|
||||
accangle = {accpitch, accroll, gyroangle.z};
|
||||
}
|
||||
|
||||
// Massage accelerometer and gyroscope angle values so that averaging them works when they are on
|
||||
// opposite sides of TAU / zero (which both represent the same angle)
|
||||
// TODO: There must be a more elegant way to do this
|
||||
constexpr float DEG360 = float(MathUtil::TAU);
|
||||
constexpr float DEG270 = DEG360 * 0.75f;
|
||||
constexpr float DEG90 = DEG360 * 0.25f;
|
||||
if (accangle.x < DEG90 && gyroangle.x > DEG270)
|
||||
accangle.x += DEG360;
|
||||
else if (gyroangle.x < DEG90 && accangle.x > DEG270)
|
||||
gyroangle.x += DEG360;
|
||||
if (accangle.y < DEG90 && gyroangle.y > DEG270)
|
||||
accangle.y += DEG360;
|
||||
else if (gyroangle.y < DEG90 && accangle.y > DEG270)
|
||||
gyroangle.y += DEG360;
|
||||
|
||||
// Combine accelerometer and gyroscope angles
|
||||
return NormalizeAngle((gyroangle * 0.98f) + (accangle * 0.02f));
|
||||
}
|
||||
|
||||
void EmulateIMUCursor(std::optional<RotationalState>* state, ControllerEmu::IMUCursor* imu_ir_group,
|
||||
ControllerEmu::IMUAccelerometer* imu_accelerometer_group,
|
||||
ControllerEmu::IMUGyroscope* imu_gyroscope_group, float time_elapsed)
|
||||
{
|
||||
// Avoid having to double dereference
|
||||
auto& st = *state;
|
||||
|
||||
auto accel = imu_accelerometer_group->GetState();
|
||||
auto ang_vel = imu_gyroscope_group->GetState();
|
||||
|
||||
// The IMU Cursor requires both an accelerometer and a gyroscope to function correctly.
|
||||
if (!(accel.has_value() && ang_vel.has_value()))
|
||||
{
|
||||
st = std::nullopt;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!st.has_value())
|
||||
st = RotationalState{};
|
||||
|
||||
st->angle = ComplementaryFilter(st->angle, accel.value(), ang_vel.value(), time_elapsed);
|
||||
|
||||
// Reset camera yaw angle
|
||||
constexpr ControlState BUTTON_THRESHOLD = 0.5;
|
||||
if (imu_ir_group->controls[0]->control_ref->State() > BUTTON_THRESHOLD)
|
||||
st->angle.z = 0;
|
||||
|
||||
// Limit camera yaw angle
|
||||
float totalyaw = float(imu_ir_group->GetTotalYaw());
|
||||
float yawmax = totalyaw / 2;
|
||||
float yawmin = float(MathUtil::TAU) - totalyaw / 2;
|
||||
if (st->angle.z > yawmax && st->angle.z <= float(MathUtil::PI))
|
||||
st->angle.z = yawmax;
|
||||
if (st->angle.z < yawmin && st->angle.z > float(MathUtil::PI))
|
||||
st->angle.z = yawmin;
|
||||
}
|
||||
|
||||
void ApproachPositionWithJerk(PositionalState* state, const Common::Vec3& position_target,
|
||||
const Common::Vec3& max_jerk, float time_elapsed)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUAccelerometer.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
|
||||
namespace WiimoteEmu
|
||||
@@ -53,6 +56,9 @@ void EmulateShake(PositionalState* state, ControllerEmu::Shake* shake_group, flo
|
||||
void EmulateTilt(RotationalState* state, ControllerEmu::Tilt* tilt_group, float time_elapsed);
|
||||
void EmulateSwing(MotionState* state, ControllerEmu::Force* swing_group, float time_elapsed);
|
||||
void EmulateCursor(MotionState* state, ControllerEmu::Cursor* ir_group, float time_elapsed);
|
||||
void EmulateIMUCursor(std::optional<RotationalState>* state, ControllerEmu::IMUCursor* imu_ir_group,
|
||||
ControllerEmu::IMUAccelerometer* imu_accelerometer_group,
|
||||
ControllerEmu::IMUGyroscope* imu_gyroscope_group, float time_elapsed);
|
||||
|
||||
// Convert m/s/s acceleration data to the format used by Wiimote/Nunchuk (10-bit unsigned integers).
|
||||
WiimoteCommon::DataReportBuilder::AccelData ConvertAccelData(const Common::Vec3& accel, u16 zero_g,
|
||||
|
||||
@@ -41,6 +41,9 @@
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUAccelerometer.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUCursor.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h"
|
||||
#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
|
||||
|
||||
@@ -150,6 +153,7 @@ void Wiimote::Reset()
|
||||
m_tilt_state = {};
|
||||
m_cursor_state = {};
|
||||
m_shake_state = {};
|
||||
m_imu_cursor_state = {};
|
||||
}
|
||||
|
||||
Wiimote::Wiimote(const unsigned int index) : m_index(index)
|
||||
@@ -169,6 +173,11 @@ Wiimote::Wiimote(const unsigned int index) : m_index(index)
|
||||
groups.emplace_back(m_swing = new ControllerEmu::Force(_trans("Swing")));
|
||||
groups.emplace_back(m_tilt = new ControllerEmu::Tilt(_trans("Tilt")));
|
||||
groups.emplace_back(m_shake = new ControllerEmu::Shake(_trans("Shake")));
|
||||
groups.emplace_back(m_imu_accelerometer = new ControllerEmu::IMUAccelerometer(
|
||||
"IMUAccelerometer", _trans("Accelerometer")));
|
||||
groups.emplace_back(m_imu_gyroscope =
|
||||
new ControllerEmu::IMUGyroscope("IMUGyroscope", _trans("Gyroscope")));
|
||||
groups.emplace_back(m_imu_ir = new ControllerEmu::IMUCursor("IMUIR", _trans("Point")));
|
||||
|
||||
// Extension
|
||||
groups.emplace_back(m_attachments = new ControllerEmu::Attachments(_trans("Extension")));
|
||||
@@ -263,6 +272,12 @@ ControllerEmu::ControlGroup* Wiimote::GetWiimoteGroup(WiimoteGroup group)
|
||||
return m_options;
|
||||
case WiimoteGroup::Hotkeys:
|
||||
return m_hotkeys;
|
||||
case WiimoteGroup::IMUAccelerometer:
|
||||
return m_imu_accelerometer;
|
||||
case WiimoteGroup::IMUGyroscope:
|
||||
return m_imu_gyroscope;
|
||||
case WiimoteGroup::IMUPoint:
|
||||
return m_imu_ir;
|
||||
default:
|
||||
assert(false);
|
||||
return nullptr;
|
||||
@@ -447,7 +462,7 @@ void Wiimote::SendDataReport()
|
||||
{
|
||||
// Calibration values are 8-bit but we want 10-bit precision, so << 2.
|
||||
DataReportBuilder::AccelData accel =
|
||||
ConvertAccelData(GetAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||
rpt_builder.SetAccelData(accel);
|
||||
}
|
||||
|
||||
@@ -456,7 +471,7 @@ void Wiimote::SendDataReport()
|
||||
{
|
||||
// Note: Camera logic currently contains no changing state so we can just update it here.
|
||||
// If that changes this should be moved to Wiimote::Update();
|
||||
m_camera_logic.Update(GetTransformation());
|
||||
m_camera_logic.Update(GetTotalTransformation());
|
||||
|
||||
// The real wiimote reads camera data from the i2c bus starting at offset 0x37:
|
||||
const u8 camera_data_offset =
|
||||
@@ -477,7 +492,7 @@ void Wiimote::SendDataReport()
|
||||
if (m_is_motion_plus_attached)
|
||||
{
|
||||
// TODO: Make input preparation triggered by bus read.
|
||||
m_motion_plus.PrepareInput(GetAngularVelocity());
|
||||
m_motion_plus.PrepareInput(GetTotalAngularVelocity());
|
||||
}
|
||||
|
||||
u8* ext_data = rpt_builder.GetExtDataPtr();
|
||||
@@ -670,6 +685,20 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface)
|
||||
m_dpad->SetControlExpression(3, "Right"); // Right
|
||||
#endif
|
||||
|
||||
// Motion Source
|
||||
m_imu_accelerometer->SetControlExpression(0, "Accel Left");
|
||||
m_imu_accelerometer->SetControlExpression(1, "Accel Right");
|
||||
m_imu_accelerometer->SetControlExpression(2, "Accel Forward");
|
||||
m_imu_accelerometer->SetControlExpression(3, "Accel Backward");
|
||||
m_imu_accelerometer->SetControlExpression(4, "Accel Up");
|
||||
m_imu_accelerometer->SetControlExpression(5, "Accel Down");
|
||||
m_imu_gyroscope->SetControlExpression(0, "Gyro Pitch Up");
|
||||
m_imu_gyroscope->SetControlExpression(1, "Gyro Pitch Down");
|
||||
m_imu_gyroscope->SetControlExpression(2, "Gyro Roll Left");
|
||||
m_imu_gyroscope->SetControlExpression(3, "Gyro Roll Right");
|
||||
m_imu_gyroscope->SetControlExpression(4, "Gyro Yaw Left");
|
||||
m_imu_gyroscope->SetControlExpression(5, "Gyro Yaw Right");
|
||||
|
||||
// Enable Nunchuk:
|
||||
constexpr ExtensionNumber DEFAULT_EXT = ExtensionNumber::NUNCHUK;
|
||||
m_attachments->SetSelectedAttachment(DEFAULT_EXT);
|
||||
@@ -720,14 +749,14 @@ void Wiimote::StepDynamics()
|
||||
EmulateTilt(&m_tilt_state, m_tilt, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulateCursor(&m_cursor_state, m_ir, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulateShake(&m_shake_state, m_shake, 1.f / ::Wiimote::UPDATE_FREQ);
|
||||
EmulateIMUCursor(&m_imu_cursor_state, m_imu_ir, m_imu_accelerometer, m_imu_gyroscope,
|
||||
1.f / ::Wiimote::UPDATE_FREQ);
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::GetAcceleration()
|
||||
Common::Vec3 Wiimote::GetAcceleration(Common::Vec3 extra_acceleration)
|
||||
{
|
||||
Common::Vec3 accel =
|
||||
GetOrientation() *
|
||||
GetTransformation().Transform(
|
||||
m_swing_state.acceleration + Common::Vec3(0, 0, float(GRAVITY_ACCELERATION)), 0);
|
||||
Common::Vec3 accel = GetOrientation() * GetTransformation().Transform(
|
||||
m_swing_state.acceleration + extra_acceleration, 0);
|
||||
|
||||
// Our shake effects have never been affected by orientation. Should they be?
|
||||
accel += m_shake_state.acceleration;
|
||||
@@ -735,13 +764,13 @@ Common::Vec3 Wiimote::GetAcceleration()
|
||||
return accel;
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::GetAngularVelocity()
|
||||
Common::Vec3 Wiimote::GetAngularVelocity(Common::Vec3 extra_angular_velocity)
|
||||
{
|
||||
return GetOrientation() * (m_tilt_state.angular_velocity + m_swing_state.angular_velocity +
|
||||
m_cursor_state.angular_velocity);
|
||||
m_cursor_state.angular_velocity + extra_angular_velocity);
|
||||
}
|
||||
|
||||
Common::Matrix44 Wiimote::GetTransformation() const
|
||||
Common::Matrix44 Wiimote::GetTransformation(Common::Vec3 extra_rotation) const
|
||||
{
|
||||
// Includes positional and rotational effects of:
|
||||
// Cursor, Swing, Tilt, Shake
|
||||
@@ -749,7 +778,7 @@ Common::Matrix44 Wiimote::GetTransformation() const
|
||||
// TODO: Think about and clean up matrix order + make nunchuk match.
|
||||
return Common::Matrix44::Translate(-m_shake_state.position) *
|
||||
Common::Matrix44::FromMatrix33(GetRotationalMatrix(
|
||||
-m_tilt_state.angle - m_swing_state.angle - m_cursor_state.angle)) *
|
||||
-m_tilt_state.angle - m_swing_state.angle - m_cursor_state.angle - extra_rotation)) *
|
||||
Common::Matrix44::Translate(-m_swing_state.position - m_cursor_state.position);
|
||||
}
|
||||
|
||||
@@ -759,4 +788,31 @@ Common::Matrix33 Wiimote::GetOrientation() const
|
||||
Common::Matrix33::RotateX(float(MathUtil::TAU / 4 * IsUpright()));
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::GetTotalAcceleration()
|
||||
{
|
||||
auto accel = m_imu_accelerometer->GetState();
|
||||
if (accel.has_value())
|
||||
return GetAcceleration(accel.value());
|
||||
else
|
||||
return GetAcceleration();
|
||||
}
|
||||
|
||||
Common::Vec3 Wiimote::GetTotalAngularVelocity()
|
||||
{
|
||||
auto ang_vel = m_imu_gyroscope->GetState();
|
||||
if (ang_vel.has_value())
|
||||
return GetAngularVelocity(ang_vel.value());
|
||||
else
|
||||
return GetAngularVelocity();
|
||||
}
|
||||
|
||||
Common::Matrix44 Wiimote::GetTotalTransformation() const
|
||||
{
|
||||
auto state = m_imu_cursor_state;
|
||||
if (state.has_value())
|
||||
return GetTransformation(state->angle);
|
||||
else
|
||||
return GetTransformation();
|
||||
}
|
||||
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
@@ -28,6 +28,9 @@ class ControlGroup;
|
||||
class Cursor;
|
||||
class Extension;
|
||||
class Force;
|
||||
class IMUAccelerometer;
|
||||
class IMUGyroscope;
|
||||
class IMUCursor;
|
||||
class ModifySettingsButton;
|
||||
class Output;
|
||||
class Tilt;
|
||||
@@ -45,9 +48,11 @@ enum class WiimoteGroup
|
||||
Swing,
|
||||
Rumble,
|
||||
Attachments,
|
||||
|
||||
Options,
|
||||
Hotkeys
|
||||
Hotkeys,
|
||||
IMUAccelerometer,
|
||||
IMUGyroscope,
|
||||
IMUPoint,
|
||||
};
|
||||
|
||||
enum class NunchukGroup;
|
||||
@@ -140,22 +145,29 @@ private:
|
||||
// This is the region exposed over bluetooth:
|
||||
static constexpr int EEPROM_FREE_SIZE = 0x1700;
|
||||
|
||||
static constexpr double BUTTON_THRESHOLD = 0.5;
|
||||
|
||||
void UpdateButtonsStatus();
|
||||
|
||||
// Returns simulated accelerometer data in m/s^2.
|
||||
Common::Vec3 GetAcceleration();
|
||||
Common::Vec3 GetAcceleration(
|
||||
Common::Vec3 extra_acceleration = Common::Vec3(0, 0, float(GRAVITY_ACCELERATION)));
|
||||
|
||||
// Returns simulated gyroscope data in radians/s.
|
||||
Common::Vec3 GetAngularVelocity();
|
||||
Common::Vec3 GetAngularVelocity(Common::Vec3 extra_angular_velocity = {});
|
||||
|
||||
// Returns the transformation of the world around the wiimote.
|
||||
// Used for simulating camera data and for rotating acceleration data.
|
||||
// Does not include orientation transformations.
|
||||
Common::Matrix44 GetTransformation() const;
|
||||
Common::Matrix44 GetTransformation(Common::Vec3 extra_rotation = {}) const;
|
||||
|
||||
// Returns the world rotation from the effects of sideways/upright settings.
|
||||
Common::Matrix33 GetOrientation() const;
|
||||
|
||||
Common::Vec3 GetTotalAcceleration();
|
||||
Common::Vec3 GetTotalAngularVelocity();
|
||||
Common::Matrix44 GetTotalTransformation() const;
|
||||
|
||||
void HIDOutputReport(const void* data, u32 size);
|
||||
|
||||
void HandleReportRumble(const WiimoteCommon::OutputReportRumble&);
|
||||
@@ -246,6 +258,9 @@ private:
|
||||
ControllerEmu::Attachments* m_attachments;
|
||||
ControllerEmu::ControlGroup* m_options;
|
||||
ControllerEmu::ModifySettingsButton* m_hotkeys;
|
||||
ControllerEmu::IMUAccelerometer* m_imu_accelerometer;
|
||||
ControllerEmu::IMUGyroscope* m_imu_gyroscope;
|
||||
ControllerEmu::IMUCursor* m_imu_ir;
|
||||
|
||||
ControllerEmu::SettingValue<bool> m_sideways_setting;
|
||||
ControllerEmu::SettingValue<bool> m_upright_setting;
|
||||
@@ -284,5 +299,6 @@ private:
|
||||
RotationalState m_tilt_state;
|
||||
MotionState m_cursor_state;
|
||||
PositionalState m_shake_state;
|
||||
std::optional<RotationalState> m_imu_cursor_state;
|
||||
};
|
||||
} // namespace WiimoteEmu
|
||||
|
||||
@@ -51,6 +51,10 @@ add_executable(dolphin-emu
|
||||
Config/CheatCodeEditor.h
|
||||
Config/CheatWarningWidget.cpp
|
||||
Config/CheatWarningWidget.h
|
||||
Config/ControllerInterface/DualShockUDPClientWidget.cpp
|
||||
Config/ControllerInterface/DualShockUDPClientWidget.h
|
||||
Config/ControllerInterface/ControllerInterfaceWindow.cpp
|
||||
Config/ControllerInterface/ControllerInterfaceWindow.h
|
||||
Config/ControllersWindow.cpp
|
||||
Config/ControllersWindow.h
|
||||
Config/FilesystemWidget.cpp
|
||||
@@ -140,6 +144,8 @@ add_executable(dolphin-emu
|
||||
Config/Mapping/WiimoteEmuGeneral.h
|
||||
Config/Mapping/WiimoteEmuMotionControl.cpp
|
||||
Config/Mapping/WiimoteEmuMotionControl.h
|
||||
Config/Mapping/WiimoteEmuMotionControlIMU.cpp
|
||||
Config/Mapping/WiimoteEmuMotionControlIMU.h
|
||||
Config/NewPatchDialog.cpp
|
||||
Config/NewPatchDialog.h
|
||||
Config/PatchesWidget.cpp
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#if defined(CIFACE_USE_DUALSHOCKUDPCLIENT)
|
||||
#include "DolphinQt/Config/ControllerInterface/DualShockUDPClientWidget.h"
|
||||
#endif
|
||||
|
||||
ControllerInterfaceWindow::ControllerInterfaceWindow(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
CreateMainLayout();
|
||||
|
||||
setWindowTitle(tr("Alternate Input Sources"));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
}
|
||||
|
||||
void ControllerInterfaceWindow::CreateMainLayout()
|
||||
{
|
||||
m_button_box = new QDialogButtonBox(QDialogButtonBox::Close);
|
||||
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
m_tab_widget = new QTabWidget();
|
||||
#if defined(CIFACE_USE_DUALSHOCKUDPCLIENT)
|
||||
m_dsuclient_widget = new DualShockUDPClientWidget();
|
||||
m_tab_widget->addTab(m_dsuclient_widget, tr("DSU Client")); // TODO: use GetWrappedWidget()?
|
||||
#endif
|
||||
|
||||
auto* main_layout = new QVBoxLayout();
|
||||
if (m_tab_widget->count() > 0)
|
||||
{
|
||||
main_layout->addWidget(m_tab_widget);
|
||||
}
|
||||
else
|
||||
{
|
||||
main_layout->addWidget(new QLabel(tr("Nothing to configure")), 0,
|
||||
Qt::AlignVCenter | Qt::AlignHCenter);
|
||||
}
|
||||
main_layout->addWidget(m_button_box);
|
||||
setLayout(main_layout);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
||||
#if defined(CIFACE_USE_DUALSHOCKUDPCLIENT)
|
||||
class DualShockUDPClientWidget;
|
||||
#endif
|
||||
class QTabWidget;
|
||||
class QDialogButtonBox;
|
||||
|
||||
class ControllerInterfaceWindow final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ControllerInterfaceWindow(QWidget* parent);
|
||||
|
||||
private:
|
||||
void CreateMainLayout();
|
||||
|
||||
QTabWidget* m_tab_widget;
|
||||
QDialogButtonBox* m_button_box;
|
||||
|
||||
#if defined(CIFACE_USE_DUALSHOCKUDPCLIENT)
|
||||
DualShockUDPClientWidget* m_dsuclient_widget;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2019 Dolphin Emulator Project5~5~5~
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinQt/Config/ControllerInterface/DualShockUDPClientWidget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QSpinBox>
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
#include "InputCommon/ControllerInterface/DualShockUDPClient/DualShockUDPClient.h"
|
||||
|
||||
DualShockUDPClientWidget::DualShockUDPClientWidget()
|
||||
{
|
||||
CreateWidgets();
|
||||
ConnectWidgets();
|
||||
}
|
||||
|
||||
void DualShockUDPClientWidget::CreateWidgets()
|
||||
{
|
||||
auto* main_layout = new QGridLayout;
|
||||
|
||||
m_server_enabled = new QCheckBox(tr("Enable"));
|
||||
m_server_enabled->setChecked(Config::Get(ciface::DualShockUDPClient::Settings::SERVER_ENABLED));
|
||||
|
||||
m_server_address = new QLineEdit(
|
||||
QString::fromStdString(Config::Get(ciface::DualShockUDPClient::Settings::SERVER_ADDRESS)));
|
||||
|
||||
m_server_port = new QSpinBox();
|
||||
m_server_port->setMaximum(65535);
|
||||
m_server_port->setValue(Config::Get(ciface::DualShockUDPClient::Settings::SERVER_PORT));
|
||||
|
||||
auto* description =
|
||||
new QLabel(tr("DSU protocol enables the use of input and motion data from compatible "
|
||||
"sources, like PlayStation, Nintendo Switch and Steam controllers.<br><br>"
|
||||
"For setup instructions, "
|
||||
"<a href=\"https://wiki.dolphin-emu.org/index.php?title=DSU_Client\">"
|
||||
"refer to this page</a>."));
|
||||
description->setTextFormat(Qt::RichText);
|
||||
description->setWordWrap(true);
|
||||
description->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
description->setOpenExternalLinks(true);
|
||||
|
||||
main_layout->addWidget(m_server_enabled, 1, 1);
|
||||
main_layout->addWidget(new QLabel(tr("Server IP Address")), 2, 1);
|
||||
main_layout->addWidget(m_server_address, 2, 2);
|
||||
main_layout->addWidget(new QLabel(tr("Server Port")), 3, 1);
|
||||
main_layout->addWidget(m_server_port, 3, 2);
|
||||
main_layout->addWidget(description, 4, 1, 1, 2);
|
||||
|
||||
setLayout(main_layout);
|
||||
}
|
||||
|
||||
void DualShockUDPClientWidget::ConnectWidgets()
|
||||
{
|
||||
connect(m_server_enabled, &QCheckBox::toggled, this, [this] {
|
||||
Config::SetBaseOrCurrent(ciface::DualShockUDPClient::Settings::SERVER_ENABLED,
|
||||
m_server_enabled->isChecked());
|
||||
});
|
||||
|
||||
connect(m_server_address, &QLineEdit::editingFinished, this, [this] {
|
||||
Config::SetBaseOrCurrent(ciface::DualShockUDPClient::Settings::SERVER_ADDRESS,
|
||||
m_server_address->text().toStdString());
|
||||
});
|
||||
|
||||
connect(m_server_port, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||
[this] {
|
||||
Config::SetBaseOrCurrent(ciface::DualShockUDPClient::Settings::SERVER_PORT,
|
||||
static_cast<u16>(m_server_port->value()));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QCheckBox;
|
||||
class QLineEdit;
|
||||
class QSpinBox;
|
||||
|
||||
class DualShockUDPClientWidget final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DualShockUDPClientWidget();
|
||||
|
||||
private:
|
||||
void CreateWidgets();
|
||||
void ConnectWidgets();
|
||||
|
||||
QCheckBox* m_server_enabled;
|
||||
QLineEdit* m_server_address;
|
||||
QSpinBox* m_server_port;
|
||||
};
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "Core/IOS/USB/Bluetooth/BTReal.h"
|
||||
|
||||
#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h"
|
||||
#include "DolphinQt/Config/Mapping/GCPadWiiUConfigDialog.h"
|
||||
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||
@@ -67,7 +68,7 @@ ControllersWindow::ControllersWindow(QWidget* parent) : QDialog(parent)
|
||||
|
||||
CreateGamecubeLayout();
|
||||
CreateWiimoteLayout();
|
||||
CreateAdvancedLayout();
|
||||
CreateCommonLayout();
|
||||
CreateMainLayout();
|
||||
LoadSettings();
|
||||
ConnectWidgets();
|
||||
@@ -199,15 +200,18 @@ void ControllersWindow::CreateWiimoteLayout()
|
||||
m_wiimote_layout->addWidget(m_wiimote_speaker_data, m_wiimote_layout->rowCount(), 1, 1, -1);
|
||||
}
|
||||
|
||||
void ControllersWindow::CreateAdvancedLayout()
|
||||
void ControllersWindow::CreateCommonLayout()
|
||||
{
|
||||
m_advanced_box = new QGroupBox(tr("Advanced"));
|
||||
m_advanced_layout = new QHBoxLayout();
|
||||
m_advanced_bg_input = new QCheckBox(tr("Background Input"));
|
||||
// i18n: This is "common" as in "shared", not the opposite of "uncommon"
|
||||
m_common_box = new QGroupBox(tr("Common"));
|
||||
m_common_layout = new QVBoxLayout();
|
||||
m_common_bg_input = new QCheckBox(tr("Background Input"));
|
||||
m_common_configure_controller_interface = new QPushButton(tr("Alternate Input Sources"));
|
||||
|
||||
m_advanced_layout->addWidget(m_advanced_bg_input);
|
||||
m_common_layout->addWidget(m_common_bg_input);
|
||||
m_common_layout->addWidget(m_common_configure_controller_interface);
|
||||
|
||||
m_advanced_box->setLayout(m_advanced_layout);
|
||||
m_common_box->setLayout(m_common_layout);
|
||||
}
|
||||
|
||||
void ControllersWindow::CreateMainLayout()
|
||||
@@ -217,7 +221,8 @@ void ControllersWindow::CreateMainLayout()
|
||||
|
||||
layout->addWidget(m_gc_box);
|
||||
layout->addWidget(m_wiimote_box);
|
||||
layout->addWidget(m_advanced_box);
|
||||
layout->addWidget(m_common_box);
|
||||
layout->addStretch();
|
||||
layout->addWidget(m_button_box);
|
||||
|
||||
WrapInScrollArea(this, layout);
|
||||
@@ -232,7 +237,9 @@ void ControllersWindow::ConnectWidgets()
|
||||
connect(m_wiimote_passthrough, &QRadioButton::toggled, this,
|
||||
&ControllersWindow::OnWiimoteModeChanged);
|
||||
|
||||
connect(m_advanced_bg_input, &QCheckBox::toggled, this, &ControllersWindow::SaveSettings);
|
||||
connect(m_common_bg_input, &QCheckBox::toggled, this, &ControllersWindow::SaveSettings);
|
||||
connect(m_common_configure_controller_interface, &QPushButton::clicked, this,
|
||||
&ControllersWindow::OnControllerInterfaceConfigure);
|
||||
connect(m_wiimote_continuous_scanning, &QCheckBox::toggled, this,
|
||||
&ControllersWindow::SaveSettings);
|
||||
connect(m_wiimote_real_balance_board, &QCheckBox::toggled, this,
|
||||
@@ -462,6 +469,14 @@ void ControllersWindow::OnWiimoteConfigure()
|
||||
window->show();
|
||||
}
|
||||
|
||||
void ControllersWindow::OnControllerInterfaceConfigure()
|
||||
{
|
||||
ControllerInterfaceWindow* window = new ControllerInterfaceWindow(this);
|
||||
window->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
window->setWindowModality(Qt::WindowModality::WindowModal);
|
||||
window->show();
|
||||
}
|
||||
|
||||
void ControllersWindow::LoadSettings()
|
||||
{
|
||||
for (size_t i = 0; i < m_wiimote_groups.size(); i++)
|
||||
@@ -480,7 +495,7 @@ void ControllersWindow::LoadSettings()
|
||||
m_wiimote_speaker_data->setChecked(SConfig::GetInstance().m_WiimoteEnableSpeaker);
|
||||
m_wiimote_continuous_scanning->setChecked(SConfig::GetInstance().m_WiimoteContinuousScanning);
|
||||
|
||||
m_advanced_bg_input->setChecked(SConfig::GetInstance().m_BackgroundInput);
|
||||
m_common_bg_input->setChecked(SConfig::GetInstance().m_BackgroundInput);
|
||||
|
||||
if (SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
m_wiimote_passthrough->setChecked(true);
|
||||
@@ -495,7 +510,7 @@ void ControllersWindow::SaveSettings()
|
||||
SConfig::GetInstance().m_WiimoteEnableSpeaker = m_wiimote_speaker_data->isChecked();
|
||||
SConfig::GetInstance().m_WiimoteContinuousScanning = m_wiimote_continuous_scanning->isChecked();
|
||||
SConfig::GetInstance().m_bt_passthrough_enabled = m_wiimote_passthrough->isChecked();
|
||||
SConfig::GetInstance().m_BackgroundInput = m_advanced_bg_input->isChecked();
|
||||
SConfig::GetInstance().m_BackgroundInput = m_common_bg_input->isChecked();
|
||||
|
||||
WiimoteReal::ChangeWiimoteSource(WIIMOTE_BALANCE_BOARD,
|
||||
m_wiimote_real_balance_board->isChecked() ? WIIMOTE_SRC_REAL :
|
||||
|
||||
@@ -37,10 +37,11 @@ private:
|
||||
void OnWiimoteRefreshPressed();
|
||||
void OnGCPadConfigure();
|
||||
void OnWiimoteConfigure();
|
||||
void OnControllerInterfaceConfigure();
|
||||
|
||||
void CreateGamecubeLayout();
|
||||
void CreateWiimoteLayout();
|
||||
void CreateAdvancedLayout();
|
||||
void CreateCommonLayout();
|
||||
void CreateMainLayout();
|
||||
void ConnectWidgets();
|
||||
void LoadSettings();
|
||||
@@ -73,8 +74,9 @@ private:
|
||||
QCheckBox* m_wiimote_speaker_data;
|
||||
QPushButton* m_wiimote_refresh;
|
||||
|
||||
// Advanced
|
||||
QGroupBox* m_advanced_box;
|
||||
QHBoxLayout* m_advanced_layout;
|
||||
QCheckBox* m_advanced_bg_input;
|
||||
// Common
|
||||
QGroupBox* m_common_box;
|
||||
QVBoxLayout* m_common_layout;
|
||||
QCheckBox* m_common_bg_input;
|
||||
QPushButton* m_common_configure_controller_interface;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user