Compare commits

...

16 Commits

Author SHA1 Message Date
anirudhb
751f9dc802 Merge yuzu-emu/master 2020-05-02 16:58:42 -07:00
anirudhb
8ed512b0c4 Merge remote-tracking branch 'yuzu-emu/master' 2020-05-02 16:57:30 -07:00
anirudhb
e4c40c2eed Fix saving of float values 2020-05-02 16:31:51 -07:00
anirudhb
d0b70fb925 Fix motion controls config saving 2020-05-02 15:50:19 -07:00
anirudhb
b777f00628 Clang-format 2020-05-02 15:31:53 -07:00
anirudhb
79e5d0e96b GUI + calibration + multiple sources
Added proper QT GUI and proper multiple controller support.
Calibration using offsets and sensitivity as a scale factor has also
been added.
2020-05-02 15:15:52 -07:00
anirudhb
bf03e64491 Remove ReloadClient, parametrize cemuhookudp
Added logging code for gyro in npad
Removed ReloadClient from cemuhookudp because it wasn't used.
2020-04-29 21:16:06 -07:00
anirudhb
11c04e2d10 Merge branch 'master' of https://github.com/yuzu-emu/yuzu 2020-04-29 19:53:37 -07:00
anirudhb
4b5eefeefd Revert cemuhookudp patch 2020-04-29 09:31:38 -07:00
anirudhb
7e17b5574c Only activate sixaxis for controller type + fix cemuhookudp
Cemuhookudp patch from johngalt
2020-04-29 09:14:50 -07:00
anirudhb
e3faff893a Clang-format again 2020-04-28 18:42:00 -07:00
anirudhb
c6b03386c0 Address review nits and make always_one field always one 2020-04-28 18:39:43 -07:00
anirudhb
7419ac0952 Trial and error: try setting all sixaxis entries 2020-04-28 18:22:29 -07:00
anirudhb
4e6c97dd38 Nit: remove sixaxis include from HID (nonexistent) 2020-04-28 18:00:32 -07:00
anirudhb
b95e6c0b0a Clang-format 2020-04-28 17:39:44 -07:00
anirudhb
bcba34ae7d Add a small implementation of motion controls 2020-04-28 17:13:41 -07:00
15 changed files with 1222 additions and 409 deletions

View File

