browser_keyevents_browsertest.cc revision 8bcbed890bc3ce4d7a057a8f32cab53fa534672e
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#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[] = "/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        base::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// Flaky: http://crbug.com/129235, http://crbug.com/81451.
302IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_NormalKeyEvents) {
303  static const KeyEventTestData kTestNoInput[] = {
304    // a
305    { ui::VKEY_A, false, false, false, false,
306      false, false, false, false, 3,
307      { "D 65 0 false false false false",
308        "P 97 97 false false false false",
309        "U 65 0 false false false false" } },
310    // shift-a
311    { ui::VKEY_A, false, true, false, false,
312      false, false, false, false, 5,
313      { "D 16 0 false true false false",
314        "D 65 0 false true false false",
315        "P 65 65 false true false false",
316        "U 65 0 false true false false",
317        "U 16 0 false true false false" } },
318    // a, suppress keydown
319    { ui::VKEY_A, false, false, false, false,
320      true, false, false, false, 2,
321      { "D 65 0 false false false false",
322        "U 65 0 false false false false" } },
323  };
324
325  static const KeyEventTestData kTestWithInput[] = {
326    // a
327    { ui::VKEY_A, false, false, false, false,
328      false, false, false, false, 4,
329      { "D 65 0 false false false false",
330        "P 97 97 false false false false",
331        "T a",
332        "U 65 0 false false false false" } },
333    // shift-a
334    { ui::VKEY_A, false, true, false, false,
335      false, false, false, false, 6,
336      { "D 16 0 false true false false",
337        "D 65 0 false true false false",
338        "P 65 65 false true false false",
339        "T A",
340        "U 65 0 false true false false",
341        "U 16 0 false true false false" } },
342    // a, suppress keydown
343    { ui::VKEY_A, false, false, false, false,
344      true, false, false, false, 2,
345      { "D 65 0 false false false false",
346        "U 65 0 false false false false" } },
347    // a, suppress keypress
348    { ui::VKEY_A, false, false, false, false,
349      false, true, false, false, 3,
350      { "D 65 0 false false false false",
351        "P 97 97 false false false false",
352        "U 65 0 false false false false" } },
353    // a, suppress textInput
354    { ui::VKEY_A, false, false, false, false,
355      false, false, false, true, 4,
356      { "D 65 0 false false false false",
357        "P 97 97 false false false false",
358        "T a",
359        "U 65 0 false false false false" } },
360  };
361
362  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
363
364  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
365  GURL url = embedded_test_server()->GetURL(kTestingPage);
366  ui_test_utils::NavigateToURL(browser(), url);
367
368  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
369  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
370
371  int tab_index = browser()->tab_strip_model()->active_index();
372  for (size_t i = 0; i < arraysize(kTestNoInput); ++i) {
373    EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestNoInput[i]))
374        << "kTestNoInput[" << i << "] failed:\n"
375        << GetTestDataDescription(kTestNoInput[i]);
376  }
377
378  // Input in normal text box.
379  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
380  for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
381    EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
382        << "kTestWithInput[" << i << "] in text box failed:\n"
383        << GetTestDataDescription(kTestWithInput[i]);
384  }
385  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"aA"));
386
387  // Input in password box.
388  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"B"));
389  for (size_t i = 0; i < arraysize(kTestWithInput); ++i) {
390    EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestWithInput[i]))
391        << "kTestWithInput[" << i << "] in password box failed:\n"
392        << GetTestDataDescription(kTestWithInput[i]);
393  }
394  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"B", L"aA"));
395}
396
397#if defined(OS_WIN) || defined(OS_LINUX)
398
399#if defined(OS_LINUX) || (defined(OS_WIN) && defined(USE_AURA))
400// Linux: http://crbug.com/129235
401// Win Aura: crbug.com/269564
402#define MAYBE_CtrlKeyEvents DISABLED_CtrlKeyEvents
403#else
404#define MAYBE_CtrlKeyEvents CtrlKeyEvents
405#endif
406
407IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_CtrlKeyEvents) {
408  static const KeyEventTestData kTestCtrlF = {
409    ui::VKEY_F, true, false, false, false,
410    false, false, false, false, 2,
411    { "D 17 0 true false false false",
412      "D 70 0 true false false false" }
413  };
414
415  static const KeyEventTestData kTestCtrlFSuppressKeyDown = {
416    ui::VKEY_F, true, false, false, false,
417    true, false, false, false, 4,
418    { "D 17 0 true false false false",
419      "D 70 0 true false false false",
420      "U 70 0 true false false false",
421      "U 17 0 true false false false" }
422  };
423
424  // Ctrl+Z doesn't bind to any accelerators, which then should generate a
425  // keypress event with charCode=26.
426  static const KeyEventTestData kTestCtrlZ = {
427    ui::VKEY_Z, true, false, false, false,
428    false, false, false, false, 5,
429    { "D 17 0 true false false false",
430      "D 90 0 true false false false",
431      "P 26 26 true false false false",
432      "U 90 0 true false false false",
433      "U 17 0 true false false false" }
434  };
435
436  static const KeyEventTestData kTestCtrlZSuppressKeyDown = {
437    ui::VKEY_Z, true, false, false, false,
438    true, false, false, false, 4,
439    { "D 17 0 true false false false",
440      "D 90 0 true false false false",
441      "U 90 0 true false false false",
442      "U 17 0 true false false false" }
443  };
444
445  // Ctrl+Enter shall generate a keypress event with charCode=10 (LF).
446  static const KeyEventTestData kTestCtrlEnter = {
447    ui::VKEY_RETURN, true, false, false, false,
448    false, false, false, false, 5,
449    { "D 17 0 true false false false",
450      "D 13 0 true false false false",
451      "P 10 10 true false false false",
452      "U 13 0 true false false false",
453      "U 17 0 true false false false" }
454  };
455
456  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
457
458  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
459  GURL url = embedded_test_server()->GetURL(kTestingPage);
460  ui_test_utils::NavigateToURL(browser(), url);
461
462  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
463  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
464
465  int tab_index = browser()->tab_strip_model()->active_index();
466  // Press Ctrl+F, which will make the Find box open and request focus.
467  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
468  EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
469
470  // Press Escape to close the Find box and move the focus back to the web page.
471  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
472      browser(), ui::VKEY_ESCAPE, false, false, false, false));
473  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
474
475  // Press Ctrl+F with keydown suppressed shall not open the find box.
476  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlFSuppressKeyDown));
477  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
478
479  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZ));
480  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlZSuppressKeyDown));
481  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlEnter));
482}
483#elif defined(OS_MACOSX)
484// http://crbug.com/81451
485IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_CommandKeyEvents) {
486  static const KeyEventTestData kTestCmdF = {
487    ui::VKEY_F, false, false, false, true,
488    false, false, false, false, 2,
489    { "D 91 0 false false false true",
490      "D 70 0 false false false true" }
491  };
492
493  // On Mac we don't send key up events when command modifier is down.
494  static const KeyEventTestData kTestCmdFSuppressKeyDown = {
495    ui::VKEY_F, false, false, false, true,
496    true, false, false, false, 3,
497    { "D 91 0 false false false true",
498      "D 70 0 false false false true",
499      "U 91 0 false false false true" }
500  };
501
502  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
503
504  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
505  GURL url = embedded_test_server()->GetURL(kTestingPage);
506  ui_test_utils::NavigateToURL(browser(), url);
507
508  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
509  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
510
511  int tab_index = browser()->tab_strip_model()->active_index();
512  // Press Cmd+F, which will make the Find box open and request focus.
513  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdF));
514  EXPECT_TRUE(IsViewFocused(VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
515
516  // Press Escape to close the Find box and move the focus back to the web page.
517  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
518      browser(), ui::VKEY_ESCAPE, false, false, false, false));
519  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
520
521  // Press Cmd+F with keydown suppressed shall not open the find box.
522  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCmdFSuppressKeyDown));
523  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
524}
525#endif
526
527// Flaky: http://crbug.com/81451 , http://crbug.com/129235 ,
528// also fails on Windows.
529IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_AccessKeys) {
530#if defined(OS_MACOSX)
531  // On Mac, access keys use ctrl+alt modifiers.
532  static const KeyEventTestData kTestAccessA = {
533    ui::VKEY_A, true, false, true, false,
534    false, false, false, false, 6,
535    { "D 17 0 true false false false",
536      "D 18 0 true false true false",
537      "D 65 0 true false true false",
538      "U 65 0 true false true false",
539      "U 18 0 true false true false",
540      "U 17 0 true false false false" }
541  };
542
543  static const KeyEventTestData kTestAccessDSuppress = {
544    ui::VKEY_D, true, false, true, false,
545    true, true, true, false, 6,
546    { "D 17 0 true false false false",
547      "D 18 0 true false true false",
548      "D 68 0 true false true false",
549      "U 68 0 true false true false",
550      "U 18 0 true false true false",
551      "U 17 0 true false false false" }
552  };
553
554  static const KeyEventTestData kTestAccess1 = {
555    ui::VKEY_1, true, false, true, false,
556    false, false, false, false, 6,
557    { "D 17 0 true false false false",
558      "D 18 0 true false true false",
559      "D 49 0 true false true false",
560      "U 49 0 true false true false",
561      "U 18 0 true false true false",
562      "U 17 0 true false false false" }
563  };
564#else
565  static const KeyEventTestData kTestAccessA = {
566    ui::VKEY_A, false, false, true, false,
567    false, false, false, false, 4,
568    { "D 18 0 false false true false",
569      "D 65 0 false false true false",
570      "U 65 0 false false true false",
571      "U 18 0 false false true false" }
572  };
573
574  static const KeyEventTestData kTestAccessD = {
575    ui::VKEY_D, false, false, true, false,
576    false, false, false, false, 2,
577    { "D 18 0 false false true false",
578      "D 68 0 false false true false" }
579  };
580
581  static const KeyEventTestData kTestAccessDSuppress = {
582    ui::VKEY_D, false, false, true, false,
583    true, true, true, false, 4,
584    { "D 18 0 false false true false",
585      "D 68 0 false false true false",
586      "U 68 0 false false true false",
587      "U 18 0 false false true false" }
588  };
589
590#if !defined(USE_ASH)
591  static const KeyEventTestData kTestAccess1 = {
592    ui::VKEY_1, false, false, true, false,
593    false, false, false, false, 4,
594    { "D 18 0 false false true false",
595      "D 49 0 false false true false",
596      "U 49 0 false false true false",
597      "U 18 0 false false true false" }
598  };
599#endif
600#endif
601
602  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
603
604  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
605  GURL url = embedded_test_server()->GetURL(kTestingPage);
606  ui_test_utils::NavigateToURL(browser(), url);
607
608  content::RunAllPendingInMessageLoop();
609  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
610  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
611
612  int tab_index = browser()->tab_strip_model()->active_index();
613  // Make sure no element is focused.
614  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
615  // Alt+A should focus the element with accesskey = "A".
616  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessA));
617  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"A"));
618
619  // Blur the focused element.
620  EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
621  // Make sure no element is focused.
622  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
623
624#if !defined(OS_MACOSX)
625  // Alt+D should move the focus to the location entry.
626  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessD));
627
628  // TODO(isherman): This is an experimental change to help diagnose
629  // http://crbug.com/55713
630  content::RunAllPendingInMessageLoop();
631  EXPECT_TRUE(IsViewFocused(VIEW_ID_OMNIBOX));
632  // No element should be focused, as Alt+D was handled by the browser.
633  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
634
635  // Move the focus back to the web page.
636  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
637  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
638
639  // Make sure no element is focused.
640  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
641#endif
642
643  // If the keydown event is suppressed, then Alt+D should be handled as an
644  // accesskey rather than an accelerator key. Activation of an accesskey is not
645  // a part of the default action of the key event, so it should not be
646  // suppressed at all.
647  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccessDSuppress));
648  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
649  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"D"));
650
651  // Blur the focused element.
652  EXPECT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L""));
653  // Make sure no element is focused.
654  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
655#if !defined(USE_ASH)
656  // On Ash, alt-1..9 are assigned as window selection global accelerators, so
657  // they can not be used as accesskeys.
658  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAccess1));
659#if defined(TOOLKIT_GTK)
660  // On GTK, alt-0..9 are assigned as tab selection accelerators, so they can
661  // not be used as accesskeys.
662  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L""));
663#else
664  EXPECT_NO_FATAL_FAILURE(CheckFocusedElement(tab_index, L"1"));
665#endif
666#endif
667}
668
669// Flaky, http://crbug.com/69475.
670#if defined(OS_LINUX) || (defined(OS_WIN) && defined(USE_AURA))
671#define MAYBE_ReservedAccelerators DISABLED_ReservedAccelerators
672#else
673#define MAYBE_ReservedAccelerators ReservedAccelerators
674#endif
675IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_ReservedAccelerators) {
676  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
677
678  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
679  GURL url = embedded_test_server()->GetURL(kTestingPage);
680  ui_test_utils::NavigateToURL(browser(), url);
681
682  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
683  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
684
685  ASSERT_EQ(1, browser()->tab_strip_model()->count());
686
687  static const KeyEventTestData kTestCtrlOrCmdT = {
688#if defined(OS_MACOSX)
689    ui::VKEY_T, false, false, false, true,
690    true, false, false, false, 1,
691    { "D 91 0 false false false true" }
692#else
693    ui::VKEY_T, true, false, false, false,
694    true, false, false, false, 1,
695    { "D 17 0 true false false false" }
696#endif
697  };
698
699  content::WindowedNotificationObserver wait_for_new_tab(
700      chrome::NOTIFICATION_TAB_PARENTED,
701      content::NotificationService::AllSources());
702
703  // Press Ctrl/Cmd+T, which will open a new tab. It cannot be suppressed.
704  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(0, kTestCtrlOrCmdT));
705  wait_for_new_tab.Wait();
706
707  int result_length;
708  ASSERT_NO_FATAL_FAILURE(GetResultLength(0, &result_length));
709  EXPECT_EQ(1, result_length);
710
711  EXPECT_EQ(2, browser()->tab_strip_model()->count());
712  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
713
714  // Because of issue <http://crbug.com/65375>, switching back to the first tab
715  // may cause the focus to be grabbed by omnibox. So instead, we load our
716  // testing page in the newly created tab and try Cmd-W here.
717  ui_test_utils::NavigateToURL(browser(), url);
718
719  // Make sure the focus is in the testing page.
720  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
721  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
722
723  // Reserved accelerators can't be suppressed.
724  ASSERT_NO_FATAL_FAILURE(SuppressAllEvents(1, true));
725
726  content::WebContentsDestroyedWatcher destroyed_watcher(
727      browser()->tab_strip_model()->GetWebContentsAt(1));
728
729  // Press Ctrl/Cmd+W, which will close the tab.
730#if defined(OS_MACOSX)
731  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
732      browser(), ui::VKEY_W, false, false, false, true));
733#else
734  ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
735      browser(), ui::VKEY_W, true, false, false, false));
736#endif
737
738  ASSERT_NO_FATAL_FAILURE(destroyed_watcher.Wait());
739
740  EXPECT_EQ(1, browser()->tab_strip_model()->count());
741}
742
743#if defined(OS_MACOSX)
744IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, EditorKeyBindings) {
745  // TODO(kbr): re-enable: http://crbug.com/222296
746  if (base::mac::IsOSMountainLionOrLater())
747    return;
748
749  static const KeyEventTestData kTestCtrlA = {
750    ui::VKEY_A, true, false, false, false,
751    false, false, false, false, 4,
752    { "D 17 0 true false false false",
753      "D 65 0 true false false false",
754      "U 65 0 true false false false",
755      "U 17 0 true false false false" }
756  };
757
758  static const KeyEventTestData kTestCtrlF = {
759    ui::VKEY_F, true, false, false, false,
760    false, false, false, false, 4,
761    { "D 17 0 true false false false",
762      "D 70 0 true false false false",
763      "U 70 0 true false false false",
764      "U 17 0 true false false false" }
765  };
766
767  static const KeyEventTestData kTestCtrlK = {
768    ui::VKEY_K, true, false, false, false,
769    false, false, false, false, 4,
770    { "D 17 0 true false false false",
771      "D 75 0 true false false false",
772      "U 75 0 true false false false",
773      "U 17 0 true false false false" }
774  };
775
776  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
777
778  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
779  GURL url = embedded_test_server()->GetURL(kTestingPage);
780  ui_test_utils::NavigateToURL(browser(), url);
781
782  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
783  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
784
785  int tab_index = browser()->tab_strip_model()->active_index();
786  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
787  ASSERT_NO_FATAL_FAILURE(SetTextBoxValue(tab_index, L"A", L"Hello"));
788  // Move the caret to the beginning of the line.
789  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlA));
790  // Forward one character
791  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlF));
792  // Delete to the end of the line.
793  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlK));
794  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L"H"));
795}
796#endif
797
798// See http://crbug.com/147579
799IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, DISABLED_PageUpDownKeys) {
800  static const KeyEventTestData kTestPageUp = {
801    ui::VKEY_PRIOR, false, false, false, false,
802    false, false, false, false, 2,
803    { "D 33 0 false false false false",
804      "U 33 0 false false false false" }
805  };
806
807  static const KeyEventTestData kTestPageDown = {
808    ui::VKEY_NEXT, false, false, false, false,
809    false, false, false, false, 2,
810    { "D 34 0 false false false false",
811      "U 34 0 false false false false" }
812  };
813
814  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
815
816  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
817  GURL url = embedded_test_server()->GetURL(kTestingPage);
818  ui_test_utils::NavigateToURL(browser(), url);
819
820  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
821  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
822
823  int tab_index = browser()->tab_strip_model()->active_index();
824  ASSERT_NO_FATAL_FAILURE(SetFocusedElement(tab_index, L"A"));
825  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageUp));
826  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestPageDown));
827  EXPECT_NO_FATAL_FAILURE(CheckTextBoxValue(tab_index, L"A", L""));
828}
829
830#if defined(OS_WIN)
831// AltKey is enabled only on Windows. See crbug.com/114537.
832IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, FocusMenuBarByAltKey) {
833  static const KeyEventTestData kTestAltKey = {
834    ui::VKEY_MENU, false, false, false, false,
835    false, false, false, false, 2,
836    { "D 18 0 false false true false",
837      "U 18 0 false false true false" }
838  };
839
840  static const KeyEventTestData kTestAltKeySuppress = {
841    ui::VKEY_MENU, false, false, false, false,
842    true, false, false, false, 2,
843    { "D 18 0 false false true false",
844      "U 18 0 false false true false" }
845  };
846
847  static const KeyEventTestData kTestCtrlAltKey = {
848    ui::VKEY_MENU, true, false, false, false,
849    false, false, false, false, 4,
850    { "D 17 0 true false false false",
851      "D 18 0 true false true false",
852      "U 18 0 true false true false",
853      "U 17 0 true false false false" }
854  };
855
856  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
857
858  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
859  GURL url = embedded_test_server()->GetURL(kTestingPage);
860  ui_test_utils::NavigateToURL(browser(), url);
861
862  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
863  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
864
865  int tab_index = browser()->tab_strip_model()->active_index();
866  // Press and release Alt key to focus wrench menu button.
867  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKey));
868  EXPECT_TRUE(IsViewFocused(VIEW_ID_APP_MENU));
869
870  ASSERT_NO_FATAL_FAILURE(ClickOnView(VIEW_ID_TAB_CONTAINER));
871  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
872
873  // Alt key can be suppressed.
874  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestAltKeySuppress));
875  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
876
877  // Ctrl+Alt should have no effect.
878  EXPECT_NO_FATAL_FAILURE(TestKeyEvent(tab_index, kTestCtrlAltKey));
879  ASSERT_TRUE(IsViewFocused(VIEW_ID_TAB_CONTAINER));
880}
881#endif
882
883}  // namespace
884