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