Windows mouse wheel when out of focus

Made a cool mod to CEF that you'd like to share with others? Discuss CEF modifications here, and view modifications that others have made.

Windows mouse wheel when out of focus

Postby PolesApart » Sun Oct 18, 2015 7:55 am

I'm posting in this forum more as a way to archive as tip in case someone looks for it. It's not a modification per se.

I have a gtk windows application, but I suspect whenever you use any toolkit on top of native windows api, you could face the same issue I had. Also this is not exactly CEF specific, other "pluggable" systems are affected.

The thing is that my UI is composed by a gtk window with a toolbar on top, similar to any regular browser UIs. Below it, there's a GtkDrawingArea, which as a low-level GdkWindow from which I stole the HWND as a parenting window for CEF. Chromium within CEF does it's own magic and puts anything it wants on it, i.e. older versions draw using GDI, newer versions draws using newer APIs, such as textures and such. The only thing I had to make sure was that the window resize events were adequately handled. Voila.

However, I further noticed that Gtk text entry widget does't fairly compete for focus with CEF. This is due to the fact that some gtk widgets are rendered on top of a larger WIN32 window, i.e. not every widget has a window, they drawn on a Rect under a window (similar for cocoa NSView vs NSWindow conceptual relationship, abstracting the event handling part which I'm unsure how cocoa handles).

So when I click on the URL text entry of my entry, GtkEntry (the text input widget) thinks it has win32 keyboard focus (it even blinks the cursor) but the keyboard events still goes to CEF. I fixed that by reacting to the GtkEntry focus in event and forcing a low-level Windows API SetFocus on the gdk window handle hosting the gtkentry (which points to whatever windowed widget is above the hierarchy. In my case it probably is the main window, but YMMV). CEF realizes it lost focus and gtk realizes it has the focus, and everything works.

Evertything but a small detail: For using the mouse wheel, I have to click back within CEF widget, so CEF gets the focus and the mouse wheel events are routed to it.

Although it involves the gtk events hierarchy, that can also be seen as a low-level (windows api) issue, or more correctly, standard behavior. Windows low level event per se doesn't route mouse motion to the window hovered by the mouse cursor, by default it routes them to the topmost focused window which is within the hover area (and I suspect the root window if there's no one else listening).

So instead of messing with gtk events hierarchy and CEF, I went on to read this article:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx

And within the user comments there's code for non-intrusively routing the events to hovered windows within the same process.
There's also mentions to microsoft windows vista suggesting this as a good practice:

https://msdn.microsoft.com/en-us/library/dn742466.aspx#MOUSE_WHEEL

So I tested the code and it worked.
The good:

- it's non-intrusive, just copy and paste (you'd have to include windowsx.h if not doing that already) to the same file where your WinMain resides. I decided to put it inside an anonymous namespace.
- it makes the wheel work for any panel / external plugin / whatever.

The "bad"
- None I can think of

The limits:

- There's at least one other non-natural user interface behavior which this approach doesn't tackle: keyboard tab order. Gtk (and most likely Qt, wxWidgets and whatever) has it's own tabbing system, and low level windows has them too. Cef window when focused isn't other-widget-aware and other widgets aren't cef-aware.

I opted to don't care. You may think different. Why I put this here? Because I suspect the intrusive keyboard focus handling needed to make the external ui cooperate with the internal (cef) handing, if implemented correctly and fully, would need to react to mouse regular button clicks too. With both keyboard and mouse (and touch) events covered, you'd probably not need the non-intrusive solution, as the windows low-level focus and the toolkit focus would have to synchronize. A partial solution however might not involve the focus changing, and thus still require the above wheel handling.
Last edited by PolesApart on Tue Feb 02, 2016 12:28 pm, edited 1 time in total.
PolesApart
Mentor
 
Posts: 73
Joined: Fri Dec 05, 2014 1:24 pm

Re: Windows mouse wheel when out of focus

Postby magreenblatt » Mon Oct 19, 2015 9:27 am

Thanks for posting this. One comment:

PolesApart wrote:Cef window when focused isn't other-widget-aware and other widgets aren't cef-aware.

When changing focus via tab (traversing the focus chain) you should be able to do the following:

- Wrap the browser in a Gtk widget that's part of the Gtk focus chain, or use a very tiny but focusable Gtk widget to represent the browser. When the widget gains focus apply that focus to the browser.
- CefFocusHandler::OnTakeFocus should be called [1] when tabbing past the last focusable node in the browser. Use that notification to pass focus back to the Gtk focus chain.

[1] bug on Mac: https://bitbucket.org/chromiumembedded/cef/issues/1382
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Windows mouse wheel when out of focus

Postby PolesApart » Tue Oct 20, 2015 3:00 pm

Thanks, that would be a nice solution.

I also noticed that when cef has the keyboard focus, (at least) function (e.g. F5) keys aren't propagated (perhaps because I'm using multithreaded message loop) to parent windows. I had to implement OnPreKeyEvent, filter a range of interested events and PostMessage() them to the main window, and then it worked. I'm not sure why it was necessary, though.
PolesApart
Mentor
 
Posts: 73
Joined: Fri Dec 05, 2014 1:24 pm

Re: Windows mouse wheel when out of focus

Postby romariorios » Mon Jan 18, 2016 3:25 pm

Hello.

I have a Qt application that uses CEF, but the executable that directly links to libcef (based on cefsimple) is different from the main window executable. I pass the HWND of the main window trhough IPC to the backend executable, then set the CEF window as its child.

Anyway, I tried to paste the code in the comments in both cefsimple and the main executable but nothing changed. Maybe my different configuration has something to do with it, but I don't know. Any ideas?
romariorios
Mentor
 
Posts: 50
Joined: Thu Apr 30, 2015 6:13 am
Location: Brazil

Re: Windows mouse wheel when out of focus

Postby PolesApart » Tue Feb 02, 2016 11:49 am

The comments in the code suggests that you can't pass a message to a HWND of another process via that method.
I suspect that it would work if instead of changing the message in the filter chain, you postmessage() it or something. But I haven't tried it.
PolesApart
Mentor
 
Posts: 73
Joined: Fri Dec 05, 2014 1:24 pm


Return to Modifications Forum

Who is online

Users browsing this forum: No registered users and 11 guests