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.
This commit is contained in:
Andreas FlΓΆjt 2017-08-02 21:16:37 +02:00
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ 5e06ac11e9
ΠšΠΎΠΌΠΌΠΈΡ‚ a84fa0eecb
6 ΠΈΠ·ΠΌΠ΅Π½Ρ‘Π½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ²: 111 Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΉ ΠΈ 0 ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΉ

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -787,6 +787,10 @@ void Window::SetAppDetails(const mate::Dictionary& options) {
relaunch_command, relaunch_display_name,
window_->GetAcceleratedWidget());
}
void Window::SetForwardMouseMessages(bool forward) {
window_->SetForwardMouseMessages(forward);
}
#endif
#if defined(TOOLKIT_VIEWS)
@ -1060,6 +1064,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setThumbnailClip", &Window::SetThumbnailClip)
.SetMethod("setThumbnailToolTip", &Window::SetThumbnailToolTip)
.SetMethod("setAppDetails", &Window::SetAppDetails)
.SetMethod("setForwardMouseMessages", &Window::SetForwardMouseMessages)
#endif
#if defined(TOOLKIT_VIEWS)
.SetMethod("setIcon", &Window::SetIcon)

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -201,6 +201,7 @@ class Window : public mate::TrackableObject<Window>,
bool SetThumbnailClip(const gfx::Rect& region);
bool SetThumbnailToolTip(const std::string& tooltip);
void SetAppDetails(const mate::Dictionary& options);
void SetForwardMouseMessages(bool forward);
#endif
#if defined(TOOLKIT_VIEWS)

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -152,6 +152,9 @@ class NativeWindow : public base::SupportsUserData,
virtual gfx::NativeView GetNativeView() const = 0;
virtual gfx::NativeWindow GetNativeWindow() const = 0;
virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0;
#if defined(OS_WIN)
virtual void SetForwardMouseMessages(bool forward) = 0;
#endif
// Taskbar/Dock APIs.
enum ProgressState {

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1064,6 +1064,13 @@ void NativeWindowViews::SetEnabled(bool enable) {
#endif
}
#if defined(OS_WIN)
void NativeWindowViews::SetForwardMouseMessages(bool forward) {
forwarding_mouse_messages_ = forward;
SetIgnoreMouseEvents(forward);
}
#endif
void NativeWindowViews::OnWidgetActivationChanged(
views::Widget* widget, bool active) {
if (widget != window_.get())

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -7,6 +7,7 @@
#include "atom/browser/native_window.h"
#include <map>
#include <string>
#include <vector>
@ -133,6 +134,7 @@ class NativeWindowViews : public NativeWindow,
#if defined(OS_WIN)
TaskbarHost& taskbar_host() { return taskbar_host_; }
void SetForwardMouseMessages(bool forward) override;
#endif
private:
@ -169,6 +171,8 @@ class NativeWindowViews : public NativeWindow,
bool PreHandleMSG(
UINT message, WPARAM w_param, LPARAM l_param, LRESULT* result) override;
void HandleSizeEvent(WPARAM w_param, LPARAM l_param);
static LRESULT CALLBACK SubclassProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param, UINT_PTR subclass_id, DWORD_PTR ref_data);
static LRESULT CALLBACK MouseHookProc(int n_code, WPARAM w_param, LPARAM l_param);
#endif
// NativeWindow:
@ -259,6 +263,11 @@ class NativeWindowViews : public NativeWindow,
// The icons of window and taskbar.
base::win::ScopedHICON window_icon_;
base::win::ScopedHICON app_icon_;
// Handles to legacy windows iterated by the mouse hook
static std::map<HWND, NativeWindowViews*> legacy_window_map_;
static HHOOK mouse_hook_;
bool forwarding_mouse_messages_ = false;
#endif
// Handles unhandled keyboard messages coming back from the renderer process.

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -80,6 +80,9 @@ bool IsScreenReaderActive() {
} // namespace
std::map<HWND, NativeWindowViews*> NativeWindowViews::legacy_window_map_;
HHOOK NativeWindowViews::mouse_hook_ = NULL;
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
std::string command = AppCommandToString(command_id);
NotifyWindowExecuteWindowsCommand(command);
@ -151,6 +154,24 @@ bool NativeWindowViews::PreHandleMSG(
if (w_param) {
NotifyWindowEndSession();
}
return false;
}
case WM_PARENTNOTIFY: {
if (LOWORD(w_param) == WM_CREATE) {
// Because of reasons regarding legacy drivers and stuff, a window that
// matches the client area is created and used internally by Chromium.
// This window is subclassed in order to fix some issues when forwarding
// mouse messages; see comments in |SubclassProc|. If by any chance
// Chromium removes the legacy window in the future it may be fine to
// move the logic to this very switch statement.
HWND legacy_window = reinterpret_cast<HWND>(l_param);
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);
}
legacy_window_map_.insert({ legacy_window, this });
}
return false;
}
default:
return false;
@ -207,4 +228,69 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
}
}
LRESULT CALLBACK NativeWindowViews::SubclassProc(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param, UINT_PTR subclass_id, DWORD_PTR ref_data) {
NativeWindowViews* window = reinterpret_cast<NativeWindowViews*>(ref_data);
switch (msg) {
case WM_MOUSELEAVE: {
// When input is forwarded to underlying windows, this message is posted.
// If not handled, it interferes with Chromium logic, causing for example
// mouseleave events to fire. If those events are used to exit forward
// mode, excessive flickering on for example hover items in underlying
// windows can occur due to rapidly entering and leaving forwarding mode.
// By consuming and ignoring the message, we're essentially telling
// Chromium that we have not left the window despite somebody else getting
// the messages. As to why this is catched for the legacy window and not
// the actual browser window is simply that the legacy window somehow
// makes use of these events; posting to the main window didn't work.
if (window->forwarding_mouse_messages_) {
return 0;
}
break;
}
case WM_DESTROY: {
legacy_window_map_.erase(hwnd);
if (legacy_window_map_.size() == 0) {
UnhookWindowsHookEx(mouse_hook_);
mouse_hook_ = NULL;
}
break;
}
}
return DefSubclassProc(hwnd, msg, w_param, l_param);
}
LRESULT CALLBACK NativeWindowViews::MouseHookProc(int n_code, WPARAM w_param, LPARAM l_param) {
if (n_code < 0) {
return CallNextHookEx(NULL, n_code, w_param, l_param);
}
// Post a WM_MOUSEMOVE message for those windows whose client area contains
// the cursor and are set to forward messages since they are in a state where
// they would otherwise ignore all mouse input.
if (w_param == WM_MOUSEMOVE) {
for (auto legacy : legacy_window_map_) {
if (!legacy.second->forwarding_mouse_messages_) {
continue;
}
// At first I considered enumerating windows to check whether the cursor
// was directly above the window, but since nothing bad seems to happen
// if we post the message even if some other window occludes it I have
// just left it as is.
RECT client_rect;
GetClientRect(legacy.first, &client_rect);
POINT p = ((MSLLHOOKSTRUCT*)l_param)->pt;
ScreenToClient(legacy.first, &p);
if (PtInRect(&client_rect, p)) {
WPARAM w = 0; // No virtual keys pressed for our purposes
LPARAM l = MAKELPARAM(p.x, p.y);
PostMessage(legacy.first, WM_MOUSEMOVE, w, l);
}
}
}
return CallNextHookEx(NULL, n_code, w_param, l_param);
}
} // namespace atom