Controller: Add invert and button deadzone options

This commit is contained in:
Connor McLaughlin 2022-09-22 13:50:31 +10:00
parent 1a6bc86136
commit 736996ab38
12 changed files with 299 additions and 232 deletions

View file

@ -136,7 +136,7 @@ void AnalogController::SetBindState(u32 index, float value)
if (index == static_cast<s32>(Button::Analog)) if (index == static_cast<s32>(Button::Analog))
{ {
// analog toggle // analog toggle
if (value >= 0.5f) if (value >= m_button_deadzone)
{ {
if (m_command == Command::Idle) if (m_command == Command::Idle)
ProcessAnalogModeToggle(); ProcessAnalogModeToggle();
@ -168,22 +168,30 @@ void AnalogController::SetBindState(u32 index, float value)
{ {
case HalfAxis::LLeft: case HalfAxis::LLeft:
case HalfAxis::LRight: case HalfAxis::LRight:
m_axis_state[static_cast<u8>(Axis::LeftX)] = MERGE(HalfAxis::LRight, HalfAxis::LLeft); m_axis_state[static_cast<u8>(Axis::LeftX)] = ((m_invert_left_stick & 1u) != 0u) ?
MERGE(HalfAxis::LLeft, HalfAxis::LRight) :
MERGE(HalfAxis::LRight, HalfAxis::LLeft);
break; break;
case HalfAxis::LDown: case HalfAxis::LDown:
case HalfAxis::LUp: case HalfAxis::LUp:
m_axis_state[static_cast<u8>(Axis::LeftY)] = MERGE(HalfAxis::LDown, HalfAxis::LUp); m_axis_state[static_cast<u8>(Axis::LeftY)] = ((m_invert_left_stick & 2u) != 0u) ?
MERGE(HalfAxis::LUp, HalfAxis::LDown) :
MERGE(HalfAxis::LDown, HalfAxis::LUp);
break; break;
case HalfAxis::RLeft: case HalfAxis::RLeft:
case HalfAxis::RRight: case HalfAxis::RRight:
m_axis_state[static_cast<u8>(Axis::RightX)] = MERGE(HalfAxis::RRight, HalfAxis::RLeft); m_axis_state[static_cast<u8>(Axis::RightX)] = ((m_invert_right_stick & 1u) != 0u) ?
MERGE(HalfAxis::RLeft, HalfAxis::RRight) :
MERGE(HalfAxis::RRight, HalfAxis::RLeft);
break; break;
case HalfAxis::RDown: case HalfAxis::RDown:
case HalfAxis::RUp: case HalfAxis::RUp:
m_axis_state[static_cast<u8>(Axis::RightY)] = MERGE(HalfAxis::RDown, HalfAxis::RUp); m_axis_state[static_cast<u8>(Axis::RightY)] = ((m_invert_right_stick & 2u) != 0u) ?
MERGE(HalfAxis::RUp, HalfAxis::RDown) :
MERGE(HalfAxis::RDown, HalfAxis::RUp);
break; break;
default: default:
@ -197,7 +205,7 @@ void AnalogController::SetBindState(u32 index, float value)
const u16 bit = u16(1) << static_cast<u8>(index); const u16 bit = u16(1) << static_cast<u8>(index);
if (value >= 0.5f) if (value >= m_button_deadzone)
{ {
if (m_button_state & bit) if (m_button_state & bit)
System::SetRunaheadReplayFlag(); System::SetRunaheadReplayFlag();
@ -779,6 +787,11 @@ static const Controller::ControllerBindingInfo s_binding_info[] = {
#undef BUTTON #undef BUTTON
}; };
static const char* s_invert_settings[] = {TRANSLATABLE("AnalogController", "Not Inverted"),
TRANSLATABLE("AnalogController", "Invert Left/Right"),
TRANSLATABLE("AnalogController", "Invert Up/Down"),
TRANSLATABLE("AnalogController", "Invert Left/Right + Up/Down"), nullptr};
static const SettingInfo s_settings[] = { static const SettingInfo s_settings[] = {
{SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"), {SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May " TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May "
@ -792,17 +805,26 @@ 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", "%.0f%%", 100.0f}, "0.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", nullptr, 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 130% and 140% 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", "%.0f%%", 100.0f}, "1.33f", "0.01f", "2.00f", "0.01f", "%.0f%%", nullptr, 100.0f},
{SettingInfo::Type::Float, "ButtonDeadzone", "Button/Trigger Deadzone",
"Sets the deadzone for activating buttons/triggers, i.e. the fraction of the trigger which will be ignored.", "0.25",
"0.00", "1.00", "0.01", "%.0f%%", nullptr, 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", "%d", 1.0f}}; "8", "0", "255", "1", "%d", nullptr, 1.0f},
{SettingInfo::Type::IntegerList, "InvertLeftStick", "Invert Left Stick",
"Inverts the direction of the left analog stick.", "0", "0", "3", nullptr, nullptr, s_invert_settings, 0.0f},
{SettingInfo::Type::IntegerList, "InvertRightStick", "Invert Right Stick",
"Inverts the direction of the right analog stick.", "0", "0", "3", nullptr, nullptr, s_invert_settings, 0.0f},
};
const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController, const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController,
"AnalogController", "AnalogController",
@ -821,5 +843,8 @@ void AnalogController::LoadSettings(SettingsInterface& si, const char* section)
m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f); m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
m_analog_sensitivity = m_analog_sensitivity =
std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f); std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
m_button_deadzone = std::clamp(si.GetFloatValue(section, "ButtonDeadzone", DEFAULT_BUTTON_DEADZONE), 0.0f, 1.0f);
m_rumble_bias = static_cast<u8>(std::min<u32>(si.GetIntValue(section, "VibrationBias", 8), 255)); m_rumble_bias = static_cast<u8>(std::min<u32>(si.GetIntValue(section, "VibrationBias", 8), 255));
m_invert_left_stick = static_cast<u8>(si.GetIntValue(section, "InvertLeftStick", 0));
m_invert_right_stick = static_cast<u8>(si.GetIntValue(section, "InvertRightStick", 0));
} }

View file

@ -121,7 +121,10 @@ private:
bool m_analog_dpad_in_digital_mode = false; bool m_analog_dpad_in_digital_mode = false;
float m_analog_deadzone = 0.0f; float m_analog_deadzone = 0.0f;
float m_analog_sensitivity = 1.33f; float m_analog_sensitivity = 1.33f;
float m_button_deadzone = 0.0f;
u8 m_rumble_bias = 8; u8 m_rumble_bias = 8;
u8 m_invert_left_stick = 0;
u8 m_invert_right_stick = 0;
bool m_analog_mode = false; bool m_analog_mode = false;
bool m_analog_locked = false; bool m_analog_locked = false;

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", "%.0f%%", 100.0f}, "1.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", nullptr, 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 130% and 140% 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", "%.0f%%", 100.0f}}; "1.33f", "0.01f", "2.00f", "0.01f", "%.0f%%", nullptr, 100.0f}};
const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick, const Controller::ControllerInfo AnalogJoystick::INFO = {ControllerType::AnalogJoystick,
"AnalogJoystick", "AnalogJoystick",

View file

@ -60,6 +60,7 @@ public:
/// Default stick deadzone/sensitivity. /// Default stick deadzone/sensitivity.
static constexpr float DEFAULT_STICK_DEADZONE = 0.0f; static constexpr float DEFAULT_STICK_DEADZONE = 0.0f;
static constexpr float DEFAULT_STICK_SENSITIVITY = 1.33f; static constexpr float DEFAULT_STICK_SENSITIVITY = 1.33f;
static constexpr float DEFAULT_BUTTON_DEADZONE = 0.25f;
Controller(u32 index); Controller(u32 index);
virtual ~Controller(); virtual ~Controller();

View file

@ -220,10 +220,11 @@ 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", "%.0f%%", 100.0f}, TRANSLATABLE("GunCon", "Scale of crosshair image on screen."), "1.0", "0.0001", "100.0", "0.10", "%.0f%%", nullptr,
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}}; "%.0f%%", nullptr, 100.0f}};
const Controller::ControllerInfo GunCon::INFO = {ControllerType::GunCon, const Controller::ControllerInfo GunCon::INFO = {ControllerType::GunCon,
"GunCon", "GunCon",

View file

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

View file

@ -17,6 +17,7 @@ struct SettingInfo
{ {
Boolean, Boolean,
Integer, Integer,
IntegerList,
Float, Float,
String, String,
Path, Path,
@ -31,6 +32,7 @@ struct SettingInfo
const char* max_value; const char* max_value;
const char* step_value; const char* step_value;
const char* format; const char* format;
const char** options;
float multiplier; float multiplier;
const char* StringDefaultValue() const; const char* StringDefaultValue() const;

View file

@ -554,6 +554,20 @@ void ControllerCustomSettingsWidget::createSettingWidgets(ControllerBindingWidge
} }
break; break;
case SettingInfo::Type::IntegerList:
{
QComboBox* cb = new QComboBox(this);
cb->setObjectName(QString::fromUtf8(si.name));
for (u32 j = 0; si.options[j] != nullptr; j++)
cb->addItem(qApp->translate(cinfo->name, si.options[j]));
SettingWidgetBinder::BindWidgetToIntSetting(sif, cb, section, std::move(key_name), si.IntegerDefaultValue(),
si.IntegerMinValue());
layout->addWidget(new QLabel(qApp->translate(cinfo->name, si.display_name), this), current_row, 0);
layout->addWidget(cb, current_row, 1, 1, 3);
current_row++;
}
break;
case SettingInfo::Type::Float: case SettingInfo::Type::Float:
{ {
QDoubleSpinBox* sb = new QDoubleSpinBox(this); QDoubleSpinBox* sb = new QDoubleSpinBox(this);
@ -639,6 +653,14 @@ void ControllerCustomSettingsWidget::restoreDefaults()
} }
break; break;
case SettingInfo::Type::IntegerList:
{
QComboBox* widget = findChild<QComboBox*>(QString::fromStdString(si.name));
if (widget)
widget->setCurrentIndex(si.IntegerDefaultValue() - si.IntegerMinValue());
}
break;
case SettingInfo::Type::Float: case SettingInfo::Type::Float:
{ {
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name)); QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name));

View file

@ -27,10 +27,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode", SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.multitapMode, "ControllerPorts", "MultitapMode",
&Settings::ParseMultitapModeName, &Settings::GetMultitapModeName, &Settings::ParseMultitapModeName, &Settings::GetMultitapModeName,
Settings::DEFAULT_MULTITAP_MODE); Settings::DEFAULT_MULTITAP_MODE);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerXInvert, "ControllerPorts",
"PointerXInvert", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerYInvert, "ControllerPorts",
"PointerYInvert", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "ControllerPorts", ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "ControllerPorts",
"PointerXScale", 8.0f); "PointerXScale", 8.0f);
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "ControllerPorts", ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "ControllerPorts",

