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 }