mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
@ -12,446 +12,423 @@
|
||||
|
||||
#include "Common/IniFile.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
|
||||
#define sign(x) ((x)?(x)<0?-1:1:0)
|
||||
#define sign(x) ((x) ? (x) < 0 ? -1 : 1 : 0)
|
||||
|
||||
enum
|
||||
{
|
||||
GROUP_TYPE_OTHER,
|
||||
GROUP_TYPE_STICK,
|
||||
GROUP_TYPE_MIXED_TRIGGERS,
|
||||
GROUP_TYPE_BUTTONS,
|
||||
GROUP_TYPE_FORCE,
|
||||
GROUP_TYPE_EXTENSION,
|
||||
GROUP_TYPE_TILT,
|
||||
GROUP_TYPE_CURSOR,
|
||||
GROUP_TYPE_TRIGGERS,
|
||||
GROUP_TYPE_SLIDER
|
||||
GROUP_TYPE_OTHER,
|
||||
GROUP_TYPE_STICK,
|
||||
GROUP_TYPE_MIXED_TRIGGERS,
|
||||
GROUP_TYPE_BUTTONS,
|
||||
GROUP_TYPE_FORCE,
|
||||
GROUP_TYPE_EXTENSION,
|
||||
GROUP_TYPE_TILT,
|
||||
GROUP_TYPE_CURSOR,
|
||||
GROUP_TYPE_TRIGGERS,
|
||||
GROUP_TYPE_SLIDER
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SETTING_RADIUS,
|
||||
SETTING_DEADZONE,
|
||||
SETTING_RADIUS,
|
||||
SETTING_DEADZONE,
|
||||
};
|
||||
|
||||
const char* const named_directions[] =
|
||||
{
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right"
|
||||
};
|
||||
const char* const named_directions[] = {"Up", "Down", "Left", "Right"};
|
||||
|
||||
class ControllerEmu
|
||||
{
|
||||
public:
|
||||
|
||||
class ControlGroup
|
||||
{
|
||||
public:
|
||||
|
||||
class Control
|
||||
{
|
||||
protected:
|
||||
Control(ControllerInterface::ControlReference* const _ref, const std::string& _name)
|
||||
: control_ref(_ref), name(_name) {}
|
||||
|
||||
public:
|
||||
virtual ~Control() {}
|
||||
std::unique_ptr<ControllerInterface::ControlReference> const control_ref;
|
||||
const std::string name;
|
||||
|
||||
};
|
||||
|
||||
class Input : public Control
|
||||
{
|
||||
public:
|
||||
|
||||
Input(const std::string& _name)
|
||||
: Control(new ControllerInterface::InputReference, _name) {}
|
||||
};
|
||||
|
||||
class Output : public Control
|
||||
{
|
||||
public:
|
||||
|
||||
Output(const std::string& _name)
|
||||
: Control(new ControllerInterface::OutputReference, _name) {}
|
||||
};
|
||||
|
||||
class Setting
|
||||
{
|
||||
public:
|
||||
Setting(const std::string& _name, const ControlState def_value
|
||||
, const unsigned int _low = 0, const unsigned int _high = 100)
|
||||
: name(_name)
|
||||
, value(def_value)
|
||||
, default_value(def_value)
|
||||
, low(_low)
|
||||
, high(_high)
|
||||
, is_virtual(false)
|
||||
, is_iterate(false) {}
|
||||
|
||||
virtual ~Setting()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string name;
|
||||
ControlState value;
|
||||
const ControlState default_value;
|
||||
const unsigned int low, high;
|
||||
bool is_virtual;
|
||||
bool is_iterate;
|
||||
|
||||
virtual void SetValue(ControlState new_value)
|
||||
{
|
||||
value = new_value;
|
||||
}
|
||||
|
||||
virtual ControlState GetValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
class BackgroundInputSetting : public Setting
|
||||
{
|
||||
public:
|
||||
BackgroundInputSetting(const std::string &_name) : Setting(_name, false)
|
||||
{
|
||||
is_virtual = true;
|
||||
}
|
||||
|
||||
void SetValue(ControlState new_value) override
|
||||
{
|
||||
SConfig::GetInstance().m_BackgroundInput = !!new_value;
|
||||
}
|
||||
|
||||
ControlState GetValue() override
|
||||
{
|
||||
return SConfig::GetInstance().m_BackgroundInput;
|
||||
}
|
||||
};
|
||||
|
||||
class IterateUI : public Setting
|
||||
{
|
||||
public:
|
||||
IterateUI(const std::string &_name) : Setting(_name, false)
|
||||
{
|
||||
is_iterate = true;
|
||||
}
|
||||
};
|
||||
|
||||
ControlGroup(const std::string& _name, const unsigned int _type = GROUP_TYPE_OTHER)
|
||||
: name(_name), ui_name(_name), type(_type) {}
|
||||
ControlGroup(const std::string& _name, const std::string& _ui_name, const unsigned int _type = GROUP_TYPE_OTHER)
|
||||
: name(_name), ui_name(_ui_name), type(_type) {}
|
||||
virtual ~ControlGroup() {}
|
||||
|
||||
virtual void LoadConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
|
||||
virtual void SaveConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
|
||||
|
||||
void SetControlExpression(int index, const std::string& expression);
|
||||
|
||||
const std::string name;
|
||||
const std::string ui_name;
|
||||
const unsigned int type;
|
||||
|
||||
std::vector<std::unique_ptr<Control>> controls;
|
||||
std::vector<std::unique_ptr<Setting>> settings;
|
||||
|
||||
};
|
||||
|
||||
class AnalogStick : public ControlGroup
|
||||
{
|
||||
public:
|
||||
// The GameCube controller and Wiimote attachments have a different default radius
|
||||
AnalogStick(const char* const _name, ControlState default_radius);
|
||||
AnalogStick(const char* const _name, const char* const _ui_name, ControlState default_radius);
|
||||
|
||||
void GetState(ControlState* const x, ControlState* const y)
|
||||
{
|
||||
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
|
||||
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
|
||||
|
||||
ControlState radius = settings[SETTING_RADIUS]->value;
|
||||
ControlState deadzone = settings[SETTING_DEADZONE]->value;
|
||||
ControlState m = controls[4]->control_ref->State();
|
||||
|
||||
ControlState ang = atan2(yy, xx);
|
||||
ControlState ang_sin = sin(ang);
|
||||
ControlState ang_cos = cos(ang);
|
||||
|
||||
ControlState dist = sqrt(xx*xx + yy*yy);
|
||||
|
||||
// dead zone code
|
||||
dist = std::max(0.0, dist - deadzone);
|
||||
dist /= (1 - deadzone);
|
||||
|
||||
// radius
|
||||
dist *= radius;
|
||||
|
||||
// The modifier halves the distance by 50%, which is useful
|
||||
// for keyboard controls.
|
||||
if (m)
|
||||
dist *= 0.5;
|
||||
|
||||
yy = std::max(-1.0, std::min(1.0, ang_sin * dist));
|
||||
xx = std::max(-1.0, std::min(1.0, ang_cos * dist));
|
||||
|
||||
*y = yy;
|
||||
*x = xx;
|
||||
}
|
||||
};
|
||||
|
||||
class Buttons : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Buttons(const std::string& _name);
|
||||
|
||||
template <typename C>
|
||||
void GetState(C* const buttons, const C* bitmasks)
|
||||
{
|
||||
for (auto& control : controls)
|
||||
{
|
||||
if (control->control_ref->State() > settings[0]->value) // threshold
|
||||
*buttons |= *bitmasks;
|
||||
|
||||
bitmasks++;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class MixedTriggers : public ControlGroup
|
||||
{
|
||||
public:
|
||||
MixedTriggers(const std::string& _name);
|
||||
|
||||
void GetState(u16 *const digital, const u16* bitmasks, ControlState* analog)
|
||||
{
|
||||
const unsigned int trig_count = ((unsigned int) (controls.size() / 2));
|
||||
for (unsigned int i=0; i<trig_count; ++i,++bitmasks,++analog)
|
||||
{
|
||||
if (controls[i]->control_ref->State() > settings[0]->value) //threshold
|
||||
{
|
||||
*analog = 1.0;
|
||||
*digital |= *bitmasks;
|
||||
}
|
||||
else
|
||||
{
|
||||
*analog = controls[i+trig_count]->control_ref->State();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Triggers : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Triggers(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* analog)
|
||||
{
|
||||
const unsigned int trig_count = ((unsigned int) (controls.size()));
|
||||
const ControlState deadzone = settings[0]->value;
|
||||
for (unsigned int i=0; i<trig_count; ++i,++analog)
|
||||
*analog = std::max(controls[i]->control_ref->State() - deadzone, 0.0) / (1 - deadzone);
|
||||
}
|
||||
};
|
||||
|
||||
class Slider : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Slider(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* const slider)
|
||||
{
|
||||
const ControlState deadzone = settings[0]->value;
|
||||
const ControlState state = controls[1]->control_ref->State() - controls[0]->control_ref->State();
|
||||
|
||||
if (fabs(state) > deadzone)
|
||||
*slider = (state - (deadzone * sign(state))) / (1 - deadzone);
|
||||
else
|
||||
*slider = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Force : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Force(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* axis)
|
||||
{
|
||||
const ControlState deadzone = settings[0]->value;
|
||||
for (unsigned int i = 0; i < 6; i += 2)
|
||||
{
|
||||
ControlState tmpf = 0;
|
||||
const ControlState state = controls[i+1]->control_ref->State() - controls[i]->control_ref->State();
|
||||
if (fabs(state) > deadzone)
|
||||
tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone));
|
||||
|
||||
ControlState &ax = m_swing[i >> 1];
|
||||
*axis++ = (tmpf - ax);
|
||||
ax = tmpf;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ControlState m_swing[3];
|
||||
};
|
||||
|
||||
class Tilt : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Tilt(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* const x, ControlState* const y, const bool step = true)
|
||||
{
|
||||
// this is all a mess
|
||||
|
||||
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
|
||||
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
|
||||
|
||||
ControlState deadzone = settings[0]->value;
|
||||
ControlState circle = settings[1]->value;
|
||||
auto const angle = settings[2]->value / 1.8;
|
||||
ControlState m = controls[4]->control_ref->State();
|
||||
|
||||
// deadzone / circle stick code
|
||||
// this section might be all wrong, but its working good enough, I think
|
||||
|
||||
ControlState ang = atan2(yy, xx);
|
||||
ControlState ang_sin = sin(ang);
|
||||
ControlState ang_cos = cos(ang);
|
||||
|
||||
// the amt a full square stick would have at current angle
|
||||
ControlState square_full = std::min(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2);
|
||||
|
||||
// the amt a full stick would have that was (user setting circular) at current angle
|
||||
// I think this is more like a pointed circle rather than a rounded square like it should be
|
||||
ControlState stick_full = (square_full * (1 - circle)) + (circle);
|
||||
|
||||
ControlState dist = sqrt(xx*xx + yy*yy);
|
||||
|
||||
// dead zone code
|
||||
dist = std::max(0.0, dist - deadzone * stick_full);
|
||||
dist /= (1 - deadzone);
|
||||
|
||||
// circle stick code
|
||||
ControlState amt = dist / stick_full;
|
||||
dist += (square_full - 1) * amt * circle;
|
||||
|
||||
if (m)
|
||||
dist *= 0.5;
|
||||
|
||||
yy = std::max(-1.0, std::min(1.0, ang_sin * dist));
|
||||
xx = std::max(-1.0, std::min(1.0, ang_cos * dist));
|
||||
|
||||
// this is kinda silly here
|
||||
// gui being open will make this happen 2x as fast, o well
|
||||
|
||||
// silly
|
||||
if (step)
|
||||
{
|
||||
if (xx > m_tilt[0])
|
||||
m_tilt[0] = std::min(m_tilt[0] + 0.1, xx);
|
||||
else if (xx < m_tilt[0])
|
||||
m_tilt[0] = std::max(m_tilt[0] - 0.1, xx);
|
||||
|
||||
if (yy > m_tilt[1])
|
||||
m_tilt[1] = std::min(m_tilt[1] + 0.1, yy);
|
||||
else if (yy < m_tilt[1])
|
||||
m_tilt[1] = std::max(m_tilt[1] - 0.1, yy);
|
||||
}
|
||||
|
||||
*y = m_tilt[1] * angle;
|
||||
*x = m_tilt[0] * angle;
|
||||
}
|
||||
|
||||
private:
|
||||
ControlState m_tilt[2];
|
||||
};
|
||||
|
||||
class Cursor : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Cursor(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* const x, ControlState* const y, ControlState* const z, const bool adjusted = false)
|
||||
{
|
||||
const ControlState zz = controls[4]->control_ref->State() - controls[5]->control_ref->State();
|
||||
|
||||
// silly being here
|
||||
if (zz > m_z)
|
||||
m_z = std::min(m_z + 0.1, zz);
|
||||
else if (zz < m_z)
|
||||
m_z = std::max(m_z - 0.1, zz);
|
||||
|
||||
*z = m_z;
|
||||
|
||||
// hide
|
||||
if (controls[6]->control_ref->State() > 0.5)
|
||||
{
|
||||
*x = 10000; *y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
|
||||
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
|
||||
|
||||
// adjust cursor according to settings
|
||||
if (adjusted)
|
||||
{
|
||||
xx *= (settings[1]->value * 2);
|
||||
yy *= (settings[2]->value * 2);
|
||||
yy += (settings[0]->value - 0.5);
|
||||
}
|
||||
|
||||
*x = xx;
|
||||
*y = yy;
|
||||
}
|
||||
}
|
||||
|
||||
ControlState m_z;
|
||||
};
|
||||
|
||||
class Extension : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Extension(const std::string& _name)
|
||||
: ControlGroup(_name, GROUP_TYPE_EXTENSION)
|
||||
, switch_extension(0)
|
||||
, active_extension(0) {}
|
||||
|
||||
~Extension() {}
|
||||
|
||||
void GetState(u8* const data);
|
||||
bool IsButtonPressed() const;
|
||||
|
||||
std::vector<std::unique_ptr<ControllerEmu>> attachments;
|
||||
|
||||
int switch_extension;
|
||||
int active_extension;
|
||||
};
|
||||
|
||||
virtual ~ControllerEmu() {}
|
||||
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
virtual void LoadDefaults(const ControllerInterface& ciface);
|
||||
|
||||
virtual void LoadConfig(IniFile::Section *sec, const std::string& base = "");
|
||||
virtual void SaveConfig(IniFile::Section *sec, const std::string& base = "");
|
||||
void UpdateDefaultDevice();
|
||||
|
||||
void UpdateReferences(ControllerInterface& devi);
|
||||
|
||||
std::vector<std::unique_ptr<ControlGroup>> groups;
|
||||
|
||||
ciface::Core::DeviceQualifier default_device;
|
||||
class ControlGroup
|
||||
{
|
||||
public:
|
||||
class Control
|
||||
{
|
||||
protected:
|
||||
Control(ControllerInterface::ControlReference* const _ref, const std::string& _name)
|
||||
: control_ref(_ref), name(_name)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~Control() {}
|
||||
std::unique_ptr<ControllerInterface::ControlReference> const control_ref;
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
class Input : public Control
|
||||
{
|
||||
public:
|
||||
Input(const std::string& _name) : Control(new ControllerInterface::InputReference, _name) {}
|
||||
};
|
||||
|
||||
class Output : public Control
|
||||
{
|
||||
public:
|
||||
Output(const std::string& _name) : Control(new ControllerInterface::OutputReference, _name) {}
|
||||
};
|
||||
|
||||
class Setting
|
||||
{
|
||||
public:
|
||||
Setting(const std::string& _name, const ControlState def_value, const unsigned int _low = 0,
|
||||
const unsigned int _high = 100)
|
||||
: name(_name), value(def_value), default_value(def_value), low(_low), high(_high),
|
||||
is_virtual(false), is_iterate(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Setting() {}
|
||||
const std::string name;
|
||||
ControlState value;
|
||||
const ControlState default_value;
|
||||
const unsigned int low, high;
|
||||
bool is_virtual;
|
||||
bool is_iterate;
|
||||
|
||||
virtual void SetValue(ControlState new_value) { value = new_value; }
|
||||
virtual ControlState GetValue() { return value; }
|
||||
};
|
||||
|
||||
class BackgroundInputSetting : public Setting
|
||||
{
|
||||
public:
|
||||
BackgroundInputSetting(const std::string& _name) : Setting(_name, false)
|
||||
{
|
||||
is_virtual = true;
|
||||
}
|
||||
|
||||
void SetValue(ControlState new_value) override
|
||||
{
|
||||
SConfig::GetInstance().m_BackgroundInput = !!new_value;
|
||||
}
|
||||
|
||||
ControlState GetValue() override { return SConfig::GetInstance().m_BackgroundInput; }
|
||||
};
|
||||
|
||||
class IterateUI : public Setting
|
||||
{
|
||||
public:
|
||||
IterateUI(const std::string& _name) : Setting(_name, false) { is_iterate = true; }
|
||||
};
|
||||
|
||||
ControlGroup(const std::string& _name, const unsigned int _type = GROUP_TYPE_OTHER)
|
||||
: name(_name), ui_name(_name), type(_type)
|
||||
{
|
||||
}
|
||||
ControlGroup(const std::string& _name, const std::string& _ui_name,
|
||||
const unsigned int _type = GROUP_TYPE_OTHER)
|
||||
: name(_name), ui_name(_ui_name), type(_type)
|
||||
{
|
||||
}
|
||||
virtual ~ControlGroup() {}
|
||||
virtual void LoadConfig(IniFile::Section* sec, const std::string& defdev = "",
|
||||
const std::string& base = "");
|
||||
virtual void SaveConfig(IniFile::Section* sec, const std::string& defdev = "",
|
||||
const std::string& base = "");
|
||||
|
||||
void SetControlExpression(int index, const std::string& expression);
|
||||
|
||||
const std::string name;
|
||||
const std::string ui_name;
|
||||
const unsigned int type;
|
||||
|
||||
std::vector<std::unique_ptr<Control>> controls;
|
||||
std::vector<std::unique_ptr<Setting>> settings;
|
||||
};
|
||||
|
||||
class AnalogStick : public ControlGroup
|
||||
{
|
||||
public:
|
||||
// The GameCube controller and Wiimote attachments have a different default radius
|
||||
AnalogStick(const char* const _name, ControlState default_radius);
|
||||
AnalogStick(const char* const _name, const char* const _ui_name, ControlState default_radius);
|
||||
|
||||
void GetState(ControlState* const x, ControlState* const y)
|
||||
{
|
||||
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
|
||||
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
|
||||
|
||||
ControlState radius = settings[SETTING_RADIUS]->value;
|
||||
ControlState deadzone = settings[SETTING_DEADZONE]->value;
|
||||
ControlState m = controls[4]->control_ref->State();
|
||||
|
||||
ControlState ang = atan2(yy, xx);
|
||||
ControlState ang_sin = sin(ang);
|
||||
ControlState ang_cos = cos(ang);
|
||||
|
||||
ControlState dist = sqrt(xx * xx + yy * yy);
|
||||
|
||||
// dead zone code
|
||||
dist = std::max(0.0, dist - deadzone);
|
||||
dist /= (1 - deadzone);
|
||||
|
||||
// radius
|
||||
dist *= radius;
|
||||
|
||||
// The modifier halves the distance by 50%, which is useful
|
||||
// for keyboard controls.
|
||||
if (m)
|
||||
dist *= 0.5;
|
||||
|
||||
yy = std::max(-1.0, std::min(1.0, ang_sin * dist));
|
||||
xx = std::max(-1.0, std::min(1.0, ang_cos * dist));
|
||||
|
||||
*y = yy;
|
||||
*x = xx;
|
||||
}
|
||||
};
|
||||
|
||||
class Buttons : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Buttons(const std::string& _name);
|
||||
|
||||
template <typename C>
|
||||
void GetState(C* const buttons, const C* bitmasks)
|
||||
{
|
||||
for (auto& control : controls)
|
||||
{
|
||||
if (control->control_ref->State() > settings[0]->value) // threshold
|
||||
*buttons |= *bitmasks;
|
||||
|
||||
bitmasks++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MixedTriggers : public ControlGroup
|
||||
{
|
||||
public:
|
||||
MixedTriggers(const std::string& _name);
|
||||
|
||||
void GetState(u16* const digital, const u16* bitmasks, ControlState* analog)
|
||||
{
|
||||
const unsigned int trig_count = ((unsigned int)(controls.size() / 2));
|
||||
for (unsigned int i = 0; i < trig_count; ++i, ++bitmasks, ++analog)
|
||||
{
|
||||
if (controls[i]->control_ref->State() > settings[0]->value) // threshold
|
||||
{
|
||||
*analog = 1.0;
|
||||
*digital |= *bitmasks;
|
||||
}
|
||||
else
|
||||
{
|
||||
*analog = controls[i + trig_count]->control_ref->State();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Triggers : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Triggers(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* analog)
|
||||
{
|
||||
const unsigned int trig_count = ((unsigned int)(controls.size()));
|
||||
const ControlState deadzone = settings[0]->value;
|
||||
for (unsigned int i = 0; i < trig_count; ++i, ++analog)
|
||||
*analog = std::max(controls[i]->control_ref->State() - deadzone, 0.0) / (1 - deadzone);
|
||||
}
|
||||
};
|
||||
|
||||
class Slider : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Slider(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* const slider)
|
||||
{
|
||||
const ControlState deadzone = settings[0]->value;
|
||||
const ControlState state =
|
||||
controls[1]->control_ref->State() - controls[0]->control_ref->State();
|
||||
|
||||
if (fabs(state) > deadzone)
|
||||
*slider = (state - (deadzone * sign(state))) / (1 - deadzone);
|
||||
else
|
||||
*slider = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Force : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Force(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* axis)
|
||||
{
|
||||
const ControlState deadzone = settings[0]->value;
|
||||
for (unsigned int i = 0; i < 6; i += 2)
|
||||
{
|
||||
ControlState tmpf = 0;
|
||||
const ControlState state =
|
||||
controls[i + 1]->control_ref->State() - controls[i]->control_ref->State();
|
||||
if (fabs(state) > deadzone)
|
||||
tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone));
|
||||
|
||||
ControlState& ax = m_swing[i >> 1];
|
||||
*axis++ = (tmpf - ax);
|
||||
ax = tmpf;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ControlState m_swing[3];
|
||||
};
|
||||
|
||||
class Tilt : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Tilt(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* const x, ControlState* const y, const bool step = true)
|
||||
{
|
||||
// this is all a mess
|
||||
|
||||
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
|
||||
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
|
||||
|
||||
ControlState deadzone = settings[0]->value;
|
||||
ControlState circle = settings[1]->value;
|
||||
auto const angle = settings[2]->value / 1.8;
|
||||
ControlState m = controls[4]->control_ref->State();
|
||||
|
||||
// deadzone / circle stick code
|
||||
// this section might be all wrong, but its working good enough, I think
|
||||
|
||||
ControlState ang = atan2(yy, xx);
|
||||
ControlState ang_sin = sin(ang);
|
||||
ControlState ang_cos = cos(ang);
|
||||
|
||||
// the amt a full square stick would have at current angle
|
||||
ControlState square_full =
|
||||
std::min(ang_sin ? 1 / fabs(ang_sin) : 2, ang_cos ? 1 / fabs(ang_cos) : 2);
|
||||
|
||||
// the amt a full stick would have that was (user setting circular) at current angle
|
||||
// I think this is more like a pointed circle rather than a rounded square like it should be
|
||||
ControlState stick_full = (square_full * (1 - circle)) + (circle);
|
||||
|
||||
ControlState dist = sqrt(xx * xx + yy * yy);
|
||||
|
||||
// dead zone code
|
||||
dist = std::max(0.0, dist - deadzone * stick_full);
|
||||
dist /= (1 - deadzone);
|
||||
|
||||
// circle stick code
|
||||
ControlState amt = dist / stick_full;
|
||||
dist += (square_full - 1) * amt * circle;
|
||||
|
||||
if (m)
|
||||
dist *= 0.5;
|
||||
|
||||
yy = std::max(-1.0, std::min(1.0, ang_sin * dist));
|
||||
xx = std::max(-1.0, std::min(1.0, ang_cos * dist));
|
||||
|
||||
// this is kinda silly here
|
||||
// gui being open will make this happen 2x as fast, o well
|
||||
|
||||
// silly
|
||||
if (step)
|
||||
{
|
||||
if (xx > m_tilt[0])
|
||||
m_tilt[0] = std::min(m_tilt[0] + 0.1, xx);
|
||||
else if (xx < m_tilt[0])
|
||||
m_tilt[0] = std::max(m_tilt[0] - 0.1, xx);
|
||||
|
||||
if (yy > m_tilt[1])
|
||||
m_tilt[1] = std::min(m_tilt[1] + 0.1, yy);
|
||||
else if (yy < m_tilt[1])
|
||||
m_tilt[1] = std::max(m_tilt[1] - 0.1, yy);
|
||||
}
|
||||
|
||||
*y = m_tilt[1] * angle;
|
||||
*x = m_tilt[0] * angle;
|
||||
}
|
||||
|
||||
private:
|
||||
ControlState m_tilt[2];
|
||||
};
|
||||
|
||||
class Cursor : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Cursor(const std::string& _name);
|
||||
|
||||
void GetState(ControlState* const x, ControlState* const y, ControlState* const z,
|
||||
const bool adjusted = false)
|
||||
{
|
||||
const ControlState zz = controls[4]->control_ref->State() - controls[5]->control_ref->State();
|
||||
|
||||
// silly being here
|
||||
if (zz > m_z)
|
||||
m_z = std::min(m_z + 0.1, zz);
|
||||
else if (zz < m_z)
|
||||
m_z = std::max(m_z - 0.1, zz);
|
||||
|
||||
*z = m_z;
|
||||
|
||||
// hide
|
||||
if (controls[6]->control_ref->State() > 0.5)
|
||||
{
|
||||
*x = 10000;
|
||||
*y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
|
||||
ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
|
||||
|
||||
// adjust cursor according to settings
|
||||
if (adjusted)
|
||||
{
|
||||
xx *= (settings[1]->value * 2);
|
||||
yy *= (settings[2]->value * 2);
|
||||
yy += (settings[0]->value - 0.5);
|
||||
}
|
||||
|
||||
*x = xx;
|
||||
*y = yy;
|
||||
}
|
||||
}
|
||||
|
||||
ControlState m_z;
|
||||
};
|
||||
|
||||
class Extension : public ControlGroup
|
||||
{
|
||||
public:
|
||||
Extension(const std::string& _name)
|
||||
: ControlGroup(_name, GROUP_TYPE_EXTENSION), switch_extension(0), active_extension(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Extension() {}
|
||||
void GetState(u8* const data);
|
||||
bool IsButtonPressed() const;
|
||||
|
||||
std::vector<std::unique_ptr<ControllerEmu>> attachments;
|
||||
|
||||
int switch_extension;
|
||||
int active_extension;
|
||||
};
|
||||
|
||||
virtual ~ControllerEmu() {}
|
||||
virtual std::string GetName() const = 0;
|
||||
|
||||
virtual void LoadDefaults(const ControllerInterface& ciface);
|
||||
|
||||
virtual void LoadConfig(IniFile::Section* sec, const std::string& base = "");
|
||||
virtual void SaveConfig(IniFile::Section* sec, const std::string& base = "");
|
||||
void UpdateDefaultDevice();
|
||||
|
||||
void UpdateReferences(ControllerInterface& devi);
|
||||
|
||||
std::vector<std::unique_ptr<ControlGroup>> groups;
|
||||
|
||||
ciface::Core::DeviceQualifier default_device;
|
||||
};
|
||||
|
Reference in New Issue
Block a user