mirror of
https://github.com/stenzek/duckstation.git
synced 2026-10-29 13:08:21 +01:00
NeGcon: Create common base class for NeGcon controllers
And move common logic into base class.
This commit is contained in:
13 files changed
+600
-405
No files matched your search
@@ -5,6 +5,7 @@ add_executable(core-tests
|
||||
cheats_tests.cpp
|
||||
cpu_disasm_tests.cpp
|
||||
lightgun_controller_tests.cpp
|
||||
negcon_base_tests.cpp
|
||||
spu_tests.cpp
|
||||
stub_host.cpp
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<ClCompile Include="cheats_tests.cpp" />
|
||||
<ClCompile Include="cpu_disasm_tests.cpp" />
|
||||
<ClCompile Include="lightgun_controller_tests.cpp" />
|
||||
<ClCompile Include="negcon_base_tests.cpp" />
|
||||
<ClCompile Include="spu_tests.cpp" />
|
||||
<ClCompile Include="stub_host.cpp" />
|
||||
</ItemGroup>
|
||||
@@ -43,4 +44,4 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="..\..\dep\vsprops\Targets.props" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -6,6 +6,8 @@
|
||||
<ClCompile Include="cpu_disasm_tests.cpp" />
|
||||
<ClCompile Include="stub_host.cpp" />
|
||||
<ClCompile Include="spu_tests.cpp" />
|
||||
<ClCompile Include="lightgun_controller_tests.cpp" />
|
||||
<ClCompile Include="negcon_base_tests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "core/negcon.h"
|
||||
#include "core/negcon_base.h"
|
||||
#include "core/negcon_rumble.h"
|
||||
#include "core/save_state_version.h"
|
||||
|
||||
#include "util/ini_settings_interface.h"
|
||||
#include "util/state_wrapper.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <gtest/gtest.h>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
static_assert(std::is_base_of_v<NegConBase, NeGcon>);
|
||||
static_assert(std::is_base_of_v<NegConBase, NeGconRumble>);
|
||||
static_assert(static_cast<u32>(NeGcon::Button::Count) == 8);
|
||||
static_assert(static_cast<u32>(NeGconRumble::Button::Analog) == 8);
|
||||
static_assert(static_cast<u32>(NeGconRumble::Button::Count) == 9);
|
||||
|
||||
static const Controller::ControllerBindingInfo* FindBinding(const Controller::ControllerInfo& info,
|
||||
std::string_view name);
|
||||
static bool HasSetting(const Controller::ControllerInfo& info, std::string_view name);
|
||||
|
||||
TEST(NegConBase, BindingIndices)
|
||||
{
|
||||
const Controller::ControllerBindingInfo* negcon_steering_left = FindBinding(NeGcon::INFO, "SteeringLeft");
|
||||
const Controller::ControllerBindingInfo* rumble_analog = FindBinding(NeGconRumble::INFO, "Analog");
|
||||
const Controller::ControllerBindingInfo* rumble_steering_left = FindBinding(NeGconRumble::INFO, "SteeringLeft");
|
||||
const Controller::ControllerBindingInfo* rumble_large_motor = FindBinding(NeGconRumble::INFO, "LargeMotor");
|
||||
const Controller::ControllerBindingInfo* rumble_mode_led = FindBinding(NeGconRumble::INFO, "ModeLED");
|
||||
|
||||
ASSERT_NE(negcon_steering_left, nullptr);
|
||||
ASSERT_NE(rumble_analog, nullptr);
|
||||
ASSERT_NE(rumble_steering_left, nullptr);
|
||||
ASSERT_NE(rumble_large_motor, nullptr);
|
||||
ASSERT_NE(rumble_mode_led, nullptr);
|
||||
EXPECT_EQ(negcon_steering_left->bind_index, 8u);
|
||||
EXPECT_EQ(rumble_analog->bind_index, 8u);
|
||||
EXPECT_EQ(rumble_steering_left->bind_index, 9u);
|
||||
EXPECT_EQ(rumble_large_motor->bind_index, 14u);
|
||||
EXPECT_EQ(rumble_mode_led->bind_index, 16u);
|
||||
}
|
||||
|
||||
TEST(NegConBase, CommonButtonMappings)
|
||||
{
|
||||
NeGcon negcon(0);
|
||||
NeGconRumble rumble(0);
|
||||
|
||||
negcon.SetBindState(static_cast<u32>(NeGcon::Button::Up), 1.0f);
|
||||
negcon.SetBindState(static_cast<u32>(NeGcon::Button::A), 1.0f);
|
||||
rumble.SetBindState(static_cast<u32>(NeGconRumble::Button::Up), 1.0f);
|
||||
rumble.SetBindState(static_cast<u32>(NeGconRumble::Button::A), 1.0f);
|
||||
|
||||
EXPECT_EQ(negcon.GetButtonStateBits(), UINT16_C(0x2010));
|
||||
EXPECT_EQ(rumble.GetButtonStateBits(), UINT16_C(0x2010));
|
||||
EXPECT_EQ(negcon.GetBindState(static_cast<u32>(NeGcon::Button::Up)), 1.0f);
|
||||
EXPECT_EQ(rumble.GetBindState(static_cast<u32>(NeGconRumble::Button::Up)), 1.0f);
|
||||
EXPECT_EQ(rumble.GetBindState(static_cast<u32>(NeGconRumble::Button::Analog)), 0.0f);
|
||||
}
|
||||
|
||||
TEST(NegConBase, DefaultAxisModifiers)
|
||||
{
|
||||
NeGcon negcon(0);
|
||||
NeGconRumble rumble(0);
|
||||
constexpr u32 negcon_axis_start = static_cast<u32>(NeGcon::Button::Count);
|
||||
constexpr u32 rumble_axis_start = static_cast<u32>(NeGconRumble::Button::Count);
|
||||
|
||||
negcon.SetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::SteeringRight), 1.0f);
|
||||
rumble.SetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::SteeringRight), 1.0f);
|
||||
negcon.SetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::I), 0.5f);
|
||||
rumble.SetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::I), 0.5f);
|
||||
|
||||
ASSERT_TRUE(negcon.GetAnalogInputBytes().has_value());
|
||||
ASSERT_TRUE(rumble.GetAnalogInputBytes().has_value());
|
||||
EXPECT_EQ(negcon.GetAnalogInputBytes(), rumble.GetAnalogInputBytes());
|
||||
EXPECT_EQ(negcon.GetAnalogInputBytes().value(), UINT32_C(0x000080FF));
|
||||
EXPECT_EQ(negcon.GetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::SteeringRight)), 1.0f);
|
||||
EXPECT_EQ(rumble.GetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::SteeringRight)), 1.0f);
|
||||
}
|
||||
|
||||
TEST(NegConBase, ConfiguredAxisModifiers)
|
||||
{
|
||||
INISettingsInterface si;
|
||||
si.SetFloatValue("Controller", "SteeringDeadzone", 0.2f);
|
||||
si.SetFloatValue("Controller", "SteeringSaturation", 0.8f);
|
||||
si.SetFloatValue("Controller", "SteeringScaling", 0.5f);
|
||||
si.SetFloatValue("Controller", "IDeadzone", 0.1f);
|
||||
si.SetFloatValue("Controller", "ISaturation", 0.9f);
|
||||
si.SetFloatValue("Controller", "ILinearity", 0.69314718f);
|
||||
si.SetFloatValue("Controller", "IScaling", 0.5f);
|
||||
si.SetFloatValue("Controller", "IIDeadzone", 0.25f);
|
||||
si.SetFloatValue("Controller", "IISaturation", 0.75f);
|
||||
si.SetFloatValue("Controller", "LDeadzone", 0.0f);
|
||||
si.SetFloatValue("Controller", "LSaturation", 0.5f);
|
||||
si.SetFloatValue("Controller", "LScaling", 0.25f);
|
||||
|
||||
NeGcon negcon(0);
|
||||
NeGconRumble rumble(0);
|
||||
negcon.LoadSettings(si, "Controller", true);
|
||||
rumble.LoadSettings(si, "Controller", true);
|
||||
|
||||
constexpr u32 negcon_axis_start = static_cast<u32>(NeGcon::Button::Count);
|
||||
constexpr u32 rumble_axis_start = static_cast<u32>(NeGconRumble::Button::Count);
|
||||
negcon.SetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::SteeringRight), 0.5f);
|
||||
rumble.SetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::SteeringRight), 0.5f);
|
||||
negcon.SetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::I), 0.5f);
|
||||
rumble.SetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::I), 0.5f);
|
||||
negcon.SetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::II), 0.5f);
|
||||
rumble.SetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::II), 0.5f);
|
||||
negcon.SetBindState(negcon_axis_start + static_cast<u32>(NeGcon::HalfAxis::L), 0.5f);
|
||||
rumble.SetBindState(rumble_axis_start + static_cast<u32>(NeGconRumble::HalfAxis::L), 0.5f);
|
||||
|
||||
ASSERT_TRUE(negcon.GetAnalogInputBytes().has_value());
|
||||
ASSERT_TRUE(rumble.GetAnalogInputBytes().has_value());
|
||||
EXPECT_EQ(negcon.GetAnalogInputBytes(), rumble.GetAnalogInputBytes());
|
||||
EXPECT_EQ(negcon.GetAnalogInputBytes().value(), UINT32_C(0x408020A0));
|
||||
}
|
||||
|
||||
TEST(NegConBase, RumbleSettings)
|
||||
{
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "SteeringDeadzone"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "SteeringSaturation"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "SteeringLinearity"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "SteeringScaling"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "IDeadzone"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "ISaturation"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "ILinearity"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "IScaling"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "IIDeadzone"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "IISaturation"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "IILinearity"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "IIScaling"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "LDeadzone"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "LSaturation"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "LLinearity"));
|
||||
EXPECT_TRUE(HasSetting(NeGconRumble::INFO, "LScaling"));
|
||||
EXPECT_FALSE(HasSetting(NeGconRumble::INFO, "SteeringSensitivity"));
|
||||
}
|
||||
|
||||
TEST(NegConBase, DeviceStateLayouts)
|
||||
{
|
||||
std::array<u8, 64> state_data = {};
|
||||
|
||||
NeGcon negcon(0);
|
||||
negcon.SetBindState(static_cast<u32>(NeGcon::Button::A), 1.0f);
|
||||
StateWrapper negcon_sw(std::span<u8>(state_data), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
|
||||
ASSERT_TRUE(negcon.DoState(negcon_sw, true));
|
||||
ASSERT_FALSE(negcon_sw.HasError());
|
||||
EXPECT_EQ(negcon_sw.GetPosition(), 3u);
|
||||
|
||||
u16 negcon_buttons;
|
||||
std::memcpy(&negcon_buttons, state_data.data(), sizeof(negcon_buttons));
|
||||
EXPECT_EQ(negcon_buttons, UINT16_C(0xDFFF));
|
||||
|
||||
state_data.fill(0);
|
||||
NeGconRumble rumble(0);
|
||||
rumble.SetBindState(static_cast<u32>(NeGconRumble::Button::A), 1.0f);
|
||||
StateWrapper rumble_sw(std::span<u8>(state_data), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
|
||||
ASSERT_TRUE(rumble.DoState(rumble_sw, true));
|
||||
ASSERT_FALSE(rumble_sw.HasError());
|
||||
EXPECT_EQ(rumble_sw.GetPosition(), 24u);
|
||||
|
||||
u16 rumble_buttons;
|
||||
std::memcpy(&rumble_buttons, &state_data[4], sizeof(rumble_buttons));
|
||||
EXPECT_EQ(rumble_buttons, UINT16_C(0xDFFF));
|
||||
|
||||
std::array<u8, 6> legacy_state_data = {};
|
||||
NeGconRumble legacy_rumble(0);
|
||||
legacy_rumble.SetBindState(static_cast<u32>(NeGconRumble::Button::A), 1.0f);
|
||||
StateWrapper legacy_rumble_sw(std::span<const u8>(legacy_state_data), StateWrapper::Mode::Read, 43);
|
||||
ASSERT_TRUE(legacy_rumble.DoState(legacy_rumble_sw, true));
|
||||
ASSERT_FALSE(legacy_rumble_sw.HasError());
|
||||
EXPECT_EQ(legacy_rumble_sw.GetPosition(), legacy_state_data.size());
|
||||
EXPECT_EQ(legacy_rumble.GetButtonStateBits(), 0u);
|
||||
}
|
||||
|
||||
TEST(NegConBase, DeviceProtocols)
|
||||
{
|
||||
NeGcon negcon(0);
|
||||
negcon.SetBindState(static_cast<u32>(NeGcon::Button::A), 1.0f);
|
||||
|
||||
u8 data_out;
|
||||
EXPECT_TRUE(negcon.Transfer(0x01, &data_out));
|
||||
EXPECT_EQ(data_out, 0xFF);
|
||||
EXPECT_TRUE(negcon.Transfer(0x42, &data_out));
|
||||
EXPECT_EQ(data_out, 0x23);
|
||||
EXPECT_TRUE(negcon.Transfer(0x00, &data_out));
|
||||
EXPECT_EQ(data_out, 0x5A);
|
||||
EXPECT_TRUE(negcon.Transfer(0x00, &data_out));
|
||||
EXPECT_EQ(data_out, 0xFF);
|
||||
EXPECT_TRUE(negcon.Transfer(0x00, &data_out));
|
||||
EXPECT_EQ(data_out, 0xDF);
|
||||
|
||||
NeGconRumble rumble(0);
|
||||
rumble.SetBindState(static_cast<u32>(NeGconRumble::Button::A), 1.0f);
|
||||
EXPECT_TRUE(rumble.Transfer(0x01, &data_out));
|
||||
EXPECT_EQ(data_out, 0xFF);
|
||||
EXPECT_TRUE(rumble.Transfer(0x42, &data_out));
|
||||
EXPECT_EQ(data_out, 0x41);
|
||||
EXPECT_TRUE(rumble.Transfer(0x00, &data_out));
|
||||
EXPECT_EQ(data_out, 0x5A);
|
||||
EXPECT_TRUE(rumble.Transfer(0x00, &data_out));
|
||||
EXPECT_EQ(data_out, 0xFF);
|
||||
EXPECT_FALSE(rumble.Transfer(0x00, &data_out));
|
||||
EXPECT_EQ(data_out, 0xDF);
|
||||
}
|
||||
|
||||
const Controller::ControllerBindingInfo* FindBinding(const Controller::ControllerInfo& info, std::string_view name)
|
||||
{
|
||||
for (const Controller::ControllerBindingInfo& binding : info.bindings)
|
||||
{
|
||||
if (name == binding.name)
|
||||
return &binding;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool HasSetting(const Controller::ControllerInfo& info, std::string_view name)
|
||||
{
|
||||
for (const SettingInfo& setting : info.settings)
|
||||
{
|
||||
if (name == setting.name)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -116,6 +116,8 @@ add_library(core
|
||||
multitap.h
|
||||
negcon.cpp
|
||||
negcon.h
|
||||
negcon_base.cpp
|
||||
negcon_base.h
|
||||
negcon_rumble.cpp
|
||||
negcon_rumble.h
|
||||
pad.cpp
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
<ClCompile Include="multitap.cpp" />
|
||||
<ClCompile Include="guncon.cpp" />
|
||||
<ClCompile Include="negcon.cpp" />
|
||||
<ClCompile Include="negcon_base.cpp" />
|
||||
<ClCompile Include="negcon_rumble.cpp" />
|
||||
<ClCompile Include="pad.cpp" />
|
||||
<ClCompile Include="controller.cpp" />
|
||||
@@ -164,6 +165,7 @@
|
||||
<ClInclude Include="multitap.h" />
|
||||
<ClInclude Include="guncon.h" />
|
||||
<ClInclude Include="negcon.h" />
|
||||
<ClInclude Include="negcon_base.h" />
|
||||
<ClInclude Include="negcon_rumble.h" />
|
||||
<ClInclude Include="pad.h" />
|
||||
<ClInclude Include="controller.h" />
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<ClCompile Include="guncon.cpp" />
|
||||
<ClCompile Include="playstation_mouse.cpp" />
|
||||
<ClCompile Include="negcon.cpp" />
|
||||
<ClCompile Include="negcon_base.cpp" />
|
||||
<ClCompile Include="cpu_pgxp.cpp" />
|
||||
<ClCompile Include="cheats.cpp" />
|
||||
<ClCompile Include="memory_card_image.cpp" />
|
||||
@@ -112,6 +113,7 @@
|
||||
<ClInclude Include="guncon.h" />
|
||||
<ClInclude Include="playstation_mouse.h" />
|
||||
<ClInclude Include="negcon.h" />
|
||||
<ClInclude Include="negcon_base.h" />
|
||||
<ClInclude Include="gte_types.h" />
|
||||
<ClInclude Include="cpu_pgxp.h" />
|
||||
<ClInclude Include="cpu_core_private.h" />
|
||||
|
||||
+1
-160
@@ -3,29 +3,17 @@
|
||||
|
||||
#include "negcon.h"
|
||||
#include "controller_helpers.h"
|
||||
#include "host.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "util/state_wrapper.h"
|
||||
#include "util/translation.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/bitutils.h"
|
||||
#include "common/log.h"
|
||||
#include "common/settings_interface.h"
|
||||
|
||||
#include "IconsPromptFont.h"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
// Mapping of Button to index of corresponding bit in m_button_state
|
||||
static constexpr std::array<u8, static_cast<size_t>(NeGcon::Button::Count)> s_button_indices = {3, 4, 5, 6,
|
||||
7, 11, 12, 13};
|
||||
NeGcon::NeGcon(u32 index) : Controller(index)
|
||||
NeGcon::NeGcon(u32 index) : NegConBase(index, static_cast<u32>(Button::Count))
|
||||
{
|
||||
m_axis_state.fill(0x00);
|
||||
m_axis_state[static_cast<u8>(Axis::Steering)] = 0x80;
|
||||
}
|
||||
|
||||
NeGcon::~NeGcon() = default;
|
||||
@@ -51,116 +39,6 @@ bool NeGcon::DoState(StateWrapper& sw, bool apply_input_state)
|
||||
return true;
|
||||
}
|
||||
|
||||
float NeGcon::GetBindState(u32 index) const
|
||||
{
|
||||
if (index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringLeft)) ||
|
||||
index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringRight)))
|
||||
{
|
||||
float value = m_axis_state[static_cast<u32>(Axis::Steering)];
|
||||
value = value - 128.0f;
|
||||
value /= value < 0.0f ? 128.0f : 127.0f;
|
||||
value = std::clamp(value, -1.0f, 1.0f);
|
||||
if (index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringLeft)))
|
||||
{
|
||||
value *= -1.0f;
|
||||
}
|
||||
return std::max(0.0f, value);
|
||||
}
|
||||
else if (index >= static_cast<u32>(Button::Count))
|
||||
{
|
||||
// less one because of the two steering axes
|
||||
const u32 sub_index = index - (static_cast<u32>(Button::Count) + 1);
|
||||
if (sub_index >= m_axis_state.size())
|
||||
return 0.0f;
|
||||
|
||||
return static_cast<float>(m_axis_state[sub_index]) * (1.0f / 255.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 bit = s_button_indices[index];
|
||||
return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u);
|
||||
}
|
||||
}
|
||||
|
||||
static float apply_axis_modifier(float value, const NeGcon::AxisModifier& axis_modifier)
|
||||
{
|
||||
value = (value - axis_modifier.deadzone) / (axis_modifier.saturation - axis_modifier.deadzone);
|
||||
value = std::clamp(value, 0.0f, 1.0f);
|
||||
value = std::pow(value, std::exp(axis_modifier.linearity));
|
||||
return value;
|
||||
}
|
||||
|
||||
static u8 get_scaled_value(float value, const NeGcon::AxisModifier& axis_modifier)
|
||||
{
|
||||
value = axis_modifier.scaling * axis_modifier.unit * value + axis_modifier.zero;
|
||||
return static_cast<u8>(std::clamp(std::round(value), 0.0f, 255.0f));
|
||||
}
|
||||
|
||||
void NeGcon::SetBindState(u32 index, float value)
|
||||
{
|
||||
// Steering Axis: -1..1 -> 0..255
|
||||
if (index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringLeft)) ||
|
||||
index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringRight)))
|
||||
{
|
||||
value = apply_axis_modifier(value, m_steering_modifier);
|
||||
|
||||
m_half_axis_state[index - static_cast<u32>(Button::Count)] = std::clamp(value, 0.0f, 1.0f);
|
||||
|
||||
float merged = m_half_axis_state[1] - m_half_axis_state[0];
|
||||
m_axis_state[static_cast<u32>(Axis::Steering)] = get_scaled_value(merged, m_steering_modifier);
|
||||
}
|
||||
else if (index >= static_cast<u32>(Button::Count))
|
||||
{
|
||||
// less one because of the two steering axes
|
||||
const u32 sub_index = index - (static_cast<u32>(Button::Count) + 1);
|
||||
if (sub_index >= m_axis_state.size())
|
||||
return;
|
||||
|
||||
if (index >= (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::I)) &&
|
||||
index <= (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::L)))
|
||||
{
|
||||
const AxisModifier& axis_modifier =
|
||||
m_half_axis_modifiers[index - (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::I))];
|
||||
value = apply_axis_modifier(value, axis_modifier);
|
||||
m_axis_state[sub_index] = get_scaled_value(value, axis_modifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_axis_state[sub_index] = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
|
||||
}
|
||||
}
|
||||
else if (index < static_cast<u32>(Button::Count))
|
||||
{
|
||||
const u16 bit = u16(1) << s_button_indices[static_cast<u8>(index)];
|
||||
|
||||
if (value >= 0.5f)
|
||||
{
|
||||
if (m_button_state & bit)
|
||||
System::SetRunaheadReplayFlag(false);
|
||||
|
||||
m_button_state &= ~bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(m_button_state & bit))
|
||||
System::SetRunaheadReplayFlag(false);
|
||||
|
||||
m_button_state |= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 NeGcon::GetButtonStateBits() const
|
||||
{
|
||||
return m_button_state ^ 0xFFFF;
|
||||
}
|
||||
|
||||
std::optional<u32> NeGcon::GetAnalogInputBytes() const
|
||||
{
|
||||
return m_axis_state[static_cast<size_t>(Axis::L)] << 24 | m_axis_state[static_cast<size_t>(Axis::II)] << 16 |
|
||||
m_axis_state[static_cast<size_t>(Axis::I)] << 8 | m_axis_state[static_cast<size_t>(Axis::Steering)];
|
||||
}
|
||||
|
||||
void NeGcon::ResetTransferState()
|
||||
{
|
||||
m_transfer_state = TransferState::Idle;
|
||||
@@ -337,40 +215,3 @@ const Controller::ControllerInfo NeGcon::INFO = {ControllerType::NeGcon,
|
||||
"images/controllers/negcon.svg",
|
||||
s_binding_info,
|
||||
s_settings};
|
||||
|
||||
void NeGcon::LoadSettings(const SettingsInterface& si, const char* section, bool initial)
|
||||
{
|
||||
m_disable_socd = si.GetBoolValue(section, "DisableSOCD", false);
|
||||
m_steering_modifier = {
|
||||
.deadzone = si.GetFloatValue(section, "SteeringDeadzone", DEFAULT_STEERING_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "SteeringSaturation", DEFAULT_STEERING_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "SteeringLinearity", DEFAULT_STEERING_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "SteeringScaling", DEFAULT_STEERING_MODIFIER.scaling),
|
||||
.zero = DEFAULT_STEERING_MODIFIER.zero,
|
||||
.unit = DEFAULT_STEERING_MODIFIER.unit,
|
||||
};
|
||||
m_half_axis_modifiers[0] = {
|
||||
.deadzone = si.GetFloatValue(section, "IDeadzone", DEFAULT_PEDAL_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "ISaturation", DEFAULT_PEDAL_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "ILinearity", DEFAULT_PEDAL_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "IScaling", DEFAULT_PEDAL_MODIFIER.scaling),
|
||||
.zero = DEFAULT_PEDAL_MODIFIER.zero,
|
||||
.unit = DEFAULT_PEDAL_MODIFIER.unit,
|
||||
};
|
||||
m_half_axis_modifiers[1] = {
|
||||
.deadzone = si.GetFloatValue(section, "IIDeadzone", DEFAULT_PEDAL_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "IISaturation", DEFAULT_PEDAL_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "IILinearity", DEFAULT_PEDAL_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "IIScaling", DEFAULT_PEDAL_MODIFIER.scaling),
|
||||
.zero = DEFAULT_PEDAL_MODIFIER.zero,
|
||||
.unit = DEFAULT_PEDAL_MODIFIER.unit,
|
||||
};
|
||||
m_half_axis_modifiers[2] = {
|
||||
.deadzone = si.GetFloatValue(section, "LDeadzone", DEFAULT_PEDAL_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "LSaturation", DEFAULT_PEDAL_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "LLinearity", DEFAULT_PEDAL_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "LScaling", DEFAULT_PEDAL_MODIFIER.scaling),
|
||||
.zero = DEFAULT_PEDAL_MODIFIER.zero,
|
||||
.unit = DEFAULT_PEDAL_MODIFIER.unit,
|
||||
};
|
||||
}
|
||||
+2
-95
@@ -3,82 +3,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "controller.h"
|
||||
#include "negcon_base.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
class NeGcon final : public Controller
|
||||
class NeGcon final : public NegConBase
|
||||
{
|
||||
public:
|
||||
enum class Axis : u8
|
||||
{
|
||||
Steering = 0,
|
||||
I = 1,
|
||||
II = 2,
|
||||
L = 3,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class Button : u8
|
||||
{
|
||||
Start = 0,
|
||||
Up = 1,
|
||||
Right = 2,
|
||||
Down = 3,
|
||||
Left = 4,
|
||||
R = 5,
|
||||
B = 6,
|
||||
A = 7,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class HalfAxis : u8
|
||||
{
|
||||
SteeringLeft,
|
||||
SteeringRight,
|
||||
I,
|
||||
II,
|
||||
L,
|
||||
Count
|
||||
};
|
||||
|
||||
struct AxisModifier
|
||||
{
|
||||
float deadzone;
|
||||
float saturation;
|
||||
float linearity;
|
||||
float scaling;
|
||||
float zero;
|
||||
float unit;
|
||||
};
|
||||
|
||||
static constexpr float DEFAULT_DEADZONE = 0.00f;
|
||||
static constexpr float DEFAULT_SATURATION = 1.00f;
|
||||
static constexpr float DEFAULT_LINEARITY = 0.00f;
|
||||
static constexpr float DEFAULT_SCALING = 1.00f;
|
||||
static constexpr float DEFAULT_STEERING_ZERO = 128.0f;
|
||||
static constexpr float DEFAULT_STEERING_UNIT = 128.0f;
|
||||
static constexpr float DEFAULT_PEDAL_ZERO = 0.0f;
|
||||
static constexpr float DEFAULT_PEDAL_UNIT = 255.0f;
|
||||
static constexpr AxisModifier DEFAULT_STEERING_MODIFIER = {
|
||||
.deadzone = DEFAULT_DEADZONE,
|
||||
.saturation = DEFAULT_SATURATION,
|
||||
.linearity = DEFAULT_LINEARITY,
|
||||
.scaling = DEFAULT_SCALING,
|
||||
.zero = DEFAULT_STEERING_ZERO,
|
||||
.unit = DEFAULT_STEERING_UNIT,
|
||||
};
|
||||
static constexpr AxisModifier DEFAULT_PEDAL_MODIFIER = {
|
||||
.deadzone = DEFAULT_DEADZONE,
|
||||
.saturation = DEFAULT_SATURATION,
|
||||
.linearity = DEFAULT_LINEARITY,
|
||||
.scaling = DEFAULT_SCALING,
|
||||
.zero = DEFAULT_PEDAL_ZERO,
|
||||
.unit = DEFAULT_PEDAL_UNIT,
|
||||
};
|
||||
|
||||
static const Controller::ControllerInfo INFO;
|
||||
|
||||
explicit NeGcon(u32 index);
|
||||
@@ -91,17 +22,9 @@ public:
|
||||
void Reset() override;
|
||||
bool DoState(StateWrapper& sw, bool apply_input_state) override;
|
||||
|
||||
float GetBindState(u32 index) const override;
|
||||
void SetBindState(u32 index, float value) override;
|
||||
|
||||
void ResetTransferState() override;
|
||||
bool Transfer(const u8 data_in, u8* data_out) override;
|
||||
|
||||
u32 GetButtonStateBits() const override;
|
||||
std::optional<u32> GetAnalogInputBytes() const override;
|
||||
|
||||
void LoadSettings(const SettingsInterface& si, const char* section, bool initial) override;
|
||||
|
||||
private:
|
||||
enum class TransferState : u8
|
||||
{
|
||||
@@ -116,21 +39,5 @@ private:
|
||||
AnalogL
|
||||
};
|
||||
|
||||
std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{};
|
||||
|
||||
// steering, merged to m_axis_state
|
||||
std::array<float, 2> m_half_axis_state;
|
||||
|
||||
// buttons are active low; bits 0-2, 8-10, 14-15 are not used and are always high
|
||||
u16 m_button_state = UINT16_C(0xFFFF);
|
||||
|
||||
TransferState m_transfer_state = TransferState::Idle;
|
||||
bool m_disable_socd = false;
|
||||
|
||||
AxisModifier m_steering_modifier = DEFAULT_STEERING_MODIFIER;
|
||||
std::array<AxisModifier, 3> m_half_axis_modifiers = {
|
||||
DEFAULT_PEDAL_MODIFIER,
|
||||
DEFAULT_PEDAL_MODIFIER,
|
||||
DEFAULT_PEDAL_MODIFIER,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "negcon_base.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "common/settings_interface.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
// Mapping of Button to index of corresponding bit in m_button_state
|
||||
static constexpr std::array<u8, static_cast<size_t>(NegConBase::Button::Count)> s_button_indices = {3, 4, 5, 6,
|
||||
7, 11, 12, 13};
|
||||
|
||||
static float ApplyAxisModifier(float value, const NegConBase::AxisModifier& axis_modifier);
|
||||
static u8 GetScaledValue(float value, const NegConBase::AxisModifier& axis_modifier);
|
||||
|
||||
NegConBase::NegConBase(u32 index, u32 half_axis_bind_start)
|
||||
: Controller(index), m_half_axis_bind_start(half_axis_bind_start)
|
||||
{
|
||||
m_axis_state.fill(0x00);
|
||||
m_axis_state[static_cast<u8>(Axis::Steering)] = 0x80;
|
||||
}
|
||||
|
||||
NegConBase::~NegConBase() = default;
|
||||
|
||||
float NegConBase::GetBindState(u32 index) const
|
||||
{
|
||||
if (index == (m_half_axis_bind_start + static_cast<u32>(HalfAxis::SteeringLeft)) ||
|
||||
index == (m_half_axis_bind_start + static_cast<u32>(HalfAxis::SteeringRight)))
|
||||
{
|
||||
float value = m_axis_state[static_cast<u32>(Axis::Steering)];
|
||||
value = value - 128.0f;
|
||||
value /= value < 0.0f ? 128.0f : 127.0f;
|
||||
value = std::clamp(value, -1.0f, 1.0f);
|
||||
if (index == (m_half_axis_bind_start + static_cast<u32>(HalfAxis::SteeringLeft)))
|
||||
value *= -1.0f;
|
||||
|
||||
return std::max(0.0f, value);
|
||||
}
|
||||
else if (index >= m_half_axis_bind_start)
|
||||
{
|
||||
// less one because of the two steering axes
|
||||
const u32 sub_index = index - (m_half_axis_bind_start + 1);
|
||||
if (sub_index >= m_axis_state.size())
|
||||
return 0.0f;
|
||||
|
||||
return static_cast<float>(m_axis_state[sub_index]) * (1.0f / 255.0f);
|
||||
}
|
||||
else if (index < static_cast<u32>(Button::Count))
|
||||
{
|
||||
const u32 bit = s_button_indices[index];
|
||||
return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void NegConBase::SetBindState(u32 index, float value)
|
||||
{
|
||||
// Steering Axis: -1..1 -> 0..255
|
||||
if (index == (m_half_axis_bind_start + static_cast<u32>(HalfAxis::SteeringLeft)) ||
|
||||
index == (m_half_axis_bind_start + static_cast<u32>(HalfAxis::SteeringRight)))
|
||||
{
|
||||
value = ApplyAxisModifier(value, m_steering_modifier);
|
||||
|
||||
m_half_axis_state[index - m_half_axis_bind_start] = std::clamp(value, 0.0f, 1.0f);
|
||||
|
||||
const float merged = m_half_axis_state[1] - m_half_axis_state[0];
|
||||
m_axis_state[static_cast<u32>(Axis::Steering)] = GetScaledValue(merged, m_steering_modifier);
|
||||
}
|
||||
else if (index >= m_half_axis_bind_start)
|
||||
{
|
||||
// less one because of the two steering axes
|
||||
const u32 sub_index = index - (m_half_axis_bind_start + 1);
|
||||
if (sub_index >= m_axis_state.size())
|
||||
return;
|
||||
|
||||
if (index >= (m_half_axis_bind_start + static_cast<u32>(HalfAxis::I)) &&
|
||||
index <= (m_half_axis_bind_start + static_cast<u32>(HalfAxis::L)))
|
||||
{
|
||||
const AxisModifier& axis_modifier =
|
||||
m_half_axis_modifiers[index - (m_half_axis_bind_start + static_cast<u32>(HalfAxis::I))];
|
||||
value = ApplyAxisModifier(value, axis_modifier);
|
||||
m_axis_state[sub_index] = GetScaledValue(value, axis_modifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_axis_state[sub_index] = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
|
||||
}
|
||||
}
|
||||
else if (index < static_cast<u32>(Button::Count))
|
||||
{
|
||||
const u16 bit = u16(1) << s_button_indices[static_cast<u8>(index)];
|
||||
|
||||
if (value >= 0.5f)
|
||||
{
|
||||
if (m_button_state & bit)
|
||||
System::SetRunaheadReplayFlag(false);
|
||||
|
||||
m_button_state &= ~bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(m_button_state & bit))
|
||||
System::SetRunaheadReplayFlag(false);
|
||||
|
||||
m_button_state |= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 NegConBase::GetButtonStateBits() const
|
||||
{
|
||||
return m_button_state ^ 0xFFFF;
|
||||
}
|
||||
|
||||
std::optional<u32> NegConBase::GetAnalogInputBytes() const
|
||||
{
|
||||
return m_axis_state[static_cast<size_t>(Axis::L)] << 24 | m_axis_state[static_cast<size_t>(Axis::II)] << 16 |
|
||||
m_axis_state[static_cast<size_t>(Axis::I)] << 8 | m_axis_state[static_cast<size_t>(Axis::Steering)];
|
||||
}
|
||||
|
||||
void NegConBase::LoadSettings(const SettingsInterface& si, const char* section, bool initial)
|
||||
{
|
||||
m_disable_socd = si.GetBoolValue(section, "DisableSOCD", false);
|
||||
m_steering_modifier = {
|
||||
.deadzone = si.GetFloatValue(section, "SteeringDeadzone", DEFAULT_STEERING_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "SteeringSaturation", DEFAULT_STEERING_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "SteeringLinearity", DEFAULT_STEERING_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "SteeringScaling", DEFAULT_STEERING_MODIFIER.scaling),
|
||||
.zero = DEFAULT_STEERING_MODIFIER.zero,
|
||||
.unit = DEFAULT_STEERING_MODIFIER.unit,
|
||||
};
|
||||
m_half_axis_modifiers[0] = {
|
||||
.deadzone = si.GetFloatValue(section, "IDeadzone", DEFAULT_PEDAL_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "ISaturation", DEFAULT_PEDAL_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "ILinearity", DEFAULT_PEDAL_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "IScaling", DEFAULT_PEDAL_MODIFIER.scaling),
|
||||
.zero = DEFAULT_PEDAL_MODIFIER.zero,
|
||||
.unit = DEFAULT_PEDAL_MODIFIER.unit,
|
||||
};
|
||||
m_half_axis_modifiers[1] = {
|
||||
.deadzone = si.GetFloatValue(section, "IIDeadzone", DEFAULT_PEDAL_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "IISaturation", DEFAULT_PEDAL_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "IILinearity", DEFAULT_PEDAL_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "IIScaling", DEFAULT_PEDAL_MODIFIER.scaling),
|
||||
.zero = DEFAULT_PEDAL_MODIFIER.zero,
|
||||
.unit = DEFAULT_PEDAL_MODIFIER.unit,
|
||||
};
|
||||
m_half_axis_modifiers[2] = {
|
||||
.deadzone = si.GetFloatValue(section, "LDeadzone", DEFAULT_PEDAL_MODIFIER.deadzone),
|
||||
.saturation = si.GetFloatValue(section, "LSaturation", DEFAULT_PEDAL_MODIFIER.saturation),
|
||||
.linearity = si.GetFloatValue(section, "LLinearity", DEFAULT_PEDAL_MODIFIER.linearity),
|
||||
.scaling = si.GetFloatValue(section, "LScaling", DEFAULT_PEDAL_MODIFIER.scaling),
|
||||
.zero = DEFAULT_PEDAL_MODIFIER.zero,
|
||||
.unit = DEFAULT_PEDAL_MODIFIER.unit,
|
||||
};
|
||||
}
|
||||
|
||||
float ApplyAxisModifier(float value, const NegConBase::AxisModifier& axis_modifier)
|
||||
{
|
||||
value = (value - axis_modifier.deadzone) / (axis_modifier.saturation - axis_modifier.deadzone);
|
||||
value = std::clamp(value, 0.0f, 1.0f);
|
||||
value = std::pow(value, std::exp(axis_modifier.linearity));
|
||||
return value;
|
||||
}
|
||||
|
||||
u8 GetScaledValue(float value, const NegConBase::AxisModifier& axis_modifier)
|
||||
{
|
||||
value = axis_modifier.scaling * axis_modifier.unit * value + axis_modifier.zero;
|
||||
return static_cast<u8>(std::clamp(std::round(value), 0.0f, 255.0f));
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
class NegConBase : public Controller
|
||||
{
|
||||
public:
|
||||
enum class Axis : u8
|
||||
{
|
||||
Steering = 0,
|
||||
I = 1,
|
||||
II = 2,
|
||||
L = 3,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class Button : u8
|
||||
{
|
||||
Start = 0,
|
||||
Up = 1,
|
||||
Right = 2,
|
||||
Down = 3,
|
||||
Left = 4,
|
||||
R = 5,
|
||||
B = 6,
|
||||
A = 7,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class HalfAxis : u8
|
||||
{
|
||||
SteeringLeft,
|
||||
SteeringRight,
|
||||
I,
|
||||
II,
|
||||
L,
|
||||
Count
|
||||
};
|
||||
|
||||
struct AxisModifier
|
||||
{
|
||||
float deadzone;
|
||||
float saturation;
|
||||
float linearity;
|
||||
float scaling;
|
||||
float zero;
|
||||
float unit;
|
||||
};
|
||||
|
||||
static constexpr float DEFAULT_DEADZONE = 0.00f;
|
||||
static constexpr float DEFAULT_SATURATION = 1.00f;
|
||||
static constexpr float DEFAULT_LINEARITY = 0.00f;
|
||||
static constexpr float DEFAULT_SCALING = 1.00f;
|
||||
static constexpr float DEFAULT_STEERING_ZERO = 128.0f;
|
||||
static constexpr float DEFAULT_STEERING_UNIT = 128.0f;
|
||||
static constexpr float DEFAULT_PEDAL_ZERO = 0.0f;
|
||||
static constexpr float DEFAULT_PEDAL_UNIT = 255.0f;
|
||||
static constexpr AxisModifier DEFAULT_STEERING_MODIFIER = {
|
||||
.deadzone = DEFAULT_DEADZONE,
|
||||
.saturation = DEFAULT_SATURATION,
|
||||
.linearity = DEFAULT_LINEARITY,
|
||||
.scaling = DEFAULT_SCALING,
|
||||
.zero = DEFAULT_STEERING_ZERO,
|
||||
.unit = DEFAULT_STEERING_UNIT,
|
||||
};
|
||||
static constexpr AxisModifier DEFAULT_PEDAL_MODIFIER = {
|
||||
.deadzone = DEFAULT_DEADZONE,
|
||||
.saturation = DEFAULT_SATURATION,
|
||||
.linearity = DEFAULT_LINEARITY,
|
||||
.scaling = DEFAULT_SCALING,
|
||||
.zero = DEFAULT_PEDAL_ZERO,
|
||||
.unit = DEFAULT_PEDAL_UNIT,
|
||||
};
|
||||
|
||||
~NegConBase() override;
|
||||
|
||||
float GetBindState(u32 index) const override;
|
||||
void SetBindState(u32 index, float value) override;
|
||||
|
||||
u32 GetButtonStateBits() const override;
|
||||
std::optional<u32> GetAnalogInputBytes() const override;
|
||||
|
||||
void LoadSettings(const SettingsInterface& si, const char* section, bool initial) override;
|
||||
|
||||
protected:
|
||||
NegConBase(u32 index, u32 half_axis_bind_start);
|
||||
|
||||
std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{};
|
||||
|
||||
// steering, merged to m_axis_state
|
||||
std::array<float, 2> m_half_axis_state{};
|
||||
|
||||
// buttons are active low; bits 0-2, 8-10, 14-15 are not used and are always high
|
||||
u16 m_button_state = UINT16_C(0xFFFF);
|
||||
|
||||
bool m_disable_socd = false;
|
||||
|
||||
private:
|
||||
u32 m_half_axis_bind_start;
|
||||
AxisModifier m_steering_modifier = DEFAULT_STEERING_MODIFIER;
|
||||
std::array<AxisModifier, 3> m_half_axis_modifiers = {
|
||||
DEFAULT_PEDAL_MODIFIER,
|
||||
DEFAULT_PEDAL_MODIFIER,
|
||||
DEFAULT_PEDAL_MODIFIER,
|
||||
};
|
||||
};
|
||||
+62
-111
@@ -3,8 +3,7 @@
|
||||
|
||||
#include "negcon_rumble.h"
|
||||
#include "controller_helpers.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
#include "host.h"
|
||||
|
||||
#include "util/imgui_manager.h"
|
||||
#include "util/input_manager.h"
|
||||
@@ -14,24 +13,19 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/bitutils.h"
|
||||
#include "common/log.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
#include "IconsFontAwesome.h"
|
||||
#include "IconsPromptFont.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
LOG_CHANNEL(Controller);
|
||||
|
||||
// Mapping of Button to index of corresponding bit in m_button_state
|
||||
static constexpr std::array<u8, static_cast<size_t>(NeGconRumble::Button::Count)> s_button_indices = {3, 4, 5, 6,
|
||||
7, 11, 12, 13};
|
||||
NeGconRumble::NeGconRumble(u32 index) : Controller(index)
|
||||
NeGconRumble::NeGconRumble(u32 index) : NegConBase(index, HALFAXIS_BIND_START_INDEX)
|
||||
{
|
||||
m_status_byte = 0x5A;
|
||||
m_axis_state.fill(0x00);
|
||||
m_axis_state[static_cast<u8>(Axis::Steering)] = 0x80;
|
||||
m_rumble_config.fill(0xFF);
|
||||
}
|
||||
|
||||
@@ -120,23 +114,9 @@ float NeGconRumble::GetBindState(u32 index) const
|
||||
{
|
||||
return GetMotorStrength(index - MOTOR_BIND_START_INDEX);
|
||||
}
|
||||
else if (index >= (HALFAXIS_BIND_START_INDEX + static_cast<u32>(HalfAxis::I)))
|
||||
{
|
||||
return static_cast<float>(m_axis_state[index - (HALFAXIS_BIND_START_INDEX + static_cast<u32>(HalfAxis::I)) + 1]) *
|
||||
(1.0f / 255.0f);
|
||||
}
|
||||
else if (index >= HALFAXIS_BIND_START_INDEX)
|
||||
{
|
||||
return static_cast<float>(m_half_axis_state[index - HALFAXIS_BIND_START_INDEX]) * (1.0f / 255.0f);
|
||||
}
|
||||
else if (index < static_cast<u32>(Button::Analog))
|
||||
{
|
||||
const u16 bit = u16(1) << s_button_indices[static_cast<u8>(index)];
|
||||
return BoolToFloat((m_button_state & bit) == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
return NegConBase::GetBindState(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,60 +135,7 @@ void NeGconRumble::SetBindState(u32 index, float value)
|
||||
|
||||
return;
|
||||
}
|
||||
// Steering Axis: -1..1 -> 0..255
|
||||
else if (index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringLeft)) ||
|
||||
index == (static_cast<u32>(Button::Count) + static_cast<u32>(HalfAxis::SteeringRight)))
|
||||
{
|
||||
value *= m_steering_sensitivity;
|
||||
if (value < m_steering_deadzone)
|
||||
value = 0.0f;
|
||||
|
||||
m_half_axis_state[index - static_cast<u32>(Button::Count)] =
|
||||
static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
|
||||
|
||||
m_axis_state[static_cast<u32>(Axis::Steering)] =
|
||||
ControllerHelpers::MergeHalfAxes(m_half_axis_state[static_cast<size_t>(HalfAxis::SteeringLeft)],
|
||||
m_half_axis_state[static_cast<size_t>(HalfAxis::SteeringRight)], false);
|
||||
}
|
||||
else if (index >= static_cast<u32>(Button::Count))
|
||||
{
|
||||
// less one because of the two steering axes
|
||||
const u32 sub_index = index - (static_cast<u32>(Button::Count) + 1);
|
||||
if (sub_index >= m_axis_state.size())
|
||||
return;
|
||||
|
||||
m_axis_state[sub_index] = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
|
||||
}
|
||||
else if (index < static_cast<u32>(Button::Count))
|
||||
{
|
||||
const u16 bit = u16(1) << s_button_indices[static_cast<u8>(index)];
|
||||
|
||||
if (value >= 0.5f)
|
||||
{
|
||||
if (m_button_state & bit)
|
||||
System::SetRunaheadReplayFlag(false);
|
||||
|
||||
m_button_state &= ~bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(m_button_state & bit))
|
||||
System::SetRunaheadReplayFlag(false);
|
||||
|
||||
m_button_state |= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 NeGconRumble::GetButtonStateBits() const
|
||||
{
|
||||
return m_button_state ^ 0xFFFF;
|
||||
}
|
||||
|
||||
std::optional<u32> NeGconRumble::GetAnalogInputBytes() const
|
||||
{
|
||||
return m_axis_state[static_cast<size_t>(Axis::L)] << 24 | m_axis_state[static_cast<size_t>(Axis::II)] << 16 |
|
||||
m_axis_state[static_cast<size_t>(Axis::I)] << 8 | m_axis_state[static_cast<size_t>(Axis::Steering)];
|
||||
NegConBase::SetBindState(index, value);
|
||||
}
|
||||
|
||||
void NeGconRumble::ResetTransferState()
|
||||
@@ -717,25 +644,25 @@ constinit const Controller::ControllerBindingInfo NeGconRumble::s_binding_info[]
|
||||
{name, display_name, icon_name, LED_BIND_START_INDEX + index, InputBindingInfo::Type::LED, genb}
|
||||
|
||||
// clang-format off
|
||||
BUTTON("Up", TRANSLATE_NOOP("NeGconRumble", "D-Pad Up"), ICON_PF_DPAD_UP, NeGconRumble::Button::Up, GenericInputBinding::DPadUp),
|
||||
BUTTON("Right", TRANSLATE_NOOP("NeGconRumble", "D-Pad Right"), ICON_PF_DPAD_RIGHT, NeGconRumble::Button::Right, GenericInputBinding::DPadRight),
|
||||
BUTTON("Down", TRANSLATE_NOOP("NeGconRumble", "D-Pad Down"), ICON_PF_DPAD_DOWN, NeGconRumble::Button::Down, GenericInputBinding::DPadDown),
|
||||
BUTTON("Left", TRANSLATE_NOOP("NeGconRumble", "D-Pad Left"), ICON_PF_DPAD_LEFT, NeGconRumble::Button::Left, GenericInputBinding::DPadLeft),
|
||||
BUTTON("Start", TRANSLATE_NOOP("NeGconRumble", "Start"),ICON_PF_START, NeGconRumble::Button::Start, GenericInputBinding::Start),
|
||||
BUTTON("A", TRANSLATE_NOOP("NeGconRumble", "A Button"), ICON_PF_BUTTON_A, NeGconRumble::Button::A, GenericInputBinding::Circle),
|
||||
BUTTON("B", TRANSLATE_NOOP("NeGconRumble", "B Button"), ICON_PF_BUTTON_B, NeGconRumble::Button::B, GenericInputBinding::Triangle),
|
||||
AXIS("I", TRANSLATE_NOOP("NeGconRumble", "I Button"), ICON_PF_RIGHT_TRIGGER_R2, NeGconRumble::HalfAxis::I, GenericInputBinding::R2),
|
||||
AXIS("II", TRANSLATE_NOOP("NeGconRumble", "II Button"), ICON_PF_LEFT_TRIGGER_L2, NeGconRumble::HalfAxis::II, GenericInputBinding::L2),
|
||||
AXIS("L", TRANSLATE_NOOP("NeGconRumble", "Left Trigger"), ICON_PF_LEFT_ANALOG_LEFT, NeGconRumble::HalfAxis::L, GenericInputBinding::L1),
|
||||
BUTTON("R", TRANSLATE_NOOP("NeGconRumble", "Right Trigger"), ICON_PF_RIGHT_SHOULDER_R1, NeGconRumble::Button::R, GenericInputBinding::R1),
|
||||
AXIS("SteeringLeft", TRANSLATE_NOOP("NeGconRumble", "Steering (Twist) Left"), ICON_PF_LEFT_ANALOG_LEFT, NeGconRumble::HalfAxis::SteeringLeft, GenericInputBinding::LeftStickLeft),
|
||||
AXIS("SteeringRight", TRANSLATE_NOOP("NeGconRumble", "Steering (Twist) Right"), ICON_PF_LEFT_ANALOG_RIGHT, NeGconRumble::HalfAxis::SteeringRight, GenericInputBinding::LeftStickRight),
|
||||
BUTTON("Analog", TRANSLATE_NOOP("NeGconRumble", "Analog Toggle"), ICON_PF_ANALOG_LEFT_RIGHT, NeGconRumble::Button::Analog, GenericInputBinding::System),
|
||||
BUTTON("Up", TRANSLATE_NOOP("NeGcon", "D-Pad Up"), ICON_PF_DPAD_UP, NeGconRumble::Button::Up, GenericInputBinding::DPadUp),
|
||||
BUTTON("Right", TRANSLATE_NOOP("NeGcon", "D-Pad Right"), ICON_PF_DPAD_RIGHT, NeGconRumble::Button::Right, GenericInputBinding::DPadRight),
|
||||
BUTTON("Down", TRANSLATE_NOOP("NeGcon", "D-Pad Down"), ICON_PF_DPAD_DOWN, NeGconRumble::Button::Down, GenericInputBinding::DPadDown),
|
||||
BUTTON("Left", TRANSLATE_NOOP("NeGcon", "D-Pad Left"), ICON_PF_DPAD_LEFT, NeGconRumble::Button::Left, GenericInputBinding::DPadLeft),
|
||||
BUTTON("Start", TRANSLATE_NOOP("NeGcon", "Start"),ICON_PF_START, NeGconRumble::Button::Start, GenericInputBinding::Start),
|
||||
BUTTON("A", TRANSLATE_NOOP("NeGcon", "A Button"), ICON_PF_BUTTON_A, NeGconRumble::Button::A, GenericInputBinding::Circle),
|
||||
BUTTON("B", TRANSLATE_NOOP("NeGcon", "B Button"), ICON_PF_BUTTON_B, NeGconRumble::Button::B, GenericInputBinding::Triangle),
|
||||
AXIS("I", TRANSLATE_NOOP("NeGcon", "I Button"), ICON_PF_BUTTON_ALT_1, NeGconRumble::HalfAxis::I, GenericInputBinding::R2),
|
||||
AXIS("II", TRANSLATE_NOOP("NeGcon", "II Button"), ICON_PF_BUTTON_ALT_2, NeGconRumble::HalfAxis::II, GenericInputBinding::L2),
|
||||
AXIS("L", TRANSLATE_NOOP("NeGcon", "Left Trigger"), ICON_PF_LEFT_TRIGGER_LT, NeGconRumble::HalfAxis::L, GenericInputBinding::L1),
|
||||
BUTTON("R", TRANSLATE_NOOP("NeGcon", "Right Trigger"), ICON_PF_RIGHT_TRIGGER_RT, NeGconRumble::Button::R, GenericInputBinding::R1),
|
||||
AXIS("SteeringLeft", TRANSLATE_NOOP("NeGcon", "Steering (Twist) Left"), ICON_PF_ANALOG_LEFT, NeGconRumble::HalfAxis::SteeringLeft, GenericInputBinding::LeftStickLeft),
|
||||
AXIS("SteeringRight", TRANSLATE_NOOP("NeGcon", "Steering (Twist) Right"), ICON_PF_ANALOG_RIGHT, NeGconRumble::HalfAxis::SteeringRight, GenericInputBinding::LeftStickRight),
|
||||
BUTTON("Analog", TRANSLATE_NOOP("NeGcon", "Analog Toggle"), ICON_PF_ANALOG_LEFT_RIGHT, NeGconRumble::Button::Analog, GenericInputBinding::System),
|
||||
|
||||
MOTOR("LargeMotor", TRANSLATE_NOOP("AnalogController", "Large Motor"), ICON_PF_VIBRATION_L, LargeMotor, GenericInputBinding::LargeMotor),
|
||||
MOTOR("SmallMotor", TRANSLATE_NOOP("AnalogController", "Small Motor"), ICON_PF_VIBRATION, SmallMotor, GenericInputBinding::SmallMotor),
|
||||
MOTOR("LargeMotor", TRANSLATE_NOOP("NeGcon", "Large Motor"), ICON_PF_VIBRATION_L, LargeMotor, GenericInputBinding::LargeMotor),
|
||||
MOTOR("SmallMotor", TRANSLATE_NOOP("NeGcon", "Small Motor"), ICON_PF_VIBRATION, SmallMotor, GenericInputBinding::SmallMotor),
|
||||
|
||||
MODE_LED("ModeLED", TRANSLATE_NOOP("AnalogController", "Mode LED"), ICON_PF_LED, 0, GenericInputBinding::ModeLED),
|
||||
MODE_LED("ModeLED", TRANSLATE_NOOP("NeGcon", "Mode LED"), ICON_PF_LED, 0, GenericInputBinding::ModeLED),
|
||||
// clang-format on
|
||||
|
||||
#undef MOTOR
|
||||
@@ -745,22 +672,48 @@ constinit const Controller::ControllerBindingInfo NeGconRumble::s_binding_info[]
|
||||
|
||||
static constexpr SettingInfo s_settings[] = {
|
||||
{SettingInfo::Type::Boolean, "DisableSOCD",
|
||||
TRANSLATE_NOOP("NeGconRumble", "Disable Simultaneous Opposing Cardinal Directions"),
|
||||
TRANSLATE_NOOP("NeGconRumble", "Prevents concurrent left/right or up/down inputs from being presented to the game."),
|
||||
TRANSLATE_NOOP("NeGcon", "Disable Simultaneous Opposing Cardinal Directions"),
|
||||
TRANSLATE_NOOP("NeGcon", "Prevents concurrent left/right or up/down inputs from being presented to the game."),
|
||||
"false", nullptr, nullptr, nullptr, nullptr, nullptr, 0.0f},
|
||||
{SettingInfo::Type::Float, "SteeringDeadzone", TRANSLATE_NOOP("NeGconRumble", "Steering Axis Deadzone"),
|
||||
TRANSLATE_NOOP("NeGconRumble", "Sets deadzone size for steering axis."), "0", "0", "0.99", "0.01", "%.0f%%", nullptr,
|
||||
100.0f},
|
||||
{SettingInfo::Type::Float, "SteeringSensitivity", TRANSLATE_NOOP("NeGconRumble", "Steering Axis Sensitivity"),
|
||||
TRANSLATE_NOOP("NeGconRumble", "Sets the steering axis scaling factor."), "1", "0.01", "2", "0.01", "%.0f%%",
|
||||
nullptr, 100.0f},
|
||||
{SettingInfo::Type::Integer, "LargeMotorVibrationBias", TRANSLATE_NOOP("NeGconRumble", "Large Motor Vibration Bias"),
|
||||
TRANSLATE_NOOP("NeGconRumble",
|
||||
{SettingInfo::Type::Float, "SteeringDeadzone", TRANSLATE_NOOP("NeGcon", "Steering Axis Deadzone"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets deadzone for steering axis."), "0", "0", "0.99", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "SteeringSaturation", TRANSLATE_NOOP("NeGcon", "Steering Axis Saturation"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets saturation for steering axis."), "1", "0.01", "1", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "SteeringLinearity", TRANSLATE_NOOP("NeGcon", "Steering Axis Linearity"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets linearity for steering axis."), "0", "-2", "2", "0.05", "%.2f", nullptr, 1.0f},
|
||||
{SettingInfo::Type::Float, "SteeringScaling", TRANSLATE_NOOP("NeGcon", "Steering Scaling"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets scaling for steering axis."), "1", "0.01", "10", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "IDeadzone", TRANSLATE_NOOP("NeGcon", "I Button Deadzone"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets deadzone for button I."), "0", "0", "0.99", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "ISaturation", TRANSLATE_NOOP("NeGcon", "I Button Saturation"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets saturation for button I."), "1", "0.01", "1", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "ILinearity", TRANSLATE_NOOP("NeGcon", "I Button Linearity"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets linearity for button I."), "0", "-2", "2", "0.01", "%.2f", nullptr, 1.0f},
|
||||
{SettingInfo::Type::Float, "IScaling", TRANSLATE_NOOP("NeGcon", "I Scaling"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets scaling for button I."), "1", "0.01", "10", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "IIDeadzone", TRANSLATE_NOOP("NeGcon", "II Button Deadzone"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets deadzone for button II."), "0", "0", "0.99", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "IISaturation", TRANSLATE_NOOP("NeGcon", "II Button Saturation"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets saturation for button II."), "1", "0.01", "1", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "IILinearity", TRANSLATE_NOOP("NeGcon", "II Button Linearity"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets linearity for button II."), "0", "-2", "2", "0.01", "%.2f", nullptr, 1.0f},
|
||||
{SettingInfo::Type::Float, "IIScaling", TRANSLATE_NOOP("NeGcon", "II Scaling"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets scaling for button II."), "1", "0.01", "10", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "LDeadzone", TRANSLATE_NOOP("NeGcon", "Left Trigger Deadzone"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets deadzone for left trigger."), "0", "0", "0.99", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "LSaturation", TRANSLATE_NOOP("NeGcon", "Left Trigger Saturation"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets saturation for left trigger."), "1", "0.01", "1", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Float, "LLinearity", TRANSLATE_NOOP("NeGcon", "Left Trigger Linearity"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets linearity for left trigger."), "0", "-2", "2", "0.01", "%.2f", nullptr, 1.0f},
|
||||
{SettingInfo::Type::Float, "LScaling", TRANSLATE_NOOP("NeGcon", "Left Trigger Scaling"),
|
||||
TRANSLATE_NOOP("NeGcon", "Sets scaling for left trigger."), "1", "0.01", "10", "0.01", "%.0f%%", nullptr, 100.0f},
|
||||
{SettingInfo::Type::Integer, "LargeMotorVibrationBias", TRANSLATE_NOOP("NeGcon", "Large Motor Vibration Bias"),
|
||||
TRANSLATE_NOOP("NeGcon",
|
||||
"Sets the bias value for the large vibration motor. If vibration in some games is too weak or not "
|
||||
"functioning, try increasing this value. Negative values will decrease the intensity of vibration."),
|
||||
"8", "-255", "255", "1", "%d", nullptr, 1.0f},
|
||||
{SettingInfo::Type::Integer, "SmallMotorVibrationBias", TRANSLATE_NOOP("NeGconRumble", "Small Motor Vibration Bias"),
|
||||
TRANSLATE_NOOP("NeGconRumble",
|
||||
{SettingInfo::Type::Integer, "SmallMotorVibrationBias", TRANSLATE_NOOP("NeGcon", "Small Motor Vibration Bias"),
|
||||
TRANSLATE_NOOP("NeGcon",
|
||||
"Sets the bias value for the small vibration motor. If vibration in some games is too weak or not "
|
||||
"functioning, try increasing this value. Negative values will decrease the intensity of vibration."),
|
||||
"8", "-255", "255", "1", "%d", nullptr, 1.0f},
|
||||
@@ -776,11 +729,9 @@ const Controller::ControllerInfo NeGconRumble::INFO = {ControllerType::NeGconRum
|
||||
|
||||
void NeGconRumble::LoadSettings(const SettingsInterface& si, const char* section, bool initial)
|
||||
{
|
||||
m_steering_deadzone = si.GetFloatValue(section, "SteeringDeadzone", 0.10f);
|
||||
m_steering_sensitivity = si.GetFloatValue(section, "SteeringSensitivity", 1.00f);
|
||||
m_disable_socd = si.GetBoolValue(section, "DisableSOCD", false);
|
||||
NegConBase::LoadSettings(si, section, initial);
|
||||
m_vibration_bias[0] = static_cast<s16>(
|
||||
std::clamp(si.GetIntValue(section, "LargeMotorVibrationBias", DEFAULT_LARGE_MOTOR_VIBRATION_BIAS), -255, 255));
|
||||
m_vibration_bias[1] = static_cast<s16>(
|
||||
std::clamp(si.GetIntValue(section, "SmallMotorVibrationBias", DEFAULT_SMALL_MOTOR_VIBRATION_BIAS), -255, 255));
|
||||
}
|
||||
}
|
||||
@@ -3,24 +3,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "controller.h"
|
||||
#include "negcon_base.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
class NeGconRumble final : public Controller
|
||||
class NeGconRumble final : public NegConBase
|
||||
{
|
||||
public:
|
||||
enum class Axis : u8
|
||||
{
|
||||
Steering = 0,
|
||||
I = 1,
|
||||
II = 2,
|
||||
L = 3,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class Button : u8
|
||||
{
|
||||
Start = 0,
|
||||
@@ -35,16 +25,6 @@ public:
|
||||
Count
|
||||
};
|
||||
|
||||
enum class HalfAxis : u8
|
||||
{
|
||||
SteeringLeft,
|
||||
SteeringRight,
|
||||
I,
|
||||
II,
|
||||
L,
|
||||
Count
|
||||
};
|
||||
|
||||
static constexpr u8 NUM_MOTORS = 2;
|
||||
|
||||
static const Controller::ControllerInfo INFO;
|
||||
@@ -65,9 +45,6 @@ public:
|
||||
void ResetTransferState() override;
|
||||
bool Transfer(const u8 data_in, u8* data_out) override;
|
||||
|
||||
u32 GetButtonStateBits() const override;
|
||||
std::optional<u32> GetAnalogInputBytes() const override;
|
||||
|
||||
void LoadSettings(const SettingsInterface& si, const char* section, bool initial) override;
|
||||
|
||||
private:
|
||||
@@ -97,27 +74,17 @@ private:
|
||||
static const Controller::ControllerBindingInfo s_binding_info[];
|
||||
|
||||
std::array<s16, NUM_MOTORS> m_vibration_bias{DEFAULT_LARGE_MOTOR_VIBRATION_BIAS, DEFAULT_SMALL_MOTOR_VIBRATION_BIAS};
|
||||
bool m_disable_socd = false;
|
||||
|
||||
bool m_analog_mode = false;
|
||||
bool m_analog_locked = false;
|
||||
bool m_dualshock_enabled = false;
|
||||
bool m_configuration_mode = false;
|
||||
|
||||
std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{};
|
||||
|
||||
enum : u8
|
||||
{
|
||||
LargeMotor = 0,
|
||||
SmallMotor = 1
|
||||
};
|
||||
|
||||
// steering, merged to m_axis_state
|
||||
std::array<u8, 2> m_half_axis_state{};
|
||||
|
||||
// buttons are active low; bits 0-2, 8-10, 14-15 are not used and are always high
|
||||
u16 m_button_state = UINT16_C(0xFFFF);
|
||||
|
||||
MotorState m_motor_state{};
|
||||
|
||||
Command m_command = Command::Idle;
|
||||
@@ -148,7 +115,4 @@ private:
|
||||
float GetMotorStrength(u32 motor) const;
|
||||
void ResetRumbleConfig();
|
||||
void SetMotorStateForConfigIndex(int index, u8 value);
|
||||
|
||||
float m_steering_deadzone = 0.00f;
|
||||
float m_steering_sensitivity = 1.00f;
|
||||
};
|
||||
Reference in new issue
Block a user