diff options
Diffstat (limited to 'src/input_common/tas/tas_input.h')
| -rw-r--r-- | src/input_common/tas/tas_input.h | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h new file mode 100644 index 000000000..0a152a04f --- /dev/null +++ b/src/input_common/tas/tas_input.h | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <mutex> | ||
| 9 | #include <thread> | ||
| 10 | |||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "core/frontend/input.h" | ||
| 13 | #include "input_common/main.h" | ||
| 14 | |||
| 15 | #define PLAYER_NUMBER 8 | ||
| 16 | |||
| 17 | namespace TasInput { | ||
| 18 | |||
| 19 | using TasAnalog = std::tuple<float, float>; | ||
| 20 | |||
| 21 | enum class TasButton : u32 { | ||
| 22 | BUTTON_A = 0x000001, | ||
| 23 | BUTTON_B = 0x000002, | ||
| 24 | BUTTON_X = 0x000004, | ||
| 25 | BUTTON_Y = 0x000008, | ||
| 26 | STICK_L = 0x000010, | ||
| 27 | STICK_R = 0x000020, | ||
| 28 | TRIGGER_L = 0x000040, | ||
| 29 | TRIGGER_R = 0x000080, | ||
| 30 | TRIGGER_ZL = 0x000100, | ||
| 31 | TRIGGER_ZR = 0x000200, | ||
| 32 | BUTTON_PLUS = 0x000400, | ||
| 33 | BUTTON_MINUS = 0x000800, | ||
| 34 | BUTTON_LEFT = 0x001000, | ||
| 35 | BUTTON_UP = 0x002000, | ||
| 36 | BUTTON_RIGHT = 0x004000, | ||
| 37 | BUTTON_DOWN = 0x008000, | ||
| 38 | BUTTON_SL = 0x010000, | ||
| 39 | BUTTON_SR = 0x020000, | ||
| 40 | BUTTON_HOME = 0x040000, | ||
| 41 | BUTTON_CAPTURE = 0x080000, | ||
| 42 | }; | ||
| 43 | |||
| 44 | static const std::array<std::pair<std::string, TasButton>, 20> text_to_tas_button = { | ||
| 45 | std::pair{"KEY_A", TasButton::BUTTON_A}, | ||
| 46 | {"KEY_B", TasButton::BUTTON_B}, | ||
| 47 | {"KEY_X", TasButton::BUTTON_X}, | ||
| 48 | {"KEY_Y", TasButton::BUTTON_Y}, | ||
| 49 | {"KEY_LSTICK", TasButton::STICK_L}, | ||
| 50 | {"KEY_RSTICK", TasButton::STICK_R}, | ||
| 51 | {"KEY_L", TasButton::TRIGGER_L}, | ||
| 52 | {"KEY_R", TasButton::TRIGGER_R}, | ||
| 53 | {"KEY_PLUS", TasButton::BUTTON_PLUS}, | ||
| 54 | {"KEY_MINUS", TasButton::BUTTON_MINUS}, | ||
| 55 | {"KEY_DLEFT", TasButton::BUTTON_LEFT}, | ||
| 56 | {"KEY_DUP", TasButton::BUTTON_UP}, | ||
| 57 | {"KEY_DRIGHT", TasButton::BUTTON_RIGHT}, | ||
| 58 | {"KEY_DDOWN", TasButton::BUTTON_DOWN}, | ||
| 59 | {"KEY_SL", TasButton::BUTTON_SL}, | ||
| 60 | {"KEY_SR", TasButton::BUTTON_SR}, | ||
| 61 | {"KEY_CAPTURE", TasButton::BUTTON_CAPTURE}, | ||
| 62 | {"KEY_HOME", TasButton::BUTTON_HOME}, | ||
| 63 | {"KEY_ZL", TasButton::TRIGGER_ZL}, | ||
| 64 | {"KEY_ZR", TasButton::TRIGGER_ZR}, | ||
| 65 | }; | ||
| 66 | |||
| 67 | enum class TasAxes : u8 { | ||
| 68 | StickX, | ||
| 69 | StickY, | ||
| 70 | SubstickX, | ||
| 71 | SubstickY, | ||
| 72 | Undefined, | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct TasData { | ||
| 76 | u32 buttons{}; | ||
| 77 | std::array<float, 4> axis{}; | ||
| 78 | }; | ||
| 79 | |||
| 80 | class Tas { | ||
| 81 | public: | ||
| 82 | Tas(); | ||
| 83 | ~Tas(); | ||
| 84 | |||
| 85 | static std::string buttonsToString(u32 button) { | ||
| 86 | std::string returns; | ||
| 87 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_A)) != 0) | ||
| 88 | returns += ", A"; | ||
| 89 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_B)) != 0) | ||
| 90 | returns += ", B"; | ||
| 91 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_X)) != 0) | ||
| 92 | returns += ", X"; | ||
| 93 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_Y)) != 0) | ||
| 94 | returns += ", Y"; | ||
| 95 | if ((button & static_cast<u32>(TasInput::TasButton::STICK_L)) != 0) | ||
| 96 | returns += ", STICK_L"; | ||
| 97 | if ((button & static_cast<u32>(TasInput::TasButton::STICK_R)) != 0) | ||
| 98 | returns += ", STICK_R"; | ||
| 99 | if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_L)) != 0) | ||
| 100 | returns += ", TRIGGER_L"; | ||
| 101 | if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_R)) != 0) | ||
| 102 | returns += ", TRIGGER_R"; | ||
| 103 | if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_ZL)) != 0) | ||
| 104 | returns += ", TRIGGER_ZL"; | ||
| 105 | if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_ZR)) != 0) | ||
| 106 | returns += ", TRIGGER_ZR"; | ||
| 107 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_PLUS)) != 0) | ||
| 108 | returns += ", PLUS"; | ||
| 109 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_MINUS)) != 0) | ||
| 110 | returns += ", MINUS"; | ||
| 111 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_LEFT)) != 0) | ||
| 112 | returns += ", LEFT"; | ||
| 113 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_UP)) != 0) | ||
| 114 | returns += ", UP"; | ||
| 115 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_RIGHT)) != 0) | ||
| 116 | returns += ", RIGHT"; | ||
| 117 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_DOWN)) != 0) | ||
| 118 | returns += ", DOWN"; | ||
| 119 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_SL)) != 0) | ||
| 120 | returns += ", SL"; | ||
| 121 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_SR)) != 0) | ||
| 122 | returns += ", SR"; | ||
| 123 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_HOME)) != 0) | ||
| 124 | returns += ", HOME"; | ||
| 125 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_CAPTURE)) != 0) | ||
| 126 | returns += ", CAPTURE"; | ||
| 127 | return returns.length() != 0 ? returns.substr(2) : ""; | ||
| 128 | } | ||
| 129 | |||
| 130 | void RefreshTasFile(); | ||
| 131 | void LoadTasFiles(); | ||
| 132 | void RecordInput(u32 buttons, std::array<std::pair<float, float>, 2> axes); | ||
| 133 | void UpdateThread(); | ||
| 134 | std::string GetStatusDescription(); | ||
| 135 | |||
| 136 | InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; | ||
| 137 | InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; | ||
| 138 | [[nodiscard]] const TasData& GetTasState(std::size_t pad) const; | ||
| 139 | |||
| 140 | private: | ||
| 141 | struct TASCommand { | ||
| 142 | u32 buttons{}; | ||
| 143 | TasAnalog l_axis{}; | ||
| 144 | TasAnalog r_axis{}; | ||
| 145 | }; | ||
| 146 | void LoadTasFile(int playerIndex); | ||
| 147 | void WriteTasFile(); | ||
| 148 | TasAnalog ReadCommandAxis(const std::string line) const; | ||
| 149 | u32 ReadCommandButtons(const std::string line) const; | ||
| 150 | std::string WriteCommandButtons(u32 data) const; | ||
| 151 | std::string WriteCommandAxis(TasAnalog data) const; | ||
| 152 | std::pair<float, float> flipY(std::pair<float, float> old) const; | ||
| 153 | |||
| 154 | size_t scriptLength{0}; | ||
| 155 | std::array<TasData, PLAYER_NUMBER> tas_data; | ||
| 156 | bool update_thread_running{true}; | ||
| 157 | bool refresh_tas_fle{false}; | ||
| 158 | std::array<std::vector<TASCommand>, PLAYER_NUMBER> newCommands{}; | ||
| 159 | std::vector<TASCommand> recordCommands{}; | ||
| 160 | std::size_t current_command{0}; | ||
| 161 | TASCommand lastInput{}; // only used for recording | ||
| 162 | }; | ||
| 163 | } // namespace TasInput | ||