mirror of https://github.com/PCSX2/pcsx2.git
Qt: Add per-bind sensitivity/deadzone controls (shift-click)
This commit is contained in:
parent
88487de72f
commit
31ebe842e8
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "QtHost.h"
|
#include "QtHost.h"
|
||||||
#include "QtUtils.h"
|
#include "QtUtils.h"
|
||||||
|
#include "Settings/ControllerSettingWidgetBinder.h"
|
||||||
#include "Settings/InputBindingDialog.h"
|
#include "Settings/InputBindingDialog.h"
|
||||||
#include "Settings/InputBindingWidget.h"
|
#include "Settings/InputBindingWidget.h"
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
|
@ -24,6 +25,8 @@
|
||||||
#include <QtGui/QMouseEvent>
|
#include <QtGui/QMouseEvent>
|
||||||
#include <QtGui/QWheelEvent>
|
#include <QtGui/QWheelEvent>
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
// _BitScanForward()
|
// _BitScanForward()
|
||||||
#include "pcsx2/GS/GSIntrin.h"
|
#include "pcsx2/GS/GSIntrin.h"
|
||||||
|
|
||||||
|
@ -45,6 +48,26 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
|
||||||
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
|
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
|
||||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
|
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
|
||||||
updateList();
|
updateList();
|
||||||
|
|
||||||
|
// Only show the sensitivity controls for binds where it's applicable.
|
||||||
|
if (bind_type == InputBindingInfo::Type::Button || bind_type == InputBindingInfo::Type::Axis ||
|
||||||
|
bind_type == InputBindingInfo::Type::HalfAxis)
|
||||||
|
{
|
||||||
|
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||||
|
sif, m_ui.sensitivity, m_section_name, fmt::format("{}Scale", m_key_name), 100.0f, 1.0f);
|
||||||
|
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||||
|
sif, m_ui.deadzone, m_section_name, fmt::format("{}Deadzone", m_key_name), 100.0f, 0.0f);
|
||||||
|
|
||||||
|
connect(m_ui.sensitivity, &QSlider::valueChanged, this, &InputBindingDialog::onSensitivityChanged);
|
||||||
|
connect(m_ui.deadzone, &QSlider::valueChanged, this, &InputBindingDialog::onDeadzoneChanged);
|
||||||
|
|
||||||
|
onSensitivityChanged(m_ui.sensitivity->value());
|
||||||
|
onDeadzoneChanged(m_ui.deadzone->value());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui.verticalLayout->removeWidget(m_ui.sensitivityWidget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputBindingDialog::~InputBindingDialog()
|
InputBindingDialog::~InputBindingDialog()
|
||||||
|
@ -318,6 +341,16 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputBindingDialog::onSensitivityChanged(int value)
|
||||||
|
{
|
||||||
|
m_ui.sensitivityValue->setText(tr("%1%").arg(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputBindingDialog::onDeadzoneChanged(int value)
|
||||||
|
{
|
||||||
|
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
|
||||||
|
}
|
||||||
|
|
||||||
void InputBindingDialog::hookInputManager()
|
void InputBindingDialog::hookInputManager()
|
||||||
{
|
{
|
||||||
InputManager::SetHook([this](InputBindingKey key, float value) {
|
InputManager::SetHook([this](InputBindingKey key, float value) {
|
||||||
|
|
|
@ -41,6 +41,9 @@ protected Q_SLOTS:
|
||||||
void onInputListenTimerTimeout();
|
void onInputListenTimerTimeout();
|
||||||
void inputManagerHookCallback(InputBindingKey key, float value);
|
void inputManagerHookCallback(InputBindingKey key, float value);
|
||||||
|
|
||||||
|
void onSensitivityChanged(int value);
|
||||||
|
void onDeadzoneChanged(int value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>533</width>
|
<width>533</width>
|
||||||
<height>283</height>
|
<height>266</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -30,6 +30,93 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListWidget" name="bindingList"/>
|
<widget class="QListWidget" name="bindingList"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="sensitivityWidget" native="true">
|
||||||
|
<layout class="QGridLayout" name="sensitivityLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="sensitivityLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sensitivity:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSlider" name="sensitivity">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>200</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TicksBelow</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="sensitivityValue">
|
||||||
|
<property name="text">
|
||||||
|
<string>100%</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="deadzoneLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Deadzone:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSlider" name="deadzone">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TicksBelow</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickInterval">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLabel" name="deadzoneValue">
|
||||||
|
<property name="text">
|
||||||
|
<string>100%</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="status">
|
<widget class="QLabel" name="status">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -105,6 +105,7 @@ namespace InputManager
|
||||||
static bool ParseBindingAndGetSource(const std::string_view& binding, InputBindingKey* key, InputSource** source);
|
static bool ParseBindingAndGetSource(const std::string_view& binding, InputBindingKey* key, InputSource** source);
|
||||||
|
|
||||||
static bool IsAxisHandler(const InputEventHandler& handler);
|
static bool IsAxisHandler(const InputEventHandler& handler);
|
||||||
|
static float ApplySingleBindingScale(float sensitivity, float deadzone, float value);
|
||||||
|
|
||||||
static void AddHotkeyBindings(SettingsInterface& si);
|
static void AddHotkeyBindings(SettingsInterface& si);
|
||||||
static void AddPadBindings(SettingsInterface& si, u32 pad, const char* default_type);
|
static void AddPadBindings(SettingsInterface& si, u32 pad, const char* default_type);
|
||||||
|
@ -585,6 +586,12 @@ std::string InputManager::GetPointerDeviceName(u32 pointer_index)
|
||||||
// Binding Enumeration
|
// Binding Enumeration
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
float InputManager::ApplySingleBindingScale(float scale, float deadzone, float value)
|
||||||
|
{
|
||||||
|
const float svalue = std::clamp(value * scale, 0.0f, 1.0f);
|
||||||
|
return (deadzone > 0.0f && svalue < deadzone) ? 0.0f : svalue;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<const HotkeyInfo*> InputManager::GetHotkeyList()
|
std::vector<const HotkeyInfo*> InputManager::GetHotkeyList()
|
||||||
{
|
{
|
||||||
std::vector<const HotkeyInfo*> ret;
|
std::vector<const HotkeyInfo*> ret;
|
||||||
|
@ -613,7 +620,7 @@ void InputManager::AddHotkeyBindings(SettingsInterface& si)
|
||||||
|
|
||||||
void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const char* default_type)
|
void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const char* default_type)
|
||||||
{
|
{
|
||||||
const std::string section(StringUtil::StdStringFromFormat("Pad%u", pad_index + 1));
|
const std::string section(fmt::format("Pad{}", pad_index + 1));
|
||||||
const std::string type(si.GetStringValue(section.c_str(), "Type", default_type));
|
const std::string type(si.GetStringValue(section.c_str(), "Type", default_type));
|
||||||
if (type.empty() || type == "None")
|
if (type.empty() || type == "None")
|
||||||
return;
|
return;
|
||||||
|
@ -636,8 +643,11 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
|
||||||
if (!bindings.empty())
|
if (!bindings.empty())
|
||||||
{
|
{
|
||||||
// we use axes for all pad bindings to simplify things, and because they are pressure sensitive
|
// we use axes for all pad bindings to simplify things, and because they are pressure sensitive
|
||||||
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index](float value) {
|
const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f);
|
||||||
PAD::SetControllerState(pad_index, bind_index, value);
|
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
|
||||||
|
AddBindings(
|
||||||
|
bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](float value) {
|
||||||
|
PAD::SetControllerState(pad_index, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -717,8 +727,11 @@ void InputManager::AddUSBBindings(SettingsInterface& si, u32 port)
|
||||||
const std::vector<std::string> bindings(si.GetStringList(section.c_str(), bind_name.c_str()));
|
const std::vector<std::string> bindings(si.GetStringList(section.c_str(), bind_name.c_str()));
|
||||||
if (!bindings.empty())
|
if (!bindings.empty())
|
||||||
{
|
{
|
||||||
AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index](
|
const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f);
|
||||||
float value) { USB::SetDeviceBindValue(port, bind_index, value); }});
|
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
|
||||||
|
AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](float value) {
|
||||||
|
USB::SetDeviceBindValue(port, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -504,7 +504,12 @@ void PAD::ClearPortBindings(SettingsInterface& si, u32 port)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (u32 i = 0; i < info->num_bindings; i++)
|
for (u32 i = 0; i < info->num_bindings; i++)
|
||||||
si.DeleteValue(section.c_str(), info->bindings[i].name);
|
{
|
||||||
|
const InputBindingInfo& bi = info->bindings[i];
|
||||||
|
si.DeleteValue(section.c_str(), bi.name);
|
||||||
|
si.DeleteValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str());
|
||||||
|
si.DeleteValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PAD::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si,
|
void PAD::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si,
|
||||||
|
@ -545,6 +550,8 @@ void PAD::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface&
|
||||||
{
|
{
|
||||||
const InputBindingInfo& bi = info->bindings[i];
|
const InputBindingInfo& bi = info->bindings[i];
|
||||||
dest_si->CopyStringListValue(src_si, section.c_str(), bi.name);
|
dest_si->CopyStringListValue(src_si, section.c_str(), bi.name);
|
||||||
|
dest_si->CopyFloatValue(src_si, section.c_str(), fmt::format("{}Sensitivity", bi.name).c_str());
|
||||||
|
dest_si->CopyFloatValue(src_si, section.c_str(), fmt::format("{}Deadzone", bi.name).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < NUM_MACRO_BUTTONS_PER_CONTROLLER; i++)
|
for (u32 i = 0; i < NUM_MACRO_BUTTONS_PER_CONTROLLER; i++)
|
||||||
|
@ -601,8 +608,8 @@ void PAD::CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface&
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& section,
|
static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& section,
|
||||||
const InputManager::GenericInputBindingMapping& mapping, GenericInputBinding generic_name,
|
const InputManager::GenericInputBindingMapping& mapping, InputBindingInfo::Type bind_type,
|
||||||
const char* bind_name)
|
GenericInputBinding generic_name, const char* bind_name)
|
||||||
{
|
{
|
||||||
// find the mapping it corresponds to
|
// find the mapping it corresponds to
|
||||||
const std::string* found_mapping = nullptr;
|
const std::string* found_mapping = nullptr;
|
||||||
|
@ -615,6 +622,14 @@ static u32 TryMapGenericMapping(SettingsInterface& si, const std::string& sectio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove previously-set binding scales.
|
||||||
|
if (bind_type == InputBindingInfo::Type::Button || bind_type == InputBindingInfo::Type::Axis ||
|
||||||
|
bind_type == InputBindingInfo::Type::HalfAxis)
|
||||||
|
{
|
||||||
|
si.DeleteValue(section.c_str(), fmt::format("{}Scale", bind_name).c_str());
|
||||||
|
si.DeleteValue(section.c_str(), fmt::format("{}Deadzone", bind_name).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (found_mapping)
|
if (found_mapping)
|
||||||
{
|
{
|
||||||
Console.WriteLn("(MapController) Map %s/%s to '%s'", section.c_str(), bind_name, found_mapping->c_str());
|
Console.WriteLn("(MapController) Map %s/%s to '%s'", section.c_str(), bind_name, found_mapping->c_str());
|
||||||
|
@ -645,17 +660,17 @@ bool PAD::MapController(SettingsInterface& si, u32 controller,
|
||||||
if (bi.generic_mapping == GenericInputBinding::Unknown)
|
if (bi.generic_mapping == GenericInputBinding::Unknown)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
num_mappings += TryMapGenericMapping(si, section, mapping, bi.generic_mapping, bi.name);
|
num_mappings += TryMapGenericMapping(si, section, mapping, bi.bind_type, bi.generic_mapping, bi.name);
|
||||||
}
|
}
|
||||||
if (info->vibration_caps == VibrationCapabilities::LargeSmallMotors)
|
if (info->vibration_caps == VibrationCapabilities::LargeSmallMotors)
|
||||||
{
|
{
|
||||||
num_mappings += TryMapGenericMapping(si, section, mapping, GenericInputBinding::SmallMotor, "SmallMotor");
|
num_mappings += TryMapGenericMapping(si, section, mapping, InputBindingInfo::Type::Motor, GenericInputBinding::SmallMotor, "SmallMotor");
|
||||||
num_mappings += TryMapGenericMapping(si, section, mapping, GenericInputBinding::LargeMotor, "LargeMotor");
|
num_mappings += TryMapGenericMapping(si, section, mapping, InputBindingInfo::Type::Motor, GenericInputBinding::LargeMotor, "LargeMotor");
|
||||||
}
|
}
|
||||||
else if (info->vibration_caps == VibrationCapabilities::SingleMotor)
|
else if (info->vibration_caps == VibrationCapabilities::SingleMotor)
|
||||||
{
|
{
|
||||||
if (TryMapGenericMapping(si, section, mapping, GenericInputBinding::LargeMotor, "Motor") == 0)
|
if (TryMapGenericMapping(si, section, mapping, InputBindingInfo::Type::Motor, GenericInputBinding::LargeMotor, "Motor") == 0)
|
||||||
num_mappings += TryMapGenericMapping(si, section, mapping, GenericInputBinding::SmallMotor, "Motor");
|
num_mappings += TryMapGenericMapping(si, section, mapping, InputBindingInfo::Type::Motor, GenericInputBinding::SmallMotor, "Motor");
|
||||||
else
|
else
|
||||||
num_mappings++;
|
num_mappings++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue