簡體   English   中英

C#-捕獲WebBrowser控件中的CTRL-鼠標滾輪

[英]C# - Capturing CTRL-Mouse wheel in WebBrowser control

我正在用C#開發帶有嵌入式WebBrowser控件的Windows Forms應用程序,以“虛擬”(例如,禁用上下文菜單,后退按鈕,自由導航等)對第三方Web應用程序的訪問。

現在,我正在嘗試將縮放功能添加到自定義瀏覽器中。 我有鍵盤組合為此工作(CTRL +和CTRL-對基礎ActiveX WebBrowser對象進行正確的OLE調用),但是在不得不處理的有關WebBrowser的其他令人沮喪的事情中,我似乎無法弄清楚像IE一樣,如何捕獲CTRL-鼠標滾輪來模擬縮放功能。 我到處都在尋找解決方案,但無濟於事。

為了找出答案,我創建了一個僅包含WebBrowser控件的空表單,並發現了以下內容:

  1. 當父窗體具有焦點並且鼠標光標懸停在窗口頂部(例如,應用程序的標題上方)時,或者當鼠標光標懸停在WebBrowser控件上時,CTRL-MouseWheel始終會觸發MouseWheel事件即使父窗體具有焦點,也似乎沒有焦點。
  2. 當鼠標光標懸停在WebBrowser控件上並且WebBrowser擁有焦點時,CTRL-MouseWheel永遠不會觸發MouseWheel事件。
  3. 使用不帶CTRL的鼠標滾輪滾動WebBrowser的窗口內容,但在垂直滾動條完全到達頂部或底部之前,不會觸發MouseWheel事件。
  4. 通過重寫WndProcDefWndProc來攔截從WebBrowser繼承的示例類和父窗體的WM_MOUSEWHEEL Message僅適用於上述條件( wParam正確表示MK_CONTROL )。
  5. 如預期的那樣,按下CTRL時會觸發PreviewKeyDown事件,但仍然無法與鼠標滾輪保持一致。

因此,我猜該Message正在父窗體和托管控件級別以下進行處理,並且不會冒到我可以攔截甚至處理它的地方。 有沒有辦法做到這一點,或者有其他方法可以使用CTRL-MouseWheel模擬放大和縮小?

謝謝閱讀!

首先將WebBrowser.Document.DomDocument投射到mshtml命名空間中的正確接口,例如mshtml.HTMLDocumentEvents2_Event ,然后可以處理(並取消)鼠標滾輪事件。 我不確定,但是我認為您隨時需要在文檔更改時連接事件處理程序,因此我在WebBrowser.DocumentCompleted事件上進行操作。 我也不確定是否需要釋放任何COM對象。

這實在令人沮喪,以至於我開始工作並停止關心……

這里是至少一個解釋基礎的文檔: 如何在Visual C#.NET應用程序中處理文檔事件

對於您的特定情況,只需根據是否按下CTRL鍵有條件地壓縮onmousewheel事件。

private void webBrowser_DocumentCompleted(object sender,
                                         WebBrowserDocumentCompletedEventArgs e)
{
    if (webBrowser.Url.ToString() == "about:blank")
        return;
    var docEvents = (mshtml.HTMLDocumentEvents2_Event)webBrowser.Document.DomDocument;
    docEvents.onmousewheel -= docEvents_onmousewheel; //may not be necessary?
    docEvents.onmousewheel += docEvents_onmousewheel;
}

bool docEvents_onmousewheel(mshtml.IHTMLEventObj pEvtObj)
{
    if (pEvtObj.ctrlKey)
    {
        pEvtObj.cancelBubble = true; //not sure what this does really
        pEvtObj.returnValue = false;  //this cancels the event
        return false; //not sure what this does really
    }
    else
        return true; //again not sure what this does
} 

現在,如果您需要了解Wheel Delta(滾動量),則需要將事件對象投射到另一個接口。

bool docEvents_onmousewheel(mshtml.IHTMLEventObj pEvtObj)
{
    var wheelEventObj = (mshtml.IHTMLEventObj4)pEvtObj;
    var delta = wheelEventObj.wheelDelta;
    [...]
}

這是我用來禁用ctrl + shift的代碼:
您需要在最深層的控件“ Internet Explorer_Server”中更改WndProc的行為,
在您的網絡瀏覽器准備就緒后執行以下操作:

