I have a problem with TWebBrowser
(MSHTML/IE) handling of arrow-keys.
Basically, if I host TWebBrowser
and load a HTML file, it displays it incorrectly and arrow keys work. If I add a registry key FEATURE_BROWSER_EMULATION
or use X-UA-Compatible
meta header it renders the HTML properly but arrow keys stop working (they do work, but they want to "tab" to other control so content scrolling no longer works). It looks as if the keys drop to the main form before (or after) being processed by the TWebBrowser
.
I found a solution by handling keydown event and then using something like:
WebBrowser1->Document->parentWindow->scrollBy(0, 100);
This solution works, but I found something better which I'm trying to translate into Delphi/C++ Builder:
This C# code I found does the following:
private void webBrowser1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
{
e.IsInputKey = true;
return;
}
}
I can do something similar with KeyPreview
set to true
on the form and then handling the VK_LEFT / VK_RIGHT / VK_DOWN / VK_UP keys in the KeyDown event of the form, or use other message handling or ApplicationEvents, to set the Key to 0 (or Handled to true
, same effect) for example:
void __fastcall TForm1::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
if (Msg.message == WM_KEYDOWN && ActiveControl &&
ActiveControl->InheritsFrom(__classid(TWebBrowser))
)
{
if (Msg.wParam == VK_LEFT) {Handled = true; return;}
if (Msg.wParam == VK_RIGHT) {Handled = true; return;}
if (Msg.wParam == VK_UP) {Handled = true; return;}
if (Msg.wParam == VK_DOWN) {Handled = true; return;}
}
}
Problem is, it is not the same thing. IsInputKey
, if set to true
, appears to process the keys only for the TWebBrowser
control in the above C# code, but there is no such equivalent that I've found in Delphi/C++ Builder.
Any idea how I can drop key processing for the Delphi/C++Builder main form which hosts the TWebBrowser
and only let the TWebBrowser
do the processing of the key event only for the arrow keys above?
A test HTML to load into WebBrowser control (if it is not scrollable for testing with arrow keys, simply increase the size of the font in the <div>
tag:
<html>
<head>
<!-- This meta tag ensures that TWebBrowser runs in IE-11 mode -->
<!-- Which causes issues with scrolling with arrow keys -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
<div style="font-size:36px;">
01<br>
02<br>
03<br>
04<br>
05<br>
06<br>
07<br>
08<br>
09<br>
10<br>
11<br>
12<br>
13<br>
14<br>
15<br>
16<br>
17<br>
18<br>
19<br>
20<br>
21<br>
22<br>
23<br>
24<br>
25<br>
26<br>
27<br>
28<br>
29<br>
30<br>
</div>
</body>
</html>
Code to reproduce - Create a form with a TWebBrowser
and a TButton
and add this into TButton
code: (clicking into control - mouse wheel works, page up/down works, arrows up/down want to "tab" into the button (or other control):
void __fastcall TForm1::Button1Click(TObject *Sender)
{
WebBrowser1->Navigate("about:<html><head><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"></head><body><div style=\"font-size:36px;\">01<br>02<br>03<br>04<br>05<br>06<br>07<br>08<br>09<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br></div></body></html>");
}
Thanks to @whosrdaddy - The following solution has worked (taken from here). The key was IsDialogMessage
function.
// FIX voor webbrowser keys, install application wide message handler
constructor TBrowserHelper.Create(ADebug : TDebuggerSlot);
begin
Debug := ADebug;
if Assigned(Debug) then
Debug.OutputL(Self, 'Create', '', LVL_SPARSE);
OldMessageHandler := Application.OnMessage;
Application.OnMessage := MsgHandler;
end;
destructor TBrowserHelper.Destroy;
begin
if Assigned(Debug) then
Debug.OutputL(Self, 'Destroy', '', LVL_SPARSE);
Application.OnMessage := OldMessageHandler;
inherited;
end;
procedure TBrowserHelper.MsgHandler(var Msg: TMsg; var Handled: Boolean);
const StdKeys = [VK_BACK, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT];
var IOIPAO: IOleInPlaceActiveObject;
Browser : TEmbeddedWb;
begin
try
Browser := nil;
if Assigned(Screen.ActiveForm) then
begin
if Screen.ActiveForm is TFrm_Browser then
Browser := TFrm_Browser(Screen.ActiveForm).Browser;
if Assigned(Browser) then
begin
Handled := IsDialogMessage(Browser.Handle, Msg);
if Handled then//and (not Browser.Busy) then
begin
// if Assigned(Debug) then
// Debug.OutputL(Self, 'MsgHandler', Format('Message: %x, wParam: %x, lParam: %x', [Msg.message, Msg.wParam, Msg.lParam]), LVL_FULL);
if ((Msg.message = WM_KEYDOWN) or (Msg.message = WM_KEYUP)) and (Msg.wParam in StdKeys) then
begin
//nothing - do not pass on Backspace, Left, Right, Up, Down arrows
end
else
begin
IOIPAO := (Browser.Application as IOleInPlaceActiveObject);
if Assigned(IOIPAO)then
IOIPAO.TranslateAccelerator(Msg)
end;
end;
end;
end;
except
//Handled := False; // leave it for other handlers
end;
end;
initialization
begin
iCaptSize := GetSystemMetrics(SM_CYCAPTION);
iBorderSize := GetSystemMetrics(SM_CXBORDER);
iBorderThick := GetSystemMetrics(SM_CXSIZEFRAME);
BrowserHelper := TBrowserHelper.Create(nil);
end;
finalization
begin
if Assigned(BrowserHelper) then
FreeAndNil(BrowserHelper);
end;