chromium/device/gamepad/wgi_data_fetcher_win.h

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DEVICE_GAMEPAD_WGI_DATA_FETCHER_WIN_H_
#define DEVICE_GAMEPAD_WGI_DATA_FETCHER_WIN_H_

#include <Windows.Gaming.Input.h>
#include <wrl/event.h>

#include <memory>
#include <optional>
#include <string>

#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/gamepad_id_list.h"
#include "device/gamepad/public/mojom/gamepad.mojom.h"
#include "device/gamepad/wgi_gamepad_device.h"
#include "device/gamepad/xinput_data_fetcher_win.h"

namespace device {

class DEVICE_GAMEPAD_EXPORT WgiDataFetcherWin final
    : public GamepadDataFetcher {
 public:
  enum class InitializationState {
    kUninitialized,
    kInitialized,
    kAddGamepadAddedFailed,
    kAddGamepadRemovedFailed,
    kRoGetActivationFactoryFailed,
  };

  using Factory =
      GamepadDataFetcherFactoryImpl<WgiDataFetcherWin, GamepadSource::kWinWgi>;

  // Define test hooks to use a fake WinRT RoGetActivationFactory
  // implementation to avoid dependencies on the OS for WGI testing.
  using GetActivationFactoryFunction = HRESULT (*)(HSTRING class_id,
                                                   const IID& iid,
                                                   void** out_factory);

  WgiDataFetcherWin();
  WgiDataFetcherWin(const WgiDataFetcherWin&) = delete;
  WgiDataFetcherWin& operator=(const WgiDataFetcherWin&) = delete;
  ~WgiDataFetcherWin() override;

  // GamepadDataFetcher implementation.
  GamepadSource source() override;
  void OnAddedToProvider() override;
  void GetGamepadData(bool devices_changed_hint) override;
  void PlayEffect(int source_id,
                  mojom::GamepadHapticEffectType,
                  mojom::GamepadEffectParametersPtr,
                  mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback,
                  scoped_refptr<base::SequencedTaskRunner>) override;
  void ResetVibration(
      int source_id,
      mojom::GamepadHapticsManager::ResetVibrationActuatorCallback,
      scoped_refptr<base::SequencedTaskRunner>) override;

  // Set fake ActivationFunction for test to avoid dependencies on the OS API.
  using ActivationFactoryFunctionCallback =
      base::RepeatingCallback<GetActivationFactoryFunction()>;
  static void OverrideActivationFactoryFunctionForTesting(
      ActivationFactoryFunctionCallback callback);

  // Used to store gamepad devices indexed by its source id.
  using DeviceMap = base::flat_map<int, std::unique_ptr<WgiGamepadDevice>>;
  const DeviceMap& GetGamepadsForTesting() const { return devices_; }

  InitializationState GetInitializationState() const;

 private:
  // Set the state of the new connected gamepad to initialized, update
  // gamepad state connection status, and add a new controller mapping for
  // `gamepad` to `gamepads_` on gamepad polling thread.
  void OnGamepadAdded(IInspectable* /* sender */,
                      ABI::Windows::Gaming::Input::IGamepad* gamepad);

  // Remove the corresponding controller mapping of `gamepad` in `gamepads_`
  // on gamepad polling thread.
  void OnGamepadRemoved(IInspectable* /* sender */,
                        ABI::Windows::Gaming::Input::IGamepad* gamepad);

  // WgiDataFetcherWin has its own instance of XInputDataFetcherWin to query for
  // the meta button state.
  std::unique_ptr<XInputDataFetcherWin> xinput_data_fetcher_;

  static ActivationFactoryFunctionCallback&
  GetActivationFactoryFunctionCallback();

  std::u16string GetGamepadDisplayName(
      ABI::Windows::Gaming::Input::IGamepad* gamepad);

  std::u16string BuildGamepadIdString(
      GamepadId gamepad_id,
      const std::u16string& display_name,
      ABI::Windows::Gaming::Input::IGamepad* gamepad);

  Microsoft::WRL::ComPtr<ABI::Windows::Gaming::Input::IRawGameController>
  GetRawGameController(ABI::Windows::Gaming::Input::IGamepad* gamepad);

  void UnregisterEventHandlers();

  int next_source_id_ = 0;
  InitializationState initialization_state_ =
      InitializationState::kUninitialized;

  DeviceMap devices_;

  Microsoft::WRL::ComPtr<ABI::Windows::Gaming::Input::IGamepadStatics>
      gamepad_statics_;

  GetActivationFactoryFunction get_activation_factory_function_;

  std::optional<EventRegistrationToken> added_event_token_;
  std::optional<EventRegistrationToken> removed_event_token_;

  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<WgiDataFetcherWin> weak_factory_{this};
};

}  // namespace device

#endif  // DEVICE_GAMEPAD_WGI_DATA_FETCHER_WIN_H_