summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2022-10-03 16:25:40 -0400
committerGitHub <noreply@github.com>2022-10-03 16:25:40 -0400
commit052c7395fbc0789147703a4c5cc754ae28f8f8bd (patch)
treec6e206df257937e8373aeeb012e29ea74f0d0fc7 /Source/Core/InputCommon
parentcb6d476538afe85c25d30e8679b6f15abe5d1760 (diff)
parent51ee05cb35f401c82adf815cbb4f4c3133e7ea84 (diff)
Merge pull request #9624 from JosJuice/input-override
Add new "input override" system for TAS input and Android touch controls
Diffstat (limited to 'Source/Core/InputCommon')
-rw-r--r--Source/Core/InputCommon/CMakeLists.txt2
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp29
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h2
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h17
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h7
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp25
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h3
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp48
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h2
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp17
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h3
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp22
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h1
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp12
-rw-r--r--Source/Core/InputCommon/ControllerEmu/ControllerEmu.h32
-rw-r--r--Source/Core/InputCommon/ControllerEmu/StickGate.h4
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp45
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h3
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.cpp272
-rw-r--r--Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.h89
20 files changed, 578 insertions, 57 deletions
diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt
index 06ffb37a2d..53929b7f6c 100644
--- a/Source/Core/InputCommon/CMakeLists.txt
+++ b/Source/Core/InputCommon/CMakeLists.txt
@@ -140,6 +140,8 @@ elseif(ANDROID)
ControllerInterface/Android/Android.h
ControllerInterface/Touch/ButtonManager.cpp
ControllerInterface/Touch/ButtonManager.h
+ ControllerInterface/Touch/InputOverrider.cpp
+ ControllerInterface/Touch/InputOverrider.h
ControllerInterface/Touch/Touchscreen.cpp
ControllerInterface/Touch/Touchscreen.h
)
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp
index 539e02b449..0f30b50f63 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.cpp
@@ -4,6 +4,7 @@
#include "InputCommon/ControllerEmu/ControlGroup/AnalogStick.h"
#include <cmath>
+#include <optional>
#include "Common/Common.h"
#include "Common/MathUtil.h"
@@ -48,6 +49,34 @@ AnalogStick::StateData AnalogStick::GetState() const
return GetReshapableState(true);
}
+AnalogStick::StateData AnalogStick::GetState(const InputOverrideFunction& override_func) const
+{
+ bool override_occurred = false;
+ return GetState(override_func, &override_occurred);
+}
+
+AnalogStick::StateData AnalogStick::GetState(const InputOverrideFunction& override_func,
+ bool* override_occurred) const
+{
+ StateData state = GetState();
+ if (!override_func)
+ return state;
+
+ if (const std::optional<ControlState> x_override = override_func(name, X_INPUT_OVERRIDE, state.x))
+ {
+ state.x = *x_override;
+ *override_occurred = true;
+ }
+
+ if (const std::optional<ControlState> y_override = override_func(name, Y_INPUT_OVERRIDE, state.y))
+ {
+ state.y = *y_override;
+ *override_occurred = true;
+ }
+
+ return state;
+}
+
ControlState AnalogStick::GetGateRadiusAtAngle(double ang) const
{
return m_stick_gate->GetRadiusAtAngle(ang);
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h
index 47e3ad5743..377e63251d 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/AnalogStick.h
@@ -21,6 +21,8 @@ public:
ControlState GetGateRadiusAtAngle(double ang) const override;
StateData GetState() const;
+ StateData GetState(const InputOverrideFunction& override_func) const;
+ StateData GetState(const InputOverrideFunction& override_func, bool* override_occurred) const;
private:
Control* GetModifierInput() const override;
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h
index 2d02adabf1..652f64ae5f 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Buttons.h
@@ -3,6 +3,7 @@
#pragma once
+#include <cmath>
#include <string>
#include "InputCommon/ControlReference/ControlReference.h"
@@ -24,5 +25,21 @@ public:
for (auto& control : controls)
*buttons |= *(bitmasks++) * control->GetState<bool>();
}
+
+ template <typename C>
+ void GetState(C* const buttons, const C* bitmasks,
+ const InputOverrideFunction& override_func) const
+ {
+ if (!override_func)
+ return GetState(buttons, bitmasks);
+
+ for (auto& control : controls)
+ {
+ ControlState state = control->GetState();
+ if (std::optional<ControlState> state_override = override_func(name, control->name, state))
+ state = *state_override;
+ *buttons |= *(bitmasks++) * (std::lround(state) > 0);
+ }
+ }
};
} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h
index c08c072aba..fb10bab074 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/ControlGroup.h
@@ -5,14 +5,18 @@
#include <algorithm>
#include <cmath>
+#include <functional>
#include <memory>
+#include <optional>
#include <string>
+#include <string_view>
#include <type_traits>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/IniFile.h"
#include "InputCommon/ControllerEmu/Control/Control.h"
+#include "InputCommon/ControllerInterface/CoreDevice.h"
namespace ControllerEmu
{
@@ -27,6 +31,9 @@ class NumericSetting;
template <typename T>
class SettingValue;
+using InputOverrideFunction = std::function<std::optional<ControlState>(
+ const std::string_view group_name, const std::string_view control_name, ControlState state)>;
+
enum class GroupType
{
Other,
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp
index 043ef37356..7359a4e66d 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp
@@ -82,15 +82,28 @@ ControlState Cursor::GetGateRadiusAtAngle(double ang) const
Cursor::StateData Cursor::GetState(const bool adjusted)
{
- if (!adjusted)
- {
- const auto raw_input = GetReshapableState(false);
+ const ReshapeData input = GetReshapableState(adjusted);
+ const StateData state = adjusted ? UpdateState(input) : StateData{input.x, input.y};
+ return state;
+}
- return {raw_input.x, raw_input.y};
- }
+Cursor::StateData Cursor::GetState(const bool adjusted,
+ const ControllerEmu::InputOverrideFunction& override_func)
+{
+ StateData state = GetState(adjusted);
+ if (!override_func)
+ return state;
+
+ if (const std::optional<ControlState> x_override = override_func(name, X_INPUT_OVERRIDE, state.x))
+ state.x = *x_override;
+ if (const std::optional<ControlState> y_override = override_func(name, Y_INPUT_OVERRIDE, state.y))
+ state.y = *y_override;
- const auto input = GetReshapableState(true);
+ return state;
+}
+Cursor::StateData Cursor::UpdateState(Cursor::ReshapeData input)
+{
// TODO: Using system time is ugly.
// Kill this after state is moved into wiimote rather than this class.
const auto now = Clock::now();
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h
index 5e64ce86dc..3710a40d92 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.h
@@ -29,6 +29,7 @@ public:
// Modifies the state
StateData GetState(bool adjusted);
+ StateData GetState(bool adjusted, const ControllerEmu::InputOverrideFunction& override_func);
// Yaw movement in radians.
ControlState GetTotalYaw() const;
@@ -40,6 +41,8 @@ public:
ControlState GetVerticalOffset() const;
private:
+ Cursor::StateData UpdateState(Cursor::ReshapeData input);
+
// This is used to reduce the cursor speed for relative input
// to something that makes sense with the default range.
static constexpr double STEP_PER_SEC = 0.01 * 200;
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.cpp
index 8c2f4cbac5..8783087650 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 <algorithm>
+#include <cmath>
#include <cstddef>
#include <memory>
#include <string>
@@ -63,6 +64,53 @@ void MixedTriggers::GetState(u16* const digital, const u16* bitmasks, ControlSta
}
}
+void MixedTriggers::GetState(u16* digital, const u16* bitmasks, ControlState* analog,
+ const InputOverrideFunction& override_func, bool adjusted) const
+{
+ if (!override_func)
+ return GetState(digital, bitmasks, analog, adjusted);
+
+ const ControlState threshold = GetThreshold();
+ ControlState deadzone = GetDeadzone();
+
+ // Return raw values. (used in UI)
+ if (!adjusted)
+ {
+ deadzone = 0.0;
+ }
+
+ const int trigger_count = int(controls.size() / 2);
+ for (int i = 0; i != trigger_count; ++i)
+ {
+ bool button_bool = false;
+ const ControlState button_value = ApplyDeadzone(controls[i]->GetState(), deadzone);
+ ControlState analog_value = ApplyDeadzone(controls[trigger_count + i]->GetState(), deadzone);
+
+ // Apply threshold:
+ if (button_value > threshold)
+ {
+ analog_value = 1.0;
+ button_bool = true;
+ }
+
+ if (const std::optional<ControlState> button_override =
+ override_func(name, controls[i]->name, static_cast<ControlState>(button_bool)))
+ {
+ button_bool = std::lround(*button_override) > 0;
+ }
+
+ if (const std::optional<ControlState> analog_override =
+ override_func(name, controls[trigger_count + i]->name, analog_value))
+ {
+ analog_value = *analog_override;
+ }
+
+ if (button_bool)
+ *digital |= bitmasks[i];
+ analog[i] = std::min(analog_value, 1.0);
+ }
+}
+
ControlState MixedTriggers::GetDeadzone() const
{
return m_deadzone_setting.GetValue() / 100;
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h
index fcd98b279e..2e1014d047 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h
@@ -17,6 +17,8 @@ public:
void GetState(u16* digital, const u16* bitmasks, ControlState* analog,
bool adjusted = true) const;
+ void GetState(u16* digital, const u16* bitmasks, ControlState* analog,
+ const InputOverrideFunction& override_func, bool adjusted = true) const;
ControlState GetDeadzone() const;
ControlState GetThreshold() const;
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp
index f0516a567f..708831a4c3 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.cpp
@@ -35,4 +35,21 @@ Slider::StateData Slider::GetState() const
return {std::clamp(ApplyDeadzone(state, deadzone), -1.0, 1.0)};
}
+
+Slider::StateData Slider::GetState(const InputOverrideFunction& override_func) const
+{
+ if (!override_func)
+ return GetState();
+
+ const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
+ ControlState state = controls[1]->GetState() - controls[0]->GetState();
+
+ state = ApplyDeadzone(state, deadzone);
+
+ if (std::optional<ControlState> state_override = override_func(name, X_INPUT_OVERRIDE, state))
+ state = *state_override;
+
+ return {std::clamp(state, -1.0, 1.0)};
+}
+
} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h
index 9d1bf697a5..0e635da235 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Slider.h
@@ -23,6 +23,9 @@ public:
explicit Slider(const std::string& name_);
StateData GetState() const;
+ StateData GetState(const InputOverrideFunction& override_func) const;
+
+ static constexpr const char* X_INPUT_OVERRIDE = "X";
private:
SettingValue<double> m_deadzone_setting;
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp
index 17e64d2a8b..321c9272d0 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.cpp
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cstddef>
#include <memory>
+#include <optional>
#include <string>
#include "Common/Common.h"
@@ -31,4 +32,25 @@ Triggers::StateData Triggers::GetState() const
return result;
}
+
+Triggers::StateData Triggers::GetState(const InputOverrideFunction& override_func) const
+{
+ if (!override_func)
+ return GetState();
+
+ const size_t trigger_count = controls.size();
+ const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
+
+ StateData result(trigger_count);
+ for (size_t i = 0; i < trigger_count; ++i)
+ {
+ ControlState state = ApplyDeadzone(controls[i]->GetState(), deadzone);
+ if (std::optional<ControlState> state_override = override_func(name, controls[i]->name, state))
+ state = *state_override;
+ result.data[i] = std::min(state, 1.0);
+ }
+
+ return result;
+}
+
} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h
index 2ea02bedb5..c73dee9cfa 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Triggers.h
@@ -26,6 +26,7 @@ public:
explicit Triggers(const std::string& name);
StateData GetState() const;
+ StateData GetState(const InputOverrideFunction& override_func) const;
private:
SettingValue<double> m_deadzone_setting;
diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp
index 0a3de3e391..dc9830de3f 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp
+++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp
@@ -6,6 +6,7 @@
#include <memory>
#include <mutex>
#include <string>
+#include <utility>
#include "Common/IniFile.h"
@@ -176,4 +177,15 @@ void EmulatedController::LoadDefaults(const ControllerInterface& ciface)
SetDefaultDevice(default_device_string);
}
}
+
+void EmulatedController::SetInputOverrideFunction(InputOverrideFunction override_func)
+{
+ m_input_override_function = std::move(override_func);
+}
+
+void EmulatedController::ClearInputOverrideFunction()
+{
+ m_input_override_function = {};
+}
+
} // namespace ControllerEmu
diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h
index 2db991eb82..e7e957e608 100644
--- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h
+++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h
@@ -15,12 +15,18 @@
#include "Common/IniFile.h"
#include "Common/MathUtil.h"
#include "InputCommon/ControlReference/ExpressionParser.h"
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
#include "InputCommon/ControllerInterface/CoreDevice.h"
class ControllerInterface;
-const char* const named_directions[] = {_trans("Up"), _trans("Down"), _trans("Left"),
- _trans("Right")};
+constexpr const char* DIRECTION_UP = _trans("Up");
+constexpr const char* DIRECTION_DOWN = _trans("Down");
+constexpr const char* DIRECTION_LEFT = _trans("Left");
+constexpr const char* DIRECTION_RIGHT = _trans("Right");
+
+constexpr const char* named_directions[] = {DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT,
+ DIRECTION_RIGHT};
class ControlReference;
@@ -184,6 +190,9 @@ public:
void SetDefaultDevice(const std::string& device);
void SetDefaultDevice(ciface::Core::DeviceQualifier devq);
+ void SetInputOverrideFunction(InputOverrideFunction override_func);
+ void ClearInputOverrideFunction();
+
void UpdateReferences(const ControllerInterface& devi);
void UpdateSingleControlReference(const ControllerInterface& devi, ControlReference* ref);
@@ -200,7 +209,7 @@ public:
std::vector<std::unique_ptr<ControlGroup>> groups;
- // Maps a float from -1.0..+1.0 to an integer of the provided values.
+ // Maps a float from -1.0..+1.0 to an integer in the provided range.
template <typename T, typename F>
static T MapFloat(F input_value, T zero_value, T neg_1_value = std::numeric_limits<T>::min(),
T pos_1_value = std::numeric_limits<T>::max())
@@ -223,11 +232,28 @@ public:
return T(std::llround((zero_value - neg_1_value) * input_value + zero_value));
}
+ // The inverse of the function above.
+ // Maps an integer in the provided range to a float in the range -1.0..1.0.
+ template <typename F, typename T>
+ static F MapToFloat(T input_value, T zero_value, T neg_1_value = std::numeric_limits<T>::min(),
+ T pos_1_value = std::numeric_limits<T>::max())
+ {
+ static_assert(std::is_integral<T>(), "T is only sane for int types.");
+ static_assert(std::is_floating_point<F>(), "F is only sane for float types.");
+
+ if (input_value >= zero_value)
+ return F(input_value - zero_value) / F(pos_1_value - zero_value);
+ else
+ return -F(zero_value - input_value) / F(zero_value - neg_1_value);
+ }
+
protected:
// TODO: Wiimote attachments actually end up using their parent controller value for this,
// so theirs won't be used (and thus shouldn't even exist).
ciface::ExpressionParser::ControlEnvironment::VariableContainer m_expression_vars;
+ InputOverrideFunction m_input_override_function;
+
void UpdateReferences(ciface::ExpressionParser::ControlEnvironment& env);
private:
diff --git a/Source/Core/InputCommon/ControllerEmu/StickGate.h b/Source/Core/InputCommon/ControllerEmu/StickGate.h
index 528aa4a5c8..831762fda3 100644
--- a/Source/Core/InputCommon/ControllerEmu/StickGate.h
+++ b/Source/Core/InputCommon/ControllerEmu/StickGate.h
@@ -106,6 +106,10 @@ public:
const ReshapeData& GetCenter() const;
void SetCenter(ReshapeData center);
+ static constexpr const char* X_INPUT_OVERRIDE = "X";
+ static constexpr const char* Y_INPUT_OVERRIDE = "Y";
+ static constexpr const char* Z_INPUT_OVERRIDE = "Z";
+
protected:
ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0,
ControlState clamp = 1.0) const;
diff --git a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp
index 7b15f92de9..d55284a65a 100644
--- a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp
+++ b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.cpp
@@ -9,23 +9,11 @@
#include <unordered_map>
#include <vector>
-#include "Common/Assert.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h"
-#include "Core/Core.h"
-#include "Core/HW/GCPad.h"
-#include "Core/HW/GCPadEmu.h"
-#include "Core/HW/Wiimote.h"
-#include "Core/HW/WiimoteEmu/Extension/Classic.h"
-#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
-#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
-
-#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
-#include "InputCommon/ControllerEmu/StickGate.h"
-
namespace ButtonManager
{
namespace
@@ -700,39 +688,6 @@ float GetAxisValue(int pad_id, ButtonType axis)
return value;
}
-double GetInputRadiusAtAngle(int pad_id, ButtonType stick, double angle)
-{
- // To avoid a crash, don't access controllers before they've been initialized by the boot process
- if (!Core::IsRunningAndStarted())
- return 0;
-
- ControllerEmu::ControlGroup* group;
-
- switch (stick)
- {
- case STICK_MAIN:
- group = Pad::GetGroup(pad_id, PadGroup::MainStick);
- break;
- case STICK_C:
- group = Pad::GetGroup(pad_id, PadGroup::CStick);
- break;
- case NUNCHUK_STICK:
- group = Wiimote::GetNunchukGroup(pad_id, WiimoteEmu::NunchukGroup::Stick);
- break;
- case CLASSIC_STICK_LEFT:
- group = Wiimote::GetClassicGroup(pad_id, WiimoteEmu::ClassicGroup::LeftStick);
- break;
- case CLASSIC_STICK_RIGHT:
- group = Wiimote::GetClassicGroup(pad_id, WiimoteEmu::ClassicGroup::RightStick);
- break;
- default:
- ASSERT(false);
- return 0;
- }
-
- return static_cast<ControllerEmu::ReshapableInput*>(group)->GetInputRadiusAtAngle(angle);
-}
-
bool GamepadEvent(const std::string& dev, int button, int action)
{
auto it = m_controllers.find(dev);
diff --git a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h
index 136d15915f..08c4349c84 100644
--- a/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h
+++ b/Source/Core/InputCommon/ControllerInterface/Touch/ButtonManager.h
@@ -272,9 +272,6 @@ void Init(const std::string&);
bool GetButtonPressed(int pad_id, ButtonType button);
float GetAxisValue(int pad_id, ButtonType axis);
-// emu_pad_id is numbered 0 to 3 for both GC pads and Wiimotes
-double GetInputRadiusAtAngle(int emu_pad_id, ButtonType stick, double angle);
-
bool GamepadEvent(const std::string& dev, int button, int action);
void GamepadAxisEvent(const std::string& dev, int axis, float value);
diff --git a/Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.cpp b/Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.cpp
new file mode 100644
index 0000000000..9ddbaffcd6
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.cpp
@@ -0,0 +1,272 @@
+// Copyright 2021 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include "InputCommon/ControllerInterface/Touch/InputOverrider.h"
+
+#include <array>
+#include <map>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
+
+#include "Common/Assert.h"
+
+#include "Core/HW/GCPad.h"
+#include "Core/HW/GCPadEmu.h"
+#include "Core/HW/Wiimote.h"
+#include "Core/HW/WiimoteEmu/Extension/Classic.h"
+#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
+#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
+
+#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
+#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+#include "InputCommon/ControllerEmu/StickGate.h"
+#include "InputCommon/ControllerInterface/CoreDevice.h"
+#include "InputCommon/InputConfig.h"
+
+namespace ciface::Touch
+{
+namespace
+{
+struct InputState
+{
+ ControlState normal_state = 0;
+ ControlState override_state = 0;
+ bool overriding = false;
+};
+
+using ControlsMap = std::map<std::pair<std::string_view, std::string_view>, ControlID>;
+using StateArray = std::array<InputState, ControlID::NUMBER_OF_CONTROLS>;
+
+std::array<StateArray, 4> s_state_arrays;
+
+const ControlsMap s_gcpad_controls_map = {{
+ {{GCPad::BUTTONS_GROUP, GCPad::A_BUTTON}, ControlID::GCPAD_A_BUTTON},
+ {{GCPad::BUTTONS_GROUP, GCPad::B_BUTTON}, ControlID::GCPAD_B_BUTTON},
+ {{GCPad::BUTTONS_GROUP, GCPad::X_BUTTON}, ControlID::GCPAD_X_BUTTON},
+ {{GCPad::BUTTONS_GROUP, GCPad::Y_BUTTON}, ControlID::GCPAD_Y_BUTTON},
+ {{GCPad::BUTTONS_GROUP, GCPad::Z_BUTTON}, ControlID::GCPAD_Z_BUTTON},
+ {{GCPad::BUTTONS_GROUP, GCPad::START_BUTTON}, ControlID::GCPAD_START_BUTTON},
+ {{GCPad::DPAD_GROUP, DIRECTION_UP}, ControlID::GCPAD_DPAD_UP},
+ {{GCPad::DPAD_GROUP, DIRECTION_DOWN}, ControlID::GCPAD_DPAD_DOWN},
+ {{GCPad::DPAD_GROUP, DIRECTION_LEFT}, ControlID::GCPAD_DPAD_LEFT},
+ {{GCPad::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::GCPAD_DPAD_RIGHT},
+ {{GCPad::TRIGGERS_GROUP, GCPad::L_DIGITAL}, ControlID::GCPAD_L_DIGITAL},
+ {{GCPad::TRIGGERS_GROUP, GCPad::R_DIGITAL}, ControlID::GCPAD_R_DIGITAL},
+ {{GCPad::TRIGGERS_GROUP, GCPad::L_ANALOG}, ControlID::GCPAD_L_ANALOG},
+ {{GCPad::TRIGGERS_GROUP, GCPad::R_ANALOG}, ControlID::GCPAD_R_ANALOG},
+ {{GCPad::MAIN_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
+ ControlID::GCPAD_MAIN_STICK_X},
+ {{GCPad::MAIN_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
+ ControlID::GCPAD_MAIN_STICK_Y},
+ {{GCPad::C_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
+ ControlID::GCPAD_C_STICK_X},
+ {{GCPad::C_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
+ ControlID::GCPAD_C_STICK_Y},
+}};
+
+const ControlsMap s_wiimote_controls_map = {{
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::A_BUTTON},
+ ControlID::WIIMOTE_A_BUTTON},
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::B_BUTTON},
+ ControlID::WIIMOTE_B_BUTTON},
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::ONE_BUTTON},
+ ControlID::WIIMOTE_ONE_BUTTON},
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::TWO_BUTTON},
+ ControlID::WIIMOTE_TWO_BUTTON},
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::PLUS_BUTTON},
+ ControlID::WIIMOTE_PLUS_BUTTON},
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::MINUS_BUTTON},
+ ControlID::WIIMOTE_MINUS_BUTTON},
+ {{WiimoteEmu::Wiimote::BUTTONS_GROUP, WiimoteEmu::Wiimote::HOME_BUTTON},
+ ControlID::WIIMOTE_HOME_BUTTON},
+ {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_UP}, ControlID::WIIMOTE_DPAD_UP},
+ {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_DOWN}, ControlID::WIIMOTE_DPAD_DOWN},
+ {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_LEFT}, ControlID::WIIMOTE_DPAD_LEFT},
+ {{WiimoteEmu::Wiimote::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::WIIMOTE_DPAD_RIGHT},
+ {{WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
+ ControlID::WIIMOTE_IR_X},
+ {{WiimoteEmu::Wiimote::IR_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
+ ControlID::WIIMOTE_IR_Y},
+}};
+
+const ControlsMap s_nunchuk_controls_map = {{
+ {{WiimoteEmu::Nunchuk::BUTTONS_GROUP, WiimoteEmu::Nunchuk::C_BUTTON},
+ ControlID::NUNCHUK_C_BUTTON},
+ {{WiimoteEmu::Nunchuk::BUTTONS_GROUP, WiimoteEmu::Nunchuk::Z_BUTTON},
+ ControlID::NUNCHUK_Z_BUTTON},
+ {{WiimoteEmu::Nunchuk::STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
+ ControlID::NUNCHUK_STICK_X},
+ {{WiimoteEmu::Nunchuk::STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
+ ControlID::NUNCHUK_STICK_Y},
+}};
+
+const ControlsMap s_classic_controls_map = {{
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::A_BUTTON},
+ ControlID::CLASSIC_A_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::B_BUTTON},
+ ControlID::CLASSIC_B_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::X_BUTTON},
+ ControlID::CLASSIC_X_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::Y_BUTTON},
+ ControlID::CLASSIC_Y_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::ZL_BUTTON},
+ ControlID::CLASSIC_ZL_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::ZR_BUTTON},
+ ControlID::CLASSIC_ZR_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::PLUS_BUTTON},
+ ControlID::CLASSIC_PLUS_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::MINUS_BUTTON},
+ ControlID::CLASSIC_MINUS_BUTTON},
+ {{WiimoteEmu::Classic::BUTTONS_GROUP, WiimoteEmu::Classic::HOME_BUTTON},
+ ControlID::CLASSIC_HOME_BUTTON},
+ {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_UP}, ControlID::CLASSIC_DPAD_UP},
+ {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_DOWN}, ControlID::CLASSIC_DPAD_DOWN},
+ {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_LEFT}, ControlID::CLASSIC_DPAD_LEFT},
+ {{WiimoteEmu::Classic::DPAD_GROUP, DIRECTION_RIGHT}, ControlID::CLASSIC_DPAD_RIGHT},
+ {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_DIGITAL},
+ ControlID::CLASSIC_L_DIGITAL},
+ {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_DIGITAL},
+ ControlID::CLASSIC_R_DIGITAL},
+ {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::L_ANALOG},
+ ControlID::CLASSIC_L_ANALOG},
+ {{WiimoteEmu::Classic::TRIGGERS_GROUP, WiimoteEmu::Classic::R_ANALOG},
+ ControlID::CLASSIC_R_ANALOG},
+ {{WiimoteEmu::Classic::LEFT_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
+ ControlID::CLASSIC_LEFT_STICK_X},
+ {{WiimoteEmu::Classic::LEFT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
+ ControlID::CLASSIC_LEFT_STICK_Y},
+ {{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::X_INPUT_OVERRIDE},
+ ControlID::CLASSIC_RIGHT_STICK_X},
+ {{WiimoteEmu::Classic::RIGHT_STICK_GROUP, ControllerEmu::ReshapableInput::Y_INPUT_OVERRIDE},
+ ControlID::CLASSIC_RIGHT_STICK_Y},
+}};
+
+ControllerEmu::InputOverrideFunction GetInputOverrideFunction(const ControlsMap& controls_map,
+ size_t i)
+{
+ StateArray& state_array = s_state_arrays[i];
+
+ return [&](std::string_view group_name, std::string_view control_name,
+ ControlState controller_state) -> std::optional<ControlState> {
+ const auto it = controls_map.find(std::make_pair(group_name, control_name));
+ if (it == controls_map.end())
+ return std::nullopt;
+
+ const ControlID control = it->second;
+ InputState& input_state = state_array[control];
+ if (input_state.normal_state != controller_state)
+ {
+ input_state.normal_state = controller_state;
+ input_state.overriding = false;
+ }
+
+ return input_state.overriding ? std::make_optional(input_state.override_state) : std::nullopt;
+ };
+}
+
+} // namespace
+
+void RegisterGameCubeInputOverrider(int controller_index)
+{
+ Pad::GetConfig()
+ ->GetController(controller_index)
+ ->SetInputOverrideFunction(GetInputOverrideFunction(s_gcpad_controls_map, controller_index));
+}
+
+void RegisterWiiInputOverrider(int controller_index)
+{
+ auto* wiimote =
+ static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(controller_index));
+
+ wiimote->SetInputOverrideFunction(
+ GetInputOverrideFunction(s_wiimote_controls_map, controller_index));
+
+ auto& attachments = static_cast<ControllerEmu::Attachments*>(
+ wiimote->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
+ ->GetAttachmentList();
+
+ attachments[WiimoteEmu::ExtensionNumber::NUNCHUK]->SetInputOverrideFunction(
+ GetInputOverrideFunction(s_nunchuk_controls_map, controller_index));
+ attachments[WiimoteEmu::ExtensionNumber::CLASSIC]->SetInputOverrideFunction(
+ GetInputOverrideFunction(s_classic_controls_map, controller_index));
+}
+
+void UnregisterGameCubeInputOverrider(int controller_index)
+{
+ Pad::GetConfig()->GetController(controller_index)->ClearInputOverrideFunction();
+
+ for (size_t i = ControlID::FIRST_GC_CONTROL; i <= ControlID::LAST_GC_CONTROL; ++i)
+ s_state_arrays[controller_index][i].overriding = false;
+}
+
+void UnregisterWiiInputOverrider(int controller_index)
+{
+ auto* wiimote =
+ static_cast<WiimoteEmu::Wiimote*>(Wiimote::GetConfig()->GetController(controller_index));
+
+ wiimote->ClearInputOverrideFunction();
+
+ auto& attachments = static_cast<ControllerEmu::Attachments*>(
+ wiimote->GetWiimoteGroup(WiimoteEmu::WiimoteGroup::Attachments))
+ ->GetAttachmentList();
+
+ attachments[WiimoteEmu::ExtensionNumber::NUNCHUK]->ClearInputOverrideFunction();
+ attachments[WiimoteEmu::ExtensionNumber::CLASSIC]->ClearInputOverrideFunction();
+
+ for (size_t i = ControlID::FIRST_WII_CONTROL; i <= ControlID::LAST_WII_CONTROL; ++i)
+ s_state_arrays[controller_index][i].overriding = false;
+}
+
+void SetControlState(int controller_index, ControlID control, double state)
+{
+ InputState& input_state = s_state_arrays[controller_index][control];
+
+ input_state.override_state = state;
+ input_state.overriding = true;
+}
+
+void ClearControlState(int controller_index, ControlID control)
+{
+ InputState& input_state = s_state_arrays[controller_index][control];
+
+ input_state.overriding = false;
+}
+
+double GetGateRadiusAtAngle(int controller_index, ControlID stick, double angle)
+{
+ ControllerEmu::ControlGroup* group;
+
+ switch (stick)
+ {
+ case ControlID::GCPAD_MAIN_STICK_X:
+ case ControlID::GCPAD_MAIN_STICK_Y:
+ group = Pad::GetGroup(controller_index, PadGroup::MainStick);
+ break;
+ case ControlID::GCPAD_C_STICK_X:
+ case ControlID::GCPAD_C_STICK_Y:
+ group = Pad::GetGroup(controller_index, PadGroup::CStick);
+ break;
+ case ControlID::NUNCHUK_STICK_X:
+ case ControlID::NUNCHUK_STICK_Y:
+ group = Wiimote::GetNunchukGroup(controller_index, WiimoteEmu::NunchukGroup::Stick);
+ break;
+ case ControlID::CLASSIC_LEFT_STICK_X:
+ case ControlID::CLASSIC_LEFT_STICK_Y:
+ group = Wiimote::GetClassicGroup(controller_index, WiimoteEmu::ClassicGroup::LeftStick);
+ break;
+ case ControlID::CLASSIC_RIGHT_STICK_X:
+ case ControlID::CLASSIC_RIGHT_STICK_Y:
+ group = Wiimote::GetClassicGroup(controller_index, WiimoteEmu::ClassicGroup::RightStick);
+ break;
+ default:
+ ASSERT(false);
+ return 0;
+ }
+
+ return static_cast<ControllerEmu::ReshapableInput*>(group)->GetGateRadiusAtAngle(angle);
+}
+} // namespace ciface::Touch
diff --git a/Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.h b/Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.h
new file mode 100644
index 0000000000..6217b44d4e
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerInterface/Touch/InputOverrider.h
@@ -0,0 +1,89 @@
+// Copyright 2021 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace ciface::Touch
+{
+enum ControlID
+{
+ GCPAD_A_BUTTON = 0,
+ GCPAD_B_BUTTON = 1,
+ GCPAD_X_BUTTON = 2,
+ GCPAD_Y_BUTTON = 3,
+ GCPAD_Z_BUTTON = 4,
+ GCPAD_START_BUTTON = 5,
+ GCPAD_DPAD_UP = 6,
+ GCPAD_DPAD_DOWN = 7,
+ GCPAD_DPAD_LEFT = 8,
+ GCPAD_DPAD_RIGHT = 9,
+ GCPAD_L_DIGITAL = 10,
+ GCPAD_R_DIGITAL = 11,
+ GCPAD_L_ANALOG = 12,
+ GCPAD_R_ANALOG = 13,
+ GCPAD_MAIN_STICK_X = 14,
+ GCPAD_MAIN_STICK_Y = 15,
+ GCPAD_C_STICK_X = 16,
+ GCPAD_C_STICK_Y = 17,
+
+ WIIMOTE_A_BUTTON = 18,
+ WIIMOTE_B_BUTTON = 19,
+ WIIMOTE_ONE_BUTTON = 20,
+ WIIMOTE_TWO_BUTTON = 21,
+ WIIMOTE_PLUS_BUTTON = 22,
+ WIIMOTE_MINUS_BUTTON = 23,
+ WIIMOTE_HOME_BUTTON = 24,
+ WIIMOTE_DPAD_UP = 25,
+ WIIMOTE_DPAD_DOWN = 26,
+ WIIMOTE_DPAD_LEFT = 27,
+ WIIMOTE_DPAD_RIGHT = 28,
+ WIIMOTE_IR_X = 29,
+ WIIMOTE_IR_Y = 30,
+
+ NUNCHUK_C_BUTTON = 31,
+ NUNCHUK_Z_BUTTON = 32,
+ NUNCHUK_STICK_X = 33,
+ NUNCHUK_STICK_Y = 34,
+
+ CLASSIC_A_BUTTON = 35,
+ CLASSIC_B_BUTTON = 36,
+ CLASSIC_X_BUTTON = 37,
+ CLASSIC_Y_BUTTON = 38,
+ CLASSIC_ZL_BUTTON = 39,
+ CLASSIC_ZR_BUTTON = 40,
+ CLASSIC_PLUS_BUTTON = 41,
+ CLASSIC_MINUS_BUTTON = 42,
+ CLASSIC_HOME_BUTTON = 43,
+ CLASSIC_DPAD_UP = 44,
+ CLASSIC_DPAD_DOWN = 45,
+ CLASSIC_DPAD_LEFT = 46,
+ CLASSIC_DPAD_RIGHT = 47,
+ CLASSIC_L_DIGITAL = 48,
+ CLASSIC_R_DIGITAL = 49,
+ CLASSIC_L_ANALOG = 50,
+ CLASSIC_R_ANALOG = 51,
+ CLASSIC_LEFT_STICK_X = 52,
+ CLASSIC_LEFT_STICK_Y = 53,
+ CLASSIC_RIGHT_STICK_X = 54,
+ CLASSIC_RIGHT_STICK_Y = 55,
+
+ NUMBER_OF_CONTROLS,
+
+ FIRST_GC_CONTROL = GCPAD_A_BUTTON,
+ LAST_GC_CONTROL = GCPAD_C_STICK_Y,
+ FIRST_WII_CONTROL = WIIMOTE_A_BUTTON,
+ LAST_WII_CONTROL = CLASSIC_RIGHT_STICK_Y,
+
+};
+void RegisterGameCubeInputOverrider(int controller_index);
+void RegisterWiiInputOverrider(int controller_index);
+void UnregisterGameCubeInputOverrider(int controller_index);
+void UnregisterWiiInputOverrider(int controller_index);
+
+void SetControlState(int controller_index, ControlID control, double state);
+void ClearControlState(int controller_index, ControlID control);
+
+// Angle is in radians and should be non-negative
+double GetGateRadiusAtAngle(int controller_index, ControlID stick, double angle);
+} // namespace ciface::Touch