Controller: Add multiplier/format to settings

This commit is contained in:
Connor McLaughlin 2022-08-10 13:03:15 +10:00
parent ae0d60fcd8
commit 5ac9c3f022
7 changed files with 70 additions and 53 deletions

View File

@ -1,4 +1,5 @@
#include "analog_controller.h" #include "analog_controller.h"
#include "IconsFontAwesome5.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "host.h" #include "host.h"
@ -10,8 +11,9 @@ Log_SetChannel(AnalogController);
AnalogController::AnalogController(u32 index) : Controller(index) AnalogController::AnalogController(u32 index) : Controller(index)
{ {
m_status_byte = 0x5A;
m_axis_state.fill(0x80); m_axis_state.fill(0x80);
Reset(); m_rumble_config.fill(0xFF);
} }
AnalogController::~AnalogController() = default; AnalogController::~AnalogController() = default;
@ -45,14 +47,16 @@ void AnalogController::Reset()
{ {
if (g_settings.controller_disable_analog_mode_forcing) if (g_settings.controller_disable_analog_mode_forcing)
{ {
Host::AddKeyedOSDMessage( Host::AddIconOSDMessage(
"analog_controller_mode_ignored", fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
Host::TranslateStdString( Host::TranslateStdString(
"OSDMessage", "Analog mode forcing is disabled by game settings. Controller will start in digital mode."), "OSDMessage", "Analog mode forcing is disabled by game settings. Controller will start in digital mode."),
10.0f); 10.0f);
} }
else else
SetAnalogMode(true); {
SetAnalogMode(true, false);
}
} }
} }
@ -94,11 +98,14 @@ bool AnalogController::DoState(StateWrapper& sw, bool apply_input_state)
if (old_analog_mode != m_analog_mode) if (old_analog_mode != m_analog_mode)
{ {
Host::AddFormattedOSDMessage( Host::AddIconOSDMessage(
5.0f, fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
m_analog_mode ? Host::TranslateString("AnalogController", "Controller %u switched to analog mode.") : fmt::format((m_analog_mode ?
Host::TranslateString("AnalogController", "Controller %u switched to digital mode."), Host::TranslateString("AnalogController", "Controller {} switched to analog mode.") :
m_index + 1u); Host::TranslateString("AnalogController", "Controller {} switched to digital mode."))
.GetCharArray(),
m_index + 1u),
5.0f);
} }
} }
return true; return true;
@ -230,17 +237,22 @@ void AnalogController::ResetTransferState()
m_command_step = 0; m_command_step = 0;
} }
void AnalogController::SetAnalogMode(bool enabled) void AnalogController::SetAnalogMode(bool enabled, bool show_message)
{ {
if (m_analog_mode == enabled) if (m_analog_mode == enabled)
return; return;
Log_InfoPrintf("Controller %u switched to %s mode.", m_index + 1u, enabled ? "analog" : "digital"); Log_InfoPrintf("Controller %u switched to %s mode.", m_index + 1u, enabled ? "analog" : "digital");
Host::AddFormattedOSDMessage(5.0f, if (show_message)
enabled ? {
Host::TranslateString("AnalogController", "Controller %u switched to analog mode.") : Host::AddIconOSDMessage(
Host::TranslateString("AnalogController", "Controller %u switched to digital mode."), fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
m_index + 1u); fmt::format((enabled ? Host::TranslateString("AnalogController", "Controller {} switched to analog mode.") :
Host::TranslateString("AnalogController", "Controller {} switched to digital mode."))
.GetCharArray(),
m_index + 1u),
5.0f);
}
m_analog_mode = enabled; m_analog_mode = enabled;
} }
@ -248,15 +260,18 @@ void AnalogController::ProcessAnalogModeToggle()
{ {
if (m_analog_locked) if (m_analog_locked)
{ {
Host::AddFormattedOSDMessage( Host::AddIconOSDMessage(
5.0f, fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
m_analog_mode ? Host::TranslateString("AnalogController", "Controller %u is locked to analog mode by the game.") : fmt::format((m_analog_mode ?
Host::TranslateString("AnalogController", "Controller %u is locked to digital mode by the game."), Host::TranslateString("AnalogController", "Controller %u is locked to analog mode by the game.") :
m_index + 1u); Host::TranslateString("AnalogController", "Controller %u is locked to digital mode by the game."))
.GetCharArray(),
m_index + 1u),
5.0f);
} }
else else
{ {
SetAnalogMode(!m_analog_mode); SetAnalogMode(!m_analog_mode, true);
ResetRumbleConfig(); ResetRumbleConfig();
if (m_dualshock_enabled) if (m_dualshock_enabled)
@ -604,7 +619,7 @@ bool AnalogController::Transfer(const u8 data_in, u8* data_out)
Log_DevPrintf("analog mode val 0x%02x", data_in); Log_DevPrintf("analog mode val 0x%02x", data_in);
if (data_in == 0x00 || data_in == 0x01) if (data_in == 0x00 || data_in == 0x01)
SetAnalogMode((data_in == 0x01)); SetAnalogMode((data_in == 0x01), true);
} }
else if (m_command_step == 3) else if (m_command_step == 3)
{ {
@ -777,17 +792,17 @@ static const SettingInfo s_settings[] = {
{SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogController", "Analog Deadzone"), {SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogController", "Analog Deadzone"),
TRANSLATABLE("AnalogController", TRANSLATABLE("AnalogController",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."), "Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"0.00f", "0.00f", "1.00f", "0.01f"}, "0.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", 100.0f},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogController", "Analog Sensitivity"), {SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogController", "Analog Sensitivity"),
TRANSLATABLE( TRANSLATABLE(
"AnalogController", "AnalogController",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent " "Sets the analog stick axis scaling factor. A value between 130% and 140% is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."), "controllers, e.g. DualShock 4, Xbox One Controller."),
"1.33f", "0.01f", "2.00f", "0.01f"}, "1.33f", "0.01f", "2.00f", "0.01f", "%.0f%%", 100.0f},
{SettingInfo::Type::Integer, "VibrationBias", TRANSLATABLE("AnalogController", "Vibration Bias"), {SettingInfo::Type::Integer, "VibrationBias", TRANSLATABLE("AnalogController", "Vibration Bias"),
TRANSLATABLE("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not " TRANSLATABLE("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not "
"functioning, try increasing this value."), "functioning, try increasing this value."),
"8", "0", "255", "1"}}; "8", "0", "255", "1", "%d", 1.0f}};
const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController, const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController,
"AnalogController", "AnalogController",

View File

@ -108,7 +108,7 @@ private:
u8 GetModeID() const; u8 GetModeID() const;
u8 GetIDByte() const; u8 GetIDByte() const;
void SetAnalogMode(bool enabled); void SetAnalogMode(bool enabled, bool show_message);
void ProcessAnalogModeToggle(); void ProcessAnalogModeToggle();
void SetMotorState(u32 motor, u8 value); void SetMotorState(u32 motor, u8 value);
void UpdateHostVibration(); void UpdateHostVibration();
@ -140,7 +140,7 @@ private:
int m_rumble_config_small_motor_index = -1; int m_rumble_config_small_motor_index = -1;
bool m_analog_toggle_queued = false; bool m_analog_toggle_queued = false;
u8 m_status_byte = 0x5A; u8 m_status_byte = 0;
// TODO: Set this with command 0x4D and increase response length in digital mode accordingly // TODO: Set this with command 0x4D and increase response length in digital mode accordingly
u8 m_digital_mode_extra_halfwords = 0; u8 m_digital_mode_extra_halfwords = 0;

View File

@ -328,13 +328,13 @@ static const SettingInfo s_settings[] = {
{SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogJoystick", "Analog Deadzone"), {SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATABLE("AnalogJoystick", "Analog Deadzone"),
TRANSLATABLE("AnalogJoystick", TRANSLATABLE("AnalogJoystick",
"Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."), "Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
"1.00f", "0.00f", "1.00f", "0.01f"}, "1.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", 100.0f},
{SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogJoystick", "Analog Sensitivity"), {SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATABLE("AnalogJoystick", "Analog Sensitivity"),
TRANSLATABLE( TRANSLATABLE(
"AnalogJoystick", "AnalogJoystick",
"Sets the analog stick axis scaling factor. A value between 1.30 and 1.40 is recommended when using recent " "Sets the analog stick axis scaling factor. A value between 130% and 140% is recommended when using recent "
"controllers, e.g. DualShock 4, Xbox One Controller."), "controllers, e.g. DualShock 4, Xbox One Controller."),
"1.33f", "0.01f", "2.00f", "0.01f"}}; "1.33f", "0.01f", "2.00f", "0.01f", "%.0f%%", 100.0f}};
const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick, const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick,
"AnalogJoystick", "AnalogJoystick",

