@@ -188,6 +188,53 @@ bool Element::IsInteractable() {
188
188
return result;
189
189
}
190
190
191
+ bool Element::IsFocusable () {
192
+ LOG (TRACE) << " Entering Element::IsFocusable" ;
193
+
194
+ bool result = false ;
195
+
196
+ CComPtr<IHTMLBodyElement> body;
197
+ HRESULT hr = this ->element_ ->QueryInterface <IHTMLBodyElement>(&body);
198
+ if (SUCCEEDED (hr) && body) {
199
+ // The <body> element is explicitly focusable.
200
+ return true ;
201
+ }
202
+
203
+ CComPtr<IHTMLDocument2> doc;
204
+ this ->GetContainingDocument (false , &doc);
205
+
206
+ CComPtr<IHTMLDocument3> document_element_doc;
207
+ hr = doc->QueryInterface <IHTMLDocument3>(&document_element_doc);
208
+ if (SUCCEEDED (hr) && document_element_doc) {
209
+ CComPtr<IHTMLElement> doc_element;
210
+ hr = document_element_doc->get_documentElement (&doc_element);
211
+ if (SUCCEEDED (hr) && doc_element && this ->element_ .IsEqualObject (doc_element)) {
212
+ // The document's documentElement is explicitly focusable.
213
+ return true ;
214
+ }
215
+ }
216
+
217
+ // The atom is just the definition of an anonymous
218
+ // function: "function() {...}"; Wrap it in another function so we can
219
+ // invoke it with our arguments without polluting the current namespace.
220
+ std::wstring script_source (L" (function() { return (" );
221
+ script_source += atoms::asString (atoms::IS_FOCUSABLE);
222
+ script_source += L" )})();" ;
223
+
224
+
225
+ Script script_wrapper (doc, script_source, 1 );
226
+ script_wrapper.AddArgument (this ->element_ );
227
+ int status_code = script_wrapper.Execute ();
228
+
229
+ if (status_code == WD_SUCCESS) {
230
+ result = script_wrapper.result ().boolVal == VARIANT_TRUE;
231
+ } else {
232
+ LOG (WARN) << " Failed to determine is element enabled" ;
233
+ }
234
+
235
+ return result;
236
+ }
237
+
191
238
bool Element::IsObscured (LocationInfo* click_location,
192
239
std::string* obscuring_element_description) {
193
240
CComPtr<ISVGElement> svg_element;
0 commit comments