mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-28 17:35:43 -04:00
CommonHostInterface: Implement controller autofire
This commit is contained in:
parent
c7beac5efd
commit
01c869b704
@ -569,7 +569,7 @@ void AndroidHostInterface::EmulationThreadLoop(JNIEnv* env)
|
|||||||
else
|
else
|
||||||
System::RunFrame();
|
System::RunFrame();
|
||||||
|
|
||||||
UpdateControllerRumble();
|
UpdateControllerMetaState();
|
||||||
if (m_vibration_enabled)
|
if (m_vibration_enabled)
|
||||||
UpdateVibration();
|
UpdateVibration();
|
||||||
}
|
}
|
||||||
|
@ -213,7 +213,7 @@ void NoGUIHostInterface::Run()
|
|||||||
else
|
else
|
||||||
System::RunFrames();
|
System::RunFrames();
|
||||||
|
|
||||||
UpdateControllerRumble();
|
UpdateControllerMetaState();
|
||||||
if (m_frame_step_request)
|
if (m_frame_step_request)
|
||||||
{
|
{
|
||||||
m_frame_step_request = false;
|
m_frame_step_request = false;
|
||||||
|
@ -1485,7 +1485,7 @@ void QtHostInterface::threadEntryPoint()
|
|||||||
else
|
else
|
||||||
System::RunFrames();
|
System::RunFrames();
|
||||||
|
|
||||||
UpdateControllerRumble();
|
UpdateControllerMetaState();
|
||||||
if (m_frame_step_request)
|
if (m_frame_step_request)
|
||||||
{
|
{
|
||||||
m_frame_step_request = false;
|
m_frame_step_request = false;
|
||||||
|
@ -1427,6 +1427,73 @@ void CommonHostInterface::StopControllerRumble()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::SetControllerAutoFireState(u32 controller_index, s32 button_code, bool active)
|
||||||
|
{
|
||||||
|
for (ControllerAutoFireState& ts : m_controller_autofires)
|
||||||
|
{
|
||||||
|
if (ts.controller_index != controller_index || ts.button_code != button_code)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!active)
|
||||||
|
{
|
||||||
|
if (ts.state)
|
||||||
|
{
|
||||||
|
Controller* controller = System::GetController(ts.controller_index);
|
||||||
|
if (controller)
|
||||||
|
controller->SetButtonState(ts.button_code, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.state = false;
|
||||||
|
ts.countdown = ts.frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.active = active;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::UpdateControllerAutoFire()
|
||||||
|
{
|
||||||
|
for (ControllerAutoFireState& ts : m_controller_autofires)
|
||||||
|
{
|
||||||
|
if (!ts.active || (--ts.countdown) > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ts.countdown = ts.frequency;
|
||||||
|
ts.state = !ts.state;
|
||||||
|
|
||||||
|
Controller* controller = System::GetController(ts.controller_index);
|
||||||
|
if (controller)
|
||||||
|
controller->SetButtonState(ts.button_code, ts.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::StopControllerAutoFire()
|
||||||
|
{
|
||||||
|
for (ControllerAutoFireState& ts : m_controller_autofires)
|
||||||
|
{
|
||||||
|
if (!ts.active)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ts.countdown = ts.frequency;
|
||||||
|
|
||||||
|
if (ts.state)
|
||||||
|
{
|
||||||
|
Controller* controller = System::GetController(ts.controller_index);
|
||||||
|
if (controller)
|
||||||
|
controller->SetButtonState(ts.button_code, false);
|
||||||
|
|
||||||
|
ts.state = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::UpdateControllerMetaState()
|
||||||
|
{
|
||||||
|
UpdateControllerRumble();
|
||||||
|
UpdateControllerAutoFire();
|
||||||
|
}
|
||||||
|
|
||||||
static bool SplitBinding(const std::string& binding, std::string_view* device, std::string_view* sub_binding)
|
static bool SplitBinding(const std::string& binding, std::string_view* device, std::string_view* sub_binding)
|
||||||
{
|
{
|
||||||
const std::string::size_type slash_pos = binding.find('/');
|
const std::string::size_type slash_pos = binding.find('/');
|
||||||
@ -1443,8 +1510,10 @@ static bool SplitBinding(const std::string& binding, std::string_view* device, s
|
|||||||
|
|
||||||
void CommonHostInterface::UpdateControllerInputMap(SettingsInterface& si)
|
void CommonHostInterface::UpdateControllerInputMap(SettingsInterface& si)
|
||||||
{
|
{
|
||||||
|
StopControllerAutoFire();
|
||||||
StopControllerRumble();
|
StopControllerRumble();
|
||||||
m_controller_vibration_motors.clear();
|
m_controller_vibration_motors.clear();
|
||||||
|
m_controller_autofires.clear();
|
||||||
|
|
||||||
for (u32 controller_index = 0; controller_index < NUM_CONTROLLER_AND_CARD_PORTS; controller_index++)
|
for (u32 controller_index = 0; controller_index < NUM_CONTROLLER_AND_CARD_PORTS; controller_index++)
|
||||||
{
|
{
|
||||||
@ -1517,6 +1586,58 @@ void CommonHostInterface::UpdateControllerInputMap(SettingsInterface& si)
|
|||||||
const float deadzone_size = si.GetFloatValue(category, "Deadzone", 0.25f);
|
const float deadzone_size = si.GetFloatValue(category, "Deadzone", 0.25f);
|
||||||
m_controller_interface->SetControllerDeadzone(controller_index, deadzone_size);
|
m_controller_interface->SetControllerDeadzone(controller_index, deadzone_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (u32 turbo_button_index = 0; turbo_button_index < NUM_CONTROLLER_AUTOFIRE_BUTTONS; turbo_button_index++)
|
||||||
|
{
|
||||||
|
const std::string button_name(
|
||||||
|
si.GetStringValue(category, TinyString::FromFormat("AutoFire%uButton", turbo_button_index + 1), ""));
|
||||||
|
if (button_name.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::string binding(
|
||||||
|
si.GetStringValue(category, TinyString::FromFormat("AutoFire%u", turbo_button_index + 1), ""));
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
// Android doesn't require a binding, since we can trigger it from the touchscreen controller.
|
||||||
|
if (binding.empty())
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const std::optional<s32> button_code = Controller::GetButtonCodeByName(ctype, button_name);
|
||||||
|
if (!button_code.has_value())
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Invalid autofire button binding '%s'", button_name.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControllerAutoFireState ts;
|
||||||
|
ts.controller_index = controller_index;
|
||||||
|
ts.button_code = button_code.value();
|
||||||
|
ts.frequency = static_cast<u8>(
|
||||||
|
std::clamp<s32>(si.GetIntValue(category, TinyString::FromFormat("AutoFire%uFrequency", turbo_button_index + 1),
|
||||||
|
DEFAULT_AUTOFIRE_FREQUENCY),
|
||||||
|
1, std::numeric_limits<decltype(ts.frequency)>::max()));
|
||||||
|
ts.countdown = ts.frequency;
|
||||||
|
ts.active = false;
|
||||||
|
ts.state = false;
|
||||||
|
|
||||||
|
if (!binding.empty())
|
||||||
|
{
|
||||||
|
std::string_view device, button;
|
||||||
|
if (!SplitBinding(binding, &device, &button) ||
|
||||||
|
!AddButtonToInputMap(binding, device, button,
|
||||||
|
std::bind(&CommonHostInterface::SetControllerAutoFireState, this, controller_index,
|
||||||
|
button_code.value(), std::placeholders::_1)))
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to register binding '%s' for autofire button", binding.c_str());
|
||||||
|
#ifndef __ANDROID__
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_controller_autofires.push_back(ts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,9 @@ public:
|
|||||||
enum : s32
|
enum : s32
|
||||||
{
|
{
|
||||||
PER_GAME_SAVE_STATE_SLOTS = 10,
|
PER_GAME_SAVE_STATE_SLOTS = 10,
|
||||||
GLOBAL_SAVE_STATE_SLOTS = 10
|
GLOBAL_SAVE_STATE_SLOTS = 10,
|
||||||
|
NUM_CONTROLLER_AUTOFIRE_BUTTONS = 4,
|
||||||
|
DEFAULT_AUTOFIRE_FREQUENCY = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
using HostKeyCode = s32;
|
using HostKeyCode = s32;
|
||||||
@ -370,10 +372,17 @@ protected:
|
|||||||
virtual void UpdateInputMap(SettingsInterface& si);
|
virtual void UpdateInputMap(SettingsInterface& si);
|
||||||
void ClearInputMap();
|
void ClearInputMap();
|
||||||
|
|
||||||
|
/// Updates controller metastate, including turbo and rumble.
|
||||||
|
void UpdateControllerMetaState();
|
||||||
|
|
||||||
void AddControllerRumble(u32 controller_index, u32 num_motors, ControllerRumbleCallback callback);
|
void AddControllerRumble(u32 controller_index, u32 num_motors, ControllerRumbleCallback callback);
|
||||||
void UpdateControllerRumble();
|
void UpdateControllerRumble();
|
||||||
void StopControllerRumble();
|
void StopControllerRumble();
|
||||||
|
|
||||||
|
void SetControllerAutoFireState(u32 controller_index, s32 button_code, bool active);
|
||||||
|
void StopControllerAutoFire();
|
||||||
|
void UpdateControllerAutoFire();
|
||||||
|
|
||||||
/// Returns the path to a save state file. Specifying an index of -1 is the "resume" save state.
|
/// Returns the path to a save state file. Specifying an index of -1 is the "resume" save state.
|
||||||
std::string GetGameSaveStateFileName(const char* game_code, s32 slot) const;
|
std::string GetGameSaveStateFileName(const char* game_code, s32 slot) const;
|
||||||
|
|
||||||
@ -519,6 +528,18 @@ private:
|
|||||||
};
|
};
|
||||||
std::vector<ControllerRumbleState> m_controller_vibration_motors;
|
std::vector<ControllerRumbleState> m_controller_vibration_motors;
|
||||||
|
|
||||||
|
// controller turbo buttons
|
||||||
|
struct ControllerAutoFireState
|
||||||
|
{
|
||||||
|
u32 controller_index;
|
||||||
|
s32 button_code;
|
||||||
|
u8 frequency;
|
||||||
|
u8 countdown;
|
||||||
|
bool active;
|
||||||
|
bool state;
|
||||||
|
};
|
||||||
|
std::vector<ControllerAutoFireState> m_controller_autofires;
|
||||||
|
|
||||||
#ifdef WITH_DISCORD_PRESENCE
|
#ifdef WITH_DISCORD_PRESENCE
|
||||||
// discord rich presence
|
// discord rich presence
|
||||||
bool m_discord_presence_enabled = false;
|
bool m_discord_presence_enabled = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user