[Перевод] Серфинг интернета геймпадом (Javascript)
Сидя за столом, вы используете мышку и клавиатуру, сидя на диване — скорей всего тачпад ноутбука или тачскрин планшета. Возможно, вы даже используете Leap Motion и управляете компьютером с помощью жестов. Как вы уже поняли, существует множество способов серфить интернет и управлять вашим компьютером. Геймпад может быть одним из них.
В этой статье я поделюсь с вами как:
- подключить геймпад к браузеру
- слушать события геймпада
- контролировать фокус на элементах страницы используя геймпад
- сделать фидбек в виде вибрации
Подключайте свой геймпад используя USB или Bluetooth и давайте начнем.
Геймпад API
Геймпад API было добавлено в стандарт HTML 5. API позволяет использовать геймпады в браузере. В комбинации с элементом, это API может быть использовано для создания игр которые поддерживают геймпад. Следовательно, пользователи могут играть в игры используя геймпад прямо в браузере, что очень круто. Но API может использоваться не только для игр. Никто не мешает вам сделать устройство ввода в виде геймпада для совершенно других целей.
Gamepad API хорошо поддерживается, но по-прежнему находится в стадии драфта. Может, что-то изменится, удалится или добавится в будущем.
Подключаем геймпад
Когда геймпад подключается к компьютеру, используя USB или Bluetooth мы можем использоваться два ивента, для того, что бы обрабатывать подключения и отключения:
window.addEventListener('gamepadconnected', function(event) {
// Делаем, что-то на подключение
console.log(event)
});
window.addEventListener('gamepaddisconnected', function(event) {
// Делаем, что-то на отключение
});
Геймпад начнет работать только после того как вы нажмете кнопку (прим. перев. Любую или Start). Дело в том, что это security/privacy браузера. Следовательно, придется продумать интерфейс сообщающий пользователю о необходимости нажать кнопку для начала работы.
События геймпада выглядит следующим образом в консоле:
Раскладка геймпада: кнопки и оси
Как вы можете видеть, в логе события есть куча кнопок (0 — 16) и оси (axes 0 — 3). Но откуда вам знать как из кнопок прячется за номером? Геймпады имеют различные раскладки в зависимости от бренда. По этому следует поискать информацию в интернете. В данном случае мы подключаем геймпад Xbox One и у него такая раскладка:
Слушаем нажатие клавиши
При разработке интерфейсов можно использовать .addEventListener()
для добавления события на нажатие клавиши. В данном случае это сделать не получится, так как кнопки на геймпаде не создают события. И как видно по логу выше, придется проверять поле pressed
в ручную:
const xBoxButtonB = gamepad.buttons[1]
if (xBoxButtonB.pressed) {
doSomethingOnButtonPress();
}
Так как мы хотим делать проверку постоянно, надо завернуть все это в цикл. Например используя requestAnimationFrame
:
const rAF = window.mozRequestAnimationFrame || window.requestAnimationFrame;
window.addEventListener('gamepadconnected', function() {
updateLoop();
});
function updateLoop() {
// проверям состояние кнопки
rAF(updateLoop);
}
Навигация между элементами
Для того, что бы использовать геймпад для навигации по веб страницы, необходимо симулировать клавиатуру. Но для начала необходимо получить все элементы на странице котрые могут быть сфокусированы.
Используя следующий селектор, можно получить все эти элементы:
const focusableElements = document.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
Двигаем фокус программно
Для фокусирования на элементе, мы будем пробегаться в цикле по NodeList
и фокусироваться на текущем элементе используя метод element.focus()
.
В этом примере показывается как можно прыгать фокусом с элемента на элемент:
let current;
function updateLoop() {
const gamepad = navigator.getGamepads()[0]
const gamepadBumperL = gamepad.buttons[4]
const gamepadBumperR = gamepad.buttons[5]
if (gamepadBumperL.pressed) { prevItem(current) }
if (gamepadBumperR.pressed) { nextItem(current) }
setTimeout(() => rAF(updateLoop), 100)
}
function prevItem(index) {
current = (index - 1) % focusableElements.length
focusableElements[current].focus()
}
function nextItem(index) {
current = (index + 1) % focusableElements.length
focusableElements[current].focus()
}
Обратите внимание на использования функции setTimeout
. Она используется для ограничения requestAnimationFrame
в рамках 100 миллисекунд. Без этого, одно нажатие на клавишу может сгенерировать несколько событий геймпада, так как нет привычного нам onClick, а нажать и отпустить клавишу за миллисекунду физически не возможно.
Кликаем по элементам
Кликать по элементам можно используя метод click()
:
clickItem(index) {
focusableElements[index].click();
}
Добавляем фидбек используя вибрацию
Современные геймпады умеют вибрировать. Эти вибрации используются для фидбека пользователю, как правило, в играх. Но так же можно попытаться сделать фидбек от веб элементов на странице.
Геймпады зачастую оснащены двумя электромоторами, мощным и слабым:
Мы можем управлять этими моторами из браузера используя vibrationActuator
.
Для создания вибрации мы можем использовать метод playEffect()
:
gamepad.vibrationActuator.playEffect('dual-rumble', {
startDelay: 0, // Add a delay in milliseconds
duration: 1000, // Total duration in milliseconds
weakMagnitude: 0.5, // intensity (0-1) of the small ERM
strongMagnitude: 1 // intesity (0-1) of the bigger ERM
});
Используя моторы для вибрации, помните, что большому мотору требуется больше времени для разгона. По этому для краткосрочных откликов, лучше использовать маленький мотор.
Заключение
В этом примере мы рассмотрели базовые функции Геймпад API и то как его можно использовать для навигации в интернете.
Код на GitHub и демо можно посмотреть здесь.
Полезные ссылки
html5gamepad.com — инструмент для проверки геймпада
Gamepad API on MDN