Search code examples
wpfon-screen-keyboardwebview2

Can WebView2 currently receive Keyboard inputs?


I am trying to create a software in WPF which hosts a browser (WebView2 currently 1.0.818.41) and also show a OnScreenKeyboard when there is a input field focused in the browser.

I have done this kind of stuff with CefSharp in WPF before but I cannot do it with WebView2 currently. My problem is I do not find a way to send keystrokes from the OnScreenKeyboard (or from the WPF Window) to the Browser.

In CefSharp there we have a function called ChromiumWebBrowser.GetHost().SendKeyEvent() but I cannot find something similar in WebView2.

Am I blind or is this something which is currently not implemented (or maybe not planned)?

Thank you in advance!


Solution

  • There is no direct way. What can be done is execute some JS, which in turn posts a message to WebView. This message can then be caught back in wv2_WebMessageReceived event.

    There is extensive documentation on the interop between.NET and JS and interop between JS and .NET WPF Forms here.

    A solution would be to inject a sendMessage JS function in the NavigationStarting event:

    private void wv2_NavigationStarting(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationStartingEventArgs args){
    var sc = "function sendMessage(txt) { window.chrome.webview.postMessage(txt); }";
                wv2.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(sc);
            }
    

    Now you collect input fields and add onfocus and onblur events to these input fields for example in the NavigationCompleted event like this:

    private void wv2_NavigationCompleted(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs args){
         string script = "const collection ="+ 
                     "document.getElementsByTagName(\"input\");" +
                     "for (let i = 0; i < collection.length; i++){" +
                     "collection[i].onfocus= ()=>{ sendMessage('onFocus('+collection[i].name')'); }; " +
                     "collection[i].onblur= (ev)=>{ sendMessage('onBlur('+collection[i].name')'); };"+
                     "}";
         sender.ExecuteScriptAsync(script);
    }
    

    Now catch the message in the wv2_WebMessageReceived event:

    private void wv2_WebMessageReceived(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2WebMessageReceivedEventArgs args)
            {
                var postMess = args.TryGetWebMessageAsString();
                
                if (postMess == "onFocus(nameOfField)" )
                {
                    // here activate the button(keyboard)
                     // store the Name on focusField variable
    
                }
                if (postMess == "onBlur" && paneShown)
                {
                   // here deactivate the button(keyboard)
                    // release the focusField
    
                }
            }
    

    Now you can send a click event to the input fields:

    private void btn_Clicked(Object sender, EventArgs args)
            {
                var script = "var field "+
                             "= document.getElementsByName("+focusField+");" +
                             " field.value+=field.value"+args.keyValue();
                 wv2.CoreWebView2.ExecuteScriptAsync(script);
            }
    

    wv2 is an instance of WebView2 and the code is typed directly here and not compiled. Hope you get the idea.