duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 }