De geflashte Stadia-controller gedraagt zich als een standaard gamepad, wat betekent dat niet alle knoppen toegankelijk zijn via de Gamepad API. Met WebHID heeft u nu toegang tot de ontbrekende knoppen.
Sinds Stadia werd gesloten, vreesden velen dat de controller als een nutteloos stuk hardware op de vuilstort zou belanden. Gelukkig heeft het Stadia-team besloten om in plaats daarvan de Stadia-controller te openen door aangepaste firmware aan te bieden die je op je controller kunt flashen door naar de Stadia Bluetooth- moduspagina te gaan. Hierdoor verschijnt je Stadia-controller als een standaard gamepad waar je via een USB-kabel of draadloos via Bluetooth verbinding mee kunt maken. De Stadia Bluetooth-pagina, die met trots te zien is in de Project Fugu API Showcase , gebruikt WebHID en WebUSB , maar dit is niet het onderwerp van dit artikel. In dit bericht wil ik uitleggen hoe je via WebHID met de Stadia-controller kunt praten.
De Stadia-controller als standaard gamepad
Na het flashen verschijnt de controller als een standaard gamepad voor het besturingssysteem. Zie de volgende schermafbeelding voor een algemene opstelling van knoppen en assen op een standaard gamepad. Zoals gedefinieerd in de Gamepad API- specificatie, hebben standaard gamepads knoppen van 0 tot 16, dus 17 in totaal (de d-pad telt als vier knoppen). Als je de Stadia-controller op de gamepad-testdemo uitprobeert, zul je merken dat deze als een tierelier werkt.
Als je echter de knoppen op de Stadia-controller meetelt, zijn het er 19. Als je ze systematisch één voor één probeert in de gamepad-tester, zul je merken dat de Assistant- en de Capture- knoppen niet werken. Zelfs als het kenmerk van de buttons
zoals gedefinieerd in de Gamepad-specificatie, een open einde heeft, worden alleen de knoppen 0–16 toegewezen, aangezien de Stadia-controller als een standaard gamepad verschijnt. Je kunt nog steeds de andere knoppen gebruiken, maar de meeste games verwachten niet dat ze bestaan.
WebHID schiet te hulp
Dankzij de WebHID API kun je praten met de ontbrekende knoppen 17 en 18. En als je echt wilt, kun je zelfs gegevens krijgen over alle andere knoppen en assen die al beschikbaar zijn via de Gamepad API. De eerste stap is uitzoeken hoe de Stadia-controller zichzelf rapporteert aan het besturingssysteem. Eén manier om dit te doen is door de Chrome DevTools Console op een willekeurige pagina te openen en een ongefilterde lijst met apparaten op te vragen bij de WebHID API. Vervolgens kies je handmatig de Stadia-controller voor verdere inspectie. Krijg een ongefilterde lijst met apparaten door simpelweg een lege array met filters
door te geven.
const [device] = await navigator.hid.requestDevice({filters: []});
In de kiezer lijkt de voorlaatste vermelding op de Stadia-controller.
Nadat je het apparaat 'Stadia Controller rev. A' hebt geselecteerd, log je het resulterende HIDDevice
object in de console. Dit onthult de productId
van de Stadia-controller ( 37888
, wat 0x9400
is in hex) en vendorId
( 6353
, wat 0x18d1
is in hex). Als u de vendorID
opzoekt in de officiële USB-vendor ID-tabel , ziet u dat 6353
overeenkomt met wat u zou verwachten: Google Inc.
Een alternatief voor de hierboven beschreven procedure is navigeren naar chrome://device-log/
in de URL-balk, op de knop Wissen drukken, je Stadia-controller aansluiten en vervolgens op Vernieuwen drukken. Hierdoor krijgt u dezelfde informatie.
Nog een ander alternatief is het gebruik van de HID Explorer- tool waarmee u nog meer details kunt verkennen van de HID-apparaten die op uw computer zijn aangesloten.
Gebruik deze twee ID's, de vendorId
en de productId
, om te verfijnen wat er in de kiezer wordt weergegeven door nu correct te filteren op het juiste WebHID-apparaat.
const [stadiaController] = await navigator.hid.requestDevice({filters: [{
vendorId: 6353,
productId: 37888,
}]});
Nu is het geluid van alle niet-gerelateerde apparaten verdwenen en verschijnt alleen de Stadia-controller.
Open vervolgens het HIDDevice
door de methode open()
aan te roepen.
await stadiaController.open();
Log het HIDDevice
opnieuw in en de opened
vlag wordt ingesteld op true
.
Terwijl het apparaat open is, luistert u naar binnenkomende inputreport
gebeurtenissen door een gebeurtenislistener aan te sluiten.
stadiaController.addEventListener('inputreport', (e) => {
console.log(e);
});
Wanneer u de Assistent- knop op de controller indrukt en loslaat, worden er twee gebeurtenissen in de console geregistreerd. Je kunt ze beschouwen als de gebeurtenissen ' Assistent- knop omlaag' en ' Assistent -knop omhoog'. Afgezien van de timeStamp
lijken de twee gebeurtenissen op het eerste gezicht niet van elkaar te onderscheiden.
De eigenschap reportId
van de HIDInputReportEvent
interface retourneert het identificatievoorvoegsel van één byte voor dit rapport, of 0
als de HID-interface geen rapport-ID's gebruikt. In dit geval is dat 3
. Het geheim zit in de data
eigenschap , die wordt weergegeven als een DataView
van grootte 10. Een DataView
biedt een interface op laag niveau voor het lezen en schrijven van meerdere getaltypen in een binaire ArrayBuffer
. De manier om iets beter verteerbaars uit deze representatie te halen, is door een Uint8Array
te maken van de ArrayBuffer
, zodat je de individuele 8-bit gehele getallen zonder teken kunt zien.
const data = new Uint8Array(event.data.buffer);
Wanneer u vervolgens de gebeurtenisgegevens van het invoerrapport opnieuw registreert, worden de zaken logischer en beginnen de gebeurtenissen " Assistent -knop omlaag" en " Assistent- knop omhoog" ontcijferbaar te worden. Het eerste gehele getal ( 8
in beide gevallen) lijkt verband te houden met het indrukken van knoppen, en het tweede gehele getal ( 2
en 0
) lijkt verband te houden met het feit of de Assistent- knop wordt ingedrukt of niet.
Druk op de Capture- knop in plaats van de Assistent -knop en je zult zien dat het tweede gehele getal verandert van 1
wanneer de knop wordt ingedrukt naar 0
wanneer deze wordt losgelaten. Hiermee kunt u een zeer eenvoudige "driver" schrijven waarmee u gebruik kunt maken van de ontbrekende twee knoppen.
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');
}
}
});
Met behulp van een dergelijke reverse-engineering-aanpak kun je knop voor knop en as voor as uitzoeken hoe je met WebHID met de Stadia-controller kunt praten. Als je het eenmaal onder de knie hebt, is de rest bijna mechanisch werk voor het in kaart brengen van gehele getallen.
Het enige dat nu ontbreekt, is de soepele verbindingservaring die de Gamepad API je biedt. Hoewel je om veiligheidsredenen altijd één keer de initiële picker-ervaring moet doorlopen om met een WebHID-apparaat zoals de Stadia-controller te kunnen werken, kun je voor toekomstige verbindingen opnieuw verbinding maken met bekende apparaten. Doe dat door de methode getDevices()
aan te roepen.
let stadiaController;
const [device] = await navigator.hid.getDevices();
if (device && device.vendorId === 6353 && device.productId === 37888) {
stadiaController = device;
}
Demo
Je kunt de Stadia-controller zien die gezamenlijk wordt bestuurd door de Gamepad API en de WebHID API in een demo die ik heb gebouwd. Zorg ervoor dat u de broncode bekijkt, die voortbouwt op de fragmenten uit dit artikel. Voor de eenvoud geef ik alleen de knoppen A , B , X en Y weer (bestuurd door de Gamepad API), en de Assistant- en Capture- knoppen (bestuurd door de WebHID API). Onder de controllerafbeelding ziet u de onbewerkte WebHID-gegevens, zodat u een idee krijgt van alle knoppen en assen op de controller.
Conclusies
Dankzij de nieuwe firmware is de Stadia-controller nu bruikbaar als een standaard gamepad met 17 knoppen, wat in de meeste gevallen ruim voldoende is om gangbare webgames te besturen. Als u, om welke reden dan ook, gegevens nodig heeft van alle 19 knoppen op de controller, kunt u met WebHID toegang krijgen tot invoerrapporten op laag niveau die u kunt ontcijferen door ze een voor een te reverse-engineeren. Als u na het lezen van dit artikel een compleet WebHID-stuurprogramma schrijft, neem dan zeker contact met mij op, dan zal ik uw project hier graag linken. Veel plezier met WebHIDing!
Dankbetuigingen
Dit artikel werd beoordeeld door François Beaufort .