| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/strings/string16.h" |
| #include "base/strings/string_util.h" |
| #include "content/public/browser/native_web_keyboard_event.h" |
| #include "content/public/test/render_view_test.h" |
| #include "content/renderer/render_view_impl.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "webkit/common/webpreferences.h" |
| |
| #include <Cocoa/Cocoa.h> |
| #include <Carbon/Carbon.h> // for the kVK_* constants. |
| |
| namespace content { |
| |
| NSEvent* CmdDeadKeyEvent(NSEventType type, unsigned short code) { |
| UniChar uniChar = 0; |
| switch(code) { |
| case kVK_UpArrow: |
| uniChar = NSUpArrowFunctionKey; |
| break; |
| case kVK_DownArrow: |
| uniChar = NSDownArrowFunctionKey; |
| break; |
| default: |
| CHECK(false); |
| } |
| NSString* s = [NSString stringWithFormat:@"%C", uniChar]; |
| |
| return [NSEvent keyEventWithType:type |
| location:NSZeroPoint |
| modifierFlags:NSCommandKeyMask |
| timestamp:0.0 |
| windowNumber:0 |
| context:nil |
| characters:s |
| charactersIgnoringModifiers:s |
| isARepeat:NO |
| keyCode:code]; |
| } |
| |
| // Test that cmd-up/down scrolls the page exactly if it is not intercepted by |
| // javascript. |
| TEST_F(RenderViewTest, MacTestCmdUp) { |
| // Some preprocessor trickery so that we can have literal html in our source, |
| // makes it easier to copy html to and from an html file for testing (the |
| // preprocessor will remove the newlines at the line ends, turning this into |
| // a single long line). |
| #define HTML(s) #s |
| const char* kRawHtml = HTML( |
| <html> |
| <head><title></title> |
| <script type='text/javascript' language='javascript'> |
| function OnKeyEvent(ev) { |
| var result = document.getElementById(ev.type); |
| result.innerText = (ev.which || ev.keyCode) + ',' + |
| ev.shiftKey + ',' + |
| ev.ctrlKey + ',' + |
| ev.metaKey + ',' + |
| ev.altKey; |
| return %s; /* Replace with "return true;" when testing in an html file. */ |
| } |
| function OnScroll(ev) { |
| var result = document.getElementById("scroll"); |
| result.innerText = window.pageYOffset; |
| return true; |
| } |
| </script> |
| <style type="text/css"> |
| p { border-bottom:5000px solid black; } /* enforce vertical scroll bar */ |
| </style> |
| </head> |
| <body |
| onscroll='return OnScroll(event);' |
| onkeydown='return OnKeyEvent(event);'> |
| <div id='keydown' contenteditable='true'> </div> |
| <div id='scroll' contenteditable='true'> </div> |
| <p>p1 |
| <p>p2 |
| </body> |
| </html> |
| ); |
| #undef HTML |
| |
| WebPreferences prefs; |
| prefs.enable_scroll_animator = false; |
| |
| RenderViewImpl* view = static_cast<RenderViewImpl*>(view_); |
| view->OnUpdateWebPreferences(prefs); |
| |
| const int kMaxOutputCharacters = 1024; |
| string16 output; |
| char htmlBuffer[2048]; |
| |
| NSEvent* arrowDownKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_DownArrow); |
| NSEvent* arrowUpKeyDown = CmdDeadKeyEvent(NSKeyDown, kVK_UpArrow); |
| |
| // First test when javascript does not eat keypresses -- should scroll. |
| sprintf(htmlBuffer, kRawHtml, "true"); |
| view->set_send_content_state_immediately(true); |
| LoadHTML(htmlBuffer); |
| render_thread_->sink().ClearMessages(); |
| |
| const char* kArrowDownScrollDown = |
| "40,false,false,true,false\n10128\np1\n\np2"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToEndOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); |
| ProcessPendingMessages(); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowDownScrollDown, UTF16ToASCII(output)); |
| |
| const char* kArrowUpScrollUp = |
| "38,false,false,true,false\n0\np1\n\np2"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); |
| ProcessPendingMessages(); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowUpScrollUp, UTF16ToASCII(output)); |
| |
| |
| // Now let javascript eat the key events -- no scrolling should happen |
| sprintf(htmlBuffer, kRawHtml, "false"); |
| view->set_send_content_state_immediately(true); |
| LoadHTML(htmlBuffer); |
| render_thread_->sink().ClearMessages(); |
| |
| const char* kArrowDownNoScroll = |
| "40,false,false,true,false\np1\n\np2"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToEndOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowDownKeyDown)); |
| ProcessPendingMessages(); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowDownNoScroll, UTF16ToASCII(output)); |
| |
| const char* kArrowUpNoScroll = |
| "38,false,false,true,false\np1\n\np2"; |
| view->OnSetEditCommandsForNextKeyEvent( |
| EditCommands(1, EditCommand("moveToBeginningOfDocument", ""))); |
| SendNativeKeyEvent(NativeWebKeyboardEvent(arrowUpKeyDown)); |
| ProcessPendingMessages(); |
| output = GetMainFrame()->contentAsText(kMaxOutputCharacters); |
| EXPECT_EQ(kArrowUpNoScroll, UTF16ToASCII(output)); |
| } |
| |
| } // namespace content |