@@ -5,6 +5,7 @@
#include <algorithm>
#include <array>
#include <cstring>
#include <sstream>
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_types.h"
@@ -235,6 +236,11 @@ void Controller_NPad::OnLoadInputDevices() {
std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
std::transform(players[i].motion_devices.begin(), players[i].motion_devices.end(),
motion_sensors[i].begin(), [](const Settings::MotionRaw& raw) {
return raw.enabled ? Input::CreateDevice<Input::MotionDevice>(raw.device)
: nullptr;
});
}
}
@@ -338,6 +344,25 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
cur_entry.timestamp2 = cur_entry.timestamp;
}
const std::array<SixAxisGeneric*, 6> controller_sixaxes{
&npad.full, &npad.handheld, &npad.left_dual, &npad.right_dual, &npad.left, &npad.right,
};
for (auto* sixaxis : controller_sixaxes) {
sixaxis->common.entry_count = 16;
sixaxis->common.total_entry_count = 17;
const auto& last_entry = sixaxis->sixaxis[sixaxis->common.last_entry_index];
sixaxis->common.timestamp = core_timing.GetTicks();
sixaxis->common.last_entry_index = (sixaxis->common.last_entry_index + 1) % 17;
auto& cur_entry = sixaxis->sixaxis[sixaxis->common.last_entry_index];
cur_entry.timestamp = last_entry.timestamp + 1;
cur_entry.timestamp2 = cur_entry.timestamp;
}
const auto& controller_type = connected_controllers[i].type;
if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
@@ -347,6 +372,19 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
RequestPadStateUpdate(npad_index);
auto& pad_state = npad_pad_states[npad_index];
// Try to get motion sensor state if it exists
Common::Vec3f accel1, gyro1, accel2, gyro2;
if (sixaxis_sensor_enabled) {
const auto& sensor1 = motion_sensors[i][0];
const auto& sensor2 = motion_sensors[i][1];
if (sensor1) {
std::tie(accel1, gyro1) = sensor1->GetStatus();
}
if (sensor2) {
std::tie(accel2, gyro2) = sensor2->GetStatus();
}
}
auto& main_controller =
npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
auto& handheld_entry =
@@ -375,6 +413,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
handheld_entry.pad.l_stick = pad_state.l_stick;
handheld_entry.pad.r_stick = pad_state.r_stick;
if (sixaxis_sensor_enabled && motion_sensors[i][0]) {
npad.handheld.sixaxis[npad.handheld.common.last_entry_index].accelerometer = accel1;
npad.handheld.sixaxis[npad.handheld.common.last_entry_index].gyroscope = gyro1;
}
break;
case NPadControllerType::JoyDual:
dual_entry.connection_status.raw = 0;
@@ -390,6 +433,24 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
dual_entry.pad.l_stick = pad_state.l_stick;
dual_entry.pad.r_stick = pad_state.r_stick;
if (sixaxis_sensor_enabled) {
if (motion_sensors[i][0] && motion_sensors[i][1]) {
npad.left_dual.sixaxis[npad.left_dual.common.last_entry_index].accelerometer =
accel1;
npad.left_dual.sixaxis[npad.left_dual.common.last_entry_index].gyroscope =
gyro1;
npad.right_dual.sixaxis[npad.right_dual.common.last_entry_index].accelerometer =
accel2;
npad.right_dual.sixaxis[npad.right_dual.common.last_entry_index].gyroscope =
gyro2;
} else {
npad.right_dual.sixaxis[npad.right_dual.common.last_entry_index].accelerometer =
accel1;
npad.right_dual.sixaxis[npad.right_dual.common.last_entry_index].gyroscope =
gyro1;
}
}
break;
case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
@@ -398,6 +459,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
left_entry.pad.l_stick = pad_state.l_stick;
left_entry.pad.r_stick = pad_state.r_stick;
if (sixaxis_sensor_enabled && motion_sensors[i][0]) {
npad.left.sixaxis[npad.left.common.last_entry_index].accelerometer = accel1;
npad.left.sixaxis[npad.left.common.last_entry_index].gyroscope = gyro1;
}
break;
case NPadControllerType::JoyRight:
right_entry.connection_status.raw = 0;
@@ -406,6 +472,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
right_entry.pad.l_stick = pad_state.l_stick;
right_entry.pad.r_stick = pad_state.r_stick;
if (sixaxis_sensor_enabled && motion_sensors[i][0]) {
npad.right.sixaxis[npad.right.common.last_entry_index].accelerometer = accel1;
npad.right.sixaxis[npad.right.common.last_entry_index].gyroscope = gyro1;
}
break;
case NPadControllerType::Pokeball:
pokeball_entry.connection_status.raw = 0;
@@ -425,6 +496,11 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
main_controller.pad.l_stick = pad_state.l_stick;
main_controller.pad.r_stick = pad_state.r_stick;
if (sixaxis_sensor_enabled && motion_sensors[i][0]) {
npad.full.sixaxis[npad.full.common.last_entry_index].accelerometer = accel1;
npad.full.sixaxis[npad.full.common.last_entry_index].gyroscope = gyro1;
}
break;
}

View File

