Home > front end >  TEdgeBrowser for Delphi 10.4.1 and later: How to trap F12 (OpenDevToolsWindow)?
TEdgeBrowser for Delphi 10.4.1 and later: How to trap F12 (OpenDevToolsWindow)?

Time:11-30

I am using TEdgeBrowser in Delphi 10.4.1. It works very well.

The only nagging issue is, when TEdgeBrowser has focus, it grabs F12 and CTRL SHIFT C and presents the OpenDevToolsWindow. This is great, except I want to change some of the topmost properties of the Form before it loads (otherwise, the DevTools window will be behind the MainForm).

Is there any way to trap F12 from the parent MainForm? I have tried Application and MainForm key captures, but both fail to capture the TEdgeBrowser key events (when TEdgeBrowser has focus).

procedure TMainForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  case Msg.Message of
    WM_KEYDOWN, WM_KEYUP:
      begin
      if Msg.WParam = VK_F11 then
         begin
         SetStatusLog(EID_KEYPRESS,'F11');
         Handled := true;
         end
      else if Msg.WParam = VK_F12 then
         begin
{ do something here and consider F12 handled, preventing F12 from going to TEdgeBrowser???}
         SetStatusLog(EID_KEYPRESS,'F12');
         Handled := true;
         end;
      end;
  end;
end;

Is there another way to tackle this?

Additionally, can I launch the OpenDevToolsWindow programmably?

CodePudding user response:

@stackman

I cannot seem to use the recommended solution because it requires changes to the page code. I would like to point EdgeBrowser to any site and still have control over keypress.

procedure TForm1.Button1Click(Sender: TObject);
{$J }
const
  STEP: integer = 1;
var
 Js: string;
begin
  case STEP of
    1: web.CreateWebView;
    2: web.Navigate('https://stackoverflow.com/questions/70089520/tedgebrowser-for-delphi-10-4-1-and-later-how-to-trap-f12-opendevtoolswindow?noredirect=1#comment123929534_70089520');
    3: begin //Step 2 must have finished!
         Js := Concat('aaa = new Object; ',
                      'aaa.Message = function(Msg) ',
                      '{ ',
                      '   alert(Msg); ',
                      '}');
                      //DevTools-->Console: type aaa
                      web.ExecuteScript(Js);

        end;
     else
        begin
          Js := 'aaa.Message("Hallo Welt!")';
          web.ExecuteScript(Js);
        end;
   end;
   STEP := STEP   1;
 end;

Console Source

CodePudding user response:

I have used two ways to handle this. (1) You can call Set_AreBrowserAcceleratorKeysEnabled(0) to disable the browser's accelerator keys (but that might include disabling more than you want. And it requires some additional work to get access to this interface as it is not included in the current TEdgeBrowser (2) Use the AddScriptToExecuteOnDocumentCreated to inject some Javascript that will prevent the default behavior and send your app a message (which you'll pick up on OnWebMessageReceived) so you can process the event.

Option 1:

You'll need to define the following to get access to the interfaces you need as they were introduced after what TEdgeBrowser has:

const
  IID_ICoreWebview2Settings2: TGUID = '{EE9A0F68-F46C-4E32-AC23-EF8CAC224D2A}'; //Introduced: SDK  1.0.864.35
  IID_ICoreWebview2Settings3: TGUID = '{FDB5AB74-AF33-4854-84F0-0A631DEB5EBA}'; //Introduced: SDK  1.0.864.35

type
  ICoreWebView2Settings2 = interface(ICoreWebView2Settings)
    ['{EE9A0F68-F46C-4E32-AC23-EF8CAC224D2A}']
    function Get_UserAgent(out UserAgent: PWideChar): HResult; stdcall;
    function Set_UserAgent(UserAgent: PWideChar): HResult; stdcall;
  end;

  ICoreWebView2Settings3 = interface(ICoreWebView2Settings2)
    ['{FDB5AB74-AF33-4854-84F0-0A631DEB5EBA}']
    function Get_AreBrowserAcceleratorKeysEnabled(out AreBrowserAcceleratorKeysEnabled: Integer): HResult; stdcall;
    function Set_AreBrowserAcceleratorKeysEnabled(AreBrowserAcceleratorKeysEnabled: Integer): HResult; stdcall;
  end;

Then in your OnCreateWebViewCompleted event you can do

var
  Settings3: ICoreWebView2Settings3;
  HR: HRESULT;
begin
  Sender.SettingsInterface.QueryInterface(IID_ICoreWebView2Settings3, Settings3);
  if Assigned(Settings3) then
  begin
    HR := Settings3.Set_AreBrowserAcceleratorKeysEnabled(0);
    if not SUCCEEDED(HR) then
      {Do something - Set_AreBrowserAcceleratorKeysEnabled failed};
  end
  else
    {Do something - ICoreWebView2Settings3 interface not found.};
  end;  

Option 2:

In your OnCreateWebViewCompleted event you can do the following

const
  JavaScript =
    '  document.addEventListener(''keydown'', function(event){'   sLineBreak  
    '    if (event.code == "F12") {'   sLineBreak  
    '      Result = "#KEY_EVENT#"   event.code;'   sLineBreak  
    '      event.preventDefault();'   sLineBreak  
    '      window.chrome.webview.postMessage(Result);'   sLineBreak  
    '    };'   sLineBreak  
    '  });'; 

{...}                                                                       
begin
  Sender.DefaultInterface.AddScriptToExecuteOnDocumentCreated(JavaScript,
    Callback<HResult, PChar>.CreateAs<ICoreWebView2AddScriptToExecuteOnDocumentCreatedCompletedHandler>(
    function(ErrorCode: HResult; Id: PWideChar): HResult stdcall
    begin
      if not(Succeeded(ErrorCode)) then
        {Do something if this function failed.  It gets called later when a document id created.  Or you can pass nil for the Callback};
      Result := 1;
    end));

Note, in Option 2, see TEdgeBrowser code as example for defining the Callback. It is defined in the implementation part of TEdgeBrowser. I just replicated it in my own form's unit implementation section.

  • Related