blob: 808cdacbc6e55ddf66bf1884301f7ba1cf2be965 [file] [log] [blame]
// Copyright (c) 2018 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 <CoreFoundation/CoreFoundation.h>
#include <ForceFeedback/ForceFeedback.h>
#include <IOKit/hid/IOHIDManager.h>
#include <stddef.h>
#include "device/gamepad/abstract_haptic_gamepad.h"
#include "device/gamepad/dualshock4_controller_mac.h"
#include "device/gamepad/hid_haptic_gamepad_mac.h"
#include "device/gamepad/public/cpp/gamepad.h"
namespace device {
// 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 : public AbstractHapticGamepad {
GamepadDeviceMac(int location_id,
IOHIDDeviceRef device_ref,
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();
// Starts vibrating the device with the specified magnitudes.
void SetVibration(double strong_magnitude, double weak_magnitude) override;
// Stop vibration by canceling any ongoing vibration effect.
void SetZeroVibration() override;
// Stop vibration and release held resources.
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_;
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<Dualshock4ControllerMac> dualshock4_;
// A controller that uses a HID output report for vibration effects.
std::unique_ptr<HidHapticGamepadMac> hid_haptics_;
} // namespace device