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