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

analog_controller.cpp (33011B)


      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 "analog_controller.h"
      5 #include "host.h"
      6 #include "settings.h"
      7 #include "system.h"
      8 
      9 #include "util/imgui_manager.h"
     10 #include "util/input_manager.h"
     11 #include "util/state_wrapper.h"
     12 
     13 #include "common/bitutils.h"
     14 #include "common/log.h"
     15 #include "common/string_util.h"
     16 
     17 #include "IconsFontAwesome5.h"
     18 #include "IconsPromptFont.h"
     19 
     20 #include <cmath>
     21 
     22 Log_SetChannel(AnalogController);
     23 
     24 AnalogController::AnalogController(u32 index) : Controller(index)
     25 {
     26   m_status_byte = 0x5A;
     27   m_axis_state.fill(0x80);
     28   m_rumble_config.fill(0xFF);
     29 }
     30 
     31 AnalogController::~AnalogController() = default;
     32 
     33 ControllerType AnalogController::GetType() const
     34 {
     35   return ControllerType::AnalogController;
     36 }
     37 
     38 bool AnalogController::InAnalogMode() const
     39 {
     40   return m_analog_mode;
     41 }
     42 
     43 void AnalogController::Reset()
     44 {
     45   m_command = Command::Idle;
     46   m_command_step = 0;
     47   m_rx_buffer.fill(0x00);
     48   m_tx_buffer.fill(0x00);
     49   m_analog_mode = false;
     50   m_configuration_mode = false;
     51 
     52   for (u32 i = 0; i < NUM_MOTORS; i++)
     53   {
     54     if (m_motor_state[i] != 0)
     55       SetMotorState(i, 0);
     56   }
     57 
     58   m_dualshock_enabled = false;
     59   ResetRumbleConfig();
     60 
     61   m_status_byte = 0x5A;
     62 
     63   if (m_force_analog_on_reset)
     64   {
     65     if (!CanStartInAnalogMode(ControllerType::AnalogController))
     66     {
     67       Host::AddIconOSDMessage(
     68         fmt::format("Controller{}AnalogMode", m_index), ICON_PF_GAMEPAD_ALT,
     69         TRANSLATE_STR("OSDMessage",
     70                       "Analog mode forcing is disabled by game settings. Controller will start in digital mode."),
     71         10.0f);
     72     }
     73     else
     74     {
     75       SetAnalogMode(true, false);
     76     }
     77   }
     78 }
     79 
     80 bool AnalogController::DoState(StateWrapper& sw, bool apply_input_state)
     81 {
     82   if (!Controller::DoState(sw, apply_input_state))
     83     return false;
     84 
     85   const bool old_analog_mode = m_analog_mode;
     86 
     87   sw.Do(&m_analog_mode);
     88   sw.Do(&m_dualshock_enabled);
     89   sw.DoEx(&m_legacy_rumble_unlocked, 44, false);
     90   sw.Do(&m_configuration_mode);
     91   sw.Do(&m_command_param);
     92   sw.DoEx(&m_status_byte, 55, static_cast<u8>(0x5A));
     93 
     94   u16 button_state = m_button_state;
     95   sw.DoEx(&button_state, 44, static_cast<u16>(0xFFFF));
     96   if (apply_input_state)
     97     m_button_state = button_state;
     98 
     99   sw.Do(&m_command);
    100 
    101   sw.DoEx(&m_rumble_config, 45, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
    102   sw.DoEx(&m_rumble_config_large_motor_index, 45, -1);
    103   sw.DoEx(&m_rumble_config_small_motor_index, 45, -1);
    104   sw.DoEx(&m_analog_toggle_queued, 45, false);
    105 
    106   MotorState motor_state = m_motor_state;
    107   sw.Do(&motor_state);
    108 
    109   if (sw.IsReading())
    110   {
    111     for (u8 i = 0; i < NUM_MOTORS; i++)
    112       SetMotorState(i, motor_state[i]);
    113 
    114     if (old_analog_mode != m_analog_mode)
    115     {
    116       Host::AddIconOSDMessage(fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
    117                               fmt::format(m_analog_mode ?
    118                                             TRANSLATE_FS("AnalogController", "Controller {} switched to analog mode.") :
    119                                             TRANSLATE_FS("AnalogController", "Controller {} switched to digital mode."),
    120                                           m_index + 1u),
    121                               5.0f);
    122     }
    123   }
    124   return true;
    125 }
    126 
    127 float AnalogController::GetBindState(u32 index) const
    128 {
    129   if (index >= static_cast<u32>(Button::Count))
    130   {
    131     const u32 sub_index = index - static_cast<u32>(Button::Count);
    132     if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
    133       return 0.0f;
    134 
    135     return static_cast<float>(m_half_axis_state[sub_index]) * (1.0f / 255.0f);
    136   }
    137   else if (index < static_cast<u32>(Button::Analog))
    138   {
    139     return static_cast<float>(((m_button_state >> index) & 1u) ^ 1u);
    140   }
    141   else
    142   {
    143     return 0.0f;
    144   }
    145 }
    146 
    147 void AnalogController::SetBindState(u32 index, float value)
    148 {
    149   if (index == static_cast<s32>(Button::Analog))
    150   {
    151     // analog toggle
    152     if (value >= m_button_deadzone)
    153     {
    154       if (m_command == Command::Idle)
    155         ProcessAnalogModeToggle();
    156       else
    157         m_analog_toggle_queued = true;
    158     }
    159 
    160     return;
    161   }
    162   else if (index >= static_cast<u32>(Button::Count))
    163   {
    164     const u32 sub_index = index - static_cast<u32>(Button::Count);
    165     if (sub_index >= static_cast<u32>(m_half_axis_state.size()))
    166       return;
    167 
    168     const u8 u8_value = static_cast<u8>(std::clamp(value * m_analog_sensitivity * 255.0f, 0.0f, 255.0f));
    169     if (u8_value == m_half_axis_state[sub_index])
    170       return;
    171 
    172     m_half_axis_state[sub_index] = u8_value;
    173     System::SetRunaheadReplayFlag();
    174 
    175 #define MERGE(pos, neg)                                                                                                \
    176   ((m_half_axis_state[static_cast<u32>(pos)] != 0) ? (127u + ((m_half_axis_state[static_cast<u32>(pos)] + 1u) / 2u)) : \
    177                                                      (127u - (m_half_axis_state[static_cast<u32>(neg)] / 2u)))
    178     switch (static_cast<HalfAxis>(sub_index))
    179     {
    180       case HalfAxis::LLeft:
    181       case HalfAxis::LRight:
    182         m_axis_state[static_cast<u8>(Axis::LeftX)] = ((m_invert_left_stick & 1u) != 0u) ?
    183                                                        MERGE(HalfAxis::LLeft, HalfAxis::LRight) :
    184                                                        MERGE(HalfAxis::LRight, HalfAxis::LLeft);
    185         break;
    186 
    187       case HalfAxis::LDown:
    188       case HalfAxis::LUp:
    189         m_axis_state[static_cast<u8>(Axis::LeftY)] = ((m_invert_left_stick & 2u) != 0u) ?
    190                                                        MERGE(HalfAxis::LUp, HalfAxis::LDown) :
    191                                                        MERGE(HalfAxis::LDown, HalfAxis::LUp);
    192         break;
    193 
    194       case HalfAxis::RLeft:
    195       case HalfAxis::RRight:
    196         m_axis_state[static_cast<u8>(Axis::RightX)] = ((m_invert_right_stick & 1u) != 0u) ?
    197                                                         MERGE(HalfAxis::RLeft, HalfAxis::RRight) :
    198                                                         MERGE(HalfAxis::RRight, HalfAxis::RLeft);
    199         break;
    200 
    201       case HalfAxis::RDown:
    202       case HalfAxis::RUp:
    203         m_axis_state[static_cast<u8>(Axis::RightY)] = ((m_invert_right_stick & 2u) != 0u) ?
    204                                                         MERGE(HalfAxis::RUp, HalfAxis::RDown) :
    205                                                         MERGE(HalfAxis::RDown, HalfAxis::RUp);
    206         break;
    207 
    208       default:
    209         break;
    210     }
    211 
    212     if (m_analog_deadzone > 0.0f)
    213     {
    214 #define MERGE_F(pos, neg)                                                                                              \
    215   ((m_half_axis_state[static_cast<u32>(pos)] != 0) ?                                                                   \
    216      (static_cast<float>(m_half_axis_state[static_cast<u32>(pos)]) / 255.0f) :                                         \
    217      (static_cast<float>(m_half_axis_state[static_cast<u32>(neg)]) / -255.0f))
    218 
    219       float pos_x, pos_y;
    220       if (static_cast<HalfAxis>(sub_index) < HalfAxis::RLeft)
    221       {
    222         pos_x = ((m_invert_left_stick & 1u) != 0u) ? MERGE_F(HalfAxis::LLeft, HalfAxis::LRight) :
    223                                                      MERGE_F(HalfAxis::LRight, HalfAxis::LLeft);
    224         pos_y = ((m_invert_left_stick & 2u) != 0u) ? MERGE_F(HalfAxis::LUp, HalfAxis::LDown) :
    225                                                      MERGE_F(HalfAxis::LDown, HalfAxis::LUp);
    226       }
    227       else
    228       {
    229         pos_x = ((m_invert_right_stick & 1u) != 0u) ? MERGE_F(HalfAxis::RLeft, HalfAxis::RRight) :
    230                                                       MERGE_F(HalfAxis::RRight, HalfAxis::RLeft);
    231         ;
    232         pos_y = ((m_invert_right_stick & 2u) != 0u) ? MERGE_F(HalfAxis::RUp, HalfAxis::RDown) :
    233                                                       MERGE_F(HalfAxis::RDown, HalfAxis::RUp);
    234       }
    235 
    236       if (InCircularDeadzone(m_analog_deadzone, pos_x, pos_y))
    237       {
    238         // Set to 127 (center).
    239         if (static_cast<HalfAxis>(sub_index) < HalfAxis::RLeft)
    240           m_axis_state[static_cast<u8>(Axis::LeftX)] = m_axis_state[static_cast<u8>(Axis::LeftY)] = 127;
    241         else
    242           m_axis_state[static_cast<u8>(Axis::RightX)] = m_axis_state[static_cast<u8>(Axis::RightY)] = 127;
    243       }
    244 #undef MERGE_F
    245     }
    246 
    247 #undef MERGE
    248 
    249     return;
    250   }
    251 
    252   const u16 bit = u16(1) << static_cast<u8>(index);
    253 
    254   if (value >= m_button_deadzone)
    255   {
    256     if (m_button_state & bit)
    257       System::SetRunaheadReplayFlag();
    258 
    259     m_button_state &= ~(bit);
    260   }
    261   else
    262   {
    263     if (!(m_button_state & bit))
    264       System::SetRunaheadReplayFlag();
    265 
    266     m_button_state |= bit;
    267   }
    268 }
    269 
    270 u32 AnalogController::GetButtonStateBits() const
    271 {
    272   // flip bits, native data is active low
    273   return m_button_state ^ 0xFFFF;
    274 }
    275 
    276 std::optional<u32> AnalogController::GetAnalogInputBytes() const
    277 {
    278   return m_axis_state[static_cast<size_t>(Axis::LeftY)] << 24 | m_axis_state[static_cast<size_t>(Axis::LeftX)] << 16 |
    279          m_axis_state[static_cast<size_t>(Axis::RightY)] << 8 | m_axis_state[static_cast<size_t>(Axis::RightX)];
    280 }
    281 
    282 u32 AnalogController::GetInputOverlayIconColor() const
    283 {
    284   return m_analog_mode ? 0xFF2534F0u : 0xFFCCCCCCu;
    285 }
    286 
    287 void AnalogController::ResetTransferState()
    288 {
    289   if (m_analog_toggle_queued)
    290   {
    291     ProcessAnalogModeToggle();
    292     m_analog_toggle_queued = false;
    293   }
    294 
    295   m_command = Command::Idle;
    296   m_command_step = 0;
    297 }
    298 
    299 void AnalogController::SetAnalogMode(bool enabled, bool show_message)
    300 {
    301   if (m_analog_mode == enabled)
    302     return;
    303 
    304   INFO_LOG("Controller {} switched to {} mode.", m_index + 1u, m_analog_mode ? "analog" : "digital");
    305   if (show_message)
    306   {
    307     Host::AddIconOSDMessage(
    308       fmt::format("analog_mode_toggle_{}", m_index), ICON_PF_GAMEPAD_ALT,
    309       enabled ? fmt::format(TRANSLATE_FS("Controller", "Controller {} switched to analog mode."), m_index + 1u) :
    310                 fmt::format(TRANSLATE_FS("Controller", "Controller {} switched to digital mode."), m_index + 1u));
    311   }
    312 
    313   m_analog_mode = enabled;
    314 }
    315 
    316 void AnalogController::ProcessAnalogModeToggle()
    317 {
    318   if (m_analog_locked)
    319   {
    320     Host::AddIconOSDMessage(
    321       fmt::format("Controller{}AnalogMode", m_index), ICON_PF_GAMEPAD_ALT,
    322       fmt::format(m_analog_mode ?
    323                     TRANSLATE_FS("AnalogController", "Controller {} is locked to analog mode by the game.") :
    324                     TRANSLATE_FS("AnalogController", "Controller {} is locked to digital mode by the game."),
    325                   m_index + 1u),
    326       5.0f);
    327   }
    328   else
    329   {
    330     SetAnalogMode(!m_analog_mode, true);
    331     ResetRumbleConfig();
    332 
    333     if (m_dualshock_enabled)
    334       m_status_byte = 0x00;
    335   }
    336 }
    337 
    338 void AnalogController::SetMotorState(u32 motor, u8 value)
    339 {
    340   DebugAssert(motor < NUM_MOTORS);
    341   if (m_motor_state[motor] != value)
    342   {
    343     m_motor_state[motor] = value;
    344     UpdateHostVibration();
    345   }
    346 }
    347 
    348 void AnalogController::UpdateHostVibration()
    349 {
    350   std::array<float, NUM_MOTORS> hvalues;
    351   for (u32 motor = 0; motor < NUM_MOTORS; motor++)
    352   {
    353     // Curve from https://github.com/KrossX/Pokopom/blob/master/Pokopom/Input_XInput.cpp#L210
    354     const u8 state = m_motor_state[motor];
    355     const double x = static_cast<double>(std::min<u32>(state + static_cast<u32>(m_rumble_bias), 255));
    356     const double strength = 0.006474549734772402 * std::pow(x, 3.0) - 1.258165252213538 * std::pow(x, 2.0) +
    357                             156.82454281087692 * x + 3.637978807091713e-11;
    358 
    359     hvalues[motor] = (state != 0) ? static_cast<float>(strength / 65535.0) : 0.0f;
    360   }
    361 
    362   InputManager::SetPadVibrationIntensity(m_index, hvalues[0], hvalues[1]);
    363 }
    364 
    365 u8 AnalogController::GetExtraButtonMaskLSB() const
    366 {
    367   if (!m_analog_dpad_in_digital_mode || m_analog_mode || m_configuration_mode)
    368     return 0xFF;
    369 
    370   static constexpr u8 NEG_THRESHOLD = static_cast<u8>(128.0f - (127.0 * 0.5f));
    371   static constexpr u8 POS_THRESHOLD = static_cast<u8>(128.0f + (127.0 * 0.5f));
    372 
    373   const bool left = (m_axis_state[static_cast<u8>(Axis::LeftX)] <= NEG_THRESHOLD);
    374   const bool right = (m_axis_state[static_cast<u8>(Axis::LeftX)] >= POS_THRESHOLD);
    375   const bool up = (m_axis_state[static_cast<u8>(Axis::LeftY)] <= NEG_THRESHOLD);
    376   const bool down = (m_axis_state[static_cast<u8>(Axis::LeftY)] >= POS_THRESHOLD);
    377 
    378   return ~((static_cast<u8>(left) << static_cast<u8>(Button::Left)) |
    379            (static_cast<u8>(right) << static_cast<u8>(Button::Right)) |
    380            (static_cast<u8>(up) << static_cast<u8>(Button::Up)) |
    381            (static_cast<u8>(down) << static_cast<u8>(Button::Down)));
    382 }
    383 
    384 void AnalogController::ResetRumbleConfig()
    385 {
    386   m_rumble_config.fill(0xFF);
    387 
    388   m_rumble_config_large_motor_index = -1;
    389   m_rumble_config_small_motor_index = -1;
    390 
    391   SetMotorState(LargeMotor, 0);
    392   SetMotorState(SmallMotor, 0);
    393 }
    394 
    395 void AnalogController::SetMotorStateForConfigIndex(int index, u8 value)
    396 {
    397   if (m_rumble_config_small_motor_index == index)
    398     SetMotorState(SmallMotor, ((value & 0x01) != 0) ? 255 : 0);
    399   else if (m_rumble_config_large_motor_index == index)
    400     SetMotorState(LargeMotor, value);
    401 }
    402 
    403 u8 AnalogController::GetResponseNumHalfwords() const
    404 {
    405   if (m_configuration_mode || m_analog_mode)
    406     return 0x3;
    407 
    408   return (0x1 + m_digital_mode_extra_halfwords);
    409 }
    410 
    411 u8 AnalogController::GetModeID() const
    412 {
    413   if (m_configuration_mode)
    414     return 0xF;
    415 
    416   if (m_analog_mode)
    417     return 0x7;
    418 
    419   return 0x4;
    420 }
    421 
    422 u8 AnalogController::GetIDByte() const
    423 {
    424   return Truncate8((GetModeID() << 4) | GetResponseNumHalfwords());
    425 }
    426 
    427 bool AnalogController::Transfer(const u8 data_in, u8* data_out)
    428 {
    429   bool ack;
    430   m_rx_buffer[m_command_step] = data_in;
    431 
    432   switch (m_command)
    433   {
    434     case Command::Idle:
    435     {
    436       *data_out = 0xFF;
    437 
    438       if (data_in == 0x01)
    439       {
    440         DEBUG_LOG("ACK controller access");
    441         m_command = Command::Ready;
    442         return true;
    443       }
    444 
    445       DEV_LOG("Unknown data_in = 0x{:02X}", data_in);
    446       return false;
    447     }
    448     break;
    449 
    450     case Command::Ready:
    451     {
    452       if (data_in == 0x42)
    453       {
    454         Assert(m_command_step == 0);
    455         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    456         m_command = Command::ReadPad;
    457         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    458       }
    459       else if (data_in == 0x43)
    460       {
    461         Assert(m_command_step == 0);
    462         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    463         m_command = Command::ConfigModeSetMode;
    464         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    465       }
    466       else if (m_configuration_mode && data_in == 0x44)
    467       {
    468         Assert(m_command_step == 0);
    469         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    470         m_command = Command::SetAnalogMode;
    471         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    472 
    473         ResetRumbleConfig();
    474       }
    475       else if (m_configuration_mode && data_in == 0x45)
    476       {
    477         Assert(m_command_step == 0);
    478         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    479         m_command = Command::GetAnalogMode;
    480         m_tx_buffer = {GetIDByte(), m_status_byte, 0x01, 0x02, BoolToUInt8(m_analog_mode), 0x02, 0x01, 0x00};
    481       }
    482       else if (m_configuration_mode && data_in == 0x46)
    483       {
    484         Assert(m_command_step == 0);
    485         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    486         m_command = Command::Command46;
    487         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    488       }
    489       else if (m_configuration_mode && data_in == 0x47)
    490       {
    491         Assert(m_command_step == 0);
    492         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    493         m_command = Command::Command47;
    494         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00};
    495       }
    496       else if (m_configuration_mode && data_in == 0x4C)
    497       {
    498         Assert(m_command_step == 0);
    499         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    500         m_command = Command::Command4C;
    501         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    502       }
    503       else if (m_configuration_mode && data_in == 0x4D)
    504       {
    505         Assert(m_command_step == 0);
    506         m_response_length = (GetResponseNumHalfwords() + 1) * 2;
    507         m_command = Command::GetSetRumble;
    508         m_tx_buffer = {GetIDByte(), m_status_byte, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
    509 
    510         m_rumble_config_large_motor_index = -1;
    511         m_rumble_config_small_motor_index = -1;
    512       }
    513       else
    514       {
    515         if (m_configuration_mode)
    516           ERROR_LOG("Unimplemented config mode command 0x{:02X}", data_in);
    517 
    518         *data_out = 0xFF;
    519         return false;
    520       }
    521     }
    522     break;
    523 
    524     case Command::ReadPad:
    525     {
    526       const int rumble_index = m_command_step - 2;
    527 
    528       switch (m_command_step)
    529       {
    530         case 2:
    531         {
    532           m_tx_buffer[m_command_step] = Truncate8(m_button_state) & GetExtraButtonMaskLSB();
    533 
    534           if (m_dualshock_enabled)
    535             SetMotorStateForConfigIndex(rumble_index, data_in);
    536         }
    537         break;
    538 
    539         case 3:
    540         {
    541           m_tx_buffer[m_command_step] = Truncate8(m_button_state >> 8);
    542 
    543           if (m_dualshock_enabled)
    544           {
    545             SetMotorStateForConfigIndex(rumble_index, data_in);
    546           }
    547           else
    548           {
    549             bool legacy_rumble_on = (m_rx_buffer[2] & 0xC0) == 0x40 && (m_rx_buffer[3] & 0x01) != 0;
    550             SetMotorState(SmallMotor, legacy_rumble_on ? 255 : 0);
    551           }
    552         }
    553         break;
    554 
    555         case 4:
    556         {
    557           if (m_configuration_mode || m_analog_mode)
    558             m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightX)];
    559 
    560           if (m_dualshock_enabled)
    561             SetMotorStateForConfigIndex(rumble_index, data_in);
    562         }
    563         break;
    564 
    565         case 5:
    566         {
    567           if (m_configuration_mode || m_analog_mode)
    568             m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightY)];
    569 
    570           if (m_dualshock_enabled)
    571             SetMotorStateForConfigIndex(rumble_index, data_in);
    572         }
    573         break;
    574 
    575         case 6:
    576         {
    577           if (m_configuration_mode || m_analog_mode)
    578             m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftX)];
    579 
    580           if (m_dualshock_enabled)
    581             SetMotorStateForConfigIndex(rumble_index, data_in);
    582         }
    583         break;
    584 
    585         case 7:
    586         {
    587           if (m_configuration_mode || m_analog_mode)
    588             m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftY)];
    589 
    590           if (m_dualshock_enabled)
    591             SetMotorStateForConfigIndex(rumble_index, data_in);
    592         }
    593         break;
    594 
    595         default:
    596         {
    597         }
    598         break;
    599       }
    600     }
    601     break;
    602 
    603     case Command::ConfigModeSetMode:
    604     {
    605       if (!m_configuration_mode)
    606       {
    607         switch (m_command_step)
    608         {
    609           case 2:
    610           {
    611             m_tx_buffer[m_command_step] = Truncate8(m_button_state) & GetExtraButtonMaskLSB();
    612           }
    613           break;
    614 
    615           case 3:
    616           {
    617             m_tx_buffer[m_command_step] = Truncate8(m_button_state >> 8);
    618           }
    619           break;
    620 
    621           case 4:
    622           {
    623             if (m_configuration_mode || m_analog_mode)
    624               m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightX)];
    625           }
    626           break;
    627 
    628           case 5:
    629           {
    630             if (m_configuration_mode || m_analog_mode)
    631               m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::RightY)];
    632           }
    633           break;
    634 
    635           case 6:
    636           {
    637             if (m_configuration_mode || m_analog_mode)
    638               m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftX)];
    639           }
    640           break;
    641 
    642           case 7:
    643           {
    644             if (m_configuration_mode || m_analog_mode)
    645               m_tx_buffer[m_command_step] = m_axis_state[static_cast<u8>(Axis::LeftY)];
    646           }
    647           break;
    648 
    649           default:
    650           {
    651           }
    652           break;
    653         }
    654       }
    655 
    656       if (m_command_step == (static_cast<s32>(m_response_length) - 1))
    657       {
    658         m_configuration_mode = (m_rx_buffer[2] == 1);
    659 
    660         if (m_configuration_mode)
    661         {
    662           m_dualshock_enabled = true;
    663           m_status_byte = 0x5A;
    664         }
    665 
    666         DEV_LOG("0x{:02x}({}) config mode", m_rx_buffer[2], m_configuration_mode ? "enter" : "leave");
    667       }
    668     }
    669     break;
    670 
    671     case Command::SetAnalogMode:
    672     {
    673       if (m_command_step == 2)
    674       {
    675         DEV_LOG("analog mode val 0x{:02x}", data_in);
    676 
    677         if (data_in == 0x00 || data_in == 0x01)
    678           SetAnalogMode((data_in == 0x01), true);
    679       }
    680       else if (m_command_step == 3)
    681       {
    682         DEV_LOG("analog mode lock 0x{:02x}", data_in);
    683 
    684         if (data_in == 0x02 || data_in == 0x03)
    685           m_analog_locked = (data_in == 0x03);
    686       }
    687     }
    688     break;
    689 
    690     case Command::GetAnalogMode:
    691     {
    692       // Intentionally empty, analog mode byte is set in reply buffer when command is first received
    693     }
    694     break;
    695 
    696     case Command::Command46:
    697     {
    698       if (m_command_step == 2)
    699       {
    700         if (data_in == 0x00)
    701         {
    702           m_tx_buffer[4] = 0x01;
    703           m_tx_buffer[5] = 0x02;
    704           m_tx_buffer[6] = 0x00;
    705           m_tx_buffer[7] = 0x0A;
    706         }
    707         else if (data_in == 0x01)
    708         {
    709           m_tx_buffer[4] = 0x01;
    710           m_tx_buffer[5] = 0x01;
    711           m_tx_buffer[6] = 0x01;
    712           m_tx_buffer[7] = 0x14;
    713         }
    714       }
    715     }
    716     break;
    717 
    718     case Command::Command47:
    719     {
    720       if (m_command_step == 2 && data_in != 0x00)
    721       {
    722         m_tx_buffer[4] = 0x00;
    723         m_tx_buffer[5] = 0x00;
    724         m_tx_buffer[6] = 0x00;
    725         m_tx_buffer[7] = 0x00;
    726       }
    727     }
    728     break;
    729 
    730     case Command::Command4C:
    731     {
    732       if (m_command_step == 2)
    733       {
    734         if (data_in == 0x00)
    735           m_tx_buffer[5] = 0x04;
    736         else if (data_in == 0x01)
    737           m_tx_buffer[5] = 0x07;
    738       }
    739     }
    740     break;
    741 
    742     case Command::GetSetRumble:
    743     {
    744       int rumble_index = m_command_step - 2;
    745       if (rumble_index >= 0)
    746       {
    747         m_tx_buffer[m_command_step] = m_rumble_config[rumble_index];
    748         m_rumble_config[rumble_index] = data_in;
    749 
    750         if (data_in == 0x00)
    751           m_rumble_config_small_motor_index = rumble_index;
    752         else if (data_in == 0x01)
    753           m_rumble_config_large_motor_index = rumble_index;
    754       }
    755 
    756       if (m_command_step == 7)
    757       {
    758         if (m_rumble_config_large_motor_index == -1)
    759           SetMotorState(LargeMotor, 0);
    760 
    761         if (m_rumble_config_small_motor_index == -1)
    762           SetMotorState(SmallMotor, 0);
    763       }
    764     }
    765     break;
    766 
    767       DefaultCaseIsUnreachable();
    768   }
    769 
    770   *data_out = m_tx_buffer[m_command_step];
    771 
    772   m_command_step = (m_command_step + 1) % m_response_length;
    773   ack = (m_command_step == 0) ? false : true;
    774 
    775   if (m_command_step == 0)
    776   {
    777     m_command = Command::Idle;
    778 
    779     DEBUG_LOG("Rx: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}", m_rx_buffer[0], m_rx_buffer[1],
    780               m_rx_buffer[2], m_rx_buffer[3], m_rx_buffer[4], m_rx_buffer[5], m_rx_buffer[6], m_rx_buffer[7]);
    781     DEBUG_LOG("Tx: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}", m_tx_buffer[0], m_tx_buffer[1],
    782               m_tx_buffer[2], m_tx_buffer[3], m_tx_buffer[4], m_tx_buffer[5], m_tx_buffer[6], m_tx_buffer[7]);
    783 
    784     m_rx_buffer.fill(0x00);
    785     m_tx_buffer.fill(0x00);
    786   }
    787 
    788   return ack;
    789 }
    790 
    791 std::unique_ptr<AnalogController> AnalogController::Create(u32 index)
    792 {
    793   return std::make_unique<AnalogController>(index);
    794 }
    795 
    796 static const Controller::ControllerBindingInfo s_binding_info[] = {
    797 #define BUTTON(name, display_name, icon_name, button, genb)                                                            \
    798   {                                                                                                                    \
    799     name, display_name, icon_name, static_cast<u32>(button), InputBindingInfo::Type::Button, genb                      \
    800   }
    801 #define AXIS(name, display_name, icon_name, halfaxis, genb)                                                            \
    802   {                                                                                                                    \
    803     name, display_name, icon_name, static_cast<u32>(AnalogController::Button::Count) + static_cast<u32>(halfaxis),     \
    804       InputBindingInfo::Type::HalfAxis, genb                                                                           \
    805   }
    806 
    807   // clang-format off
    808   BUTTON("Up", TRANSLATE_NOOP("AnalogController", "D-Pad Up"), ICON_PF_DPAD_UP, AnalogController::Button::Up, GenericInputBinding::DPadUp),
    809   BUTTON("Right", TRANSLATE_NOOP("AnalogController", "D-Pad Right"), ICON_PF_DPAD_RIGHT, AnalogController::Button::Right, GenericInputBinding::DPadRight),
    810   BUTTON("Down", TRANSLATE_NOOP("AnalogController", "D-Pad Down"), ICON_PF_DPAD_DOWN, AnalogController::Button::Down, GenericInputBinding::DPadDown),
    811   BUTTON("Left", TRANSLATE_NOOP("AnalogController", "D-Pad Left"), ICON_PF_DPAD_LEFT, AnalogController::Button::Left, GenericInputBinding::DPadLeft),
    812   BUTTON("Triangle", TRANSLATE_NOOP("AnalogController", "Triangle"), ICON_PF_BUTTON_TRIANGLE, AnalogController::Button::Triangle, GenericInputBinding::Triangle),
    813   BUTTON("Circle", TRANSLATE_NOOP("AnalogController", "Circle"), ICON_PF_BUTTON_CIRCLE, AnalogController::Button::Circle, GenericInputBinding::Circle),
    814   BUTTON("Cross", TRANSLATE_NOOP("AnalogController", "Cross"), ICON_PF_BUTTON_CROSS, AnalogController::Button::Cross, GenericInputBinding::Cross),
    815   BUTTON("Square", TRANSLATE_NOOP("AnalogController", "Square"), ICON_PF_BUTTON_SQUARE, AnalogController::Button::Square, GenericInputBinding::Square),
    816   BUTTON("Select", TRANSLATE_NOOP("AnalogController", "Select"), ICON_PF_SELECT_SHARE, AnalogController::Button::Select, GenericInputBinding::Select),
    817   BUTTON("Start", TRANSLATE_NOOP("AnalogController", "Start"),ICON_PF_START, AnalogController::Button::Start, GenericInputBinding::Start),
    818   BUTTON("Analog", TRANSLATE_NOOP("AnalogController", "Analog Toggle"), ICON_PF_ANALOG_LEFT_RIGHT, AnalogController::Button::Analog, GenericInputBinding::System),
    819   BUTTON("L1", TRANSLATE_NOOP("AnalogController", "L1"), ICON_PF_LEFT_SHOULDER_L1, AnalogController::Button::L1, GenericInputBinding::L1),
    820   BUTTON("R1", TRANSLATE_NOOP("AnalogController", "R1"), ICON_PF_RIGHT_SHOULDER_R1, AnalogController::Button::R1, GenericInputBinding::R1),
    821   BUTTON("L2", TRANSLATE_NOOP("AnalogController", "L2"), ICON_PF_LEFT_TRIGGER_L2, AnalogController::Button::L2, GenericInputBinding::L2),
    822   BUTTON("R2", TRANSLATE_NOOP("AnalogController", "R2"), ICON_PF_RIGHT_TRIGGER_R2, AnalogController::Button::R2, GenericInputBinding::R2),
    823   BUTTON("L3", TRANSLATE_NOOP("AnalogController", "L3"), ICON_PF_LEFT_ANALOG_CLICK, AnalogController::Button::L3, GenericInputBinding::L3),
    824   BUTTON("R3", TRANSLATE_NOOP("AnalogController", "R3"), ICON_PF_RIGHT_ANALOG_CLICK, AnalogController::Button::R3, GenericInputBinding::R3),
    825 
    826   AXIS("LLeft", TRANSLATE_NOOP("AnalogController", "Left Stick Left"), ICON_PF_LEFT_ANALOG_LEFT, AnalogController::HalfAxis::LLeft, GenericInputBinding::LeftStickLeft),
    827   AXIS("LRight", TRANSLATE_NOOP("AnalogController", "Left Stick Right"), ICON_PF_LEFT_ANALOG_RIGHT, AnalogController::HalfAxis::LRight, GenericInputBinding::LeftStickRight),
    828   AXIS("LDown", TRANSLATE_NOOP("AnalogController", "Left Stick Down"), ICON_PF_LEFT_ANALOG_DOWN, AnalogController::HalfAxis::LDown, GenericInputBinding::LeftStickDown),
    829   AXIS("LUp", TRANSLATE_NOOP("AnalogController", "Left Stick Up"), ICON_PF_LEFT_ANALOG_UP, AnalogController::HalfAxis::LUp, GenericInputBinding::LeftStickUp),
    830   AXIS("RLeft", TRANSLATE_NOOP("AnalogController", "Right Stick Left"), ICON_PF_RIGHT_ANALOG_LEFT, AnalogController::HalfAxis::RLeft, GenericInputBinding::RightStickLeft),
    831   AXIS("RRight", TRANSLATE_NOOP("AnalogController", "Right Stick Right"), ICON_PF_RIGHT_ANALOG_RIGHT, AnalogController::HalfAxis::RRight, GenericInputBinding::RightStickRight),
    832   AXIS("RDown", TRANSLATE_NOOP("AnalogController", "Right Stick Down"), ICON_PF_RIGHT_ANALOG_DOWN, AnalogController::HalfAxis::RDown, GenericInputBinding::RightStickDown),
    833   AXIS("RUp", TRANSLATE_NOOP("AnalogController", "Right Stick Up"), ICON_PF_RIGHT_ANALOG_UP, AnalogController::HalfAxis::RUp, GenericInputBinding::RightStickUp),
    834 // clang-format on
    835 
    836 #undef AXIS
    837 #undef BUTTON
    838 };
    839 
    840 static const char* s_invert_settings[] = {TRANSLATE_NOOP("AnalogController", "Not Inverted"),
    841                                           TRANSLATE_NOOP("AnalogController", "Invert Left/Right"),
    842                                           TRANSLATE_NOOP("AnalogController", "Invert Up/Down"),
    843                                           TRANSLATE_NOOP("AnalogController", "Invert Left/Right + Up/Down"), nullptr};
    844 
    845 static const SettingInfo s_settings[] = {
    846   {SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATE_NOOP("AnalogController", "Force Analog Mode on Reset"),
    847    TRANSLATE_NOOP("AnalogController", "Forces the controller to analog mode when the console is reset/powered on."),
    848    "true", nullptr, nullptr, nullptr, nullptr, nullptr, 0.0f},
    849   {SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode",
    850    TRANSLATE_NOOP("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"),
    851    TRANSLATE_NOOP("AnalogController",
    852                   "Allows you to use the analog sticks to control the d-pad in digital mode, as well as the buttons."),
    853    "true", nullptr, nullptr, nullptr, nullptr, nullptr, 0.0f},
    854   {SettingInfo::Type::Float, "AnalogDeadzone", TRANSLATE_NOOP("AnalogController", "Analog Deadzone"),
    855    TRANSLATE_NOOP("AnalogController",
    856                   "Sets the analog stick deadzone, i.e. the fraction of the stick movement which will be ignored."),
    857    "0.00f", "0.00f", "1.00f", "0.01f", "%.0f%%", nullptr, 100.0f},
    858   {SettingInfo::Type::Float, "AnalogSensitivity", TRANSLATE_NOOP("AnalogController", "Analog Sensitivity"),
    859    TRANSLATE_NOOP(
    860      "AnalogController",
    861      "Sets the analog stick axis scaling factor. A value between 130% and 140% is recommended when using recent "
    862      "controllers, e.g. DualShock 4, Xbox One Controller."),
    863    "1.33f", "0.01f", "2.00f", "0.01f", "%.0f%%", nullptr, 100.0f},
    864   {SettingInfo::Type::Float, "ButtonDeadzone", TRANSLATE_NOOP("AnalogController", "Button/Trigger Deadzone"),
    865    TRANSLATE_NOOP("AnalogController", "Sets the deadzone for activating buttons/triggers, "
    866                                       "i.e. the fraction of the trigger which will be ignored."),
    867    "0.25", "0.01", "1.00", "0.01", "%.0f%%", nullptr, 100.0f},
    868   {SettingInfo::Type::Integer, "VibrationBias", TRANSLATE_NOOP("AnalogController", "Vibration Bias"),
    869    TRANSLATE_NOOP("AnalogController", "Sets the rumble bias value. If rumble in some games is too weak or not "
    870                                       "functioning, try increasing this value."),
    871    "8", "0", "255", "1", "%d", nullptr, 1.0f},
    872   {SettingInfo::Type::IntegerList, "InvertLeftStick", TRANSLATE_NOOP("AnalogController", "Invert Left Stick"),
    873    TRANSLATE_NOOP("AnalogController", "Inverts the direction of the left analog stick."), "0", "0", "3", nullptr,
    874    nullptr, s_invert_settings, 0.0f},
    875   {SettingInfo::Type::IntegerList, "InvertRightStick", TRANSLATE_NOOP("AnalogController", "Invert Right Stick"),
    876    TRANSLATE_NOOP("AnalogController", "Inverts the direction of the right analog stick."), "0", "0", "3", nullptr,
    877    nullptr, s_invert_settings, 0.0f},
    878 };
    879 
    880 const Controller::ControllerInfo AnalogController::INFO = {ControllerType::AnalogController,
    881                                                            "AnalogController",
    882                                                            TRANSLATE_NOOP("ControllerType", "Analog Controller"),
    883                                                            ICON_PF_GAMEPAD_ALT,
    884                                                            s_binding_info,
    885                                                            s_settings,
    886                                                            Controller::VibrationCapabilities::LargeSmallMotors};
    887 
    888 void AnalogController::LoadSettings(SettingsInterface& si, const char* section, bool initial)
    889 {
    890   Controller::LoadSettings(si, section, initial);
    891   m_force_analog_on_reset = si.GetBoolValue(section, "ForceAnalogOnReset", true);
    892   m_analog_dpad_in_digital_mode = si.GetBoolValue(section, "AnalogDPadInDigitalMode", true);
    893   m_analog_deadzone = std::clamp(si.GetFloatValue(section, "AnalogDeadzone", DEFAULT_STICK_DEADZONE), 0.0f, 1.0f);
    894   m_analog_sensitivity =
    895     std::clamp(si.GetFloatValue(section, "AnalogSensitivity", DEFAULT_STICK_SENSITIVITY), 0.01f, 3.0f);
    896   m_button_deadzone = std::clamp(si.GetFloatValue(section, "ButtonDeadzone", DEFAULT_BUTTON_DEADZONE), 0.01f, 1.0f);
    897   m_rumble_bias = static_cast<u8>(std::min<u32>(si.GetIntValue(section, "VibrationBias", 8), 255));
    898   m_invert_left_stick = static_cast<u8>(si.GetIntValue(section, "InvertLeftStick", 0));
    899   m_invert_right_stick = static_cast<u8>(si.GetIntValue(section, "InvertRightStick", 0));
    900 }