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