commit
9f91fb6447
|
@ -20,6 +20,7 @@ enum LOG_TYPE
|
||||||
COMMANDPROCESSOR,
|
COMMANDPROCESSOR,
|
||||||
COMMON,
|
COMMON,
|
||||||
CONSOLE,
|
CONSOLE,
|
||||||
|
CONTROLLERINTERFACE,
|
||||||
CORE,
|
CORE,
|
||||||
DISCIO,
|
DISCIO,
|
||||||
DSPHLE,
|
DSPHLE,
|
||||||
|
|
|
@ -123,6 +123,7 @@ LogManager::LogManager()
|
||||||
m_log[COMMANDPROCESSOR] = {"CP", "Command Processor"};
|
m_log[COMMANDPROCESSOR] = {"CP", "Command Processor"};
|
||||||
m_log[COMMON] = {"COMMON", "Common"};
|
m_log[COMMON] = {"COMMON", "Common"};
|
||||||
m_log[CONSOLE] = {"CONSOLE", "Dolphin Console"};
|
m_log[CONSOLE] = {"CONSOLE", "Dolphin Console"};
|
||||||
|
m_log[CONTROLLERINTERFACE] = {"CI", "Controller Interface"};
|
||||||
m_log[CORE] = {"CORE", "Core"};
|
m_log[CORE] = {"CORE", "Core"};
|
||||||
m_log[DISCIO] = {"DIO", "Disc IO"};
|
m_log[DISCIO] = {"DIO", "Disc IO"};
|
||||||
m_log[DSPHLE] = {"DSPHLE", "DSP HLE"};
|
m_log[DSPHLE] = {"DSPHLE", "DSP HLE"};
|
||||||
|
|
|
@ -93,10 +93,15 @@ GCPad::GCPad(const unsigned int index) : m_index(index)
|
||||||
|
|
||||||
// options
|
// options
|
||||||
groups.emplace_back(m_options = new ControllerEmu::ControlGroup(_trans("Options")));
|
groups.emplace_back(m_options = new ControllerEmu::ControlGroup(_trans("Options")));
|
||||||
m_options->AddSetting(&m_always_connected_setting,
|
m_options->AddSetting(
|
||||||
|
&m_always_connected_setting,
|
||||||
// i18n: Treat a controller as always being connected regardless of what
|
// i18n: Treat a controller as always being connected regardless of what
|
||||||
// devices the user actually has plugged in
|
// devices the user actually has plugged in
|
||||||
_trans("Always Connected"), false);
|
{_trans("Always Connected"), _trans(""),
|
||||||
|
_trans("Always connected if checked.\n"
|
||||||
|
"If unchecked, it will link the emulated controller connection state\n"
|
||||||
|
"to the real default device connection state (if there is one).")},
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCPad::GetName() const
|
std::string GCPad::GetName() const
|
||||||
|
@ -181,17 +186,17 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface)
|
||||||
EmulatedController::LoadDefaults(ciface);
|
EmulatedController::LoadDefaults(ciface);
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
m_buttons->SetControlExpression(0, "X"); // A
|
m_buttons->SetControlExpression(0, "`X`"); // A
|
||||||
m_buttons->SetControlExpression(1, "Z"); // B
|
m_buttons->SetControlExpression(1, "`Z`"); // B
|
||||||
m_buttons->SetControlExpression(2, "C"); // X
|
m_buttons->SetControlExpression(2, "`C`"); // X
|
||||||
m_buttons->SetControlExpression(3, "S"); // Y
|
m_buttons->SetControlExpression(3, "`S`"); // Y
|
||||||
m_buttons->SetControlExpression(4, "D"); // Z
|
m_buttons->SetControlExpression(4, "`D`"); // Z
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
m_buttons->SetControlExpression(5, "RETURN"); // Start
|
m_buttons->SetControlExpression(5, "`RETURN`"); // Start
|
||||||
#else
|
#else
|
||||||
// OS X/Linux
|
// OS X/Linux
|
||||||
// Start
|
// Start
|
||||||
m_buttons->SetControlExpression(5, "Return");
|
m_buttons->SetControlExpression(5, "`Return`");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// stick modifiers to 50 %
|
// stick modifiers to 50 %
|
||||||
|
@ -199,46 +204,46 @@ void GCPad::LoadDefaults(const ControllerInterface& ciface)
|
||||||
m_c_stick->controls[4]->control_ref->range = 0.5f;
|
m_c_stick->controls[4]->control_ref->range = 0.5f;
|
||||||
|
|
||||||
// D-Pad
|
// D-Pad
|
||||||
m_dpad->SetControlExpression(0, "T"); // Up
|
m_dpad->SetControlExpression(0, "`T`"); // Up
|
||||||
m_dpad->SetControlExpression(1, "G"); // Down
|
m_dpad->SetControlExpression(1, "`G`"); // Down
|
||||||
m_dpad->SetControlExpression(2, "F"); // Left
|
m_dpad->SetControlExpression(2, "`F`"); // Left
|
||||||
m_dpad->SetControlExpression(3, "H"); // Right
|
m_dpad->SetControlExpression(3, "`H`"); // Right
|
||||||
|
|
||||||
// C Stick
|
// C Stick
|
||||||
m_c_stick->SetControlExpression(0, "I"); // Up
|
m_c_stick->SetControlExpression(0, "`I`"); // Up
|
||||||
m_c_stick->SetControlExpression(1, "K"); // Down
|
m_c_stick->SetControlExpression(1, "`K`"); // Down
|
||||||
m_c_stick->SetControlExpression(2, "J"); // Left
|
m_c_stick->SetControlExpression(2, "`J`"); // Left
|
||||||
m_c_stick->SetControlExpression(3, "L"); // Right
|
m_c_stick->SetControlExpression(3, "`L`"); // Right
|
||||||
// Modifier
|
// Modifier
|
||||||
m_c_stick->SetControlExpression(4, "Ctrl");
|
m_c_stick->SetControlExpression(4, "`Ctrl`");
|
||||||
|
|
||||||
// Control Stick
|
// Control Stick
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
m_main_stick->SetControlExpression(0, "UP"); // Up
|
m_main_stick->SetControlExpression(0, "`UP`"); // Up
|
||||||
m_main_stick->SetControlExpression(1, "DOWN"); // Down
|
m_main_stick->SetControlExpression(1, "`DOWN`"); // Down
|
||||||
m_main_stick->SetControlExpression(2, "LEFT"); // Left
|
m_main_stick->SetControlExpression(2, "`LEFT`"); // Left
|
||||||
m_main_stick->SetControlExpression(3, "RIGHT"); // Right
|
m_main_stick->SetControlExpression(3, "`RIGHT`"); // Right
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
m_main_stick->SetControlExpression(0, "`Up Arrow`"); // Up
|
m_main_stick->SetControlExpression(0, "`Up Arrow`"); // Up
|
||||||
m_main_stick->SetControlExpression(1, "`Down Arrow`"); // Down
|
m_main_stick->SetControlExpression(1, "`Down Arrow`"); // Down
|
||||||
m_main_stick->SetControlExpression(2, "`Left Arrow`"); // Left
|
m_main_stick->SetControlExpression(2, "`Left Arrow`"); // Left
|
||||||
m_main_stick->SetControlExpression(3, "`Right Arrow`"); // Right
|
m_main_stick->SetControlExpression(3, "`Right Arrow`"); // Right
|
||||||
#else
|
#else
|
||||||
m_main_stick->SetControlExpression(0, "Up"); // Up
|
m_main_stick->SetControlExpression(0, "`Up`"); // Up
|
||||||
m_main_stick->SetControlExpression(1, "Down"); // Down
|
m_main_stick->SetControlExpression(1, "`Down`"); // Down
|
||||||
m_main_stick->SetControlExpression(2, "Left"); // Left
|
m_main_stick->SetControlExpression(2, "`Left`"); // Left
|
||||||
m_main_stick->SetControlExpression(3, "Right"); // Right
|
m_main_stick->SetControlExpression(3, "`Right`"); // Right
|
||||||
#endif
|
#endif
|
||||||
// Modifier
|
// Modifier
|
||||||
m_main_stick->SetControlExpression(4, "Shift");
|
m_main_stick->SetControlExpression(4, "`Shift`");
|
||||||
|
|
||||||
// Because our defaults use keyboard input, set calibration shapes to squares.
|
// Because our defaults use keyboard input, set calibration shapes to squares.
|
||||||
m_c_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0));
|
m_c_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0));
|
||||||
m_main_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0));
|
m_main_stick->SetCalibrationFromGate(ControllerEmu::SquareStickGate(1.0));
|
||||||
|
|
||||||
// Triggers
|
// Triggers
|
||||||
m_triggers->SetControlExpression(0, "Q"); // L
|
m_triggers->SetControlExpression(0, "`Q`"); // L
|
||||||
m_triggers->SetControlExpression(1, "W"); // R
|
m_triggers->SetControlExpression(1, "`W`"); // R
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GCPad::GetMicButton() const
|
bool GCPad::GetMicButton() const
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/Attachments.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h"
|
|
||||||
|
|
||||||
namespace WiimoteEmu
|
namespace WiimoteEmu
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,6 @@ void ExtensionPort::AttachExtension(Extension* ext)
|
||||||
|
|
||||||
m_extension = ext;
|
m_extension = ext;
|
||||||
m_i2c_bus.AddSlave(m_extension);
|
m_i2c_bus.AddSlave(m_extension);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace WiimoteEmu
|
} // namespace WiimoteEmu
|
||||||
|
|
|
@ -22,6 +22,8 @@ enum ExtensionNumber : u8
|
||||||
UDRAW_TABLET,
|
UDRAW_TABLET,
|
||||||
DRAWSOME_TABLET,
|
DRAWSOME_TABLET,
|
||||||
TATACON,
|
TATACON,
|
||||||
|
|
||||||
|
MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
// FYI: An extension must be attached.
|
// FYI: An extension must be attached.
|
||||||
|
|
|
@ -428,7 +428,7 @@ void Wiimote::Update()
|
||||||
|
|
||||||
// Hotkey / settings modifier
|
// Hotkey / settings modifier
|
||||||
// Data is later accessed in IsSideways and IsUpright
|
// Data is later accessed in IsSideways and IsUpright
|
||||||
m_hotkeys->GetState();
|
m_hotkeys->UpdateState();
|
||||||
|
|
||||||
// Update our motion simulations.
|
// Update our motion simulations.
|
||||||
StepDynamics();
|
StepDynamics();
|
||||||
|
@ -700,15 +700,15 @@ EncryptionKey Wiimote::GetExtensionEncryptionKey() const
|
||||||
|
|
||||||
bool Wiimote::IsSideways() const
|
bool Wiimote::IsSideways() const
|
||||||
{
|
{
|
||||||
const bool sideways_modifier_toggle = m_hotkeys->getSettingsModifier()[0];
|
const bool sideways_modifier_toggle = m_hotkeys->GetSettingsModifier()[0];
|
||||||
const bool sideways_modifier_switch = m_hotkeys->getSettingsModifier()[2];
|
const bool sideways_modifier_switch = m_hotkeys->GetSettingsModifier()[2];
|
||||||
return m_sideways_setting.GetValue() ^ sideways_modifier_toggle ^ sideways_modifier_switch;
|
return m_sideways_setting.GetValue() ^ sideways_modifier_toggle ^ sideways_modifier_switch;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wiimote::IsUpright() const
|
bool Wiimote::IsUpright() const
|
||||||
{
|
{
|
||||||
const bool upright_modifier_toggle = m_hotkeys->getSettingsModifier()[1];
|
const bool upright_modifier_toggle = m_hotkeys->GetSettingsModifier()[1];
|
||||||
const bool upright_modifier_switch = m_hotkeys->getSettingsModifier()[3];
|
const bool upright_modifier_switch = m_hotkeys->GetSettingsModifier()[3];
|
||||||
return m_upright_setting.GetValue() ^ upright_modifier_toggle ^ upright_modifier_switch;
|
return m_upright_setting.GetValue() ^ upright_modifier_toggle ^ upright_modifier_switch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ void MappingDouble::Update()
|
||||||
MappingBool::MappingBool(MappingWidget* parent, ControllerEmu::NumericSetting<bool>* setting)
|
MappingBool::MappingBool(MappingWidget* parent, ControllerEmu::NumericSetting<bool>* setting)
|
||||||
: QCheckBox(parent), m_setting(*setting)
|
: QCheckBox(parent), m_setting(*setting)
|
||||||
{
|
{
|
||||||
|
if (const auto ui_description = m_setting.GetUIDescription())
|
||||||
|
setToolTip(tr(ui_description));
|
||||||
|
|
||||||
connect(this, &QCheckBox::stateChanged, this, [this, parent](int value) {
|
connect(this, &QCheckBox::stateChanged, this, [this, parent](int value) {
|
||||||
m_setting.SetValue(value != 0);
|
m_setting.SetValue(value != 0);
|
||||||
ConfigChanged();
|
ConfigChanged();
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include "DolphinQt/Config/Graphics/BalloonTip.h"
|
#include "DolphinQt/Config/Graphics/BalloonTip.h"
|
||||||
|
|
||||||
|
constexpr int TOOLTIP_DELAY = 300;
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
class ToolTipWidget : public Derived
|
class ToolTipWidget : public Derived
|
||||||
{
|
{
|
||||||
|
@ -25,7 +27,7 @@ private:
|
||||||
{
|
{
|
||||||
if (m_timer_id)
|
if (m_timer_id)
|
||||||
return;
|
return;
|
||||||
m_timer_id = this->startTimer(300);
|
m_timer_id = this->startTimer(TOOLTIP_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void leaveEvent(QEvent* event) override
|
void leaveEvent(QEvent* event) override
|
||||||
|
|
|
@ -247,22 +247,18 @@ ParseStatus Lexer::Tokenize(std::vector<Token>& tokens)
|
||||||
class ControlExpression : public Expression
|
class ControlExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Keep a shared_ptr to the device so the control pointer doesn't become invalid.
|
explicit ControlExpression(ControlQualifier qualifier) : m_qualifier(qualifier) {}
|
||||||
std::shared_ptr<Device> m_device;
|
|
||||||
|
|
||||||
explicit ControlExpression(ControlQualifier qualifier_) : qualifier(qualifier_) {}
|
|
||||||
|
|
||||||
ControlState GetValue() const override
|
ControlState GetValue() const override
|
||||||
{
|
{
|
||||||
if (s_hotkey_suppressions.IsSuppressed(input))
|
if (s_hotkey_suppressions.IsSuppressed(m_input))
|
||||||
return 0;
|
return 0;
|
||||||
else
|
|
||||||
return GetValueIgnoringSuppression();
|
return GetValueIgnoringSuppression();
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlState GetValueIgnoringSuppression() const
|
ControlState GetValueIgnoringSuppression() const
|
||||||
{
|
{
|
||||||
if (!input)
|
if (!m_input)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
// Note: Inputs may return negative values in situations where opposing directions are
|
// Note: Inputs may return negative values in situations where opposing directions are
|
||||||
|
@ -271,27 +267,29 @@ public:
|
||||||
// FYI: Clamping values greater than 1.0 is purposely not done to support unbounded values in
|
// FYI: Clamping values greater than 1.0 is purposely not done to support unbounded values in
|
||||||
// the future. (e.g. raw accelerometer/gyro data)
|
// the future. (e.g. raw accelerometer/gyro data)
|
||||||
|
|
||||||
return std::max(0.0, input->GetState());
|
return std::max(0.0, m_input->GetState());
|
||||||
}
|
}
|
||||||
void SetValue(ControlState value) override
|
void SetValue(ControlState value) override
|
||||||
{
|
{
|
||||||
if (output)
|
if (m_output)
|
||||||
output->SetState(value);
|
m_output->SetState(value);
|
||||||
}
|
}
|
||||||
int CountNumControls() const override { return (input || output) ? 1 : 0; }
|
int CountNumControls() const override { return (m_input || m_output) ? 1 : 0; }
|
||||||
void UpdateReferences(ControlEnvironment& env) override
|
void UpdateReferences(ControlEnvironment& env) override
|
||||||
{
|
{
|
||||||
m_device = env.FindDevice(qualifier);
|
m_device = env.FindDevice(m_qualifier);
|
||||||
input = env.FindInput(qualifier);
|
m_input = env.FindInput(m_qualifier);
|
||||||
output = env.FindOutput(qualifier);
|
m_output = env.FindOutput(m_qualifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Input* GetInput() const { return input; };
|
Device::Input* GetInput() const { return m_input; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ControlQualifier qualifier;
|
// Keep a shared_ptr to the device so the control pointer doesn't become invalid.
|
||||||
Device::Input* input = nullptr;
|
std::shared_ptr<Device> m_device;
|
||||||
Device::Output* output = nullptr;
|
ControlQualifier m_qualifier;
|
||||||
|
Device::Input* m_input = nullptr;
|
||||||
|
Device::Output* m_output = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HotkeySuppressions::IsSuppressedIgnoringModifiers(Device::Input* input,
|
bool HotkeySuppressions::IsSuppressedIgnoringModifiers(Device::Input* input,
|
||||||
|
@ -371,6 +369,7 @@ public:
|
||||||
}
|
}
|
||||||
case TOK_ASSIGN:
|
case TOK_ASSIGN:
|
||||||
{
|
{
|
||||||
|
// Use this carefully as it's extremely powerful and can end up in unforeseen situations
|
||||||
lhs->SetValue(rhs->GetValue());
|
lhs->SetValue(rhs->GetValue());
|
||||||
return lhs->GetValue();
|
return lhs->GetValue();
|
||||||
}
|
}
|
||||||
|
@ -565,6 +564,9 @@ private:
|
||||||
|
|
||||||
// This class proxies all methods to its either left-hand child if it has bound controls, or its
|
// This class proxies all methods to its either left-hand child if it has bound controls, or its
|
||||||
// right-hand child. Its intended use is for supporting old-style barewords expressions.
|
// right-hand child. Its intended use is for supporting old-style barewords expressions.
|
||||||
|
// Note that if you have a keyboard device as default device and the expression is a single digit
|
||||||
|
// number, this will usually resolve in a numerical key instead of a numerical value.
|
||||||
|
// Though if this expression belongs to NumericSetting, it will likely be simplifed back to a value.
|
||||||
class CoalesceExpression : public Expression
|
class CoalesceExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -945,6 +947,7 @@ static std::unique_ptr<Expression> ParseBarewordExpression(const std::string& st
|
||||||
qualifier.control_name = str;
|
qualifier.control_name = str;
|
||||||
qualifier.has_device = false;
|
qualifier.has_device = false;
|
||||||
|
|
||||||
|
// This control expression will only work (find the specified control) with the default device.
|
||||||
return std::make_unique<ControlExpression>(qualifier);
|
return std::make_unique<ControlExpression>(qualifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,9 @@ public:
|
||||||
enum class ParseStatus
|
enum class ParseStatus
|
||||||
{
|
{
|
||||||
Successful,
|
Successful,
|
||||||
|
// Note that the expression could still work in this case (be valid and return a value)
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
|
// Will return the default value
|
||||||
EmptyExpression,
|
EmptyExpression,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,6 +109,7 @@ class ControlQualifier
|
||||||
public:
|
public:
|
||||||
bool has_device;
|
bool has_device;
|
||||||
Core::DeviceQualifier device_qualifier;
|
Core::DeviceQualifier device_qualifier;
|
||||||
|
// Makes no distinction between input and output
|
||||||
std::string control_name;
|
std::string control_name;
|
||||||
|
|
||||||
ControlQualifier() : has_device(false) {}
|
ControlQualifier() : has_device(false) {}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
virtual ~Control();
|
virtual ~Control();
|
||||||
|
|
||||||
template <typename T = ControlState>
|
template <typename T = ControlState>
|
||||||
T GetState()
|
T GetState() const
|
||||||
{
|
{
|
||||||
return control_ref->GetState<T>();
|
return control_ref->GetState<T>();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ AnalogStick::AnalogStick(const char* const name_, const char* const ui_name_,
|
||||||
AddInput(Translate, _trans("Modifier"));
|
AddInput(Translate, _trans("Modifier"));
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalogStick::ReshapeData AnalogStick::GetReshapableState(bool adjusted)
|
AnalogStick::ReshapeData AnalogStick::GetReshapableState(bool adjusted) const
|
||||||
{
|
{
|
||||||
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
||||||
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
||||||
|
@ -46,7 +46,7 @@ AnalogStick::ReshapeData AnalogStick::GetReshapableState(bool adjusted)
|
||||||
return Reshape(x, y, modifier);
|
return Reshape(x, y, modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalogStick::StateData AnalogStick::GetState()
|
AnalogStick::StateData AnalogStick::GetState() const
|
||||||
{
|
{
|
||||||
return GetReshapableState(true);
|
return GetReshapableState(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,10 @@ public:
|
||||||
AnalogStick(const char* name, std::unique_ptr<StickGate>&& stick_gate);
|
AnalogStick(const char* name, std::unique_ptr<StickGate>&& stick_gate);
|
||||||
AnalogStick(const char* name, const char* ui_name, std::unique_ptr<StickGate>&& stick_gate);
|
AnalogStick(const char* name, const char* ui_name, std::unique_ptr<StickGate>&& stick_gate);
|
||||||
|
|
||||||
ReshapeData GetReshapableState(bool adjusted) final override;
|
ReshapeData GetReshapableState(bool adjusted) const final override;
|
||||||
ControlState GetGateRadiusAtAngle(double ang) const override;
|
ControlState GetGateRadiusAtAngle(double ang) const override;
|
||||||
|
|
||||||
StateData GetState();
|
StateData GetState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<StickGate> m_stick_gate;
|
std::unique_ptr<StickGate> m_stick_gate;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Core/HW/WiimoteEmu/ExtensionPort.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||||
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
#include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
|
||||||
|
@ -34,7 +35,11 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SettingValue<int> m_selection_value;
|
SettingValue<int> m_selection_value;
|
||||||
NumericSetting<int> m_selection_setting = {&m_selection_value, {""}, 0, 0, 0};
|
// This is here and not added to the list of numeric_settings because it's serialized differently,
|
||||||
|
// by string (to be independent from the enum), and visualized differently in the UI.
|
||||||
|
// For the rest, it's treated similarly to other numeric_settings in the group.
|
||||||
|
NumericSetting<int> m_selection_setting = {
|
||||||
|
&m_selection_value, {""}, 0, 0, WiimoteEmu::ExtensionNumber::MAX - 1};
|
||||||
|
|
||||||
std::vector<std::unique_ptr<EmulatedController>> m_attachments;
|
std::vector<std::unique_ptr<EmulatedController>> m_attachments;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ public:
|
||||||
Buttons(const std::string& ini_name, const std::string& group_name);
|
Buttons(const std::string& ini_name, const std::string& group_name);
|
||||||
|
|
||||||
template <typename C>
|
template <typename C>
|
||||||
void GetState(C* const buttons, const C* bitmasks)
|
void GetState(C* const buttons, const C* bitmasks) const
|
||||||
{
|
{
|
||||||
for (auto& control : controls)
|
for (auto& control : controls)
|
||||||
*buttons |= *(bitmasks++) * control->GetState<bool>();
|
*buttons |= *(bitmasks++) * control->GetState<bool>();
|
||||||
|
|
|
@ -44,7 +44,7 @@ void ControlGroup::AddDeadzoneSetting(SettingValue<double>* value, double maximu
|
||||||
// i18n: The percent symbol.
|
// i18n: The percent symbol.
|
||||||
_trans("%"),
|
_trans("%"),
|
||||||
// i18n: Refers to the dead-zone setting of gamepad inputs.
|
// i18n: Refers to the dead-zone setting of gamepad inputs.
|
||||||
_trans("Input strength to ignore.")},
|
_trans("Input strength to ignore and remap.")},
|
||||||
0, 0, maximum_deadzone);
|
0, 0, maximum_deadzone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ Cursor::Cursor(std::string name_, std::string ui_name_)
|
||||||
AddSetting(&m_autohide_setting, {_trans("Auto-Hide")}, false);
|
AddSetting(&m_autohide_setting, {_trans("Auto-Hide")}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cursor::ReshapeData Cursor::GetReshapableState(bool adjusted)
|
Cursor::ReshapeData Cursor::GetReshapableState(bool adjusted) const
|
||||||
{
|
{
|
||||||
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
||||||
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
||||||
|
|
|
@ -25,9 +25,10 @@ public:
|
||||||
|
|
||||||
Cursor(std::string name, std::string ui_name);
|
Cursor(std::string name, std::string ui_name);
|
||||||
|
|
||||||
ReshapeData GetReshapableState(bool adjusted) final override;
|
ReshapeData GetReshapableState(bool adjusted) const final override;
|
||||||
ControlState GetGateRadiusAtAngle(double ang) const override;
|
ControlState GetGateRadiusAtAngle(double ang) const override;
|
||||||
|
|
||||||
|
// Modifies the state
|
||||||
StateData GetState(bool adjusted);
|
StateData GetState(bool adjusted);
|
||||||
|
|
||||||
// Yaw movement in radians.
|
// Yaw movement in radians.
|
||||||
|
|
|
@ -65,7 +65,7 @@ Force::Force(const std::string& name_) : ReshapableInput(name_, name_, GroupType
|
||||||
90, 1, 180);
|
90, 1, 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
Force::ReshapeData Force::GetReshapableState(bool adjusted)
|
Force::ReshapeData Force::GetReshapableState(bool adjusted) const
|
||||||
{
|
{
|
||||||
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
||||||
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
||||||
|
@ -77,7 +77,7 @@ Force::ReshapeData Force::GetReshapableState(bool adjusted)
|
||||||
return Reshape(x, y);
|
return Reshape(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Force::StateData Force::GetState(bool adjusted)
|
Force::StateData Force::GetState(bool adjusted) const
|
||||||
{
|
{
|
||||||
const auto state = GetReshapableState(adjusted);
|
const auto state = GetReshapableState(adjusted);
|
||||||
ControlState z = controls[4]->GetState() - controls[5]->GetState();
|
ControlState z = controls[4]->GetState() - controls[5]->GetState();
|
||||||
|
|
|
@ -19,12 +19,12 @@ public:
|
||||||
|
|
||||||
explicit Force(const std::string& name);
|
explicit Force(const std::string& name);
|
||||||
|
|
||||||
ReshapeData GetReshapableState(bool adjusted) final override;
|
ReshapeData GetReshapableState(bool adjusted) const final override;
|
||||||
ControlState GetGateRadiusAtAngle(double ang) const final override;
|
ControlState GetGateRadiusAtAngle(double ang) const final override;
|
||||||
|
|
||||||
ControlState GetDefaultInputRadiusAtAngle(double angle) const final override;
|
ControlState GetDefaultInputRadiusAtAngle(double angle) const final override;
|
||||||
|
|
||||||
StateData GetState(bool adjusted = true);
|
StateData GetState(bool adjusted = true) const;
|
||||||
|
|
||||||
// Velocities returned in m/s.
|
// Velocities returned in m/s.
|
||||||
ControlState GetSpeed() const;
|
ControlState GetSpeed() const;
|
||||||
|
|
|
@ -40,7 +40,7 @@ IMUGyroscope::IMUGyroscope(std::string name_, std::string ui_name_)
|
||||||
// i18n: "°/s" is the symbol for degrees (angular measurement) divided by seconds.
|
// i18n: "°/s" is the symbol for degrees (angular measurement) divided by seconds.
|
||||||
_trans("°/s"),
|
_trans("°/s"),
|
||||||
// i18n: Refers to the dead-zone setting of gyroscope input.
|
// i18n: Refers to the dead-zone setting of gyroscope input.
|
||||||
_trans("Angular velocity to ignore.")},
|
_trans("Angular velocity to ignore and remap.")},
|
||||||
2, 0, 180);
|
2, 0, 180);
|
||||||
|
|
||||||
AddSetting(&m_calibration_period_setting,
|
AddSetting(&m_calibration_period_setting,
|
||||||
|
|
|
@ -26,52 +26,52 @@ ModifySettingsButton::ModifySettingsButton(std::string button_name)
|
||||||
void ModifySettingsButton::AddInput(std::string button_name, bool toggle)
|
void ModifySettingsButton::AddInput(std::string button_name, bool toggle)
|
||||||
{
|
{
|
||||||
ControlGroup::AddInput(Translate, std::move(button_name));
|
ControlGroup::AddInput(Translate, std::move(button_name));
|
||||||
threshold_exceeded.emplace_back(false);
|
m_threshold_exceeded.emplace_back(false);
|
||||||
associated_settings.emplace_back(false);
|
m_associated_settings.emplace_back(false);
|
||||||
associated_settings_toggle.emplace_back(toggle);
|
m_associated_settings_toggle.emplace_back(toggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModifySettingsButton::GetState()
|
void ModifySettingsButton::UpdateState()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < controls.size(); ++i)
|
for (size_t i = 0; i < controls.size(); ++i)
|
||||||
{
|
{
|
||||||
const bool state = controls[i]->GetState<bool>();
|
const bool state = controls[i]->GetState<bool>();
|
||||||
|
|
||||||
if (!associated_settings_toggle[i])
|
if (!m_associated_settings_toggle[i])
|
||||||
{
|
{
|
||||||
// not toggled
|
// not toggled
|
||||||
associated_settings[i] = state;
|
m_associated_settings[i] = state;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// toggle (loading savestates does not en-/disable toggle)
|
// toggle (loading savestates does not en-/disable toggle)
|
||||||
// after we passed the threshold, we en-/disable. but after that, we don't change it
|
// after we passed the threshold, we en-/disable. but after that, we don't change it
|
||||||
// anymore
|
// anymore
|
||||||
if (!threshold_exceeded[i] && state)
|
if (!m_threshold_exceeded[i] && state)
|
||||||
{
|
{
|
||||||
associated_settings[i] = !associated_settings[i];
|
m_associated_settings[i] = !m_associated_settings[i];
|
||||||
|
|
||||||
if (associated_settings[i])
|
if (m_associated_settings[i])
|
||||||
OSD::AddMessage(controls[i]->ui_name + ": on");
|
OSD::AddMessage(controls[i]->ui_name + ": on");
|
||||||
else
|
else
|
||||||
OSD::AddMessage(controls[i]->ui_name + ": off");
|
OSD::AddMessage(controls[i]->ui_name + ": off");
|
||||||
|
|
||||||
threshold_exceeded[i] = true;
|
m_threshold_exceeded[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state)
|
if (!state)
|
||||||
threshold_exceeded[i] = false;
|
m_threshold_exceeded[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<bool>& ModifySettingsButton::isSettingToggled() const
|
const std::vector<bool>& ModifySettingsButton::IsSettingToggled() const
|
||||||
{
|
{
|
||||||
return associated_settings_toggle;
|
return m_associated_settings_toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<bool>& ModifySettingsButton::getSettingsModifier() const
|
const std::vector<bool>& ModifySettingsButton::GetSettingsModifier() const
|
||||||
{
|
{
|
||||||
return associated_settings;
|
return m_associated_settings;
|
||||||
}
|
}
|
||||||
} // namespace ControllerEmu
|
} // namespace ControllerEmu
|
||||||
|
|
|
@ -18,14 +18,14 @@ public:
|
||||||
|
|
||||||
void AddInput(std::string button_name, bool toggle = false);
|
void AddInput(std::string button_name, bool toggle = false);
|
||||||
|
|
||||||
void GetState();
|
void UpdateState();
|
||||||
|
|
||||||
const std::vector<bool>& isSettingToggled() const;
|
const std::vector<bool>& IsSettingToggled() const;
|
||||||
const std::vector<bool>& getSettingsModifier() const;
|
const std::vector<bool>& GetSettingsModifier() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<bool> threshold_exceeded; // internal calculation (if "state" was above threshold)
|
std::vector<bool> m_threshold_exceeded; // internal calculation (if "state" was above threshold)
|
||||||
std::vector<bool> associated_settings_toggle; // is setting toggled or hold?
|
std::vector<bool> m_associated_settings_toggle; // is setting toggled or hold?
|
||||||
std::vector<bool> associated_settings; // result
|
std::vector<bool> m_associated_settings; // result
|
||||||
};
|
};
|
||||||
} // namespace ControllerEmu
|
} // namespace ControllerEmu
|
||||||
|
|
|
@ -29,7 +29,7 @@ Slider::Slider(const std::string& name_) : Slider(name_, name_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Slider::StateData Slider::GetState()
|
Slider::StateData Slider::GetState() const
|
||||||
{
|
{
|
||||||
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
|
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
|
||||||
const ControlState state = controls[1]->GetState() - controls[0]->GetState();
|
const ControlState state = controls[1]->GetState() - controls[0]->GetState();
|
||||||
|
|
|
@ -23,7 +23,7 @@ public:
|
||||||
Slider(const std::string& name_, const std::string& ui_name_);
|
Slider(const std::string& name_, const std::string& ui_name_);
|
||||||
explicit Slider(const std::string& name_);
|
explicit Slider(const std::string& name_);
|
||||||
|
|
||||||
StateData GetState();
|
StateData GetState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SettingValue<double> m_deadzone_setting;
|
SettingValue<double> m_deadzone_setting;
|
||||||
|
|
|
@ -42,7 +42,7 @@ Tilt::Tilt(const std::string& name_) : ReshapableInput(name_, name_, GroupType::
|
||||||
7, 1, 50);
|
7, 1, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tilt::ReshapeData Tilt::GetReshapableState(bool adjusted)
|
Tilt::ReshapeData Tilt::GetReshapableState(bool adjusted) const
|
||||||
{
|
{
|
||||||
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
const ControlState y = controls[0]->GetState() - controls[1]->GetState();
|
||||||
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
const ControlState x = controls[3]->GetState() - controls[2]->GetState();
|
||||||
|
@ -56,7 +56,7 @@ Tilt::ReshapeData Tilt::GetReshapableState(bool adjusted)
|
||||||
return Reshape(x, y, modifier);
|
return Reshape(x, y, modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tilt::StateData Tilt::GetState()
|
Tilt::StateData Tilt::GetState() const
|
||||||
{
|
{
|
||||||
return GetReshapableState(true);
|
return GetReshapableState(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,14 +19,14 @@ public:
|
||||||
|
|
||||||
explicit Tilt(const std::string& name);
|
explicit Tilt(const std::string& name);
|
||||||
|
|
||||||
ReshapeData GetReshapableState(bool adjusted) final override;
|
ReshapeData GetReshapableState(bool adjusted) const final override;
|
||||||
ControlState GetGateRadiusAtAngle(double angle) const final override;
|
ControlState GetGateRadiusAtAngle(double angle) const final override;
|
||||||
|
|
||||||
// Tilt is using the gate radius to adjust the tilt angle so we must provide an unadjusted value
|
// Tilt is using the gate radius to adjust the tilt angle so we must provide an unadjusted value
|
||||||
// for the default input radius.
|
// for the default input radius.
|
||||||
ControlState GetDefaultInputRadiusAtAngle(double angle) const final override;
|
ControlState GetDefaultInputRadiusAtAngle(double angle) const final override;
|
||||||
|
|
||||||
StateData GetState();
|
StateData GetState() const;
|
||||||
|
|
||||||
// Return peak rotational velocity (for a complete turn) in radians/sec
|
// Return peak rotational velocity (for a complete turn) in radians/sec
|
||||||
ControlState GetMaxRotationalVelocity() const;
|
ControlState GetMaxRotationalVelocity() const;
|
||||||
|
|
|
@ -21,7 +21,7 @@ Triggers::Triggers(const std::string& name_) : ControlGroup(name_, GroupType::Tr
|
||||||
AddDeadzoneSetting(&m_deadzone_setting, 50);
|
AddDeadzoneSetting(&m_deadzone_setting, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
Triggers::StateData Triggers::GetState()
|
Triggers::StateData Triggers::GetState() const
|
||||||
{
|
{
|
||||||
const size_t trigger_count = controls.size();
|
const size_t trigger_count = controls.size();
|
||||||
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
|
const ControlState deadzone = m_deadzone_setting.GetValue() / 100;
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
|
|
||||||
explicit Triggers(const std::string& name);
|
explicit Triggers(const std::string& name);
|
||||||
|
|
||||||
StateData GetState();
|
StateData GetState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SettingValue<double> m_deadzone_setting;
|
SettingValue<double> m_deadzone_setting;
|
||||||
|
|
|
@ -128,6 +128,7 @@ std::optional<u32> SquareStickGate::GetIdealCalibrationSampleCount() const
|
||||||
ReshapableInput::ReshapableInput(std::string name_, std::string ui_name_, GroupType type_)
|
ReshapableInput::ReshapableInput(std::string name_, std::string ui_name_, GroupType type_)
|
||||||
: ControlGroup(std::move(name_), std::move(ui_name_), type_)
|
: ControlGroup(std::move(name_), std::move(ui_name_), type_)
|
||||||
{
|
{
|
||||||
|
// 50 is not always enough but users can set it to more with an expression
|
||||||
AddDeadzoneSetting(&m_deadzone_setting, 50);
|
AddDeadzoneSetting(&m_deadzone_setting, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,11 +281,16 @@ void ReshapableInput::SaveConfig(IniFile::Section* section, const std::string& d
|
||||||
}
|
}
|
||||||
|
|
||||||
ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlState y,
|
ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlState y,
|
||||||
ControlState modifier)
|
ControlState modifier,
|
||||||
|
ControlState clamp) const
|
||||||
{
|
{
|
||||||
x -= m_center.x;
|
x -= m_center.x;
|
||||||
y -= m_center.y;
|
y -= m_center.y;
|
||||||
|
|
||||||
|
// We run this even if both x and y will be zero.
|
||||||
|
// In that case, std::atan2(0, 0) returns a valid non-NaN value, but the exact value
|
||||||
|
// (which depends on the signs of x and y) does not matter here as dist is zero
|
||||||
|
|
||||||
// TODO: make the AtAngle functions work with negative angles:
|
// TODO: make the AtAngle functions work with negative angles:
|
||||||
ControlState angle = std::atan2(y, x) + MathUtil::TAU;
|
ControlState angle = std::atan2(y, x) + MathUtil::TAU;
|
||||||
|
|
||||||
|
@ -321,8 +327,8 @@ ReshapableInput::ReshapeData ReshapableInput::Reshape(ControlState x, ControlSta
|
||||||
// Scale to the gate shape/radius:
|
// Scale to the gate shape/radius:
|
||||||
dist *= gate_max_dist;
|
dist *= gate_max_dist;
|
||||||
|
|
||||||
return {std::clamp(std::cos(angle) * dist, -1.0, 1.0),
|
return {std::clamp(std::cos(angle) * dist, -clamp, clamp),
|
||||||
std::clamp(std::sin(angle) * dist, -1.0, 1.0)};
|
std::clamp(std::sin(angle) * dist, -clamp, clamp)};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ControllerEmu
|
} // namespace ControllerEmu
|
||||||
|
|
|
@ -91,7 +91,7 @@ public:
|
||||||
virtual ControlState GetVirtualNotchSize() const { return 0.0; };
|
virtual ControlState GetVirtualNotchSize() const { return 0.0; };
|
||||||
|
|
||||||
virtual ControlState GetGateRadiusAtAngle(double angle) const = 0;
|
virtual ControlState GetGateRadiusAtAngle(double angle) const = 0;
|
||||||
virtual ReshapeData GetReshapableState(bool adjusted) = 0;
|
virtual ReshapeData GetReshapableState(bool adjusted) const = 0;
|
||||||
virtual ControlState GetDefaultInputRadiusAtAngle(double ang) const;
|
virtual ControlState GetDefaultInputRadiusAtAngle(double ang) const;
|
||||||
|
|
||||||
void SetCalibrationToDefault();
|
void SetCalibrationToDefault();
|
||||||
|
@ -108,7 +108,8 @@ public:
|
||||||
void SetCenter(ReshapeData center);
|
void SetCenter(ReshapeData center);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0);
|
ReshapeData Reshape(ControlState x, ControlState y, ControlState modifier = 0.0,
|
||||||
|
ControlState clamp = 1.0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LoadConfig(IniFile::Section*, const std::string&, const std::string&) override;
|
void LoadConfig(IniFile::Section*, const std::string&, const std::string&) override;
|
||||||
|
|
|
@ -237,7 +237,7 @@ void ControllerInterface::AddDevice(std::shared_ptr<ciface::Core::Device> device
|
||||||
device->SetId(id);
|
device->SetId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "Added device: {}", device->GetQualifiedName());
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Added device: {}", device->GetQualifiedName());
|
||||||
m_devices.emplace_back(std::move(device));
|
m_devices.emplace_back(std::move(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +252,7 @@ void ControllerInterface::RemoveDevice(std::function<bool(const ciface::Core::De
|
||||||
auto it = std::remove_if(m_devices.begin(), m_devices.end(), [&callback](const auto& dev) {
|
auto it = std::remove_if(m_devices.begin(), m_devices.end(), [&callback](const auto& dev) {
|
||||||
if (callback(dev.get()))
|
if (callback(dev.get()))
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "Removed device: {}", dev->GetQualifiedName());
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Removed device: {}", dev->GetQualifiedName());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -205,7 +205,7 @@ static bool IsSameController(const Proto::MessageType::PortInfo& a,
|
||||||
static void HotplugThreadFunc()
|
static void HotplugThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("DualShockUDPClient Hotplug Thread");
|
Common::SetCurrentThreadName("DualShockUDPClient Hotplug Thread");
|
||||||
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient hotplug thread started");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread started");
|
||||||
|
|
||||||
while (s_hotplug_thread_running.IsSet())
|
while (s_hotplug_thread_running.IsSet())
|
||||||
{
|
{
|
||||||
|
@ -225,7 +225,7 @@ static void HotplugThreadFunc()
|
||||||
if (server.m_socket.send(&list_ports, sizeof list_ports, server.m_address, server.m_port) !=
|
if (server.m_socket.send(&list_ports, sizeof list_ports, server.m_address, server.m_port) !=
|
||||||
sf::Socket::Status::Done)
|
sf::Socket::Status::Done)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient HotplugThreadFunc send failed");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient HotplugThreadFunc send failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -277,7 +277,7 @@ static void HotplugThreadFunc()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient hotplug thread stopped");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient hotplug thread stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StartHotplugThread()
|
static void StartHotplugThread()
|
||||||
|
@ -310,7 +310,7 @@ static void StopHotplugThread()
|
||||||
|
|
||||||
static void Restart()
|
static void Restart()
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient Restart");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient Restart");
|
||||||
|
|
||||||
StopHotplugThread();
|
StopHotplugThread();
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ void Init()
|
||||||
|
|
||||||
void PopulateDevices()
|
void PopulateDevices()
|
||||||
{
|
{
|
||||||
INFO_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient PopulateDevices");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient PopulateDevices");
|
||||||
|
|
||||||
// s_servers has already been updated so we can't use it to know which devices we removed,
|
// s_servers has already been updated so we can't use it to know which devices we removed,
|
||||||
// also it's good to remove all of them before adding new ones so that their id will be set
|
// also it's good to remove all of them before adding new ones so that their id will be set
|
||||||
|
@ -510,7 +510,7 @@ void Device::UpdateInput()
|
||||||
if (m_socket.send(&data_req, sizeof(data_req), m_server_address, m_server_port) !=
|
if (m_socket.send(&data_req, sizeof(data_req), m_server_address, m_server_port) !=
|
||||||
sf::Socket::Status::Done)
|
sf::Socket::Status::Done)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "DualShockUDPClient UpdateInput send failed");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DualShockUDPClient UpdateInput send failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ struct Message
|
||||||
if (crc32_in_header != crc32_calculated)
|
if (crc32_in_header != crc32_calculated)
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(
|
NOTICE_LOG_FMT(
|
||||||
SERIALINTERFACE,
|
CONTROLLERINTERFACE,
|
||||||
"DualShockUDPClient Received message with bad CRC in header: got {:08x}, expected {:08x}",
|
"DualShockUDPClient Received message with bad CRC in header: got {:08x}, expected {:08x}",
|
||||||
crc32_in_header, crc32_calculated);
|
crc32_in_header, crc32_calculated);
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
|
@ -178,11 +178,11 @@ void Init(void* window)
|
||||||
|
|
||||||
HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
||||||
if (!HIDManager)
|
if (!HIDManager)
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "Failed to create HID Manager reference");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Failed to create HID Manager reference");
|
||||||
|
|
||||||
IOHIDManagerSetDeviceMatching(HIDManager, nullptr);
|
IOHIDManagerSetDeviceMatching(HIDManager, nullptr);
|
||||||
if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
|
if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "Failed to open HID Manager");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "Failed to open HID Manager");
|
||||||
|
|
||||||
// Callbacks for acquisition or loss of a matching device
|
// Callbacks for acquisition or loss of a matching device
|
||||||
IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, DeviceMatchingCallback, nullptr);
|
IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, DeviceMatchingCallback, nullptr);
|
||||||
|
@ -198,7 +198,7 @@ void Init(void* window)
|
||||||
// Enable hotplugging
|
// Enable hotplugging
|
||||||
s_hotplug_thread = std::thread([] {
|
s_hotplug_thread = std::thread([] {
|
||||||
Common::SetCurrentThreadName("IOHIDManager Hotplug Thread");
|
Common::SetCurrentThreadName("IOHIDManager Hotplug Thread");
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "IOHIDManager hotplug thread started");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "IOHIDManager hotplug thread started");
|
||||||
|
|
||||||
IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
|
IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
|
||||||
s_stopper.AddToRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
|
s_stopper.AddToRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
|
||||||
|
@ -206,7 +206,7 @@ void Init(void* window)
|
||||||
s_stopper.RemoveFromRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
|
s_stopper.RemoveFromRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
|
||||||
IOHIDManagerUnscheduleFromRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
|
IOHIDManagerUnscheduleFromRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "IOHIDManager hotplug thread stopped");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "IOHIDManager hotplug thread stopped");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,9 @@ void Joystick::AddElements(CFArrayRef elements, std::set<IOHIDElementCookie>& co
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "Unknown IOHIDElement, ignoring (Usage: {:x}, Type: {:x})",
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE,
|
||||||
usage, IOHIDElementGetType(e));
|
"Unknown IOHIDElement, ignoring (Usage: {:x}, Type: {:x})", usage,
|
||||||
|
IOHIDElementGetType(e));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ void Init()
|
||||||
{
|
{
|
||||||
#if !SDL_VERSION_ATLEAST(2, 0, 0)
|
#if !SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
|
if (SDL_Init(SDL_INIT_JOYSTICK) != 0)
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "SDL failed to initialize");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
|
||||||
return;
|
return;
|
||||||
#else
|
#else
|
||||||
s_hotplug_thread = std::thread([] {
|
s_hotplug_thread = std::thread([] {
|
||||||
|
@ -95,14 +95,14 @@ void Init()
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
|
if (SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "SDL failed to initialize");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to initialize");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Uint32 custom_events_start = SDL_RegisterEvents(2);
|
const Uint32 custom_events_start = SDL_RegisterEvents(2);
|
||||||
if (custom_events_start == static_cast<Uint32>(-1))
|
if (custom_events_start == static_cast<Uint32>(-1))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "SDL failed to register custom events");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "SDL failed to register custom events");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s_stop_event_type = custom_events_start;
|
s_stop_event_type = custom_events_start;
|
||||||
|
|
|
@ -766,7 +766,7 @@ bool InputDevice::PressEvent(int button, int action)
|
||||||
if (binding.second->m_bind_type == BIND_BUTTON)
|
if (binding.second->m_bind_type == BIND_BUTTON)
|
||||||
m_buttons[binding.second->m_button_type] = action == BUTTON_PRESSED ? true : false;
|
m_buttons[binding.second->m_button_type] = action == BUTTON_PRESSED ? true : false;
|
||||||
else
|
else
|
||||||
m_axises[binding.second->m_button_type] = action == BUTTON_PRESSED ? 1.0f : 0.0f;
|
m_axes[binding.second->m_button_type] = action == BUTTON_PRESSED ? 1.0f : 0.0f;
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -780,34 +780,54 @@ void InputDevice::AxisEvent(int axis, float value)
|
||||||
if (binding.second->m_bind == axis)
|
if (binding.second->m_bind == axis)
|
||||||
{
|
{
|
||||||
if (binding.second->m_bind_type == BIND_AXIS)
|
if (binding.second->m_bind_type == BIND_AXIS)
|
||||||
m_axises[binding.second->m_button_type] = value;
|
m_axes[binding.second->m_button_type] = value;
|
||||||
else
|
else
|
||||||
m_buttons[binding.second->m_button_type] = value > 0.5f ? true : false;
|
m_buttons[binding.second->m_button_type] = value > 0.5f ? true : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputDevice::ButtonValue(int pad_id, ButtonType button)
|
bool InputDevice::ButtonValue(int pad_id, ButtonType button) const
|
||||||
{
|
{
|
||||||
const auto& binding = m_input_binds.find(std::make_pair(pad_id, button));
|
const auto binding = m_input_binds.find(std::make_pair(pad_id, button));
|
||||||
if (binding == m_input_binds.end())
|
if (binding == m_input_binds.end())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (binding->second->m_bind_type == BIND_BUTTON)
|
if (binding->second->m_bind_type == BIND_BUTTON)
|
||||||
return m_buttons[binding->second->m_button_type];
|
{
|
||||||
|
const auto button = m_buttons.find(binding->second->m_button_type);
|
||||||
|
if (button == m_buttons.end())
|
||||||
|
return false;
|
||||||
|
return button->second;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return (m_axises[binding->second->m_button_type] * binding->second->m_neg) > 0.5f;
|
{
|
||||||
|
const auto axis = m_axes.find(binding->second->m_button_type);
|
||||||
|
if (axis == m_axes.end())
|
||||||
|
return false;
|
||||||
|
return (axis->second * binding->second->m_neg) > 0.5f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float InputDevice::AxisValue(int pad_id, ButtonType axis)
|
float InputDevice::AxisValue(int pad_id, ButtonType axis) const
|
||||||
{
|
{
|
||||||
const auto& binding = m_input_binds.find(std::make_pair(pad_id, axis));
|
const auto binding = m_input_binds.find(std::make_pair(pad_id, axis));
|
||||||
if (binding == m_input_binds.end())
|
if (binding == m_input_binds.end())
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
if (binding->second->m_bind_type == BIND_AXIS)
|
if (binding->second->m_bind_type == BIND_AXIS)
|
||||||
return m_axises[binding->second->m_button_type] * binding->second->m_neg;
|
{
|
||||||
|
const auto axis = m_axes.find(binding->second->m_button_type);
|
||||||
|
if (axis == m_axes.end())
|
||||||
|
return 0.0f;
|
||||||
|
return axis->second * binding->second->m_neg;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return m_buttons[binding->second->m_button_type] == BUTTON_PRESSED ? 1.0f : 0.0f;
|
{
|
||||||
|
const auto button = m_buttons.find(binding->second->m_button_type);
|
||||||
|
if (button == m_buttons.end())
|
||||||
|
return 0.0f;
|
||||||
|
return button->second == BUTTON_PRESSED ? 1.0f : 0.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace ButtonManager
|
} // namespace ButtonManager
|
||||||
|
|
|
@ -210,7 +210,7 @@ private:
|
||||||
public:
|
public:
|
||||||
Button() : m_state(BUTTON_RELEASED) {}
|
Button() : m_state(BUTTON_RELEASED) {}
|
||||||
void SetState(ButtonState state) { m_state = state; }
|
void SetState(ButtonState state) { m_state = state; }
|
||||||
bool Pressed() { return m_state == BUTTON_PRESSED; }
|
bool Pressed() const { return m_state == BUTTON_PRESSED; }
|
||||||
~Button() {}
|
~Button() {}
|
||||||
};
|
};
|
||||||
class Axis
|
class Axis
|
||||||
|
@ -221,7 +221,7 @@ private:
|
||||||
public:
|
public:
|
||||||
Axis() : m_value(0.0f) {}
|
Axis() : m_value(0.0f) {}
|
||||||
void SetValue(float value) { m_value = value; }
|
void SetValue(float value) { m_value = value; }
|
||||||
float AxisValue() { return m_value; }
|
float AxisValue() const { return m_value; }
|
||||||
~Axis() {}
|
~Axis() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ class InputDevice
|
||||||
private:
|
private:
|
||||||
const std::string m_dev;
|
const std::string m_dev;
|
||||||
std::map<ButtonType, bool> m_buttons;
|
std::map<ButtonType, bool> m_buttons;
|
||||||
std::map<ButtonType, float> m_axises;
|
std::map<ButtonType, float> m_axes;
|
||||||
|
|
||||||
// Key is pad_id and ButtonType
|
// Key is pad_id and ButtonType
|
||||||
std::map<std::pair<int, ButtonType>, sBind*> m_input_binds;
|
std::map<std::pair<int, ButtonType>, sBind*> m_input_binds;
|
||||||
|
@ -263,8 +263,8 @@ public:
|
||||||
}
|
}
|
||||||
bool PressEvent(int button, int action);
|
bool PressEvent(int button, int action);
|
||||||
void AxisEvent(int axis, float value);
|
void AxisEvent(int axis, float value);
|
||||||
bool ButtonValue(int pad_id, ButtonType button);
|
bool ButtonValue(int pad_id, ButtonType button) const;
|
||||||
float AxisValue(int pad_id, ButtonType axis);
|
float AxisValue(int pad_id, ButtonType axis) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init(const std::string&);
|
void Init(const std::string&);
|
||||||
|
|
|
@ -53,7 +53,7 @@ void ciface::Win32::Init(void* hwnd)
|
||||||
|
|
||||||
if (FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
|
if (FAILED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "CoInitializeEx failed: {}", GetLastError());
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "CoInitializeEx failed: {}", GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Common::ScopeGuard uninit([] { CoUninitialize(); });
|
Common::ScopeGuard uninit([] { CoUninitialize(); });
|
||||||
|
@ -67,12 +67,12 @@ void ciface::Win32::Init(void* hwnd)
|
||||||
ATOM window_class = RegisterClassEx(&window_class_info);
|
ATOM window_class = RegisterClassEx(&window_class_info);
|
||||||
if (!window_class)
|
if (!window_class)
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "RegisterClassEx failed: {}", GetLastError());
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "RegisterClassEx failed: {}", GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Common::ScopeGuard unregister([&window_class] {
|
Common::ScopeGuard unregister([&window_class] {
|
||||||
if (!UnregisterClass(MAKEINTATOM(window_class), GetModuleHandle(nullptr)))
|
if (!UnregisterClass(MAKEINTATOM(window_class), GetModuleHandle(nullptr)))
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "UnregisterClass failed: {}", GetLastError());
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "UnregisterClass failed: {}", GetLastError());
|
||||||
});
|
});
|
||||||
|
|
||||||
message_window = CreateWindowEx(0, L"Message", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
|
message_window = CreateWindowEx(0, L"Message", nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr,
|
||||||
|
@ -80,12 +80,12 @@ void ciface::Win32::Init(void* hwnd)
|
||||||
promise_guard.Exit();
|
promise_guard.Exit();
|
||||||
if (!message_window)
|
if (!message_window)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "CreateWindowEx failed: {}", GetLastError());
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "CreateWindowEx failed: {}", GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Common::ScopeGuard destroy([&] {
|
Common::ScopeGuard destroy([&] {
|
||||||
if (!DestroyWindow(message_window))
|
if (!DestroyWindow(message_window))
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "DestroyWindow failed: {}", GetLastError());
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "DestroyWindow failed: {}", GetLastError());
|
||||||
});
|
});
|
||||||
|
|
||||||
std::array<RAWINPUTDEVICE, 2> devices;
|
std::array<RAWINPUTDEVICE, 2> devices;
|
||||||
|
@ -103,7 +103,7 @@ void ciface::Win32::Init(void* hwnd)
|
||||||
if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
|
if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
|
||||||
static_cast<UINT>(sizeof(decltype(devices)::value_type))))
|
static_cast<UINT>(sizeof(decltype(devices)::value_type))))
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "RegisterRawInputDevices failed: {}", GetLastError());
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "RegisterRawInputDevices failed: {}", GetLastError());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,18 +128,18 @@ void ciface::Win32::PopulateDevices(void* hwnd)
|
||||||
s_done_populating.Reset();
|
s_done_populating.Reset();
|
||||||
PostMessage(s_message_window, WM_INPUT_DEVICE_CHANGE, 0, 0);
|
PostMessage(s_message_window, WM_INPUT_DEVICE_CHANGE, 0, 0);
|
||||||
if (!s_done_populating.WaitFor(std::chrono::seconds(10)))
|
if (!s_done_populating.WaitFor(std::chrono::seconds(10)))
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "win32 timed out when trying to populate devices");
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "win32 timed out when trying to populate devices");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE,
|
ERROR_LOG_FMT(CONTROLLERINTERFACE,
|
||||||
"win32 asked to populate devices, but device thread isn't running");
|
"win32 asked to populate devices, but device thread isn't running");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ciface::Win32::DeInit()
|
void ciface::Win32::DeInit()
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "win32 DeInit");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "win32 DeInit");
|
||||||
if (s_thread.joinable())
|
if (s_thread.joinable())
|
||||||
{
|
{
|
||||||
PostMessage(s_message_window, WM_DOLPHIN_STOP, 0, 0);
|
PostMessage(s_message_window, WM_DOLPHIN_STOP, 0, 0);
|
||||||
|
|
|
@ -253,7 +253,7 @@ static void AddDeviceNode(const char* devnode)
|
||||||
auto evdev_device = FindDeviceWithUniqueIDAndPhysicalLocation(uniq, phys);
|
auto evdev_device = FindDeviceWithUniqueIDAndPhysicalLocation(uniq, phys);
|
||||||
if (evdev_device)
|
if (evdev_device)
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE,
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE,
|
||||||
"evdev combining devices with unique id: {}, physical location: {}", uniq, phys);
|
"evdev combining devices with unique id: {}, physical location: {}", uniq, phys);
|
||||||
|
|
||||||
evdev_device->AddNode(devnode, fd, dev);
|
evdev_device->AddNode(devnode, fd, dev);
|
||||||
|
@ -282,7 +282,7 @@ static void AddDeviceNode(const char* devnode)
|
||||||
static void HotplugThreadFunc()
|
static void HotplugThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("evdev Hotplug Thread");
|
Common::SetCurrentThreadName("evdev Hotplug Thread");
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "evdev hotplug thread started");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "evdev hotplug thread started");
|
||||||
|
|
||||||
udev* const udev = udev_new();
|
udev* const udev = udev_new();
|
||||||
Common::ScopeGuard udev_guard([udev] { udev_unref(udev); });
|
Common::ScopeGuard udev_guard([udev] { udev_unref(udev); });
|
||||||
|
@ -337,7 +337,7 @@ static void HotplugThreadFunc()
|
||||||
AddDeviceNode(devnode);
|
AddDeviceNode(devnode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "evdev hotplug thread stopped");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "evdev hotplug thread stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StartHotplugThread()
|
static void StartHotplugThread()
|
||||||
|
|
|
@ -88,7 +88,8 @@ static void Read()
|
||||||
int err = libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap,
|
int err = libusb_interrupt_transfer(s_handle, s_endpoint_in, s_controller_payload_swap,
|
||||||
sizeof(s_controller_payload_swap), &payload_size, 16);
|
sizeof(s_controller_payload_swap), &payload_size, 16);
|
||||||
if (err)
|
if (err)
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "adapter libusb read failed: err={}", libusb_error_name(err));
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "adapter libusb read failed: err={}",
|
||||||
|
libusb_error_name(err));
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lk(s_mutex);
|
std::lock_guard<std::mutex> lk(s_mutex);
|
||||||
|
@ -121,7 +122,8 @@ static void Write()
|
||||||
const int err =
|
const int err =
|
||||||
libusb_interrupt_transfer(s_handle, s_endpoint_out, payload, sizeof(payload), &size, 16);
|
libusb_interrupt_transfer(s_handle, s_endpoint_out, payload, sizeof(payload), &size, 16);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "adapter libusb write failed: err={}", libusb_error_name(err));
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "adapter libusb write failed: err={}",
|
||||||
|
libusb_error_name(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +156,7 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl
|
||||||
static void ScanThreadFunc()
|
static void ScanThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
|
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread started");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread started");
|
||||||
|
|
||||||
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
|
#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102
|
||||||
#ifndef __FreeBSD__
|
#ifndef __FreeBSD__
|
||||||
|
@ -170,7 +172,7 @@ static void ScanThreadFunc()
|
||||||
nullptr, &s_hotplug_handle) != LIBUSB_SUCCESS)
|
nullptr, &s_hotplug_handle) != LIBUSB_SUCCESS)
|
||||||
s_libusb_hotplug_enabled = false;
|
s_libusb_hotplug_enabled = false;
|
||||||
if (s_libusb_hotplug_enabled)
|
if (s_libusb_hotplug_enabled)
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "Using libUSB hotplug detection");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Using libUSB hotplug detection");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -187,7 +189,7 @@ static void ScanThreadFunc()
|
||||||
else
|
else
|
||||||
Common::SleepCurrentThread(500);
|
Common::SleepCurrentThread(500);
|
||||||
}
|
}
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread stopped");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetAdapterCallback(std::function<void()> func)
|
void SetAdapterCallback(std::function<void()> func)
|
||||||
|
@ -265,7 +267,7 @@ static bool CheckDeviceAccess(libusb_device* device)
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
// could not acquire the descriptor, no point in trying to use it.
|
// could not acquire the descriptor, no point in trying to use it.
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_get_device_descriptor failed with error: {}", ret);
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_get_device_descriptor failed with error: {}", ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +277,7 @@ static bool CheckDeviceAccess(libusb_device* device)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "Found GC Adapter with Vendor: {:X} Product: {:X} Devnum: {}",
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "Found GC Adapter with Vendor: {:X} Product: {:X} Devnum: {}",
|
||||||
desc.idVendor, desc.idProduct, 1);
|
desc.idVendor, desc.idProduct, 1);
|
||||||
|
|
||||||
// In case of failure, capture the libusb error code into the adapter status
|
// In case of failure, capture the libusb error code into the adapter status
|
||||||
|
@ -287,14 +289,14 @@ static bool CheckDeviceAccess(libusb_device* device)
|
||||||
if (ret == LIBUSB_ERROR_ACCESS)
|
if (ret == LIBUSB_ERROR_ACCESS)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(
|
ERROR_LOG_FMT(
|
||||||
SERIALINTERFACE,
|
CONTROLLERINTERFACE,
|
||||||
"Dolphin does not have access to this device: Bus {:03d} Device {:03d}: ID {:04X}:{:04X}.",
|
"Dolphin does not have access to this device: Bus {:03d} Device {:03d}: ID {:04X}:{:04X}.",
|
||||||
bus, port, desc.idVendor, desc.idProduct);
|
bus, port, desc.idVendor, desc.idProduct);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_open failed to open device with error = {}", ret);
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_open failed to open device with error = {}", ret);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,14 +305,14 @@ static bool CheckDeviceAccess(libusb_device* device)
|
||||||
{
|
{
|
||||||
ret = libusb_detach_kernel_driver(s_handle, 0);
|
ret = libusb_detach_kernel_driver(s_handle, 0);
|
||||||
if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
|
if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED)
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: {}", ret);
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_detach_kernel_driver failed with error: {}", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This call makes Nyko-brand (and perhaps other) adapters work.
|
// This call makes Nyko-brand (and perhaps other) adapters work.
|
||||||
// However it returns LIBUSB_ERROR_PIPE with Mayflash adapters.
|
// However it returns LIBUSB_ERROR_PIPE with Mayflash adapters.
|
||||||
const int transfer = libusb_control_transfer(s_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
|
const int transfer = libusb_control_transfer(s_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
|
||||||
if (transfer < 0)
|
if (transfer < 0)
|
||||||
WARN_LOG_FMT(SERIALINTERFACE, "libusb_control_transfer failed with error: {}", transfer);
|
WARN_LOG_FMT(CONTROLLERINTERFACE, "libusb_control_transfer failed with error: {}", transfer);
|
||||||
|
|
||||||
// this split is needed so that we don't avoid claiming the interface when
|
// this split is needed so that we don't avoid claiming the interface when
|
||||||
// detaching the kernel driver is successful
|
// detaching the kernel driver is successful
|
||||||
|
@ -324,7 +326,7 @@ static bool CheckDeviceAccess(libusb_device* device)
|
||||||
ret = libusb_claim_interface(s_handle, 0);
|
ret = libusb_claim_interface(s_handle, 0);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "libusb_claim_interface failed with error: {}", ret);
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "libusb_claim_interface failed with error: {}", ret);
|
||||||
libusb_close(s_handle);
|
libusb_close(s_handle);
|
||||||
s_handle = nullptr;
|
s_handle = nullptr;
|
||||||
return false;
|
return false;
|
||||||
|
@ -410,7 +412,7 @@ static void Reset()
|
||||||
}
|
}
|
||||||
if (s_detect_callback != nullptr)
|
if (s_detect_callback != nullptr)
|
||||||
s_detect_callback();
|
s_detect_callback();
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter detached");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter detached");
|
||||||
}
|
}
|
||||||
|
|
||||||
GCPadStatus Input(int chan)
|
GCPadStatus Input(int chan)
|
||||||
|
@ -436,8 +438,8 @@ GCPadStatus Input(int chan)
|
||||||
controller_payload_copy[0] != LIBUSB_DT_HID)
|
controller_payload_copy[0] != LIBUSB_DT_HID)
|
||||||
{
|
{
|
||||||
// This can occur for a few frames on initialization.
|
// This can occur for a few frames on initialization.
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "error reading payload (size: {}, type: {:02x})", payload_size,
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})",
|
||||||
controller_payload_copy[0]);
|
payload_size, controller_payload_copy[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -446,8 +448,8 @@ GCPadStatus Input(int chan)
|
||||||
if (type != ControllerTypes::CONTROLLER_NONE &&
|
if (type != ControllerTypes::CONTROLLER_NONE &&
|
||||||
s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE)
|
s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE)
|
||||||
{
|
{
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "New device connected to Port {} of Type: {:02x}", chan + 1,
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "New device connected to Port {} of Type: {:02x}",
|
||||||
controller_payload_copy[1 + (9 * chan)]);
|
chan + 1, controller_payload_copy[1 + (9 * chan)]);
|
||||||
get_origin = true;
|
get_origin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,7 +553,7 @@ static void ResetRumbleLockNeeded()
|
||||||
int size = 0;
|
int size = 0;
|
||||||
libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16);
|
libusb_interrupt_transfer(s_handle, s_endpoint_out, rumble, sizeof(rumble), &size, 16);
|
||||||
|
|
||||||
INFO_LOG_FMT(SERIALINTERFACE, "Rumble state reset");
|
INFO_LOG_FMT(CONTROLLERINTERFACE, "Rumble state reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output(int chan, u8 rumble_command)
|
void Output(int chan, u8 rumble_command)
|
||||||
|
|
|
@ -64,7 +64,7 @@ static u64 s_last_init = 0;
|
||||||
static void ScanThreadFunc()
|
static void ScanThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
|
Common::SetCurrentThreadName("GC Adapter Scanning Thread");
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread started");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread started");
|
||||||
|
|
||||||
JNIEnv* env = IDCache::GetEnvForThread();
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
|
|
||||||
|
@ -78,13 +78,13 @@ static void ScanThreadFunc()
|
||||||
Common::SleepCurrentThread(1000);
|
Common::SleepCurrentThread(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter scanning thread stopped");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter scanning thread stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Write()
|
static void Write()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("GC Adapter Write Thread");
|
Common::SetCurrentThreadName("GC Adapter Write Thread");
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter write thread started");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter write thread started");
|
||||||
|
|
||||||
JNIEnv* env = IDCache::GetEnvForThread();
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I");
|
jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I");
|
||||||
|
@ -108,7 +108,7 @@ static void Write()
|
||||||
// Netplay sends invalid data which results in size = 0x00. Ignore it.
|
// Netplay sends invalid data which results in size = 0x00. Ignore it.
|
||||||
if (size != write_size && size != 0x00)
|
if (size != write_size && size != 0x00)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "error writing rumble (size: {})", size);
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error writing rumble (size: {})", size);
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,13 +116,13 @@ static void Write()
|
||||||
Common::YieldCPU();
|
Common::YieldCPU();
|
||||||
}
|
}
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter write thread stopped");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter write thread stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Read()
|
static void Read()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("GC Adapter Read Thread");
|
Common::SetCurrentThreadName("GC Adapter Read Thread");
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter read thread started");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter read thread started");
|
||||||
|
|
||||||
bool first_read = true;
|
bool first_read = true;
|
||||||
JNIEnv* env = IDCache::GetEnvForThread();
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
|
@ -179,7 +179,7 @@ static void Read()
|
||||||
s_fd = 0;
|
s_fd = 0;
|
||||||
s_detected = false;
|
s_detected = false;
|
||||||
|
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter read thread stopped");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter read thread stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
|
@ -229,7 +229,7 @@ static void Reset()
|
||||||
|
|
||||||
s_detected = false;
|
s_detected = false;
|
||||||
s_fd = 0;
|
s_fd = 0;
|
||||||
NOTICE_LOG_FMT(SERIALINTERFACE, "GC Adapter detached");
|
NOTICE_LOG_FMT(CONTROLLERINTERFACE, "GC Adapter detached");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
|
@ -270,8 +270,8 @@ GCPadStatus Input(int chan)
|
||||||
GCPadStatus pad = {};
|
GCPadStatus pad = {};
|
||||||
if (payload_size != controller_payload_copy.size())
|
if (payload_size != controller_payload_copy.size())
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "error reading payload (size: {}, type: {:02x})", payload_size,
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})",
|
||||||
controller_payload_copy[0]);
|
payload_size, controller_payload_copy[0]);
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -281,8 +281,8 @@ GCPadStatus Input(int chan)
|
||||||
if (type != ControllerTypes::CONTROLLER_NONE &&
|
if (type != ControllerTypes::CONTROLLER_NONE &&
|
||||||
s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE)
|
s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE)
|
||||||
{
|
{
|
||||||
ERROR_LOG_FMT(SERIALINTERFACE, "New device connected to Port {} of Type: {:02x}", chan + 1,
|
ERROR_LOG_FMT(CONTROLLERINTERFACE, "New device connected to Port {} of Type: {:02x}",
|
||||||
controller_payload_copy[1 + (9 * chan)]);
|
chan + 1, controller_payload_copy[1 + (9 * chan)]);
|
||||||
get_origin = true;
|
get_origin = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,6 @@ bool InputConfig::LoadConfig(bool isGC)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
controller->LoadConfig(&config);
|
controller->LoadConfig(&config);
|
||||||
// Update refs
|
|
||||||
controller->UpdateReferences(g_controller_interface);
|
controller->UpdateReferences(g_controller_interface);
|
||||||
controller_names.push_back(controller->GetName());
|
controller_names.push_back(controller->GetName());
|
||||||
|
|
||||||
|
@ -171,7 +170,7 @@ void InputConfig::SaveConfig()
|
||||||
inifile.Save(ini_filename);
|
inifile.Save(ini_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerEmu::EmulatedController* InputConfig::GetController(int index)
|
ControllerEmu::EmulatedController* InputConfig::GetController(int index) const
|
||||||
{
|
{
|
||||||
return m_controllers.at(index).get();
|
return m_controllers.at(index).get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
m_controllers.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
|
m_controllers.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerEmu::EmulatedController* GetController(int index);
|
ControllerEmu::EmulatedController* GetController(int index) const;
|
||||||
void ClearControllers();
|
void ClearControllers();
|
||||||
bool ControllersNeedToBeCreated() const;
|
bool ControllersNeedToBeCreated() const;
|
||||||
bool IsControllerControlledByGamepadDevice(int index) const;
|
bool IsControllerControlledByGamepadDevice(int index) const;
|
||||||
|
|
|
@ -776,6 +776,7 @@ void Renderer::UpdateDrawRectangle()
|
||||||
const float win_width = static_cast<float>(m_backbuffer_width);
|
const float win_width = static_cast<float>(m_backbuffer_width);
|
||||||
const float win_height = static_cast<float>(m_backbuffer_height);
|
const float win_height = static_cast<float>(m_backbuffer_height);
|
||||||
|
|
||||||
|
// FIXME: this breaks at very low widget sizes
|
||||||
// Make ControllerInterface aware of the render window region actually being used
|
// Make ControllerInterface aware of the render window region actually being used
|
||||||
// to adjust mouse cursor inputs.
|
// to adjust mouse cursor inputs.
|
||||||
g_controller_interface.SetAspectRatioAdjustment(draw_aspect_ratio / (win_width / win_height));
|
g_controller_interface.SetAspectRatioAdjustment(draw_aspect_ratio / (win_width / win_height));
|
||||||
|
|
Loading…
Reference in New Issue