WebViewGadget PermissionRequested callback

Share your advanced PureBasic knowledge/code with the community.
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

WebViewGadget PermissionRequested callback

Post 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:
Last edited by infratec on Fri Oct 25, 2024 4:15 pm, edited 7 times in total.
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget permission callback

Post 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()
dige
Addict
Addict
Posts: 1391
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: WebViewGadget permission callback

Post by dige »

Great stuff! Now I can finally build my own notebook with voice input and directly integrate ChatGPT for certain tasks. :D
"Daddy, I'll run faster, then it is not so far..."
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget permission callback

Post by infratec »

Updated a view things and fixed a bug in Remove.
User avatar
mk-soft
Always Here
Always Here
Posts: 6201
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: WebViewGadget permission callback

Post by mk-soft »

Nice ;)

For Linux see WebGadget Extensions
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 772
Joined: Fri Dec 04, 2015 9:26 pm

Re: WebViewGadget PermissionRequested callback

Post by skinkairewalker »

works in mac ??
infratec
Always Here
Always Here
Posts: 7575
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: WebViewGadget PermissionRequested callback

Post by infratec »

No, this code works only in windows (WebView2), but macOS uses webkit, so maybe mk-softs code can be adopted.
Post Reply