I'm using CefGlue to make an application with an embedded webkit browser in it, and I need to listen for mousemovements in the browser window. The winforms control doesn't pass down mouse events to the control so I can't listen to them.
However, I found a bug/feature request with a solution in it, but it's beyond me on how to implement it, I'm not familiar with working directly in the WinAPI. The developer says I need to:
2. OS-specific (windows) - after browser created (CefLifeSpanHandler.OnAfterCreated) get window handle and subclass them (window subclassing technique). Actually now we have native window with class CefBrowserWindow (returned by CefBrowser.GetHost().GetWindowHandle()), then child window Chrome_WidgetWin_0, and then Chrome_RenderWidgetHostHWND. For intercepting WM_MOUSEMOVE you are interesting in Chrome_WidgetWin_0 window, which can be easily obtained via CefBrowserWindow. Just play with Spy++ to see precisely.
https://bitbucket.org/xilium/xilium.cefglue/issue/4/mouse-events-unaccessible
I've done some googling, but I'm not sure how to hook into this. I have this function on my form:
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
switch (m.Msg) {
case WM_MOUSEMOVE:
Console.WriteLine("Mouse move!");
break;
default:
Console.WriteLine(m.ToString());
break;
}
}
But I never see a mouse move when I'm over the control. I suspect I need to be listening on the WndProc of CefBrowser.GetHost().GetWindowHandle()
But I'm not sure how to do that.
I found a solution. I call this function in the OnAfterCreated event from the WebLifeSpanHandler.
The function I was looking for is GetWindowThreadProcessId which I can use the window handle provided by
browser.CefBrowser.GetHost().GetWindowHandle()
One thing to note is that the Hook Procedure needs to have some sort of larger scope. C# doesn't see it hooked into the native process and will Garbage Collect it if you let it go out of scope. To fix this, I made them class properties.
Supporting Documents:
My two hooks (not good code, I don't do anything with the marshaled data):
This is the externs and the code needed to expose the hooks, this is class level scope:
I'm not sure this is entirely required, especially since the thread being hooked to is going away on close, but just for good measure, don't forget to cleanup your hook after you're done listening. I do this on my form's dispose method: