| // Copyright 2017 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 "modules/gamepad/GamepadHapticActuator.h" |
| |
| #include "bindings/core/v8/ScriptPromiseResolver.h" |
| #include "modules/gamepad/GamepadDispatcher.h" |
| |
| namespace { |
| |
| using device::mojom::GamepadHapticsResult; |
| using device::mojom::GamepadHapticEffectType; |
| |
| const char kGamepadHapticActuatorTypeVibration[] = "vibration"; |
| const char kGamepadHapticActuatorTypeDualRumble[] = "dual-rumble"; |
| |
| const char kGamepadHapticEffectTypeDualRumble[] = "dual-rumble"; |
| |
| const char kGamepadHapticsResultComplete[] = "complete"; |
| const char kGamepadHapticsResultPreempted[] = "preempted"; |
| const char kGamepadHapticsResultInvalidParameter[] = "invalid-parameter"; |
| const char kGamepadHapticsResultNotSupported[] = "not-supported"; |
| |
| const double kMaxEffectDurationMillis = 5000.0; // 5 seconds |
| |
| GamepadHapticEffectType EffectTypeFromString(const String& type) { |
| if (type == kGamepadHapticEffectTypeDualRumble) |
| return GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble; |
| |
| NOTREACHED(); |
| return GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble; |
| } |
| |
| String ResultToString(GamepadHapticsResult result) { |
| switch (result) { |
| case GamepadHapticsResult::GamepadHapticsResultComplete: |
| return kGamepadHapticsResultComplete; |
| case GamepadHapticsResult::GamepadHapticsResultPreempted: |
| return kGamepadHapticsResultPreempted; |
| case GamepadHapticsResult::GamepadHapticsResultInvalidParameter: |
| return kGamepadHapticsResultInvalidParameter; |
| case GamepadHapticsResult::GamepadHapticsResultNotSupported: |
| return kGamepadHapticsResultNotSupported; |
| default: |
| NOTREACHED(); |
| } |
| return kGamepadHapticsResultNotSupported; |
| } |
| |
| } // namespace |
| |
| namespace blink { |
| |
| // static |
| GamepadHapticActuator* GamepadHapticActuator::Create(int pad_index) { |
| return new GamepadHapticActuator( |
| pad_index, device::GamepadHapticActuatorType::kDualRumble); |
| } |
| |
| GamepadHapticActuator::GamepadHapticActuator( |
| int pad_index, |
| device::GamepadHapticActuatorType type) |
| : pad_index_(pad_index) { |
| SetType(type); |
| } |
| |
| GamepadHapticActuator::~GamepadHapticActuator() = default; |
| |
| void GamepadHapticActuator::SetType(device::GamepadHapticActuatorType type) { |
| switch (type) { |
| case device::GamepadHapticActuatorType::kVibration: |
| type_ = kGamepadHapticActuatorTypeVibration; |
| break; |
| case device::GamepadHapticActuatorType::kDualRumble: |
| type_ = kGamepadHapticActuatorTypeDualRumble; |
| break; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| ScriptPromise GamepadHapticActuator::playEffect( |
| ScriptState* script_state, |
| const String& type, |
| const GamepadEffectParameters& params) { |
| ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
| |
| if (params.duration() < 0.0 || params.startDelay() < 0.0 || |
| params.strongMagnitude() < 0.0 || params.strongMagnitude() > 1.0 || |
| params.weakMagnitude() < 0.0 || params.weakMagnitude() > 1.0) { |
| ScriptPromise promise = resolver->Promise(); |
| resolver->Resolve(kGamepadHapticsResultInvalidParameter); |
| return promise; |
| } |
| |
| // Limit the total effect duration. |
| double effect_duration = params.duration() + params.startDelay(); |
| if (effect_duration > kMaxEffectDurationMillis) { |
| ScriptPromise promise = resolver->Promise(); |
| resolver->Resolve(kGamepadHapticsResultInvalidParameter); |
| return promise; |
| } |
| |
| auto callback = ConvertToBaseCallback( |
| WTF::Bind(&GamepadHapticActuator::OnPlayEffectCompleted, |
| WrapPersistent(this), WrapPersistent(resolver))); |
| |
| GamepadDispatcher::Instance().PlayVibrationEffectOnce( |
| pad_index_, EffectTypeFromString(type), |
| device::mojom::blink::GamepadEffectParameters::New( |
| params.duration(), params.startDelay(), params.strongMagnitude(), |
| params.weakMagnitude()), |
| std::move(callback)); |
| |
| return resolver->Promise(); |
| } |
| |
| void GamepadHapticActuator::OnPlayEffectCompleted( |
| ScriptPromiseResolver* resolver, |
| device::mojom::GamepadHapticsResult result) { |
| if (result == GamepadHapticsResult::GamepadHapticsResultError) { |
| resolver->Reject(); |
| return; |
| } |
| resolver->Resolve(ResultToString(result)); |
| } |
| |
| ScriptPromise GamepadHapticActuator::reset(ScriptState* script_state) { |
| ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
| |
| auto callback = ConvertToBaseCallback( |
| WTF::Bind(&GamepadHapticActuator::OnResetCompleted, WrapPersistent(this), |
| WrapPersistent(resolver))); |
| |
| GamepadDispatcher::Instance().ResetVibrationActuator(pad_index_, |
| std::move(callback)); |
| |
| return resolver->Promise(); |
| } |
| |
| void GamepadHapticActuator::OnResetCompleted( |
| ScriptPromiseResolver* resolver, |
| device::mojom::GamepadHapticsResult result) { |
| if (result == GamepadHapticsResult::GamepadHapticsResultError) { |
| resolver->Reject(); |
| return; |
| } |
| resolver->Resolve(ResultToString(result)); |
| } |
| |
| void GamepadHapticActuator::Trace(blink::Visitor* visitor) { |
| ScriptWrappable::Trace(visitor); |
| } |
| |
| } // namespace blink |