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
3 // found in the LICENSE file.
5 #include "content/browser/accessibility/accessibility_event_recorder.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/win/scoped_bstr.h"
16 #include "base/win/scoped_comptr.h"
17 #include "base/win/scoped_variant.h"
18 #include "content/browser/accessibility/accessibility_tree_formatter_utils_win.h"
19 #include "content/browser/accessibility/browser_accessibility_manager.h"
20 #include "content/browser/accessibility/browser_accessibility_win.h"
21 #include "third_party/iaccessible2/ia2_api_all.h"
22 #include "ui/base/win/atl_module.h"
28 std::string
RoleVariantToString(const base::win::ScopedVariant
& role
) {
29 if (role
.type() == VT_I4
) {
30 return base::UTF16ToUTF8(IAccessibleRoleToString(V_I4(&role
)));
31 } else if (role
.type() == VT_BSTR
) {
32 return base::UTF16ToUTF8(
33 base::string16(V_BSTR(&role
), SysStringLen(V_BSTR(&role
))));
38 HRESULT
QueryIAccessible2(IAccessible
* accessible
, IAccessible2
** accessible2
) {
39 base::win::ScopedComPtr
<IServiceProvider
> service_provider
;
40 HRESULT hr
= accessible
->QueryInterface(service_provider
.Receive());
41 return SUCCEEDED(hr
) ?
42 service_provider
->QueryService(IID_IAccessible2
, accessible2
) : hr
;
45 std::string
BstrToUTF8(BSTR bstr
) {
46 base::string16
str16(bstr
, SysStringLen(bstr
));
47 return base::UTF16ToUTF8(str16
);
50 std::string
AccessibilityEventToStringUTF8(int32 event_id
) {
51 return base::UTF16ToUTF8(AccessibilityEventToString(event_id
));
56 class AccessibilityEventRecorderWin
: public AccessibilityEventRecorder
{
58 explicit AccessibilityEventRecorderWin(BrowserAccessibilityManager
* manager
);
59 virtual ~AccessibilityEventRecorderWin();
61 // Callback registered by SetWinEventHook. Just calls OnWinEventHook.
62 static void CALLBACK
WinEventHookThunk(
72 // Called by the thunk registered by SetWinEventHook. Retrives accessibility
73 // info about the node the event was fired on and appends a string to
75 void OnWinEventHook(HWINEVENTHOOK handle
,
83 HWINEVENTHOOK win_event_hook_handle_
;
84 static AccessibilityEventRecorderWin
* instance_
;
88 AccessibilityEventRecorderWin
*
89 AccessibilityEventRecorderWin::instance_
= nullptr;
92 AccessibilityEventRecorder
* AccessibilityEventRecorder::Create(
93 BrowserAccessibilityManager
* manager
) {
94 return new AccessibilityEventRecorderWin(manager
);
98 void CALLBACK
AccessibilityEventRecorderWin::WinEventHookThunk(
107 instance_
->OnWinEventHook(handle
, event
, hwnd
, obj_id
, child_id
,
108 event_thread
, event_time
);
112 AccessibilityEventRecorderWin::AccessibilityEventRecorderWin(
113 BrowserAccessibilityManager
* manager
)
114 : AccessibilityEventRecorder(manager
) {
115 CHECK(!instance_
) << "There can be only one instance of"
116 << " WinAccessibilityEventMonitor at a time.";
118 win_event_hook_handle_
= SetWinEventHook(
121 GetModuleHandle(NULL
),
122 &AccessibilityEventRecorderWin::WinEventHookThunk
,
123 GetCurrentProcessId(),
124 0, // Hook all threads
128 AccessibilityEventRecorderWin::~AccessibilityEventRecorderWin() {
129 UnhookWinEvent(win_event_hook_handle_
);
133 void AccessibilityEventRecorderWin::OnWinEventHook(
134 HWINEVENTHOOK handle
,
141 base::win::ScopedComPtr
<IAccessible
> browser_accessible
;
142 HRESULT hr
= AccessibleObjectFromWindow(
146 reinterpret_cast<void**>(browser_accessible
.Receive()));
147 CHECK(SUCCEEDED(hr
)) << "Failure accessing accessible object from hwnd "
148 << hwnd
<< " obj_id=" << obj_id
<< " child_id="
151 base::win::ScopedVariant
childid_variant(child_id
);
152 base::win::ScopedComPtr
<IDispatch
> dispatch
;
153 hr
= browser_accessible
->get_accChild(childid_variant
, dispatch
.Receive());
154 CHECK(SUCCEEDED(hr
));
155 base::win::ScopedComPtr
<IAccessible
> iaccessible
;
156 dispatch
.QueryInterface(iaccessible
.Receive());
158 base::win::ScopedVariant
childid_self(CHILDID_SELF
);
159 base::win::ScopedVariant role
;
160 iaccessible
->get_accRole(childid_self
, role
.Receive());
161 base::win::ScopedBstr name_bstr
;
162 iaccessible
->get_accName(childid_self
, name_bstr
.Receive());
163 base::win::ScopedBstr value_bstr
;
164 iaccessible
->get_accValue(childid_self
, value_bstr
.Receive());
166 std::string log
= base::StringPrintf(
168 AccessibilityEventToStringUTF8(event
).c_str(),
169 RoleVariantToString(role
).c_str());
170 if (name_bstr
.Length() > 0)
171 log
+= base::StringPrintf(" name=\"%s\"", BstrToUTF8(name_bstr
).c_str());
172 if (value_bstr
.Length() > 0)
173 log
+= base::StringPrintf(" value=\"%s\"", BstrToUTF8(value_bstr
).c_str());
175 event_logs_
.push_back(log
);
178 } // namespace content