diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index d87199458c..1be1a2436c 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,10 @@ PadSettingCheckBox::PadSettingCheckBox(wxWindow* const parent, void PadSettingCheckBox::UpdateGUI() { ((wxCheckBox*)wxcontrol)->SetValue(setting->GetValue()); + // Force WX to trigger an event after updating the value + wxCommandEvent event(wxEVT_CHECKBOX); + event.SetEventObject(wxcontrol); + wxPostEvent(wxcontrol, event); } void PadSettingCheckBox::UpdateValue() @@ -162,8 +167,10 @@ ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config, ControlButton::ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref, - const unsigned int width, const std::string& label) - : wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxSize(width, 20)), control_reference(_ref) + const std::string& name, const unsigned int width, + const std::string& label) + : wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxSize(width, 20)), control_reference(_ref), + m_name(name) { if (label.empty()) SetLabel(StrToWxStr(_ref->expression)); @@ -457,15 +464,68 @@ void ControlDialog::AppendControl(wxCommandEvent& event) UpdateGUI(); } -void GamepadPage::AdjustSetting(wxCommandEvent& event) +void GamepadPage::EnablePadSetting(const std::string& group_name, const std::string& name, + const bool enabled) { - ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); + const auto box_iterator = + std::find_if(control_groups.begin(), control_groups.end(), [&group_name](const auto& box) { + return group_name == box->control_group->name; + }); + if (box_iterator == control_groups.end()) + return; + + const auto* box = *box_iterator; + const auto it = + std::find_if(box->options.begin(), box->options.end(), [&name](const auto& pad_setting) { + return pad_setting->wxcontrol->GetLabelText() == name; + }); + if (it == box->options.end()) + return; + (*it)->wxcontrol->Enable(enabled); } -void GamepadPage::AdjustSettingUI(wxCommandEvent& event) +void GamepadPage::EnableControlButton(const std::string& group_name, const std::string& name, + const bool enabled) { - m_iterate = !m_iterate; - ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); + const auto box_iterator = + std::find_if(control_groups.begin(), control_groups.end(), [&group_name](const auto& box) { + return group_name == box->control_group->name; + }); + if (box_iterator == control_groups.end()) + return; + + const auto* box = *box_iterator; + const auto it = + std::find_if(box->control_buttons.begin(), box->control_buttons.end(), + [&name](const auto& control_button) { return control_button->m_name == name; }); + if (it == box->control_buttons.end()) + return; + (*it)->Enable(enabled); +} + +void GamepadPage::AdjustSetting(wxCommandEvent& event) +{ + const auto* const control = static_cast(event.GetEventObject()); + auto* const pad_setting = static_cast(control->GetClientData()); + pad_setting->UpdateValue(); +} + +void GamepadPage::AdjustBooleanSetting(wxCommandEvent& event) +{ + const auto* const control = static_cast(event.GetEventObject()); + auto* const pad_setting = static_cast(control->GetClientData()); + pad_setting->UpdateValue(); + + // TODO: find a cleaner way to have actions depending on the setting + if (control->GetLabelText() == "Iterative Input") + { + m_iterate = pad_setting->setting->GetValue(); + } + else if (control->GetLabelText() == "Relative Input") + { + EnablePadSetting("IR", "Dead Zone", pad_setting->setting->GetValue()); + EnableControlButton("IR", "Recenter", pad_setting->setting->GetValue()); + } } void GamepadPage::AdjustControlOption(wxCommandEvent&) @@ -766,6 +826,8 @@ void GamepadPage::RefreshDevices(wxCommandEvent&) Pad::LoadConfig(); HotkeyManagerEmu::LoadConfig(); + UpdateGUI(); + Core::PauseAndLock(false, was_unpaused); } @@ -790,7 +852,8 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin wxStaticText* const label = new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(control->name))); - ControlButton* const control_button = new ControlButton(parent, control->control_ref.get(), 80); + ControlButton* const control_button = + new ControlButton(parent, control->control_ref.get(), control->name, 80); control_button->SetFont(m_SmallFont); control_buttons.push_back(control_button); @@ -848,6 +911,13 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name)))); szr->Add(setting->wxcontrol, 0, wxLEFT, 0); } + for (auto& groupSetting : group->boolean_settings) + { + auto* checkbox = new PadSettingCheckBox(parent, groupSetting.get()); + checkbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustBooleanSetting, eventsink); + options.push_back(checkbox); + Add(checkbox->wxcontrol, 0, wxALL | wxLEFT, 5); + } wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL); h_szr->Add(szr, 1, 0, 5); @@ -942,15 +1012,9 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin for (auto& groupSetting : group->boolean_settings) { PadSettingCheckBox* setting_cbox = new PadSettingCheckBox(parent, groupSetting.get()); + setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustBooleanSetting, eventsink); if (groupSetting->m_name == "Iterative Input") - { - setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSettingUI, eventsink); groupSetting->SetValue(false); - } - else - { - setting_cbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSetting, eventsink); - } options.push_back(setting_cbox); Add(setting_cbox->wxcontrol, 0, wxALL | wxLEFT, 5); } diff --git a/Source/Core/DolphinWX/InputConfigDiag.h b/Source/Core/DolphinWX/InputConfigDiag.h index 1db88b284c..41390d8d60 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.h +++ b/Source/Core/DolphinWX/InputConfigDiag.h @@ -68,6 +68,7 @@ public: (int)(_setting->GetValue() * 100))), setting(_setting) { + wxcontrol->SetLabel(setting->m_name); } void UpdateGUI() override; @@ -164,9 +165,10 @@ class ControlButton : public wxButton { public: ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref, - const unsigned int width, const std::string& label = ""); + const std::string& name, const unsigned int width, const std::string& label = ""); ControllerInterface::ControlReference* const control_reference; + const std::string m_name; }; class ControlGroupBox : public wxBoxSizer @@ -222,8 +224,10 @@ public: void LoadDefaults(wxCommandEvent& event); void AdjustControlOption(wxCommandEvent& event); + void EnablePadSetting(const std::string& group_name, const std::string& name, bool enabled); + void EnableControlButton(const std::string& group_name, const std::string& name, bool enabled); void AdjustSetting(wxCommandEvent& event); - void AdjustSettingUI(wxCommandEvent& event); + void AdjustBooleanSetting(wxCommandEvent& event); void GetProfilePath(std::string& path); diff --git a/Source/Core/InputCommon/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu.cpp index 2fd85b3fac..84f511f822 100644 --- a/Source/Core/InputCommon/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu.cpp @@ -295,10 +295,13 @@ ControllerEmu::Cursor::Cursor(const std::string& _name) controls.emplace_back(std::make_unique("Forward")); controls.emplace_back(std::make_unique("Backward")); controls.emplace_back(std::make_unique(_trans("Hide"))); + controls.emplace_back(std::make_unique("Recenter")); numeric_settings.emplace_back(std::make_unique(_trans("Center"), 0.5)); numeric_settings.emplace_back(std::make_unique(_trans("Width"), 0.5)); numeric_settings.emplace_back(std::make_unique(_trans("Height"), 0.5)); + numeric_settings.emplace_back(std::make_unique(_trans("Dead Zone"), 0, 0, 20)); + boolean_settings.emplace_back(std::make_unique(_trans("Relative Input"), false)); } void ControllerEmu::LoadDefaults(const ControllerInterface& ciface) diff --git a/Source/Core/InputCommon/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu.h index 215b2557b4..90247d699e 100644 --- a/Source/Core/InputCommon/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu.h @@ -12,6 +12,7 @@ #include #include "Common/IniFile.h" +#include "Common/MathUtil.h" #include "Core/ConfigManager.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "InputCommon/GCPadStatus.h" @@ -424,12 +425,43 @@ public: yy += (numeric_settings[0]->GetValue() - 0.5); } - *x = xx; - *y = yy; + // relative input + if (boolean_settings[0]->GetValue()) + { + const ControlState deadzone = numeric_settings[3]->GetValue(); + // deadzone to avoid the cursor slowly drifting + if (std::abs(xx) > deadzone) + m_x = MathUtil::Clamp(m_x + xx * SPEED_MULTIPLIER, -1.0, 1.0); + if (std::abs(yy) > deadzone) + m_y = MathUtil::Clamp(m_y + yy * SPEED_MULTIPLIER, -1.0, 1.0); + + // recenter + if (controls[7]->control_ref->State() > 0.5) + { + m_x = 0.0; + m_y = 0.0; + } + } + else + { + m_x = xx; + m_y = yy; + } + + *x = m_x; + *y = m_y; } } ControlState m_z; + + private: + // This is used to reduce the cursor speed for relative input + // to something that makes sense with the default range. + static constexpr double SPEED_MULTIPLIER = 0.04; + + ControlState m_x = 0.0; + ControlState m_y = 0.0; }; class Extension : public ControlGroup