WebBrowser键盘快捷键

9
我有一个显示HTML的WebBrowser控件。
我希望用户能够复制整个文档,但不能进行其他操作。

我将IsWebBrowserContextMenuEnabledWebBrowserShortcutsEnabled属性设置为false,并希望在用户按下Ctrl+C时处理KeyUp并运行一些代码。

我该怎么做?
WebBrowser控件不支持键盘事件。
我尝试使用表单的KeyUp事件和KeyPreview,但它根本没有触发。

编辑:这是我的解决方案,受Jerb答案的启发。

class CopyableWebBrowser : WebBrowser {
    public override bool PreProcessMessage(ref Message msg) {
        if (msg.Msg == 0x101    //WM_KEYUP
         && msg.WParam.ToInt32() == (int)Keys.C && ModifierKeys == Keys.Control) {
            DoCopy();
            return true;
        }
        return base.PreProcessMessage(ref msg);
    }
    void DoCopy() {
        Document.ExecCommand("SelectAll", false, null);
        Document.ExecCommand("Copy", false, null);
        Document.ExecCommand("Unselect", false, null);
    }
}
4个回答

10

你也可以尝试这个方法。将其放在主表单区域中,它应该能够捕获所有的键盘命令。我使用它来为动态创建的选项卡添加键盘快捷键。

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    switch (keyData)
    {
        case Keys.Control|Keys.Tab:
            NextTab();
            return true;
        case Keys.Control|Keys.Shift|Keys.Tab:
            PreviousTab();
            return true;
        case Keys.Control|Keys.N:
            CreateConnection(null);
            return true;
    }
    return false;

这个几乎可以工作,但我无法获取CTRL+C的消息。如果我按C键,keyData是C,但如果我按Control键,无论是否与其他键一起按下,keyData都是LButton | ShiftKey | Control,并且无法确定是否按下了其他键。 - SLaks
最后一个 case 语句 "case Keys.Control|Keys.N" 正好做了你想做的事情。 | 用于捕获多个键。因此,"case Keys.Control|Keys.C:" 应该可以解决问题。 - Jerb

4

Windows Forms中存在一个bug。其IDocHostUIHandler.TranslateAccelerator实现实际上尝试通过在检查WebBrowserShortcutsEnabled并将键数据与预定义快捷键进行比较后返回S_OK来将按键发送到ActiveX主机。不幸的是,在Windows Forms的键盘处理过程中,shortcutkey属性是在ProcessCmdKey期间进行检查的,这意味着IDocHostUIHandler.TranslateAccelerator返回得有点晚。当WebBrowserShortcutsEnabled设置为false时,这会导致Shortcut枚举中的任何内容(例如Control+C、Del、Control+N等)停止工作。

您可以创建或查找一个WebBrowser ActiveX包装类(例如csexwb2),该类提供了不同的IDocHostUIHandler.TranslateAccelerator实现来检查快捷键。Windows Forms WebBrowser控件不允许自定义其IDocHostUIHandler实现。


0

您可以为WebBrowser控件设置键盘消息钩子,并过滤掉keyup键消息或对它们进行一些处理。请查看下面的代码是否适用于您:

[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, IntPtr windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();

public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
public const int WH_KEYBOARD = 2;
public static int hHook = 0;

// keyboard messages handling procedure
public static int KeyboardHookProcedure(int nCode, IntPtr wParam, IntPtr lParam)
{
    Keys keyPressed = (Keys)wParam.ToInt32();
    Console.WriteLine(keyPressed);

    if (keyPressed.Equals(Keys.Up) || keyPressed.Equals(Keys.Down))
    {
        Console.WriteLine(String.Format("{0} stop", keyPressed));
        return -1;
    }
    return CallNextHookEx(hHook, nCode, wParam, lParam);
}

// find explorer window
private IntPtr FindExplorerWindow()
{
    IntPtr wnd = FindWindowEx(webBrowser1.Handle, IntPtr.Zero, "Shell Embedding", IntPtr.Zero);
    if (wnd != IntPtr.Zero)
    {
        wnd = FindWindowEx(wnd, IntPtr.Zero, "Shell DocObject View", IntPtr.Zero);
        if (wnd != IntPtr.Zero)
            return FindWindowEx(wnd, IntPtr.Zero, "Internet Explorer_Server", IntPtr.Zero);
    }
    return IntPtr.Zero;
}
...
        // install hook    
        IntPtr wnd = FindExplorerWindow();
        if (wnd != IntPtr.Zero)
        {
            // you can either subclass explorer window or install a hook
            // for hooking you don't really need a window handle but can use it
            // later to filter out messages going to this exact window
            hHook = SetWindowsHookEx(WH_KEYBOARD, new HookProc(KeyboardHookProcedure),
                (IntPtr)0, GetCurrentThreadId());
            //....
        }
...

希望这能有所帮助,敬礼


0
经过大量调查,我们发现这是浏览器兼容性问题。
我们已经在HTML页面中添加了meta标签,然后快捷键就可以正常工作了。以下是示例代码。
 <html>
<body>
<Head>
<meta http-equiv="X-UA-Compatible" content="IE=IE8" />
</head>
<form>
First name:<br>
<input type="text" name="firstname">
<br>
Last name:<br>
<input type="text" name="lastname">
</form></body>
</html>

这个问题有三种不同的解决方案。

  1. 添加元标记以使网站浏览器兼容。

  2. 覆盖“PreocessCmdKey”方法并处理快捷键。

  3. 通过在FEATURE_BROWSER_EMULATION下添加密钥来模拟浏览器。

如果您不想在HTML代码中设置元标记,可以在导航URL之前将元标记分配给WebBrowser控件的Document文本属性。以下是示例。

    //Setting compatible mode of IE.
                    this.m_oWebBrowser.DocumentText = @"<html>
                      <head><meta http-equiv=""X-UA-Compatible"" content=""IE=IE8"" /> </head>
                      <body></body>
                      </html>";
this.m_oWebBrowser.Navigate("www.google.com");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接