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?
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 that is not really what you asked.) And it requires some additional work to get access to this interface as it is not included in the current TEdgeBrowser. Also, I read somewhere that the AcceleratorKey event still fires, even if you disable them in the EdgeBrowser so if you use that approach, you can process them. (2) Use the AddScriptToExecuteOnDocumentCreated to inject some Javascript that can prevent the default behavior (if desired) 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.