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