analog_controller.h (4086B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors. 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "controller.h" 7 8 #include <array> 9 #include <memory> 10 #include <optional> 11 12 class AnalogController final : public Controller 13 { 14 public: 15 enum class Axis : u8 16 { 17 LeftX, 18 LeftY, 19 RightX, 20 RightY, 21 Count 22 }; 23 24 enum class Button : u8 25 { 26 Select = 0, 27 L3 = 1, 28 R3 = 2, 29 Start = 3, 30 Up = 4, 31 Right = 5, 32 Down = 6, 33 Left = 7, 34 L2 = 8, 35 R2 = 9, 36 L1 = 10, 37 R1 = 11, 38 Triangle = 12, 39 Circle = 13, 40 Cross = 14, 41 Square = 15, 42 Analog = 16, 43 Count 44 }; 45 46 enum class HalfAxis : u8 47 { 48 LLeft, 49 LRight, 50 LDown, 51 LUp, 52 RLeft, 53 RRight, 54 RDown, 55 RUp, 56 Count 57 }; 58 59 static constexpr u8 NUM_MOTORS = 2; 60 61 static const Controller::ControllerInfo INFO; 62 63 AnalogController(u32 index); 64 ~AnalogController() override; 65 66 static std::unique_ptr<AnalogController> Create(u32 index); 67 68 ControllerType GetType() const override; 69 bool InAnalogMode() const override; 70 71 void Reset() override; 72 bool DoState(StateWrapper& sw, bool ignore_input_state) override; 73 74 float GetBindState(u32 index) const override; 75 void SetBindState(u32 index, float value) override; 76 u32 GetButtonStateBits() const override; 77 std::optional<u32> GetAnalogInputBytes() const override; 78 u32 GetInputOverlayIconColor() const override; 79 80 void ResetTransferState() override; 81 bool Transfer(const u8 data_in, u8* data_out) override; 82 83 void LoadSettings(SettingsInterface& si, const char* section, bool initial) override; 84 85 private: 86 using MotorState = std::array<u8, NUM_MOTORS>; 87 88 enum class Command : u8 89 { 90 Idle, 91 Ready, 92 ReadPad, // 0x42 93 ConfigModeSetMode, // 0x43 94 SetAnalogMode, // 0x44 95 GetAnalogMode, // 0x45 96 Command46, // 0x46 97 Command47, // 0x47 98 Command4C, // 0x4C 99 GetSetRumble // 0x4D 100 }; 101 102 Command m_command = Command::Idle; 103 int m_command_step = 0; 104 105 // Transmit and receive buffers, not including the first Hi-Z/ack response byte 106 static constexpr u32 MAX_RESPONSE_LENGTH = 8; 107 std::array<u8, MAX_RESPONSE_LENGTH> m_rx_buffer; 108 std::array<u8, MAX_RESPONSE_LENGTH> m_tx_buffer; 109 u32 m_response_length = 0; 110 111 // Get number of response halfwords (excluding the initial controller info halfword) 112 u8 GetResponseNumHalfwords() const; 113 114 u8 GetModeID() const; 115 u8 GetIDByte() const; 116 117 void SetAnalogMode(bool enabled, bool show_message); 118 void ProcessAnalogModeToggle(); 119 void SetMotorState(u32 motor, u8 value); 120 void UpdateHostVibration(); 121 u8 GetExtraButtonMaskLSB() const; 122 void ResetRumbleConfig(); 123 void SetMotorStateForConfigIndex(int index, u8 value); 124 125 bool m_force_analog_on_reset = false; 126 bool m_analog_dpad_in_digital_mode = false; 127 float m_analog_deadzone = 0.0f; 128 float m_analog_sensitivity = 1.33f; 129 float m_button_deadzone = 0.0f; 130 u8 m_rumble_bias = 8; 131 u8 m_invert_left_stick = 0; 132 u8 m_invert_right_stick = 0; 133 134 bool m_analog_mode = false; 135 bool m_analog_locked = false; 136 bool m_dualshock_enabled = false; 137 bool m_configuration_mode = false; 138 139 std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{}; 140 141 enum : u8 142 { 143 LargeMotor = 0, 144 SmallMotor = 1 145 }; 146 147 std::array<u8, 6> m_rumble_config{}; 148 int m_rumble_config_large_motor_index = -1; 149 int m_rumble_config_small_motor_index = -1; 150 151 bool m_analog_toggle_queued = false; 152 u8 m_status_byte = 0; 153 154 // TODO: Set this with command 0x4D and increase response length in digital mode accordingly 155 u8 m_digital_mode_extra_halfwords = 0; 156 157 // buttons are active low 158 u16 m_button_state = UINT16_C(0xFFFF); 159 160 MotorState m_motor_state{}; 161 162 // both directions of axis state, merged to m_axis_state 163 std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{}; 164 165 // Member variables that are no longer used, but kept and serialized for compatibility with older save states 166 u8 m_command_param = 0; 167 bool m_legacy_rumble_unlocked = false; 168 };