Berbicara dengan pengontrol Stadia dengan WebHID

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

Sejak Stadia dimatikan, banyak yang khawatir bahwa pengontrol akan berakhir sebagai hardware 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. Tindakan ini akan 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 itu sendiri menggunakan WebHID dan WebUSB, tetapi ini bukan topik artikel ini. Dalam postingan ini, saya ingin menjelaskan cara berkomunikasi dengan pengontrol Stadia melalui WebHID.

Pengontrol Stadia sebagai gamepad standar

Setelah di-flash, pengontrol akan muncul sebagai gamepad standar ke sistem operasi. Lihat screenshot berikut untuk mengetahui pengaturan tombol dan sumbu umum pada gamepad standar. Seperti yang ditentukan dalam spesifikasi Gamepad API, gamepad standar memiliki tombol dari 0 hingga 16, sehingga totalnya 17 (d-pad dihitung sebagai empat tombol). Jika 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 Rekam 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 lain, tetapi sebagian besar game tidak akan mengharapkannya.

WebHID datang untuk menyelamatkan

Berkat WebHID API, Anda dapat berkomunikasi dengan tombol 17 dan 18 yang tidak ada. Dan jika 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 cara untuk melakukannya adalah dengan membuka Konsol Chrome DevTools di halaman acak, dan meminta daftar perangkat yang tidak difilter dari WebHID API. Kemudian, Anda dapat memilih pengontrol Stadia secara manual untuk pemeriksaan lebih lanjut. Dapatkan daftar perangkat yang tidak difilter dengan meneruskan array opsi filters kosong.

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

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

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

Setelah memilih perangkat "Stadia Controller rev. A", catat objek HIDDevice yang dihasilkan ke Konsol. Tindakan ini akan menampilkan productId (37888, yang merupakan 0x9400 dalam heksadesimal) dan vendorId (6353, yang merupakan 0x18d1 dalam heksadesimal) pengontrol Stadia. Jika mencari vendorID di tabel ID vendor USB resmi, Anda akan menemukan bahwa 6353 dipetakan ke hal 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 Hapus, mencolokkan pengontrol Stadia, lalu menekan Muat ulang. Tindakan ini akan memberi Anda informasi yang sama.

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.

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

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

Sekarang, derau dari semua perangkat yang tidak terkait akan 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();

Catat HIDDevice lagi, dan flag opened ditetapkan ke true.

Konsol Chrome DevTools 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 akan dicatat ke dalam log di Konsol. Anda dapat menganggapnya sebagai peristiwa "tombol Asisten ditekan" dan "tombol Asisten dilepaskan". Selain timeStamp, kedua peristiwa tersebut terlihat tidak dapat dibedakan pada pandangan pertama.

Konsol Chrome DevTools menampilkan objek HIDInputReportEvent yang dicatat ke dalam log.

Properti reportId 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 direpresentasikan sebagai DataView berukuran 10. DataView menyediakan antarmuka tingkat rendah untuk membaca dan menulis beberapa jenis angka dalam ArrayBuffer biner. Cara mendapatkan sesuatu yang lebih mudah dicerna dari representasi ini adalah dengan membuat Uint8Array dari ArrayBuffer, sehingga Anda dapat melihat setiap bilangan bulat 8-bit yang tidak ditandatangani.

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

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

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

Tekan tombol Capture, bukan tombol Assistant, dan Anda akan melihat bahwa bilangan bulat kedua beralih dari 1 saat tombol ditekan ke 0 saat tombol dilepaskan. Hal ini memungkinkan Anda menulis "driver" yang sangat sederhana yang memungkinkan Anda menggunakan 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 menggunakan pendekatan rekayasa balik seperti ini, Anda dapat, tombol demi tombol dan sumbu demi sumbu, mencari tahu cara berkomunikasi dengan pengontrol Stadia menggunakan WebHID. Setelah Anda memahaminya, sisanya hampir merupakan pekerjaan pemetaan bilangan bulat mekanis.

Satu hal yang sekarang tidak ada adalah pengalaman koneksi yang lancar yang diberikan Gamepad API kepada Anda. Meskipun untuk alasan keamanan, Anda harus selalu melalui pengalaman pemilih awal sekali untuk menggunakan perangkat WebHID seperti pengontrol Stadia, untuk koneksi mendatang, Anda dapat terhubung 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. Untuk memudahkan, saya hanya menampilkan tombol A, B, X, dan Y (dikontrol oleh Gamepad API), serta tombol Asisten dan Rekaman (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 di https://stadia-controller-webhid-gamepad.glitch.me/ 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, lebih dari cukup untuk mengontrol game web umum. Jika, karena alasan apa pun, Anda memerlukan data dari 19 tombol di pengontrol, WebHID memungkinkan Anda mendapatkan akses ke laporan input tingkat rendah yang dapat Anda tafsirkan dengan melakukan rekayasa balik 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 project Anda di sini. Selamat menggunakan WebHID!

Ucapan terima kasih

Artikel ini ditinjau oleh François Beaufort.