La manette Stadia flashée se comporte comme une manette de jeu standard, ce qui signifie que tous ses boutons ne sont pas accessibles à l'aide de l'API Gamepad. Avec WebHID, vous pouvez désormais accéder aux boutons manquants.
Depuis l'arrêt de Stadia, beaucoup craignaient que la manette ne devienne un matériel inutile à la décharge. Heureusement, l'équipe Stadia a décidé de rendre la manette Stadia compatible avec le Bluetooth en fournissant un micrologiciel personnalisé que vous pouvez installer sur votre manette en accédant à la page Mode Bluetooth de Stadia. Votre manette Stadia apparaît alors comme une manette de jeu standard que vous pouvez connecter via un câble USB ou sans fil via Bluetooth. La page Bluetooth de Stadia est fièrement présentée dans la vitrine des API Project Fugu. Elle utilise WebHID et WebUSB, mais ce n'est pas le sujet de cet article. Dans cet article, je vais vous expliquer comment communiquer avec la manette Stadia via WebHID.
Utiliser la manette Stadia comme une manette de jeu standard
Une fois le flashage effectué, la manette apparaît comme une manette de jeu standard pour le système d'exploitation. La capture d'écran suivante montre une disposition courante des boutons et des axes sur une manette de jeu standard. Comme défini dans la spécification de l'API Gamepad, les manettes de jeu standards comportent des boutons numérotés de 0 à 16, soit 17 boutons au total (le pavé directionnel compte pour quatre boutons). Si vous essayez la manette Stadia dans la démonstration de test de la manette de jeu, vous remarquerez qu'elle fonctionne parfaitement.
Toutefois, si vous comptez les boutons de la manette Stadia, vous en trouverez 19. Si vous les essayez systématiquement un par un dans le testeur de manette de jeu, vous vous rendrez compte que les boutons Assistant et Capture ne fonctionnent pas. Même si l'attribut buttons
de la manette de jeu tel que défini dans la spécification Gamepad est ouvert, étant donné que la manette Stadia apparaît comme une manette de jeu standard, seuls les boutons 0 à 16 sont mappés. Vous pouvez toujours utiliser les autres boutons, mais la plupart des jeux ne s'attendront pas à ce qu'ils existent.
WebHID à la rescousse
Grâce à l'API WebHID, vous pouvez communiquer avec les boutons 17 et 18 manquants. Si vous le souhaitez, vous pouvez même obtenir des données sur tous les autres boutons et axes déjà disponibles via l'API Gamepad. La première étape consiste à déterminer comment la manette Stadia se présente au système d'exploitation. Pour ce faire, vous pouvez ouvrir la console des outils pour les développeurs Chrome sur une page aléatoire et demander une liste non filtrée des appareils à partir de l'API WebHID. Vous choisissez ensuite manuellement la manette Stadia pour l'examiner plus en détail. Pour obtenir une liste non filtrée des appareils, il vous suffit de transmettre un tableau d'options filters
vide.
const [device] = await navigator.hid.requestDevice({filters: []});
Dans le sélecteur, l'avant-dernière entrée ressemble à la manette Stadia.
Après avoir sélectionné l'appareil "Manette Stadia rev. A", enregistrez l'objet HIDDevice
résultant dans la console. Les productId
(37888
, soit 0x9400
en hexadécimal) et vendorId
(6353
, soit 0x18d1
en hexadécimal) de la manette Stadia s'affichent. Si vous recherchez vendorID
dans le tableau officiel des ID de fournisseur USB, vous constaterez que 6353
correspond à ce que vous attendez : Google Inc.
.
Vous pouvez également accéder à chrome://device-log/
dans la barre d'URL, appuyer sur le bouton Effacer, brancher votre manette Stadia, puis appuyer sur Actualiser. Vous y trouverez les mêmes informations.
Vous pouvez également utiliser l'outil HID Explorer, qui vous permet d'explorer encore plus en détail les appareils HID connectés à votre ordinateur.
Utilisez ces deux ID, vendorId
et productId
, pour affiner ce qui est affiché dans le sélecteur en filtrant correctement le bon appareil WebHID.
const [stadiaController] = await navigator.hid.requestDevice({filters: [{
vendorId: 6353,
productId: 37888,
}]});
Le bruit de tous les appareils non associés a disparu, et seule la manette Stadia s'affiche.
Ensuite, ouvrez HIDDevice
en appelant la méthode open()
.
await stadiaController.open();
Enregistrez à nouveau HIDDevice
. L'option opened
est définie sur true
.
Une fois l'appareil ouvert, écoutez les événements inputreport
entrants en associant un écouteur d'événements.
stadiaController.addEventListener('inputreport', (e) => {
console.log(e);
});
Lorsque vous appuyez sur le bouton Assistant de la manette et que vous le relâchez, deux événements sont enregistrés dans la console. Vous pouvez les considérer comme des événements "Bouton Assistant enfoncé" et "Bouton Assistant relâché". À première vue, les deux événements semblent identiques, à l'exception de timeStamp
.
La propriété reportId
de l'interface HIDInputReportEvent
renvoie le préfixe d'identification d'un octet pour ce rapport, ou 0
si l'interface HID n'utilise pas d'ID de rapport. Dans ce cas, il s'agit de 3
. Le secret se trouve dans la propriété data
, qui est représentée sous la forme d'un DataView
de taille 10. Un DataView
fournit une interface de bas niveau pour lire et écrire plusieurs types de nombres dans un ArrayBuffer
binaire. Pour obtenir une représentation plus digeste, vous pouvez créer un Uint8Array
à partir de ArrayBuffer
afin de voir les entiers non signés de 8 bits individuels.
const data = new Uint8Array(event.data.buffer);
Lorsque vous enregistrez à nouveau les données d'événement du rapport d'entrée, les choses commencent à avoir plus de sens et les événements "Bouton Assistant enfoncé" et "Bouton Assistant relâché" deviennent compréhensibles. Le premier nombre entier (8
dans les deux événements) semble être lié aux appuis sur les boutons, et le deuxième nombre entier (2
et 0
) semble être lié à l'appui ou non sur le bouton Assistant.
Appuyez sur le bouton Capture au lieu du bouton Assistant. Vous verrez que le deuxième entier passe de 1
lorsque le bouton est enfoncé à 0
lorsqu'il est relâché. Cela vous permet d'écrire un "pilote" très simple qui vous permet d'utiliser les deux boutons manquants.
stadia.addEventListener('inputreport', (event) => {
if (!e.reportId === 3) {
return;
}
const data = new Uint8Array(event.data.buffer);
if (data[0] === 8) {
if (data[1] === 1) {
hidButtons[1].classList.add('highlight');
} else if (data[1] === 2) {
hidButtons[0].classList.add('highlight');
} else if (data[1] === 3) {
hidButtons[0].classList.add('highlight');
hidButtons[1].classList.add('highlight');
} else {
hidButtons[0].classList.remove('highlight');
hidButtons[1].classList.remove('highlight');
}
}
});
En utilisant une approche d'ingénierie inverse comme celle-ci, vous pouvez, bouton par bouton et axe par axe, déterminer comment communiquer avec la manette Stadia avec WebHID. Une fois que vous aurez compris le principe, le reste du travail de mappage des nombres entiers sera presque mécanique.
Il ne manque plus qu'une expérience de connexion fluide, comme celle que vous offre l'API Gamepad. Pour des raisons de sécurité, vous devez toujours passer par l'expérience de sélection initiale une fois pour pouvoir utiliser un appareil WebHID comme la manette Stadia. Toutefois, pour les connexions futures, vous pouvez vous reconnecter aux appareils connus. Pour ce faire, appelez la méthode getDevices()
.
let stadiaController;
const [device] = await navigator.hid.getDevices();
if (device && device.vendorId === 6353 && device.productId === 37888) {
stadiaController = device;
}
Démo
Vous pouvez voir la manette Stadia contrôlée conjointement par l'API Gamepad et l'API WebHID dans une démonstration que j'ai créée. N'oubliez pas de consulter le code source, qui s'appuie sur les extraits de cet article. Pour plus de simplicité, je n'affiche que les boutons A, B, X et Y (contrôlés par l'API Gamepad), ainsi que les boutons Assistant et Capture (contrôlés par l'API WebHID). Sous l'image du contrôleur, vous pouvez voir les données WebHID brutes, ce qui vous permet de vous familiariser avec tous les boutons et axes du contrôleur.
Conclusions
Grâce au nouveau micrologiciel, la manette Stadia peut désormais être utilisée comme une manette de jeu standard avec 17 boutons, ce qui est généralement suffisant pour contrôler les jeux Web courants. Si, pour une raison quelconque, vous avez besoin des données des 19 boutons de la manette, WebHID vous permet d'accéder à des rapports d'entrée de bas niveau que vous pouvez déchiffrer en les analysant un par un. Si vous écrivez un pilote WebHID complet après avoir lu cet article, n'hésitez pas à me contacter. Je serai ravi d'ajouter un lien vers votre projet ici. Bonne utilisation de WebHID !
Remerciements
Cet article a été examiné par François Beaufort.