From 5cf07fdfbf07bbf768f3ed02bc29b45713b08106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 9 Jul 2016 14:29:41 +0200 Subject: [PATCH 1/4] Add relative input for the Wiimote IR This adds an option to enable relative input for the Wiimote IR as described in issue 9014. Enabling it will result in the pointer not going back to the centre and the inputs will control the direction, not the absolute position. Also adds a Dead Zone setting which is really needed when relative input is enabled to prevent the cursor from slowly drifting on most controllers. (Note: the Deadzone setting has no effect when relative input is disabled) --- Source/Core/DolphinWX/InputConfigDiag.cpp | 7 ++++++ Source/Core/InputCommon/ControllerEmu.cpp | 2 ++ Source/Core/InputCommon/ControllerEmu.h | 29 +++++++++++++++++++++-- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index 5971e3ac60..5f77ba7434 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -843,6 +843,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::AdjustSetting, 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); diff --git a/Source/Core/InputCommon/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu.cpp index 2fd85b3fac..5b0b93f021 100644 --- a/Source/Core/InputCommon/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu.cpp @@ -299,6 +299,8 @@ ControllerEmu::Cursor::Cursor(const std::string& _name) 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..d90850b137 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,36 @@ 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); + } + 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 From 2472db4355ff9dbb4c235a2820005c83a55b9a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 13 Jul 2016 12:49:28 +0200 Subject: [PATCH 2/4] Disable IR/deadzone when relative input is disabled This changes InputConfigDiag to disable the Dead Zone field in the IR group when relative input is disabled. --- Source/Core/DolphinWX/InputConfigDiag.cpp | 58 ++++++++++++++++++----- Source/Core/DolphinWX/InputConfigDiag.h | 4 +- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index 5f77ba7434..a2ff75aced 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() @@ -452,15 +457,48 @@ void ControlDialog::AppendControl(wxCommandEvent& event) UpdateGUI(); } -void GamepadPage::AdjustSetting(wxCommandEvent& event) +void GamepadPage::EnableSettingControl(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::AdjustSetting(wxCommandEvent& event) { - m_iterate = !m_iterate; - ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue(); + 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") + { + EnableSettingControl("IR", "Dead Zone", pad_setting->setting->GetValue()); + } } void GamepadPage::AdjustControlOption(wxCommandEvent&) @@ -846,7 +884,7 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin for (auto& groupSetting : group->boolean_settings) { auto* checkbox = new PadSettingCheckBox(parent, groupSetting.get()); - checkbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustSetting, eventsink); + checkbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustBooleanSetting, eventsink); options.push_back(checkbox); Add(checkbox->wxcontrol, 0, wxALL | wxLEFT, 5); } @@ -944,15 +982,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 4489099eee..36d1d15017 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; @@ -222,8 +223,9 @@ public: void LoadDefaults(wxCommandEvent& event); void AdjustControlOption(wxCommandEvent& event); + void EnableSettingControl(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); From 1ad19f9371ce359bf43c61eca27bffb96a16cd09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 14 Jul 2016 21:41:05 +0200 Subject: [PATCH 3/4] InputConfigDiag: Update GUI when config is reloaded This makes the GUI show the settings that are loaded when the config gets reloaded, instead of showing potentially outdated settings that are not applied. --- Source/Core/DolphinWX/InputConfigDiag.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index a2ff75aced..d11c2b7db6 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -799,6 +799,8 @@ void GamepadPage::RefreshDevices(wxCommandEvent&) Pad::LoadConfig(); HotkeyManagerEmu::LoadConfig(); + UpdateGUI(); + Core::PauseAndLock(false, was_unpaused); } From 149654df5a7db04315badc95354bab3ccd02964f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 17 Jul 2016 14:32:06 +0200 Subject: [PATCH 4/4] Add a recenter control for Wiimote IR relative input This adds a recenter control binding which allows recentering the cursor when relative input is enabled. (EnableSettingControl is renamed to avoid confusions.) --- Source/Core/DolphinWX/InputConfigDiag.cpp | 35 +++++++++++++++++++---- Source/Core/DolphinWX/InputConfigDiag.h | 6 ++-- Source/Core/InputCommon/ControllerEmu.cpp | 1 + Source/Core/InputCommon/ControllerEmu.h | 7 +++++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp index d11c2b7db6..2748f70124 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/InputConfigDiag.cpp @@ -167,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,8 +459,8 @@ void ControlDialog::AppendControl(wxCommandEvent& event) UpdateGUI(); } -void GamepadPage::EnableSettingControl(const std::string& group_name, const std::string& name, - const bool enabled) +void GamepadPage::EnablePadSetting(const std::string& group_name, const std::string& name, + const bool enabled) { const auto box_iterator = std::find_if(control_groups.begin(), control_groups.end(), [&group_name](const auto& box) { @@ -477,6 +479,25 @@ void GamepadPage::EnableSettingControl(const std::string& group_name, const std: (*it)->wxcontrol->Enable(enabled); } +void GamepadPage::EnableControlButton(const std::string& group_name, const std::string& name, + const bool enabled) +{ + 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()); @@ -497,7 +518,8 @@ void GamepadPage::AdjustBooleanSetting(wxCommandEvent& event) } else if (control->GetLabelText() == "Relative Input") { - EnableSettingControl("IR", "Dead Zone", pad_setting->setting->GetValue()); + EnablePadSetting("IR", "Dead Zone", pad_setting->setting->GetValue()); + EnableControlButton("IR", "Recenter", pad_setting->setting->GetValue()); } } @@ -825,7 +847,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); diff --git a/Source/Core/DolphinWX/InputConfigDiag.h b/Source/Core/DolphinWX/InputConfigDiag.h index 36d1d15017..7f982e5bd3 100644 --- a/Source/Core/DolphinWX/InputConfigDiag.h +++ b/Source/Core/DolphinWX/InputConfigDiag.h @@ -165,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 @@ -223,7 +224,8 @@ public: void LoadDefaults(wxCommandEvent& event); void AdjustControlOption(wxCommandEvent& event); - void EnableSettingControl(const std::string& group_name, const std::string& name, bool enabled); + 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 AdjustBooleanSetting(wxCommandEvent& event); diff --git a/Source/Core/InputCommon/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu.cpp index 5b0b93f021..84f511f822 100644 --- a/Source/Core/InputCommon/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu.cpp @@ -295,6 +295,7 @@ 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)); diff --git a/Source/Core/InputCommon/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu.h index d90850b137..90247d699e 100644 --- a/Source/Core/InputCommon/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu.h @@ -434,6 +434,13 @@ public: 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 {