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 }