View File

@ -220,10 +220,10 @@ static const SettingInfo s_settings[] = {
{SettingInfo::Type::Path, "CrosshairImagePath", TRANSLATABLE("GunCon", "Crosshair Image Path"), {SettingInfo::Type::Path, "CrosshairImagePath", TRANSLATABLE("GunCon", "Crosshair Image Path"),
TRANSLATABLE("GunCon", "Path to an image to use as a crosshair/cursor.")}, TRANSLATABLE("GunCon", "Path to an image to use as a crosshair/cursor.")},
{SettingInfo::Type::Float, "CrosshairScale", TRANSLATABLE("GunCon", "Crosshair Image Scale"), {SettingInfo::Type::Float, "CrosshairScale", TRANSLATABLE("GunCon", "Crosshair Image Scale"),
TRANSLATABLE("GunCon", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10"}, TRANSLATABLE("GunCon", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10", "%.0f%%", 100.0f},
{SettingInfo::Type::Float, "XScale", TRANSLATABLE("GunCon", "X Scale"), {SettingInfo::Type::Float, "XScale", TRANSLATABLE("GunCon", "X Scale"),
TRANSLATABLE("GunCon", "Scales X coordinates relative to the center of the screen."), "1.0", "0.01", "2.0", TRANSLATABLE("GunCon", "Scales X coordinates relative to the center of the screen."), "1.0", "0.01", "2.0",
"0.01"}}; "0.01", "%.0f%%", 100.0f}};
const Controller::ControllerInfo GunCon::INFO = {ControllerType::GunCon, const Controller::ControllerInfo GunCon::INFO = {ControllerType::GunCon,
"GunCon", "GunCon",

View File

@ -251,7 +251,7 @@ static const Controller::ControllerBindingInfo s_binding_info[] = {
static const SettingInfo s_settings[] = { static const SettingInfo s_settings[] = {
{SettingInfo::Type::Float, "SteeringDeadzone", TRANSLATABLE("NeGcon", "Steering Axis Deadzone"), {SettingInfo::Type::Float, "SteeringDeadzone", TRANSLATABLE("NeGcon", "Steering Axis Deadzone"),
TRANSLATABLE("NeGcon", "Sets deadzone size for steering axis."), "0.00f", "0.00f", "0.99f", "0.01f"}}; TRANSLATABLE("NeGcon", "Sets deadzone size for steering axis."), "0.00f", "0.00f", "0.99f", "0.01f", "%.0f%%", 100.0f}};
const Controller::ControllerInfo NeGcon::INFO = {ControllerType::NeGcon, const Controller::ControllerInfo NeGcon::INFO = {ControllerType::NeGcon,
"NeGcon", "NeGcon",

View File

@ -21,13 +21,15 @@ struct SettingInfo
}; };
Type type; Type type;
const char* key; const char* name;
const char* visible_name; const char* display_name;
const char* description; const char* description;
const char* default_value; const char* default_value;
const char* min_value; const char* min_value;
const char* max_value; const char* max_value;
const char* step_value; const char* step_value;
const char* format;
float multiplier;
const char* StringDefaultValue() const; const char* StringDefaultValue() const;
bool BooleanDefaultValue() const; bool BooleanDefaultValue() const;

View File

@ -521,14 +521,14 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
for (u32 i = 0; i < cinfo->num_settings; i++) for (u32 i = 0; i < cinfo->num_settings; i++)
{ {
const SettingInfo& si = cinfo->settings[i]; const SettingInfo& si = cinfo->settings[i];
std::string key_name = si.key; std::string key_name = si.name;
switch (si.type) switch (si.type)
{ {
case SettingInfo::Type::Boolean: case SettingInfo::Type::Boolean:
{ {
QCheckBox* cb = new QCheckBox(qApp->translate(cinfo->name, si.visible_name), this); QCheckBox* cb = new QCheckBox(qApp->translate(cinfo->name, si.display_name), this);
cb->setObjectName(QString::fromUtf8(si.key)); cb->setObjectName(QString::fromUtf8(si.name));
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, cb, section, std::move(key_name), ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, cb, section, std::move(key_name),
si.BooleanDefaultValue()); si.BooleanDefaultValue());
layout->addWidget(cb, current_row, 0, 1, 4); layout->addWidget(cb, current_row, 0, 1, 4);
@ -539,12 +539,12 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
case SettingInfo::Type::Integer: case SettingInfo::Type::Integer:
{ {
QSpinBox* sb = new QSpinBox(this); QSpinBox* sb = new QSpinBox(this);
sb->setObjectName(QString::fromUtf8(si.key)); sb->setObjectName(QString::fromUtf8(si.name));
sb->setMinimum(si.IntegerMinValue()); sb->setMinimum(si.IntegerMinValue());
sb->setMaximum(si.IntegerMaxValue()); sb->setMaximum(si.IntegerMaxValue());
sb->setSingleStep(si.IntegerStepValue()); sb->setSingleStep(si.IntegerStepValue());
SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, section, std::move(key_name), si.IntegerDefaultValue()); SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, section, std::move(key_name), si.IntegerDefaultValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), this), current_row, 0); layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), this), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3); layout->addWidget(sb, current_row, 1, 1, 3);
current_row++; current_row++;
} }
@ -553,12 +553,12 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
case SettingInfo::Type::Float: case SettingInfo::Type::Float:
{ {
QDoubleSpinBox* sb = new QDoubleSpinBox(this); QDoubleSpinBox* sb = new QDoubleSpinBox(this);
sb->setObjectName(QString::fromUtf8(si.key)); sb->setObjectName(QString::fromUtf8(si.name));
sb->setMinimum(si.FloatMinValue()); sb->setMinimum(si.FloatMinValue());
sb->setMaximum(si.FloatMaxValue()); sb->setMaximum(si.FloatMaxValue());
sb->setSingleStep(si.FloatStepValue()); sb->setSingleStep(si.FloatStepValue());
SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, section, std::move(key_name), si.FloatDefaultValue()); SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, section, std::move(key_name), si.FloatDefaultValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), this), current_row, 0); layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), this), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3); layout->addWidget(sb, current_row, 1, 1, 3);
current_row++; current_row++;
} }
@ -567,9 +567,9 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
case SettingInfo::Type::String: case SettingInfo::Type::String:
{ {
QLineEdit* le = new QLineEdit(this); QLineEdit* le = new QLineEdit(this);
le->setObjectName(QString::fromUtf8(si.key)); le->setObjectName(QString::fromUtf8(si.name));
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue()); SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), this), current_row, 0); layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), this), current_row, 0);
layout->addWidget(le, current_row, 1, 1, 3); layout->addWidget(le, current_row, 1, 1, 3);
current_row++; current_row++;
} }
@ -578,7 +578,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
case SettingInfo::Type::Path: case SettingInfo::Type::Path:
{ {
QLineEdit* le = new QLineEdit(this); QLineEdit* le = new QLineEdit(this);
le->setObjectName(QString::fromUtf8(si.key)); le->setObjectName(QString::fromUtf8(si.name));
QPushButton* browse_button = new QPushButton(tr("Browse..."), this); QPushButton* browse_button = new QPushButton(tr("Browse..."), this);
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue()); SettingWidgetBinder::BindWidgetToStringSetting(sif, le, section, std::move(key_name), si.StringDefaultValue());
connect(browse_button, &QPushButton::clicked, [this, le]() { connect(browse_button, &QPushButton::clicked, [this, le]() {
@ -591,7 +591,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
hbox->addWidget(le, 1); hbox->addWidget(le, 1);
hbox->addWidget(browse_button); hbox->addWidget(browse_button);
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.visible_name), this), current_row, 0); layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), this), current_row, 0);
layout->addLayout(hbox, current_row, 1, 1, 3); layout->addLayout(hbox, current_row, 1, 1, 3);
current_row++; current_row++;
} }
@ -615,13 +615,13 @@ void ControllerCustomSettingsWidget::restoreDefaults()
for (u32 i = 0; i < cinfo->num_settings; i++) for (u32 i = 0; i < cinfo->num_settings; i++)
{ {
const SettingInfo& si = cinfo->settings[i]; const SettingInfo& si = cinfo->settings[i];
const QString key(QString::fromStdString(si.key)); const QString key(QString::fromStdString(si.name));
switch (si.type) switch (si.type)
{ {
case SettingInfo::Type::Boolean: case SettingInfo::Type::Boolean:
{ {
QCheckBox* widget = findChild<QCheckBox*>(QString::fromStdString(si.key)); QCheckBox* widget = findChild<QCheckBox*>(QString::fromStdString(si.name));
if (widget) if (widget)
widget->setChecked(si.BooleanDefaultValue()); widget->setChecked(si.BooleanDefaultValue());
} }
@ -629,7 +629,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
case SettingInfo::Type::Integer: case SettingInfo::Type::Integer:
{ {
QSpinBox* widget = findChild<QSpinBox*>(QString::fromStdString(si.key)); QSpinBox* widget = findChild<QSpinBox*>(QString::fromStdString(si.name));
if (widget) if (widget)
widget->setValue(si.IntegerDefaultValue()); widget->setValue(si.IntegerDefaultValue());
} }
@ -637,7 +637,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
case SettingInfo::Type::Float: case SettingInfo::Type::Float:
{ {
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.key)); QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name));
if (widget) if (widget)
widget->setValue(si.FloatDefaultValue()); widget->setValue(si.FloatDefaultValue());
} }
@ -645,7 +645,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
case SettingInfo::Type::String: case SettingInfo::Type::String:
{ {
QLineEdit* widget = findChild<QLineEdit*>(QString::fromStdString(si.key)); QLineEdit* widget = findChild<QLineEdit*>(QString::fromStdString(si.name));
if (widget) if (widget)
widget->setText(QString::fromUtf8(si.StringDefaultValue())); widget->setText(QString::fromUtf8(si.StringDefaultValue()));
} }
@ -653,7 +653,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
case SettingInfo::Type::Path: case SettingInfo::Type::Path:
{ {
QLineEdit* widget = findChild<QLineEdit*>(QString::fromStdString(si.key)); QLineEdit* widget = findChild<QLineEdit*>(QString::fromStdString(si.name));
if (widget) if (widget)
widget->setText(QString::fromUtf8(si.StringDefaultValue())); widget->setText(QString::fromUtf8(si.StringDefaultValue()));
} }