Berbicara dengan pengontrol Stadia dengan WebHID

Pengontrol Stadia yang di-flash berperilaku seperti gamepad standar, yang berarti tidak semua tombolnya dapat diakses menggunakan Gamepad API. Dengan WebHID, Anda kini dapat mengakses tombol yang hilang.

Sejak Stadia ditutup, banyak orang khawatir bahwa pengontrol akan berakhir sebagai perangkat keras yang tidak berguna di tempat pembuangan sampah. Untungnya, tim Stadia telah memutuskan untuk membuka pengontrol Stadia dengan menyediakan firmware kustom yang dapat Anda flash di pengontrol dengan membuka halaman mode Bluetooth Stadia. Hal ini membuat pengontrol Stadia Anda muncul sebagai gamepad standar yang dapat Anda hubungkan melalui kabel USB atau secara nirkabel melalui Bluetooth. Dengan bangga ditampilkan di Project Fugu API Showcase, halaman Bluetooth Stadia sendiri menggunakan WebHID dan WebUSB, tetapi bukan itu yang dibahas dalam artikel ini. Dalam postingan ini, saya ingin menjelaskan cara Anda dapat berbicara dengan pengontrol Stadia melalui WebHID.

Pengontrol Stadia sebagai gamepad standar

Setelah flashing, pengontrol akan muncul sebagai gamepad standar di sistem operasi. Lihat screenshot berikut untuk tata letak tombol dan sumbu umum pada gamepad standar. Seperti yang ditentukan dalam spesifikasi Gamepad API, gamepad standar memiliki tombol dari 0 hingga 16, jadi total 17 tombol (d-pad dihitung sebagai empat tombol). Jika Anda mencoba pengontrol Stadia di demo penguji gamepad, Anda akan melihat bahwa pengontrol tersebut berfungsi dengan baik.

Skema gamepad standar dengan berbagai sumbu dan tombol yang diberi label.

Namun, jika Anda menghitung tombol di pengontrol Stadia, ada 19 tombol. Jika Anda mencobanya satu per satu secara sistematis di penguji gamepad, Anda akan menyadari bahwa tombol Asisten dan Ambil Gambar tidak berfungsi. Meskipun atribut buttons gamepad seperti yang ditentukan dalam spesifikasi Gamepad bersifat terbuka, karena pengontrol Stadia muncul sebagai gamepad standar, hanya tombol 0–16 yang dipetakan. Anda tetap dapat menggunakan tombol lainnya, tetapi sebagian besar game tidak akan menganggapnya ada.

WebHID hadir untuk membantu

Berkat WebHID API, Anda dapat berinteraksi dengan tombol 17 dan 18 yang hilang. Jika Anda benar-benar ingin, Anda bahkan bisa mendapatkan data tentang semua tombol dan sumbu lain yang sudah tersedia melalui Gamepad API. Langkah pertama adalah mencari tahu cara pengontrol Stadia melaporkan dirinya ke sistem operasi. Salah satu caranya adalah dengan membuka Konsol Chrome DevTools di halaman acak, dan meminta daftar perangkat yang tidak difilter dari WebHID API. Kemudian, Anda memilih pengontrol Stadia secara manual untuk pemeriksaan lebih lanjut. Dapatkan daftar perangkat yang tidak difilter hanya dengan meneruskan array opsi filters yang kosong.

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

Di pemilih, entri kedua dari terakhir terlihat seperti pengontrol Stadia.

Pemilih perangkat WebHID API menampilkan beberapa perangkat yang tidak terkait, dan pengontrol Stadia di posisi kedua dari terakhir.

Setelah memilih perangkat "Stadia Controller rev. A", catat objek HIDDevice yang dihasilkan ke Konsol. Hal ini akan menampilkan productId (37888, yang merupakan 0x9400 dalam hex) dan vendorId (6353, yang merupakan 0x18d1 dalam hex) pengontrol Stadia. Jika Anda mencari vendorID di tabel ID vendor USB resmi, Anda akan menemukan bahwa 6353 dipetakan ke yang Anda harapkan: Google Inc..

Konsol Chrome DevTools yang menampilkan output logging objek HIDDevice.

Alternatif untuk alur yang dijelaskan di atas adalah membuka chrome://device-log/ di kolom URL, menekan tombol Hapus, mencolokkan pengontrol Stadia, lalu menekan Muat Ulang. Tindakan ini akan memberikan informasi yang sama kepada Anda.

Antarmuka debug chrome://device-log yang menampilkan informasi tentang pengontrol Stadia yang dicolokkan.

Alternatif lainnya adalah menggunakan alat HID Explorer yang memungkinkan Anda menjelajahi lebih banyak detail perangkat HID yang terhubung ke komputer Anda.

Gunakan dua ID ini, vendorId dan productId, untuk menyempurnakan apa yang ditampilkan di pemilih dengan memfilter perangkat WebHID yang tepat dengan benar.

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

Sekarang, derau dari semua perangkat yang tidak terkait sudah hilang, dan hanya pengontrol Stadia yang muncul.