View file

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>902</width> <width>902</width>
<height>677</height> <height>673</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -26,6 +26,57 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item row="2" column="0">
<widget class="QGroupBox" name="dinputGroup">
<property name="title">
<string>DInput Source</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>The DInput source provides support for legacy controllers which do not support XInput. Accessing these controllers via SDL instead is recommended.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enableDInputSource">
<property name="text">
<string>Enable DInput Input Source</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1" rowspan="7">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Detected Devices</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QListWidget" name="deviceList">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QGroupBox" name="groupBox_4"> <widget class="QGroupBox" name="groupBox_4">
<property name="title"> <property name="title">
@ -76,32 +127,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QGroupBox" name="dinputGroup">
<property name="title">
<string>DInput Source</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>The DInput source provides support for legacy controllers which do not support XInput. Accessing these controllers via SDL instead is recommended.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enableDInputSource">
<property name="text">
<string>Enable DInput Input Source</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QGroupBox" name="sdlGroup"> <widget class="QGroupBox" name="sdlGroup">
<property name="title"> <property name="title">
@ -135,180 +160,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="0" column="1" rowspan="7">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Detected Devices</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QListWidget" name="deviceList">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Mouse/Pointer Source</string>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="2">
<widget class="QLabel" name="pointerXScaleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>10</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="pointerXScale">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QCheckBox" name="pointerYInvert">
<property name="text">
<string>Invert</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSlider" name="pointerYScale">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="pointerYScaleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>10</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QCheckBox" name="pointerXInvert">
<property name="text">
<string>Invert</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Using raw input improves precision when you bind controller sticks to the mouse pointer. Also enables multiple mice to be used.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Vertical Sensitivity:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Horizontal Sensitivity:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="enableMouseMapping">
<property name="text">
<string>Enable Mouse Mapping</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2">
<widget class="QCheckBox" name="enableRawInput">
<property name="text">
<string>Use Raw Input</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QGroupBox" name="xinputGroup"> <widget class="QGroupBox" name="xinputGroup">
<property name="title"> <property name="title">
@ -361,6 +212,153 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>Mouse/Pointer Source</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Using raw input improves precision when you bind controller sticks to the mouse pointer. Also enables multiple mice to be used.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Horizontal Sensitivity:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSlider" name="pointerXScale">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="pointerXScaleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>10</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Vertical Sensitivity:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSlider" name="pointerYScale">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="pointerYScaleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>10</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="enableMouseMapping">
<property name="text">
<string>Enable Mouse Mapping</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enableRawInput">
<property name="text">
<string>Use Raw Input</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="6" column="0"> <item row="6" column="0">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">

