Commit 27a13dea authored by Matt Reynolds's avatar Matt Reynolds Committed by Commit Bot

[gamepad] Refactor HID output report platform logic

Previously, HID gamepad haptics duplicated the OS-specific
logic for writing HID output reports. This CL factors out the
duplicated logic.

BUG=984155

Change-Id: I31001415f840a169a261ee9c1e84030e0e6ee17e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1754666
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Reviewed-by: default avatarOvidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688716}
parent d3045ebd
......@@ -108,7 +108,7 @@ test("device_unittests") {
"gamepad/gamepad_id_list_unittest.cc",
"gamepad/gamepad_provider_unittest.cc",
"gamepad/gamepad_service_unittest.cc",
"gamepad/hid_haptic_gamepad_base_unittest.cc",
"gamepad/hid_haptic_gamepad_unittest.cc",
"gamepad/public/cpp/gamepad_mojom_traits_unittest.cc",
"test/run_all_unittests.cc",
]
......
......@@ -15,14 +15,8 @@ component("gamepad") {
sources = [
"abstract_haptic_gamepad.cc",
"abstract_haptic_gamepad.h",
"dualshock4_controller_base.cc",
"dualshock4_controller_base.h",
"dualshock4_controller_linux.cc",
"dualshock4_controller_linux.h",
"dualshock4_controller_mac.cc",
"dualshock4_controller_mac.h",
"dualshock4_controller_win.cc",
"dualshock4_controller_win.h",
"dualshock4_controller.cc",
"dualshock4_controller.h",
"game_controller_data_fetcher_mac.h",
"game_controller_data_fetcher_mac.mm",
"gamepad_blocklist.cc",
......@@ -72,14 +66,15 @@ component("gamepad") {
"gamepad_user_gesture.h",
"hid_dll_functions_win.cc",
"hid_dll_functions_win.h",
"hid_haptic_gamepad_base.cc",
"hid_haptic_gamepad_base.h",
"hid_haptic_gamepad_linux.cc",
"hid_haptic_gamepad_linux.h",
"hid_haptic_gamepad_mac.cc",
"hid_haptic_gamepad_mac.h",
"hid_haptic_gamepad_win.cc",
"hid_haptic_gamepad_win.h",
"hid_haptic_gamepad.cc",
"hid_haptic_gamepad.h",
"hid_writer.h",
"hid_writer_linux.cc",
"hid_writer_linux.h",
"hid_writer_mac.cc",
"hid_writer_mac.h",
"hid_writer_win.cc",
"hid_writer_win.h",
"raw_input_data_fetcher_win.cc",
"raw_input_data_fetcher_win.h",
"raw_input_gamepad_device_win.cc",
......
......@@ -2,52 +2,39 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/gamepad/dualshock4_controller_base.h"
#include "device/gamepad/dualshock4_controller.h"
#include <array>
#include "device/gamepad/gamepad_id_list.h"
#include "device/gamepad/hid_writer.h"
namespace {
const uint16_t kVendorSony = 0x054c;
const uint16_t kProductDualshock4 = 0x05c4;
const uint16_t kProductDualshock4Slim = 0x9cc;
const uint8_t kRumbleMagnitudeMax = 0xff;
enum ControllerType {
UNKNOWN_CONTROLLER,
DUALSHOCK4_CONTROLLER,
DUALSHOCK4_SLIM_CONTROLLER
};
ControllerType ControllerTypeFromDeviceIds(uint16_t vendor_id,
uint16_t product_id) {
if (vendor_id == kVendorSony) {
switch (product_id) {
case kProductDualshock4:
return DUALSHOCK4_CONTROLLER;
case kProductDualshock4Slim:
return DUALSHOCK4_SLIM_CONTROLLER;
default:
break;
}
}
return UNKNOWN_CONTROLLER;
}
} // namespace
namespace device {
Dualshock4ControllerBase::~Dualshock4ControllerBase() = default;
Dualshock4Controller::Dualshock4Controller(std::unique_ptr<HidWriter> writer)
: writer_(std::move(writer)) {}
Dualshock4Controller::~Dualshock4Controller() = default;
// static
bool Dualshock4ControllerBase::IsDualshock4(uint16_t vendor_id,
bool Dualshock4Controller::IsDualshock4(uint16_t vendor_id,
uint16_t product_id) {
return ControllerTypeFromDeviceIds(vendor_id, product_id) !=
UNKNOWN_CONTROLLER;
auto gamepad_id = GamepadIdList::Get().GetGamepadId(vendor_id, product_id);
return gamepad_id == GamepadId::kSonyProduct05c4 ||
gamepad_id == GamepadId::kSonyProduct09cc;
}
void Dualshock4Controller::DoShutdown() {
writer_.reset();
}
void Dualshock4ControllerBase::SetVibration(double strong_magnitude,
void Dualshock4Controller::SetVibration(double strong_magnitude,
double weak_magnitude) {
DCHECK(writer_);
std::array<uint8_t, 32> control_report;
control_report.fill(0);
control_report[0] = 0x05; // report ID
......@@ -57,7 +44,11 @@ void Dualshock4ControllerBase::SetVibration(double strong_magnitude,
control_report[5] =
static_cast<uint8_t>(strong_magnitude * kRumbleMagnitudeMax);
WriteOutputReport(control_report);
writer_->WriteOutputReport(control_report);
}
base::WeakPtr<AbstractHapticGamepad> Dualshock4Controller::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
......@@ -2,28 +2,38 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_BASE_
#define DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_BASE_
#ifndef DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_H_
#define DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_H_
#include <stdint.h>
#include <memory>
#include "base/memory/weak_ptr.h"
#include "device/gamepad/abstract_haptic_gamepad.h"
namespace device {
class Dualshock4ControllerBase : public AbstractHapticGamepad {
class HidWriter;
class Dualshock4Controller final : public AbstractHapticGamepad {
public:
Dualshock4ControllerBase() = default;
~Dualshock4ControllerBase() override;
Dualshock4Controller(std::unique_ptr<HidWriter> hid_writer);
~Dualshock4Controller() override;
static bool IsDualshock4(uint16_t vendor_id, uint16_t product_id);
// AbstractHapticGamepad implementation.
// AbstractHapticGamepad public implementation.
void SetVibration(double strong_magnitude, double weak_magnitude) override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
private:
// AbstractHapticGamepad private implementation.
void DoShutdown() override;
// Sends an output report to the gamepad. Derived classes should override this
// method with a platform-specific implementation.
virtual size_t WriteOutputReport(base::span<const uint8_t> report) = 0;
std::unique_ptr<HidWriter> writer_;
base::WeakPtrFactory<Dualshock4Controller> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_BASE_
#endif // DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_H_
// Copyright 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.
#ifndef DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_LINUX_
#define DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_LINUX_
#include "base/files/scoped_file.h"
#include "base/memory/weak_ptr.h"
#include "device/gamepad/dualshock4_controller_base.h"
namespace device {
class Dualshock4ControllerLinux final : public Dualshock4ControllerBase {
public:
Dualshock4ControllerLinux(const base::ScopedFD& fd);
~Dualshock4ControllerLinux() override;
// AbstractHapticGamepad implementation.
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
// Dualshock4ControllerBase implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
int fd_; // Not owned.
base::WeakPtrFactory<Dualshock4ControllerLinux> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_LINUX_
......@@ -16,7 +16,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "device/gamepad/dualshock4_controller.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/hid_haptic_gamepad.h"
#include "device/gamepad/hid_writer_linux.h"
#include "device/udev_linux/udev.h"
#if defined(OS_CHROMEOS)
......@@ -542,18 +545,19 @@ void GamepadDeviceLinux::InitializeHidraw(base::ScopedFD fd) {
bool is_dualshock4 = false;
bool is_hid_haptic = false;
if (GetHidrawDevinfo(hidraw_fd_, &bus_type_, &vendor_id, &product_id)) {
is_dualshock4 =
Dualshock4ControllerLinux::IsDualshock4(vendor_id, product_id);
is_hid_haptic = HidHapticGamepadLinux::IsHidHaptic(vendor_id, product_id);
is_dualshock4 = Dualshock4Controller::IsDualshock4(vendor_id, product_id);
is_hid_haptic = HidHapticGamepad::IsHidHaptic(vendor_id, product_id);
DCHECK_LE(is_dualshock4 + is_hid_haptic, 1);
}
if (is_dualshock4 && !dualshock4_)
dualshock4_ = std::make_unique<Dualshock4ControllerLinux>(hidraw_fd_);
if (is_dualshock4 && !dualshock4_) {
dualshock4_ = std::make_unique<Dualshock4Controller>(
std::make_unique<HidWriterLinux>(hidraw_fd_));
}
if (is_hid_haptic && !hid_haptics_) {
hid_haptics_ =
HidHapticGamepadLinux::Create(vendor_id, product_id, hidraw_fd_);
hid_haptics_ = HidHapticGamepad::Create(
vendor_id, product_id, std::make_unique<HidWriterLinux>(hidraw_fd_));
}
}
......
......@@ -12,10 +12,8 @@
#include "base/files/scoped_file.h"
#include "base/memory/weak_ptr.h"
#include "device/gamepad/abstract_haptic_gamepad.h"
#include "device/gamepad/dualshock4_controller_linux.h"
#include "device/gamepad/gamepad_id_list.h"
#include "device/gamepad/gamepad_standard_mappings.h"
#include "device/gamepad/hid_haptic_gamepad_linux.h"
#include "device/gamepad/udev_gamepad_linux.h"
extern "C" {
......@@ -24,6 +22,9 @@ struct udev_device;
namespace device {
class Dualshock4Controller;
class HidHapticGamepad;
// GamepadDeviceLinux represents a single gamepad device which may be accessed
// through multiple host interfaces. Gamepad button and axis state are queried
// through the joydev interface, while haptics commands are routed through the
......@@ -91,8 +92,7 @@ class GamepadDeviceLinux final : public AbstractHapticGamepad {
// Closes the hidraw device node and shuts down haptics.
void CloseHidrawNode();
// AbstractHapticGamepad implementation.
void DoShutdown() override;
// AbstractHapticGamepad public implementation.
void SetVibration(double strong_magnitude, double weak_magnitude) override;
void SetZeroVibration() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
......@@ -100,6 +100,9 @@ class GamepadDeviceLinux final : public AbstractHapticGamepad {
private:
using OpenPathCallback = base::OnceCallback<void(base::ScopedFD)>;
// AbstractHapticGamepad private implementation.
void DoShutdown() override;
void OnOpenHidrawNodeComplete(OpenDeviceNodeCallback callback,
base::ScopedFD fd);
void InitializeHidraw(base::ScopedFD fd);
......@@ -183,10 +186,10 @@ class GamepadDeviceLinux final : public AbstractHapticGamepad {
GamepadBusType bus_type_ = GAMEPAD_BUS_UNKNOWN;
// Dualshock4 functionality, if available.
std::unique_ptr<Dualshock4ControllerLinux> dualshock4_;
std::unique_ptr<Dualshock4Controller> dualshock4_;
// A controller that uses a HID output report for vibration effects.
std::unique_ptr<HidHapticGamepadLinux> hid_haptics_;
std::unique_ptr<HidHapticGamepad> hid_haptics_;
// Task runner to use for D-Bus tasks. D-Bus client classes (including
// PermissionBrokerClient) are not thread-safe and should be used only on the
......
......@@ -13,12 +13,13 @@
#include "base/memory/weak_ptr.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 {
class Dualshock4Controller;
class HidHapticGamepad;
// 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.
......@@ -51,13 +52,13 @@ class GamepadDeviceMac final : public AbstractHapticGamepad {
// ForceFeedback framework.
bool SupportsVibration();
// AbstractHapticGamepad implementation.
// AbstractHapticGamepad public implementation.
void SetVibration(double strong_magnitude, double weak_magnitude) override;
void SetZeroVibration() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
private:
// AbstractHapticGamepad implementation.
// AbstractHapticGamepad private implementation.
void DoShutdown() override;
// Initialize button capabilities for |gamepad|.
......@@ -106,10 +107,10 @@ class GamepadDeviceMac final : public AbstractHapticGamepad {
LONG direction_data_[2];
// Dualshock4 functionality, if available.
std::unique_ptr<Dualshock4ControllerMac> dualshock4_;
std::unique_ptr<Dualshock4Controller> dualshock4_;
// A controller that uses a HID output report for vibration effects.
std::unique_ptr<HidHapticGamepadMac> hid_haptics_;
std::unique_ptr<HidHapticGamepad> hid_haptics_;
base::WeakPtrFactory<GamepadDeviceMac> weak_factory_{this};
};
......
......@@ -7,7 +7,10 @@
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/stl_util.h"
#include "device/gamepad/dualshock4_controller.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/hid_haptic_gamepad.h"
#include "device/gamepad/hid_writer_mac.h"
#import <Foundation/Foundation.h>
......@@ -76,11 +79,12 @@ GamepadDeviceMac::GamepadDeviceMac(int location_id,
device_ref_(device_ref),
ff_device_ref_(nullptr),
ff_effect_ref_(nullptr) {
if (Dualshock4ControllerMac::IsDualshock4(vendor_id, product_id)) {
dualshock4_ = std::make_unique<Dualshock4ControllerMac>(device_ref);
} else if (HidHapticGamepadMac::IsHidHaptic(vendor_id, product_id)) {
hid_haptics_ =
HidHapticGamepadMac::Create(vendor_id, product_id, device_ref);
if (Dualshock4Controller::IsDualshock4(vendor_id, product_id)) {
dualshock4_ = std::make_unique<Dualshock4Controller>(
std::make_unique<HidWriterMac>(device_ref));
} else if (HidHapticGamepad::IsHidHaptic(vendor_id, product_id)) {
hid_haptics_ = HidHapticGamepad::Create(
vendor_id, product_id, std::make_unique<HidWriterMac>(device_ref));
} else if (device_ref) {
ff_device_ref_ = CreateForceFeedbackDevice(device_ref);
if (ff_device_ref_) {
......
......@@ -2,7 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/gamepad/hid_haptic_gamepad_base.h"
#include "device/gamepad/hid_haptic_gamepad.h"
#include <algorithm>
#include <vector>
#include "device/gamepad/hid_writer.h"
namespace device {
......@@ -37,7 +42,7 @@ void MagnitudeToBytes(double magnitude,
} // namespace
// Supported HID gamepads.
HidHapticGamepadBase::HapticReportData kHapticReportData[] = {
HidHapticGamepad::HapticReportData kHapticReportData[] = {
// XSkills Gamecube USB adapter
{0x0b43, 0x0005, 0x00, 4, 3, 3, 1 * kBitsPerByte, 0, 1},
// Stadia controller prototype
......@@ -47,20 +52,33 @@ HidHapticGamepadBase::HapticReportData kHapticReportData[] = {
};
size_t kHapticReportDataLength = base::size(kHapticReportData);
HidHapticGamepadBase::HidHapticGamepadBase(const HapticReportData& data)
HidHapticGamepad::HidHapticGamepad(const HapticReportData& data,
std::unique_ptr<HidWriter> writer)
: report_id_(data.report_id),
report_length_bytes_(data.report_length_bytes),
strong_offset_bytes_(data.strong_offset_bytes),
weak_offset_bytes_(data.weak_offset_bytes),
report_size_bits_(data.report_size_bits),
logical_min_(data.logical_min),
logical_max_(data.logical_max) {}
logical_max_(data.logical_max),
writer_(std::move(writer)) {}
HidHapticGamepadBase::~HidHapticGamepadBase() = default;
HidHapticGamepad::~HidHapticGamepad() = default;
// static
bool HidHapticGamepadBase::IsHidHaptic(uint16_t vendor_id,
uint16_t product_id) {
std::unique_ptr<HidHapticGamepad> HidHapticGamepad::Create(
uint16_t vendor_id,
uint16_t product_id,
std::unique_ptr<HidWriter> writer) {
DCHECK(writer);
const auto* haptic_data = GetHapticReportData(vendor_id, product_id);
if (!haptic_data)
return nullptr;
return std::make_unique<HidHapticGamepad>(*haptic_data, std::move(writer));
}
// static
bool HidHapticGamepad::IsHidHaptic(uint16_t vendor_id, uint16_t product_id) {
const auto* begin = kHapticReportData;
const auto* end = kHapticReportData + kHapticReportDataLength;
const auto* find_it =
......@@ -71,8 +89,8 @@ bool HidHapticGamepadBase::IsHidHaptic(uint16_t vendor_id,
}
// static
const HidHapticGamepadBase::HapticReportData*
HidHapticGamepadBase::GetHapticReportData(uint16_t vendor_id,
const HidHapticGamepad::HapticReportData* HidHapticGamepad::GetHapticReportData(
uint16_t vendor_id,
uint16_t product_id) {
const auto* begin = kHapticReportData;
const auto* end = kHapticReportData + kHapticReportDataLength;
......@@ -83,8 +101,13 @@ HidHapticGamepadBase::GetHapticReportData(uint16_t vendor_id,
return find_it == end ? nullptr : &*find_it;
}
void HidHapticGamepadBase::SetVibration(double strong_magnitude,
void HidHapticGamepad::DoShutdown() {
writer_.reset();
}
void HidHapticGamepad::SetVibration(double strong_magnitude,
double weak_magnitude) {
DCHECK(writer_);
std::vector<uint8_t> control_report(report_length_bytes_);
control_report[0] = report_id_;
if (strong_offset_bytes_ == weak_offset_bytes_) {
......@@ -123,7 +146,11 @@ void HidHapticGamepadBase::SetVibration(double strong_magnitude,
std::copy(right_bytes.begin(), right_bytes.end(),
control_report.begin() + weak_offset_bytes_);
}
WriteOutputReport(control_report);
writer_->WriteOutputReport(control_report);
}
base::WeakPtr<AbstractHapticGamepad> HidHapticGamepad::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
......@@ -2,19 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_BASE_H_
#define DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_BASE_H_
#ifndef DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_H_
#define DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include "base/memory/weak_ptr.h"
#include "device/gamepad/abstract_haptic_gamepad.h"
#include "device/gamepad/gamepad_export.h"
namespace device {
class DEVICE_GAMEPAD_EXPORT HidHapticGamepadBase
class HidWriter;
class DEVICE_GAMEPAD_EXPORT HidHapticGamepad final
: public AbstractHapticGamepad {
public:
// Devices that support HID haptic effects with a simple output report can
// be supported through HidHapticGamepadBase by adding a new HapticReportData
// be supported through HidHapticGamepad by adding a new HapticReportData
// item to kHapticReportData.
//
// Example:
......@@ -61,26 +68,32 @@ class DEVICE_GAMEPAD_EXPORT HidHapticGamepadBase
const uint32_t logical_max;
};
~HidHapticGamepadBase() override;
HidHapticGamepad(const HapticReportData& data,
std::unique_ptr<HidWriter> writer);
~HidHapticGamepad() override;
static std::unique_ptr<HidHapticGamepad> Create(
uint16_t vendor_id,
uint16_t product_id,
std::unique_ptr<HidWriter> writer);
// Return true if the device IDs match an item in kHapticReportData.
static bool IsHidHaptic(uint16_t vendor_id, uint16_t product_id);
// Return the HapticReportData for the device with matching device IDs.
static const HidHapticGamepadBase::HapticReportData* GetHapticReportData(
static const HidHapticGamepad::HapticReportData* GetHapticReportData(
uint16_t vendor_id,
uint16_t product_id);
// Set the current vibration magnitudes.
// AbstractHapticGamepad public implementation.
void SetVibration(double strong_magnitude, double weak_magnitude) override;
// Write the vibration output report to the device.
virtual size_t WriteOutputReport(base::span<const uint8_t> report) = 0;
protected:
HidHapticGamepadBase(const HapticReportData& data);
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
private:
// AbstractHapticGamepad private implementation.
void DoShutdown() override;
// Report ID of the report to use for vibration commands, or zero if report
// IDs are not used.
uint8_t report_id_;
......@@ -98,11 +111,15 @@ class DEVICE_GAMEPAD_EXPORT HidHapticGamepadBase
// Logical bounds of the vibration magnitude. Assumed to be positive.
uint32_t logical_min_;
uint32_t logical_max_;
std::unique_ptr<HidWriter> writer_;
base::WeakPtrFactory<HidHapticGamepad> weak_factory_{this};
};
extern HidHapticGamepadBase::HapticReportData kHapticReportData[];
extern HidHapticGamepad::HapticReportData kHapticReportData[];
extern size_t kHapticReportDataLength;
} // namespace device
#endif // DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_BASE_H_
#endif // DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_H_
// Copyright 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 "device/gamepad/hid_haptic_gamepad_linux.h"
#include "base/posix/eintr_wrapper.h"
namespace device {
HidHapticGamepadLinux::HidHapticGamepadLinux(const base::ScopedFD& fd,
const HapticReportData& data)
: HidHapticGamepadBase(data), fd_(fd.get()) {}
HidHapticGamepadLinux::~HidHapticGamepadLinux() = default;
// static
std::unique_ptr<HidHapticGamepadLinux> HidHapticGamepadLinux::Create(
uint16_t vendor_id,
uint16_t product_id,
const base::ScopedFD& fd) {
const auto* haptic_data = GetHapticReportData(vendor_id, product_id);
if (!haptic_data)
return nullptr;
return std::make_unique<HidHapticGamepadLinux>(fd, *haptic_data);
}
size_t HidHapticGamepadLinux::WriteOutputReport(
base::span<const uint8_t> report) {
DCHECK_GE(report.size_bytes(), 1U);
ssize_t bytes_written =
HANDLE_EINTR(write(fd_, report.data(), report.size_bytes()));
return bytes_written < 0 ? 0 : static_cast<size_t>(bytes_written);
}
base::WeakPtr<AbstractHapticGamepad> HidHapticGamepadLinux::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
// Copyright 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.
#ifndef DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_LINUX_H_
#define DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_LINUX_H_
#include "device/gamepad/hid_haptic_gamepad_base.h"
#include <memory>
#include "base/files/scoped_file.h"
#include "base/memory/weak_ptr.h"
namespace device {
class HidHapticGamepadLinux final : public HidHapticGamepadBase {
public:
HidHapticGamepadLinux(const base::ScopedFD& fd, const HapticReportData& data);
~HidHapticGamepadLinux() override;
static std::unique_ptr<HidHapticGamepadLinux>
Create(uint16_t vendor_id, uint16_t product_id, const base::ScopedFD& fd);
// AbstractHapticGamepad implementation.
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
// HidHapticGamepadBase implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
// Not owned.
int fd_;
base::WeakPtrFactory<HidHapticGamepadLinux> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_LINUX_H_
// Copyright 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 "device/gamepad/hid_haptic_gamepad_mac.h"
#include <CoreFoundation/CoreFoundation.h>
namespace device {
HidHapticGamepadMac::HidHapticGamepadMac(IOHIDDeviceRef device_ref,
const HapticReportData& data)
: HidHapticGamepadBase(data), device_ref_(device_ref) {}
HidHapticGamepadMac::~HidHapticGamepadMac() = default;
void HidHapticGamepadMac::DoShutdown() {
device_ref_ = nullptr;
}
// static
std::unique_ptr<HidHapticGamepadMac> HidHapticGamepadMac::Create(
uint16_t vendor_id,
uint16_t product_id,
IOHIDDeviceRef device_ref) {
const auto* haptic_data = GetHapticReportData(vendor_id, product_id);
if (!haptic_data)
return nullptr;
return std::make_unique<HidHapticGamepadMac>(device_ref, *haptic_data);
}
size_t HidHapticGamepadMac::WriteOutputReport(
base::span<const uint8_t> report) {
DCHECK_GE(report.size_bytes(), 1U);
if (!device_ref_)
return 0;
IOReturn success =
IOHIDDeviceSetReport(device_ref_, kIOHIDReportTypeOutput, report[0],
report.data(), report.size_bytes());
return (success == kIOReturnSuccess) ? report.size_bytes() : 0;
}
base::WeakPtr<AbstractHapticGamepad> HidHapticGamepadMac::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
// Copyright 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.
#ifndef DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_MAC_H_
#define DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_MAC_H_
#include <memory>
#include <IOKit/hid/IOHIDManager.h>
#include "base/memory/weak_ptr.h"
#include "device/gamepad/hid_haptic_gamepad_base.h"
namespace device {
class HidHapticGamepadMac final : public HidHapticGamepadBase {
public:
HidHapticGamepadMac(IOHIDDeviceRef device_ref, const HapticReportData& data);
~HidHapticGamepadMac() override;
static std::unique_ptr<HidHapticGamepadMac> Create(uint16_t vendor_id,
uint16_t product_id,
IOHIDDeviceRef device_ref);
// AbstractHapticGamepad implementation.
void DoShutdown() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
// HidHapticGamepadBase implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
IOHIDDeviceRef device_ref_;
base::WeakPtrFactory<HidHapticGamepadMac> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_MAC_H_
// Copyright 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 "device/gamepad/hid_haptic_gamepad_win.h"
#include <Unknwn.h>
#include <WinDef.h>
#include <stdint.h>
#include <windows.h>
namespace device {
HidHapticGamepadWin::HidHapticGamepadWin(HANDLE device_handle,
const HapticReportData& data)
: HidHapticGamepadBase(data) {
// Fetch the size of the RIDI_DEVICENAME string.
UINT size;
UINT result = ::GetRawInputDeviceInfo(device_handle, RIDI_DEVICENAME,
/*pData=*/nullptr, &size);
if (result == 0U) {
// Read RIDI_DEVICENAME into a buffer.
std::unique_ptr<wchar_t[]> name_buffer(new wchar_t[size]);
result = ::GetRawInputDeviceInfo(device_handle, RIDI_DEVICENAME,
name_buffer.get(), &size);
if (result == size) {
// Open the device handle for asynchronous I/O.
hid_handle_.Set(::CreateFile(
name_buffer.get(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
/*lpSecurityAttributes=*/nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
/*hTemplateFile=*/nullptr));
}
}
}
HidHapticGamepadWin::~HidHapticGamepadWin() = default;
// static
std::unique_ptr<HidHapticGamepadWin> HidHapticGamepadWin::Create(
uint16_t vendor_id,
uint16_t product_id,
HANDLE device_handle) {
const auto* haptic_data = GetHapticReportData(vendor_id, product_id);
if (!haptic_data)
return nullptr;
return std::make_unique<HidHapticGamepadWin>(device_handle, *haptic_data);
}
void HidHapticGamepadWin::DoShutdown() {
hid_handle_.Close();
}
size_t HidHapticGamepadWin::WriteOutputReport(
base::span<const uint8_t> report) {
DCHECK_GE(report.size_bytes(), 1U);
if (!hid_handle_.IsValid())
return 0;
base::win::ScopedHandle event_handle(
::CreateEvent(/*lpEventAttributes=*/nullptr,
/*bManualReset=*/false,
/*bInitialState=*/false,
/*lpName=*/L""));
OVERLAPPED overlapped = {0};
overlapped.hEvent = event_handle.Get();
// Set up an asynchronous write.
DWORD bytes_written = 0;
BOOL write_success =
::WriteFile(hid_handle_.Get(), report.data(), report.size_bytes(),
&bytes_written, &overlapped);
if (!write_success) {
DWORD error = ::GetLastError();
if (error == ERROR_IO_PENDING) {
// Wait for the write to complete. This causes WriteOutputReport to behave
// synchronously.
DWORD wait_object = ::WaitForSingleObject(overlapped.hEvent,
/*dwMilliseconds=*/100);
if (wait_object == WAIT_OBJECT_0) {
::GetOverlappedResult(hid_handle_.Get(), &overlapped, &bytes_written,
/*bWait=*/true);
} else {
// Wait failed, or the timeout was exceeded before the write completed.
// Cancel the write request.
if (::CancelIo(hid_handle_.Get())) {
HANDLE handles[2];
handles[0] = hid_handle_.Get();
handles[1] = overlapped.hEvent;
::WaitForMultipleObjects(/*nCount=*/2, handles,
/*bWaitAll=*/false, INFINITE);
}
}
}
}
return write_success ? bytes_written : 0;
}
base::WeakPtr<AbstractHapticGamepad> HidHapticGamepadWin::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
// Copyright 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.
#ifndef DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_WIN_H_
#define DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_WIN_H_
#include "base/memory/weak_ptr.h"
#include "base/win/scoped_handle.h"
#include "device/gamepad/hid_haptic_gamepad_base.h"
#include <memory>
namespace device {
class HidHapticGamepadWin final : public HidHapticGamepadBase {
public:
HidHapticGamepadWin(HANDLE device_handle, const HapticReportData& data);
~HidHapticGamepadWin() override;
static std::unique_ptr<HidHapticGamepadWin> Create(uint16_t vendor_id,
uint16_t product_id,
HANDLE device_handle);
// AbstractHapticGamepad implementation.
void DoShutdown() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
// HidHapticGamepadBase implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
base::win::ScopedHandle hid_handle_;
base::WeakPtrFactory<HidHapticGamepadWin> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_HID_HAPTIC_GAMEPAD_WIN_H_
// Copyright 2019 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.
#ifndef DEVICE_GAMEPAD_HID_WRITER_H_
#define DEVICE_GAMEPAD_HID_WRITER_H_
#include <stddef.h>
#include <stdint.h>
#include "base/containers/span.h"
namespace device {
// HidWriter defines an interface for writing output reports to a single HID
// device.
class HidWriter {
public:
HidWriter() = default;
virtual ~HidWriter() = default;
// Platform implementation for writing an output report. |report| contains
// the data to be written, with the report ID (if present) as the first byte.
// Returns the number of bytes written, or zero on failure.
virtual size_t WriteOutputReport(base::span<const uint8_t> report) = 0;
};
} // namespace device
#endif // DEVICE_GAMEPAD_HID_WRITER_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright 2019 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 "device/gamepad/dualshock4_controller_linux.h"
#include "device/gamepad/hid_writer_linux.h"
#include "base/posix/eintr_wrapper.h"
namespace device {
Dualshock4ControllerLinux::Dualshock4ControllerLinux(const base::ScopedFD& fd)
: fd_(fd.get()) {}
HidWriterLinux::HidWriterLinux(const base::ScopedFD& fd) : fd_(fd.get()) {}
Dualshock4ControllerLinux::~Dualshock4ControllerLinux() = default;
HidWriterLinux::~HidWriterLinux() = default;
size_t Dualshock4ControllerLinux::WriteOutputReport(
base::span<const uint8_t> report) {
DCHECK_GE(report.size_bytes(), 1U);
size_t HidWriterLinux::WriteOutputReport(base::span<const uint8_t> report) {
ssize_t bytes_written =
HANDLE_EINTR(write(fd_, report.data(), report.size_bytes()));
return bytes_written < 0 ? 0 : static_cast<size_t>(bytes_written);
}
base::WeakPtr<AbstractHapticGamepad> Dualshock4ControllerLinux::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
// Copyright 2019 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.
#ifndef DEVICE_GAMEPAD_HID_WRITER_LINUX_H_
#define DEVICE_GAMEPAD_HID_WRITER_LINUX_H_
#include <stddef.h>
#include <stdint.h>
#include "base/containers/span.h"
#include "base/files/scoped_file.h"
#include "device/gamepad/hid_writer.h"
namespace device {
class HidWriterLinux final : public HidWriter {
public:
explicit HidWriterLinux(const base::ScopedFD& fd);
~HidWriterLinux() override;
// HidWriter implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
// Not owned.
int fd_;
};
} // namespace device
#endif // DEVICE_GAMEPAD_HID_WRITER_LINUX_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright 2019 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 "device/gamepad/dualshock4_controller_mac.h"
#include "device/gamepad/hid_writer_mac.h"
#include <CoreFoundation/CoreFoundation.h>
namespace device {
Dualshock4ControllerMac::Dualshock4ControllerMac(IOHIDDeviceRef device_ref)
HidWriterMac::HidWriterMac(IOHIDDeviceRef device_ref)
: device_ref_(device_ref) {}
Dualshock4ControllerMac::~Dualshock4ControllerMac() = default;
void Dualshock4ControllerMac::DoShutdown() {
device_ref_ = nullptr;
}
size_t Dualshock4ControllerMac::WriteOutputReport(
base::span<const uint8_t> report) {
DCHECK_GE(report.size_bytes(), 1U);
if (!device_ref_)
return 0;
HidWriterMac::~HidWriterMac() = default;
size_t HidWriterMac::WriteOutputReport(base::span<const uint8_t> report) {
IOReturn success =
IOHIDDeviceSetReport(device_ref_, kIOHIDReportTypeOutput, report[0],
report.data(), report.size_bytes());
return (success == kIOReturnSuccess) ? report.size_bytes() : 0;
}
base::WeakPtr<AbstractHapticGamepad> Dualshock4ControllerMac::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright 2019 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.
#ifndef DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_MAC_H_
#define DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_MAC_H_
#ifndef DEVICE_GAMEPAD_HID_WRITER_MAC_H_
#define DEVICE_GAMEPAD_HID_WRITER_MAC_H_
#include <stddef.h>
#include <stdint.h>
#include <IOKit/hid/IOHIDManager.h>
#include "base/memory/weak_ptr.h"
#include "device/gamepad/dualshock4_controller_base.h"
#include "base/containers/span.h"
#include "device/gamepad/hid_writer.h"
namespace device {
class Dualshock4ControllerMac final : public Dualshock4ControllerBase {
class HidWriterMac final : public HidWriter {
public:
Dualshock4ControllerMac(IOHIDDeviceRef device_ref);
~Dualshock4ControllerMac() override;
// AbstractHapticGamepad implementation.
void DoShutdown() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
explicit HidWriterMac(IOHIDDeviceRef device_ref);
~HidWriterMac() override;
// Dualshock4ControllerBase implementation.
// HidWriter implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
IOHIDDeviceRef device_ref_;
base::WeakPtrFactory<Dualshock4ControllerMac> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_MAC_H_
#endif // DEVICE_GAMEPAD_HID_WRITER_MAC_H_
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/gamepad/dualshock4_controller_win.h"
#include "device/gamepad/hid_writer_win.h"
#include <Unknwn.h>
#include <WinDef.h>
......@@ -11,14 +11,14 @@
namespace device {
Dualshock4ControllerWin::Dualshock4ControllerWin(HANDLE device_handle) {
HidWriterWin::HidWriterWin(HANDLE device) {
UINT size;
UINT result =
::GetRawInputDeviceInfo(device_handle, RIDI_DEVICENAME, nullptr, &size);
::GetRawInputDeviceInfo(device, RIDI_DEVICENAME, nullptr, &size);
if (result == 0U) {
std::unique_ptr<wchar_t[]> name_buffer(new wchar_t[size]);
result = ::GetRawInputDeviceInfo(device_handle, RIDI_DEVICENAME,
name_buffer.get(), &size);
result = ::GetRawInputDeviceInfo(device, RIDI_DEVICENAME, name_buffer.get(),
&size);
if (result == size) {
// Open the device handle for asynchronous I/O.
hid_handle_.Set(
......@@ -29,14 +29,9 @@ Dualshock4ControllerWin::Dualshock4ControllerWin(HANDLE device_handle) {
}
}
Dualshock4ControllerWin::~Dualshock4ControllerWin() = default;
HidWriterWin::~HidWriterWin() = default;
void Dualshock4ControllerWin::DoShutdown() {
hid_handle_.Close();
}
size_t Dualshock4ControllerWin::WriteOutputReport(
base::span<const uint8_t> report) {
size_t HidWriterWin::WriteOutputReport(base::span<const uint8_t> report) {
DCHECK_GE(report.size_bytes(), 1U);
if (!hid_handle_.IsValid())
return 0;
......@@ -75,8 +70,4 @@ size_t Dualshock4ControllerWin::WriteOutputReport(
return write_success ? bytes_written : 0;
}
base::WeakPtr<AbstractHapticGamepad> Dualshock4ControllerWin::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
} // namespace device
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright 2019 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.
#ifndef DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_WIN_
#define DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_WIN_
#ifndef DEVICE_GAMEPAD_HID_WRITER_WIN_H_
#define DEVICE_GAMEPAD_HID_WRITER_WIN_H_
#include "base/memory/weak_ptr.h"
#include <stddef.h>
#include <stdint.h>
#include "base/containers/span.h"
#include "base/win/scoped_handle.h"
#include "device/gamepad/dualshock4_controller_base.h"
#include "base/win/windows_types.h"
#include "device/gamepad/hid_writer.h"
namespace device {
class Dualshock4ControllerWin final : public Dualshock4ControllerBase {
class HidWriterWin final : public HidWriter {
public:
explicit Dualshock4ControllerWin(HANDLE device_handle);
~Dualshock4ControllerWin() override;
// AbstractHapticGamepad implementation.
void DoShutdown() override;
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override;
explicit HidWriterWin(HANDLE device);
~HidWriterWin() override;
// Dualshock4ControllerBase implementation.
// HidWriter implementation.
size_t WriteOutputReport(base::span<const uint8_t> report) override;
private:
base::win::ScopedHandle hid_handle_;
base::WeakPtrFactory<Dualshock4ControllerWin> weak_factory_{this};
};
} // namespace device
#endif // DEVICE_GAMEPAD_DUALSHOCK4_CONTROLLER_WIN_
#endif // DEVICE_GAMEPAD_HID_WRITER_WIN_H_
......@@ -5,8 +5,11 @@
#include "raw_input_gamepad_device_win.h"
#include "base/stl_util.h"
#include "device/gamepad/dualshock4_controller.h"
#include "device/gamepad/gamepad_blocklist.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/hid_haptic_gamepad.h"
#include "device/gamepad/hid_writer_win.h"
namespace device {
......@@ -68,11 +71,12 @@ RawInputGamepadDeviceWin::RawInputGamepadDeviceWin(
is_valid_ = QueryDeviceInfo();
if (is_valid_) {
if (Dualshock4ControllerWin::IsDualshock4(vendor_id_, product_id_)) {
dualshock4_ = std::make_unique<Dualshock4ControllerWin>(handle_);
} else if (HidHapticGamepadWin::IsHidHaptic(vendor_id_, product_id_)) {
hid_haptics_ =
HidHapticGamepadWin::Create(vendor_id_, product_id_, handle_);
if (Dualshock4Controller::IsDualshock4(vendor_id_, product_id_)) {
dualshock4_ = std::make_unique<Dualshock4Controller>(
std::make_unique<HidWriterWin>(handle_));
} else if (HidHapticGamepad::IsHidHaptic(vendor_id_, product_id_)) {
hid_haptics_ = HidHapticGamepad::Create(
vendor_id_, product_id_, std::make_unique<HidWriterWin>(handle_));
}
}
}
......
......@@ -17,13 +17,14 @@
#include "base/memory/weak_ptr.h"
#include "device/gamepad/abstract_haptic_gamepad.h"
#include "device/gamepad/dualshock4_controller_win.h"
#include "device/gamepad/hid_dll_functions_win.h"
#include "device/gamepad/hid_haptic_gamepad_win.h"
#include "device/gamepad/public/cpp/gamepad.h"
namespace device {
class HidHapticGamepad;
class Dualshock4Controller;
class RawInputGamepadDeviceWin final : public AbstractHapticGamepad {
public:
// Relevant usage IDs within the Generic Desktop usage page. RawInput gamepads
......@@ -138,10 +139,10 @@ class RawInputGamepadDeviceWin final : public AbstractHapticGamepad {
PHIDP_PREPARSED_DATA preparsed_data_ = nullptr;
// Dualshock4-specific functionality (e.g., haptics), if available.
std::unique_ptr<Dualshock4ControllerWin> dualshock4_;
std::unique_ptr<Dualshock4Controller> dualshock4_;
// A controller that uses a HID output report for vibration effects.
std::unique_ptr<HidHapticGamepadWin> hid_haptics_;
std::unique_ptr<HidHapticGamepad> hid_haptics_;
base::WeakPtrFactory<RawInputGamepadDeviceWin> weak_factory_{this};
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment