From 157e0b85fdd805e02d234dccf1ce578e3159adee Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 2 Nov 2021 22:50:30 -0600 Subject: core/hid: Prevent Emulated controller from flapping with multiple inputs devices --- src/common/input.h | 4 ++ src/core/hid/emulated_controller.cpp | 68 +++++++++++++++++++++++++++++----- src/core/hid/emulated_controller.h | 6 +-- src/input_common/drivers/tas_input.cpp | 24 +++++------- src/input_common/drivers/tas_input.h | 11 ++---- 5 files changed, 77 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/common/input.h b/src/common/input.h index 8f29026a1..f21872b0a 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -11,6 +11,7 @@ #include #include "common/logging/log.h" #include "common/param_package.h" +#include "common/uuid.h" namespace Common::Input { @@ -81,6 +82,7 @@ struct AnalogStatus { }; struct ButtonStatus { + Common::UUID uuid{}; bool value{}; bool inverted{}; bool toggle{}; @@ -90,6 +92,7 @@ struct ButtonStatus { using BatteryStatus = BatteryLevel; struct StickStatus { + Common::UUID uuid{}; AnalogStatus x{}; AnalogStatus y{}; bool left{}; @@ -99,6 +102,7 @@ struct StickStatus { }; struct TriggerStatus { + Common::UUID uuid{}; AnalogStatus analog{}; ButtonStatus pressed{}; }; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 2db2b4da0..6fe3744fd 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -183,8 +183,11 @@ void EmulatedController::ReloadInput() { if (!button_devices[index]) { continue; } + const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetButton(callback, index, uuid); + }}; button_devices[index]->SetCallback(button_callback); button_devices[index]->ForceUpdate(); } @@ -193,8 +196,11 @@ void EmulatedController::ReloadInput() { if (!stick_devices[index]) { continue; } + const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; Common::Input::InputCallback stick_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetStick(callback, index, uuid); + }}; stick_devices[index]->SetCallback(stick_callback); stick_devices[index]->ForceUpdate(); } @@ -203,8 +209,11 @@ void EmulatedController::ReloadInput() { if (!trigger_devices[index]) { continue; } + const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; Common::Input::InputCallback trigger_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetTrigger(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetTrigger(callback, index, uuid); + }}; trigger_devices[index]->SetCallback(trigger_callback); trigger_devices[index]->ForceUpdate(); } @@ -229,13 +238,18 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } + // Use a common UUID for TAS + const auto tas_uuid = Common::UUID{0x0, 0x7A5}; + // Register TAS devices. No need to force update for (std::size_t index = 0; index < tas_button_devices.size(); ++index) { if (!tas_button_devices[index]) { continue; } Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; + [this, index, tas_uuid](Common::Input::CallbackStatus callback) { + SetButton(callback, index, tas_uuid); + }}; tas_button_devices[index]->SetCallback(button_callback); } @@ -244,7 +258,9 @@ void EmulatedController::ReloadInput() { continue; } Common::Input::InputCallback stick_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; + [this, index, tas_uuid](Common::Input::CallbackStatus callback) { + SetStick(callback, index, tas_uuid); + }}; tas_stick_devices[index]->SetCallback(stick_callback); } } @@ -423,7 +439,8 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage ReloadInput(); } -void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.button_values.size()) { return; } @@ -432,7 +449,16 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: bool value_changed = false; const auto new_status = TransformToButton(callback); auto& current_status = controller.button_values[index]; + + // Only read button values that have the same uuid or are pressed once + if (current_status.uuid != uuid) { + if (!new_status.value) { + return; + } + } + current_status.toggle = new_status.toggle; + current_status.uuid = uuid; // Update button status with current if (!current_status.toggle) { @@ -553,12 +579,23 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: TriggerOnChange(ControllerTriggerType::Button, true); } -void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.stick_values.size()) { return; } std::lock_guard lock{mutex}; - controller.stick_values[index] = TransformToStick(callback); + const auto stick_value = TransformToStick(callback); + + // Only read stick values that have the same uuid or are over the threshold to avoid flapping + if (controller.stick_values[index].uuid != uuid) { + if (!stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) { + return; + } + } + + controller.stick_values[index] = stick_value; + controller.stick_values[index].uuid = uuid; if (is_configuring) { controller.analog_stick_state.left = {}; @@ -592,12 +629,23 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s TriggerOnChange(ControllerTriggerType::Stick, true); } -void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.trigger_values.size()) { return; } std::lock_guard lock{mutex}; - controller.trigger_values[index] = TransformToTrigger(callback); + const auto trigger_value = TransformToTrigger(callback); + + // Only read trigger values that have the same uuid or are pressed once + if (controller.stick_values[index].uuid != uuid) { + if (!trigger_value.pressed.value) { + return; + } + } + + controller.trigger_values[index] = trigger_value; + controller.trigger_values[index].uuid = uuid; if (is_configuring) { controller.gc_trigger_state.left = 0; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 2f7afff56..9a8bdf14d 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -313,21 +313,21 @@ private: * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetButton(Common::Input::CallbackStatus callback, std::size_t index); + void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the analog stick status of the controller * @param callback: A CallbackStatus containing the analog stick status * @param index: stick ID of the to be updated */ - void SetStick(Common::Input::CallbackStatus callback, std::size_t index); + void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the trigger status of the controller * @param callback: A CallbackStatus containing the trigger status * @param index: trigger ID of the to be updated */ - void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index); + void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the motion status of the controller diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index d2748b240..bb9c236ea 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -71,21 +71,21 @@ Tas::~Tas() { void Tas::LoadTasFiles() { script_length = 0; for (size_t i = 0; i < commands.size(); i++) { - LoadTasFile(i); + LoadTasFile(i, 0); if (commands[i].size() > script_length) { script_length = commands[i].size(); } } } -void Tas::LoadTasFile(size_t player_index) { +void Tas::LoadTasFile(size_t player_index, size_t file_index) { if (!commands[player_index].empty()) { commands[player_index].clear(); } - std::string file = - Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / - fmt::format("script0-{}.txt", player_index + 1), - Common::FS::FileType::BinaryFile); + std::string file = Common::FS::ReadStringFromFile( + Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / + fmt::format("script{}-{}.txt", file_index, player_index + 1), + Common::FS::FileType::BinaryFile); std::stringstream command_line(file); std::string line; int frame_no = 0; @@ -144,15 +144,8 @@ void Tas::WriteTasFile(std::u8string file_name) { void Tas::RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis) { last_input = { .buttons = buttons, - .l_axis = FlipAxisY(left_axis), - .r_axis = FlipAxisY(right_axis), - }; -} - -TasAnalog Tas::FlipAxisY(TasAnalog old) { - return { - .x = old.x, - .y = -old.y, + .l_axis = left_axis, + .r_axis = right_axis, }; } @@ -219,6 +212,7 @@ void Tas::UpdateThread() { } } else { is_running = Settings::values.tas_loop.GetValue(); + LoadTasFiles(); current_command = 0; ClearInput(); } diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 82dc9d616..bfb37a638 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -138,21 +138,16 @@ private: void LoadTasFiles(); /** Loads TAS file from the specified player - * @param player_index: player number where data is going to be stored + * @param player_index: player number to save the script + * @param file_index: script number of the file */ - void LoadTasFile(size_t player_index); + void LoadTasFile(size_t player_index, size_t file_index); /** Writes a TAS file from the recorded commands * @param file_name: name of the file to be written */ void WriteTasFile(std::u8string file_name); - /** Inverts the Y axis polarity - * @param old: value of the axis - * @return new value of the axis - */ - TasAnalog FlipAxisY(TasAnalog old); - /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 * @param line: string containing axis values with the following format "x;y" -- cgit v1.2.3