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 "build/build_config.h"
6
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/common/chrome_paths.h"
17 #include "chrome/test/base/in_process_browser_test.h"
18 #include "chrome/test/base/interactive_test_utils.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/dom_operation_notification_details.h"
21 #include "content/public/browser/notification_registrar.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/render_widget_host_view.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "ui/events/keycodes/keyboard_codes.h"
28
29 // TODO(kbr): remove: http://crbug.com/222296
30 #if defined(OS_MACOSX)
31 #import "base/mac/mac_util.h"
32 #endif
33
34 using content::DomOperationNotificationDetails;
35 using content::NavigationController;
36
37 namespace {
38
39 const char kTestingPage[] = "/keyevents_test.html";
40 const char kSuppressEventJS[] =
41 "window.domAutomationController.send(setDefaultAction('%ls', %ls));";
42 const char kGetResultJS[] =
43 "window.domAutomationController.send(keyEventResult[%d]);";
44 const char kGetResultLengthJS[] =
45 "window.domAutomationController.send(keyEventResult.length);";
46 const char kGetFocusedElementJS[] =
47 "window.domAutomationController.send(focusedElement);";
48 const char kSetFocusedElementJS[] =
49 "window.domAutomationController.send(setFocusedElement('%ls'));";
50 const char kGetTextBoxValueJS[] =
51 "window.domAutomationController.send("
52 " document.getElementById('%ls').value);";
53 const char kSetTextBoxValueJS[] =
54 "window.domAutomationController.send("
55 " document.getElementById('%ls').value = '%ls');";
56 const char kStartTestJS[] =
57 "window.domAutomationController.send(startTest(%d));";
58
59 // Maximum lenght of the result array in KeyEventTestData structure.
60 const size_t kMaxResultLength = 10;
61
62 // A structure holding test data of a keyboard event.
63 // Each keyboard event may generate multiple result strings representing
64 // the result of keydown, keypress, keyup and textInput events.
65 // For keydown, keypress and keyup events, the format of the result string is:
66 // <type> <keyCode> <charCode> <ctrlKey> <shiftKey> <altKey> <commandKey>
67 // where <type> may be 'D' (keydown), 'P' (keypress) or 'U' (keyup).
68 // <ctrlKey>, <shiftKey> <altKey> and <commandKey> are boolean value indicating
69 // the state of corresponding modifier key.
70 // For textInput event, the format is: T <text>, where <text> is the text to be
71 // input.
72 // Please refer to chrome/test/data/keyevents_test.html for details.
73 struct KeyEventTestData {
74 ui::KeyboardCode key;
75 bool ctrl;
76 bool shift;
77 bool alt;
78 bool command;
79
80 bool suppress_keydown;
81 bool suppress_keypress;
82 bool suppress_keyup;
83 bool suppress_textinput;
84
85 int result_length;
86 const char* const result[kMaxResultLength];
87 };
88
GetBoolString(bool value)89 const wchar_t* GetBoolString(bool value) {
90 return value ? L"true" : L"false";
91 }
92
93 // A class to help wait for the finish of a key event test.
94 class TestFinishObserver : public content::NotificationObserver {
95 public:
TestFinishObserver(content::WebContents * web_contents)96 explicit TestFinishObserver(content::WebContents* web_contents)
97 : finished_(false), waiting_(false) {
98 registrar_.Add(this,
99 content::NOTIFICATION_DOM_OPERATION_RESPONSE,
100 content::Source<content::WebContents>(web_contents));
101 }
102
WaitForFinish()103 bool WaitForFinish() {
104 if (!finished_) {
105 waiting_ = true;
106 content::RunMessageLoop();
107 waiting_ = false;
108 }
109 return finished_;
110 }
111
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)112 virtual void Observe(int type,
113 const content::NotificationSource& source,
114 const content::NotificationDetails& details) OVERRIDE {
115 DCHECK(type == content::NOTIFICATION_DOM_OPERATION_RESPONSE);
116 content::Details<DomOperationNotificationDetails> dom_op_details(details);
117 // We might receive responses for other script execution, but we only
118 // care about the test finished message.
119 if (dom_op_details->json == "\"FINISHED\"") {
120 finished_ = true;
121 if (waiting_)
122 base::MessageLoopForUI::current()->Quit();
123 }
124 }
125
126 private:
127 bool finished_;
128 bool waiting_;
129 content::NotificationRegistrar registrar_;
130
131 DISALLOW_COPY_AND_ASSIGN(TestFinishObserver);
132 };
133
134 class BrowserKeyEventsTest : public InProcessBrowserTest {
135 public:
BrowserKeyEventsTest()136 BrowserKeyEventsTest() {}
137
IsViewFocused(ViewID vid)138 bool IsViewFocused(ViewID vid) {
139 return ui_test_utils::IsViewFocused(browser(), vid);
140 }
141
ClickOnView(ViewID vid)142 void ClickOnView(ViewID vid) {
143 ui_test_utils::ClickOnView(browser(), vid);
144 }
145
146 // Set the suppress flag of an event specified by |type|. If |suppress| is
147 // true then the web page will suppress all events with |type|. Following
148 // event types are supported: keydown, keypress, keyup and textInput.
SuppressEventByType(int tab_index,const wchar_t * type,bool suppress)149 void SuppressEventByType(int tab_index, const wchar_t* type, bool suppress) {
150 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
151 bool actual;
152 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
153 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
154 base::StringPrintf(kSuppressEventJS, type, GetBoolString(!suppress)),
155 &actual));
156 ASSERT_EQ(!suppress, actual);
157 }
158
SuppressEvents(int tab_index,bool keydown,bool keypress,bool keyup,bool textinput)159 void SuppressEvents(int tab_index, bool keydown, bool keypress,
160 bool keyup, bool textinput) {
161 ASSERT_NO_FATAL_FAILURE(
162 SuppressEventByType(tab_index, L"keydown", keydown));
163 ASSERT_NO_FATAL_FAILURE(
164 SuppressEventByType(tab_index, L"keypress", keypress));
165 ASSERT_NO_FATAL_FAILURE(
166 SuppressEventByType(tab_index, L"keyup", keyup));
167 ASSERT_NO_FATAL_FAILURE(
168 SuppressEventByType(tab_index, L"textInput", textinput));
169 }
170
SuppressAllEvents(int tab_index,bool suppress)171 void SuppressAllEvents(int tab_index, bool suppress) {
172 SuppressEvents(tab_index, suppress, suppress, suppress, suppress);
173 }
174
GetResultLength(int tab_index,int * length)175 void GetResultLength(int tab_index, int* length) {
176 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
177 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
178 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
179 kGetResultLengthJS,
180 length));
181 }
182
CheckResult(int tab_index,int length,const char * const result[])183 void CheckResult(int tab_index, int length, const char* const result[]) {
184 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
185 int actual_length;
186 ASSERT_NO_FATAL_FAILURE(GetResultLength(tab_index, &actual_length));
187 ASSERT_GE(actual_length, length);
188 for (int i = 0; i < actual_length; ++i) {
189 std::string actual;
190 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
191 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
192 base::StringPrintf(kGetResultJS, i),
193 &actual));
194
195 // If more events were received than expected, then the additional events
196 // must be keyup events.
197 if (i < length)
198 ASSERT_STREQ(result[i], actual.c_str());
199 else
200 ASSERT_EQ('U', actual[0]);
201 }
202 }
203
CheckFocusedElement(int tab_index,const wchar_t * focused)204 void CheckFocusedElement(int tab_index, const wchar_t* focused) {
205 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
206 std::string actual;
207 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
208 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
209 kGetFocusedElementJS,
210 &actual));
211 ASSERT_EQ(base::WideToUTF8(focused), actual);
212 }
213
SetFocusedElement(int tab_index,const wchar_t * focused)214 void SetFocusedElement(int tab_index, const wchar_t* focused) {
215 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
216 bool actual;
217 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
218 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
219 base::StringPrintf(kSetFocusedElementJS, focused),
220 &actual));
221 ASSERT_TRUE(actual);
222 }
223
CheckTextBoxValue(int tab_index,const wchar_t * id,const wchar_t * value)224 void CheckTextBoxValue(int tab_index, const wchar_t* id,
225 const wchar_t* value) {
226 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
227 std::string actual;
228 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
229 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
230 base::StringPrintf(kGetTextBoxValueJS, id),
231 &actual));
232 ASSERT_EQ(base::WideToUTF8(value), actual);
233 }
234
SetTextBoxValue(int tab_index,const wchar_t * id,const wchar_t * value)235 void SetTextBoxValue(int tab_index, const wchar_t* id,
236 const wchar_t* value) {
237 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
238 std::string actual;
239 ASSERT_TRUE(content::ExecuteScriptAndExtractString(
240 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
241 base::StringPrintf(kSetTextBoxValueJS, id, value),
242 &actual));
243 ASSERT_EQ(base::WideToUTF8(value), actual);
244 }
245
StartTest(int tab_index,int result_length)246 void StartTest(int tab_index, int result_length) {
247 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
248 bool actual;
249 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
250 browser()->tab_strip_model()->GetWebContentsAt(tab_index),
251 base::StringPrintf(kStartTestJS, result_length),
252 &actual));
253 ASSERT_TRUE(actual);
254 }
255
TestKeyEvent(int tab_index,const KeyEventTestData & test)256 void TestKeyEvent(int tab_index, const KeyEventTestData& test) {
257 ASSERT_LT(tab_index, browser()->tab_strip_model()->count());
258 ASSERT_EQ(tab_index, browser()->tab_strip_model()->active_index());
259
260 // Inform our testing web page that we are about to start testing a key
261 // event.
262 ASSERT_NO_FATAL_FAILURE(StartTest(tab_index, test.result_length));
263 ASSERT_NO_FATAL_FAILURE(SuppressEvents(
264 tab_index, test.suppress_keydown, test.suppress_keypress,
265 test.suppress_keyup, test.suppress_textinput));
266
267 // We need to create a finish observer before sending the key event,
268 // because the test finished message might be arrived before returning
269 // from the SendKeyPressSync() method.
270 TestFinishObserver finish_observer(
271 browser()->tab_strip_model()->GetWebContentsAt(tab_index));
272
273 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
274 browser(), test.key, test.ctrl, test.shift, test.alt, test.command));
275 ASSERT_TRUE(finish_observer.WaitForFinish());
276 ASSERT_NO_FATAL_FAILURE(CheckResult(
277 tab_index, test.result_length, test.result));
278 }
279
GetTestDataDescription(const KeyEventTestData & data)280 std::string GetTestDataDescription(const KeyEventTestData& data) {
281 std::string desc = base::StringPrintf(
282 " VKEY:0x%02x, ctrl:%d, shift:%d, alt:%d, command:%d\n"
283 " Suppress: keydown:%d, keypress:%d, keyup:%d, textInput:%d\n"
284 " Expected results(%d):\n",
285 data.key, data.ctrl, data.shift, data.alt, data.command,
286 data.suppress_keydown, data.suppress_keypress, data.suppress_keyup,
287 data.suppress_textinput, data.result_length);
288 for (int i = 0; i < data.result_length; ++i) {
289 desc.append(" ");
290 desc.append(data.result[i]);
291 desc.append("\n");
292 }
293 return desc;
294 }
295 };
296
297 // Flaky: http://crbug.com/129235, http://crbug.com/81451.
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,DISABLED_NormalKeyEvents)298 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_NormalKeyEvents) {
299 static const KeyEventTestData kTestNoInput[] = {
300 // a
301 { ui::VKEY_A, false, false, false, false,
302 false, false, false, false, 3,
303 { "D 65 0 false false false false",
304 "P 97 97 false false false false",
305 "U 65 0 false false false false" } },
306 // shift-a
307 { ui::VKEY_A, false, true, false, false,
308 false, false, false, false, 5,
309 { "D 16 0 false true false false",
310 "D 65 0 false true false false",
311 "P 65 65 false true false false",
312 "U 65 0 false true false false",
313 "U 16 0 false true false false" } },
314 // a, suppress keydown
315 { ui::VKEY_A, false, false, false, false,
316 true, false, false, false, 2,
317 { "D 65 0 false false false false",
318 "U 65 0 false false false false" } },
319 };
320
321 static const KeyEventTestData kTestWithInput[] = {
322 // a
323 { ui::VKEY_A, false, false, false, false,
324 false, false, false, false, 4,
325 { "D 65 0 false false false false",
326 "P 97 97 false false false false",
327 "T a",
328 "U 65 0 false false false false" } },
329 // shift-a
330 { ui::VKEY_A, false, true, false, false,
331 false, false, false, false, 6,
332 { "D 16 0 false true false false",
333 "D 65 0 false true false false",
334 "P 65 65 false true false false",
335 "T A",
336 "U 65 0 false true false false",
337 "U 16 0 false true false false" } },
338 // a, suppress keydown
339 { ui::VKEY_A, false, false, false, false,
340 true, false, false, false, 2,
341 { "D 65 0 false false false false",
342 "U 65 0 false false false false" } },
343 // a, suppress keypress
344 { ui::VKEY_A, false, false, false, false,
345 false, true, false, false, 3,
346 { "D 65 0 false false false false",
347 "P 97 97 false false false false",
348 "U 65 0 false false false false" } },
349 // a, suppress textInput
350 { ui::VKEY_A, false, false, false, false,
351 false, false, false, true, 4,
352 { "D 65 0 false false false false",
353 "P 97 97 false false false false",
354 "T a",
355 "U 65 0 false false false false" } },
356 };
357
358 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
359
360 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
361 GURL url = embedded_test_server()->GetURL(kTestingPage);
362 ui_test_utils::NavigateToURL(browser(), url);
363
364 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
365 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
366
367 int tab_index = browser()->tab_strip_model()->active_index();
368 for (size_t i = 0; i < arraysize(kTestNoInput); ++i) {
369 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestNoInput[i]))
370 << "kTestNoInput[" << i << "] failed:\n"
371 << GetTestDataDescription(kTestNoInput[i]);
372 }
373
374 // Input in normal text box.
375 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
376 for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
377 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
378 << "kTestWithInput[" << i << "] in text box failed:\n"
379 << GetTestDataDescription(kTestWithInput[i]);
380 }
381 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA"));
382
383 // Input in password box.
384 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B"));
385 for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
386 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
387 << "kTestWithInput[" << i << "] in password box failed:\n"
388 << GetTestDataDescription(kTestWithInput[i]);
389 }
390 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA"));
391 }
392
393 #if defined(OS_WIN) || defined(OS_LINUX)
394
395 #if defined(OS_LINUX) || defined(OS_WIN)
396 // Linux: http://crbug.com/129235
397 // Win: crbug.com/269564
398 #define MAYBE_CtrlKeyEvents DISABLED_CtrlKeyEvents
399 #else
400 #define MAYBE_CtrlKeyEvents CtrlKeyEvents
401 #endif
402
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,MAYBE_CtrlKeyEvents)403 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_CtrlKeyEvents) {
404 static const KeyEventTestData kTestCtrlF = {
405 ui::VKEY_F, true, false, false, false,
406 false, false, false, false, 2,
407 { "D 17 0 true false false false",
408 "D 70 0 true false false false" }
409 };
410
411 static const KeyEventTestData kTestCtrlFSuppressKeyDown = {
412 ui::VKEY_F, true, false, false, false,
413 true, false, false, false, 4,
414 { "D 17 0 true false false false",
415 "D 70 0 true false false false",
416 "U 70 0 true false false false",
417 "U 17 0 true false false false" }
418 };
419
420 // Ctrl+Z doesn't bind to any accelerators, which then should generate a
421 // keypress event with charCode=26.
422 static const KeyEventTestData kTestCtrlZ = {
423 ui::VKEY_Z, true, false, false, false,
424 false, false, false, false, 5,
425 { "D 17 0 true false false false",
426 "D 90 0 true false false false",
427 "P 26 26 true false false false",
428 "U 90 0 true false false false",
429 "U 17 0 true false false false" }
430 };
431
432 static const KeyEventTestData kTestCtrlZSuppressKeyDown = {
433 ui::VKEY_Z, true, false, false, false,
434 true, false, false, false, 4,
435 { "D 17 0 true false false false",
436 "D 90 0 true false false false",
437 "U 90 0 true false false false",
438 "U 17 0 true false false false" }
439 };
440
441 // Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
442 static const KeyEventTestData kTestCtrlEnter = {
443 ui::VKEY_RETURN, true, false, false, false,
444 false, false, false, false, 5,
445 { "D 17 0 true false false false",
446 "D 13 0 true false false false",
447 "P 10 10 true false false false",
448 "U 13 0 true false false false",
449 "U 17 0 true false false false" }
450 };
451
452 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
453
454 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
455 GURL url = embedded_test_server()->GetURL(kTestingPage);
456 ui_test_utils::NavigateToURL(browser(), url);
457
458 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
459 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
460
461 int tab_index = browser()->tab_strip_model()->active_index();
462 // Press Ctrl+F, which will make the Find box open and request focus.
463 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
464 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
465
466 // Press Escape to close the Find box and move the focus back to the web page.
467 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
468 browser(), ui::VKEY_ESCAPE, false, false, false, false));
469 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
470
471 // Press Ctrl+F with keydown suppressed shall not open the find box.
472 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlFSuppressKeyDown));
473 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
474
475 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZ));
476 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown));
477 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter));
478 }
479 #elif defined(OS_MACOSX)
480 // http://crbug.com/81451
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,DISABLED_CommandKeyEvents)481 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_CommandKeyEvents) {
482 static const KeyEventTestData kTestCmdF = {
483 ui::VKEY_F, false, false, false, true,
484 false, false, false, false, 2,
485 { "D 91 0 false false false true",
486 "D 70 0 false false false true" }
487 };
488
489 // On Mac we don't send key up events when command modifier is down.
490 static const KeyEventTestData kTestCmdFSuppressKeyDown = {
491 ui::VKEY_F, false, false, false, true,
492 true, false, false, false, 3,
493 { "D 91 0 false false false true",
494 "D 70 0 false false false true",
495 "U 91 0 false false false true" }
496 };
497
498 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
499
500 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
501 GURL url = embedded_test_server()->GetURL(kTestingPage);
502 ui_test_utils::NavigateToURL(browser(), url);
503
504 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
505 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
506
507 int tab_index = browser()->tab_strip_model()->active_index();
508 // Press Cmd+F, which will make the Find box open and request focus.
509 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF));
510 EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
511
512 // Press Escape to close the Find box and move the focus back to the web page.
513 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
514 browser(), ui::VKEY_ESCAPE, false, false, false, false));
515 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
516
517 // Press Cmd+F with keydown suppressed shall not open the find box.
518 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown));
519 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
520 }
521 #endif
522
523 // Flaky: http://crbug.com/81451 , http://crbug.com/129235 ,
524 // also fails on Windows.
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,DISABLED_AccessKeys)525 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_AccessKeys) {
526 #if defined(OS_MACOSX)
527 // On Mac, access keys use ctrl+alt modifiers.
528 static const KeyEventTestData kTestAccessA = {
529 ui::VKEY_A, true, false, true, false,
530 false, false, false, false, 6,
531 { "D 17 0 true false false false",
532 "D 18 0 true false true false",
533 "D 65 0 true false true false",
534 "U 65 0 true false true false",
535 "U 18 0 true false true false",
536 "U 17 0 true false false false" }
537 };
538
539 static const KeyEventTestData kTestAccessDSuppress = {
540 ui::VKEY_D, true, false, true, false,
541 true, true, true, false, 6,
542 { "D 17 0 true false false false",
543 "D 18 0 true false true false",
544 "D 68 0 true false true false",
545 "U 68 0 true false true false",
546 "U 18 0 true false true false",
547 "U 17 0 true false false false" }
548 };
549
550 static const KeyEventTestData kTestAccess1 = {
551 ui::VKEY_1, true, false, true, false,
552 false, false, false, false, 6,
553 { "D 17 0 true false false false",
554 "D 18 0 true false true false",
555 "D 49 0 true false true false",
556 "U 49 0 true false true false",
557 "U 18 0 true false true false",
558 "U 17 0 true false false false" }
559 };
560 #else
561 static const KeyEventTestData kTestAccessA = {
562 ui::VKEY_A, false, false, true, false,
563 false, false, false, false, 4,
564 { "D 18 0 false false true false",
565 "D 65 0 false false true false",
566 "U 65 0 false false true false",
567 "U 18 0 false false true false" }
568 };
569
570 static const KeyEventTestData kTestAccessD = {
571 ui::VKEY_D, false, false, true, false,
572 false, false, false, false, 2,
573 { "D 18 0 false false true false",
574 "D 68 0 false false true false" }
575 };
576
577 static const KeyEventTestData kTestAccessDSuppress = {
578 ui::VKEY_D, false, false, true, false,
579 true, true, true, false, 4,
580 { "D 18 0 false false true false",
581 "D 68 0 false false true false",
582 "U 68 0 false false true false",
583 "U 18 0 false false true false" }
584 };
585
586 #if !defined(USE_ASH)
587 static const KeyEventTestData kTestAccess1 = {
588 ui::VKEY_1, false, false, true, false,
589 false, false, false, false, 4,
590 { "D 18 0 false false true false",
591 "D 49 0 false false true false",
592 "U 49 0 false false true false",
593 "U 18 0 false false true false" }
594 };
595 #endif
596 #endif
597
598 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
599
600 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
601 GURL url = embedded_test_server()->GetURL(kTestingPage);
602 ui_test_utils::NavigateToURL(browser(), url);
603
604 content::RunAllPendingInMessageLoop();
605 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
606 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
607
608 int tab_index = browser()->tab_strip_model()->active_index();
609 // Make sure no element is focused.
610 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
611 // Alt+A should focus the element with accesskey = "A".
612 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessA));
613 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A"));
614
615 // Blur the focused element.
616 EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
617 // Make sure no element is focused.
618 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
619
620 #if !defined(OS_MACOSX)
621 // Alt+D should move the focus to the location entry.
622 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD));
623
624 // TODO(isherman): This is an experimental change to help diagnose
625 // http://crbug.com/55713
626 content::RunAllPendingInMessageLoop();
627 EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
628 // No element should be focused, as Alt+D was handled by the browser.
629 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
630
631 // Move the focus back to the web page.
632 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
633 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
634
635 // Make sure no element is focused.
636 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
637 #endif
638
639 // If the keydown event is suppressed, then Alt+D should be handled as an
640 // accesskey rather than an accelerator key. Activation of an accesskey is not
641 // a part of the default action of the key event, so it should not be
642 // suppressed at all.
643 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress));
644 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
645 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D"));
646
647 // Blur the focused element.
648 EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
649 // Make sure no element is focused.
650 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
651 #if !defined(USE_ASH)
652 // On Ash, alt-1..9 are assigned as window selection global accelerators, so
653 // they can not be used as accesskeys.
654 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1));
655 EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1"));
656 #endif
657 }
658
659 // Flaky, http://crbug.com/69475.
660 #if defined(OS_LINUX) || defined(OS_WIN)
661 #define MAYBE_ReservedAccelerators DISABLED_ReservedAccelerators
662 #else
663 #define MAYBE_ReservedAccelerators ReservedAccelerators
664 #endif
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,MAYBE_ReservedAccelerators)665 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
666 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
667
668 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
669 GURL url = embedded_test_server()->GetURL(kTestingPage);
670 ui_test_utils::NavigateToURL(browser(), url);
671
672 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
673 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
674
675 ASSERT_EQ(1, browser()->tab_strip_model()->count());
676
677 static const KeyEventTestData kTestCtrlOrCmdT = {
678 #if defined(OS_MACOSX)
679 ui::VKEY_T, false, false, false, true,
680 true, false, false, false, 1,
681 { "D 91 0 false false false true" }
682 #else
683 ui::VKEY_T, true, false, false, false,
684 true, false, false, false, 1,
685 { "D 17 0 true false false false" }
686 #endif
687 };
688
689 content::WindowedNotificationObserver wait_for_new_tab(
690 chrome::NOTIFICATION_TAB_PARENTED,
691 content::NotificationService::AllSources());
692
693 // Press Ctrl/Cmd+T, which will open a new tab. It cannot be suppressed.
694 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlOrCmdT));
695 wait_for_new_tab.Wait();
696
697 int result_length;
698 ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
699 EXPECT_EQ(1, result_length);
700
701 EXPECT_EQ(2, browser()->tab_strip_model()->count());
702 ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
703
704 // Because of issue <http://crbug.com/65375>, switching back to the first tab
705 // may cause the focus to be grabbed by omnibox. So instead, we load our
706 // testing page in the newly created tab and try Cmd-W here.
707 ui_test_utils::NavigateToURL(browser(), url);
708
709 // Make sure the focus is in the testing page.
710 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
711 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
712
713 // Reserved accelerators can't be suppressed.
714 ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));
715
716 content::WebContentsDestroyedWatcher destroyed_watcher(
717 browser()->tab_strip_model()->GetWebContentsAt(1));
718
719 // Press Ctrl/Cmd+W, which will close the tab.
720 #if defined(OS_MACOSX)
721 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
722 browser(), ui::VKEY_W, false, false, false, true));
723 #else
724 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
725 browser(), ui::VKEY_W, true, false, false, false));
726 #endif
727
728 ASSERT_NO_FATAL_FAILURE(destroyed_watcher.Wait());
729
730 EXPECT_EQ(1, browser()->tab_strip_model()->count());
731 }
732
733 #if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,EditorKeyBindings)734 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) {
735 // TODO(kbr): re-enable: http://crbug.com/222296
736 if (base::mac::IsOSMountainLionOrLater())
737 return;
738
739 static const KeyEventTestData kTestCtrlA = {
740 ui::VKEY_A, true, false, false, false,
741 false, false, false, false, 4,
742 { "D 17 0 true false false false",
743 "D 65 0 true false false false",
744 "U 65 0 true false false false",
745 "U 17 0 true false false false" }
746 };
747
748 static const KeyEventTestData kTestCtrlF = {
749 ui::VKEY_F, true, false, false, false,
750 false, false, false, false, 4,
751 { "D 17 0 true false false false",
752 "D 70 0 true false false false",
753 "U 70 0 true false false false",
754 "U 17 0 true false false false" }
755 };
756
757 static const KeyEventTestData kTestCtrlK = {
758 ui::VKEY_K, true, false, false, false,
759 false, false, false, false, 4,
760 { "D 17 0 true false false false",
761 "D 75 0 true false false false",
762 "U 75 0 true false false false",
763 "U 17 0 true false false false" }
764 };
765
766 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
767
768 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
769 GURL url = embedded_test_server()->GetURL(kTestingPage);
770 ui_test_utils::NavigateToURL(browser(), url);
771
772 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
773 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
774
775 int tab_index = browser()->tab_strip_model()->active_index();
776 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
777 ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello"));
778 // Move the caret to the beginning of the line.
779 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA));
780 // Forward one character
781 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
782 // Delete to the end of the line.
783 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK));
784 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H"));
785 }
786 #endif
787
788 // See http://crbug.com/147579
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,DISABLED_PageUpDownKeys)789 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_PageUpDownKeys) {
790 static const KeyEventTestData kTestPageUp = {
791 ui::VKEY_PRIOR, false, false, false, false,
792 false, false, false, false, 2,
793 { "D 33 0 false false false false",
794 "U 33 0 false false false false" }
795 };
796
797 static const KeyEventTestData kTestPageDown = {
798 ui::VKEY_NEXT, false, false, false, false,
799 false, false, false, false, 2,
800 { "D 34 0 false false false false",
801 "U 34 0 false false false false" }
802 };
803
804 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
805
806 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
807 GURL url = embedded_test_server()->GetURL(kTestingPage);
808 ui_test_utils::NavigateToURL(browser(), url);
809
810 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
811 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
812
813 int tab_index = browser()->tab_strip_model()->active_index();
814 ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
815 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp));
816 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown));
817 EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L""));
818 }
819
820 #if defined(OS_WIN)
821 // AltKey is enabled only on Windows. See crbug.com/114537.
IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest,FocusMenuBarByAltKey)822 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FocusMenuBarByAltKey) {
823 static const KeyEventTestData kTestAltKey = {
824 ui::VKEY_MENU, false, false, false, false,
825 false, false, false, false, 2,
826 { "D 18 0 false false true false",
827 "U 18 0 false false true false" }
828 };
829
830 static const KeyEventTestData kTestAltKeySuppress = {
831 ui::VKEY_MENU, false, false, false, false,
832 true, false, false, false, 2,
833 { "D 18 0 false false true false",
834 "U 18 0 false false true false" }
835 };
836
837 static const KeyEventTestData kTestCtrlAltKey = {
838 ui::VKEY_MENU, true, false, false, false,
839 false, false, false, false, 4,
840 { "D 17 0 true false false false",
841 "D 18 0 true false true false",
842 "U 18 0 true false true false",
843 "U 17 0 true false false false" }
844 };
845
846 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
847
848 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
849 GURL url = embedded_test_server()->GetURL(kTestingPage);
850 ui_test_utils::NavigateToURL(browser(), url);
851
852 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
853 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
854
855 int tab_index = browser()->tab_strip_model()->active_index();
856 // Press and release Alt key to focus wrench menu button.
857 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKey));
858 EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU));
859
860 ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
861 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
862
863 // Alt key can be suppressed.
864 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKeySuppress));
865 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
866
867 // Ctrl+Alt should have no effect.
868 EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlAltKey));
869 ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
870 }
871 #endif
872
873 } // namespace
874