OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "views/focus/focus_util_win.h" | |
6 | |
7 #include <windowsx.h> | |
8 | |
9 #include "base/auto_reset.h" | |
10 #include "ui/base/view_prop.h" | |
11 #include "ui/base/win/hwnd_util.h" | |
12 | |
13 using ui::ViewProp; | |
14 | |
15 namespace views { | |
16 | |
17 // Property used to indicate the HWND supports having mouse wheel messages | |
18 // rerouted to it. | |
19 static const char* const kHWNDSupportMouseWheelRerouting = | |
20 "__HWND_MW_REROUTE_OK"; | |
21 | |
22 static bool WindowSupportsRerouteMouseWheel(HWND window) { | |
23 while (GetWindowLong(window, GWL_STYLE) & WS_CHILD) { | |
24 if (!IsWindow(window)) | |
25 break; | |
26 | |
27 if (reinterpret_cast<bool>( | |
28 ViewProp::GetValue(window, kHWNDSupportMouseWheelRerouting))) { | |
29 return true; | |
30 } | |
31 window = GetParent(window); | |
32 } | |
33 return false; | |
34 } | |
35 | |
36 static bool IsCompatibleWithMouseWheelRedirection(HWND window) { | |
37 std::wstring class_name = ui::GetClassName(window); | |
38 // Mousewheel redirection to comboboxes is a surprising and | |
39 // undesireable user behavior. | |
40 return !(class_name == L"ComboBox" || | |
41 class_name == L"ComboBoxEx32"); | |
42 } | |
43 | |
44 static bool CanRedirectMouseWheelFrom(HWND window) { | |
45 std::wstring class_name = ui::GetClassName(window); | |
46 | |
47 // Older Thinkpad mouse wheel drivers create a window under mouse wheel | |
48 // pointer. Detect if we are dealing with this window. In this case we | |
49 // don't need to do anything as the Thinkpad mouse driver will send | |
50 // mouse wheel messages to the right window. | |
51 if ((class_name == L"Syn Visual Class") || | |
52 (class_name == L"SynTrackCursorWindowClass")) | |
53 return false; | |
54 | |
55 return true; | |
56 } | |
57 | |
58 ViewProp* SetWindowSupportsRerouteMouseWheel(HWND hwnd) { | |
59 return new ViewProp(hwnd, kHWNDSupportMouseWheelRerouting, | |
60 reinterpret_cast<HANDLE>(true)); | |
61 } | |
62 | |
63 bool RerouteMouseWheel(HWND window, WPARAM w_param, LPARAM l_param) { | |
64 // Since this is called from a subclass for every window, we can get | |
65 // here recursively. This will happen if, for example, a control | |
66 // reflects wheel scroll messages to its parent. Bail out if we got | |
67 // here recursively. | |
68 static bool recursion_break = false; | |
69 if (recursion_break) | |
70 return false; | |
71 // Check if this window's class has a bad interaction with rerouting. | |
72 if (!IsCompatibleWithMouseWheelRedirection(window)) | |
73 return false; | |
74 | |
75 DWORD current_process = GetCurrentProcessId(); | |
76 POINT wheel_location = { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) }; | |
77 HWND window_under_wheel = WindowFromPoint(wheel_location); | |
78 | |
79 if (!CanRedirectMouseWheelFrom(window_under_wheel)) | |
80 return false; | |
81 | |
82 // Find the lowest Chrome window in the hierarchy that can be the | |
83 // target of mouse wheel redirection. | |
84 while (window != window_under_wheel) { | |
85 // If window_under_wheel is not a valid Chrome window, then return true to | |
86 // suppress further processing of the message. | |
87 if (!::IsWindow(window_under_wheel)) | |
88 return true; | |
89 DWORD wheel_window_process = 0; | |
90 GetWindowThreadProcessId(window_under_wheel, &wheel_window_process); | |
91 if (current_process != wheel_window_process) { | |
92 if (IsChild(window, window_under_wheel)) { | |
93 // If this message is reflected from a child window in a different | |
94 // process (happens with out of process windowed plugins) then | |
95 // we don't want to reroute the wheel message. | |
96 return false; | |
97 } else { | |
98 // The wheel is scrolling over an unrelated window. Make sure that we | |
99 // have marked that window as supporting mouse wheel rerouting. | |
100 // Otherwise, we cannot send random WM_MOUSEWHEEL messages to arbitrary | |
101 // windows. So just drop the message. | |
102 if (!WindowSupportsRerouteMouseWheel(window_under_wheel)) | |
103 return true; | |
104 } | |
105 } | |
106 | |
107 // window_under_wheel is a Chrome window. If allowed, redirect. | |
108 if (IsCompatibleWithMouseWheelRedirection(window_under_wheel)) { | |
109 AutoReset<bool> auto_reset_recursion_break(&recursion_break, true); | |
110 SendMessage(window_under_wheel, WM_MOUSEWHEEL, w_param, l_param); | |
111 return true; | |
112 } | |
113 // If redirection is disallowed, try the parent. | |
114 window_under_wheel = GetAncestor(window_under_wheel, GA_PARENT); | |
115 } | |
116 // If we traversed back to the starting point, we should process | |
117 // this message normally; return false. | |
118 return false; | |
119 } | |
120 | |
121 } // namespace views | |
OLD | NEW |