View file

@ -3018,6 +3018,10 @@ void FullscreenUI::DrawControllerSettingsPage()
DrawIntRangeSetting(bsi, title, si.description, section.c_str(), si.name, si.IntegerDefaultValue(), DrawIntRangeSetting(bsi, title, si.description, section.c_str(), si.name, si.IntegerDefaultValue(),
si.IntegerMinValue(), si.IntegerMaxValue(), si.format, true); si.IntegerMinValue(), si.IntegerMaxValue(), si.format, true);
break; break;
case SettingInfo::Type::IntegerList:
DrawIntListSetting(bsi, title, si.description, section.c_str(), si.name, si.IntegerDefaultValue(),
si.options, 0, si.IntegerMinValue(), true);
break;
case SettingInfo::Type::Float: case SettingInfo::Type::Float:
DrawFloatRangeSetting(bsi, title, si.description, section.c_str(), si.name, si.FloatDefaultValue(), DrawFloatRangeSetting(bsi, title, si.description, section.c_str(), si.name, si.FloatDefaultValue(),
si.FloatMinValue(), si.FloatMaxValue(), si.format, si.multiplier, true); si.FloatMinValue(), si.FloatMaxValue(), si.format, si.multiplier, true);

View file

@ -962,12 +962,28 @@ void InputManager::CopyConfiguration(SettingsInterface* dest_si, const SettingsI
if (copy_pad_config) if (copy_pad_config)
{ {
dest_si->CopyFloatValue(src_si, section.c_str(), "AxisScale"); for (u32 i = 0; i < info->num_settings; i++)
if (info->vibration_caps != Controller::VibrationCapabilities::NoVibration)
{ {
dest_si->CopyFloatValue(src_si, section.c_str(), "LargeMotorScale"); const SettingInfo& csi = info->settings[i];
dest_si->CopyFloatValue(src_si, section.c_str(), "SmallMotorScale"); switch (csi.type)
{
case SettingInfo::Type::Boolean:
dest_si->CopyBoolValue(src_si, section.c_str(), csi.name);
break;
case SettingInfo::Type::Integer:
case SettingInfo::Type::IntegerList:
dest_si->CopyIntValue(src_si, section.c_str(), csi.name);
break;
case SettingInfo::Type::Float:
dest_si->CopyFloatValue(src_si, section.c_str(), csi.name);
break;
case SettingInfo::Type::String:
case SettingInfo::Type::Path:
dest_si->CopyStringValue(src_si, section.c_str(), csi.name);
break;
default:
break;
}
} }
} }
} }
@ -1350,10 +1366,8 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
{ {
// From lilypad: 1 mouse pixel = 1/8th way down. // From lilypad: 1 mouse pixel = 1/8th way down.
const float default_scale = (axis <= static_cast<u32>(InputPointerAxis::Y)) ? 8.0f : 1.0f; const float default_scale = (axis <= static_cast<u32>(InputPointerAxis::Y)) ? 8.0f : 1.0f;
const float invert =
si.GetBoolValue("Pad", fmt::format("Pointer{}Invert", s_pointer_axis_names[axis]).c_str(), false) ? -1.0f : 1.0f;
s_pointer_axis_scale[axis] = s_pointer_axis_scale[axis] =
invert / std::max(si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(), 1.0f / std::max(si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(),
default_scale), default_scale),
1.0f); 1.0f);
} }