Komunikacja z kontrolerem Stadia za pomocą protokołu WebHID

Ten kontroler Stadia działa jak standardowy pad do gier, co oznacza, że nie wszystkie jego przyciski są dostępne za pomocą interfejsu Gamepad API. Dzięki WebHID możesz teraz uzyskać dostęp do brakujących przycisków.

Po wyłączeniu usługi Stadia wielu obawiało się, że kontroler wyjdzie na wysypisko jako bezużyteczny sprzęt. Na szczęście zespół Stadia postanowił otworzyć kontroler Stadia, udostępniając własne oprogramowanie układowe, które możesz na nim załadować. Aby to zrobić, przejdź na stronę Tryb Bluetooth w Stadia. Dzięki temu kontroler Stadia wygląda jak standardowy pad do gier, z którym możesz połączyć się kablem USB lub bezprzewodowo przez Bluetooth. Strona Stadia Bluetooth, która z dumą jest w ramach Showcase w projekcie Fugu API, korzysta z WebHID i WebUSB, ale nie jest to temat tego artykułu. W tym poście wyjaśnię, jak komunikować się z kontrolerem Stadia przez WebHID.

kontroler Stadia jako standardowy pad do gier,

Po zaktualizowaniu kontroler wyświetla się w systemie operacyjnym jako standardowy pad do gier. Na zrzucie ekranu poniżej znajdziesz wspólny układ przycisku i osi na standardowym padzie do gier. Zgodnie ze specyfikacją Gamepad API standardowe pady do gier mają przyciski z zakresu od 0 do 16, więc w sumie jest ich 17 (pady liczone są jako 4 przyciski). Testując kontroler Stadia w wersji demonstracyjnej kontrolera gier pada, zauważysz, że działa on jak zaklęcie.

Schemat standardowego pada do gier z oznaczonymi różnymi osiami i przyciskami.

Jeśli jednak policzysz przyciski na kontrolerze Stadia, będzie ich 19. Jeśli będziesz systematycznie je testować po kolei na kontrolerze do gier, zauważysz, że Asystent i przyciski przechwytywania nie działają. Nawet jeśli atrybut buttons pada do gier określony w specyfikacji pada do gier jest otwarty, ponieważ kontroler Stadia jest widoczny jako standardowy pad do gier, tylko przyciski 0–16 są mapowane. Nadal możesz używać innych przycisków, ale większość gier się nie spodziewa, że one będą dostępne.

WebHID na ratunek

Dzięki interfejsowi WebHID API możesz rozmawiać z brakującymi przyciskami 17 i 18. Jeśli chcesz, możesz też pobrać dane o wszystkich innych przyciskach i osiach dostępnych już w interfejsie Gamepad API. Pierwszym krokiem jest sprawdzenie, w jaki sposób kontroler Stadia zgłasza się do systemu operacyjnego. Możesz na przykład otworzyć konsolę Chrome DevTools na dowolnej losowej stronie i poprosić o niefiltrowaną listę urządzeń z interfejsu WebHID API. Następnie ręcznie wybierz kontroler Stadia do dalszej kontroli. Aby uzyskać niefiltrowaną listę urządzeń, prześlij pustą tablicę opcji filters.

const [device] = await navigator.hid.requestDevice({filters: []});

Przedostatni wpis w selektorze wygląda jak kontroler Stadia.

Selektor urządzeń WebHID API z niepowiązanymi urządzeniami i kontrolerem Stadia w przedostatniej pozycji.

Po wybraniu urządzenia „Kontroler Stadia w wersji A” zapisz w konsoli wynikowy obiekt HIDDevice. Pojawi się wtedy pole productId kontrolera Stadia (37888, czyli 0x9400 w systemie szesnastkowym) i vendorId (6353, czyli 0x18d1 w wartości szesnastkowej). W oficjalnej tabeli identyfikatorów dostawcy USB zobaczysz, że 6353 wskazuje, że Google Inc. odpowiada oczekiwanemu numerowi vendorID.

Konsola Narzędzi deweloperskich w Chrome: dane wyjściowe logowania obiektu HIDDevice.

Zamiast tego możesz też przejść do chrome://device-log/ na pasku adresu URL, nacisnąć przycisk Wyczyść, podłączyć kontroler Stadia i nacisnąć Odśwież. Dzięki temu otrzymasz te same informacje.

Interfejs debugowania chrome://device-log z informacjami o podłączonym kontrolerze Stadia.

Kolejną alternatywą jest korzystanie z narzędzia HID Explorer, które pozwala poznać jeszcze więcej szczegółów urządzeń HID podłączonych do Twojego komputera.

Korzystając z tych 2 identyfikatorów, vendorId i productId, możesz zawęzić informacje wyświetlane w selektorze dzięki prawidłowemu filtrowaniu danych pod kątem odpowiedniego urządzenia WebHID.

const [stadiaController] = await navigator.hid.requestDevice({filters: [{
  vendorId: 6353,
  productId: 37888,
}]});

Szum ze wszystkich niepowiązanych urządzeń znika i pojawia się tylko kontroler Stadia.

Selektor urządzeń WebHID API z widocznym tylko kontrolerem Stadia.

Następnie otwórz plik HIDDevice, wywołując metodę open().

