8c95ada3850fda17a7fb978173f675004c718756
[platform/framework/web/crosswalk.git] / src / chrome / browser / browser_keyevents_browsertest.cc
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
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:
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
103   bool WaitForFinish() {
104     if (!finished_) {
105       waiting_ = true;
106       content::RunMessageLoop();
107       waiting_ = false;
108     }
109     return finished_;
110   }
111
112   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:
136   BrowserKeyEventsTest() {}
137
138   bool IsViewFocused(ViewID vid) {
139     return ui_test_utils::IsViewFocused(browser(), vid);
140   }
141
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.
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
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
171   void SuppressAllEvents(int tab_index, bool suppress) {
172     SuppressEvents(tab_index, suppress, suppress, suppress, suppress);
173   }
174
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
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
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
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
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
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
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
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
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.
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
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
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.
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
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)
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
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.
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