// Copyright 2021 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_TEST_SUPPORT_FAKE_IGAMEPAD_STATICS_H_
#define DEVICE_GAMEPAD_TEST_SUPPORT_FAKE_IGAMEPAD_STATICS_H_
#include <Windows.Gaming.Input.h>
#include <inspectable.h>
#include <windows.foundation.collections.h>
#include <wrl.h>
#include <string_view>
#include <unordered_map>
#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "device/gamepad/test_support/fake_igamepad.h"
#include "device/gamepad/test_support/fake_iraw_game_controller.h"
namespace device {
class FakeIGamepadStatics final
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<
Microsoft::WRL::WinRt | Microsoft::WRL::InhibitRoOriginateError>,
ABI::Windows::Gaming::Input::IGamepadStatics,
ABI::Windows::Gaming::Input::IRawGameControllerStatics> {
public:
FakeIGamepadStatics();
FakeIGamepadStatics(const FakeIGamepadStatics&) = delete;
FakeIGamepadStatics& operator=(const FakeIGamepadStatics&) = delete;
static FakeIGamepadStatics* GetInstance();
// ABI::Windows::Gaming::Input::IGamepadStatics fake implementation.
HRESULT WINAPI
add_GamepadAdded(ABI::Windows::Foundation::IEventHandler<
ABI::Windows::Gaming::Input::Gamepad*>* value,
EventRegistrationToken* token) override;
HRESULT WINAPI
add_GamepadRemoved(ABI::Windows::Foundation::IEventHandler<
ABI::Windows::Gaming::Input::Gamepad*>* value,
EventRegistrationToken* token) override;
HRESULT WINAPI remove_GamepadAdded(EventRegistrationToken token) override;
HRESULT WINAPI remove_GamepadRemoved(EventRegistrationToken token) override;
HRESULT WINAPI
get_Gamepads(ABI::Windows::Foundation::Collections::IVectorView<
ABI::Windows::Gaming::Input::Gamepad*>** value) override;
// ABI::Windows::Gaming::Input::IRawGameControllerStatics fake implementation.
HRESULT __stdcall add_RawGameControllerAdded(
ABI::Windows::Foundation::IEventHandler<
ABI::Windows::Gaming::Input::RawGameController*>* value,
EventRegistrationToken* token) override;
HRESULT __stdcall remove_RawGameControllerAdded(
EventRegistrationToken token) override;
HRESULT __stdcall add_RawGameControllerRemoved(
ABI::Windows::Foundation::IEventHandler<
ABI::Windows::Gaming::Input::RawGameController*>* value,
EventRegistrationToken* token) override;
HRESULT __stdcall remove_RawGameControllerRemoved(
EventRegistrationToken token) override;
HRESULT __stdcall get_RawGameControllers(
ABI::Windows::Foundation::Collections::IVectorView<
ABI::Windows::Gaming::Input::RawGameController*>** value) override;
HRESULT __stdcall FromGameController(
ABI::Windows::Gaming::Input::IGameController* gameController,
ABI::Windows::Gaming::Input::IRawGameController** value) override;
// Adds a fake gamepad to simulate a gamepad connection operation for test.
// Due to the multi-threaded apartment nature of IGamepadStatics COM API, the
// callback would return on a different thread. We are using a separate
// `SequencedTaskRunner` in this fake implementation to simulate this
// behavior.
void SimulateGamepadAdded(
const Microsoft::WRL::ComPtr<FakeIGamepad>& gamepad_to_add,
uint16_t hardware_product_id,
uint16_t hardware_vendor_id,
std::string_view display_name);
// Uses a fake gamepad to simulate a gamepad disconnection operation for test.
// Due to the multi-threaded apartment nature of IGamepadStatics COM API, the
// callback would return on a different thread. We are using a separate
// `SequencedTaskRunner` in this fake implementation to simulate this
// behavior.
void SimulateGamepadRemoved(
const Microsoft::WRL::ComPtr<FakeIGamepad>& gamepad_to_remove);
size_t GetGamepadAddedEventHandlerCount() const;
size_t GetGamepadRemovedEventHandlerCount() const;
private:
typedef base::flat_map<
int64_t /* event_registration_token */,
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IEventHandler<
ABI::Windows::Gaming::Input::Gamepad*>>>
EventHandlerMap;
using GamepadEventTriggerCallback = void (FakeIGamepadStatics::*)(
const Microsoft::WRL::ComPtr<ABI::Windows::Gaming::Input::IGamepad>
gamepad);
~FakeIGamepadStatics() override;
void SimulateGamepadEvent(const Microsoft::WRL::ComPtr<
ABI::Windows::Gaming::Input::IGamepad>& gamepad,
GamepadEventTriggerCallback callback);
void TriggerGamepadAddedCallbackOnRandomThread(
const Microsoft::WRL::ComPtr<ABI::Windows::Gaming::Input::IGamepad>
gamepad_to_add);
void TriggerGamepadRemovedCallbackOnRandomThread(
const Microsoft::WRL::ComPtr<ABI::Windows::Gaming::Input::IGamepad>
gamepad_to_remove);
void CacheGamepad(Microsoft::WRL::ComPtr<FakeIGamepad> fake_gamepad_to_add,
uint16_t hardware_product_id,
uint16_t hardware_vendor_id,
std::string_view display_name);
void RemoveCachedGamepad(
const Microsoft::WRL::ComPtr<FakeIGamepad>& fake_gamepad_to_remove);
int64_t next_event_registration_token_ = 0;
uint64_t next_gamepad_id_ = 0;
EventHandlerMap gamepad_added_event_handler_map_;
EventHandlerMap gamepad_removed_event_handler_map_;
std::unordered_map<uint64_t, Microsoft::WRL::ComPtr<FakeIGamepad>>
fake_gamepad_map_;
std::unordered_map<uint64_t, Microsoft::WRL::ComPtr<FakeIRawGameController>>
fake_raw_game_controller_map_;
};
} // namespace device
#endif // DEVICE_GAMEPAD_TEST_SUPPORT_FAKE_IGAMEPAD_STATICS_H_