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