mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-04-29 14:59:26 -04:00
201 lines
4.6 KiB
C++
201 lines
4.6 KiB
C++
#pragma once
|
|
|
|
#include "input/InputManager.h"
|
|
#include "input/motion/MotionSample.h"
|
|
|
|
namespace pugi
|
|
{
|
|
class xml_node;
|
|
}
|
|
|
|
enum Buttons2 : uint64
|
|
{
|
|
// General
|
|
kButton0,
|
|
kButton1,
|
|
kButton2,
|
|
kButton3,
|
|
kButton4,
|
|
kButton5,
|
|
kButton6,
|
|
kButton7,
|
|
kButton8,
|
|
kButton9,
|
|
kButton10,
|
|
kButton11,
|
|
kButton12,
|
|
kButton13,
|
|
kButton14,
|
|
kButton15,
|
|
kButton16,
|
|
kButton17,
|
|
kButton18,
|
|
kButton19,
|
|
kButton20,
|
|
kButton21,
|
|
kButton22,
|
|
kButton23,
|
|
kButton24,
|
|
kButton25,
|
|
kButton26,
|
|
kButton27,
|
|
kButton28,
|
|
kButton29,
|
|
kButton30,
|
|
kButton31,
|
|
|
|
// Trigger
|
|
kButtonZL,
|
|
kButtonZR,
|
|
|
|
// DPAD
|
|
kButtonUp,
|
|
kButtonDown,
|
|
kButtonLeft,
|
|
kButtonRight,
|
|
|
|
// positive values
|
|
kAxisXP,
|
|
kAxisYP,
|
|
|
|
kRotationXP,
|
|
kRotationYP,
|
|
|
|
kTriggerXP,
|
|
kTriggerYP,
|
|
|
|
// negative values
|
|
kAxisXN,
|
|
kAxisYN,
|
|
|
|
kRotationXN,
|
|
kRotationYN,
|
|
|
|
kTriggerXN,
|
|
kTriggerYN,
|
|
|
|
kButtonMAX,
|
|
|
|
kButtonNoneAxisMAX = kButtonRight,
|
|
kButtonAxisStart = kAxisXP,
|
|
};
|
|
|
|
class ControllerBase
|
|
{
|
|
public:
|
|
ControllerBase(std::string_view uuid, std::string_view display_name);
|
|
virtual ~ControllerBase() = default;
|
|
|
|
const std::string& uuid() const { return m_uuid; }
|
|
const std::string& display_name() const { return m_display_name; }
|
|
|
|
virtual std::string_view api_name() const = 0;
|
|
virtual InputAPI::Type api() const = 0;
|
|
|
|
virtual void update() {}
|
|
|
|
virtual bool connect() { return is_connected(); }
|
|
virtual bool is_connected() = 0;
|
|
|
|
virtual bool has_battery() { return false; }
|
|
virtual bool has_low_battery() { return false; }
|
|
|
|
const ControllerState& calibrate();
|
|
const ControllerState& update_state();
|
|
const ControllerState& get_state() const { return m_last_state; }
|
|
const ControllerState& get_default_state() { return is_calibrated() ? m_default_state : calibrate(); }
|
|
virtual ControllerState raw_state() = 0;
|
|
|
|
bool is_calibrated() const { return m_is_calibrated; }
|
|
|
|
float get_axis_value(uint64 button) const;
|
|
virtual bool has_axis() const { return true; }
|
|
|
|
bool use_motion() { return has_motion() && m_settings.motion; }
|
|
virtual bool has_motion() { return false; }
|
|
virtual MotionSample get_motion_sample() { return {}; }
|
|
|
|
virtual bool has_position() { return false; }
|
|
virtual glm::vec2 get_position() { return {}; }
|
|
virtual glm::vec2 get_prev_position() { return {}; }
|
|
|
|
virtual bool has_rumble() { return false; }
|
|
virtual void start_rumble() {}
|
|
virtual void stop_rumble() {}
|
|
|
|
virtual std::string get_button_name(uint64 button) const;
|
|
|
|
virtual void save(pugi::xml_node& node){}
|
|
virtual void load(const pugi::xml_node& node){}
|
|
|
|
struct AxisSetting
|
|
{
|
|
AxisSetting(float deadzone = 0.25f) : deadzone(deadzone) {}
|
|
float deadzone;
|
|
float range = 1.0f;
|
|
};
|
|
struct Settings
|
|
{
|
|
AxisSetting axis{}, rotation{}, trigger{};
|
|
float rumble = 0;
|
|
bool motion = false; // only valid when has_motion is true
|
|
};
|
|
Settings get_settings() const;
|
|
void set_settings(const Settings& settings);
|
|
void set_axis_settings(const AxisSetting& settings);
|
|
void set_rotation_settings(const AxisSetting& settings);
|
|
void set_trigger_settings(const AxisSetting& settings);
|
|
void set_rumble(float rumble);
|
|
void set_use_motion(bool state);
|
|
|
|
void apply_axis_setting(glm::vec2& axis, const glm::vec2& default_value, const AxisSetting& setting) const;
|
|
|
|
bool operator==(const ControllerBase& c) const;
|
|
bool operator!=(const ControllerBase& c) const { return !(*this == c); }
|
|
|
|
protected:
|
|
std::string m_uuid;
|
|
std::string m_display_name;
|
|
|
|
ControllerState m_last_state{};
|
|
|
|
bool m_is_calibrated = false;
|
|
ControllerState m_default_state{};
|
|
|
|
mutable std::mutex m_settings_mutex;
|
|
Settings m_settings{};
|
|
};
|
|
|
|
template<class TProvider>
|
|
class Controller : public ControllerBase
|
|
{
|
|
public:
|
|
Controller(std::string_view uuid, std::string_view display_name)
|
|
: ControllerBase(uuid, display_name)
|
|
{
|
|
static_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);
|
|
m_provider = std::dynamic_pointer_cast<TProvider>(InputManager::instance().get_api_provider(TProvider::kAPIType));
|
|
cemu_assert_debug(m_provider != nullptr);
|
|
}
|
|
|
|
Controller(std::string_view uuid, std::string_view display_name, const ControllerProviderSettings& settings)
|
|
: ControllerBase(uuid, display_name)
|
|
{
|
|
static_assert(std::is_base_of_v<ControllerProviderBase, TProvider>);
|
|
m_provider = std::dynamic_pointer_cast<TProvider>(InputManager::instance().get_api_provider(TProvider::kAPIType, settings));
|
|
cemu_assert_debug(m_provider != nullptr);
|
|
}
|
|
|
|
// update provider if settings are different from default provider
|
|
void update_provider(std::shared_ptr<TProvider> provider)
|
|
{
|
|
m_provider = std::move(provider);
|
|
}
|
|
|
|
protected:
|
|
using base_type = Controller<TProvider>;
|
|
std::shared_ptr<TProvider> m_provider;
|
|
};
|
|
|
|
using ControllerPtr = std::shared_ptr<ControllerBase>;
|
|
|