364 lines
13 KiB
C++
364 lines
13 KiB
C++
#ifndef GAMEPAD_H
|
|
#define GAMEPAD_H
|
|
|
|
#include <cstdint>
|
|
|
|
#include "sdkconfig.h"
|
|
#include "Range.h"
|
|
#include "UserSettings/UserProfile.h"
|
|
#include "UserSettings/UserSettings.h"
|
|
#include "Board/ogxm_log.h"
|
|
|
|
#define MAX_GAMEPADS CONFIG_BLUEPAD32_MAX_DEVICES
|
|
static_assert( MAX_GAMEPADS > 0 &&
|
|
MAX_GAMEPADS <= 4,
|
|
"MAX_GAMEPADS must be between 1 and 4");
|
|
|
|
namespace Gamepad
|
|
{
|
|
static constexpr uint8_t DPAD_UP = 0x01;
|
|
static constexpr uint8_t DPAD_DOWN = 0x02;
|
|
static constexpr uint8_t DPAD_LEFT = 0x04;
|
|
static constexpr uint8_t DPAD_RIGHT = 0x08;
|
|
static constexpr uint8_t DPAD_UP_LEFT = DPAD_UP | DPAD_LEFT;
|
|
static constexpr uint8_t DPAD_UP_RIGHT = DPAD_UP | DPAD_RIGHT;
|
|
static constexpr uint8_t DPAD_DOWN_LEFT = DPAD_DOWN | DPAD_LEFT;
|
|
static constexpr uint8_t DPAD_DOWN_RIGHT = DPAD_DOWN | DPAD_RIGHT;
|
|
static constexpr uint8_t DPAD_NONE = 0x00;
|
|
|
|
static constexpr uint16_t BUTTON_A = 0x0001;
|
|
static constexpr uint16_t BUTTON_B = 0x0002;
|
|
static constexpr uint16_t BUTTON_X = 0x0004;
|
|
static constexpr uint16_t BUTTON_Y = 0x0008;
|
|
static constexpr uint16_t BUTTON_L3 = 0x0010;
|
|
static constexpr uint16_t BUTTON_R3 = 0x0020;
|
|
static constexpr uint16_t BUTTON_BACK = 0x0040;
|
|
static constexpr uint16_t BUTTON_START = 0x0080;
|
|
static constexpr uint16_t BUTTON_LB = 0x0100;
|
|
static constexpr uint16_t BUTTON_RB = 0x0200;
|
|
static constexpr uint16_t BUTTON_SYS = 0x0400;
|
|
static constexpr uint16_t BUTTON_MISC = 0x0800;
|
|
}
|
|
|
|
class GamepadMapper
|
|
{
|
|
public:
|
|
uint8_t DPAD_UP = Gamepad::DPAD_UP ;
|
|
uint8_t DPAD_DOWN = Gamepad::DPAD_DOWN ;
|
|
uint8_t DPAD_LEFT = Gamepad::DPAD_LEFT ;
|
|
uint8_t DPAD_RIGHT = Gamepad::DPAD_RIGHT ;
|
|
uint8_t DPAD_UP_LEFT = Gamepad::DPAD_UP_LEFT ;
|
|
uint8_t DPAD_UP_RIGHT = Gamepad::DPAD_UP_RIGHT ;
|
|
uint8_t DPAD_DOWN_LEFT = Gamepad::DPAD_DOWN_LEFT ;
|
|
uint8_t DPAD_DOWN_RIGHT = Gamepad::DPAD_DOWN_RIGHT;
|
|
uint8_t DPAD_NONE = Gamepad::DPAD_NONE ;
|
|
|
|
uint16_t BUTTON_A = Gamepad::BUTTON_A ;
|
|
uint16_t BUTTON_B = Gamepad::BUTTON_B ;
|
|
uint16_t BUTTON_X = Gamepad::BUTTON_X ;
|
|
uint16_t BUTTON_Y = Gamepad::BUTTON_Y ;
|
|
uint16_t BUTTON_L3 = Gamepad::BUTTON_L3 ;
|
|
uint16_t BUTTON_R3 = Gamepad::BUTTON_R3 ;
|
|
uint16_t BUTTON_BACK = Gamepad::BUTTON_BACK ;
|
|
uint16_t BUTTON_START = Gamepad::BUTTON_START;
|
|
uint16_t BUTTON_LB = Gamepad::BUTTON_LB ;
|
|
uint16_t BUTTON_RB = Gamepad::BUTTON_RB ;
|
|
uint16_t BUTTON_SYS = Gamepad::BUTTON_SYS ;
|
|
uint16_t BUTTON_MISC = Gamepad::BUTTON_MISC ;
|
|
|
|
GamepadMapper() = default;
|
|
~GamepadMapper() = default;
|
|
|
|
void set_profile(const UserProfile& profile)
|
|
{
|
|
set_profile_options(profile);
|
|
set_profile_mappings(profile);
|
|
set_profile_deadzones(profile);
|
|
}
|
|
|
|
/* Get joy value adjusted for deadzones, scaling, and inversion settings.
|
|
<bits> param is optional, used for scaling specific bit values as opposed
|
|
to full range values. */
|
|
template <uint8_t bits = 0, typename T>
|
|
inline int16_t scale_joystick_rx(T value) const
|
|
{
|
|
int16_t joy_value = 0;
|
|
if constexpr (bits > 0)
|
|
{
|
|
joy_value = Range::scale_from_bits<int16_t, bits>(value);
|
|
}
|
|
else if constexpr (!std::is_same_v<T, int16_t>)
|
|
{
|
|
joy_value = Range::scale<int16_t>(value);
|
|
}
|
|
else
|
|
{
|
|
joy_value = value;
|
|
}
|
|
if (joy_value > dz_.joystick_r_pos)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
dz_.joystick_r_pos,
|
|
Range::MAX<int16_t>,
|
|
Range::MID<int16_t>,
|
|
Range::MAX<int16_t>);
|
|
}
|
|
else if (joy_value < dz_.joystick_r_neg)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
Range::MIN<int16_t>,
|
|
dz_.joystick_r_neg,
|
|
Range::MIN<int16_t>,
|
|
Range::MID<int16_t>);
|
|
}
|
|
else
|
|
{
|
|
joy_value = 0;
|
|
}
|
|
return joy_value;
|
|
}
|
|
|
|
/* Get joy value adjusted for deadzones, scaling, and inversion settings.
|
|
<bits> param is optional, used for scaling specific bit values as opposed
|
|
to full range values. */
|
|
template <uint8_t bits = 0, typename T>
|
|
inline int16_t scale_joystick_ry(T value, bool invert = false) const
|
|
{
|
|
int16_t joy_value = 0;
|
|
if constexpr (bits > 0)
|
|
{
|
|
joy_value = Range::scale_from_bits<int16_t, bits>(value);
|
|
}
|
|
else if constexpr (!std::is_same_v<T, int16_t>)
|
|
{
|
|
joy_value = Range::scale<int16_t>(value);
|
|
}
|
|
else
|
|
{
|
|
joy_value = value;
|
|
}
|
|
if (joy_value > dz_.joystick_r_pos)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
dz_.joystick_r_pos,
|
|
Range::MAX<int16_t>,
|
|
Range::MID<int16_t>,
|
|
Range::MAX<int16_t>);
|
|
}
|
|
else if (joy_value < dz_.joystick_r_neg)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
Range::MIN<int16_t>,
|
|
dz_.joystick_r_neg,
|
|
Range::MIN<int16_t>,
|
|
Range::MID<int16_t>);
|
|
}
|
|
else
|
|
{
|
|
joy_value = 0;
|
|
}
|
|
return profile_invert_ry_ ? (invert ? joy_value : Range::invert(joy_value)) : (invert ? Range::invert(joy_value) : joy_value);
|
|
}
|
|
|
|
/* Get joy value adjusted for deadzones, scaling, and inversion settings.
|
|
<bits> param is optional, used for scaling specific bit values as opposed
|
|
to full range values. */
|
|
template <uint8_t bits = 0, typename T>
|
|
inline int16_t scale_joystick_lx(T value) const
|
|
{
|
|
int16_t joy_value = 0;
|
|
if constexpr (bits > 0)
|
|
{
|
|
joy_value = Range::scale_from_bits<int16_t, bits>(value);
|
|
}
|
|
else if constexpr (!std::is_same_v<T, int16_t>)
|
|
{
|
|
joy_value = Range::scale<int16_t>(value);
|
|
}
|
|
else
|
|
{
|
|
joy_value = value;
|
|
}
|
|
if (joy_value > dz_.joystick_l_pos)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
dz_.joystick_l_pos,
|
|
Range::MAX<int16_t>,
|
|
Range::MID<int16_t>,
|
|
Range::MAX<int16_t>);
|
|
}
|
|
else if (joy_value < dz_.joystick_l_neg)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
Range::MIN<int16_t>,
|
|
dz_.joystick_l_neg,
|
|
Range::MIN<int16_t>,
|
|
Range::MID<int16_t>);
|
|
}
|
|
else
|
|
{
|
|
joy_value = 0;
|
|
}
|
|
return joy_value;
|
|
}
|
|
|
|
/* Get joy value adjusted for deadzones, scaling, and inversion settings.
|
|
<bits> param is optional, used for scaling specific bit values as opposed
|
|
to full range values. */
|
|
template <uint8_t bits = 0, typename T>
|
|
inline int16_t scale_joystick_ly(T value, bool invert = false) const
|
|
{
|
|
int16_t joy_value = 0;
|
|
if constexpr (bits > 0)
|
|
{
|
|
joy_value = Range::scale_from_bits<int16_t, bits>(value);
|
|
}
|
|
else if constexpr (!std::is_same_v<T, int16_t>)
|
|
{
|
|
joy_value = Range::scale<int16_t>(value);
|
|
}
|
|
else
|
|
{
|
|
joy_value = value;
|
|
}
|
|
if (joy_value > dz_.joystick_l_pos)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
dz_.joystick_l_pos,
|
|
Range::MAX<int16_t>,
|
|
Range::MID<int16_t>,
|
|
Range::MAX<int16_t>);
|
|
}
|
|
else if (joy_value < dz_.joystick_l_neg)
|
|
{
|
|
joy_value = Range::scale(
|
|
joy_value,
|
|
Range::MIN<int16_t>,
|
|
dz_.joystick_l_neg,
|
|
Range::MIN<int16_t>,
|
|
Range::MID<int16_t>);
|
|
}
|
|
else
|
|
{
|
|
joy_value = 0;
|
|
}
|
|
return profile_invert_ly_ ? (invert ? joy_value : Range::invert(joy_value)) : (invert ? Range::invert(joy_value) : joy_value);
|
|
}
|
|
|
|
/* Get trigger value adjusted for deadzones, scaling, and inversion.
|
|
<bits> param is optional, used for scaling speicifc bit values
|
|
as opposed to full range values */
|
|
template <uint8_t bits = 0, typename T>
|
|
inline uint8_t scale_trigger_l(T value) const
|
|
{
|
|
uint8_t trigger_value = 0;
|
|
if constexpr (bits > 0)
|
|
{
|
|
trigger_value = Range::scale_from_bits<uint8_t, bits>(value);
|
|
}
|
|
else if constexpr (!std::is_same_v<T, uint8_t>)
|
|
{
|
|
trigger_value = Range::scale<uint8_t>(value);
|
|
}
|
|
else
|
|
{
|
|
trigger_value = value;
|
|
}
|
|
return trigger_value > dz_.trigger_l ? Range::scale(trigger_value, dz_.trigger_l, Range::MAX<uint8_t>) : 0;
|
|
}
|
|
|
|
/* Get trigger value adjusted for deadzones, scaling, and inversion.
|
|
<bits> param is optional, used for scaling speicifc bit values
|
|
as opposed to full range values */
|
|
template <uint8_t bits = 0, typename T>
|
|
inline uint8_t scale_trigger_r(T value) const
|
|
{
|
|
uint8_t trigger_value = 0;
|
|
if constexpr (bits > 0)
|
|
{
|
|
trigger_value = Range::scale_from_bits<uint8_t, bits>(value);
|
|
}
|
|
else if constexpr (!std::is_same_v<T, uint8_t>)
|
|
{
|
|
trigger_value = Range::scale<uint8_t>(value);
|
|
}
|
|
else
|
|
{
|
|
trigger_value = value;
|
|
}
|
|
return trigger_value > dz_.trigger_l ? Range::scale(trigger_value, dz_.trigger_l, Range::MAX<uint8_t>) : 0;
|
|
}
|
|
|
|
private:
|
|
bool profile_invert_ly_{false};
|
|
bool profile_invert_ry_{false};
|
|
|
|
struct Deadzones
|
|
{
|
|
uint8_t trigger_l{0};
|
|
uint8_t trigger_r{0};
|
|
int16_t joystick_l_neg{0};
|
|
int16_t joystick_l_pos{0};
|
|
int16_t joystick_r_neg{0};
|
|
int16_t joystick_r_pos{0};
|
|
} dz_;
|
|
|
|
void set_profile_options(const UserProfile& profile)
|
|
{
|
|
profile_invert_ly_ = profile.invert_ly ? true : false;
|
|
profile_invert_ry_ = profile.invert_ry ? true : false;
|
|
}
|
|
|
|
void set_profile_mappings(const UserProfile& profile)
|
|
{
|
|
DPAD_UP = profile.dpad_up;
|
|
DPAD_DOWN = profile.dpad_down;
|
|
DPAD_LEFT = profile.dpad_left;
|
|
DPAD_RIGHT = profile.dpad_right;
|
|
DPAD_UP_LEFT = profile.dpad_up | profile.dpad_left;
|
|
DPAD_UP_RIGHT = profile.dpad_up | profile.dpad_right;
|
|
DPAD_DOWN_LEFT = profile.dpad_down | profile.dpad_left;
|
|
DPAD_DOWN_RIGHT = profile.dpad_down | profile.dpad_right;
|
|
DPAD_NONE = 0;
|
|
|
|
BUTTON_A = profile.button_a;
|
|
BUTTON_B = profile.button_b;
|
|
BUTTON_X = profile.button_x;
|
|
BUTTON_Y = profile.button_y;
|
|
BUTTON_L3 = profile.button_l3;
|
|
BUTTON_R3 = profile.button_r3;
|
|
BUTTON_BACK = profile.button_back;
|
|
BUTTON_START = profile.button_start;
|
|
BUTTON_LB = profile.button_lb;
|
|
BUTTON_RB = profile.button_rb;
|
|
BUTTON_SYS = profile.button_sys;
|
|
BUTTON_MISC = profile.button_misc;
|
|
|
|
OGXM_LOG("Mappings: A: %i B: %i X: %i Y: %i L3: %i R3: %i BACK: %i START: %i LB: %i RB: %i SYS: %i MISC: %i\n",
|
|
BUTTON_A, BUTTON_B, BUTTON_X, BUTTON_Y, BUTTON_L3, BUTTON_R3, BUTTON_BACK, BUTTON_START, BUTTON_LB, BUTTON_RB, BUTTON_SYS, BUTTON_MISC);
|
|
}
|
|
|
|
void set_profile_deadzones(const UserProfile& profile) //Deadzones in the profile are 0-255 (0-100%)
|
|
{
|
|
dz_.trigger_l = profile.dz_trigger_l;
|
|
dz_.trigger_r = profile.dz_trigger_r;
|
|
|
|
dz_.joystick_l_pos = profile.dz_joystick_l ? Range::scale<int16_t>(static_cast<int8_t>(profile.dz_joystick_l / 2)) : 0;
|
|
dz_.joystick_l_neg = Range::invert(dz_.joystick_l_pos);
|
|
dz_.joystick_r_pos = profile.dz_joystick_r ? Range::scale<int16_t>(static_cast<int8_t>(profile.dz_joystick_r / 2)) : 0;
|
|
dz_.joystick_r_neg = Range::invert(dz_.joystick_r_pos);
|
|
|
|
OGXM_LOG("Deadzones: TL: %i TR: %i JL: %i JR: %i\n",
|
|
dz_.trigger_l, dz_.trigger_r, dz_.joystick_l_pos, dz_.joystick_r_pos);
|
|
}
|
|
|
|
}; // class GamepadMapper
|
|
|
|
#endif // GAMEPAD_H
|