0

Reland "[Gamepad] Implement trigger rumble on MacOS"

This is a reland of commit 75a1c37990

Original change's description:
> [Gamepad] Implement trigger rumble on MacOS
>
> This CL adds support trigger rumble on MacOS for supported devices
> connected either through Bluetooth (XboxHidController) or USB (XboxControllerMac).
>
> Tested using a Xbox Series X gamepad on MacOS Sonoma 14.2
>
> Bug: 1316534
> Change-Id: I69ecbb3816d1be045cf93ce60c3abce15e9c6373
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5238741
> Reviewed-by: Matt Reynolds <mattreynolds@chromium.org>
> Reviewed-by: Reilly Grant <reillyg@chromium.org>
> Commit-Queue: Gabriel Brito <gabrielbrito@microsoft.com>
> Cr-Commit-Position: refs/heads/main@{#1256586}

Bug: 1316534
Change-Id: I87855987f8ab167dbc86f25a2537607c39ac7c47
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5273881
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Auto-Submit: Gabriel Brito <gabrielbrito@microsoft.com>
Commit-Queue: Matt Reynolds <mattreynolds@chromium.org>
Reviewed-by: Matt Reynolds <mattreynolds@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1257131}
This commit is contained in:
Gabriel Brito
2024-02-07 01:53:21 +00:00
committed by Chromium LUCI CQ
parent ac3a9b39ac
commit 8c056e7eef
9 changed files with 82 additions and 44 deletions

