Signatur
Beschreibung
Mit sendReport() schickt man Daten an ein HID-Gerät (Human Interface Device), zum Beispiel um LEDs an einer Tastatur oder einem Gamepad zu schalten, einen Rumble-Motor zu starten oder Steuerbefehle an Spezialhardware wie Stream-Decks, Barcode-Scanner oder Messgeräte zu senden. Die Methode gehört zur WebHID-API und schreibt in einen Output Report, wie er im Report-Deskriptor des Geräts definiert ist.
Das Gerät muss vorher mit navigator.hid.requestDevice() ausgewählt und mit device.open() geöffnet worden sein. Der erste Parameter ist die Report-ID. Nutzt das Gerät keine Report-IDs, übergibt man 0. Der zweite Parameter enthält die eigentlichen Nutzdaten ohne das Byte für die Report-ID, das der Browser selbst voranstellt.
Welche Report-IDs und Längen gültig sind, steht in device.collections[].outputReports. Das Promise wird erfüllt, sobald der Report übertragen wurde. Bei ungültigen Daten, einem geschlossenen Gerät oder einem Übertragungsfehler wird es mit einer DOMException abgelehnt. Antworten des Geräts kommen nicht als Rückgabewert zurück, sondern asynchron über das Ereignis inputreport.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $reportId Pflicht | number | 8-Bit-Report-ID des Ausgabereports. Für Geräte ohne Report-IDs 0 übergeben. |
|
| $data Pflicht | BufferSource (ArrayBuffer | TypedArray | DataView) | Nutzdaten des Reports ohne das Präfix mit der Report-ID. Die Länge sollte der im Report-Deskriptor definierten Größe entsprechen. |
Rückgabewert
undefined erfüllt wird, sobald der Report gesendet wurde. Schlägt das Senden fehl, wird es mit einer DOMException abgelehnt, z. B. InvalidStateError bei nicht geöffnetem Gerät oder NotAllowedError/NotSupportedError bei gesperrten oder abgelehnten Reports.Beispiele
Gerät auswählen, öffnen und Report senden
// Muss durch eine Nutzeraktion ausgelöst werden (z. B. Klick)
document.querySelector('#connect').addEventListener('click', async () => {
const [device] = await navigator.hid.requestDevice({
filters: [{ vendorId: 0x0fd9 }] // Beispiel: Elgato
});
if (!device) return;
if (!device.opened) await device.open();
// Report-ID 0x02, Nutzdaten ohne ID-Byte
const data = new Uint8Array([0x0b, 0x00, 0x00, 0x00]);
await device.sendReport(0x02, data);
console.log(`Report an ${device.productName} gesendet`);
});
Gerät ohne Report-IDs: LED einschalten mit Fehlerbehandlung
const setLed = async (device, on) => {
try {
// reportId 0, weil das Gerät keine Report-IDs verwendet
await device.sendReport(0, new Uint8Array([on ? 0x01 : 0x00]));
console.log(`LED ${on ? 'an' : 'aus'}`);
} catch (err) {
console.error(`Senden fehlgeschlagen: ${err.name} – ${err.message}`);
}
};
const [device] = await navigator.hid.getDevices();
if (device) {
await device.open();
await setLed(device, true);
}
Befehl senden und Antwort über inputreport empfangen
const sendCommand = (device, reportId, bytes, timeout = 1000) =>
new Promise((resolve, reject) => {
const timer = setTimeout(() => {
device.removeEventListener('inputreport', onReport);
reject(new Error('Zeitüberschreitung'));
}, timeout);
const onReport = (event) => {
clearTimeout(timer);
device.removeEventListener('inputreport', onReport);
resolve(new Uint8Array(event.data.buffer));
};
device.addEventListener('inputreport', onReport);
device.sendReport(reportId, Uint8Array.from(bytes)).catch(reject);
});
const [device] = await navigator.hid.getDevices();
await device.open();
const answer = await sendCommand(device, 0x01, [0x10, 0x00]);
console.log('Antwort:', answer);
Verfügbare Output-Reports prüfen
const [device] = await navigator.hid.getDevices();
for (const collection of device.collections) {
for (const report of collection.outputReports ?? []) {
console.log('Output-Report-ID:', report.reportId);
}
}
// Wichtig · Fallstricke
- Browser-Kompatibilität: WebHID gibt es nur in Chromium-Browsern auf dem Desktop (Chrome, Edge, Opera). Firefox und Safari unterstützen es nicht. Vor der Nutzung mit
'hid' in navigatorprüfen. - Sicherer Kontext: Die API funktioniert nur über HTTPS (oder
localhost).requestDevice()braucht eine Nutzeraktion. In iframes muss die Permissions-Policyhiderlaubt sein. - Gerät öffnen: Ohne vorheriges
await device.open()wird das Promise mitInvalidStateErrorabgelehnt. - Report-ID nicht doppelt senden: Das ID-Byte gehört nicht in
data. Wer es trotzdem voranstellt, verschiebt alle Nutzdaten um ein Byte. Das ist ein häufiger Fehler beim Portieren von node-hid- oder hidapi-Code. - Gesperrte Geräte: Aus Sicherheitsgründen blockiert der Browser bestimmte Top-Level-Collections, etwa Tastaturen, Mäuse und FIDO-Sicherheitsschlüssel. Manche Geräte sind außerdem auf einer Sperrliste. Reports an solche Geräte werden abgelehnt.
- Feature- vs. Output-Reports: Viele Geräte erwarten Konfigurationsdaten als Feature Report. Dafür ist
sendFeatureReport()gedacht, nichtsendReport(). - Reihenfolge: Mehrere Reports kurz hintereinander besser nacheinander mit
awaitsenden, damit die Reihenfolge feststeht und das Gerät nicht überlastet wird.