Pemilih perangkat WebHID API yang hanya menampilkan pengontrol Stadia.

Selanjutnya, buka HIDDevice dengan memanggil metode open().

await stadiaController.open();

Log HIDDevice lagi, dan flag opened ditetapkan ke true.

Konsol Chrome DevTools yang menampilkan output logging objek HIDDevice setelah membukanya.

Dengan perangkat terbuka, dengarkan peristiwa inputreport yang masuk dengan melampirkan pemroses peristiwa.

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

Saat Anda menekan dan melepaskan tombol Asisten di pengontrol, dua peristiwa dicatat ke Konsol. Anda dapat menganggapnya sebagai peristiwa "tombol Asisten ditekan" dan "tombol Asisten dilepas". Selain timeStamp, kedua peristiwa tersebut terlihat tidak dapat dibedakan pada pandangan pertama.

Konsol Chrome DevTools yang menampilkan objek HIDInputReportEvent yang sedang dicatat.

Properti reportId dari antarmuka HIDInputReportEvent menampilkan awalan identifikasi satu byte untuk laporan ini, atau 0 jika antarmuka HID tidak menggunakan ID laporan. Dalam hal ini, nilainya adalah 3. Secret ada di properti data, yang ditampilkan sebagai DataView berukuran 10. DataView menyediakan antarmuka tingkat rendah untuk membaca dan menulis beberapa jenis angka dalam ArrayBuffer biner. Cara untuk mendapatkan sesuatu yang lebih mudah dipahami dari representasi ini adalah dengan membuat Uint8Array dari ArrayBuffer, sehingga Anda dapat melihat bilangan bulat 8-bit yang tidak bertanda.

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

Saat Anda mencatat data peristiwa laporan input lagi, semuanya akan mulai lebih masuk akal dan peristiwa "tombol Asisten ditekan" dan "tombol Asisten dilepas" akan mulai dapat dipahami. Integer pertama (8 di kedua peristiwa) tampaknya terkait dengan penekanan tombol, dan integer kedua (2 dan 0) tampaknya terkait dengan apakah tombol Asisten ditekan atau tidak.

Konsol Chrome DevTools yang menampilkan objek Uint8Array yang dicatat untuk setiap HIDInputReportEvent.

Tekan tombol Ambil, bukan tombol Asisten, dan Anda akan melihat bahwa bilangan bulat kedua beralih dari 1 saat tombol ditekan ke 0 saat tombol dilepaskan. Dengan begitu, Anda dapat menulis "driver" yang sangat sederhana untuk menggunakan dua tombol yang tidak ada.

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

Dengan menggunakan pendekatan rekayasa balik seperti ini, Anda dapat, tombol demi tombol dan sumbu demi sumbu, mengetahui cara berkomunikasi dengan pengontrol Stadia menggunakan WebHID. Setelah Anda menguasainya, sisanya adalah pekerjaan pemetaan bilangan bulat yang hampir mekanis.

Satu hal yang kini hilang adalah pengalaman koneksi lancar yang diberikan Gamepad API kepada Anda. Meskipun karena alasan keamanan Anda harus selalu melalui pengalaman pemilih awal satu kali untuk bekerja dengan perangkat WebHID seperti pengontrol Stadia, untuk koneksi mendatang, Anda dapat menghubungkan kembali ke perangkat yang dikenal. Lakukan hal itu dengan memanggil metode getDevices().

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

Demo

Anda dapat melihat pengontrol Stadia yang dikontrol bersama oleh Gamepad API dan WebHID API dalam demo yang telah saya buat. Pastikan untuk melihat kode sumber, yang dibuat berdasarkan cuplikan dari artikel ini. Demi kesederhanaan, saya hanya menampilkan tombol A, B, X, dan Y (dikontrol oleh Gamepad API), serta tombol Asisten dan Ambil (dikontrol oleh WebHID API). Di bawah gambar pengontrol, Anda dapat melihat data WebHID mentah, sehingga Anda dapat merasakan semua tombol dan sumbu pada pengontrol.

Aplikasi demo pengontrol Stadia yang menampilkan tombol A, B, X, dan Y yang dikontrol oleh Gamepad API, serta tombol Asisten dan Rekam yang dikontrol oleh WebHID API.

Kesimpulan

Berkat firmware baru, pengontrol Stadia kini dapat digunakan sebagai gamepad standar dengan 17 tombol, yang dalam sebagian besar kasus, sudah lebih dari cukup untuk mengontrol game web umum. Jika karena alasan apa pun Anda memerlukan data dari semua 19 tombol di pengontrol, WebHID memungkinkan Anda mendapatkan akses ke laporan input tingkat rendah yang dapat Anda dekode dengan merekayasa baliknya satu per satu. Jika Anda menulis driver WebHID lengkap setelah membaca artikel ini, pastikan untuk menghubungi saya, dan saya akan dengan senang hati menautkan project Anda di sini. Selamat menggunakan WebHID!

Ucapan terima kasih

Artikel ini ditinjau oleh François Beaufort.