Page 1 of 1

WebViewGadget PermissionRequested callback

Posted: Fri Oct 04, 2024 10:57 am
by infratec
To avoid question for allowing access to mic or camera, you need the permission callback.

It is based on the code from breese4me:
viewtopic.php?p=628089#p628089

Save it as WebViewPermissionCallback.pbi

Code: Select all

;
; https://www.purebasic.fr/english/viewtopic.php?p=628744
;

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

CompilerIf Not Defined(IID_IUnknown, #PB_Label)
  DataSection
    IID_IUnknown:
    Data.l $00000000
    Data.w $0000, $0000
    Data.b $C0, $00, $00, $00, $00, $00, $00, $46
  EndDataSection
CompilerEndIf

CompilerIf Not Defined(IUnknownBase_Structure, #PB_Structure)
  Structure IUnknownBase_Structure
    *pVtable
    lRefCount.l
    *pQueryInterface
    *pAddRef
    *pRelease
  EndStructure
CompilerEndIf


Prototype.i WebViewPermissionCallBack_Prototype(Type.i)

Structure ICoreWebView2PermissionRequestedEventHandler_Structure Extends IUnknownBase_Structure
  *pInvoke
  Token.q
  *pCallback.WebViewPermissionCallBack_Prototype
EndStructure


Global NewMap WebViewPermissionRequestedEventHandlerMap.ICoreWebView2PermissionRequestedEventHandler_Structure()




Procedure.l ICoreWebView2PermissionRequestedEventHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
  
  Protected Result.l
  
  
  Debug "WebView PermissionRequested QueryInterface"
  
  Result = #S_OK
  
  If *ppvObject And *riid
    If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
      *this\lRefCount + 1
      *ppvObject\i = *this
    Else
      *ppvObject\i = 0
      Result = #E_NOINTERFACE
    EndIf
  Else
    Result = #E_POINTER
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




Procedure.l ICoreWebView2PermissionRequestedEventHandler_AddRef(*this.IUnknownBase_Structure)
  
  Debug "WebView PermissionRequested AddRef"
  
  *this\lRefCount + 1
  
  ProcedureReturn *this\lRefCount
  
EndProcedure




Procedure.l ICoreWebView2PermissionRequestedEventHandler_Release(*this.IUnknownBase_Structure)
  
  Debug "WebView PermissionRequested Release"
  
  *this\lRefCount - 1
  
  ProcedureReturn *this\lRefCount
  
EndProcedure




Enumeration COREWEBVIEW2_PERMISSION_KIND
  #UnknownPermission = 0            ; Indicates an unknown permission.
  #Microphone = 1                   ; Indicates permission To capture audio.
  #Camera =	2                       ; Indicates permission To capture video.
  #Geolocation = 3                  ; Indicates permission To access geolocation.
  #Notifications = 4                ; Indicates permission To send web notifications. Apps that would like To show notifications should handle PermissionRequested And/Or PermissionRequested events And no browser permission prompt will be shown For notification requests. Note that push notifications are currently unavailable in WebView2.
  #OtherSensors = 5                 ; Indicates permission To access generic sensor. Generic Sensor covers ambient-light-sensor, accelerometer, gyroscope, And magnetometer.
  #ClipboardRead = 6                ; Indicates permission To Read the system clipboard without a user gesture.
  #MultipleAutomaticDownloads = 7   ; Indicates permission To automatically download multiple files. Permission is requested when multiple downloads are triggered in quick succession.
  #FileReadWrite =	8               ; Indicates permission To Read And write To files Or folders on the device. Permission is requested when developers use the File System Access API To show the file Or folder picker To the End user, And then request "readwrite" permission For the user's selection.
  #Autoplay = 9                     ; Indicates permission To play audio And video automatically on sites. This permission affects the autoplay attribute And play method of the audio And video HTML elements, And the start method of the Web Audio API. See the Autoplay guide For media And Web Audio APIs For details.
  #LocalFonts = 10                  ; Indicates permission To use fonts on the device. Permission is requested when developers use the Local Font Access API To query the system fonts available For styling web content.
  #MidiSystemExclusiveMessages = 11 ; Indicates permission To send And receive system exclusive messages To/from MIDI (Musical Instrument Digital Interface) devices. Permission is requested when developers use the Web MIDI API To request access To system exclusive MIDI messages.
  #WindowManagement = 12            ; Indicates permission to open and place windows on the screen. Permission is requested when developers use the Multi-Screen Window Placement API to get screen details.
EndEnumeration


Enumeration COREWEBVIEW2_PERMISSION_STATE
  #Default = 0  ; Specifies that the Default browser behavior is used, which normally prompts users For decision.
  #Allow = 1    ; Specifies that the permission request is granted.
  #Deny = 2     ; Specifies that the permission request is denied.
EndEnumeration


Procedure.l ICoreWebView2PermissionRequestedEventHandler_Invoke(*this.ICoreWebView2PermissionRequestedEventHandler_Structure, *sender.ICoreWebView2, *args.ICoreWebView2PermissionRequestedEventArgs)
  
  Protected PermissionKind.i, *def.ICoreWebView2Deferral, State.i
  
  
  Debug "WebView PermissionRequested Invoke"
  
  *args\GetDeferral(@*def)
  If *args\get_PermissionKind(@PermissionKind) = #S_OK
    State = *this\pCallback(PermissionKind)
    *args\put_State(State)
  EndIf
  *def\Complete()
  
  ProcedureReturn #S_OK
  
EndProcedure




Procedure WebViewRemovePermissionRequestedCallback(WebView.i, Core.ICoreWebView2)
  
  If FindMapElement(WebViewPermissionRequestedEventHandlerMap(), Str(WebView))
    
    If WebViewPermissionRequestedEventHandlerMap()\Token
      If Core
        Core\remove_PermissionRequested(WebViewPermissionRequestedEventHandlerMap()\Token)
      EndIf
    EndIf
    
    DeleteMapElement(WebViewPermissionRequestedEventHandlerMap())
  EndIf
  
EndProcedure




Procedure.i WebViewAddPermissionRequestedCallback(WebView, *Callback.WebViewPermissionCallBack_Prototype)
  
  Protected Result.i
  Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
  Protected *EventHandler.ICoreWebView2PermissionRequestedEventHandler_Structure
  
  
  If GadgetType(WebView) = #PB_GadgetType_WebView And *Callback <> #Null
    
    Controller = GetGadgetAttribute(WebView, #PB_WebView_ICoreController)
    If Controller
      
      If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
        
        WebViewRemovePermissionRequestedCallback(WebView, Core)
        
        *EventHandler = AddMapElement(WebViewPermissionRequestedEventHandlerMap(), Str(WebView))
        If *EventHandler
          *EventHandler\pVtable = *EventHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
          *EventHandler\pQueryInterface = @ICoreWebView2PermissionRequestedEventHandler_QueryInterface()
          *EventHandler\pAddRef = @ICoreWebView2PermissionRequestedEventHandler_AddRef()
          *EventHandler\pRelease = @ICoreWebView2PermissionRequestedEventHandler_Release()
          *EventHandler\pInvoke = @ICoreWebView2PermissionRequestedEventHandler_Invoke()
          
          *EventHandler\pCallback = *Callback
                        
          If Core\add_PermissionRequested(*EventHandler, @*EventHandler\Token) = #S_OK
            ;Debug *EventHandler\Token
            Result = #True
          Else
            WebViewRemovePermissionRequestedCallback(WebView, Core)
          EndIf
            
        EndIf
        
        Core\Release()
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure




CompilerIf #PB_Compiler_IsMainFile
  
  ;-Demo
  
  
  Procedure.i PermissionRequestedCallback(PermissionKind.i)
    
    Protected.i Permission
    
    
    Debug "PermissionKind: " + Str(PermissionKind)
    
    Select PermissionKind
      Case #Microphone  : Permission = #Allow
      Default           : Permission = #Default
    EndSelect
    
    ProcedureReturn Permission
    
  EndProcedure
  
  
  Procedure OutputJS(JsonParameters$)
    Debug "From Page" + JsonParameters$
  EndProcedure
  
  
  ;-Main
  Define Html$, Filename$, Event.i
  
  
  Html$ = ~"<!DOCTYPE html>\n" +
          ~"<html lang=en>\n" +
          ~" <head>\n" +
          ~"  <title>Voice To Text</title>\n" +
          ~" </head>\n" +
          ~" <body>\n" +
          ~"  <div id=\"output\"></div>\n" +
          ~"  \n" +
          ~"  <script>\n" +
          ~"   const outputDiv = document.getElementById('output');\n" +
          ~"   \n" +
          ~"   const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition)();\n" +
          ~"   recognition.lang = 'en-US';\n" +
          ~"   recognition.continuous = true;\n" +
          ~"   recognition.interimResults = false;\n" +
          ~"   recognition.maxAlternatives = 1;\n" +
          ~"   recognition.start();\n" +
          ~"   \n" +
          ~"   recognition.onresult = (event) => {\n" +
          ~"    const transcript = event.results[event.resultIndex][0].transcript;\n" +
          ~"    outputDiv.textContent = transcript;\n" +
          ~"    window.output(transcript);\n" +
          ~"   };\n" +
          ~"   \n" +
          ~"  </script>\n" +
          ~" </body>\n" +
          ~"</html>\n"
  
  Debug Html$
  
  Filename$ = GetTemporaryDirectory() + "speech_transcription.html"
  If CreateFile(0, Filename$)
    WriteString(0, Html$)
    CloseFile(0)
  EndIf
  
  OpenWindow(0, 100, 100, 420, 460, "Live speech transcription", #PB_Window_SystemMenu)
  
  WebViewGadget(0, 0, 0, 420, 460, #PB_WebView_Debug)
  
  WebViewAddPermissionRequestedCallback(0, @PermissionRequestedCallback())
  
  ;SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)
  SetGadgetText(0, "file://" + Filename$)
  
  BindWebViewCallback(0, "output", @OutputJS())
  
  Repeat 
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
  
  DeleteFile(Filename$)
  
CompilerEndIf
With SetGadgetItemText() the html code is not working as expected.

To test if it is working, smply comment the line WebViewGadgetSetPermissionRequestedCallback(0, @PermissionRequestedCallback())
Then you should be asked to allow access.

Btw. a microphone needs to be attached. :wink:

Re: WebViewGadget permission callback

Posted: Sat Oct 05, 2024 9:57 am
by infratec
Optimized the speech reconition part of the demo.
It starts now immediately.

But still I don't know why SetGadgetItemText() does not the same as SetGadgetText()

Re: WebViewGadget permission callback

Posted: Sat Oct 05, 2024 1:57 pm
by dige
Great stuff! Now I can finally build my own notebook with voice input and directly integrate ChatGPT for certain tasks. :D

Re: WebViewGadget permission callback

Posted: Fri Oct 25, 2024 9:50 am
by infratec
Updated a view things and fixed a bug in Remove.

Re: WebViewGadget permission callback

Posted: Fri Oct 25, 2024 10:11 am
by mk-soft
Nice ;)

For Linux see WebGadget Extensions

Re: WebViewGadget PermissionRequested callback

Posted: Mon Mar 10, 2025 11:34 pm
by skinkairewalker
works in mac ??

Re: WebViewGadget PermissionRequested callback

Posted: Tue Mar 11, 2025 7:56 am
by infratec
No, this code works only in windows (WebView2), but macOS uses webkit, so maybe mk-softs code can be adopted.