// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include "common/common_types.h" #include "core/frontend/input.h" #include "input_common/main.h" #define PLAYER_NUMBER 8 namespace TasInput { using TasAnalog = std::tuple; enum class TasButton : u32 { BUTTON_A = 0x000001, BUTTON_B = 0x000002, BUTTON_X = 0x000004, BUTTON_Y = 0x000008, STICK_L = 0x000010, STICK_R = 0x000020, TRIGGER_L = 0x000040, TRIGGER_R = 0x000080, TRIGGER_ZL = 0x000100, TRIGGER_ZR = 0x000200, BUTTON_PLUS = 0x000400, BUTTON_MINUS = 0x000800, BUTTON_LEFT = 0x001000, BUTTON_UP = 0x002000, BUTTON_RIGHT = 0x004000, BUTTON_DOWN = 0x008000, BUTTON_SL = 0x010000, BUTTON_SR = 0x020000, BUTTON_HOME = 0x040000, BUTTON_CAPTURE = 0x080000, }; static const std::array, 20> text_to_tas_button = { std::pair{"KEY_A", TasButton::BUTTON_A}, {"KEY_B", TasButton::BUTTON_B}, {"KEY_X", TasButton::BUTTON_X}, {"KEY_Y", TasButton::BUTTON_Y}, {"KEY_LSTICK", TasButton::STICK_L}, {"KEY_RSTICK", TasButton::STICK_R}, {"KEY_L", TasButton::TRIGGER_L}, {"KEY_R", TasButton::TRIGGER_R}, {"KEY_PLUS", TasButton::BUTTON_PLUS}, {"KEY_MINUS", TasButton::BUTTON_MINUS}, {"KEY_DLEFT", TasButton::BUTTON_LEFT}, {"KEY_DUP", TasButton::BUTTON_UP}, {"KEY_DRIGHT", TasButton::BUTTON_RIGHT}, {"KEY_DDOWN", TasButton::BUTTON_DOWN}, {"KEY_SL", TasButton::BUTTON_SL}, {"KEY_SR", TasButton::BUTTON_SR}, {"KEY_CAPTURE", TasButton::BUTTON_CAPTURE}, {"KEY_HOME", TasButton::BUTTON_HOME}, {"KEY_ZL", TasButton::TRIGGER_ZL}, {"KEY_ZR", TasButton::TRIGGER_ZR}, }; enum class TasAxes : u8 { StickX, StickY, SubstickX, SubstickY, Undefined, }; struct TasData { u32 buttons{}; std::array axis{}; }; class Tas { public: Tas(); ~Tas(); static std::string buttonsToString(u32 button) { std::string returns; if ((button & static_cast(TasInput::TasButton::BUTTON_A)) != 0) returns += ", A"; if ((button & static_cast(TasInput::TasButton::BUTTON_B)) != 0) returns += ", B"; if ((button & static_cast(TasInput::TasButton::BUTTON_X)) != 0) returns += ", X"; if ((button & static_cast(TasInput::TasButton::BUTTON_Y)) != 0) returns += ", Y"; if ((button & static_cast(TasInput::TasButton::STICK_L)) != 0) returns += ", STICK_L"; if ((button & static_cast(TasInput::TasButton::STICK_R)) != 0) returns += ", STICK_R"; if ((button & static_cast(TasInput::TasButton::TRIGGER_L)) != 0) returns += ", TRIGGER_L"; if ((button & static_cast(TasInput::TasButton::TRIGGER_R)) != 0) returns += ", TRIGGER_R"; if ((button & static_cast(TasInput::TasButton::TRIGGER_ZL)) != 0) returns += ", TRIGGER_ZL"; if ((button & static_cast(TasInput::TasButton::TRIGGER_ZR)) != 0) returns += ", TRIGGER_ZR"; if ((button & static_cast(TasInput::TasButton::BUTTON_PLUS)) != 0) returns += ", PLUS"; if ((button & static_cast(TasInput::TasButton::BUTTON_MINUS)) != 0) returns += ", MINUS"; if ((button & static_cast(TasInput::TasButton::BUTTON_LEFT)) != 0) returns += ", LEFT"; if ((button & static_cast(TasInput::TasButton::BUTTON_UP)) != 0) returns += ", UP"; if ((button & static_cast(TasInput::TasButton::BUTTON_RIGHT)) != 0) returns += ", RIGHT"; if ((button & static_cast(TasInput::TasButton::BUTTON_DOWN)) != 0) returns += ", DOWN"; if ((button & static_cast(TasInput::TasButton::BUTTON_SL)) != 0) returns += ", SL"; if ((button & static_cast(TasInput::TasButton::BUTTON_SR)) != 0) returns += ", SR"; if ((button & static_cast(TasInput::TasButton::BUTTON_HOME)) != 0) returns += ", HOME"; if ((button & static_cast(TasInput::TasButton::BUTTON_CAPTURE)) != 0) returns += ", CAPTURE"; return returns.length() != 0 ? returns.substr(2) : ""; } void RefreshTasFile(); void LoadTasFiles(); void RecordInput(u32 buttons, std::array, 2> axes); void UpdateThread(); std::string GetStatusDescription(); InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; [[nodiscard]] const TasData& GetTasState(std::size_t pad) const; private: struct TASCommand { u32 buttons{}; TasAnalog l_axis{}; TasAnalog r_axis{}; }; void LoadTasFile(int playerIndex); void WriteTasFile(); TasAnalog ReadCommandAxis(const std::string line) const; u32 ReadCommandButtons(const std::string line) const; std::string WriteCommandButtons(u32 data) const; std::string WriteCommandAxis(TasAnalog data) const; std::pair flipY(std::pair old) const; size_t scriptLength{0}; std::array tas_data; bool update_thread_running{true}; bool refresh_tas_fle{false}; std::array, PLAYER_NUMBER> newCommands{}; std::vector recordCommands{}; std::size_t current_command{0}; TASCommand lastInput{}; // only used for recording }; } // namespace TasInput