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