mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-29 09:05:41 +00:00
Qt: Add per-bind sensitivity/deadzone controls (shift-click)
This commit is contained in:
parent
039796690c
commit
619688a135
|
@ -388,7 +388,7 @@ void ControllerBindingWidget::createBindingWidgets(QWidget* parent)
|
||||||
scrollarea->setWidget(scrollarea_widget);
|
scrollarea->setWidget(scrollarea_widget);
|
||||||
scrollarea->setWidgetResizable(true);
|
scrollarea->setWidgetResizable(true);
|
||||||
scrollarea->setFrameShape(QFrame::StyledPanel);
|
scrollarea->setFrameShape(QFrame::StyledPanel);
|
||||||
scrollarea->setFrameShadow(QFrame::Plain);
|
scrollarea->setFrameShadow(QFrame::Sunken);
|
||||||
|
|
||||||
// We do axes and buttons separately, so we can figure out how many columns to use.
|
// We do axes and buttons separately, so we can figure out how many columns to use.
|
||||||
constexpr int NUM_AXIS_COLUMNS = 2;
|
constexpr int NUM_AXIS_COLUMNS = 2;
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#include "inputbindingdialog.h"
|
#include "inputbindingdialog.h"
|
||||||
#include "common/bitutils.h"
|
#include "controllersettingwidgetbinder.h"
|
||||||
#include "inputbindingwidgets.h"
|
#include "inputbindingwidgets.h"
|
||||||
#include "qthost.h"
|
#include "qthost.h"
|
||||||
#include "qtutils.h"
|
#include "qtutils.h"
|
||||||
|
|
||||||
|
#include "common/bitutils.h"
|
||||||
|
|
||||||
#include <QtCore/QTimer>
|
#include <QtCore/QTimer>
|
||||||
#include <QtGui/QKeyEvent>
|
#include <QtGui/QKeyEvent>
|
||||||
#include <QtGui/QMouseEvent>
|
#include <QtGui/QMouseEvent>
|
||||||
|
@ -27,6 +30,28 @@ 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.resetSensitivity, &QToolButton::clicked, this, &InputBindingDialog::onResetSensitivityClicked);
|
||||||
|
connect(m_ui.deadzone, &QSlider::valueChanged, this, &InputBindingDialog::onDeadzoneChanged);
|
||||||
|
connect(m_ui.resetDeadzone, &QToolButton::clicked, this, &InputBindingDialog::onResetDeadzoneClicked);
|
||||||
|
|
||||||
|
onSensitivityChanged(m_ui.sensitivity->value());
|
||||||
|
onDeadzoneChanged(m_ui.deadzone->value());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ui.verticalLayout->removeWidget(m_ui.sensitivityWidget);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputBindingDialog::~InputBindingDialog()
|
InputBindingDialog::~InputBindingDialog()
|
||||||
|
@ -302,6 +327,56 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputBindingDialog::onSensitivityChanged(int value)
|
||||||
|
{
|
||||||
|
m_ui.sensitivityValue->setText(tr("%1%").arg(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputBindingDialog::onResetDeadzoneClicked()
|
||||||
|
{
|
||||||
|
m_ui.deadzone->setValue(0);
|
||||||
|
|
||||||
|
// May as well remove from the config completely, since it's the default.
|
||||||
|
const TinyString key = TinyString::from_format("{}Deadzone", m_key_name);
|
||||||
|
if (m_sif)
|
||||||
|
{
|
||||||
|
m_sif->DeleteValue(m_section_name.c_str(), key);
|
||||||
|
QtHost::SaveGameSettings(m_sif, false);
|
||||||
|
g_emu_thread->reloadGameSettings(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Host::DeleteBaseSettingValue(m_section_name.c_str(), key);
|
||||||
|
Host::CommitBaseSettingChanges();
|
||||||
|
g_emu_thread->applySettings(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputBindingDialog::onDeadzoneChanged(int value)
|
||||||
|
{
|
||||||
|
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputBindingDialog::onResetSensitivityClicked()
|
||||||
|
{
|
||||||
|
m_ui.sensitivity->setValue(100);
|
||||||
|
|
||||||
|
// May as well remove from the config completely, since it's the default.
|
||||||
|
const TinyString key = TinyString::from_format("{}Scale", m_key_name);
|
||||||
|
if (m_sif)
|
||||||
|
{
|
||||||
|
m_sif->DeleteValue(m_section_name.c_str(), key);
|
||||||
|
QtHost::SaveGameSettings(m_sif, false);
|
||||||
|
g_emu_thread->reloadGameSettings(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Host::DeleteBaseSettingValue(m_section_name.c_str(), key);
|
||||||
|
Host::CommitBaseSettingChanges();
|
||||||
|
g_emu_thread->applySettings(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void InputBindingDialog::hookInputManager()
|
void InputBindingDialog::hookInputManager()
|
||||||
{
|
{
|
||||||
InputManager::SetHook([this](InputBindingKey key, float value) {
|
InputManager::SetHook([this](InputBindingKey key, float value) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "util/input_manager.h"
|
|
||||||
#include "ui_inputbindingdialog.h"
|
#include "ui_inputbindingdialog.h"
|
||||||
|
#include "util/input_manager.h"
|
||||||
#include <QtWidgets/QDialog>
|
#include <QtWidgets/QDialog>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -48,6 +48,11 @@ protected:
|
||||||
void hookInputManager();
|
void hookInputManager();
|
||||||
void unhookInputManager();
|
void unhookInputManager();
|
||||||
|
|
||||||
|
void onSensitivityChanged(int value);
|
||||||
|
void onResetDeadzoneClicked();
|
||||||
|
void onDeadzoneChanged(int value);
|
||||||
|
void onResetSensitivityClicked();
|
||||||
|
|
||||||
Ui::InputBindingDialog m_ui;
|
Ui::InputBindingDialog m_ui;
|
||||||
|
|
||||||
SettingsInterface* m_sif;
|
SettingsInterface* m_sif;
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
<class>InputBindingDialog</class>
|
<class>InputBindingDialog</class>
|
||||||
<widget class="QDialog" name="InputBindingDialog">
|
<widget class="QDialog" name="InputBindingDialog">
|
||||||
<property name="windowModality">
|
<property name="windowModality">
|
||||||
<enum>Qt::WindowModal</enum>
|
<enum>Qt::WindowModality::WindowModal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<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,113 @@
|
||||||
<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="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::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TickPosition::TicksBelow</enum>
|
||||||
|
</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::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickPosition">
|
||||||
|
<enum>QSlider::TickPosition::TicksBelow</enum>
|
||||||
|
</property>
|
||||||
|
<property name="tickInterval">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="sensitivityLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sensitivity:</string>
|
||||||
|
</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="2">
|
||||||
|
<widget class="QLabel" name="deadzoneValue">
|
||||||
|
<property name="text">
|
||||||
|
<string>100%</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QToolButton" name="resetSensitivity">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reset Volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="refresh-line"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QToolButton" name="resetDeadzone">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reset Fast Forward Volume</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset theme="refresh-line"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="status">
|
<widget class="QLabel" name="status">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -63,7 +170,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="standardButtons">
|
<property name="standardButtons">
|
||||||
<set>QDialogButtonBox::Close</set>
|
<set>QDialogButtonBox::StandardButton::Close</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -109,6 +109,7 @@ static void PrettifyInputBindingPart(std::string_view binding, SmallString& ret,
|
||||||
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler);
|
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler);
|
||||||
|
|
||||||
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, const std::string& section, u32 pad,
|
static void AddPadBindings(SettingsInterface& si, const std::string& section, u32 pad,
|
||||||
|
@ -777,6 +778,12 @@ std::optional<InputBindingKey> InputManager::ParseSensorKey(std::string_view sou
|
||||||
// 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;
|
||||||
|
@ -818,13 +825,18 @@ void InputManager::AddPadBindings(SettingsInterface& si, const std::string& sect
|
||||||
{
|
{
|
||||||
if (!bindings.empty())
|
if (!bindings.empty())
|
||||||
{
|
{
|
||||||
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index](float value) {
|
const float sensitivity =
|
||||||
|
si.GetFloatValue(section.c_str(), TinyString::from_format("{}Scale", bi.name), 1.0f);
|
||||||
|
const float deadzone =
|
||||||
|
si.GetFloatValue(section.c_str(), TinyString::from_format("{}Deadzone", bi.name), 0.0f);
|
||||||
|
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity,
|
||||||
|
deadzone](float value) {
|
||||||
if (!System::IsValid())
|
if (!System::IsValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Controller* c = System::GetController(pad_index);
|
Controller* c = System::GetController(pad_index);
|
||||||
if (c)
|
if (c)
|
||||||
c->SetBindState(bind_index, value);
|
c->SetBindState(bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue