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