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