@@ -1020,89 +1020,115 @@ callFakeMenu["exit"] = () => {
10201020 } )
10211021}
10221022
1023- const devicesHID = { } ;
1024-
10251023let deviceDialogOpen = false ;
1024+ // Track callbacks we've already used so we never call the same Electron callback twice
1025+ const usedHIDCallbacks = new WeakSet ( ) ;
10261026
10271027const createHIDDialog = ( deviceList , cbk ) => {
1028- if ( deviceDialogOpen ) return ;
1028+ // If Electron passes us a callback we've already used, never touch it again.
1029+ if ( usedHIDCallbacks . has ( cbk ) ) {
1030+ console . log ( 'HID: callback already used, ignoring this event' ) ;
1031+ return ;
1032+ }
1033+
1034+ // If a dialog is already open, ignore new events and let the existing
1035+ // dialog eventually resolve its callback.
1036+ if ( deviceDialogOpen ) {
1037+ console . log ( 'HID: dialog already open, ignoring this event' ) ;
1038+ return ;
1039+ }
10291040
10301041 deviceDialogOpen = true ;
10311042 let done = false ;
10321043
1033- console . log ( 'HID Dialog!' ) ;
1044+ const finish = ( id ) => {
1045+ if ( done ) return ; // never call the same callback more than once
1046+ done = true ;
1047+ deviceDialogOpen = false ;
10341048
1035- const win = new BrowserWindow ( {
1036- vibrancy : "sidebar" , // in my case...
1037- frame : true ,
1038- show : false ,
1039- titleBarStyle : 'hiddenInset' ,
1040- width : 400 ,
1041- height : 300 ,
1042- resizable : false ,
1043- title : 'Device selector' ,
1044- webPreferences : {
1045- preload : path . join ( __dirname , 'preload_device.js' ) ,
1046- webSecurity : false ,
1047- //nodeIntegration: true
1049+ if ( ! usedHIDCallbacks . has ( cbk ) ) {
1050+ usedHIDCallbacks . add ( cbk ) ;
10481051 }
1049- } ) ;
1050-
1051- win . loadFile ( path . join ( __dirname , 'device.html' ) ) ;
10521052
1053- win . on ( 'ready-to-show' , ( ) => {
1053+ try {
1054+ cbk ( id ) ;
1055+ } catch ( err ) {
1056+ console . error ( 'Error in HID callback:' , err ) ;
1057+ }
1058+ } ;
10541059
1055- const list = deviceList . map ( ( e ) => {
1056- return { name : e . name || e . deviceName , id : e . deviceId }
1060+ console . log ( 'HID Dialog (dialog.showMessageBox)!' ) ;
1061+
1062+ const list = ( deviceList || [ ] ) . map ( ( e ) => ( {
1063+ name : e . name || e . deviceName || 'Unknown device' ,
1064+ id : e . deviceId
1065+ } ) ) ;
1066+
1067+ // No devices -> show info dialog, then "cancel" selection
1068+ if ( ! list . length ) {
1069+ dialog . showMessageBox ( {
1070+ type : 'info' ,
1071+ buttons : [ 'OK' ] ,
1072+ defaultId : 0 ,
1073+ title : 'Device selector' ,
1074+ message : 'No devices available' ,
1075+ detail : 'No HID-compatible devices are currently available. Please connect a device and try again.' ,
1076+ noLink : true ,
1077+ normalizeAccessKeys : true
1078+ } )
1079+ . finally ( ( ) => {
1080+ finish ( '' ) ; // signal "no selection"
10571081 } ) ;
1058- console . log ( deviceList ) ;
1059-
10601082
1061- win . webContents . send ( 'load' , {
1062- list : list
1063- } ) ;
1064-
1065- ipcMain . once ( 'choise_hid' , ( e , id ) => {
1066- done = true ;
1067- cbk ( id ) ;
1068- win . close ( ) ;
1069- } ) ;
1083+ return ;
1084+ }
10701085
1071- win . show ( ) ;
1072- } ) ;
1086+ const buttons = list . map ( d => d . name ) ;
1087+ buttons . push ( 'Cancel' ) ;
1088+ const cancelId = buttons . length - 1 ;
10731089
1074- win . on ( 'close' , ( ) => {
1075- deviceDialogOpen = false ;
1076- if ( done ) return ;
1077- cbk ( '' ) ;
1090+ dialog . showMessageBox ( {
1091+ type : 'question' ,
1092+ buttons,
1093+ cancelId,
1094+ defaultId : 0 ,
1095+ title : 'Device selector' ,
1096+ message : 'Select a HID device' ,
1097+ detail : 'Choose the device you want to use from the list below.' ,
1098+ noLink : true ,
1099+ normalizeAccessKeys : true
10781100 } )
1079- }
1101+ . then ( ( { response } ) => {
1102+ if ( response === cancelId ) {
1103+ finish ( '' ) ;
1104+ } else {
1105+ const selected = list [ response ] ;
1106+ finish ( selected ? selected . id : '' ) ;
1107+ }
1108+ } )
1109+ . catch ( ( err ) => {
1110+ console . error ( 'Error showing HID selection dialog:' , err ) ;
1111+ finish ( '' ) ;
1112+ } ) ;
1113+ } ;
10801114
10811115/* permissions for the main window, special headers */
10821116const setHID = ( /** @type {BrowserWindow } */ mainWindow ) => {
10831117
10841118
10851119 mainWindow . webContents . on ( 'select-bluetooth-device' , ( event , deviceList , callback ) => {
1086- console . log ( 'Select HID' ) ;
1087-
1120+ console . log ( 'Select HID (bluetooth)' ) ;
10881121 event . preventDefault ( ) ;
1089- //select bluetooth
1090- console . log ( 'select bluetooth' ) ;
10911122 createHIDDialog ( deviceList , callback ) ;
10921123 return false ;
10931124 } ) ;
1094-
1125+
10951126 mainWindow . webContents . session . on ( 'select-hid-device' , ( event , details , callback ) => {
1096- // Add events to handle devices being added or removed before the callback on
1097- // `select-hid-device` is called.
10981127 console . log ( 'Select HID' ) ;
1099-
11001128 event . preventDefault ( ) ;
1101-
1102- console . log ( 'select hid' ) ;
11031129 createHIDDialog ( details . deviceList , callback ) ;
11041130 return false ;
1105- } )
1131+ } ) ;
11061132
11071133 mainWindow . webContents . session . setPermissionCheckHandler ( ( webContents , permission , requestingOrigin , details ) => {
11081134 return true
0 commit comments