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:

committed by
Chromium LUCI CQ

parent
ac3a9b39ac
commit
8c056e7eef
@ -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.
|
||||
|
Reference in New Issue
Block a user