@@ -7,6 +7,7 @@
#include <array>
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/vector_math.h"
#include "core/frontend/input.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/writable_event.h"
@@ -236,6 +237,24 @@ private:
};
static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
struct SixAxisState {
s64_le timestamp{};
INSERT_PADDING_WORDS(2); // unknown
s64_le timestamp2{};
Common::Vec3f accelerometer{};
Common::Vec3f gyroscope{};
INSERT_PADDING_WORDS(3); // unknown
std::array<Common::Vec3f, 3> orientation{};
s64_le always_one{1}; // always 1
};
static_assert(sizeof(SixAxisState) == 0x68, "SixAxisState is an invalid size");
struct SixAxisGeneric {
CommonHeader common;
std::array<SixAxisState, 17> sixaxis;
};
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
enum class ColorReadError : u32_le {
ReadOk = 0,
ColorDoesntExist = 1,
@@ -284,9 +303,12 @@ private:
NPadGeneric pokeball_states;
NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be
// relying on this for the time being
INSERT_PADDING_BYTES(
0x708 *
6); // TODO(ogniK): SixAxis states, require more information before implementation
SixAxisGeneric full;
SixAxisGeneric handheld;
SixAxisGeneric left_dual;
SixAxisGeneric right_dual;
SixAxisGeneric left;
SixAxisGeneric right;
NPadDevice device_type;
NPadProperties properties;
INSERT_PADDING_WORDS(1);
@@ -318,6 +340,8 @@ private:
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
10>
sticks;
std::array<std::array<std::unique_ptr<Input::MotionDevice>, 2>, 10> motion_sensors;
bool sixaxis_sensor_enabled{true};
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
// Each controller should have their own styleset changed event

View File

@@ -395,9 +395,10 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
applet_resource->ActivateController(HidController::SixAxisSensor);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -825,8 +826,9 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto handle{rp.Pop<u32>()};
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle);
LOG_DEBUG(Service_HID, "called, handle={}", handle);
applet_resource->DeactivateController(HidController::SixAxisSensor);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}

View File

@@ -324,12 +324,19 @@ enum class ControllerType {
LeftJoycon,
};
struct MotionRaw {
bool enabled;
std::string device;
};
struct PlayerInput {
bool connected;
ControllerType type;
ButtonsRaw buttons;
AnalogsRaw analogs;
std::array<MotionRaw, 2> motion_devices;
u32 body_color_right;
u32 button_color_right;
u32 body_color_left;

View File

@@ -52,6 +52,17 @@ MotionEmu* GetMotionEmu() {
return motion_emu.get();
}
std::string GenerateMotionParam(const std::string& address, int port, int pad_index, float cx,
float cy, float cz, float sensitivity) {
Common::ParamPackage param{
{"engine", "cemuhookudp"}, {"address", address},
{"port", std::to_string(port)}, {"pad_index", std::to_string(pad_index)},
{"cx", std::to_string(cx)}, {"cy", std::to_string(cy)},
{"cz", std::to_string(cz)}, {"sensitivity", std::to_string(sensitivity)},
};
return param.Serialize();
}
std::string GenerateKeyboardParam(int key_code) {
Common::ParamPackage param{
{"engine", "keyboard"},

View File

@@ -30,6 +30,10 @@ class MotionEmu;
/// Gets the motion emulation factory.
MotionEmu* GetMotionEmu();
/// Generates a serialized param package for creating a cemuhookudp motion device
std::string GenerateMotionParam(const std::string& address, int port, int pad_index, float cx,
float cy, float cz, float sensitivity);
/// Generates a serialized param package for creating a keyboard button device
std::string GenerateKeyboardParam(int key_code);

View File

@@ -28,21 +28,32 @@ private:
class UDPMotionDevice final : public Input::MotionDevice {
public:
explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
explicit UDPMotionDevice(const std::string& host, int port, int pad_index, Common::Vec3f offset,
float sensitivity)
: offset(offset), sensitivity(sensitivity) {
status = std::make_shared<DeviceStatus>();
client = std::make_unique<Client>(status, host, port, pad_index);
}
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
std::lock_guard guard(status->update_mutex);
return status->motion_status;
std::tuple<Common::Vec3<float>, Common::Vec3<float>> motion = status->motion_status;
std::get<0>(motion) = (std::get<0>(motion) + offset) * sensitivity;
return motion;
}
private:
std::shared_ptr<DeviceStatus> status;
std::unique_ptr<Client> client;
Common::Vec3f offset;
float sensitivity;
};
class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> {
public:
explicit UDPTouchFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
explicit UDPTouchFactory() {}
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override {
status = std::make_shared<DeviceStatus>();
{
std::lock_guard guard(status->update_mutex);
status->touch_calibration = DeviceStatus::CalibrationData{};
@@ -52,35 +63,40 @@ public:
status->touch_calibration->max_x = params.Get("max_x", 1800);
status->touch_calibration->max_y = params.Get("max_y", 850);
}
std::string host = params.Get("host", "127.0.0.1");
int port = params.Get("port", 26760);
int pad_index = params.Get("pad_index", 0);
client = std::make_shared<Client>(status, host, port, pad_index);
return std::make_unique<UDPTouchDevice>(status);
}
private:
std::shared_ptr<DeviceStatus> status;
std::shared_ptr<Client> client;
};
class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> {
public:
explicit UDPMotionFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
explicit UDPMotionFactory() {}
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
return std::make_unique<UDPMotionDevice>(status);
std::string host = params.Get("host", "127.0.0.1");
int port = params.Get("port", 26760);
int pad_index = params.Get("pad_index", 0);
float cx = params.Get("cx", 0);
float cy = params.Get("cy", 0);
float cz = params.Get("cz", 0);
Common::Vec3f offset(cx, cy, cz);
float sensitivity = params.Get("sensitivity", 1);
return std::make_unique<UDPMotionDevice>(host, port, pad_index, offset, sensitivity);
}
private:
std::shared_ptr<DeviceStatus> status;
};
State::State() {
auto status = std::make_shared<DeviceStatus>();
client =
std::make_unique<Client>(status, Settings::values.udp_input_address,
Settings::values.udp_input_port, Settings::values.udp_pad_index);
Input::RegisterFactory<Input::TouchDevice>("cemuhookudp",
std::make_shared<UDPTouchFactory>(status));
Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", std::make_shared<UDPTouchFactory>());
Input::RegisterFactory<Input::MotionDevice>("cemuhookudp",
std::make_shared<UDPMotionFactory>(status));
std::make_shared<UDPMotionFactory>());
}
State::~State() {
@@ -88,11 +104,6 @@ State::~State() {
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
}
void State::ReloadUDPClient() {
client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
Settings::values.udp_pad_index);
}
std::unique_ptr<State> Init() {
return std::make_unique<State>();
}

