// Copyright 2018 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_GAMEPAD_DEVICE_MAC_H_
#define DEVICE_GAMEPAD_GAMEPAD_DEVICE_MAC_H_
#include <stddef.h>
#include <CoreFoundation/CoreFoundation.h>
#include <ForceFeedback/ForceFeedback.h>
#include <IOKit/hid/IOHIDManager.h>
#include <string_view>
#include "base/memory/weak_ptr.h"
#include "device/gamepad/abstract_haptic_gamepad.h"
#include "device/gamepad/gamepad_standard_mappings.h"
#include "device/gamepad/public/cpp/gamepad.h"
namespace device {
class Dualshock4Controller;
class HidHapticGamepad;
class XboxHidController;
// GamepadDeviceMac represents a single gamepad device. Gamepad enumeration
// and state polling is handled through the raw HID interface, while haptics
// commands are issued through the ForceFeedback framework.
//
// Dualshock4 haptics are not supported through ForceFeedback and are instead
// sent through the raw HID interface.
class GamepadDeviceMac final : public AbstractHapticGamepad {
public:
GamepadDeviceMac(int location_id,
IOHIDDeviceRef device_ref,
std::string_view product_name,
int vendor_id,
int product_id);
~GamepadDeviceMac() override;
// Initialize |gamepad| with the number of buttons and axes described in the
// device's elements array.
bool AddButtonsAndAxes(Gamepad* gamepad);
// Update the button and axis state in |gamepad| with the new data in |value|.
// If the updated element is an axis, the axis value will first be normalized.
void UpdateGamepadForValue(IOHIDValueRef value, Gamepad* gamepad);
// Return the OS-assigned ID for this device.
int GetLocationId() { return location_id_; }
// Return true if |device| refers to this device.
bool IsSameDevice(IOHIDDeviceRef device) { return device == device_ref_; }
// Return true if this device supports force feedback through the
// ForceFeedback framework.
bool SupportsVibration();
// AbstractHapticGamepad public implementation.
void SetVibration(mojom::GamepadEffectParametersPtr params) override;
void SetZeroVibration() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
private:
// AbstractHapticGamepad private implementation.
void DoShutdown() override;
// Initialize button capabilities for |gamepad|.
bool AddButtons(Gamepad* gamepad);
// Initialize axis capabilities for |gamepad|.
bool AddAxes(Gamepad* gamepad);
// Return true if this element has a parent collection with a usage page that
// suggests it could be a gamepad.
static bool CheckCollection(IOHIDElementRef element);
// Create a force feedback device node for controlling haptics on
// |device_ref|. Ownership of the returned reference is retained by the
// caller.
static FFDeviceObjectReference CreateForceFeedbackDevice(
IOHIDDeviceRef device_ref);
// Create a force feedback effect on |ff_device_ref| and store the description
// to |ff_effect|. Ownership of the returned reference is retained by the
// caller.
static FFEffectObjectReference CreateForceFeedbackEffect(
FFDeviceObjectReference ff_device_ref,
FFEFFECT* ff_effect,
FFCUSTOMFORCE* ff_custom_force,
LONG* force_data,
DWORD* axes_data,
LONG* direction_data);
int location_id_;
IOHIDDeviceRef device_ref_;
GamepadBusType bus_type_;
IOHIDElementRef button_elements_[Gamepad::kButtonsLengthCap];
IOHIDElementRef axis_elements_[Gamepad::kAxesLengthCap];
CFIndex axis_minimums_[Gamepad::kAxesLengthCap];
CFIndex axis_maximums_[Gamepad::kAxesLengthCap];
CFIndex axis_report_sizes_[Gamepad::kAxesLengthCap];
// Force feedback
FFDeviceObjectReference ff_device_ref_;
FFEffectObjectReference ff_effect_ref_;
FFEFFECT ff_effect_;
FFCUSTOMFORCE ff_custom_force_;
LONG force_data_[2];
DWORD axes_data_[2];
LONG direction_data_[2];
// Dualshock4 functionality, if available.
std::unique_ptr<Dualshock4Controller> dualshock4_;
// Xbox Wireless Controller behaves like a HID gamepad when connected over
// Bluetooth. In this mode, haptics functionality is provided by |xbox_hid_|.
// When connected over USB, Xbox Wireless Controller is supported through
// XboxDataFetcher.
std::unique_ptr<XboxHidController> xbox_hid_;
// A controller that uses a HID output report for vibration effects.
std::unique_ptr<HidHapticGamepad> hid_haptics_;
base::WeakPtrFactory<GamepadDeviceMac> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_GAMEPAD_DEVICE_MAC_H_