Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/core/controller.cpp
4802 views
1
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
3
4
#include "controller.h"
5
#include "analog_controller.h"
6
#include "analog_joystick.h"
7
#include "ddgo_controller.h"
8
#include "digital_controller.h"
9
#include "game_database.h"
10
#include "guncon.h"
11
#include "host.h"
12
#include "jogcon.h"
13
#include "justifier.h"
14
#include "negcon.h"
15
#include "negcon_rumble.h"
16
#include "playstation_mouse.h"
17
#include "system.h"
18
19
#include "util/state_wrapper.h"
20
21
#include "IconsPromptFont.h"
22
#include "fmt/format.h"
23
24
static const Controller::ControllerInfo s_none_info = {
25
ControllerType::None, "None", TRANSLATE_NOOP("ControllerType", "Not Connected"), ICON_PF_NO_CONTROLLER, {}, {}};
26
27
static constexpr std::array<const Controller::ControllerInfo*, static_cast<size_t>(ControllerType::Count)>
28
s_controller_info = {{
29
&s_none_info,
30
&DigitalController::INFO,
31
&AnalogController::INFO,
32
&AnalogJoystick::INFO,
33
&GunCon::INFO,
34
&PlayStationMouse::INFO,
35
&NeGcon::INFO,
36
&NeGconRumble::INFO,
37
&Justifier::INFO,
38
&DigitalController::INFO_POPN,
39
&DDGoController::INFO,
40
&JogCon::INFO,
41
}};
42
43
const std::array<u32, NUM_CONTROLLER_AND_CARD_PORTS> Controller::PortDisplayOrder = {{0, 2, 3, 4, 1, 5, 6, 7}};
44
45
std::string_view Controller::ControllerInfo::GetDisplayName() const
46
{
47
return Host::TranslateToStringView("ControllerType", display_name);
48
}
49
50
std::string_view Controller::ControllerInfo::GetBindingDisplayName(const ControllerBindingInfo& bi) const
51
{
52
return Host::TranslateToStringView(name, bi.display_name);
53
}
54
55
Controller::Controller(u32 index) : m_index(index)
56
{
57
}
58
59
Controller::~Controller() = default;
60
61
void Controller::Reset()
62
{
63
}
64
65
bool Controller::DoState(StateWrapper& sw, bool apply_input_state)
66
{
67
return !sw.HasError();
68
}
69
70
void Controller::ResetTransferState()
71
{
72
}
73
74
bool Controller::Transfer(const u8 data_in, u8* data_out)
75
{
76
*data_out = 0xFF;
77
return false;
78
}
79
80
float Controller::GetBindState(u32 index) const
81
{
82
return 0.0f;
83
}
84
85
void Controller::SetBindState(u32 index, float value)
86
{
87
}
88
89
u32 Controller::GetButtonStateBits() const
90
{
91
return 0;
92
}
93
94
std::optional<u32> Controller::GetAnalogInputBytes() const
95
{
96
return std::nullopt;
97
}
98
99
void Controller::LoadSettings(const SettingsInterface& si, const char* section, bool initial)
100
{
101
}
102
103
std::unique_ptr<Controller> Controller::Create(ControllerType type, u32 index)
104
{
105
switch (type)
106
{
107
case ControllerType::DigitalController:
108
case ControllerType::PopnController:
109
return DigitalController::Create(index, type);
110
111
case ControllerType::AnalogController:
112
return AnalogController::Create(index);
113
114
case ControllerType::AnalogJoystick:
115
return AnalogJoystick::Create(index);
116
117
case ControllerType::GunCon:
118
return GunCon::Create(index);
119
120
case ControllerType::Justifier:
121
return Justifier::Create(index);
122
123
case ControllerType::PlayStationMouse:
124
return PlayStationMouse::Create(index);
125
126
case ControllerType::NeGcon:
127
return NeGcon::Create(index);
128
129
case ControllerType::NeGconRumble:
130
return NeGconRumble::Create(index);
131
132
case ControllerType::DDGoController:
133
return DDGoController::Create(index);
134
135
case ControllerType::JogCon:
136
return JogCon::Create(index);
137
138
case ControllerType::None:
139
default:
140
return {};
141
}
142
}
143
144
const Controller::ControllerInfo& Controller::GetControllerInfo(ControllerType type)
145
{
146
DebugAssert(type < ControllerType::Count && s_controller_info[static_cast<size_t>(type)]);
147
return *s_controller_info[static_cast<size_t>(type)];
148
}
149
150
const Controller::ControllerInfo* Controller::GetControllerInfo(std::string_view name)
151
{
152
for (const ControllerInfo* info : s_controller_info)
153
{
154
if (name == info->name)
155
return info;
156
}
157
158
return nullptr;
159
}
160
161
const std::array<const Controller::ControllerInfo*, static_cast<size_t>(ControllerType::Count)>&
162
Controller::GetControllerInfoList()
163
{
164
return s_controller_info;
165
}
166
167
std::tuple<u32, u32> Controller::ConvertPadToPortAndSlot(u32 index)
168
{
169
if (index > 4) // [5,6,7]
170
return std::make_tuple(1, index - 4); // 2B,2C,2D
171
else if (index > 1) // [2,3,4]
172
return std::make_tuple(0, index - 1); // 1B,1C,1D
173
else // [0,1]
174
return std::make_tuple(index, 0); // 1A,2A
175
}
176
177
u32 Controller::ConvertPortAndSlotToPad(u32 port, u32 slot)
178
{
179
if (slot == 0)
180
return port;
181
else if (port == 0) // slot=[0,1]
182
return slot + 1; // 2,3,4
183
else
184
return slot + 4; // 5,6,7
185
}
186
187
bool Controller::PadIsMultitapSlot(u32 index)
188
{
189
return (index >= 2);
190
}
191
192
bool Controller::PortAndSlotIsMultitap(u32 port, u32 slot)
193
{
194
return (slot != 0);
195
}
196
197
const char* Controller::GetPortDisplayName(u32 port, u32 slot, bool mtap)
198
{
199
static constexpr const std::array<const char*, NUM_MULTITAPS> no_mtap_labels = {{"1", "2"}};
200
static constexpr const std::array<std::array<const char*, NUM_CONTROLLER_AND_CARD_PORTS_PER_MULTITAP>, NUM_MULTITAPS>
201
mtap_labels = {{{{"1A", "1B", "1C", "1D"}}, {{"2A", "2B", "2C", "2D"}}}};
202
203
DebugAssert(port < 2 && slot < 4);
204
return mtap ? mtap_labels[port][slot] : no_mtap_labels[port];
205
}
206
207
const char* Controller::GetPortDisplayName(u32 index)
208
{
209
const auto& [port, slot] = ConvertPadToPortAndSlot(index);
210
return GetPortDisplayName(port, slot, g_settings.IsMultitapPortEnabled(port));
211
}
212
213
std::string Controller::GetSettingsSection(u32 pad)
214
{
215
return fmt::format("Pad{}", pad + 1u);
216
}
217
218
bool Controller::InCircularDeadzone(float deadzone, float pos_x, float pos_y)
219
{
220
// Calculate the actual distance from center, and compare to deadzone radius.
221
const float distance = std::sqrt(pos_x * pos_x + pos_y * pos_y);
222
return (distance <= deadzone);
223
224
}
225
226
bool Controller::CanStartInAnalogMode(ControllerType ctype)
227
{
228
if (!g_settings.apply_compatibility_settings)
229
return true;
230
231
const GameDatabase::Entry* dbentry = System::GetGameDatabaseEntry();
232
if (!dbentry)
233
return false;
234
235
return ((dbentry->supported_controllers & (1u << static_cast<u8>(ctype))) != 0 &&
236
!dbentry->HasTrait(GameDatabase::Trait::DisableAutoAnalogMode));
237
}
238
239