blob: 2d504ec25788d2621a99f94bb9765b0d08623193 [file] [log] [blame]
// Copyright 2019 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 "device/vr/util/gamepad_builder.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "device/vr/util/copy_to_ustring.h"
namespace device {
namespace {
GamepadHand MojoToGamepadHandedness(device::mojom::XRHandedness handedness) {
switch (handedness) {
case device::mojom::XRHandedness::LEFT:
return GamepadHand::kLeft;
case device::mojom::XRHandedness::RIGHT:
return GamepadHand::kRight;
case device::mojom::XRHandedness::NONE:
return GamepadHand::kNone;
}
NOTREACHED();
}
// TODO(crbug.com/955809): Once Gamepad uses an enum this method can be removed.
std::string GamepadMappingToString(GamepadBuilder::GamepadMapping mapping) {
switch (mapping) {
case GamepadBuilder::GamepadMapping::kNone:
return "";
break;
case GamepadBuilder::GamepadMapping::kStandard:
return "standard";
break;
case GamepadBuilder::GamepadMapping::kXRStandard:
return "xr-standard";
break;
}
NOTREACHED();
}
} // anonymous namespace
GamepadBuilder::GamepadBuilder(const std::string& gamepad_id,
GamepadMapping mapping,
device::mojom::XRHandedness handedness)
: mapping_(mapping) {
DCHECK_LT(gamepad_id.size(), Gamepad::kIdLengthCap);
auto mapping_str = GamepadMappingToString(mapping);
DCHECK_LT(mapping_str.size(), Gamepad::kMappingLengthCap);
gamepad_.connected = true;
gamepad_.timestamp = base::TimeTicks::Now().since_origin().InMicroseconds();
gamepad_.hand = MojoToGamepadHandedness(handedness);
CopyToUString(base::UTF8ToUTF16(gamepad_id), gamepad_.id,
Gamepad::kIdLengthCap);
CopyToUString(base::UTF8ToUTF16(mapping_str), gamepad_.mapping,
Gamepad::kMappingLengthCap);
}
GamepadBuilder::~GamepadBuilder() = default;
bool GamepadBuilder::IsValid() const {
switch (mapping_) {
case GamepadMapping::kXRStandard:
// In order to satisfy the XRStandard mapping at least two buttons and one
// set of axes need to have been added.
return gamepad_.axes_length >= 2 && gamepad_.buttons_length >= 2;
case GamepadMapping::kStandard:
case GamepadMapping::kNone:
// Neither standard requires any buttons to be set, and all other data
// is set in the constructor.
return true;
}
NOTREACHED();
}
base::Optional<Gamepad> GamepadBuilder::GetGamepad() const {
if (IsValid())
return gamepad_;
return base::nullopt;
}
void GamepadBuilder::SetAxisDeadzone(double deadzone) {
DCHECK_GE(deadzone, 0);
axis_deadzone_ = deadzone;
}
void GamepadBuilder::AddButton(const GamepadButton& button) {
DCHECK_LT(gamepad_.buttons_length, Gamepad::kButtonsLengthCap);
gamepad_.buttons[gamepad_.buttons_length++] = button;
}
void GamepadBuilder::AddButton(const ButtonData& data) {
AddButton(GamepadButton(data.pressed, data.touched, data.value));
if (data.has_both_axes)
AddAxes(data);
}
void GamepadBuilder::AddAxis(double value) {
DCHECK_LT(gamepad_.axes_length, Gamepad::kAxesLengthCap);
gamepad_.axes[gamepad_.axes_length++] = ApplyAxisDeadzoneToValue(value);
}
void GamepadBuilder::AddAxes(const ButtonData& data) {
DCHECK(data.has_both_axes);
AddAxis(data.x_axis);
AddAxis(data.y_axis);
}
void GamepadBuilder::AddPlaceholderButton() {
AddButton(GamepadButton());
}
void GamepadBuilder::RemovePlaceholderButton() {
// Since this is a member array, it actually is full of default constructed
// buttons, so all we have to do to remove a button is decrement the length
// variable. However, we should check before we do so that we actually have
// a length and that there's not any data that's been set in the alleged
// placeholder button.
DCHECK_GT(gamepad_.buttons_length, 0u);
GamepadButton button = gamepad_.buttons[gamepad_.buttons_length - 1];
DCHECK(!button.pressed && !button.touched && button.value == 0);
gamepad_.buttons_length--;
}
double GamepadBuilder::ApplyAxisDeadzoneToValue(double value) const {
return std::fabs(value) < axis_deadzone_ ? 0 : value;
}
} // namespace device