Cemu/src/input/api/Wiimote/NativeWiimoteController.cpp
2024-05-06 03:27:30 +02:00

244 lines
6.2 KiB
C++

#include "input/api/Wiimote/NativeWiimoteController.h"
#include "input/api/Wiimote/WiimoteControllerProvider.h"
#include <pugixml.hpp>
NativeWiimoteController::NativeWiimoteController(size_t index)
: base_type(fmt::format("{}", index), fmt::format("Controller {}", index + 1)), m_index(index)
{
m_settings.motion = true;
}
void NativeWiimoteController::save(pugi::xml_node& node)
{
base_type::save(node);
node.append_child("packet_delay").append_child(pugi::node_pcdata).set_value(
fmt::format("{}", m_packet_delay).c_str());
}
void NativeWiimoteController::load(const pugi::xml_node& node)
{
base_type::load(node);
if (const auto value = node.child("packet_delay"))
m_packet_delay = ConvertString<uint32>(value.child_value());
}
bool NativeWiimoteController::connect()
{
if (is_connected())
return true;
if (!m_provider->is_registered_device(m_index))
{
m_provider->get_controllers();
}
if (m_provider->is_connected(m_index))
{
m_provider->set_packet_delay(m_index, m_packet_delay);
m_provider->set_led(m_index, m_player_index);
return true;
}
return false;
}
bool NativeWiimoteController::is_connected()
{
if (m_provider->is_connected(m_index))
{
m_provider->set_packet_delay(m_index, m_packet_delay);
return true;
}
return false;
}
void NativeWiimoteController::set_player_index(size_t player_index)
{
m_player_index = player_index;
m_provider->set_led(m_index, m_player_index);
}
NativeWiimoteController::Extension NativeWiimoteController::get_extension() const
{
Extension result = None;
const auto ext = m_provider->get_state(m_index).m_extension;
if (std::holds_alternative<NunchuckData>(ext))
result = Nunchuck;
else if (std::holds_alternative<ClassicData>(ext))
result = Classic;
return result;
}
bool NativeWiimoteController::is_mpls_attached() const
{
return m_provider->get_state(m_index).m_motion_plus.has_value();
}
bool NativeWiimoteController::has_position()
{
const auto state = m_provider->get_state(m_index);
return std::any_of(state.ir_camera.dots.cbegin(), state.ir_camera.dots.cend(),
[](const IRDot& v) { return v.visible; });
}
glm::vec2 NativeWiimoteController::get_position()
{
const auto state = m_provider->get_state(m_index);
return state.ir_camera.position;
}
glm::vec2 NativeWiimoteController::get_prev_position()
{
const auto state = m_provider->get_state(m_index);
return state.ir_camera.m_prev_position;
}
PositionVisibility NativeWiimoteController::GetPositionVisibility()
{
const auto state = m_provider->get_state(m_index);
return state.ir_camera.m_positionVisibility;
}
bool NativeWiimoteController::has_low_battery()
{
const auto state = m_provider->get_state(m_index);
return HAS_FLAG(state.flags, kBatteryEmpty);
}
void NativeWiimoteController::start_rumble()
{
if (m_settings.rumble < 1.0f)
{
return;
}
m_provider->set_rumble(m_index, true);
}
void NativeWiimoteController::stop_rumble()
{
m_provider->set_rumble(m_index, false);
}
MotionSample NativeWiimoteController::get_motion_sample()
{
const auto state = m_provider->get_state(m_index);
return state.motion_sample;
}
MotionSample NativeWiimoteController::get_nunchuck_motion_sample() const
{
const auto state = m_provider->get_state(m_index);
if (std::holds_alternative<NunchuckData>(state.m_extension))
{
return std::get<NunchuckData>(state.m_extension).motion_sample;
}
return {};
}
std::string NativeWiimoteController::get_button_name(uint64 button) const
{
switch (button)
{
case kWiimoteButton_A: return "A";
case kWiimoteButton_B: return "B";
case kWiimoteButton_One: return "1";
case kWiimoteButton_Two: return "2";
case kWiimoteButton_Plus: return "+";
case kWiimoteButton_Minus: return "-";
case kWiimoteButton_Home: return "HOME";
case kWiimoteButton_Up: return "UP";
case kWiimoteButton_Down: return "DOWN";
case kWiimoteButton_Left: return "LEFT";
case kWiimoteButton_Right: return "RIGHT";
// nunchuck
case kWiimoteButton_C: return "C";
case kWiimoteButton_Z: return "Z";
// classic
case kHighestWiimote + kClassicButton_A: return "A";
case kHighestWiimote + kClassicButton_B: return "B";
case kHighestWiimote + kClassicButton_Y: return "Y";
case kHighestWiimote + kClassicButton_X: return "X";
case kHighestWiimote + kClassicButton_Plus: return "+";
case kHighestWiimote + kClassicButton_Minus: return "-";
case kHighestWiimote + kClassicButton_Home: return "HOME";
case kHighestWiimote + kClassicButton_Up: return "UP";
case kHighestWiimote + kClassicButton_Down: return "DOWN";
case kHighestWiimote + kClassicButton_Left: return "LEFT";
case kHighestWiimote + kClassicButton_Right: return "RIGHT";
case kHighestWiimote + kClassicButton_L: return "L";
case kHighestWiimote + kClassicButton_R: return "R";
case kHighestWiimote + kClassicButton_ZL: return "ZL";
case kHighestWiimote + kClassicButton_ZR: return "ZR";
}
return base_type::get_button_name(button);
}
uint32 NativeWiimoteController::get_packet_delay()
{
m_packet_delay = m_provider->get_packet_delay(m_index);
return m_packet_delay;
}
void NativeWiimoteController::set_packet_delay(uint32 delay)
{
m_packet_delay = delay;
m_provider->set_packet_delay(m_index, delay);
}
ControllerState NativeWiimoteController::raw_state()
{
ControllerState result{};
if (!is_connected())
return result;
const auto state = m_provider->get_state(m_index);
for (int i = 0; i < std::numeric_limits<uint16>::digits; i++)
result.buttons.SetButtonState(i, (state.buttons & (1 << i)) != 0);
if (std::holds_alternative<NunchuckData>(state.m_extension))
{
const auto nunchuck = std::get<NunchuckData>(state.m_extension);
if (nunchuck.c)
result.buttons.SetButtonState(kWiimoteButton_C, true);
if (nunchuck.z)
result.buttons.SetButtonState(kWiimoteButton_Z, true);
result.axis = nunchuck.axis;
}
else if (std::holds_alternative<ClassicData>(state.m_extension))
{
const auto classic = std::get<ClassicData>(state.m_extension);
uint64 buttons = (uint64)classic.buttons << kHighestWiimote;
for (int i = 0; i < std::numeric_limits<uint64>::digits; i++)
{
// OR with base buttons
if((buttons & (1 << i)))
result.buttons.SetButtonState(i, true);
}
result.axis = classic.left_axis;
result.rotation = classic.right_axis;
result.trigger = classic.trigger;
}
return result;
}