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