Skip to content

Commit dd2ca4c

Browse files
authored
Add web command to request device access (microsoft#152310)
* Add web command to request serial access Signed-off-by: thegecko <[email protected]> * Add support for requesting HID devices Signed-off-by: thegecko <[email protected]>
1 parent 9ec50c6 commit dd2ca4c

File tree

4 files changed

+70
-5
lines changed

4 files changed

+70
-5
lines changed

src/vs/base/browser/usb.ts renamed to src/vs/base/browser/deviceAccess.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface UsbDeviceData {
2222
readonly vendorId: number;
2323
}
2424

25-
export async function requestUsb(options?: { filters?: unknown[] }): Promise<UsbDeviceData | undefined> {
25+
export async function requestUsbDevice(options?: { filters?: unknown[] }): Promise<UsbDeviceData | undefined> {
2626
const usb = (navigator as any).usb;
2727
if (!usb) {
2828
return undefined;
@@ -50,3 +50,59 @@ export async function requestUsb(options?: { filters?: unknown[] }): Promise<Usb
5050
vendorId: device.vendorId,
5151
};
5252
}
53+
54+
// https://wicg.github.io/serial/
55+
56+
export interface SerialPortData {
57+
readonly usbVendorId?: number | undefined;
58+
readonly usbProductId?: number | undefined;
59+
}
60+
61+
export async function requestSerialPort(options?: { filters?: unknown[] }): Promise<SerialPortData | undefined> {
62+
const serial = (navigator as any).serial;
63+
if (!serial) {
64+
return undefined;
65+
}
66+
67+
const port = await serial.requestPort({ filters: options?.filters ?? [] });
68+
if (!port) {
69+
return undefined;
70+
}
71+
72+
const info = port.getInfo();
73+
return {
74+
usbVendorId: info.usbVendorId,
75+
usbProductId: info.usbProductId
76+
};
77+
}
78+
79+
// https://wicg.github.io/webhid/
80+
81+
export interface HidDeviceData {
82+
readonly opened: boolean;
83+
readonly vendorId: number;
84+
readonly productId: number;
85+
readonly productName: string;
86+
readonly collections: [];
87+
}
88+
89+
export async function requestHidDevice(options?: { filters?: unknown[] }): Promise<HidDeviceData | undefined> {
90+
const hid = (navigator as any).hid;
91+
if (!hid) {
92+
return undefined;
93+
}
94+
95+
const devices = await hid.requestDevice({ filters: options?.filters ?? [] });
96+
if (!devices.length) {
97+
return undefined;
98+
}
99+
100+
const device = devices[0];
101+
return {
102+
opened: device.opened,
103+
vendorId: device.vendorId,
104+
productId: device.productId,
105+
productName: device.productName,
106+
collections: device.collections
107+
};
108+
}

src/vs/workbench/browser/actions/workspaceCommands.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,3 @@ CommandsRegistry.registerCommand('_workbench.getRecentlyOpened', async function
306306

307307
return workspacesService.getRecentlyOpened();
308308
});
309-

src/vs/workbench/browser/window.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { isSafari, setFullscreen } from 'vs/base/browser/browser';
77
import { addDisposableListener, addDisposableThrottledListener, detectFullscreen, EventHelper, EventType, windowOpenNoOpener, windowOpenPopup, windowOpenWithSuccess } from 'vs/base/browser/dom';
88
import { DomEmitter } from 'vs/base/browser/event';
9-
import { requestUsb, UsbDeviceData } from 'vs/base/browser/usb';
9+
import { HidDeviceData, requestHidDevice, requestSerialPort, requestUsbDevice, SerialPortData, UsbDeviceData } from 'vs/base/browser/deviceAccess';
1010
import { timeout } from 'vs/base/common/async';
1111
import { Event } from 'vs/base/common/event';
1212
import { Disposable } from 'vs/base/common/lifecycle';
@@ -248,7 +248,17 @@ export class BrowserWindow extends Disposable {
248248

249249
// Allow extensions to request USB devices in Web
250250
CommandsRegistry.registerCommand('workbench.experimental.requestUsbDevice', async (_accessor: ServicesAccessor, options?: { filters?: unknown[] }): Promise<UsbDeviceData | undefined> => {
251-
return requestUsb(options);
251+
return requestUsbDevice(options);
252+
});
253+
254+
// Allow extensions to request Serial devices in Web
255+
CommandsRegistry.registerCommand('workbench.experimental.requestSerialPort', async (_accessor: ServicesAccessor, options?: { filters?: unknown[] }): Promise<SerialPortData | undefined> => {
256+
return requestSerialPort(options);
257+
});
258+
259+
// Allow extensions to request HID devices in Web
260+
CommandsRegistry.registerCommand('workbench.experimental.requestHidDevice', async (_accessor: ServicesAccessor, options?: { filters?: unknown[] }): Promise<HidDeviceData | undefined> => {
261+
return requestHidDevice(options);
252262
});
253263
}
254264
}

src/vs/workbench/services/extensions/browser/webWorkerExtensionHost.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export class WebWorkerExtensionHost extends Disposable implements IExtensionHost
132132
const iframe = document.createElement('iframe');
133133
iframe.setAttribute('class', 'web-worker-ext-host-iframe');
134134
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
135-
iframe.setAttribute('allow', 'usb; cross-origin-isolated;');
135+
iframe.setAttribute('allow', 'usb; serial; hid; cross-origin-isolated;');
136136
iframe.setAttribute('aria-hidden', 'true');
137137
iframe.style.display = 'none';
138138

0 commit comments

Comments
 (0)