IntPtr wbHandle = Win32.FindWindowEx(this.wbMain.Handle, IntPtr.Zero, "Shell Embedding", String.Empty);
wbHandle = Win32.FindWindowEx(wbHandle, IntPtr.Zero, "Shell DocObject View", String.Empty);
wbHandle = Win32.FindWindowEx(wbHandle, IntPtr.Zero, "Internet Explorer_Server", String.Empty);
WbInternal wb = new WbInternal(wbHandle);

class WbInternal : NativeWindow
    {
        public WbInternal(IntPtr handle)
        {
            this.AssignHandle(handle);
        }

        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_MOUSEWHEEL)


            {
                if (((int)m.WParam & 0x00FF) == MK_SHIFT)
                {
                    return;
                }
            }
            base.WndProc(ref m);
        }
    }

您可以從MSDN中找到有關WM_MOUSEWHEEL的更多消息。
我從MSDN找到了這個。 但是我忘了鏈接,一旦找到,將在此處添加。

我無法使所有這些可靠地工作,因此在進行一些(令人沮喪的)實驗之后,我想出了TCC發布的答案的派生詞。 我的Web瀏覽器控件托管在用戶控件中。 主要區別在於我為HTMLDocumentEvents2_Event使用了類級別的變量,因此我可以成功取消訂閱,並且將mshtml.IHTMLEventObj pEvtObj.Returnvalue設置為true。

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        _wbData = (WebBrowser)FindElement("DataBrowser");
        _horzScroll = (ScrollBar)FindElement("HorizontalScroll");
        _vertScroll = (ScrollBar)FindElement("VerticalScroll");

        _wbData.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(OnLoadCompleted);

        _horzScroll.Scroll += new ScrollEventHandler(OnHorizontalScroll);
        _vertScroll.Scroll += new ScrollEventHandler(OnVerticalScroll);
        LoadDefault();
        EnableSoundEffects(SoundEffects);
    }

    private void OnHorizontalScroll(object sender, ScrollEventArgs e)
    {
       // _wbData.Handle
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;
        _horzPosition = (int)e.NewValue;

        if (htmlDoc != null && htmlDoc.body != null)
            htmlDoc.parentWindow.scroll(_horzPosition, _vertPosition);
    }

    private void OnVerticalScroll(object sender, ScrollEventArgs e)
    {
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;
        _vertPosition = (int)e.NewValue;

        if (htmlDoc != null && htmlDoc.body != null)
            htmlDoc.parentWindow.scroll(_horzPosition, _vertPosition);
    }

    private void OnLoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
    {
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;

        if (htmlDoc != null && htmlDoc.body != null)
        {
            mshtml.IHTMLElement2 body = (mshtml.IHTMLElement2)htmlDoc.body;

                _horzScroll.Visibility = Visibility.Collapsed;

            if (body.scrollHeight > _wbData.ActualHeight)
                _vertScroll.Visibility = Visibility.Visible;
            else
                _vertScroll.Visibility = Visibility.Collapsed;

            _vertScroll.ViewportSize = _wbData.ActualHeight;
            _vertScroll.Maximum = body.scrollHeight - (_wbData.ActualHeight - 8);

            _eventHelper = (HTMLDocumentEvents2_Event)_wbData.Document;
            _eventHelper.onmousewheel -= OnMouseWheel;
            _eventHelper.onmousewheel += new HTMLDocumentEvents2_onmousewheelEventHandler(OnMouseWheel);
        }
    }

    private bool OnMouseWheel(mshtml.IHTMLEventObj pEvtObj)
    {
        mshtml.HTMLDocument htmlDoc = _wbData.Document as mshtml.HTMLDocument;
        var wheelEventObj = (mshtml.IHTMLEventObj4)pEvtObj;
        var delta = wheelEventObj.wheelDelta;

        if (htmlDoc != null && htmlDoc.body != null && wheelEventObj != null)
        {
            _vertPosition += (int)wheelEventObj.wheelDelta;
            htmlDoc.parentWindow.scroll(_horzPosition, _vertPosition);
        }

        pEvtObj.returnValue = true;
        return true;
    } 

也許使用SetWindowsHookEx查找這些事件可能對您有用。 這就是我用來在ActiveX MapPoint控件上獲取滾輪事件的功能。

請注意,Windows 7上對此有一些怪異之處,可能需要進行一些修改。 有關更多詳細信息,請在MSDN論壇上的Windows 7上搜索SetWindowsHookEx。

要解決此問題,您必須偵聽並處理以下消息:

  • OLECMDID_GETZOOMRANGE
  • OLECMDID_OPTICAL_GETZOOMRANGE
  • OLECMDID_OPTICAL_ZOOM
  • OLECMDID_ZOOM

它們是由Internet Explorer調度的。 請參閱MSDN上備注

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM