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

digital_controller.cpp (7163B)


      1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> and contributors.
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "digital_controller.h"
      5 #include "host.h"
      6 #include "system.h"
      7 
      8 #include "util/state_wrapper.h"
      9 
     10 #include "IconsPromptFont.h"
     11 
     12 #include "common/assert.h"
     13 #include "common/bitutils.h"
     14 
     15 DigitalController::DigitalController(u32 index) : Controller(index)
     16 {
     17 }
     18 
     19 DigitalController::~DigitalController() = default;
     20 
     21 ControllerType DigitalController::GetType() const
     22 {
     23   return ControllerType::DigitalController;
     24 }
     25 
     26 void DigitalController::Reset()
     27 {
     28   m_transfer_state = TransferState::Idle;
     29 }
     30 
     31 bool DigitalController::DoState(StateWrapper& sw, bool apply_input_state)
     32 {
     33   if (!Controller::DoState(sw, apply_input_state))
     34     return false;
     35 
     36   u16 button_state = m_button_state;
     37   sw.Do(&button_state);
     38   if (apply_input_state)
     39     m_button_state = button_state;
     40 
     41   sw.Do(&m_transfer_state);
     42   return true;
     43 }
     44 
     45 float DigitalController::GetBindState(u32 index) const
     46 {
     47   if (index < static_cast<u32>(Button::Count))
     48   {
     49     return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
     50   }
     51   else
     52   {
     53     return 0.0f;
     54   }
     55 }
     56 
     57 void DigitalController::SetBindState(u32 index, float value)
     58 {
     59   if (index >= static_cast<u32>(Button::Count))
     60     return;
     61 
     62   const bool pressed = (value >= 0.5f);
     63   const u16 bit = u16(1) << static_cast<u8>(index);
     64   if (pressed)
     65   {
     66     if (m_button_state & bit)
     67       System::SetRunaheadReplayFlag();
     68 
     69     m_button_state &= ~bit;
     70   }
     71   else
     72   {
     73     if (!(m_button_state & bit))
     74       System::SetRunaheadReplayFlag();
     75 
     76     m_button_state |= bit;
     77   }
     78 }
     79 
     80 u32 DigitalController::GetButtonStateBits() const
     81 {
     82   return m_button_state ^ 0xFFFF;
     83 }
     84 
     85 void DigitalController::ResetTransferState()
     86 {
     87   m_transfer_state = TransferState::Idle;
     88 }
     89 
     90 bool DigitalController::Transfer(const u8 data_in, u8* data_out)
     91 {
     92   static constexpr u16 ID = 0x5A41;
     93 
     94   switch (m_transfer_state)
     95   {
     96     case TransferState::Idle:
     97     {
     98       *data_out = 0xFF;
     99 
    100       if (data_in == 0x01)
    101       {
    102         m_transfer_state = TransferState::Ready;
    103         return true;
    104       }
    105       return false;
    106     }
    107 
    108     case TransferState::Ready:
    109     {
    110       if (data_in == 0x42)
    111       {
    112         *data_out = Truncate8(ID);
    113         m_transfer_state = TransferState::IDMSB;
    114         return true;
    115       }
    116 
    117       *data_out = 0xFF;
    118       return false;
    119     }
    120 
    121     case TransferState::IDMSB:
    122     {
    123       *data_out = Truncate8(ID >> 8);
    124       m_transfer_state = TransferState::ButtonsLSB;
    125       return true;
    126     }
    127 
    128     case TransferState::ButtonsLSB:
    129     {
    130       *data_out = Truncate8(m_button_state) & GetButtonsLSBMask();
    131       m_transfer_state = TransferState::ButtonsMSB;
    132       return true;
    133     }
    134 
    135     case TransferState::ButtonsMSB:
    136       *data_out = Truncate8(m_button_state >> 8);
    137       m_transfer_state = TransferState::Idle;
    138       return false;
    139 
    140     default:
    141       UnreachableCode();
    142   }
    143 }
    144 
    145 std::unique_ptr<DigitalController> DigitalController::Create(u32 index)
    146 {
    147   return std::make_unique<DigitalController>(index);
    148 }
    149 
    150 static const Controller::ControllerBindingInfo s_binding_info[] = {
    151 #define BUTTON(name, display_name, icon_name, button, genb)                                                            \
    152   {                                                                                                                    \
    153     name, display_name, icon_name, static_cast<u32>(button), InputBindingInfo::Type::Button, genb                      \
    154   }
    155 
    156   // clang-format off
    157   BUTTON("Up", TRANSLATE_NOOP("DigitalController", "D-Pad Up"), ICON_PF_DPAD_UP, DigitalController::Button::Up, GenericInputBinding::DPadUp),
    158   BUTTON("Right", TRANSLATE_NOOP("DigitalController", "D-Pad Right"), ICON_PF_DPAD_RIGHT, DigitalController::Button::Right, GenericInputBinding::DPadRight),
    159   BUTTON("Down", TRANSLATE_NOOP("DigitalController", "D-Pad Down"), ICON_PF_DPAD_DOWN, DigitalController::Button::Down, GenericInputBinding::DPadDown),
    160   BUTTON("Left", TRANSLATE_NOOP("DigitalController", "D-Pad Left"), ICON_PF_DPAD_LEFT, DigitalController::Button::Left, GenericInputBinding::DPadLeft),
    161   BUTTON("Triangle", TRANSLATE_NOOP("DigitalController", "Triangle"), ICON_PF_BUTTON_TRIANGLE, DigitalController::Button::Triangle, GenericInputBinding::Triangle),
    162   BUTTON("Circle", TRANSLATE_NOOP("DigitalController", "Circle"), ICON_PF_BUTTON_CIRCLE, DigitalController::Button::Circle, GenericInputBinding::Circle),
    163   BUTTON("Cross", TRANSLATE_NOOP("DigitalController", "Cross"), ICON_PF_BUTTON_CROSS, DigitalController::Button::Cross, GenericInputBinding::Cross),
    164   BUTTON("Square", TRANSLATE_NOOP("DigitalController", "Square"), ICON_PF_BUTTON_SQUARE, DigitalController::Button::Square, GenericInputBinding::Square),
    165   BUTTON("Select", TRANSLATE_NOOP("DigitalController", "Select"), ICON_PF_SELECT_SHARE, DigitalController::Button::Select, GenericInputBinding::Select),
    166   BUTTON("Start", TRANSLATE_NOOP("DigitalController", "Start"), ICON_PF_START, DigitalController::Button::Start, GenericInputBinding::Start),
    167   BUTTON("L1", TRANSLATE_NOOP("DigitalController", "L1"), ICON_PF_LEFT_SHOULDER_L1, DigitalController::Button::L1, GenericInputBinding::L1),
    168   BUTTON("R1", TRANSLATE_NOOP("DigitalController", "R1"), ICON_PF_RIGHT_SHOULDER_R1, DigitalController::Button::R1, GenericInputBinding::R1),
    169   BUTTON("L2", TRANSLATE_NOOP("DigitalController", "L2"), ICON_PF_LEFT_TRIGGER_L2, DigitalController::Button::L2, GenericInputBinding::L2),
    170   BUTTON("R2", TRANSLATE_NOOP("DigitalController", "R2"), ICON_PF_RIGHT_TRIGGER_R2, DigitalController::Button::R2, GenericInputBinding::R2),
    171 // clang-format on
    172 
    173 #undef BUTTON
    174 };
    175 
    176 static const SettingInfo s_settings[] = {
    177   {SettingInfo::Type::Boolean, "ForcePopnControllerMode",
    178    TRANSLATE_NOOP("DigitalController", "Force Pop'n Controller Mode"),
    179    TRANSLATE_NOOP("DigitalController", "Forces the Digital Controller to act as a Pop'n Controller."), "false", nullptr,
    180    nullptr, nullptr, nullptr, nullptr, 0.0f}};
    181 
    182 const Controller::ControllerInfo DigitalController::INFO = {ControllerType::DigitalController,
    183                                                             "DigitalController",
    184                                                             TRANSLATE_NOOP("ControllerType", "Digital Controller"),
    185                                                             ICON_PF_GAMEPAD_ALT,
    186                                                             s_binding_info,
    187                                                             s_settings,
    188                                                             Controller::VibrationCapabilities::NoVibration};
    189 
    190 void DigitalController::LoadSettings(SettingsInterface& si, const char* section, bool initial)
    191 {
    192   Controller::LoadSettings(si, section, initial);
    193   m_popn_controller_mode = si.GetBoolValue(section, "ForcePopnControllerMode", false);
    194 }
    195 
    196 u8 DigitalController::GetButtonsLSBMask() const
    197 {
    198   constexpr u8 popn_controller_mask =
    199     static_cast<u8>(~(u8(1) << static_cast<u8>(Button::Right) | u8(1) << static_cast<u8>(Button::Down) |
    200                       u8(1) << static_cast<u8>(Button::Left)));
    201   return m_popn_controller_mode ? popn_controller_mask : 0xFF;
    202 }