chromium/device/gamepad/xinput_data_fetcher_win.h

// Copyright 2012 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_XINPUT_DATA_FETCHER_WIN_H_
#define DEVICE_GAMEPAD_XINPUT_DATA_FETCHER_WIN_H_

#include <memory>

#include "build/build_config.h"

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Unknwn.h>
#include <windows.h>

#include <WinDef.h>
#include <XInput.h>
#include <stdlib.h>

#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_native_library.h"
#include "base/task/sequenced_task_runner.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/gamepad_standard_mappings.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "device/gamepad/xinput_haptic_gamepad_win.h"

namespace device {

// XInputGetStateEx uses a slightly larger struct than XInputGetState.
struct XInputGamepadEx {
  WORD wButtons;
  BYTE bLeftTrigger;
  BYTE bRightTrigger;
  SHORT sThumbLX;
  SHORT sThumbLY;
  SHORT sThumbRX;
  SHORT sThumbRY;
  DWORD dwPaddingReserved;
};

struct XInputStateEx {
  DWORD dwPacketNumber;
  XInputGamepadEx Gamepad;
};

class DEVICE_GAMEPAD_EXPORT XInputDataFetcherWin : public GamepadDataFetcher {
 public:
  using Factory = GamepadDataFetcherFactoryImpl<XInputDataFetcherWin,
                                                GamepadSource::kWinXinput>;

  // The function types we use from XInput DLL (either xinput1_4.dll or
  // xinput9_1_0.dll).
  typedef void(WINAPI* XInputEnableFunc)(BOOL enable);
  typedef DWORD(WINAPI* XInputGetCapabilitiesFunc)(
      DWORD dwUserIndex,
      DWORD dwFlags,
      XINPUT_CAPABILITIES* pCapabilities);
  typedef DWORD(WINAPI* XInputGetStateFunc)(DWORD dwUserIndex,
                                            XINPUT_STATE* pState);
  typedef DWORD(WINAPI* XInputGetStateExFunc)(DWORD dwUserIndex,
                                              XInputStateEx* pState);

  XInputDataFetcherWin();

  XInputDataFetcherWin(const XInputDataFetcherWin&) = delete;
  XInputDataFetcherWin& operator=(const XInputDataFetcherWin&) = delete;

  ~XInputDataFetcherWin() override;

  GamepadSource source() override;

  // GamepadDataFetcher implementation.
  void GetGamepadData(bool devices_changed_hint) override;

  void PlayEffect(int pad_index,
                  mojom::GamepadHapticEffectType,
                  mojom::GamepadEffectParametersPtr,
                  mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback,
                  scoped_refptr<base::SequencedTaskRunner>) override;

  void ResetVibration(
      int pad_index,
      mojom::GamepadHapticsManager::ResetVibrationActuatorCallback,
      scoped_refptr<base::SequencedTaskRunner>) override;

  // Hooks to set fake implementations of the XInput OS functions for testing
  using XInputGetCapabilitiesFunctionCallback =
      base::RepeatingCallback<XInputGetCapabilitiesFunc()>;
  static void OverrideXInputGetCapabilitiesFuncForTesting(
      XInputGetCapabilitiesFunctionCallback callback);

  using XInputGetStateExFunctionCallback =
      base::RepeatingCallback<XInputGetStateExFunc()>;
  static void OverrideXInputGetStateExFuncForTesting(
      XInputGetStateExFunctionCallback callback);

  void InitializeForWgiDataFetcher();

  bool IsAnyMetaButtonPressed();

 private:
  void OnAddedToProvider() override;

  // Get functions from dynamically loading the xinput dll.
  // Returns true if loading was successful.
  bool GetXInputDllFunctions();
  // Same as `GetXInputDllFunctions` but loads only the functions required by
  // WgiDataFetcher and also checks for test hooks.
  bool GetXInputDllFunctionsForWgiDataFetcher();

  // Scan for connected XInput and DirectInput gamepads.
  void EnumerateDevices();
  void GetXInputPadData(int i);

  static XInputGetCapabilitiesFunctionCallback&
  GetXInputGetCapabilitiesFunctionCallback();

  static XInputGetStateExFunctionCallback&
  GetXInputGetStateExFunctionCallback();

  base::ScopedNativeLibrary xinput_dll_;
  bool xinput_available_;

  // Function pointers to XInput functionality, retrieved in
  // |GetXInputDllFunctions|.
  XInputGetCapabilitiesFunc xinput_get_capabilities_;
  XInputGetStateFunc xinput_get_state_;
  XInputGetStateExFunc xinput_get_state_ex_;
  XInputHapticGamepadWin::XInputSetStateFunc xinput_set_state_;

  bool xinput_connected_[XUSER_MAX_COUNT];
  std::unique_ptr<XInputHapticGamepadWin> haptics_[XUSER_MAX_COUNT];
};

}  // namespace device

#endif  // DEVICE_GAMEPAD_XINPUT_DATA_FETCHER_WIN_H_