#include "device/vr/util/gamepad_builder.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
namespace device {
namespace {
constexpr double kThumbstickDeadzone = 0.16;
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();
}
}
GamepadBuilder::GamepadBuilder(const std::string& gamepad_id,
GamepadMapping mapping,
device::mojom::XRHandedness handedness) {
DCHECK_LT(gamepad_id.size(), Gamepad::kIdLengthCap);
gamepad_.connected = true;
gamepad_.timestamp = base::TimeTicks::Now().since_origin().InMicroseconds();
gamepad_.mapping = mapping;
gamepad_.hand = MojoToGamepadHandedness(handedness);
gamepad_.SetID(base::UTF8ToUTF16(gamepad_id));
}
GamepadBuilder::~GamepadBuilder() = default;
bool GamepadBuilder::IsValid() const {
switch (GetMapping()) {
case GamepadMapping::kXrStandard:
return gamepad_.buttons_length > 0;
case GamepadMapping::kStandard:
case GamepadMapping::kNone:
return true;
}
NOTREACHED();
}
std::optional<Gamepad> GamepadBuilder::GetGamepad() {
if (IsValid())
return gamepad_;
return std::nullopt;
}
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.type != ButtonData::Type::kButton)
AddAxes(data);
}
void GamepadBuilder::AddAxis(double value, double deadzone) {
DCHECK_LT(gamepad_.axes_length, Gamepad::kAxesLengthCap);
gamepad_.axes[gamepad_.axes_length++] =
std::fabs(value) < deadzone ? 0.0 : value;
}
void GamepadBuilder::AddAxes(const ButtonData& data) {
DCHECK_NE(data.type, ButtonData::Type::kButton);
if (data.type == ButtonData::Type::kTouchpad && !data.touched) {
AddPlaceholderAxes();
return;
}
const double deadzone =
data.type == ButtonData::Type::kThumbstick ? kThumbstickDeadzone : 0.0;
AddAxis(data.x_axis, deadzone);
AddAxis(data.y_axis, deadzone);
}
void GamepadBuilder::AddPlaceholderButton() {
AddButton(GamepadButton());
}
void GamepadBuilder::RemovePlaceholderButton() {
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--;
}
void GamepadBuilder::AddPlaceholderAxes() {
AddAxis(0.0);
AddAxis(0.0);
}
}