Komunikacja z kontrolerem Stadia za pomocą protokołu WebHID

Flashowany 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 zamknięciu Stadia wielu obawiało się, że kontroler trafi na wysypisko jako bezużyteczny sprzęt. Na szczęście zespół Stadia zdecydował się udostępnić niestandardowe oprogramowanie układu, które można wgrać na kontrolerze. Aby to zrobić, otwórz stronę Tryb Bluetooth Stadia. Dzięki temu kontroler Stadia będzie wyglądać jak standardowy gamepad, który można podłączyć za pomocą kabla USB lub bezprzewodowo przez Bluetooth. Strona Stadia Bluetooth, która jest wyróżniona w ramach pokazu interfejsów API projektu Fugu, korzysta z interfejsu WebHID i interfejsu WebUSB, ale nie jest to temat tego artykułu. W tym poście wyjaśnię, jak możesz komunikować się z kontrolerem Stadia za pomocą interfejsu WebHID.

kontroler Stadia jako standardowy kontroler do gier;

Po przeflashowaniu kontroler jest widoczny dla systemu operacyjnego jako standardowy gamepad. Poniżej znajdziesz zrzut ekranu przedstawiający typowy układ przycisków i osi na standardowym kontrolerze. Zgodnie ze specyfikacją Gamepad API standardowe kontrolery mają od 0 do 16 przycisków, czyli łącznie 17 przycisków (krzyżak jest traktowany jako 4 przyciski). Jeśli spróbujesz użyć kontrolera Stadia w demo testera kontrolera, zauważysz, że działa on bez zarzutu.

Schemat standardowego kontrolera z oznaczonymi osiami i przyciskami.

Jeśli jednak policzyć przyciski na kontrolerze Stadia, ich liczba wyniesie 19. Jeśli będziesz je testować jeden po drugim w testerze pada, zauważysz, że przyciski AsystentaNagrywania nie działają. Nawet jeśli atrybut gamepada buttons określony w specyfikacji kontrolera gry jest otwarty, kontroler Stadia jest traktowany jako standardowy gamepad, więc tylko przyciski 0–16 są mapowane. Nadal możesz używać innych przycisków, ale większość gier nie będzie ich rozpoznawać.

WebHID na ratunek

Dzięki interfejsowi WebHID API możesz korzystać z brakujących przycisków 17 i 18. Jeśli chcesz, możesz nawet uzyskać dane o wszystkich innych przyciskach i osiach, które są już dostępne za pomocą interfejsu Gamepad API. Pierwszym krokiem jest sprawdzenie, jak kontroler Stadia zgłasza się systemowi operacyjnemu. Jednym ze sposobów jest otwarcie konsoli Narzędzi deweloperskich w Chrome na dowolnej stronie i wysłanie żądania niefiltrowanej listy urządzeń z interfejsu WebHID API. Następnie ręcznie wybierz kontroler Stadia, który ma zostać poddany dalszej kontroli. Aby uzyskać niefiltrowaną listę urządzeń, prześlij pusty tablicę opcji filters.

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

W selektorze przedostatnia pozycja wygląda jak kontroler Stadia.

Selektor urządzeń w interfejsie WebHID API, który pokazuje niezwiązane urządzenia i kontroler Stadia w przedostatnim miejscu.

Po wybraniu urządzenia „Stadia Controller rev. A” zapisz utworzony obiekt HIDDevice w konsoli. W ten sposób uzyskasz wartości productId (37888 w systemie szesnastkowym) i vendorId (6353 w systemie szesnastkowym) kontrolera Stadia.0x94000x18d1 Jeśli w oficjalnej tabeli identyfikatorów dostawców USB wyszukasz wartość vendorID, zobaczysz, że 6353 odpowiada wartości Google Inc..

Konsola DevTools w Chrome z wynikiem rejestrowania obiektu HIDDevice

Alternatywą dla opisanego powyżej procesu jest przejście na adres chrome://device-log/ na pasku adresu, naciśnięcie przycisku Wyczyść, podłączenie kontrolera Stadia i naciśnięcie Odśwież. Dzięki temu uzyskasz te same informacje.

Interfejs debugowania chrome://device-log zawierający informacje o podłączonym kontrolerze Stadia.

Inną możliwością jest użycie narzędzia HID Explorer, które pozwala uzyskać jeszcze więcej informacji o urządzeniach HID podłączonych do komputera.

Użyj tych dwóch identyfikatorów (vendorIdproductId), aby dostosować to, co jest wyświetlane w selektorze, i poprawnić filtrowanie pod kątem właściwego urządzenia WebHID.

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

Teraz szum z niepowiązanych urządzeń zniknął i widoczny jest tylko kontroler Stadia.

Selektor urządzeń w interfejsie WebHID API, który wyświetla tylko kontroler Stadia.

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

await stadiaController.open();

