Berbicara dengan pengontrol Stadia dengan WebHID

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

Sejak Stadia dihentikan, banyak yang khawatir pengontrolnya akan berubah menjadi hardware yang tidak berguna di TPA. 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 tampak sebagai gamepad standar yang dapat dihubungkan melalui kabel USB atau secara nirkabel melalui Bluetooth. Dengan bangga ditampilkan di Etalase Project Fugu API, halaman Bluetooth Stadia sendiri menggunakan WebHID dan WebUSB, tetapi ini bukan topik dalam artikel ini. Dalam postingan ini, saya ingin menjelaskan cara berkomunikasi dengan pengontrol Stadia melalui WebHID.

Pengontrol Stadia sebagai gamepad standar

Setelah berkedip, pengontrol akan muncul sebagai gamepad standar ke sistem operasi. Lihat screenshot berikut untuk mengetahui pengaturan sumbu dan tombol yang umum pada gamepad standar. Seperti yang didefinisikan dalam spesifikasi Gamepad API, gamepad standar memiliki tombol dari 0 hingga 16, jadi totalnya adalah 17 (d-pad dihitung sebagai empat tombol). Jika mencoba pengontrol Stadia pada demo penguji gamepad, Anda akan melihat bahwa pengontrol ini berfungsi seperti charm.

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

Namun, kalau kamu menghitung tombol-tombol di pengontrol Stadia, ada 19. Jika Anda mencobanya satu per satu secara sistematis di penguji gamepad, Anda akan menyadari bahwa tombol Assistant dan Capture tidak berfungsi. Meskipun atribut buttons gamepad seperti yang didefinisikan dalam spesifikasi Gamepad bersifat open-ended, karena pengontrol Stadia muncul sebagai gamepad standar, hanya tombol 0–16 yang dipetakan. Anda tetap dapat menggunakan tombol lain, tetapi sebagian besar game tidak akan mengharapkan tombol tersebut ada.

WebHID siap membantu

Berkat WebHID API, Anda dapat berkomunikasi dengan tombol 17 dan 18 yang tidak ada. Jika menginginkannya, Anda bahkan bisa mendapatkan data tentang semua tombol dan sumbu lainnya yang sudah tersedia melalui Gamepad API. Langkah pertama adalah mencari tahu bagaimana pengontrol Stadia melaporkan dirinya sendiri ke sistem operasi. Salah satu cara untuk melakukannya adalah dengan membuka Konsol Chrome DevTools di halaman acak, dan meminta daftar perangkat yang tidak difilter dari WebHID API. Kemudian, pilih pengontrol Stadia secara manual untuk melakukan 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 dari belakang terlihat seperti pengontrol Stadia.

Pemilih perangkat WebHID API menampilkan beberapa perangkat yang tidak terkait, dan pengontrol Stadia berada di posisi belakang.

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

Konsol Chrome DevTools menampilkan output logging objek HIDDevice.

Alternatif untuk alur yang dijelaskan di atas adalah membuka chrome://device-log/ di kolom URL, menekan tombol Clear, mencolokkan pengontrol Stadia, lalu menekan Refresh. Dengan begitu, Anda akan mendapatkan informasi yang sama.

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

Alternatif lainnya adalah menggunakan alat Penjelajah HID yang memungkinkan Anda menjelajahi detail selengkapnya tentang perangkat HID yang terhubung ke komputer Anda.

Gunakan kedua ID ini, vendorId dan productId, untuk mempertajam informasi yang ditampilkan di alat pilih dengan kini memfilter perangkat WebHID yang tepat dengan benar.

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

Sekarang suara dari semua perangkat yang tidak terkait akan hilang, dan hanya pengontrol Stadia yang muncul.

Pemilih perangkat WebHID API hanya menampilkan pengontrol Stadia.

Selanjutnya, buka HIDDevice dengan memanggil metode open().

await stadiaController.open();

Catat HIDDevice lagi, dan flag opened disetel ke true.

Konsol Chrome DevTools menampilkan output logging objek HIDDevice setelah membukanya.

Saat perangkat terbuka, proses peristiwa inputreport yang masuk dengan menambahkan pemroses peristiwa.

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

Saat Anda menekan dan melepaskan tombol Assistant pada pengontrol, dua peristiwa akan dicatat ke Konsol. Anda bisa menganggapnya sebagai peristiwa "Assistant tombol bawah" dan "Asisten button up". Selain timeStamp, kedua peristiwa ini terlihat tidak dapat dibedakan secara sekilas.

Konsol Chrome DevTools 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, parameternya adalah 3. Rahasia ini ada di properti data, yang direpresentasikan 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 masing-masing bilangan bulat 8-bit yang tidak ditandatangani.

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

Saat Anda kemudian mencatat data peristiwa laporan input lagi ke dalam log, semuanya akan menjadi lebih masuk akal dan peristiwa "Asisten tombol turun" dan "tombol Asisten" mulai dapat dipahami. Bilangan bulat pertama (8 di kedua peristiwa) tampaknya terkait dengan penekanan tombol, dan bilangan bulat kedua (2 dan 0) tampaknya terkait dengan apakah tombol Assistant ditekan atau tidak.

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

Tekan tombol Capture sebagai ganti tombol Assistant, dan Anda akan melihat bahwa bilangan bulat kedua beralih dari 1 saat tombol ditekan ke 0 saat dirilis. Hal ini memungkinkan Anda menulis "driver" yang sangat sederhana yang memungkinkan Anda memanfaatkan dua tombol yang hilang.

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 pendekatan rekayasa balik seperti ini, Anda dapat menentukan tombol demi tombol dan sumbu demi sumbu, untuk mencari tahu cara berkomunikasi dengan pengontrol Stadia dengan WebHID. Setelah Anda memahaminya, sisanya adalah pekerjaan pemetaan bilangan bulat mekanis.

Satu hal yang tidak ada sekarang adalah pengalaman menghubungkan yang lancar yang diberikan Gamepad API kepada Anda. Meskipun untuk alasan keamanan, Anda harus selalu menggunakan pengalaman pemilih awal satu kali untuk dapat menggunakan perangkat WebHID seperti pengontrol Stadia. Untuk koneksi mendatang, Anda dapat terhubung kembali ke perangkat yang dikenal. Lakukan hal tersebut 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 di demo yang telah saya buat. Pastikan untuk memeriksa kode sumber, yang dibuat berdasarkan cuplikan dari artikel ini. Agar lebih praktis, saya hanya menampilkan tombol A, B, X, dan Y (dikontrol oleh Gamepad API), serta tombol Assistant dan Capture (dikontrol oleh WebHID API). Di bawah gambar pengontrol, Anda dapat melihat data WebHID mentah, sehingga Anda dapat memahami semua tombol dan sumbu pada pengontrol.

Aplikasi demo di https://stadia-controller-webhid-gamepad.glitch.me/ yang menunjukkan tombol A, B, X, dan Y yang dikontrol oleh Gamepad API, serta Asisten dan tombol Capture yang dikontrol oleh WebHID API.

Kesimpulan

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

Ucapan terima kasih

Artikel ini ditinjau oleh François Beaufort.