1- import { useCallback } from "react" ;
1+ import { useCallback , useEffect } from "react" ;
22
33export const WOOT_VID = 0x31e3 ;
44
@@ -15,10 +15,60 @@ declare global {
1515}
1616
1717interface ConnectDeviceProps {
18+ device : HIDDevice | null ;
1819 onConnect : ( device : HIDDevice ) => void ;
20+ onDisconnect : ( device : HIDDevice ) => void ;
21+ showForgetButton ?: boolean ;
1922}
2023
21- export function ConnectDevice ( { onConnect } : ConnectDeviceProps ) {
24+ export async function initDevice ( device : HIDDevice ) {
25+ await device . open ( ) ;
26+ device . addEventListener ( "inputreport" , ( event ) => {
27+ const data = event . data ;
28+ const analogData = [ ] ;
29+ for ( let i = 0 ; i < data . byteLength ; i += 3 ) {
30+ const key = data . getUint16 ( i ) ;
31+ const value = data . getUint8 ( i + 2 ) / 255 ;
32+
33+ if ( value === 0 ) break ;
34+ analogData . push ( { key, value } ) ;
35+ }
36+ if ( device . onanalogreport ) {
37+ device . onanalogreport ( { data : analogData } ) ;
38+ } else {
39+ console . warn ( "No onanalogreport event listener" ) ;
40+ }
41+ } ) ;
42+ }
43+
44+ let hasDoneInit = false ;
45+
46+ export function ConnectDevice ( {
47+ device,
48+ onConnect,
49+ onDisconnect,
50+ showForgetButton = false ,
51+ } : ConnectDeviceProps ) {
52+ useEffect ( ( ) => {
53+ if ( hasDoneInit ) {
54+ return ;
55+ }
56+ hasDoneInit = true ;
57+ console . log ( "Init connected devices" ) ;
58+ navigator . hid . getDevices ( ) . then ( async ( devices ) => {
59+ const wootDevice = devices . find (
60+ ( device ) =>
61+ device . vendorId === WOOT_VID &&
62+ device . collections [ 0 ] . usagePage === WOOT_ANALOG_USAGE
63+ ) ;
64+ if ( wootDevice ) {
65+ console . log ( "Found device" , wootDevice ) ;
66+ await initDevice ( wootDevice ) ;
67+ onConnect ( wootDevice ) ;
68+ }
69+ } ) ;
70+ } , [ onConnect ] ) ;
71+
2272 const onClick = useCallback ( async ( ) => {
2373 const device = await navigator . hid . requestDevice ( {
2474 filters : [
@@ -32,42 +82,54 @@ export function ConnectDevice({ onConnect }: ConnectDeviceProps) {
3282 if ( device . length > 0 ) {
3383 const useDevice = device [ 0 ] ;
3484
35- await useDevice . open ( ) ;
36-
3785 console . log ( "Got Device" , useDevice ) ;
3886
39- useDevice . addEventListener ( "inputreport" , ( event ) => {
40- // The data structure is that there are pairs of 2 bytes for the hid id and one byte for the analog value repeated over and over
41- const data = event . data ;
42- const analogData = [ ] ;
43- for ( let i = 0 ; i < data . byteLength ; i += 3 ) {
44- const key = data . getUint16 ( i ) ;
45- const value = data . getUint8 ( i + 2 ) / 255 ;
46-
47- if ( value === 0 ) {
48- break ;
49- }
50- analogData . push ( {
51- key,
52- value,
53- } ) ;
54- }
55-
56- if ( useDevice . onanalogreport ) {
57- useDevice . onanalogreport ( { data : analogData } ) ;
58- } else {
59- console . warn ( "No onanalogreport event listener" ) ;
60- }
61- } ) ;
62-
87+ await initDevice ( useDevice ) ;
6388 onConnect ( useDevice ) ;
6489 }
6590 } , [ onConnect ] ) ;
6691
92+ useEffect ( ( ) => {
93+ const handler = async ( event : HIDConnectionEvent ) => {
94+ console . log ( "Device disconnected" , event ) ;
95+ if ( device === event . device ) {
96+ await device . close ( ) ;
97+ onDisconnect ( device ) ;
98+ }
99+ } ;
100+
101+ navigator . hid . addEventListener ( "disconnect" , handler ) ;
102+
103+ // Cleanup
104+ return ( ) => {
105+ navigator . hid . removeEventListener ( "disconnect" , handler ) ;
106+ } ;
107+ } , [ device , onDisconnect ] ) ;
108+
67109 return (
68- < button className = "bg-blue-500 text-white p-2 rounded-md" onClick = { onClick } >
69- Connect Device
70- </ button >
110+ < div >
111+ < button
112+ className = "bg-blue-500 text-white p-2 rounded-md"
113+ onClick = { onClick }
114+ onKeyDown = { ( e ) => {
115+ e . preventDefault ( ) ;
116+ } }
117+ >
118+ { device ? `${ device . productName } Connected` : "Connect Device" }
119+ </ button >
120+ { showForgetButton && device && (
121+ < button
122+ onClick = { async ( ) => {
123+ if ( device ) {
124+ await device . forget ( ) ;
125+ onDisconnect ( device ) ;
126+ }
127+ } }
128+ >
129+ x
130+ </ button >
131+ ) }
132+ </ div >
71133 ) ;
72134}
73135
0 commit comments