Zaloguj się ponownie, a flaga HIDDevice zostanie ustawiona na true.opened

Konsolę Chrome DevTools pokazującą dane wyjściowe z rejestrowania obiektu HIDDevice po jego otwarciu.

Na otwartym urządzeniu nasłuchuj przychodzące zdarzenia inputreport, dołączając odbiornik zdarzeń.

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

Gdy naciśniesz i puścisz przycisk Asystent na kontrolerze, w Konsoli zostaną zarejestrowane 2 zdarzenia. Możesz je traktować jako zdarzenia „Asystent – przycisk wciśnięty” i „Asystent – przycisk wciśnięty”. Poza wartością timeStamp te 2 zdarzenia są na pierwszy rzut oka nie do odróżnienia.

Konsolę Narzędzi deweloperskich w Chrome, która pokazuje rejestrowane obiekty HIDInputReportEvent.

Właściwość reportId interfejsu HIDInputReportEvent zwraca 1-bajtowy prefiks identyfikacyjny tego raportu lub 0, jeśli interfejs HID nie używa identyfikatorów raportów. W tym przypadku jest to 3. Tajemnica znajduje się w właściwości data, która jest reprezentowana przez DataView o rozmiarze 10. DataView udostępnia interfejs niskiego poziomu do odczytu i zapisu różnych typów liczb w postaci binarnej ArrayBuffer. Aby uzyskać bardziej przystępną postać, możesz utworzyć z ArrayBuffer Uint8Array, aby wyświetlić poszczególne 8-bitowe liczby całkowite bez znaku.

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

Gdy ponownie zarejestrujesz dane zdarzenia raportu wejściowego, wszystko stanie się bardziej zrozumiałe, a zdarzenia „przycisk Asystenta wciśnięty” i „przycisk Asystenta wciśnięty” staną się czytelniejsze. Pierwsza liczba całkowita (8 w obu zdarzeniach) wydaje się być powiązana z naciśnięciem przycisku, a druga liczba całkowita (20) wydaje się być powiązana z tym, czy przycisk Asystenta został naciśnięty, czy nie.

Konsole Narzędzi deweloperskich Chrome pokazująca obiekty Uint8Array rejestrowane w przypadku każdego zdarzenia HIDInputReportEvent.

Naciśnij przycisk Zapisywanie zamiast przycisku Asystent. Zobaczysz, że drugi zapisany numer zmienia się z 1 na 0. Dzięki temu możesz napisać bardzo prosty „sterownik”, który umożliwi korzystanie z 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 temu możesz ustalić, jak komunikować się z kontrolerem Stadia za pomocą WebHID, przycisk po przycisku i oś po osi. Gdy już się tego nauczysz, reszta będzie już tylko rutynową pracą polegającą na mapowaniu liczb całkowitych.

Jedyną rzeczą, która jest teraz nieobecna, jest płynne połączenie, które zapewnia interfejs Gamepad API. Z powodów bezpieczeństwa musisz zawsze przejść przez początkowy selektor, aby korzystać z urządzenia WebHID, takiego jak kontroler Stadia. W przypadku kolejnych połączeń możesz jednak 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;
}

Prezentacja

demo, które stworzyłem, możesz zobaczyć kontroler Stadia sterowany wspólnie przez interfejs Gamepad API i WebHID API. Zapoznaj się z kodem źródłowym, który opiera się na fragmentach kodu z tego artykułu. Dla uproszczenia wyświetlam tylko przyciski A, B, XY (sterowane przez interfejs Gamepad API) oraz przyciski AsystentNagrywanie (sterowane przez interfejs WebHID API). Pod obrazem kontrolera możesz zobaczyć nieprzetworzone dane WebHID, dzięki którym możesz poznać wszystkie przyciski i osi kontrolera.

Aplikacja demonstracyjna dostępna pod adresem https://stadia-controller-webhid-gamepad.glitch.me/, która pokazuje, jak przyciski A, B, X i Y są obsługiwane przez interfejs Gamepad API, a przyciski Asystenta i Przechwytywanie – przez interfejs WebHID API.

Podsumowanie

Dzięki nowemu oprogramowaniu układającemu można teraz używać kontrolera Stadia jako standardowego kontrolera do gier z 17 przyciskami, których w większości przypadków wystarcza do sterowania w popularnych grach internetowych. Jeśli z jakiegokolwiek powodu potrzebujesz danych ze wszystkich 19 przycisków kontrolera, WebHID umożliwia Ci dostęp do raportów o wejściu na niskim poziomie, które możesz odszyfrować, odtwarzając je jeden po drugim. Jeśli po przeczytaniu tego artykułu napiszesz kompletny sterownik WebHID, skontaktuj się ze mną, a chętnie podam link do Twojego projektu. Happy WebHIDing!

Podziękowania

Ten artykuł został sprawdzony przez François Beaufort.