Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MouseEnter and MouseLeave events of ChromiumWebBrowser control do not fire #1098

Closed
sarus opened this issue Jun 30, 2015 · 14 comments
Closed

Comments

@sarus
Copy link

sarus commented Jun 30, 2015

Hello,

Not sure if I should be expecting this to work but the MouseLeave and MouseEnter events don't seem to work when using the ChromiumWebBrowser control for WinForms. Here's the code I was using. Should I be expecting these events to trigger properly on the browser control? Thank you!

        public WebView()
        {
            InitializeComponent();
            browser = new ChromiumWebBrowser("resource://web/index.html")
            {
                Dock = DockStyle.Fill,
            };

            mainPanel.Controls.Add(browser);

            browser.MouseLeave += new System.EventHandler(this.browser_MouseLeave);
            browser.MouseEnter += new System.EventHandler(this.browser_MouseEnter);           
        }

        void browser_MouseLeave(object sender, EventArgs e)
        {
            // Never Fires
            Console.WriteLine("Browser Mouse ENter");              
        }

        void browser_MouseEnter(object sender, EventArgs e)
        {
            // Never Fires
            Console.WriteLine("Browser Mouse Enter");
        }

I'm using the latest CefSharp available from Nuget (41.0.0)

@jankurianski
Copy link
Member

The underlying CEF library captures all mouse events and does not bubble them up to WinForms. There's no way around this for WinForms - if you want to handle mouse events you need to do so in JavaScript.

Your alternative is to use the WPF CefSharp control, as this uses the underlying CEF library's OSR (Off Screen Rendering) mode, in which WPF is in charge of all keyboard and mouse events, and it passes them onto CEF. This would give you an opportunity to intercept whatever events you wanted.

@sarus
Copy link
Author

sarus commented Jun 30, 2015

Ah interesting thank you very much. Is the general recommendation to use the WPF control? We're "porting" an existing application that is built on winforms which is why I started with the winforms control but it is possible for us to move to WPF if needed (although a bit painful).

@amaitland
Copy link
Member

You may be able to hook the underlying handle and capture the raw messages, e.g. WM_MOUSELEAVE using a NativeWindow implementation. Might be worth loading Spy++ and seeing if there's a handle that receives the messages.

@sarus
Copy link
Author

sarus commented Jun 30, 2015

@amaitland Thank you for the tip. I did try out listening for WM_MOUSELEAVE and WM_MOUSEMOVE but they didn't work well if the mouse was moving fast over the control (missed messages basically). For my use case where I was changing the opacity of the form on mouse hover (in the CSS sense) this resulted in issues where the state would become mixed up (hover when it wasn't hovered or vice versa). I've resorted to using a timer which checks the mouse position to see if it's contained within the bounds of the form. Kind of makes me cringe but it works well haha.

@amaitland
Copy link
Member

What handle did you hook? It would likely need to be one of the child handles of the browser control it's self (one of the underlying handles for the CEF instance). There used to be a handle called something like Chrome_RenderWidgetHostHWND, I'd start there....

Are you actually interested in Focus? For which there are notification events.

https://github.com/cefsharp/CefSharp/blob/master/CefSharp.WinForms/Internals/DefaultFocusHandler.cs

@sarus
Copy link
Author

sarus commented Jul 1, 2015

@amaitland I'm pretty sure we aren't looking for focus. The actual use case here is to change the opacity of the form when the user's mouse is hovered over it. (transparent when there is no mouse hover and opaque when there is a mouse hover).

