forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnintendo_data_fetcher.cc
250 lines (223 loc) · 8.61 KB
/
nintendo_data_fetcher.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/gamepad/nintendo_data_fetcher.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "device/gamepad/gamepad_service.h"
#include "device/gamepad/gamepad_uma.h"
namespace device {
NintendoDataFetcher::NintendoDataFetcher() = default;
NintendoDataFetcher::~NintendoDataFetcher() {
for (auto& entry : controllers_) {
auto& device = *entry.second;
device.Shutdown();
}
}
GamepadSource NintendoDataFetcher::source() {
return Factory::static_source();
}
void NintendoDataFetcher::OnAddedToProvider() {
// Open a connection to the HID service. On a successful connection,
// OnGetDevices will be called with a list of connected HID devices.
BindHidManager(hid_manager_.BindNewPipeAndPassReceiver());
hid_manager_->GetDevicesAndSetClient(
receiver_.BindNewEndpointAndPassRemote(),
base::BindOnce(&NintendoDataFetcher::OnGetDevices,
weak_factory_.GetWeakPtr()));
}
void NintendoDataFetcher::OnGetDevices(
std::vector<mojom::HidDeviceInfoPtr> device_infos) {
for (auto& device_info : device_infos)
DeviceAdded(std::move(device_info));
}
void NintendoDataFetcher::OnDeviceReady(int source_id) {
auto find_it = controllers_.find(source_id);
if (find_it == controllers_.end())
return;
const auto* ready_device_ptr = find_it->second.get();
DCHECK(ready_device_ptr);
if (ready_device_ptr->IsComposite())
return;
// Extract a connected device that can be associated with the newly-connected
// device, if it exists.
std::unique_ptr<NintendoController> associated_device =
ExtractAssociatedDevice(ready_device_ptr);
if (associated_device) {
// Extract the newly-ready device from |controllers_|.
auto ready_device = std::move(find_it->second);
controllers_.erase(source_id);
// Create a composite gamepad from the newly-ready device and the associated
// device. Each device provides button and axis state for half of the
// gamepad and vibration effects are split between them.
int composite_source_id = next_source_id_++;
auto emplace_result = controllers_.emplace(
composite_source_id,
NintendoController::CreateComposite(
composite_source_id, std::move(associated_device),
std::move(ready_device), hid_manager_.get()));
if (emplace_result.second) {
auto& composite_gamepad = emplace_result.first->second;
DCHECK(composite_gamepad);
composite_gamepad->Open(
base::BindOnce(&NintendoDataFetcher::OnDeviceReady,
weak_factory_.GetWeakPtr(), composite_source_id));
}
}
}
void NintendoDataFetcher::DeviceAdded(mojom::HidDeviceInfoPtr device_info) {
GamepadId gamepad_id = GamepadIdList::Get().GetGamepadId(
device_info->product_name, device_info->vendor_id,
device_info->product_id);
if (NintendoController::IsNintendoController(gamepad_id)) {
AddDevice(std::move(device_info));
}
}
void NintendoDataFetcher::DeviceRemoved(mojom::HidDeviceInfoPtr device_info) {
GamepadId gamepad_id = GamepadIdList::Get().GetGamepadId(
device_info->product_name, device_info->vendor_id,
device_info->product_id);
if (NintendoController::IsNintendoController(gamepad_id)) {
RemoveDevice(device_info->guid);
}
}
void NintendoDataFetcher::DeviceChanged(mojom::HidDeviceInfoPtr device_info) {
// Ignore updated device info. NintendoController will retain the old
// HidDeviceInfo. This is fine since it does not rely on any HidDeviceInfo
// members that could change.
}
bool NintendoDataFetcher::AddDevice(mojom::HidDeviceInfoPtr device_info) {
DCHECK(hid_manager_);
GamepadId gamepad_id = GamepadIdList::Get().GetGamepadId(
device_info->product_name, device_info->vendor_id,
device_info->product_id);
RecordConnectedGamepad(gamepad_id);
int source_id = next_source_id_++;
auto emplace_result = controllers_.emplace(
source_id, NintendoController::Create(source_id, std::move(device_info),
hid_manager_.get()));
if (emplace_result.second) {
auto& new_device = emplace_result.first->second;
DCHECK(new_device);
new_device->Open(base::BindOnce(&NintendoDataFetcher::OnDeviceReady,
weak_factory_.GetWeakPtr(), source_id));
return true;
}
return false;
}
bool NintendoDataFetcher::RemoveDevice(const std::string& guid) {
for (auto& entry : controllers_) {
auto& match_device = entry.second;
if (match_device->HasGuid(guid)) {
if (match_device->IsComposite()) {
// Decompose the composite device and return the remaining subdevice to
// |controllers_|.
auto decomposed_devices = match_device->Decompose();
match_device->Shutdown();
controllers_.erase(entry.first);
for (auto& device : decomposed_devices) {
if (device->HasGuid(guid)) {
device->Shutdown();
} else {
int source_id = device->GetSourceId();
controllers_.emplace(source_id, std::move(device));
}
}
} else {
match_device->Shutdown();
controllers_.erase(entry.first);
}
return true;
}
}
return false;
}
std::unique_ptr<NintendoController>
NintendoDataFetcher::ExtractAssociatedDevice(const NintendoController* device) {
DCHECK(device);
std::unique_ptr<NintendoController> associated_device;
GamepadHand device_hand = device->GetGamepadHand();
if (device_hand != GamepadHand::kNone) {
GamepadHand target_hand = (device_hand == GamepadHand::kLeft)
? GamepadHand::kRight
: GamepadHand::kLeft;
for (auto& entry : controllers_) {
auto& match_device = entry.second;
if (match_device->IsOpen() &&
match_device->GetGamepadHand() == target_hand &&
match_device->GetBusType() == device->GetBusType()) {
associated_device = std::move(match_device);
controllers_.erase(entry.first);
break;
}
}
}
// Set the PadState source back to the default to signal that the slot
// occupied by the associated device is no longer in use.
if (associated_device) {
PadState* state = GetPadState(associated_device->GetSourceId());
if (state)
state->source = GamepadSource::kNone;
}
return associated_device;
}
void NintendoDataFetcher::GetGamepadData(bool) {
for (auto& entry : controllers_) {
auto& device = entry.second;
if (device->IsOpen() && device->IsUsable()) {
PadState* state = GetPadState(device->GetSourceId());
if (!state)
continue;
if (!state->is_initialized) {
state->mapper = device->GetMappingFunction();
device->InitializeGamepadState(state->mapper != nullptr, state->data);
state->is_initialized = true;
}
device->UpdateGamepadState(state->data);
}
}
}
NintendoController* NintendoDataFetcher::GetControllerFromGuid(
const std::string& guid) {
for (auto& entry : controllers_) {
auto& device = entry.second;
if (device->HasGuid(guid))
return device.get();
}
return nullptr;
}
NintendoController* NintendoDataFetcher::GetControllerFromSourceId(
int source_id) {
auto find_it = controllers_.find(source_id);
return find_it == controllers_.end() ? nullptr : find_it->second.get();
}
void NintendoDataFetcher::PlayEffect(
int source_id,
mojom::GamepadHapticEffectType type,
mojom::GamepadEffectParametersPtr params,
mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) {
auto* controller = GetControllerFromSourceId(source_id);
if (!controller || !controller->IsOpen()) {
RunVibrationCallback(
std::move(callback), std::move(callback_runner),
mojom::GamepadHapticsResult::GamepadHapticsResultError);
return;
}
controller->PlayEffect(type, std::move(params), std::move(callback),
std::move(callback_runner));
}
void NintendoDataFetcher::ResetVibration(
int source_id,
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback,
scoped_refptr<base::SequencedTaskRunner> callback_runner) {
auto* controller = GetControllerFromSourceId(source_id);
if (!controller || !controller->IsOpen()) {
RunVibrationCallback(
std::move(callback), std::move(callback_runner),
mojom::GamepadHapticsResult::GamepadHapticsResultError);
return;
}
controller->ResetVibration(std::move(callback), std::move(callback_runner));
}
} // namespace device