controller.cpp (6294B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "controller.h" 5 #include "analog_controller.h" 6 #include "analog_joystick.h" 7 #include "digital_controller.h" 8 #include "game_database.h" 9 #include "guncon.h" 10 #include "host.h" 11 #include "justifier.h" 12 #include "negcon.h" 13 #include "negcon_rumble.h" 14 #include "playstation_mouse.h" 15 #include "system.h" 16 17 #include "util/state_wrapper.h" 18 19 #include "fmt/format.h" 20 21 static const Controller::ControllerInfo s_none_info = {ControllerType::None, 22 "None", 23 TRANSLATE_NOOP("ControllerType", "Not Connected"), 24 nullptr, 25 {}, 26 {}, 27 Controller::VibrationCapabilities::NoVibration}; 28 29 static const Controller::ControllerInfo* s_controller_info[] = { 30 &s_none_info, &DigitalController::INFO, &AnalogController::INFO, &AnalogJoystick::INFO, 31 &NeGcon::INFO, &NeGconRumble::INFO, &GunCon::INFO, &PlayStationMouse::INFO, 32 &Justifier::INFO, 33 }; 34 35 const char* Controller::ControllerInfo::GetDisplayName() const 36 { 37 return Host::TranslateToCString("ControllerType", display_name); 38 } 39 40 Controller::Controller(u32 index) : m_index(index) 41 { 42 } 43 44 Controller::~Controller() = default; 45 46 void Controller::Reset() 47 { 48 } 49 50 bool Controller::DoState(StateWrapper& sw, bool apply_input_state) 51 { 52 return !sw.HasError(); 53 } 54 55 void Controller::ResetTransferState() 56 { 57 } 58 59 bool Controller::Transfer(const u8 data_in, u8* data_out) 60 { 61 *data_out = 0xFF; 62 return false; 63 } 64 65 float Controller::GetBindState(u32 index) const 66 { 67 return 0.0f; 68 } 69 70 void Controller::SetBindState(u32 index, float value) 71 { 72 } 73 74 u32 Controller::GetButtonStateBits() const 75 { 76 return 0; 77 } 78 79 bool Controller::InAnalogMode() const 80 { 81 return false; 82 } 83 84 std::optional<u32> Controller::GetAnalogInputBytes() const 85 { 86 return std::nullopt; 87 } 88 89 u32 Controller::GetInputOverlayIconColor() const 90 { 91 return 0xFFFFFFFFu; 92 } 93 94 void Controller::LoadSettings(SettingsInterface& si, const char* section, bool initial) 95 { 96 } 97 98 std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index) 99 { 100 switch (type) 101 { 102 case ControllerType::DigitalController: 103 return DigitalController::Create(index); 104 105 case ControllerType::AnalogController: 106 return AnalogController::Create(index); 107 108 case ControllerType::AnalogJoystick: 109 return AnalogJoystick::Create(index); 110 111 case ControllerType::GunCon: 112 return GunCon::Create(index); 113 114 case ControllerType::Justifier: 115 return Justifier::Create(index); 116 117 case ControllerType::PlayStationMouse: 118 return PlayStationMouse::Create(index); 119 120 case ControllerType::NeGcon: 121 return NeGcon::Create(index); 122 123 case ControllerType::NeGconRumble: 124 return NeGconRumble::Create(index); 125 126 case ControllerType::None: 127 default: 128 return {}; 129 } 130 } 131 132 const char* Controller::GetDefaultPadType(u32 pad) 133 { 134 return GetControllerInfo((pad == 0) ? Settings::DEFAULT_CONTROLLER_1_TYPE : Settings::DEFAULT_CONTROLLER_2_TYPE) 135 ->name; 136 } 137 138 const Controller::ControllerInfo* Controller::GetControllerInfo(ControllerType type) 139 { 140 for (const ControllerInfo* info : s_controller_info) 141 { 142 if (type == info->type) 143 return info; 144 } 145 146 return nullptr; 147 } 148 149 const Controller::ControllerInfo* Controller::GetControllerInfo(std::string_view name) 150 { 151 for (const ControllerInfo* info : s_controller_info) 152 { 153 if (name == info->name) 154 return info; 155 } 156 157 return nullptr; 158 } 159 160 std::vector<std::pair<std::string, std::string>> Controller::GetControllerTypeNames() 161 { 162 std::vector<std::pair<std::string, std::string>> ret; 163 for (const ControllerInfo* info : s_controller_info) 164 ret.emplace_back(info->name, Host::TranslateToString("ControllerType", info->display_name)); 165 166 return ret; 167 } 168 169 std::optional<u32> Controller::GetBindIndex(ControllerType type, std::string_view bind_name) 170 { 171 const ControllerInfo* info = GetControllerInfo(type); 172 if (!info) 173 return std::nullopt; 174 175 for (u32 i = 0; i < static_cast<u32>(info->bindings.size()); i++) 176 { 177 if (bind_name == info->bindings[i].name) 178 return i; 179 } 180 181 return std::nullopt; 182 } 183 184 std::tuple<u32, u32> Controller::ConvertPadToPortAndSlot(u32 index) 185 { 186 if (index > 4) // [5,6,7] 187 return std::make_tuple(1, index - 4); // 2B,2C,2D 188 else if (index > 1) // [2,3,4] 189 return std::make_tuple(0, index - 1); // 1B,1C,1D 190 else // [0,1] 191 return std::make_tuple(index, 0); // 1A,2A 192 } 193 194 u32 Controller::ConvertPortAndSlotToPad(u32 port, u32 slot) 195 { 196 if (slot == 0) 197 return port; 198 else if (port == 0) // slot=[0,1] 199 return slot + 1; // 2,3,4 200 else 201 return slot + 4; // 5,6,7 202 } 203 204 bool Controller::PadIsMultitapSlot(u32 index) 205 { 206 return (index >= 2); 207 } 208 209 bool Controller::PortAndSlotIsMultitap(u32 port, u32 slot) 210 { 211 return (slot != 0); 212 } 213 214 std::string Controller::GetSettingsSection(u32 pad) 215 { 216 return fmt::format("Pad{}", pad + 1u); 217 } 218 219 bool Controller::InCircularDeadzone(float deadzone, float pos_x, float pos_y) 220 { 221 if (pos_x == 0.0f && pos_y == 0.0f) 222 return false; 223 224 // Compute the angle at the given position in the stick's square bounding box. 225 const float theta = std::atan2(pos_y, pos_x); 226 227 // Compute the position that the edge of the circle would be at, given the angle. 228 const float dz_x = std::cos(theta) * deadzone; 229 const float dz_y = std::sin(theta) * deadzone; 230 231 // We're in the deadzone if our position is less than the circle edge. 232 const bool in_x = (pos_x < 0.0f) ? (pos_x > dz_x) : (pos_x <= dz_x); 233 const bool in_y = (pos_y < 0.0f) ? (pos_y > dz_y) : (pos_y <= dz_y); 234 return (in_x && in_y); 235 } 236 237 bool Controller::CanStartInAnalogMode(ControllerType ctype) 238 { 239 const GameDatabase::Entry* dbentry = System::GetGameDatabaseEntry(); 240 if (!dbentry) 241 return false; 242 243 return ((dbentry->supported_controllers & (1u << static_cast<u8>(ctype))) != 0 && 244 !dbentry->HasTrait(GameDatabase::Trait::DisableAutoAnalogMode)); 245 }