(I'm using hover here in the css sense, not the winform sense)

I'll take a look at the handles for the browser control itself and report back. Thanks!

@jankurianski
Copy link
Member

@sarus Not sure if it helps but inspired by you and @amaitland I decided to try intercepting the mouse events to fix another problem I had. This is how I look for the Chrome_RenderWidgetHostHWND: https://gist.github.com/jankurianski/2163d7928d3d6f839e47

Let me know if you have a cleaner approach than using EnumWindow. I found that the widget window was the 3rd direct child from the ChromiumWebBrowser.Handle, which would be shorter but I guess more likely to break between Chromium releases.

@amaitland
Copy link
Member

Nice one @jankurianski! An excellent reference 👍

@sarus
Copy link
Author

sarus commented Jul 2, 2015

@jankurianski Yes agree with amaitland. This is fantastic. Thank you for posting this Gist. Will try to find time in the next week to test it out. Have you noticed missing mouse events when using this approach?

As a test I hooked into the mouse events for the form itself to listen for WM_MOUSELEAVE and WM_MOUSEMOVE. I noticed that if I moved the mouse over the form very quickly the events were not always fired.

There was also this stackoverflow post basically outlining the same problem and hence the timer based solution:

http://stackoverflow.com/questions/12552809/mousehover-and-mouseleave-events-controlling

@jankurianski
Copy link
Member

@sarus Changing the ChromeWidgetMessageInterceptor to the following implementation resulted in lots of WM_MOUSEMOVE messages, and I always seemed to get a WM_MOUSELEAVE message, even when I was quickly swiping in and out of the browser:

        class ChromeWidgetMessageInterceptor : NativeWindow
        {
            public ChromeWidgetMessageInterceptor(IntPtr chromeWidgetHostHandle)
            {
                AssignHandle(chromeWidgetHostHandle);
            }

            const int WM_MOUSEMOVE = 0x0200;
            const int WM_MOUSELEAVE = 0x02A3;

            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);

                switch (m.Msg) {
                    case WM_MOUSEMOVE:
                        Console.WriteLine("WM_MOUSEMOVE");
                        break;
                    case WM_MOUSELEAVE:
                        Console.WriteLine("WM_MOUSELEAVE");
                        break;
                }
            }
        }

@amaitland
Copy link
Member

I've added this is faq-able? Anymore more before closing?

@rassilon
Copy link
Contributor

rassilon commented Jul 7, 2015

I don't think so. Other than maybe adding a comment to one of the example projects pointing at the gist and this issue maybe?

@qwqcode
Copy link

qwqcode commented Dec 29, 2018

@sarus Changing the ChromeWidgetMessageInterceptor to the following implementation resulted in lots of WM_MOUSEMOVE messages, and I always seemed to get a WM_MOUSELEAVE message, even when I was quickly swiping in and out of the browser:

        class ChromeWidgetMessageInterceptor : NativeWindow
        {
            public ChromeWidgetMessageInterceptor(IntPtr chromeWidgetHostHandle)
            {
                AssignHandle(chromeWidgetHostHandle);
            }

            const int WM_MOUSEMOVE = 0x0200;
            const int WM_MOUSELEAVE = 0x02A3;

            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);

                switch (m.Msg) {
                    case WM_MOUSEMOVE:
                        Console.WriteLine("WM_MOUSEMOVE");
                        break;
                    case WM_MOUSELEAVE:
                        Console.WriteLine("WM_MOUSELEAVE");
                        break;
                }
            }
        }

But const int WM_LBUTTONUP = 0x0202; can't receive ��

@MarcusN88
Copy link

@sarus Changing the ChromeWidgetMessageInterceptor to the following implementation resulted in lots of WM_MOUSEMOVE messages, and I always seemed to get a WM_MOUSELEAVE message, even when I was quickly swiping in and out of the browser:

        class ChromeWidgetMessageInterceptor : NativeWindow
        {
            public ChromeWidgetMessageInterceptor(IntPtr chromeWidgetHostHandle)
            {
                AssignHandle(chromeWidgetHostHandle);
            }

            const int WM_MOUSEMOVE = 0x0200;
            const int WM_MOUSELEAVE = 0x02A3;

            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);

                switch (m.Msg) {
                    case WM_MOUSEMOVE:
                        Console.WriteLine("WM_MOUSEMOVE");
                        break;
                    case WM_MOUSELEAVE:
                        Console.WriteLine("WM_MOUSELEAVE");
                        break;
                }
            }
        }

But const int WM_LBUTTONUP = 0x0202; can't receive ��

Having the same problem. Also not working for WM_NCLBUTTONUP = 0x00A2;. Is there any other classname i could use to grab a handle of and get the messages for mouse button up?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants