playstation_mouse.cpp (6728B)
1 // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #include "playstation_mouse.h" 5 #include "gpu.h" 6 #include "host.h" 7 #include "system.h" 8 9 #include "util/state_wrapper.h" 10 11 #include "common/assert.h" 12 #include "common/log.h" 13 14 #include "IconsPromptFont.h" 15 16 #include <array> 17 18 Log_SetChannel(PlayStationMouse); 19 20 static constexpr std::array<u8, static_cast<size_t>(PlayStationMouse::Binding::ButtonCount)> s_button_indices = { 21 {11, 10}}; 22 23 PlayStationMouse::PlayStationMouse(u32 index) : Controller(index) 24 { 25 } 26 27 PlayStationMouse::~PlayStationMouse() = default; 28 29 ControllerType PlayStationMouse::GetType() const 30 { 31 return ControllerType::PlayStationMouse; 32 } 33 34 void PlayStationMouse::Reset() 35 { 36 m_transfer_state = TransferState::Idle; 37 } 38 39 bool PlayStationMouse::DoState(StateWrapper& sw, bool apply_input_state) 40 { 41 if (!Controller::DoState(sw, apply_input_state)) 42 return false; 43 44 u16 button_state = m_button_state; 45 float delta_x = m_delta_x; 46 float delta_y = m_delta_y; 47 sw.Do(&button_state); 48 if (sw.GetVersion() >= 60) [[unlikely]] 49 { 50 sw.Do(&delta_x); 51 sw.Do(&delta_y); 52 } 53 else 54 { 55 u8 dummy = 0; 56 sw.Do(&dummy); 57 sw.Do(&dummy); 58 } 59 60 if (apply_input_state) 61 { 62 m_button_state = button_state; 63 m_delta_x = delta_x; 64 m_delta_y = delta_y; 65 } 66 67 sw.Do(&m_transfer_state); 68 return true; 69 } 70 71 float PlayStationMouse::GetBindState(u32 index) const 72 { 73 if (index >= s_button_indices.size()) 74 return 0.0f; 75 76 const u32 bit = s_button_indices[index]; 77 return static_cast<float>(((m_button_state >> bit) & 1u) ^ 1u); 78 } 79 80 void PlayStationMouse::SetBindState(u32 index, float value) 81 { 82 if (index >= s_button_indices.size()) 83 { 84 if (index == static_cast<u32>(Binding::PointerX)) 85 m_delta_x += value; 86 else if (index == static_cast<u32>(Binding::PointerY)) 87 m_delta_y += value; 88 89 return; 90 } 91 92 if (value >= 0.5f) 93 m_button_state &= ~(u16(1) << s_button_indices[index]); 94 else 95 m_button_state |= u16(1) << s_button_indices[index]; 96 } 97 98 void PlayStationMouse::ResetTransferState() 99 { 100 m_transfer_state = TransferState::Idle; 101 } 102 103 bool PlayStationMouse::Transfer(const u8 data_in, u8* data_out) 104 { 105 static constexpr u16 ID = 0x5A12; 106 107 switch (m_transfer_state) 108 { 109 case TransferState::Idle: 110 { 111 *data_out = 0xFF; 112 113 if (data_in == 0x01) 114 { 115 m_transfer_state = TransferState::Ready; 116 return true; 117 } 118 return false; 119 } 120 121 case TransferState::Ready: 122 { 123 if (data_in == 0x42) 124 { 125 *data_out = Truncate8(ID); 126 m_transfer_state = TransferState::IDMSB; 127 return true; 128 } 129 130 *data_out = 0xFF; 131 return false; 132 } 133 134 case TransferState::IDMSB: 135 { 136 *data_out = Truncate8(ID >> 8); 137 m_transfer_state = TransferState::ButtonsLSB; 138 return true; 139 } 140 141 case TransferState::ButtonsLSB: 142 { 143 *data_out = Truncate8(m_button_state); 144 m_transfer_state = TransferState::ButtonsMSB; 145 return true; 146 } 147 148 case TransferState::ButtonsMSB: 149 { 150 *data_out = Truncate8(m_button_state >> 8); 151 m_transfer_state = TransferState::DeltaX; 152 return true; 153 } 154 155 case TransferState::DeltaX: 156 { 157 const float delta_x = 158 std::clamp(std::floor(m_delta_x * m_sensitivity_x), static_cast<float>(std::numeric_limits<s8>::min()), 159 static_cast<float>(std::numeric_limits<s8>::max())); 160 m_delta_x -= delta_x / m_sensitivity_x; 161 *data_out = static_cast<s8>(delta_x); 162 m_transfer_state = TransferState::DeltaY; 163 return true; 164 } 165 166 case TransferState::DeltaY: 167 { 168 const float delta_y = 169 std::clamp(std::floor(m_delta_y * m_sensitivity_y), static_cast<float>(std::numeric_limits<s8>::min()), 170 static_cast<float>(std::numeric_limits<s8>::max())); 171 m_delta_y -= delta_y / m_sensitivity_x; 172 *data_out = static_cast<s8>(delta_y); 173 m_transfer_state = TransferState::Idle; 174 return false; 175 } 176 177 default: 178 { 179 UnreachableCode(); 180 } 181 } 182 } 183 184 void PlayStationMouse::LoadSettings(SettingsInterface& si, const char* section, bool initial) 185 { 186 Controller::LoadSettings(si, section, initial); 187 188 m_sensitivity_x = si.GetFloatValue(section, "SensitivityX", 1.0f); 189 m_sensitivity_y = si.GetFloatValue(section, "SensitivityY", 1.0f); 190 } 191 192 std::unique_ptr<PlayStationMouse> PlayStationMouse::Create(u32 index) 193 { 194 return std::make_unique<PlayStationMouse>(index); 195 } 196 197 static const Controller::ControllerBindingInfo s_binding_info[] = { 198 #define BUTTON(name, display_name, icon_name, button, genb) \ 199 { \ 200 name, display_name, icon_name, static_cast<u32>(button), InputBindingInfo::Type::Button, genb \ 201 } 202 203 // clang-format off 204 { "Pointer", TRANSLATE_NOOP("PlaystationMouse", "Pointer"), ICON_PF_MOUSE_ANY, static_cast<u32>(PlayStationMouse::Binding::PointerX), InputBindingInfo::Type::Pointer, GenericInputBinding::Unknown }, 205 BUTTON("Left", TRANSLATE_NOOP("PlayStationMouse", "Left Button"), ICON_PF_MOUSE_BUTTON_1, PlayStationMouse::Binding::Left, GenericInputBinding::Cross), 206 BUTTON("Right", TRANSLATE_NOOP("PlayStationMouse", "Right Button"), ICON_PF_MOUSE_BUTTON_2, PlayStationMouse::Binding::Right, GenericInputBinding::Circle), 207 // clang-format on 208 209 #undef BUTTON 210 }; 211 static const SettingInfo s_settings[] = { 212 {SettingInfo::Type::Float, "SensitivityX", TRANSLATE_NOOP("PlayStationMouse", "Horizontal Sensitivity"), 213 TRANSLATE_NOOP("PlayStationMouse", "Adjusts the correspondance between physical and virtual mouse movement."), "1.0", 214 "0.01", "2.0", "0.01", "%.0f", nullptr, 100.0f}, 215 {SettingInfo::Type::Float, "SensitivityY", TRANSLATE_NOOP("PlayStationMouse", "Vertical Sensitivity"), 216 TRANSLATE_NOOP("PlayStationMouse", "Adjusts the correspondance between physical and virtual mouse movement."), "1.0", 217 "0.01", "2.0", "0.01", "%.0f", nullptr, 100.0f}, 218 }; 219 220 const Controller::ControllerInfo PlayStationMouse::INFO = {ControllerType::PlayStationMouse, 221 "PlayStationMouse", 222 TRANSLATE_NOOP("ControllerType", "Mouse"), 223 ICON_PF_MOUSE, 224 s_binding_info, 225 s_settings, 226 Controller::VibrationCapabilities::NoVibration};