TWebBrowser 中方向键切换控件
Arrow keys switching control in TWebBrowser
我在 TWebBrowser
(MSHTML/IE) 处理 arrow-keys 时遇到问题。
基本上,如果我托管 TWebBrowser
并加载一个 HTML 文件,它会显示不正确并且箭头键有效。如果我添加注册表项 FEATURE_BROWSER_EMULATION
或使用 X-UA-Compatible
meta header 它会正确呈现 HTML 但箭头键停止工作(他们确实工作,但他们想“制表”到其他控件,因此内容滚动不再有效)。看起来好像键在 TWebBrowser
.
处理之前(或之后)下降到主窗体
我通过处理 keydown 事件然后使用类似的东西找到了解决方案:
WebBrowser1->Document->parentWindow->scrollBy(0, 100);
这个解决方案有效,但我发现了一些更好的东西,我正在尝试将其转化为 Delphi/C++ Builder:
我找到的这段 C# 代码执行以下操作:
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;
}
}
我可以做类似的事情,在表单上将 KeyPreview
设置为 true
,然后处理 VK_LEFT / VK_RIGHT / VK_DOWN / VK_UP 窗体的KeyDown事件中的键,或者使用其他消息处理或ApplicationEvents,将Key设置为0(或Handled为true
,效果相同)例如:
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;}
}
}
问题是,这不是一回事。 IsInputKey
,如果设置为 true
,似乎只处理上述 C# 代码中 TWebBrowser
控件的键,但我在 [=55] 中找不到这样的等效项=]++ 生成器。
知道如何放弃托管 TWebBrowser
的 Delphi/C++Builder 主窗体的键处理,只让 TWebBrowser
只处理键事件对于上面的箭头键?
加载到 WebBrowser 控件的测试 HTML(如果使用箭头键测试它不可滚动,只需增加 <div>
标签中的字体大小:
<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>
要重现的代码 - 创建一个带有 TWebBrowser
和 TButton
的表单并将其添加到 TButton
代码中:(单击进入控件 - 鼠标滚轮有效,第 [=58 页=] 有效,箭头 up/down 想要“制表”到按钮(或其他控件)中:
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>");
}
感谢@whosrdaddy - 以下解决方案有效(取自here)。关键是 IsDialogMessage
函数。
// 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;
我在 TWebBrowser
(MSHTML/IE) 处理 arrow-keys 时遇到问题。
基本上,如果我托管 TWebBrowser
并加载一个 HTML 文件,它会显示不正确并且箭头键有效。如果我添加注册表项 FEATURE_BROWSER_EMULATION
或使用 X-UA-Compatible
meta header 它会正确呈现 HTML 但箭头键停止工作(他们确实工作,但他们想“制表”到其他控件,因此内容滚动不再有效)。看起来好像键在 TWebBrowser
.
我通过处理 keydown 事件然后使用类似的东西找到了解决方案:
WebBrowser1->Document->parentWindow->scrollBy(0, 100);
这个解决方案有效,但我发现了一些更好的东西,我正在尝试将其转化为 Delphi/C++ Builder:
我找到的这段 C# 代码执行以下操作:
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;
}
}
我可以做类似的事情,在表单上将 KeyPreview
设置为 true
,然后处理 VK_LEFT / VK_RIGHT / VK_DOWN / VK_UP 窗体的KeyDown事件中的键,或者使用其他消息处理或ApplicationEvents,将Key设置为0(或Handled为true
,效果相同)例如:
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;}
}
}
问题是,这不是一回事。 IsInputKey
,如果设置为 true
,似乎只处理上述 C# 代码中 TWebBrowser
控件的键,但我在 [=55] 中找不到这样的等效项=]++ 生成器。
知道如何放弃托管 TWebBrowser
的 Delphi/C++Builder 主窗体的键处理,只让 TWebBrowser
只处理键事件对于上面的箭头键?
加载到 WebBrowser 控件的测试 HTML(如果使用箭头键测试它不可滚动,只需增加 <div>
标签中的字体大小:
<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>
要重现的代码 - 创建一个带有 TWebBrowser
和 TButton
的表单并将其添加到 TButton
代码中:(单击进入控件 - 鼠标滚轮有效,第 [=58 页=] 有效,箭头 up/down 想要“制表”到按钮(或其他控件)中:
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>");
}
感谢@whosrdaddy - 以下解决方案有效(取自here)。关键是 IsDialogMessage
函数。
// 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;