Merge pull request #19853 from larsgk/master

Add definitions for W3C Web USB API
This commit is contained in:
Benjamin Lichtman 2017-09-19 12:28:15 -07:00 committed by GitHub
commit 809e34e89f
4 changed files with 252 additions and 0 deletions

153
types/w3c-web-usb/index.d.ts vendored Normal file
View File

@ -0,0 +1,153 @@
// Type definitions for W3C Web USB API 1.0
// Project: https://wicg.github.io/webusb/
// Definitions by: Lars Knudsen <https://github.com/larsgk>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1
type USBDirection = "in" | "out";
type USBEndpointType = "bulk" | "interrupt" | "isochronous";
type USBRequestType = "standard" | "class" | "vendor";
type USBRecipient = "device" | "interface" | "endpoint" | "other";
type USBTransferStatus = "ok" | "stall" | "babble";
interface USBEndpoint {
readonly endpointNumber: number;
readonly direction: USBDirection;
readonly type: USBEndpointType;
readonly packetSize: number;
}
interface USBControlTransferParameters {
requestType: USBRequestType;
recipient: USBRecipient;
request: number;
value: number;
index: number;
}
interface USBDeviceFilter {
vendorId?: number;
productId?: number;
classCode?: number;
subclassCode?: number;
protocolCode?: number;
serialNumber?: string;
}
interface USBDeviceRequestOptions {
filters: USBDeviceFilter[];
}
interface USBConnectionEventInit extends EventInit {
device: USBDevice;
}
declare class USBConfiguration {
readonly configurationValue: number;
readonly configurationName?: string;
readonly interfaces: USBInterface[];
}
declare class USBInterface {
constructor(configuration: USBConfiguration, interfaceNumber: number);
readonly interfaceNumber: number;
readonly alternate: USBAlternateInterface;
readonly alternates: USBAlternateInterface[];
readonly claimed: boolean;
}
declare class USBAlternateInterface {
constructor(deviceInterface: USBInterface, alternateSetting: number);
readonly alternateSetting: number;
readonly interfaceClass: number;
readonly interfaceSubclass: number;
readonly interfaceProtocol: number;
readonly alternatinterfaceName?: string;
readonly endpoints: USBEndpoint[];
}
declare class USBInTransferResult {
constructor(status: USBTransferStatus, data?: DataView);
readonly data?: DataView;
readonly status?: USBTransferStatus;
}
declare class USBOutTransferResult {
constructor(status: USBTransferStatus, bytesWriten?: number);
readonly bytesWritten: number;
readonly status: USBTransferStatus;
}
declare class USBIsochronousInTransferPacket {
constructor(status: USBTransferStatus, data?: DataView);
readonly data?: DataView;
readonly status?: USBTransferStatus;
}
declare class USBIsochronousInTransferResult {
constructor(packets: USBIsochronousInTransferPacket[], data?: DataView);
readonly data?: DataView;
readonly packets: USBIsochronousInTransferPacket[];
}
declare class USBIsochronousOutTransferPacket {
constructor(status: USBTransferStatus, bytesWritten?: number);
readonly bytesWritten: number;
readonly status: USBTransferStatus;
}
declare class USBConnectionEvent extends Event {
constructor(type: string, eventInitDict: USBConnectionEventInit);
readonly device: USBDevice;
}
declare class USBIsochronousOutTransferResult {
constructor(packets: USBIsochronousOutTransferPacket[]);
readonly packets: USBIsochronousOutTransferPacket[];
}
declare class USB extends EventTarget {
onconnect(): (this: this, ev: Event) => any;
ondisconnect(): (this: this, ev: Event) => any;
getDevices(): Promise<USBDevice[]>;
requestDevice(options?: USBDeviceRequestOptions): Promise<USBDevice>;
addEventListener(type: "connect" | "disconnect", listener: (this: this, ev: USBConnectionEvent) => any, useCapture?: boolean): void;
}
declare class USBDevice {
readonly usbVersionMajor: number;
readonly usbVersionMinor: number;
readonly usbVersionSubminor: number;
readonly deviceClass: number;
readonly deviceSubclass: number;
readonly deviceProtocol: number;
readonly vendorId: number;
readonly productId: number;
readonly deviceVersionMajor: number;
readonly deviceVersionMinor: number;
readonly deviceVersionSubminor: number;
readonly manufacturerName?: string;
readonly productName?: string;
readonly serialNumber?: string;
readonly configuration?: USBConfiguration;
readonly configurations: USBConfiguration[];
readonly opened: boolean;
open(): Promise<void>;
close(): Promise<void>;
selectConfiguration(configurationValue: number): Promise<void>;
claimInterface(interfaceNumber: number): Promise<void>;
releaseInterface(interfaceNumber: number): Promise<void>;
selectAlternateInterface(interfaceNumber: number, alternateSetting: number): Promise<void>;
controlTransferIn(setup: USBControlTransferParameters, length: number): Promise<USBInTransferResult>;
controlTransferOut(setup: USBControlTransferParameters, data?: BufferSource): Promise<USBOutTransferResult>;
clearHalt(direction: USBDirection, endpointNumber: number): Promise<void>;
transferIn(endpointNumber: number, length: number): Promise<USBInTransferResult>;
transferOut(endpointNumber: number, data: BufferSource): Promise<USBOutTransferResult>;
isochronousTransferIn(endpointNumber: number, packetLengths: number[]): Promise<USBIsochronousInTransferResult>;
isochronousTransferOut(endpointNumber: number, data: BufferSource, packetLengths: number[]): Promise<USBIsochronousOutTransferResult>;
}
interface Navigator {
readonly usb: USB;
}

