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

Mouse forward functionality on Windows #10183

Merged
merged 7 commits into from Aug 17, 2017

Conversation

Projects
None yet
2 participants
@andens
Contributor

andens commented Aug 2, 2017

For top-level windows, setting the WS_EX_LAYERED and WS_EX_TRANSPARENT as done in setIgnoreMouseEvents styles effectively bypasses hit tests. This works great if the entire window should ignore mouse messages, but if we want to enable and disable bypassing based on where we are in the web page we are left in the dark since the browser window doesn't get any mouse messages anymore.

This PR solves this problem by adding a method setForwardMouseMessages to BrowserWindow. A low-level mouse hook manually sends WM_MOUSEMOVE messages to the browser window if it's in a state where it's forwarding mouse messages. This is enough for Chromium to generate events when entering/leaving HTML elements even when input is otherwise routed to underlying windows. Ultimately this allows us to stop forwarding when appropriate so that we may once again interact with the browser.

As a concrete example of where this was used, I made a transparent canvas that represents a hole the web page. Inside this area the window is treated as if it never existed. Moving out of the canvas once again acknowledges the window after disabling forwarding in the mouseleave event of the canvas.

Off-topic:
This is my very first PR so something has likely gone awry. Any feedback, minor or major, is greatly appreciated to improve quality of future ones.

andens added some commits Aug 2, 2017

🏁 Add API to forward mouse messages.
As opposed to the existing setIgnoreMouseEvents this call makes Chromium aware of mouse movements, allowing the user to stop forwarding according to movements in the webpage.
SetWindowSubclass(
legacy_window, SubclassProc, 1, reinterpret_cast<DWORD_PTR>(this));
if (legacy_window_map_.size() == 0) {
mouse_hook_ = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);

This comment has been minimized.

@zcbenz

zcbenz Aug 14, 2017

Contributor

This would install mouse hook for every Electron apps, we should only do subclass and install the hook when win.setForwardMouseMessages is called.

This comment has been minimized.

@andens

andens Aug 14, 2017

Contributor

Thanks, I completely overlooked that. Fixed.

@@ -1356,6 +1356,14 @@ removed in future Electron releases.
**Note:** The BrowserView API is currently experimental and may change or be
removed in future Electron releases.
#### `win.setForwardMouseMessages(forward)` _Windows_

This comment has been minimized.

@zcbenz

zcbenz Aug 14, 2017

Contributor

We can probably make this an option of the setIgnoreMouseEvents, I don't think there are other usages of this API.

#### `win.setIgnoreMouseEvents(ignore[, options])`

* `ignore` Boolean
* `options` Object  (optional)
  * `forwardMouseMessages` Boolean (optional) - ...

And I think it is worthwhile to add a simple example for it, otherwise it is still hard to know how to make use of it.

This comment has been minimized.

@andens

andens Aug 14, 2017

Contributor

Originally I wasn't sure if I could tamper with existing API, but an optional argument that defaults to false should not break anything and I agree that it's cleaner this way.

Examples are always good. Where would the example belong? My very simple test application is mostly just a matter of ignoring/acknowledging mouse input as I enter/leave a canvas respectively. Cleaned up it should make a good example if there is a good way to put it.

This comment has been minimized.

@zcbenz

zcbenz Aug 15, 2017

Contributor

Examples are always good. Where would the example belong?

You can make it a sub-chapter of Click-through window in frameless-window.md.

andens added some commits Aug 14, 2017

Set up legacy window subclass and mouse hook during setForwardMouseMe…
…ssages.

As opposed to when a legacy window is created/destroyed. This enables forwarding on a per-window basis.
}
} else if (!forward && forwarding_mouse_messages_) {
forwarding_mouse_messages_ = false;
forwarding_windows_.erase(this);

This comment has been minimized.

@zcbenz

zcbenz Aug 15, 2017

Contributor

The cleanup is only done when SetForwardMouseMessages(false) is called, it should also be done when the window is destroyed.

@zcbenz

zcbenz approved these changes Aug 17, 2017

@zcbenz zcbenz merged commit f908678 into electron:master Aug 17, 2017

2 checks passed

continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
@welcome

This comment has been minimized.

welcome bot commented Aug 17, 2017

Congrats on merging your first pull request! 🎉🎉🎉

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