await stadiaController.open();

Zarejestruj ponownie parametr HIDDevice, a flaga opened będzie ustawiona na true.

Konsola Narzędzi deweloperskich w Chrome: dane wyjściowe rejestrowania obiektu HIDDevice po jego otwarciu.

Gdy urządzenie jest otwarte, dołącz detektor zdarzeń, aby nasłuchiwać przychodzących zdarzeń inputreport.

stadiaController.addEventListener('inputreport', (e) => {
  console.log(e);
});

Gdy naciśniesz i puścisz przycisk Asystenta na kontrolerze, w konsoli zostaną zarejestrowane 2 zdarzenia. Możesz je opisać jako zdarzenia związane z „przyciskiem w dół” Asystenta lub przy użyciu przycisku „Asystent”. Poza timeStamp na pierwszy rzut oka nie można odróżnić tych 2 zdarzeń.

Konsola Narzędzi deweloperskich w Chrome pokazująca rejestrowane obiekty HIDInputReportEvent.

Właściwość reportId interfejsu HIDInputReportEvent zwraca jednobajtowy prefiks identyfikatora raportu lub 0, jeśli interfejs HID nie korzysta z identyfikatorów raportów. W tym przypadku jest to 3. Obiekt tajny znajduje się w właściwości data, która jest reprezentowana jako DataView o rozmiarze 10. DataView to niskopoziomowy interfejs do odczytu i zapisywania wielu typów liczb w postaci binarnej ArrayBuffer. Żeby uzyskać przystępniejszy obraz tej reprezentacji, możesz utworzyć z parametru ArrayBuffer Uint8Array. Dzięki temu będziesz widzieć poszczególne 8-bitowe liczby całkowite bez znaku.

const data = new Uint8Array(event.data.buffer);

Gdy później ponownie zapiszesz dane zdarzeń z raportu, wszystko nabiera sensu, a zdarzenia „Asystentw dół” i „AsystentPrzycisk w górę” stają się bardziej czytelne. Pierwsza liczba całkowita (8 w obu zdarzeniach) wydaje się być związana z naciśnięciami przycisków, a druga (2 i 0) – z tym, czy został naciśnięty przycisk Asystenta.

Konsola Narzędzi deweloperskich w Chrome pokazująca logowanie obiektów Uint8Array dla każdego zdarzenia HIDInputReportEvent.

Zamiast przycisku Asystent naciśnij przycisk Przechwyć. Po naciśnięciu przycisku zobaczysz, że druga liczba całkowita zmieni się z 1 na 0. W ten sposób możesz napisać bardzo prosty „sterownik”, który umożliwi wykorzystanie brakujących 2 przycisków.

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');
    }
  }
});

Dzięki takiej analizie wstecznej możesz ustalić, jak rozmawiać z kontrolerem Stadia za pomocą WebHID, za pomocą przycisków i osi po osi. Gdy już opanujesz, reszta jest niemal mechanicznym mapowaniem liczb całkowitych.

Jedyną rzeczą, której brakuje, jest bezproblemowe nawiązywanie połączeń, jakie zapewnia interfejs Gamepad API. Ze względów bezpieczeństwa, aby współpracować z urządzeniem WebHID, takim jak kontroler Stadia, w przypadku przyszłych połączeń możesz zawsze ponownie połączyć się ze znanymi urządzeniami. Aby to zrobić, wywołaj metodę getDevices().

let stadiaController;
const [device] = await navigator.hid.getDevices();
if (device && device.vendorId === 6353 && device.productId === 37888) {
  stadiaController = device;
}

Pokaz

W utworzonej przeze mnie prezentacji możesz zobaczyć kontroler Stadia, którym wspólnie steruje się interfejs Gamepad API i interfejs WebHID API. Zobacz kod źródłowy, który powstał na podstawie fragmentów tego artykułu. Dla uproszczenia wyświetlam tylko przyciski A, B, X i Y (sterowane przez interfejs Gamepad API) oraz przyciski Asystent i Przechwytywanie (sterowane przez interfejs WebHID API). Pod obrazem kontrolera widoczne są nieprzetworzone dane WebHID, dzięki czemu możesz się zorientować w działaniu wszystkich przycisków i osi na kontrolerze.

Aplikacja demonstracyjna dostępna na https://stadia-controller-webhid-gamepad.glitch.me/ z widocznymi przyciskami A, B, X i Y sterowanymi przez interfejs Gamepad API oraz przyciskami Asystenta i przechwytywania ekranu sterowanymi przez interfejs API WebHID.

Podsumowanie

Dzięki nowemu oprogramowaniu kontroler Stadia może być używany jako standardowy pad do gier z 17 przyciskami. W większości przypadków to znacznie więcej, aby sterować popularnymi grami internetowymi. Jeśli z jakiegoś powodu potrzebujesz danych ze wszystkich 19 przycisków na kontrolerze, WebHID umożliwia dostęp do raportów wejściowych niskiego poziomu, które możesz rozszyfrować, analizując wstecznie każdy z nich. Jeśli po przeczytaniu tego artykułu napiszesz pełny sterownik WebHID, skontaktuj się ze mną, a chętnie połączę Twój projekt tutaj. Powodzenia!

Podziękowania

Autor artykułu: François Beaufort.