@ -706,6 +706,35 @@ std::pair<uint16_t, uint16_t> GamepadIdList::GetDeviceIdsFromGamepadId(
return {vendor_id, product_id};
}
bool GamepadIdList::HasTriggerRumbleSupport(GamepadId gamepad_id) const {
// Xbox One USB
return gamepad_id == GamepadId::kMicrosoftProduct02d1 ||
// Xbox One USB 2015 Firmware
gamepad_id == GamepadId::kMicrosoftProduct02dd ||
// Xbox One S Bluetooth 2016 Firmware
gamepad_id == GamepadId::kMicrosoftProduct02fd ||
// Xbox One S Bluetooth 2021 Firmware
gamepad_id == GamepadId::kMicrosoftProduct0b20 ||
// Xbox One S USB
gamepad_id == GamepadId::kMicrosoftProduct02ea ||
// Xbox One S Bluetooth
gamepad_id == GamepadId::kMicrosoftProduct02e0 ||
// Xbox One S USB
gamepad_id == GamepadId::kMicrosoftProduct0b06 ||
// Xbox Series X USB
gamepad_id == GamepadId::kMicrosoftProduct0b12 ||
// Xbox Series X Bluetooth
gamepad_id == GamepadId::kMicrosoftProduct0b13 ||
// Xbox One Elite USB
gamepad_id == GamepadId::kMicrosoftProduct02e3 ||
// Xbox One Elite Series 2 USB
gamepad_id == GamepadId::kMicrosoftProduct0b00 ||
// Xbox One Elite Series 2 Bluetooth
gamepad_id == GamepadId::kMicrosoftProduct0b05 ||
// Xbox Elite Series 2 Bluetooth 2021 Firmware
gamepad_id == GamepadId::kMicrosoftProduct0b22;
}
std::vector<std::tuple<uint16_t, uint16_t, XInputType>>
GamepadIdList::GetGamepadListForTesting() const {
std::vector<std::tuple<uint16_t, uint16_t, XInputType>> gamepads;

@ -148,6 +148,10 @@ class DEVICE_GAMEPAD_EXPORT GamepadIdList {
// device is not XInput or the XInput flavor is unknown.
XInputType GetXInputType(uint16_t vendor_id, uint16_t product_id) const;
// Returns true if the gamepad device identified by |gamepad_id| has haptic
// actuators on its triggers. Returns false otherwise.
bool HasTriggerRumbleSupport(GamepadId gamepad_id) const;
// Returns the internal list of gamepad info for testing purposes.
std::vector<std::tuple<uint16_t, uint16_t, XInputType>>
GetGamepadListForTesting() const;

@ -215,7 +215,13 @@ void GamepadPlatformDataFetcherMac::DeviceAdd(IOHIDDeviceRef device) {
return;
}
state->data.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
if (GamepadIdList::Get().HasTriggerRumbleSupport(gamepad_id)) {
state->data.vibration_actuator.type =
GamepadHapticActuatorType::kTriggerRumble;
} else {
state->data.vibration_actuator.type =
GamepadHapticActuatorType::kDualRumble;
}
state->data.vibration_actuator.not_null = new_device->SupportsVibration();
state->data.connected = true;

@ -151,35 +151,6 @@ uint32_t GetPaddleNumber(
return num_paddles;
}
bool HasTriggerRumbleSupport(GamepadId gamepad_id) {
// Xbox One USB
return gamepad_id == GamepadId::kMicrosoftProduct02d1 ||
// Xbox One USB 2015 Firmware
gamepad_id == GamepadId::kMicrosoftProduct02dd ||
// Xbox One S Bluetooth 2016 Firmware
gamepad_id == GamepadId::kMicrosoftProduct02fd ||
// Xbox One S Bluetooth 2021 Firmware
gamepad_id == GamepadId::kMicrosoftProduct0b20 ||
// Xbox One S USB
gamepad_id == GamepadId::kMicrosoftProduct02ea ||
// Xbox One S Bluetooth
gamepad_id == GamepadId::kMicrosoftProduct02e0 ||
// Xbox One S USB
gamepad_id == GamepadId::kMicrosoftProduct0b06 ||
// Xbox Series X USB
gamepad_id == GamepadId::kMicrosoftProduct0b12 ||
// Xbox Series X Bluetooth
gamepad_id == GamepadId::kMicrosoftProduct0b13 ||
// Xbox One Elite USB
gamepad_id == GamepadId::kMicrosoftProduct02e3 ||
// Xbox One Elite Series 2 USB
gamepad_id == GamepadId::kMicrosoftProduct0b00 ||
// Xbox One Elite Series 2 Bluetooth
gamepad_id == GamepadId::kMicrosoftProduct0b05 ||
// Xbox Elite Series 2 Bluetooth 2021 Firmware
gamepad_id == GamepadId::kMicrosoftProduct0b22;
}
} // namespace
WgiDataFetcherWin::WgiDataFetcherWin() {
@ -287,7 +258,7 @@ void WgiDataFetcherWin::OnGamepadAdded(
pad.SetID(BuildGamepadIdString(gamepad_id, display_name, gamepad));
pad.connected = true;
if (HasTriggerRumbleSupport(gamepad_id)) {
if (GamepadIdList::Get().HasTriggerRumbleSupport(gamepad_id)) {
pad.vibration_actuator.type = GamepadHapticActuatorType::kTriggerRumble;
} else {
pad.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;

@ -157,7 +157,10 @@ class XboxControllerMac final : public AbstractHapticGamepad {
// Send an Xbox One rumble packet to the device, where |strong_magnitude| and
// |weak_magnitude| are values in the range [0,255] that represent the
// vibration intensity for the strong and weak rumble motors.
void WriteXboxOneRumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
void WriteXboxOneRumble(uint8_t strong_magnitude,
uint8_t weak_magnitude,
uint8_t left_trigger,
uint8_t right_trigger);
// Send an Xbox One packet to the device acknowledging that the Xbox button
// was pressed or released. |sequence_number| must match the value in the

@ -340,13 +340,17 @@ void XboxControllerMac::SetVibration(mojom::GamepadEffectParametersPtr params) {
double strong_magnitude =
std::clamp<double>(params->strong_magnitude, 0.0, 1.0);
double weak_magnitude = std::clamp<double>(params->weak_magnitude, 0.0, 1.0);
double left_trigger = std::clamp<double>(params->left_trigger, 0.0, 1.0);
double right_trigger = std::clamp<double>(params->right_trigger, 0.0, 1.0);
if (xinput_type_ == kXInputTypeXbox360) {
WriteXbox360Rumble(static_cast<uint8_t>(strong_magnitude * 255.0),
static_cast<uint8_t>(weak_magnitude * 255.0));
} else if (xinput_type_ == kXInputTypeXboxOne) {
WriteXboxOneRumble(static_cast<uint8_t>(strong_magnitude * 255.0),
static_cast<uint8_t>(weak_magnitude * 255.0));
static_cast<uint8_t>(weak_magnitude * 255.0),
static_cast<uint8_t>(left_trigger * 255.0),
static_cast<uint8_t>(right_trigger * 255.0));
}
}
@ -814,7 +818,9 @@ bool XboxControllerMac::WriteXboxOneInit() {
}
void XboxControllerMac::WriteXboxOneRumble(uint8_t strong_magnitude,
uint8_t weak_magnitude) {
uint8_t weak_magnitude,
uint8_t left_trigger,
uint8_t right_trigger) {
const UInt8 length = sizeof(XboxOneRumbleData);
// This buffer will be released in WriteComplete when WritePipeAsync
@ -833,8 +839,8 @@ void XboxControllerMac::WriteXboxOneRumble(uint8_t strong_magnitude,
rumble_data->extra = 0x00;
// Set rumble intensities.
rumble_data->trigger_left = 0x00;
rumble_data->trigger_right = 0x00;
rumble_data->trigger_left = left_trigger;
rumble_data->trigger_right = right_trigger;
rumble_data->strong_magnitude = strong_magnitude;
rumble_data->weak_magnitude = weak_magnitude;

@ -315,7 +315,13 @@ void XboxDataFetcher::AddController(XboxControllerMac* controller) {
state->axis_mask = 0;
state->button_mask = 0;
state->data.vibration_actuator.type = GamepadHapticActuatorType::kDualRumble;
if (GamepadIdList::Get().HasTriggerRumbleSupport(controller->gamepad_id())) {
state->data.vibration_actuator.type =
GamepadHapticActuatorType::kTriggerRumble;
} else {
state->data.vibration_actuator.type =
GamepadHapticActuatorType::kDualRumble;
}
state->data.vibration_actuator.not_null = controller->SupportsVibration();
}

@ -42,7 +42,11 @@ void XboxHidController::SetVibration(mojom::GamepadEffectParametersPtr params) {
std::array<uint8_t, 9> control_report;
control_report.fill(0);
control_report[0] = 0x03; // report ID
control_report[1] = 0x03; // enable rumble motors, disable trigger haptics
control_report[1] = 0x0f; // enable rumble motors, enable trigger haptics
control_report[2] =
static_cast<uint8_t>(params->right_trigger * kRumbleMagnitudeMax);
control_report[3] =
static_cast<uint8_t>(params->left_trigger * kRumbleMagnitudeMax);
control_report[4] =
static_cast<uint8_t>(params->strong_magnitude * kRumbleMagnitudeMax);
control_report[5] =

@ -24,7 +24,9 @@ namespace {
constexpr size_t kReportLength = 9;
constexpr uint8_t kStopVibration[] = {0x03, // report ID
0x03, 0x00, 0x00,
0x0f,
0x00, // left trigger
0x00, // right trigger
0x00, // strong magnitude
0x00, // weak magnitude
0xff, 0x00, 0x01};
@ -32,7 +34,9 @@ static_assert(sizeof(kStopVibration) == kReportLength,
"kStopVibration has incorrect size");
constexpr uint8_t kStartVibration[] = {0x03, // report ID
0x03, 0x00, 0x00,
0x0f,
0x7f, // left trigger
0xff, // right trigger
0xff, // strong magnitude
0x7f, // weak magnitude
0xff, 0x00, 0x01};
@ -49,6 +53,8 @@ constexpr double kZeroStartDelayMillis = 0.0;
// these magnitudes.
constexpr double kStrongMagnitude = 1.0; // 100% intensity
constexpr double kWeakMagnitude = 0.5; // 50% intensity
constexpr double kLeftTrigger = 1.0; // 100% intensity
constexpr double kRightTrigger = 0.5; // 50% intensity
constexpr base::TimeDelta kPendingTaskDuration =
base::Milliseconds(kDurationMillis);
@ -94,12 +100,14 @@ class XboxHidControllerTest : public testing::Test {
double start_delay,
double strong_magnitude,
double weak_magnitude,
double left_trigger,
double right_trigger,
mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
gamepad_->PlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
mojom::GamepadEffectParameters::New(
kDurationMillis, start_delay, strong_magnitude, weak_magnitude,
/*left_trigger=*/0, /*right_trigger=*/0),
mojom::GamepadEffectParameters::New(kDurationMillis, start_delay,
strong_magnitude, weak_magnitude,
left_trigger, right_trigger),
std::move(callback), base::SingleThreadTaskRunner::GetCurrentDefault());
}
@ -130,7 +138,8 @@ TEST_F(XboxHidControllerTest, PlayEffect) {
EXPECT_EQ(0, callback_count_);
PostPlayEffect(
kZeroStartDelayMillis, kStrongMagnitude, kWeakMagnitude,
kZeroStartDelayMillis, kStrongMagnitude, kWeakMagnitude, kLeftTrigger,
kRightTrigger,
base::BindOnce(&XboxHidControllerTest::Callback, base::Unretained(this)));
// Run the queued task and start vibration.