View File

@@ -14,7 +14,6 @@ class State {
public:
State();
~State();
void ReloadUDPClient();
private:
std::unique_ptr<Client> client;

View File

@@ -293,6 +293,27 @@ void Config::ReadPlayerValues() {
player_analogs = default_param;
}
}
for (int i = 0; i < 2; ++i) {
const std::string default_param =
InputCommon::GenerateMotionParam("127.0.0.1", 26760, 0, 0, 0, 0, 1);
auto& player_motion = player.motion_devices[i];
player_motion.device =
qt_config
->value(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i),
QString::fromStdString(default_param))
.toString()
.toStdString();
player_motion.enabled =
qt_config
->value(QStringLiteral("player_%1_motion_device%2/enabled").arg(p).arg(i),
false)
.toBool();
if (player_motion.device.empty()) {
player_motion.device = default_param;
}
}
}
std::stable_partition(
@@ -845,6 +866,16 @@ void Config::SavePlayerValues() {
QString::fromStdString(player.analogs[i]),
QString::fromStdString(default_param));
}
for (int i = 0; i < 2; ++i) {
const std::string default_param =
InputCommon::GenerateMotionParam("127.0.0.1", 26760, 0, 0, 0, 0, 1);
WriteSetting(QStringLiteral("player_%1_motion_device%2").arg(p).arg(i),
QString::fromStdString(player.motion_devices[i].device),
QString::fromStdString(default_param));
WriteSetting(QStringLiteral("player_%1_motion_device%2/enabled").arg(p).arg(i),
player.motion_devices[i].enabled);
}
}
}

View File

@@ -10,9 +10,13 @@
#include <QKeyEvent>
#include <QMenu>
#include <QMessageBox>
#include <QProgressBar>
#include <QProgressDialog>
#include <QThread>
#include <QTimer>
#include "common/assert.h"
#include "common/param_package.h"
#include "core/frontend/input.h"
#include "input_common/main.h"
#include "ui_configure_input_player.h"
#include "yuzu/configuration/config.h"
@@ -176,8 +180,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
if (debug)
layout = Settings::ControllerType::DualJoycon;
ui->firstMotionDeviceInner->hide();
ui->secondMotionDeviceInner->hide();
switch (layout) {
case Settings::ControllerType::ProController:
ui->secondMotionDevice_2->hide(); // frame
case Settings::ControllerType::DualJoycon:
layout_hidden = {
ui->buttonSL,
@@ -187,6 +195,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
};
break;
case Settings::ControllerType::LeftJoycon:
ui->secondMotionDevice_2->hide(); // frame
layout_hidden = {
ui->right_body_button,
ui->right_buttons_button,
@@ -205,6 +214,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
};
break;
case Settings::ControllerType::RightJoycon:
ui->secondMotionDevice_2->hide(); // frame
layout_hidden = {
ui->left_body_button, ui->left_buttons_button,
ui->left_body_label, ui->left_buttons_label,
@@ -217,6 +227,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
break;
}
if (layout == Settings::ControllerType::DualJoycon) {
ui->firstMotionEnabled->setText(tr("Left"));
}
if (debug || layout == Settings::ControllerType::ProController) {
ui->controller_color->hide();
} else {
@@ -234,6 +248,59 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
for (auto* widget : layout_hidden)
widget->setVisible(false);
motion_groups[0] = {
ui->motionAddress1, ui->motionPort1,
ui->motionPadIndex1, ui->gyroXoff1,
ui->gyroYoff1, ui->gyroZoff1,
ui->gyroSensitivity1, ui->calibrate1,
ui->firstMotionEnabled, ui->firstMotionDeviceInner,
};
motion_groups[1] = {
ui->motionAddress2, ui->motionPort2,
ui->motionPadIndex2, ui->gyroXoff2,
ui->gyroYoff2, ui->gyroZoff2,
ui->gyroSensitivity2, ui->calibrate2,
ui->secondMotionEnabled, ui->secondMotionDeviceInner,
};
for (const auto& group : motion_groups) {
connect(group.calibrateButton, &QPushButton::clicked, [=] {
if (QMessageBox::information(this, tr("Gyro calibration"),
tr("Put your controller flat, then press OK to continue."),
QMessageBox::Ok, QMessageBox::Cancel) == QMessageBox::Ok) {
QProgressDialog* progress = new QProgressDialog(this);
QProgressBar* bar = new QProgressBar(progress);
bar->setRange(0, 0);
bar->setValue(0);
progress->setWindowTitle(tr("Gyro calibration"));
progress->setLabelText(tr("Please wait..."));
progress->setBar(bar);
progress->setCancelButton(nullptr);
progress->show();
// Get 100 samples and set boxes
std::string address = group.address->text().toStdString();
// offsets are applied before scaling
std::string param = InputCommon::GenerateMotionParam(
address, group.port->value(), group.padIndex->value(), 0, 0, 0, 1);
std::unique_ptr<Input::MotionDevice> device =
Input::CreateDevice<Input::MotionDevice>(param);
Common::Vec3f acc;
for (int i = 0; i < 100; i++) {
Common::Vec3f gyro, accel;
std::tie(gyro, accel) = device->GetStatus();
acc += gyro;
QApplication::processEvents();
QThread::msleep(16);
}
acc /= 100;
progress->close();
group.cx->setValue(acc.x);
group.cy->setValue(acc.y);
group.cz->setValue(acc.z);
}
});
}
analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
analog_map_deadzone_and_modifier_slider = {ui->sliderLStickDeadzoneAndModifier,
ui->sliderRStickDeadzoneAndModifier};
@@ -387,11 +454,27 @@ void ConfigureInputPlayer::ApplyConfiguration() {
debug ? Settings::values.debug_pad_buttons : Settings::values.players[player_index].buttons;
auto& analogs =
debug ? Settings::values.debug_pad_analogs : Settings::values.players[player_index].analogs;
auto& motion = Settings::values.players[player_index].motion_devices;
// convert motion group into params
for (int i = 0; i < 2; ++i) {
auto& group = motion_groups[i];
motion_param[i] =
MotionParam{group.enabled->isChecked(),
Common::ParamPackage(InputCommon::GenerateMotionParam(
group.address->text().toStdString(), group.port->value(),
group.padIndex->value(), group.cx->value(), group.cy->value(),
group.cz->value(), group.sensitivity->value()))};
}
std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
std::transform(motion_param.begin(), motion_param.end(), motion.begin(),
[](const MotionParam& param) {
return Settings::MotionRaw{param.enabled, param.param.Serialize()};
});
if (debug)
return;
@@ -444,6 +527,11 @@ void ConfigureInputPlayer::LoadConfiguration() {
Settings::values.players[player_index].analogs.end(), analogs_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
}
std::transform(Settings::values.players[player_index].motion_devices.begin(),
Settings::values.players[player_index].motion_devices.end(),
motion_param.begin(), [](const Settings::MotionRaw& raw) {
return MotionParam{raw.enabled, Common::ParamPackage(raw.device)};
});
UpdateButtonLabels();
@@ -480,6 +568,17 @@ void ConfigureInputPlayer::RestoreDefaults() {
SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
}
}
for (const auto& group : motion_groups) {
group.address->setText(tr("127.0.0.1"));
group.port->setValue(26760);
group.padIndex->setValue(0);
group.cx->setValue(0);
group.cy->setValue(0);
group.cz->setValue(0);
group.enabled->setChecked(false);
group.inner->hide();
}
UpdateButtonLabels();
}
@@ -553,6 +652,21 @@ void ConfigureInputPlayer::UpdateButtonLabels() {
}
}
}
for (int motion_id = 0; motion_id < 2; motion_id++) {
auto& param = motion_param[motion_id];
auto& group = motion_groups[motion_id];
group.address->setText(QString::fromStdString(param.param.Get("address", "127.0.0.1")));
group.port->setValue(param.param.Get("port", 26760));
group.padIndex->setValue(param.param.Get("pad_index", 0));
group.cx->setValue(param.param.Get("cx", 0.0f));
group.cy->setValue(param.param.Get("cy", 0.0f));
group.cz->setValue(param.param.Get("cz", 0.0f));
group.sensitivity->setValue(param.param.Get("sensitivity", 1.0f));
group.enabled->setChecked(param.enabled);
group.inner->setVisible(param.enabled);
}
}
void ConfigureInputPlayer::HandleClick(

View File

@@ -17,6 +17,9 @@
#include "ui_configure_input.h"
class QKeyEvent;
class QLineEdit;
class QSpinBox;
class QDoubleSpinBox;
class QPushButton;
class QString;
class QTimer;
@@ -78,8 +81,14 @@ private:
/// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
struct MotionParam {
bool enabled;
Common::ParamPackage param;
};
std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
std::array<MotionParam, 2> motion_param;
static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
@@ -102,6 +111,21 @@ private:
std::array<QLabel*, Settings::NativeAnalog::NumAnalogs>
analog_map_deadzone_and_modifier_slider_label;
/// Motion inputs are represented with 6 fields, used to configure calibration and connection
struct MotionGroup {
QLineEdit* address;
QSpinBox* port;
QSpinBox* padIndex;
QDoubleSpinBox* cx;
QDoubleSpinBox* cy;
QDoubleSpinBox* cz;
QDoubleSpinBox* sensitivity;
QPushButton* calibrateButton;
QCheckBox* enabled;
QFrame* inner;
};
std::array<MotionGroup, 2> motion_groups;
static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;

File diff suppressed because it is too large Load Diff