1 // Copyright (c) 2012 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 "ui/base/win/hwnd_subclass.h" 6 7 #include <algorithm> 8 9 #include "base/logging.h" 10 #include "base/memory/scoped_vector.h" 11 #include "base/memory/singleton.h" 12 #include "ui/gfx/win/dpi.h" 13 #include "ui/gfx/win/hwnd_util.h" 14 15 namespace { 16 const char kHWNDSubclassKey[] = "__UI_BASE_WIN_HWND_SUBCLASS_PROC__"; 17 18 LRESULT CALLBACK WndProc(HWND hwnd, 19 UINT message, 20 WPARAM w_param, 21 LPARAM l_param) { 22 ui::HWNDSubclass* wrapped_wnd_proc = 23 reinterpret_cast<ui::HWNDSubclass*>( 24 ui::ViewProp::GetValue(hwnd, kHWNDSubclassKey)); 25 return wrapped_wnd_proc ? wrapped_wnd_proc->OnWndProc(hwnd, 26 message, 27 w_param, 28 l_param) 29 : DefWindowProc(hwnd, message, w_param, l_param); 30 } 31 32 WNDPROC GetCurrentWndProc(HWND target) { 33 return reinterpret_cast<WNDPROC>(GetWindowLongPtr(target, GWLP_WNDPROC)); 34 } 35 36 // Not defined before Win7 37 BOOL GetTouchInputInfoWrapper(HTOUCHINPUT handle, UINT count, 38 PTOUCHINPUT pointer, int size) { 39 typedef BOOL(WINAPI *GetTouchInputInfoPtr)(HTOUCHINPUT, UINT, 40 PTOUCHINPUT, int); 41 GetTouchInputInfoPtr get_touch_input_info_func = 42 reinterpret_cast<GetTouchInputInfoPtr>( 43 GetProcAddress(GetModuleHandleA("user32.dll"), "GetTouchInputInfo")); 44 if (get_touch_input_info_func) 45 return get_touch_input_info_func(handle, count, pointer, size); 46 return FALSE; 47 } 48 49 } // namespace 50 51 namespace ui { 52 53 // Singleton factory that creates and manages the lifetime of all 54 // ui::HWNDSubclass objects. 55 class HWNDSubclass::HWNDSubclassFactory { 56 public: 57 static HWNDSubclassFactory* GetInstance() { 58 return Singleton<HWNDSubclassFactory, 59 LeakySingletonTraits<HWNDSubclassFactory> >::get(); 60 } 61 62 // Returns a non-null HWNDSubclass corresponding to the HWND |target|. Creates 63 // one if none exists. Retains ownership of the returned pointer. 64 HWNDSubclass* GetHwndSubclassForTarget(HWND target) { 65 DCHECK(target); 66 HWNDSubclass* subclass = reinterpret_cast<HWNDSubclass*>( 67 ui::ViewProp::GetValue(target, kHWNDSubclassKey)); 68 if (!subclass) { 69 subclass = new ui::HWNDSubclass(target); 70 hwnd_subclasses_.push_back(subclass); 71 } 72 return subclass; 73 } 74 75 const ScopedVector<HWNDSubclass>& hwnd_subclasses() { 76 return hwnd_subclasses_; 77 } 78 79 private: 80 friend struct DefaultSingletonTraits<HWNDSubclassFactory>; 81 82 HWNDSubclassFactory() {} 83 84 ScopedVector<HWNDSubclass> hwnd_subclasses_; 85 86 DISALLOW_COPY_AND_ASSIGN(HWNDSubclassFactory); 87 }; 88 89 // static 90 void HWNDSubclass::AddFilterToTarget(HWND target, HWNDMessageFilter* filter) { 91 HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget( 92 target)->AddFilter(filter); 93 } 94 95 // static 96 void HWNDSubclass::RemoveFilterFromAllTargets(HWNDMessageFilter* filter) { 97 HWNDSubclassFactory* factory = HWNDSubclassFactory::GetInstance(); 98 ScopedVector<ui::HWNDSubclass>::const_iterator it; 99 for (it = factory->hwnd_subclasses().begin(); 100 it != factory->hwnd_subclasses().end(); ++it) 101 (*it)->RemoveFilter(filter); 102 } 103 104 // static 105 HWNDSubclass* HWNDSubclass::GetHwndSubclassForTarget(HWND target) { 106 return HWNDSubclassFactory::GetInstance()->GetHwndSubclassForTarget(target); 107 } 108 109 void HWNDSubclass::AddFilter(HWNDMessageFilter* filter) { 110 DCHECK(filter); 111 if (std::find(filters_.begin(), filters_.end(), filter) == filters_.end()) 112 filters_.push_back(filter); 113 } 114 115 void HWNDSubclass::RemoveFilter(HWNDMessageFilter* filter) { 116 std::vector<HWNDMessageFilter*>::iterator it = 117 std::find(filters_.begin(), filters_.end(), filter); 118 if (it != filters_.end()) 119 filters_.erase(it); 120 } 121 122 HWNDSubclass::HWNDSubclass(HWND target) 123 : target_(target), 124 original_wnd_proc_(GetCurrentWndProc(target)), 125 prop_(target, kHWNDSubclassKey, this) { 126 gfx::SetWindowProc(target_, &WndProc); 127 } 128 129 HWNDSubclass::~HWNDSubclass() { 130 } 131 132 LRESULT HWNDSubclass::OnWndProc(HWND hwnd, 133 UINT message, 134 WPARAM w_param, 135 LPARAM l_param) { 136 137 // Touch messages are always passed in screen coordinates. If the OS is 138 // scaled, but the app is not DPI aware, then then WM_TOUCH might be 139 // intended for a different window. 140 if (message == WM_TOUCH) { 141 TOUCHINPUT point; 142 143 if (GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param), 1, 144 &point, sizeof(TOUCHINPUT))) { 145 POINT touch_location = { 146 TOUCH_COORD_TO_PIXEL(point.x) / 147 gfx::win::GetUndocumentedDPITouchScale(), 148 TOUCH_COORD_TO_PIXEL(point.y) / 149 gfx::win::GetUndocumentedDPITouchScale()}; 150 HWND actual_target = WindowFromPoint(touch_location); 151 if (actual_target != hwnd) { 152 return SendMessage(actual_target, message, w_param, l_param); 153 } 154 } 155 } 156 157 for (std::vector<HWNDMessageFilter*>::iterator it = filters_.begin(); 158 it != filters_.end(); ++it) { 159 LRESULT l_result = 0; 160 if ((*it)->FilterMessage(hwnd, message, w_param, l_param, &l_result)) 161 return l_result; 162 } 163 164 // In most cases, |original_wnd_proc_| will take care of calling 165 // DefWindowProc. 166 return CallWindowProc(original_wnd_proc_, hwnd, message, w_param, l_param); 167 } 168 169 HWNDMessageFilter::~HWNDMessageFilter() { 170 HWNDSubclass::RemoveFilterFromAllTargets(this); 171 } 172 173 } // namespace ui 174