Π·Π΅ΡΠΊΠ°Π»ΠΎ ΠΈΠ· https://github.com/electron/electron.git
π 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.
This commit is contained in:
Π ΠΎΠ΄ΠΈΡΠ΅Π»Ρ
5e06ac11e9
ΠΠΎΠΌΠΌΠΈΡ
a84fa0eecb
|
@ -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
|
||||
|
|
ΠΠ°Π³ΡΡΠ·ΠΊΠ°β¦
Π‘ΡΡΠ»ΠΊΠ° Π² Π½ΠΎΠ²ΠΎΠΉ Π·Π°Π΄Π°ΡΠ΅