123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- // Copyright 2020 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 "components/exo/gamepad.h"
- #include "ash/constants/ash_features.h"
- #include "base/bind.h"
- #include "base/logging.h"
- namespace exo {
- Gamepad::Gamepad(const ui::GamepadDevice& gamepad_device)
- : device(gamepad_device),
- input_controller_(
- ui::OzonePlatform::GetInstance()->GetInputController()) {}
- Gamepad::~Gamepad() {
- for (GamepadObserver& observer : observer_list_)
- observer.OnGamepadDestroying(this);
- if (delegate_)
- delegate_->OnRemoved();
- }
- void Gamepad::Vibrate(const std::vector<int64_t>& duration_millis,
- const std::vector<uint8_t>& amplitudes,
- int32_t repeat) {
- if (!device.supports_vibration_rumble) {
- VLOG(2) << "Vibrate failed because gamepad does not support vibration.";
- return;
- }
- if (duration_millis.size() != amplitudes.size()) {
- VLOG(2) << "Vibrate failed because the amplitudes vector and "
- "duration_millis vector are not the same size.";
- return;
- }
- vibration_timer_.Stop();
- vibration_timer_.Start(
- FROM_HERE, base::Milliseconds(0),
- base::BindOnce(&Gamepad::HandleVibrate, base::Unretained(this),
- duration_millis, amplitudes, repeat, /*index=*/0,
- /*duration_already_vibrated=*/0));
- }
- void Gamepad::HandleVibrate(const std::vector<int64_t>& duration_millis,
- const std::vector<uint8_t>& amplitudes,
- int32_t repeat,
- size_t index,
- int64_t duration_already_vibrated) {
- size_t vector_size = duration_millis.size();
- if (index >= vector_size)
- return;
- if (!can_vibrate_) {
- VLOG(2) << "Gamepad is not allowed to vibrate because it is not in focus.";
- return;
- }
- int64_t duration_left_to_vibrate =
- duration_millis[index] - duration_already_vibrated;
- if (duration_left_to_vibrate > kMaxDurationMillis) {
- // The device does not support effects this long. Issue periodic vibration
- // commands until the effect is complete.
- SendVibrate(amplitudes[index], kMaxDurationMillis);
- vibration_timer_.Start(
- FROM_HERE, base::Milliseconds(kMaxDurationMillis),
- base::BindOnce(&Gamepad::HandleVibrate, base::Unretained(this),
- duration_millis, amplitudes, repeat, index,
- /*duration_already_vibrated=*/duration_already_vibrated +
- kMaxDurationMillis));
- } else {
- SendVibrate(amplitudes[index], duration_left_to_vibrate);
- index++;
- bool needs_to_repeat = index >= vector_size && repeat >= 0 &&
- repeat < static_cast<int32_t>(vector_size);
- if (needs_to_repeat)
- index = repeat;
- vibration_timer_.Start(
- FROM_HERE, base::Milliseconds(duration_left_to_vibrate),
- base::BindOnce(&Gamepad::HandleVibrate, base::Unretained(this),
- duration_millis, amplitudes, repeat, index,
- /*duration_already_vibrated=*/0));
- }
- }
- void Gamepad::SendVibrate(uint8_t amplitude, int64_t duration_millis) {
- // |duration_millis| is always <= |kMaxDurationMillis|, which is the max value
- // for uint16_t, so it is safe to cast it to uint16_t here.
- input_controller_->PlayVibrationEffect(
- device.id, amplitude, static_cast<uint16_t>(duration_millis));
- }
- void Gamepad::CancelVibration() {
- if (!device.supports_vibration_rumble) {
- VLOG(2)
- << "CancelVibration failed because gamepad does not support vibration.";
- return;
- }
- if (!vibration_timer_.IsRunning())
- return;
- vibration_timer_.Stop();
- SendCancelVibration();
- }
- void Gamepad::SendCancelVibration() {
- input_controller_->StopVibration(device.id);
- }
- void Gamepad::SetDelegate(std::unique_ptr<GamepadDelegate> delegate) {
- DCHECK(!delegate_);
- delegate_ = std::move(delegate);
- }
- void Gamepad::AddObserver(GamepadObserver* observer) {
- observer_list_.AddObserver(observer);
- }
- bool Gamepad::HasObserver(GamepadObserver* observer) const {
- return observer_list_.HasObserver(observer);
- }
- void Gamepad::RemoveObserver(GamepadObserver* observer) {
- observer_list_.RemoveObserver(observer);
- }
- void Gamepad::OnGamepadFocused() {
- can_vibrate_ =
- base::FeatureList::IsEnabled(chromeos::features::kGamepadVibration);
- }
- void Gamepad::OnGamepadFocusLost() {
- can_vibrate_ = false;
- CancelVibration();
- }
- void Gamepad::OnGamepadEvent(const ui::GamepadEvent& event) {
- DCHECK(delegate_);
- switch (event.type()) {
- case ui::GamepadEventType::BUTTON:
- delegate_->OnButton(event.code(), event.value(), event.timestamp());
- break;
- case ui::GamepadEventType::AXIS:
- delegate_->OnAxis(event.code(), event.value(), event.timestamp());
- break;
- case ui::GamepadEventType::FRAME:
- delegate_->OnFrame(event.timestamp());
- break;
- }
- }
- } // namespace exo
|