Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/core/analog_controller.h
4802 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]> and contributors.
2
// SPDX-License-Identifier: 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
explicit AnalogController(u32 index);
64
~AnalogController() override;
65
66
static std::unique_ptr<AnalogController> Create(u32 index);
67
68
ControllerType GetType() const override;
69
70
void Reset() override;
71
bool DoState(StateWrapper& sw, bool ignore_input_state) override;
72
73
float GetBindState(u32 index) const override;
74
void SetBindState(u32 index, float value) override;
75
u32 GetButtonStateBits() const override;
76
std::optional<u32> GetAnalogInputBytes() const override;
77
78
void ResetTransferState() override;
79
bool Transfer(const u8 data_in, u8* data_out) override;
80
81
void LoadSettings(const SettingsInterface& si, const char* section, bool initial) override;
82
83
private:
84
using MotorState = std::array<u8, NUM_MOTORS>;
85
86
enum class Command : u8
87
{
88
Idle,
89
Ready,
90
ReadPad, // 0x42
91
ConfigModeSetMode, // 0x43
92
SetAnalogMode, // 0x44
93
GetAnalogMode, // 0x45
94
Command46, // 0x46
95
Command47, // 0x47
96
Command4C, // 0x4C
97
GetSetRumble // 0x4D
98
};
99
100
static constexpr s16 DEFAULT_SMALL_MOTOR_VIBRATION_BIAS = 8;
101
static constexpr s16 DEFAULT_LARGE_MOTOR_VIBRATION_BIAS = 8;
102
103
static constexpr u32 HALFAXIS_BIND_START_INDEX = static_cast<u32>(Button::Count);
104
static constexpr u32 MOTOR_BIND_START_INDEX = HALFAXIS_BIND_START_INDEX + static_cast<u32>(HalfAxis::Count);
105
static constexpr u32 LED_BIND_START_INDEX = MOTOR_BIND_START_INDEX + NUM_MOTORS;
106
107
static const Controller::ControllerBindingInfo s_binding_info[];
108
109
Command m_command = Command::Idle;
110
u8 m_command_step = 0;
111
u8 m_response_length = 0;
112
113
// Transmit and receive buffers, not including the first Hi-Z/ack response byte
114
static constexpr u32 MAX_RESPONSE_LENGTH = 8;
115
std::array<u8, MAX_RESPONSE_LENGTH> m_rx_buffer{};
116
std::array<u8, MAX_RESPONSE_LENGTH> m_tx_buffer{};
117
118
// Get number of response halfwords (excluding the initial controller info halfword)
119
u8 GetResponseNumHalfwords() const;
120
121
u8 GetModeID() const;
122
u8 GetIDByte() const;
123
124
void SetAnalogMode(bool enabled, bool show_message);
125
void ProcessAnalogModeToggle();
126
void SetMotorState(u32 motor, u8 value);
127
float GetMotorStrength(u32 motor) const;
128
u16 GetExtraButtonMask() const;
129
void ResetRumbleConfig();
130
void Poll();
131
132
float m_analog_deadzone = 0.0f;
133
float m_analog_sensitivity = 1.33f;
134
float m_button_deadzone = 0.0f;
135
std::array<s16, NUM_MOTORS> m_vibration_bias{DEFAULT_LARGE_MOTOR_VIBRATION_BIAS, DEFAULT_SMALL_MOTOR_VIBRATION_BIAS};
136
u8 m_invert_left_stick = 0;
137
u8 m_invert_right_stick = 0;
138
139
bool m_force_analog_on_reset = false;
140
bool m_analog_dpad_in_digital_mode = false;
141
u8 m_analog_shoulder_buttons = 0;
142
143
bool m_analog_mode = false;
144
bool m_analog_locked = false;
145
bool m_dualshock_enabled = false;
146
bool m_configuration_mode = false;
147
148
std::array<u8, static_cast<u8>(Axis::Count)> m_axis_state{};
149
150
enum : u8
151
{
152
SmallMotor = 0,
153
LargeMotor = 1,
154
};
155
156
std::array<u8, 6> m_rumble_config{};
157
158
bool m_analog_toggle_queued = false;
159
u8 m_status_byte = 0;
160
161
// TODO: Set this with command 0x4D and increase response length in digital mode accordingly
162
u8 m_digital_mode_extra_halfwords = 0;
163
164
// buttons are active low
165
u16 m_button_state = UINT16_C(0xFFFF);
166
167
MotorState m_motor_state{};
168
169
// both directions of axis state, merged to m_axis_state
170
std::array<u8, static_cast<u32>(HalfAxis::Count)> m_half_axis_state{};
171
};
172
173