123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // 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 = GAMEPAD_SOURCE_NONE;
- }
- 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
|