<!doctype html>
<!--
Tests that a Gamepad API gamepad is or is not returned under different
circumstances.
-->
<html>
<head>
<link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
</head>
<body>
<canvas id="webgl-canvas"></canvas>
<script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
<script src="../resources/webxr_e2e.js"></script>
<script src="../resources/webxr_boilerplate.js"></script>
<script>
// We apparently need to register a listener, otherwise all gamepads are
// always null.
window.addEventListener("gamepadconnected", function(e) {});
let selectCount = 0;
function onSelect() {
selectCount++;
console.log('Got select event number ' + selectCount);
}
function currentImmersiveSession() {
return sessionInfos[sessionTypes.IMMERSIVE].currentSession;
}
function stepSetupListeners() {
currentImmersiveSession().addEventListener('select', onSelect, false);
}
function navigatorGamepadCount() {
let numGamepads = 0;
for (gamepad of navigator.getGamepads()) {
if (gamepad !== null) {
numGamepads++;
}
}
return numGamepads;
}
function inputSourceCount() {
return currentImmersiveSession().inputSources.length;
}
function inputSourceWithGamepadCount() {
let numGamepads = 0;
for (source of currentImmersiveSession().inputSources) {
if (source.gamepad !== null) {
numGamepads++;
}
}
return numGamepads;
}
// Especially on Android, there can be a small delay between when the test
// code sends simulated input and when that input is registered by WebXR.
// These functions return bools instead of asserting so that test code can
// poll on the return values to avoid race conditions.
function inputSourceHasNoGamepad() {
// We don't expect to have attached any non-vr gamepads, and vr
// gamepads shouldn't show up in navigator.getGamepads()
if (navigatorGamepadCount() != 0) {
return false;
}
// There should only be one input source, but there should not be
// enough data to make a gamepad.
if (inputSourceCount() != 1) {
return false;
}
if (inputSourceWithGamepadCount() != 0) {
return false;
}
return true;
}
// Especially on Android, there can be a small delay between when the test
// code sends simulated input and when that input is registered by WebXR.
// These functions return bools instead of asserting so that test code can
// poll on the return values to avoid race conditions.
function isGamepadAsExpected(verificationFunction, index) {
if (index === undefined) {
index = 0;
}
if (index >= inputSourceCount()) {
return false;
}
// We don't expect to have attached any non-vr gamepads, and vr
// gamepads shouldn't show up in navigator.getGamepads()
if (navigatorGamepadCount() != 0) {
return false;
}
if (verificationFunction) {
let gamepad = currentImmersiveSession().inputSources[index].gamepad;
if (gamepad.index !== -1) {
// The spec requires all WebXR Gamepads to have index -1.
return false;
}
if (gamepad.id !== "") {
// The spec requires all WebXR Gamepads to have the empty string for
// their ID. Related information should go on the XRInputSource
// profiles array instead.
return false;
}
if (!verificationFunction(gamepad)) {
return false;
}
}
return true;
}
function isInputSourceAsExpected(verificationFunction, index) {
if (index === undefined) {
index = 0;
}
if (index >= inputSourceCount()) {
return false;
}
if (verificationFunction) {
let source = currentImmersiveSession().inputSources[index];
if (!verificationFunction(source)) {
return false;
}
}
return true;
}
function isMappingEqualTo(expected_mapping, index) {
let verificationFunction = function(gamepad) {
return gamepad.mapping == expected_mapping;
}
return isGamepadAsExpected(verificationFunction, index);
}
function isButtonCountEqualTo(expected_count, index) {
let verificationFunction = function(gamepad) {
return gamepad.buttons.length == expected_count;
}
return isGamepadAsExpected(verificationFunction, index);
}
// WebXR only exposes axes in (x, y) pairs because triggers are reported
// as buttons on the Gamepad. The GamepadButton interface has a "value"
// attribute that supports one-dimensional analog input.
function isAxisPairCountEqualTo(expected_count, index) {
let verificationFunction = function(gamepad) {
return gamepad.axes.length == (expected_count * 2);
}
return isGamepadAsExpected(verificationFunction, index);
}
function isButtonPressedEqualTo(button_index, expected_pressed, index) {
let verificationFunction = function(gamepad) {
if (button_index >= gamepad.buttons.length) {
return false;
}
return gamepad.buttons[button_index].pressed == expected_pressed;
}
return isGamepadAsExpected(verificationFunction, index);
}
function isButtonTouchedEqualTo(button_index, expected_touched, index) {
let verificationFunction = function(gamepad) {
if (button_index >= gamepad.buttons.length) {
return false;
}
return gamepad.buttons[button_index].touched == expected_touched;
}
return isGamepadAsExpected(verificationFunction, index);
}
function areAxesValuesEqualTo(axes_pair_index, x_axis_value, y_axis_value, index) {
let verificationFunction = function(gamepad) {
let epsilon = 0.001;
let x_index = (2 * axes_pair_index);
let y_index = (2 * axes_pair_index) + 1;
if (y_index >= gamepad.axes.length) {
return false;
}
function approxEquals(a, b) {
return Math.abs(a - b) < epsilon;
}
if (!approxEquals(gamepad.axes[x_index], x_axis_value)) {
return false;
}
if (!approxEquals(gamepad.axes[y_index], y_axis_value)) {
return false;
}
return true;
}
return isGamepadAsExpected(verificationFunction, index);
}
function isProfileCountEqualTo(expected_count, index) {
let verificationFunction = function(source) {
return source.profiles.length == expected_count;
}
return isInputSourceAsExpected(verificationFunction, index);
}
function isProfileEqualTo(profile_index, expected_string, index) {
let verificationFunction = function(source) {
if (profile_index >= source.profiles.length) {
return false;
}
return source.profiles[profile_index] === expected_string;
}
return isInputSourceAsExpected(verificationFunction, index);
}
</script>
</body>
</html>