summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerEmu/ControlGroup
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/InputCommon/ControllerEmu/ControlGroup')
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp71
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h26
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.cpp24
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h33
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp132
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h117
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp98
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h29
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.cpp16
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.h31
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp51
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h22
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp42
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h19
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp77
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h31
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp37
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h19
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.cpp99
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.h22
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp31
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h19
22 files changed, 1046 insertions, 0 deletions
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp
new file mode 100644
index 0000000000..8ee7357963
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp
@@ -0,0 +1,71 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+
+#include "Common/Common.h"
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/Control/Input.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+
+namespace ControllerEmu
+{
+AnalogStick::AnalogStick(const char* const name_, ControlState default_radius)
+ : AnalogStick(name_, name_, default_radius)
+{
+}
+
+AnalogStick::AnalogStick(const char* const name_, const char* const ui_name_,
+ ControlState default_radius)
+ : ControlGroup(name_, ui_name_, GROUP_TYPE_STICK)
+{
+ for (auto& named_direction : named_directions)
+ controls.emplace_back(std::make_unique<Input>(named_direction));
+
+ controls.emplace_back(std::make_unique<Input>(_trans("Modifier")));
+ numeric_settings.emplace_back(
+ std::make_unique<NumericSetting>(_trans("Radius"), default_radius, 0, 100));
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
+}
+
+void AnalogStick::GetState(ControlState* const x, ControlState* const y)
+{
+ ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
+ ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
+
+ ControlState radius = numeric_settings[SETTING_RADIUS]->GetValue();
+ ControlState deadzone = numeric_settings[SETTING_DEADZONE]->GetValue();
+ ControlState m = controls[4]->control_ref->State();
+
+ ControlState ang = atan2(yy, xx);
+ ControlState ang_sin = sin(ang);
+ ControlState ang_cos = cos(ang);
+
+ ControlState dist = sqrt(xx * xx + yy * yy);
+
+ // dead zone code
+ dist = std::max(0.0, dist - deadzone);
+ dist /= (1 - deadzone);
+
+ // radius
+ dist *= radius;
+
+ // The modifier halves the distance by 50%, which is useful
+ // for keyboard controls.
+ if (m)
+ dist *= 0.5;
+
+ yy = std::max(-1.0, std::min(1.0, ang_sin * dist));
+ xx = std::max(-1.0, std::min(1.0, ang_cos * dist));
+
+ *y = yy;
+ *x = xx;
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h
new file mode 100644
index 0000000000..2d05b6baa4
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h
@@ -0,0 +1,26 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class AnalogStick : public ControlGroup
+{
+public:
+ enum
+ {
+ SETTING_RADIUS,
+ SETTING_DEADZONE,
+ };
+
+ // The GameCube controller and Wiimote attachments have a different default radius
+ AnalogStick(const char* name, ControlState default_radius);
+ AnalogStick(const char* name, const char* ui_name, ControlState default_radius);
+
+ void GetState(ControlState* x, ControlState* y);
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.cpp
new file mode 100644
index 0000000000..55e4532e7a
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.cpp
@@ -0,0 +1,24 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
+
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+
+namespace ControllerEmu
+{
+Buttons::Buttons(const std::string& name_) : ControlGroup(name_, name_, GROUP_TYPE_BUTTONS)
+{
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Threshold"), 0.5));
+}
+
+Buttons::Buttons(const std::string& ini_name, const std::string& group_name)
+ : ControlGroup(ini_name, group_name, GROUP_TYPE_BUTTONS)
+{
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Threshold"), 0.5));
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h
new file mode 100644
index 0000000000..9b1acd866c
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h
@@ -0,0 +1,33 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class Buttons : public ControlGroup
+{
+public:
+ explicit Buttons(const std::string& name_);
+ Buttons(const std::string& ini_name, const std::string& group_name);
+
+ template <typename C>
+ void GetState(C* const buttons, const C* bitmasks)
+ {
+ for (auto& control : controls)
+ {
+ if (control->control_ref->State() > numeric_settings[0]->GetValue()) // threshold
+ *buttons |= *bitmasks;
+
+ bitmasks++;
+ }
+ }
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp
new file mode 100644
index 0000000000..cd730697a5
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.cpp
@@ -0,0 +1,132 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+#include "Common/CommonTypes.h"
+#include "Common/IniFile.h"
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/ControlGroup/Extension.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+
+namespace ControllerEmu
+{
+ControlGroup::ControlGroup(const std::string& name_, const u32 type_)
+ : name(name_), ui_name(name_), type(type_)
+{
+}
+
+ControlGroup::ControlGroup(const std::string& name_, const std::string& ui_name_, const u32 type_)
+ : name(name_), ui_name(ui_name_), type(type_)
+{
+}
+
+ControlGroup::~ControlGroup() = default;
+
+ControlGroup::BooleanSetting::~BooleanSetting() = default;
+
+void ControlGroup::LoadConfig(IniFile::Section* sec, const std::string& defdev,
+ const std::string& base)
+{
+ std::string group(base + name + "/");
+
+ // settings
+ for (auto& s : numeric_settings)
+ {
+ if (s->m_type == SettingType::VIRTUAL)
+ continue;
+
+ sec->Get(group + s->m_name, &s->m_value, s->m_default_value * 100);
+ s->m_value /= 100;
+ }
+
+ for (auto& s : boolean_settings)
+ {
+ if (s->m_type == SettingType::VIRTUAL)
+ continue;
+
+ sec->Get(group + s->m_name, &s->m_value, s->m_default_value);
+ }
+
+ for (auto& c : controls)
+ {
+ // control expression
+ sec->Get(group + c->name, &c->control_ref->expression, "");
+
+ // range
+ sec->Get(group + c->name + "/Range", &c->control_ref->range, 100.0);
+ c->control_ref->range /= 100;
+ }
+
+ // extensions
+ if (type == GROUP_TYPE_EXTENSION)
+ {
+ Extension* const ext = (Extension*)this;
+
+ ext->switch_extension = 0;
+ u32 n = 0;
+ std::string extname;
+ sec->Get(base + name, &extname, "");
+
+ for (auto& ai : ext->attachments)
+ {
+ ai->default_device.FromString(defdev);
+ ai->LoadConfig(sec, base + ai->GetName() + "/");
+
+ if (ai->GetName() == extname)
+ ext->switch_extension = n;
+
+ n++;
+ }
+ }
+}
+
+void ControlGroup::SaveConfig(IniFile::Section* sec, const std::string& defdev,
+ const std::string& base)
+{
+ std::string group(base + name + "/");
+
+ for (auto& s : numeric_settings)
+ {
+ if (s->m_type == SettingType::VIRTUAL)
+ continue;
+
+ sec->Set(group + s->m_name, s->m_value * 100.0, s->m_default_value * 100.0);
+ }
+
+ for (auto& s : boolean_settings)
+ {
+ if (s->m_type == SettingType::VIRTUAL)
+ continue;
+
+ sec->Set(group + s->m_name, s->m_value, s->m_default_value);
+ }
+
+ for (auto& c : controls)
+ {
+ // control expression
+ sec->Set(group + c->name, c->control_ref->expression, "");
+
+ // range
+ sec->Set(group + c->name + "/Range", c->control_ref->range * 100.0, 100.0);
+ }
+
+ // extensions
+ if (type == GROUP_TYPE_EXTENSION)
+ {
+ Extension* const ext = (Extension*)this;
+ sec->Set(base + name, ext->attachments[ext->switch_extension]->GetName(), "None");
+
+ for (auto& ai : ext->attachments)
+ ai->SaveConfig(sec, base + ai->GetName() + "/");
+ }
+}
+
+void ControlGroup::SetControlExpression(int index, const std::string& expression)
+{
+ controls.at(index)->control_ref->expression = expression;
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h
new file mode 100644
index 0000000000..68eacb6e02
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h
@@ -0,0 +1,117 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Common/CommonTypes.h"
+#include "Common/IniFile.h"
+#include "Core/ConfigManager.h"
+#include "InputCommon/ControllerInterface/Device.h"
+
+namespace ControllerEmu
+{
+class Control;
+
+enum
+{
+ GROUP_TYPE_OTHER,
+ GROUP_TYPE_STICK,
+ GROUP_TYPE_MIXED_TRIGGERS,
+ GROUP_TYPE_BUTTONS,
+ GROUP_TYPE_FORCE,
+ GROUP_TYPE_EXTENSION,
+ GROUP_TYPE_TILT,
+ GROUP_TYPE_CURSOR,
+ GROUP_TYPE_TRIGGERS,
+ GROUP_TYPE_SLIDER
+};
+
+class ControlGroup
+{
+public:
+ enum class SettingType
+ {
+ NORMAL, // normal settings are saved to configuration files
+ VIRTUAL, // virtual settings are not saved at all
+ };
+
+ class NumericSetting
+ {
+ public:
+ NumericSetting(const std::string& setting_name, const ControlState default_value,
+ const u32 low = 0, const u32 high = 100,
+ const SettingType setting_type = SettingType::NORMAL)
+ : m_type(setting_type), m_name(setting_name), m_default_value(default_value), m_low(low),
+ m_high(high)
+ {
+ }
+
+ ControlState GetValue() const { return m_value; }
+ void SetValue(ControlState value) { m_value = value; }
+ const SettingType m_type;
+ const std::string m_name;
+ const ControlState m_default_value;
+ const u32 m_low;
+ const u32 m_high;
+ ControlState m_value;
+ };
+
+ class BooleanSetting
+ {
+ public:
+ BooleanSetting(const std::string& setting_name, const bool default_value,
+ const SettingType setting_type = SettingType::NORMAL)
+ : m_type(setting_type), m_name(setting_name), m_default_value(default_value)
+ {
+ }
+ virtual ~BooleanSetting();
+
+ virtual bool GetValue() const { return m_value; }
+ virtual void SetValue(bool value) { m_value = value; }
+ const SettingType m_type;
+ const std::string m_name;
+ const bool m_default_value;
+ bool m_value;
+ };
+
+ class BackgroundInputSetting : public BooleanSetting
+ {
+ public:
+ BackgroundInputSetting(const std::string& setting_name)
+ : BooleanSetting(setting_name, false, SettingType::VIRTUAL)
+ {
+ }
+
+ bool GetValue() const override { return SConfig::GetInstance().m_BackgroundInput; }
+ void SetValue(bool value) override
+ {
+ m_value = value;
+ SConfig::GetInstance().m_BackgroundInput = value;
+ }
+ };
+
+ explicit ControlGroup(const std::string& name, u32 type = GROUP_TYPE_OTHER);
+ ControlGroup(const std::string& name, const std::string& ui_name, u32 type = GROUP_TYPE_OTHER);
+ virtual ~ControlGroup();
+
+ virtual void LoadConfig(IniFile::Section* sec, const std::string& defdev = "",
+ const std::string& base = "");
+ virtual void SaveConfig(IniFile::Section* sec, const std::string& defdev = "",
+ const std::string& base = "");
+
+ void SetControlExpression(int index, const std::string& expression);
+
+ const std::string name;
+ const std::string ui_name;
+ const u32 type;
+
+ std::vector<std::unique_ptr<Control>> controls;
+ std::vector<std::unique_ptr<NumericSetting>> numeric_settings;
+ std::vector<std::unique_ptr<BooleanSetting>> boolean_settings;
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp
new file mode 100644
index 0000000000..1d0c55a8d5
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp
@@ -0,0 +1,98 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Cursor.h"
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+#include "Common/MathUtil.h"
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/Control/Input.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+
+namespace ControllerEmu
+{
+Cursor::Cursor(const std::string& name_) : ControlGroup(name_, GROUP_TYPE_CURSOR)
+{
+ for (auto& named_direction : named_directions)
+ controls.emplace_back(std::make_unique<Input>(named_direction));
+
+ controls.emplace_back(std::make_unique<Input>("Forward"));
+ controls.emplace_back(std::make_unique<Input>("Backward"));
+ controls.emplace_back(std::make_unique<Input>(_trans("Hide")));
+ controls.emplace_back(std::make_unique<Input>("Recenter"));
+
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Center"), 0.5));
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Width"), 0.5));
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Height"), 0.5));
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 20));
+ boolean_settings.emplace_back(std::make_unique<BooleanSetting>(_trans("Relative Input"), false));
+}
+
+void Cursor::GetState(ControlState* const x, ControlState* const y, ControlState* const z,
+ const bool adjusted)
+{
+ const ControlState zz = controls[4]->control_ref->State() - controls[5]->control_ref->State();
+
+ // silly being here
+ if (zz > m_z)
+ m_z = std::min(m_z + 0.1, zz);
+ else if (zz < m_z)
+ m_z = std::max(m_z - 0.1, zz);
+
+ *z = m_z;
+
+ // hide
+ if (controls[6]->control_ref->State() > 0.5)
+ {
+ *x = 10000;
+ *y = 0;
+ }
+ else
+ {
+ ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
+ ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
+
+ // adjust cursor according to settings
+ if (adjusted)
+ {
+ xx *= (numeric_settings[1]->GetValue() * 2);
+ yy *= (numeric_settings[2]->GetValue() * 2);
+ yy += (numeric_settings[0]->GetValue() - 0.5);
+ }
+
+ // 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;
+ }
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h
new file mode 100644
index 0000000000..3520d95d13
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h
@@ -0,0 +1,29 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class Cursor : public ControlGroup
+{
+public:
+ explicit Cursor(const std::string& name);
+
+ void GetState(ControlState* x, ControlState* y, ControlState* z, bool adjusted = false);
+
+ ControlState m_z = 0.0;
+
+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;
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.cpp
new file mode 100644
index 0000000000..b35eb40bbd
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.cpp
@@ -0,0 +1,16 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Extension.h"
+
+#include <string>
+
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+
+namespace ControllerEmu
+{
+Extension::Extension(const std::string& name_) : ControlGroup(name_, GROUP_TYPE_EXTENSION)
+{
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.h
new file mode 100644
index 0000000000..366e94f248
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Extension.h
@@ -0,0 +1,31 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Common/CommonTypes.h"
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class EmulatedController;
+
+class Extension : public ControlGroup
+{
+public:
+ explicit Extension(const std::string& name);
+
+ void GetState(u8* data);
+ bool IsButtonPressed() const;
+
+ std::vector<std::unique_ptr<EmulatedController>> attachments;
+
+ int switch_extension = 0;
+ int active_extension = 0;
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp
new file mode 100644
index 0000000000..29413ada2c
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.cpp
@@ -0,0 +1,51 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Force.h"
+
+#include <cmath>
+#include <cstring>
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+#include "Common/CommonTypes.h"
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Input.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+
+namespace ControllerEmu
+{
+Force::Force(const std::string& name_) : ControlGroup(name_, GROUP_TYPE_FORCE)
+{
+ memset(m_swing, 0, sizeof(m_swing));
+
+ controls.emplace_back(std::make_unique<Input>(_trans("Up")));
+ controls.emplace_back(std::make_unique<Input>(_trans("Down")));
+ controls.emplace_back(std::make_unique<Input>(_trans("Left")));
+ controls.emplace_back(std::make_unique<Input>(_trans("Right")));
+ controls.emplace_back(std::make_unique<Input>(_trans("Forward")));
+ controls.emplace_back(std::make_unique<Input>(_trans("Backward")));
+
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
+}
+
+void Force::GetState(ControlState* axis)
+{
+ const ControlState deadzone = numeric_settings[0]->GetValue();
+
+ for (u32 i = 0; i < 6; i += 2)
+ {
+ ControlState tmpf = 0;
+ const ControlState state =
+ controls[i + 1]->control_ref->State() - controls[i]->control_ref->State();
+ if (fabs(state) > deadzone)
+ tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone));
+
+ ControlState& ax = m_swing[i >> 1];
+ *axis++ = (tmpf - ax);
+ ax = tmpf;
+ }
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h
new file mode 100644
index 0000000000..767009a1f8
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Force.h
@@ -0,0 +1,22 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class Force : public ControlGroup
+{
+public:
+ explicit Force(const std::string& name);
+
+ void GetState(ControlState* axis);
+
+private:
+ ControlState m_swing[3];
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp
new file mode 100644
index 0000000000..db8efc48a5
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp
@@ -0,0 +1,42 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h"
+
+#include <cstddef>
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+#include "Common/CommonTypes.h"
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+
+namespace ControllerEmu
+{
+MixedTriggers::MixedTriggers(const std::string& name_)
+ : ControlGroup(name_, GROUP_TYPE_MIXED_TRIGGERS)
+{
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Threshold"), 0.9));
+}
+
+void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlState* analog)
+{
+ const size_t trigger_count = controls.size() / 2;
+
+ for (size_t i = 0; i < trigger_count; ++i, ++bitmasks, ++analog)
+ {
+ if (controls[i]->control_ref->State() > numeric_settings[0]->GetValue()) // threshold
+ {
+ *analog = 1.0;
+ *digital |= *bitmasks;
+ }
+ else
+ {
+ *analog = controls[i + trigger_count]->control_ref->State();
+ }
+ }
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h
new file mode 100644
index 0000000000..7cd606e53a
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h
@@ -0,0 +1,19 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class MixedTriggers : public ControlGroup
+{
+public:
+ explicit MixedTriggers(const std::string& name);
+
+ void GetState(u16* digital, const u16* bitmasks, ControlState* analog);
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp
new file mode 100644
index 0000000000..b71b1ea2c1
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.cpp
@@ -0,0 +1,77 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h"
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "Common/Common.h"
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/Control/Input.h"
+#include "VideoCommon/OnScreenDisplay.h"
+
+namespace ControllerEmu
+{
+ModifySettingsButton::ModifySettingsButton(std::string button_name)
+ : Buttons(std::move(button_name))
+{
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Threshold"), 0.5));
+}
+
+void ModifySettingsButton::AddInput(std::string button_name, bool toggle)
+{
+ controls.emplace_back(new Input(std::move(button_name)));
+ threshold_exceeded.emplace_back(false);
+ associated_settings.emplace_back(false);
+ associated_settings_toggle.emplace_back(toggle);
+}
+
+void ModifySettingsButton::GetState()
+{
+ for (size_t i = 0; i < controls.size(); ++i)
+ {
+ ControlState state = controls[i]->control_ref->State();
+
+ if (!associated_settings_toggle[i])
+ {
+ // not toggled
+ associated_settings[i] = state > numeric_settings[0]->GetValue();
+ }
+ else
+ {
+ // toggle (loading savestates does not en-/disable toggle)
+ // after we passed the threshold, we en-/disable. but after that, we don't change it
+ // anymore
+ if (!threshold_exceeded[i] && state > numeric_settings[0]->GetValue())
+ {
+ associated_settings[i] = !associated_settings[i];
+
+ if (associated_settings[i])
+ OSD::AddMessage(controls[i]->name + ": " + _trans("on"));
+ else
+ OSD::AddMessage(controls[i]->name + ": " + _trans("off"));
+
+ threshold_exceeded[i] = true;
+ }
+
+ if (state < numeric_settings[0]->GetValue())
+ threshold_exceeded[i] = false;
+ }
+ }
+}
+
+const std::vector<bool>& ModifySettingsButton::isSettingToggled() const
+{
+ return associated_settings_toggle;
+}
+
+const std::vector<bool>& ModifySettingsButton::getSettingsModifier() const
+{
+ return associated_settings;
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h
new file mode 100644
index 0000000000..667f3e5c7a
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h
@@ -0,0 +1,31 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
+
+namespace ControllerEmu
+{
+class ModifySettingsButton : public Buttons
+{
+public:
+ explicit ModifySettingsButton(std::string button_name);
+
+ void AddInput(std::string button_name, bool toggle = false);
+
+ void GetState();
+
+ const std::vector<bool>& isSettingToggled() const;
+ const std::vector<bool>& getSettingsModifier() const;
+
+private:
+ std::vector<bool> threshold_exceeded; // internal calculation (if "state" was above threshold)
+ std::vector<bool> associated_settings_toggle; // is setting toggled or hold?
+ std::vector<bool> associated_settings; // result
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp
new file mode 100644
index 0000000000..5fdf349bba
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp
@@ -0,0 +1,37 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Slider.h"
+
+#include <cmath>
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/Control/Input.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+
+namespace ControllerEmu
+{
+Slider::Slider(const std::string& name_) : ControlGroup(name_, GROUP_TYPE_SLIDER)
+{
+ controls.emplace_back(std::make_unique<Input>("Left"));
+ controls.emplace_back(std::make_unique<Input>("Right"));
+
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
+}
+
+void Slider::GetState(ControlState* const slider)
+{
+ const ControlState deadzone = numeric_settings[0]->GetValue();
+ const ControlState state = controls[1]->control_ref->State() - controls[0]->control_ref->State();
+
+ if (fabs(state) > deadzone)
+ *slider = (state - (deadzone * sign(state))) / (1 - deadzone);
+ else
+ *slider = 0;
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h
new file mode 100644
index 0000000000..3d6f7f5a02
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h
@@ -0,0 +1,19 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class Slider : public ControlGroup
+{
+public:
+ explicit Slider(const std::string& name);
+
+ void GetState(ControlState* slider);
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.cpp
new file mode 100644
index 0000000000..5481d92606
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.cpp
@@ -0,0 +1,99 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Tilt.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerEmu/Control/Input.h"
+
+namespace ControllerEmu
+{
+Tilt::Tilt(const std::string& name_) : ControlGroup(name_, GROUP_TYPE_TILT)
+{
+ memset(m_tilt, 0, sizeof(m_tilt));
+
+ controls.emplace_back(std::make_unique<Input>("Forward"));
+ controls.emplace_back(std::make_unique<Input>("Backward"));
+ controls.emplace_back(std::make_unique<Input>("Left"));
+ controls.emplace_back(std::make_unique<Input>("Right"));
+
+ controls.emplace_back(std::make_unique<Input>(_trans("Modifier")));
+
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Circle Stick"), 0));
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Angle"), 0.9, 0, 180));
+}
+
+void Tilt::GetState(ControlState* const x, ControlState* const y, const bool step)
+{
+ // this is all a mess
+
+ ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
+ ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
+
+ ControlState deadzone = numeric_settings[0]->GetValue();
+ ControlState circle = numeric_settings[1]->GetValue();
+ auto const angle = numeric_settings[2]->GetValue() / 1.8;
+ ControlState m = controls[4]->control_ref->State();
+
+ // deadzone / circle stick code
+ // this section might be all wrong, but its working good enough, I think
+
+ ControlState ang = atan2(yy, xx);
+ ControlState ang_sin = sin(ang);
+ ControlState ang_cos = cos(ang);
+
+ // the amt a full square stick would have at current angle
+ ControlState square_full =
+ std::min(ang_sin ? 1 / fabs(ang_sin) : 2, ang_cos ? 1 / fabs(ang_cos) : 2);
+
+ // the amt a full stick would have that was (user setting circular) at current angle
+ // I think this is more like a pointed circle rather than a rounded square like it should be
+ ControlState stick_full = (square_full * (1 - circle)) + (circle);
+
+ ControlState dist = sqrt(xx * xx + yy * yy);
+
+ // dead zone code
+ dist = std::max(0.0, dist - deadzone * stick_full);
+ dist /= (1 - deadzone);
+
+ // circle stick code
+ ControlState amt = dist / stick_full;
+ dist += (square_full - 1) * amt * circle;
+
+ if (m)
+ dist *= 0.5;
+
+ yy = std::max(-1.0, std::min(1.0, ang_sin * dist));
+ xx = std::max(-1.0, std::min(1.0, ang_cos * dist));
+
+ // this is kinda silly here
+ // gui being open will make this happen 2x as fast, o well
+
+ // silly
+ if (step)
+ {
+ if (xx > m_tilt[0])
+ m_tilt[0] = std::min(m_tilt[0] + 0.1, xx);
+ else if (xx < m_tilt[0])
+ m_tilt[0] = std::max(m_tilt[0] - 0.1, xx);
+
+ if (yy > m_tilt[1])
+ m_tilt[1] = std::min(m_tilt[1] + 0.1, yy);
+ else if (yy < m_tilt[1])
+ m_tilt[1] = std::max(m_tilt[1] - 0.1, yy);
+ }
+
+ *y = m_tilt[1] * angle;
+ *x = m_tilt[0] * angle;
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.h
new file mode 100644
index 0000000000..940d7d9722
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Tilt.h
@@ -0,0 +1,22 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class Tilt : public ControlGroup
+{
+public:
+ explicit Tilt(const std::string& name);
+
+ void GetState(ControlState* x, ControlState* y, bool step = true);
+
+private:
+ ControlState m_tilt[2];
+};
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp
new file mode 100644
index 0000000000..3e13b0b504
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp
@@ -0,0 +1,31 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerEmu/ControlGroup/Triggers.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+
+#include "Common/Common.h"
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/Control/Control.h"
+
+namespace ControllerEmu
+{
+Triggers::Triggers(const std::string& name_) : ControlGroup(name_, GROUP_TYPE_TRIGGERS)
+{
+ numeric_settings.emplace_back(std::make_unique<NumericSetting>(_trans("Dead Zone"), 0, 0, 50));
+}
+
+void Triggers::GetState(ControlState* analog)
+{
+ const size_t trigger_count = controls.size();
+ const ControlState deadzone = numeric_settings[0]->GetValue();
+
+ for (size_t i = 0; i < trigger_count; ++i, ++analog)
+ *analog = std::max(controls[i]->control_ref->State() - deadzone, 0.0) / (1 - deadzone);
+}
+} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h
new file mode 100644
index 0000000000..5562e5c694
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h
@@ -0,0 +1,19 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+
+namespace ControllerEmu
+{
+class Triggers : public ControlGroup
+{
+public:
+ explicit Triggers(const std::string& name);
+
+ void GetState(ControlState* analog);
+};
+} // namespace ControllerEmu