View File

@ -0,0 +1,23 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"w3c-web-usb-tests.ts"
]
}

View File

@ -0,0 +1 @@
{ "extends": "dtslint/dt.json" }

View File

@ -0,0 +1,75 @@
// Modified from WebUSB spec: https://wicg.github.io/webusb/
// NOTE: Code kept as close to spec examples as possible
const connectedDevices: USBDevice[] = [];
document.addEventListener('DOMContentLoaded', async () => {
const devices = await navigator.usb.getDevices();
devices.forEach(handleConnectedDevice);
});
const button = document.getElementById('request-device');
if (button) {
button.addEventListener('click', async () => {
let device;
try {
device = await navigator.usb.requestDevice({ filters: [{
vendorId: 0xABCD,
classCode: 0xFF, // vendor-specific
protocolCode: 0x01
}]});
} catch (e) {
// No device was selected.
}
if (device !== undefined) {
// Add |device| to the UI.
handleConnectedDevice(device);
}
});
}
navigator.usb.addEventListener('connect', evt => {
// Add |device| to the UI.
handleConnectedDevice(evt.device);
});
navigator.usb.addEventListener('disconnect', evt => {
// Remove |device| from the UI.
const i = connectedDevices.indexOf(evt.device);
if (i >= 0) {
connectedDevices.splice(i, 1);
}
});
async function handleConnectedDevice(device: USBDevice) {
connectedDevices.push(device);
await device.open();
if (device.configuration === null)
await device.selectConfiguration(1);
await device.claimInterface(1);
await device.controlTransferOut({
requestType: 'vendor',
recipient: 'interface',
request: 0x01, // vendor-specific request: enable channels
value: 0x0013, // 0b00010011 (channels 1, 2 and 5)
index: 0x0001 // Interface 1 is the recipient
});
while (true) {
const result = await device.transferIn(1, 6);
if (result.data && result.data.byteLength === 6) {
console.log('Channel 1: ' + result.data.getUint16(0));
console.log('Channel 2: ' + result.data.getUint16(2));
console.log('Channel 5: ' + result.data.getUint16(4));
}
if (result.status === 'stall') {
console.warn('Endpoint stalled. Clearing.');
await device.clearHalt("in", 1);
}
}
}