OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/accessibility/accessibility_event_recorder.h" | 5 #include "content/browser/accessibility/accessibility_event_recorder.h" |
6 | 6 |
7 #include <oleacc.h> | 7 #include <oleacc.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 // info about the node the event was fired on and appends a string to | 88 // info about the node the event was fired on and appends a string to |
89 // the event log. | 89 // the event log. |
90 void OnWinEventHook(HWINEVENTHOOK handle, | 90 void OnWinEventHook(HWINEVENTHOOK handle, |
91 DWORD event, | 91 DWORD event, |
92 HWND hwnd, | 92 HWND hwnd, |
93 LONG obj_id, | 93 LONG obj_id, |
94 LONG child_id, | 94 LONG child_id, |
95 DWORD event_thread, | 95 DWORD event_thread, |
96 DWORD event_time); | 96 DWORD event_time); |
97 | 97 |
| 98 // Wrapper around AccessibleObjectFromWindow because the function call |
| 99 // inexplicably flakes sometimes on build/trybots. |
| 100 HRESULT AccessibleObjectFromWindowWrapper( |
| 101 HWND hwnd, DWORD dwId, REFIID riid, void **ppvObject); |
| 102 |
98 HWINEVENTHOOK win_event_hook_handle_; | 103 HWINEVENTHOOK win_event_hook_handle_; |
99 static AccessibilityEventRecorderWin* instance_; | 104 static AccessibilityEventRecorderWin* instance_; |
100 }; | 105 }; |
101 | 106 |
102 // static | 107 // static |
103 AccessibilityEventRecorderWin* | 108 AccessibilityEventRecorderWin* |
104 AccessibilityEventRecorderWin::instance_ = nullptr; | 109 AccessibilityEventRecorderWin::instance_ = nullptr; |
105 | 110 |
106 // static | 111 // static |
107 AccessibilityEventRecorder* AccessibilityEventRecorder::Create( | 112 AccessibilityEventRecorder* AccessibilityEventRecorder::Create( |
(...skipping 23 matching lines...) Expand all Loading... |
131 << " WinAccessibilityEventMonitor at a time."; | 136 << " WinAccessibilityEventMonitor at a time."; |
132 instance_ = this; | 137 instance_ = this; |
133 win_event_hook_handle_ = SetWinEventHook( | 138 win_event_hook_handle_ = SetWinEventHook( |
134 EVENT_MIN, | 139 EVENT_MIN, |
135 EVENT_MAX, | 140 EVENT_MAX, |
136 GetModuleHandle(NULL), | 141 GetModuleHandle(NULL), |
137 &AccessibilityEventRecorderWin::WinEventHookThunk, | 142 &AccessibilityEventRecorderWin::WinEventHookThunk, |
138 GetCurrentProcessId(), | 143 GetCurrentProcessId(), |
139 0, // Hook all threads | 144 0, // Hook all threads |
140 WINEVENT_INCONTEXT); | 145 WINEVENT_INCONTEXT); |
141 LOG(INFO) << "SetWinEventHook handle: " << win_event_hook_handle_; | |
142 CHECK(win_event_hook_handle_); | 146 CHECK(win_event_hook_handle_); |
143 } | 147 } |
144 | 148 |
145 AccessibilityEventRecorderWin::~AccessibilityEventRecorderWin() { | 149 AccessibilityEventRecorderWin::~AccessibilityEventRecorderWin() { |
146 UnhookWinEvent(win_event_hook_handle_); | 150 UnhookWinEvent(win_event_hook_handle_); |
147 instance_ = NULL; | 151 instance_ = NULL; |
148 } | 152 } |
149 | 153 |
150 void AccessibilityEventRecorderWin::OnWinEventHook( | 154 void AccessibilityEventRecorderWin::OnWinEventHook( |
151 HWINEVENTHOOK handle, | 155 HWINEVENTHOOK handle, |
152 DWORD event, | 156 DWORD event, |
153 HWND hwnd, | 157 HWND hwnd, |
154 LONG obj_id, | 158 LONG obj_id, |
155 LONG child_id, | 159 LONG child_id, |
156 DWORD event_thread, | 160 DWORD event_thread, |
157 DWORD event_time) { | 161 DWORD event_time) { |
158 // http://crbug.com/440579 TODO(dmazzoni): remove most logging in this file, | |
159 // or change to VLOG(1), once flakiness on CrWinClang testers is fixed. | |
160 LOG(INFO) << "OnWinEventHook handle=" << handle | |
161 << " event=" << event | |
162 << " hwnd=" << hwnd | |
163 << " obj_id=" << obj_id | |
164 << " child_id=" << child_id | |
165 << " event_thread=" << event_thread | |
166 << " event_time=" << event_time; | |
167 | |
168 base::win::ScopedComPtr<IAccessible> browser_accessible; | 162 base::win::ScopedComPtr<IAccessible> browser_accessible; |
169 HRESULT hr = AccessibleObjectFromWindow( | 163 HRESULT hr = AccessibleObjectFromWindowWrapper( |
170 hwnd, | 164 hwnd, |
171 obj_id, | 165 obj_id, |
172 IID_IAccessible, | 166 IID_IAccessible, |
173 reinterpret_cast<void**>(browser_accessible.Receive())); | 167 reinterpret_cast<void**>(browser_accessible.Receive())); |
174 if (!SUCCEEDED(hr)) { | 168 if (!SUCCEEDED(hr)) { |
175 // Note: our event hook will pick up some superfluous events we | 169 // Note: our event hook will pick up some superfluous events we |
176 // don't care about, so it's safe to just ignore these failures. | 170 // don't care about, so it's safe to just ignore these failures. |
177 // Same below for other HRESULT checks. | 171 // Same below for other HRESULT checks. |
178 LOG(INFO) << "Ignoring result " << hr << " from AccessibleObjectFromWindow"; | 172 VLOG(1) << "Ignoring result " << hr << " from AccessibleObjectFromWindow"; |
179 TCHAR name[MAX_PATH]; | |
180 GetClassName(hwnd, name, _countof(name)); | |
181 LOG(INFO) << "Hwnd " << hwnd << " class is " << name; | |
182 return; | 173 return; |
183 } | 174 } |
184 | 175 |
185 base::win::ScopedVariant childid_variant(child_id); | 176 base::win::ScopedVariant childid_variant(child_id); |
186 base::win::ScopedComPtr<IDispatch> dispatch; | 177 base::win::ScopedComPtr<IDispatch> dispatch; |
187 hr = browser_accessible->get_accChild(childid_variant, dispatch.Receive()); | 178 hr = browser_accessible->get_accChild(childid_variant, dispatch.Receive()); |
188 if (!SUCCEEDED(hr) || !dispatch) { | 179 if (!SUCCEEDED(hr) || !dispatch) { |
189 LOG(INFO) << "Ignoring result " << hr << " and result " << dispatch | 180 VLOG(1) << "Ignoring result " << hr << " and result " << dispatch |
190 << " from get_accChild"; | 181 << " from get_accChild"; |
191 return; | 182 return; |
192 } | 183 } |
193 | 184 |
194 base::win::ScopedComPtr<IAccessible> iaccessible; | 185 base::win::ScopedComPtr<IAccessible> iaccessible; |
195 hr = dispatch.QueryInterface(iaccessible.Receive()); | 186 hr = dispatch.QueryInterface(iaccessible.Receive()); |
196 if (!SUCCEEDED(hr)) { | 187 if (!SUCCEEDED(hr)) { |
197 LOG(INFO) << "Ignoring result " << hr << " from QueryInterface"; | 188 VLOG(1) << "Ignoring result " << hr << " from QueryInterface"; |
198 return; | 189 return; |
199 } | 190 } |
200 | 191 |
201 std::string event_str = AccessibilityEventToStringUTF8(event); | 192 std::string event_str = AccessibilityEventToStringUTF8(event); |
202 if (event_str.empty()) { | 193 if (event_str.empty()) { |
203 LOG(INFO) << "Ignoring event " << event; | 194 VLOG(1) << "Ignoring event " << event; |
204 return; | 195 return; |
205 } | 196 } |
206 | 197 |
207 base::win::ScopedVariant childid_self(CHILDID_SELF); | 198 base::win::ScopedVariant childid_self(CHILDID_SELF); |
208 base::win::ScopedVariant role; | 199 base::win::ScopedVariant role; |
209 iaccessible->get_accRole(childid_self, role.Receive()); | 200 iaccessible->get_accRole(childid_self, role.Receive()); |
210 base::win::ScopedBstr name_bstr; | 201 base::win::ScopedBstr name_bstr; |
211 iaccessible->get_accName(childid_self, name_bstr.Receive()); | 202 iaccessible->get_accName(childid_self, name_bstr.Receive()); |
212 base::win::ScopedBstr value_bstr; | 203 base::win::ScopedBstr value_bstr; |
213 iaccessible->get_accValue(childid_self, value_bstr.Receive()); | 204 iaccessible->get_accValue(childid_self, value_bstr.Receive()); |
(...skipping 23 matching lines...) Expand all Loading... |
237 IA2TextSegment new_text; | 228 IA2TextSegment new_text; |
238 if (SUCCEEDED(accessible_text->get_newText(&new_text))) { | 229 if (SUCCEEDED(accessible_text->get_newText(&new_text))) { |
239 log += base::StringPrintf(" new_text={'%s' start=%d end=%d}", | 230 log += base::StringPrintf(" new_text={'%s' start=%d end=%d}", |
240 BstrToUTF8(new_text.text).c_str(), | 231 BstrToUTF8(new_text.text).c_str(), |
241 new_text.start, | 232 new_text.start, |
242 new_text.end); | 233 new_text.end); |
243 } | 234 } |
244 } | 235 } |
245 } | 236 } |
246 | 237 |
247 LOG(INFO) << "Got event log: " << log; | |
248 | |
249 event_logs_.push_back(log); | 238 event_logs_.push_back(log); |
250 } | 239 } |
251 | 240 |
| 241 HRESULT AccessibilityEventRecorderWin::AccessibleObjectFromWindowWrapper( |
| 242 HWND hwnd, DWORD dw_id, REFIID riid, void** ppv_object) { |
| 243 HRESULT hr = ::AccessibleObjectFromWindow(hwnd, dw_id, riid, ppv_object); |
| 244 if (SUCCEEDED(hr)) |
| 245 return hr; |
| 246 |
| 247 // The above call to ::AccessibleObjectFromWindow fails for unknown |
| 248 // reasons every once in a while on the bots. Work around it by grabbing |
| 249 // the object directly from the BrowserAccessibilityManager. |
| 250 HWND accessibility_hwnd = |
| 251 manager_->delegate()->AccessibilityGetAcceleratedWidget(); |
| 252 if (accessibility_hwnd != hwnd) |
| 253 return E_FAIL; |
| 254 |
| 255 IAccessible* obj = manager_->GetRoot()->ToBrowserAccessibilityWin(); |
| 256 obj->AddRef(); |
| 257 *ppv_object = obj; |
| 258 return S_OK; |
| 259 } |
| 260 |
252 } // namespace content | 261 } // namespace content |
OLD | NEW |