| 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 |