delphiwebviewfiremonkey

Input rendered in TWebBrowser using Edge keeps unfocusing when clicked


In my FMX application I have a webpage that I'm rendering inside a TWebBrowser. The webpage has a simple <input>, but on Windows if I click the input it focuses and immediately unfocuses. After clicking a seemingly random number of times it stops unfocusing.

But if I AltTab to another application and back the problem happens again.

I have a very simple setup that reproduces the issue. I have an FMX application with just this code added:

procedure TForm1.FormCreate(Sender: TObject);
begin
  var browser := TWebBrowser.Create(Self);
  browser.WindowsEngine := TWindowsEngine.EdgeOnly;
  browser.Align := TAlignLayout.Client;
  browser.URL := 'http://localhost:8000/test.html';
  Self.AddObject(browser);
end;

I also have a test.html file with this content:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Test</title>
  </head>
  <body>
    <input type="text" name="test">
  </body>
</html>

I'm using Python to start a HTTP server so I can load test.html in the browser.

I've also added WebView2Loader.dll so .EdgeOnly works. Now if I use .IEOnly I don't have the issue, but I need to use .EdgeOnly for other stuff. It's not an option for me to use .IEOnly.

Anybody had this issue before?

Update: If I have a second screen connected to my laptop the issue does not happen.


Solution

  • Seems to be a bug in FMX.WebBrowser.Win

    I found that if I comment out SetFocus call in code below

    FWebViewController.Add_GotFocus(
      Callback<ICoreWebView2, IUnknown>
        .CreateAs<ICoreWebView2FocusChangedEventHandler>(
          function(const WebView: ICoreWebView2; const Args: IUnknown): HResult; stdcall
          begin
            Result := S_OK;
            FWebViewFocusEventActive := True;
            SetFocus;
            FWebViewFocusEventActive := False;
          end
        ),
        FGotFocusToken);
    

    it works.

    SetFocus looks like this

    procedure TWinPresentation.SetFocus;
    begin
      Winapi.Windows.SetFocus(Handle);
    end;
    

    Compared to vcl version in VCL.Edge which does this

    FWebViewController.Add_GotFocus(
      Callback<ICoreWebView2, IUnknown>
        .CreateAs<ICoreWebView2FocusChangedEventHandler>(
          function(const WebView: ICoreWebView2; const Args: IUnknown): HResult; stdcall
          begin
            Result := S_OK;
            FWebViewFocusEventActive := True;
            DoEnter;
            FWebViewFocusEventActive := False;
          end
        ), FGotFocusToken);
    
    procedure TCustomEdgeBrowser.DoEnter;
    begin
      inherited;
      if not FWebViewFocusEventActive and (FWebViewController <> nil) then
        ProcessHResult(
         WebViewController.MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC));
    end;
    

    As you can see vcl version uses FWebViewFocusEventActive to skip changing focus on gotfocus event handler call but fmx version does set focus. So I think they wrongly copied vcl behavior here.

    I'll make a bug report for this.