gamepad.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/exo/gamepad.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "base/bind.h"
  7. #include "base/logging.h"
  8. namespace exo {
  9. Gamepad::Gamepad(const ui::GamepadDevice& gamepad_device)
  10. : device(gamepad_device),
  11. input_controller_(
  12. ui::OzonePlatform::GetInstance()->GetInputController()) {}
  13. Gamepad::~Gamepad() {
  14. for (GamepadObserver& observer : observer_list_)
  15. observer.OnGamepadDestroying(this);
  16. if (delegate_)
  17. delegate_->OnRemoved();
  18. }
  19. void Gamepad::Vibrate(const std::vector<int64_t>& duration_millis,
  20. const std::vector<uint8_t>& amplitudes,
  21. int32_t repeat) {
  22. if (!device.supports_vibration_rumble) {
  23. VLOG(2) << "Vibrate failed because gamepad does not support vibration.";
  24. return;
  25. }
  26. if (duration_millis.size() != amplitudes.size()) {
  27. VLOG(2) << "Vibrate failed because the amplitudes vector and "
  28. "duration_millis vector are not the same size.";
  29. return;
  30. }
  31. vibration_timer_.Stop();
  32. vibration_timer_.Start(
  33. FROM_HERE, base::Milliseconds(0),
  34. base::BindOnce(&Gamepad::HandleVibrate, base::Unretained(this),
  35. duration_millis, amplitudes, repeat, /*index=*/0,
  36. /*duration_already_vibrated=*/0));
  37. }
  38. void Gamepad::HandleVibrate(const std::vector<int64_t>& duration_millis,
  39. const std::vector<uint8_t>& amplitudes,
  40. int32_t repeat,
  41. size_t index,
  42. int64_t duration_already_vibrated) {
  43. size_t vector_size = duration_millis.size();
  44. if (index >= vector_size)
  45. return;
  46. if (!can_vibrate_) {
  47. VLOG(2) << "Gamepad is not allowed to vibrate because it is not in focus.";
  48. return;
  49. }
  50. int64_t duration_left_to_vibrate =
  51. duration_millis[index] - duration_already_vibrated;
  52. if (duration_left_to_vibrate > kMaxDurationMillis) {
  53. // The device does not support effects this long. Issue periodic vibration
  54. // commands until the effect is complete.
  55. SendVibrate(amplitudes[index], kMaxDurationMillis);
  56. vibration_timer_.Start(
  57. FROM_HERE, base::Milliseconds(kMaxDurationMillis),
  58. base::BindOnce(&Gamepad::HandleVibrate, base::Unretained(this),
  59. duration_millis, amplitudes, repeat, index,
  60. /*duration_already_vibrated=*/duration_already_vibrated +
  61. kMaxDurationMillis));
  62. } else {
  63. SendVibrate(amplitudes[index], duration_left_to_vibrate);
  64. index++;
  65. bool needs_to_repeat = index >= vector_size && repeat >= 0 &&
  66. repeat < static_cast<int32_t>(vector_size);
  67. if (needs_to_repeat)
  68. index = repeat;
  69. vibration_timer_.Start(
  70. FROM_HERE, base::Milliseconds(duration_left_to_vibrate),
  71. base::BindOnce(&Gamepad::HandleVibrate, base::Unretained(this),
  72. duration_millis, amplitudes, repeat, index,
  73. /*duration_already_vibrated=*/0));
  74. }
  75. }
  76. void Gamepad::SendVibrate(uint8_t amplitude, int64_t duration_millis) {
  77. // |duration_millis| is always <= |kMaxDurationMillis|, which is the max value
  78. // for uint16_t, so it is safe to cast it to uint16_t here.
  79. input_controller_->PlayVibrationEffect(
  80. device.id, amplitude, static_cast<uint16_t>(duration_millis));
  81. }
  82. void Gamepad::CancelVibration() {
  83. if (!device.supports_vibration_rumble) {
  84. VLOG(2)
  85. << "CancelVibration failed because gamepad does not support vibration.";
  86. return;
  87. }
  88. if (!vibration_timer_.IsRunning())
  89. return;
  90. vibration_timer_.Stop();
  91. SendCancelVibration();
  92. }
  93. void Gamepad::SendCancelVibration() {
  94. input_controller_->StopVibration(device.id);
  95. }
  96. void Gamepad::SetDelegate(std::unique_ptr<GamepadDelegate> delegate) {
  97. DCHECK(!delegate_);
  98. delegate_ = std::move(delegate);
  99. }
  100. void Gamepad::AddObserver(GamepadObserver* observer) {
  101. observer_list_.AddObserver(observer);
  102. }
  103. bool Gamepad::HasObserver(GamepadObserver* observer) const {
  104. return observer_list_.HasObserver(observer);
  105. }
  106. void Gamepad::RemoveObserver(GamepadObserver* observer) {
  107. observer_list_.RemoveObserver(observer);
  108. }
  109. void Gamepad::OnGamepadFocused() {
  110. can_vibrate_ =
  111. base::FeatureList::IsEnabled(chromeos::features::kGamepadVibration);
  112. }
  113. void Gamepad::OnGamepadFocusLost() {
  114. can_vibrate_ = false;
  115. CancelVibration();
  116. }
  117. void Gamepad::OnGamepadEvent(const ui::GamepadEvent& event) {
  118. DCHECK(delegate_);
  119. switch (event.type()) {
  120. case ui::GamepadEventType::BUTTON:
  121. delegate_->OnButton(event.code(), event.value(), event.timestamp());
  122. break;
  123. case ui::GamepadEventType::AXIS:
  124. delegate_->OnAxis(event.code(), event.value(), event.timestamp());
  125. break;
  126. case ui::GamepadEventType::FRAME:
  127. delegate_->OnFrame(event.timestamp());
  128. break;
  129. }
  130. }
  131. } // namespace exo