diff --git a/Source/Core/Core/HW/GCPadEmu.cpp b/Source/Core/Core/HW/GCPadEmu.cpp index c0d6836f7d..a797e32fa3 100644 --- a/Source/Core/Core/HW/GCPadEmu.cpp +++ b/Source/Core/Core/HW/GCPadEmu.cpp @@ -68,7 +68,7 @@ GCPad::GCPad(const unsigned int index) : m_index(index) groups.emplace_back(m_main_stick = new ControllerEmu::OctagonAnalogStick( "Main Stick", _trans("Control Stick"), main_gate_radius)); - constexpr auto c_gate_radius = ControlState(C_STICK_GATE_RADIUS) / GCPadStatus::MAIN_STICK_RADIUS; + constexpr auto c_gate_radius = ControlState(C_STICK_GATE_RADIUS) / GCPadStatus::C_STICK_RADIUS; groups.emplace_back(m_c_stick = new ControllerEmu::OctagonAnalogStick( "C-Stick", _trans("C Stick"), c_gate_radius)); @@ -160,23 +160,19 @@ GCPadStatus GCPad::GetInput() const m_dpad->GetState(&pad.button, dpad_bitmasks); // sticks - const ControllerEmu::AnalogStick::StateData main_stick_state = m_main_stick->GetState(); - pad.stickX = static_cast(GCPadStatus::MAIN_STICK_CENTER_X + - (main_stick_state.x * GCPadStatus::MAIN_STICK_RADIUS)); - pad.stickY = static_cast(GCPadStatus::MAIN_STICK_CENTER_Y + - (main_stick_state.y * GCPadStatus::MAIN_STICK_RADIUS)); + const auto main_stick_state = m_main_stick->GetState(); + pad.stickX = MapFloat(main_stick_state.x, GCPadStatus::MAIN_STICK_CENTER_X); + pad.stickY = MapFloat(main_stick_state.y, GCPadStatus::MAIN_STICK_CENTER_Y); - const ControllerEmu::AnalogStick::StateData c_stick_state = m_c_stick->GetState(); - pad.substickX = static_cast(GCPadStatus::C_STICK_CENTER_X + - (c_stick_state.x * GCPadStatus::C_STICK_RADIUS)); - pad.substickY = static_cast(GCPadStatus::C_STICK_CENTER_Y + - (c_stick_state.y * GCPadStatus::C_STICK_RADIUS)); + const auto c_stick_state = m_c_stick->GetState(); + pad.substickX = MapFloat(c_stick_state.x, GCPadStatus::C_STICK_CENTER_X); + pad.substickY = MapFloat(c_stick_state.y, GCPadStatus::C_STICK_CENTER_Y); // triggers std::array triggers; m_triggers->GetState(&pad.button, trigger_bitmasks, triggers.data()); - pad.triggerLeft = static_cast(triggers[0] * 0xFF); - pad.triggerRight = static_cast(triggers[1] * 0xFF); + pad.triggerLeft = MapFloat(triggers[0], 0); + pad.triggerRight = MapFloat(triggers[1], 0); return pad; } diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h index 4f734e2824..1cc9f5fd1e 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h @@ -4,9 +4,11 @@ #pragma once +#include #include #include #include +#include #include #include "Common/Common.h" @@ -50,6 +52,29 @@ public: std::vector> groups; + // Maps a float from -1.0..+1.0 to an integer of the provided values. + template + static T MapFloat(F input_value, T zero_value, T neg_1_value = std::numeric_limits::min(), + T pos_1_value = std::numeric_limits::max()) + { + static_assert(std::is_integral(), "T is only sane for int types."); + static_assert(std::is_floating_point(), "F is only sane for float types."); + + static_assert(std::numeric_limits::min() <= std::numeric_limits::min() && + std::numeric_limits::max() >= std::numeric_limits::max(), + "long is not a superset of T. use of std::lround is not sane."); + + // Here we round when converting from float to int. + // After applying our deadzone, resizing, and reshaping math + // we sometimes have a near-zero value which is slightly negative. (e.g. -0.0001) + // Casting would round down but rounding will yield our "zero_value". + + if (input_value > 0) + return T(std::lround((pos_1_value - zero_value) * input_value + zero_value)); + else + return T(std::lround((zero_value - neg_1_value) * input_value + zero_value)); + } + private: ciface::Core::DeviceQualifier m_default_device; bool m_default_device_is_connected{false};