From 6a6195f53c0a369782599b56cdbcc803bcb4203e Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 29 Dec 2018 13:56:35 -0600 Subject: [PATCH] ControllerEmu: Implement dead zone setting for triggers. --- .../Config/Mapping/MappingIndicator.cpp | 34 +++++++++---- .../ControlGroup/MixedTriggers.cpp | 51 +++++++++++++++---- .../ControlGroup/MixedTriggers.h | 11 +++- 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp index 4e58bf169d..18ed99fb58 100644 --- a/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp +++ b/Source/Core/DolphinQt/Config/Mapping/MappingIndicator.cpp @@ -37,6 +37,8 @@ static const QColor TEXT_COLOR = Qt::darkGray; // Text color that is visible atop ADJ_INPUT_COLOR: static const QColor TEXT_ALT_COLOR = Qt::white; +constexpr int INPUT_DOT_RADIUS = 2; + MappingIndicator::MappingIndicator(ControllerEmu::ControlGroup* group) : m_group(group) { setMinimumHeight(128); @@ -181,8 +183,6 @@ void MappingIndicator::DrawStick() // Bounding box size: const double scale = height() / 2.5; - const float dot_radius = 2; - QPainter p(this); p.translate(width() / 2, height() / 2); @@ -219,14 +219,14 @@ void MappingIndicator::DrawStick() // Raw stick position. p.setPen(Qt::NoPen); p.setBrush(RAW_INPUT_COLOR); - p.drawEllipse(QPointF{raw_coord.x, raw_coord.y} * scale, dot_radius, dot_radius); + p.drawEllipse(QPointF{raw_coord.x, raw_coord.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); // Adjusted stick position. if (adj_coord.x || adj_coord.y) { p.setPen(Qt::NoPen); p.setBrush(ADJ_INPUT_COLOR); - p.drawEllipse(QPointF{adj_coord.x, adj_coord.y} * scale, dot_radius, dot_radius); + p.drawEllipse(QPointF{adj_coord.x, adj_coord.y} * scale, INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); } } @@ -236,16 +236,19 @@ void MappingIndicator::DrawMixedTriggers() p.setRenderHint(QPainter::TextAntialiasing, true); auto& triggers = *static_cast(m_group); - const ControlState threshold = triggers.numeric_settings[0]->GetValue(); + const ControlState threshold = triggers.GetThreshold(); + const ControlState deadzone = triggers.GetDeadzone(); // MixedTriggers interface is a bit ugly: constexpr int TRIGGER_COUNT = 2; - std::array analog_state; + std::array raw_analog_state; + std::array adj_analog_state; const std::array button_masks = {0x1, 0x2}; u16 button_state = 0; Settings::Instance().SetControllerStateNeeded(true); - triggers.GetState(&button_state, button_masks.data(), analog_state.data()); + triggers.GetState(&button_state, button_masks.data(), raw_analog_state.data(), false); + triggers.GetState(&button_state, button_masks.data(), adj_analog_state.data(), true); Settings::Instance().SetControllerStateNeeded(false); // Rectangle sizes: @@ -261,7 +264,8 @@ void MappingIndicator::DrawMixedTriggers() for (int t = 0; t != TRIGGER_COUNT; ++t) { - const double trigger_analog = analog_state[t]; + const double raw_analog = raw_analog_state[t]; + const double adj_analog = adj_analog_state[t]; const bool trigger_button = button_state & button_masks[t]; auto const analog_name = QString::fromStdString(triggers.controls[TRIGGER_COUNT + t]->ui_name); auto const button_name = QString::fromStdString(triggers.controls[t]->ui_name); @@ -274,12 +278,20 @@ void MappingIndicator::DrawMixedTriggers() p.setPen(TEXT_COLOR); p.drawText(analog_rect, Qt::AlignCenter, analog_name); - const QRectF activated_analog_rect(0, 0, trigger_analog * trigger_analog_width, trigger_height); + const QRectF adj_analog_rect(0, 0, adj_analog * trigger_analog_width, trigger_height); // Trigger analog: p.setPen(Qt::NoPen); + p.setBrush(RAW_INPUT_COLOR); + p.drawEllipse(QPoint(raw_analog * trigger_analog_width, trigger_height - INPUT_DOT_RADIUS), + INPUT_DOT_RADIUS, INPUT_DOT_RADIUS); p.setBrush(ADJ_INPUT_COLOR); - p.drawRect(activated_analog_rect); + p.drawRect(adj_analog_rect); + + // Deadzone: + p.setPen(DEADZONE_COLOR); + p.setBrush(DEADZONE_BRUSH); + p.drawRect(0, 0, trigger_analog_width * deadzone, trigger_height); // Threshold setting: const int threshold_x = trigger_analog_width * threshold; @@ -306,7 +318,7 @@ void MappingIndicator::DrawMixedTriggers() // Activated analog text: p.setPen(TEXT_ALT_COLOR); p.setClipping(true); - p.setClipRect(activated_analog_rect); + p.setClipRect(adj_analog_rect); p.drawText(analog_rect, Qt::AlignCenter, analog_name); p.setClipping(false); diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp index 8f26fde6fc..4928127604 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp @@ -4,6 +4,7 @@ #include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h" +#include #include #include #include @@ -21,23 +22,53 @@ MixedTriggers::MixedTriggers(const std::string& name_) : ControlGroup(name_, GroupType::MixedTriggers) { numeric_settings.emplace_back(std::make_unique(_trans("Threshold"), 0.9)); + numeric_settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0.0, 0, 25)); } -void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlState* analog) +void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlState* analog, + bool adjusted) { - const size_t trigger_count = controls.size() / 2; + const ControlState threshold = numeric_settings[SETTING_THRESHOLD]->GetValue(); + ControlState deadzone = numeric_settings[SETTING_DEADZONE]->GetValue(); - for (size_t i = 0; i < trigger_count; ++i, ++bitmasks, ++analog) + // Return raw values. (used in UI) + if (!adjusted) { - if (controls[i]->control_ref->State() > numeric_settings[0]->GetValue()) // threshold + deadzone = 0.0; + } + + const int trigger_count = int(controls.size() / 2); + for (int i = 0; i != trigger_count; ++i) + { + ControlState button_value = controls[i]->control_ref->State(); + ControlState analog_value = controls[trigger_count + i]->control_ref->State(); + + // Apply deadzone: + analog_value = std::max(0.0, analog_value - deadzone) / (1.0 - deadzone); + button_value = std::max(0.0, button_value - deadzone) / (1.0 - deadzone); + + // Apply threshold: + if (button_value > threshold) { - *analog = 1.0; - *digital |= *bitmasks; - } - else - { - *analog = controls[i + trigger_count]->control_ref->State(); + // Fully activate analog: + analog_value = 1.0; + + // Activate button: + *digital |= bitmasks[i]; } + + analog[i] = analog_value; } } + +ControlState MixedTriggers::GetDeadzone() const +{ + return numeric_settings[SETTING_DEADZONE]->GetValue(); +} + +ControlState MixedTriggers::GetThreshold() const +{ + return numeric_settings[SETTING_THRESHOLD]->GetValue(); +} + } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h index cf85ffdc52..1733394223 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h @@ -13,8 +13,17 @@ namespace ControllerEmu class MixedTriggers : public ControlGroup { public: + enum + { + SETTING_THRESHOLD, + SETTING_DEADZONE, + }; + explicit MixedTriggers(const std::string& name); - void GetState(u16* digital, const u16* bitmasks, ControlState* analog); + void GetState(u16* digital, const u16* bitmasks, ControlState* analog, bool adjusted = true); + + ControlState GetDeadzone() const; + ControlState GetThreshold() const; }; } // namespace ControllerEmu