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