summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome.gyp2
-rw-r--r--chrome/renderer/mock_keyboard.cc47
-rw-r--r--chrome/renderer/mock_keyboard.h106
-rw-r--r--chrome/renderer/mock_keyboard_driver_win.cc140
-rw-r--r--chrome/renderer/mock_keyboard_driver_win.h35
-rw-r--r--chrome/renderer/render_view.h3
-rw-r--r--chrome/renderer/render_view_unittest.cc339
-rw-r--r--chrome/test/render_view_test.cc54
-rw-r--r--chrome/test/render_view_test.h10
-rw-r--r--chrome/test/unit/unittests.vcproj16
10 files changed, 665 insertions, 87 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 81e2aee..564db3b 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -2172,6 +2172,8 @@
'browser/tab_contents/test_web_contents.h',
'common/ipc_test_sink.cc',
'common/ipc_test_sink.h',
+ 'renderer/mock_keyboard.h',
+ 'renderer/mock_keyboard.cc',
'renderer/mock_render_process.h',
'renderer/mock_render_thread.cc',
'renderer/mock_render_thread.h',
diff --git a/chrome/renderer/mock_keyboard.cc b/chrome/renderer/mock_keyboard.cc
new file mode 100644
index 0000000..b18f3f6
--- /dev/null
+++ b/chrome/renderer/mock_keyboard.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2009 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 "chrome/renderer/mock_keyboard.h"
+
+#include "base/logging.h"
+
+MockKeyboard::MockKeyboard()
+ : keyboard_layout_(LAYOUT_NULL),
+ keyboard_modifiers_(INVALID) {
+}
+
+MockKeyboard::~MockKeyboard() {
+}
+
+int MockKeyboard::GetCharacters(Layout layout,
+ int key_code,
+ Modifiers modifiers,
+ std::wstring* output) {
+#if defined(OS_WIN)
+ CHECK(output);
+ // Change the keyboard layout only when we have to because it takes a lot of
+ // time to load a keyboard-layout driver.
+ // When we change the layout, we reset the modifier status to force updating
+ // the keyboard status.
+ if (layout != keyboard_layout_) {
+ if (!driver_.SetLayout(layout))
+ return -1;
+ keyboard_layout_ = layout;
+ keyboard_modifiers_ = INVALID;
+ }
+
+ // Update the keyboard states.
+ if (modifiers != keyboard_modifiers_) {
+ if (!driver_.SetModifiers(modifiers))
+ return -1;
+ keyboard_modifiers_ = modifiers;
+ }
+
+ // Retrieve Unicode characters associate with the key code.
+ return driver_.GetCharacters(key_code, output);
+#else
+ NOTIMPLEMENTED();
+ return -1;
+#endif
+}
diff --git a/chrome/renderer/mock_keyboard.h b/chrome/renderer/mock_keyboard.h
new file mode 100644
index 0000000..4ff8d1a
--- /dev/null
+++ b/chrome/renderer/mock_keyboard.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_RENDERER_MOCK_KEYBOARD_H_
+#define CHROME_RENDERER_MOCK_KEYBOARD_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include "chrome/renderer/mock_keyboard_driver_win.h"
+#endif
+
+// A mock keyboard interface.
+// This class defines a pseudo keyboard device, which implements mappings from
+// a tuple (layout, key code, modifiers) to Unicode characters so that
+// engineers can write RenderViewTest cases without taking care of such
+// mappings. (This mapping is not trivial when using non-US keyboards.)
+// A pseudo keyboard device consists of two parts: a platform-independent part
+// and a platform-dependent part. This class implements the platform-independent
+// part. The platform-dependet part is implemented in the MockKeyboardWin class.
+// This class is usually called from RenderViewTest::SendKeyEvent().
+class MockKeyboard {
+ public:
+ // Represents keyboard-layouts.
+ enum Layout {
+ LAYOUT_NULL,
+ LAYOUT_ARABIC,
+ LAYOUT_BULGARIAN,
+ LAYOUT_CHINESE_TRADITIONAL,
+ LAYOUT_CZECH,
+ LAYOUT_DANISH,
+ LAYOUT_GERMAN,
+ LAYOUT_GREEK,
+ LAYOUT_UNITED_STATES,
+ LAYOUT_SPANISH,
+ LAYOUT_FINNISH,
+ LAYOUT_FRENCH,
+ LAYOUT_HEBREW,
+ LAYOUT_HUNGARIAN,
+ LAYOUT_ICELANDIC,
+ LAYOUT_ITALIAN,
+ LAYOUT_JAPANESE,
+ LAYOUT_KOREAN,
+ LAYOUT_POLISH,
+ LAYOUT_PORTUGUESE_BRAZILIAN,
+ LAYOUT_ROMANIAN,
+ LAYOUT_RUSSIAN,
+ LAYOUT_CROATIAN,
+ LAYOUT_SLOVAK,
+ LAYOUT_THAI,
+ LAYOUT_SWEDISH,
+ LAYOUT_TURKISH_Q,
+ LAYOUT_VIETNAMESE,
+ LAYOUT_DEVANAGARI_INSCRIPT,
+ LAYOUT_PORTUGUESE,
+ LAYOUT_UNITED_STATES_DVORAK,
+ LAYOUT_CANADIAN_FRENCH,
+ };
+
+ // Enumerates keyboard modifiers.
+ // These modifiers explicitly distinguish left-keys and right-keys because we
+ // should emulate AltGr (right-alt) key, used by many European keyboards to
+ // input alternate graph characters.
+ enum Modifiers {
+ INVALID = -1,
+ NONE = 0,
+ LEFT_SHIFT = 1 << 0,
+ LEFT_CONTROL = 1 << 1,
+ LEFT_ALT = 1 << 2,
+ LEFT_META = 1 << 3,
+ RIGHT_SHIFT = 1 << 4,
+ RIGHT_CONTROL = 1 << 5,
+ RIGHT_ALT = 1 << 6,
+ RIGHT_META = 1 << 7,
+ KEYPAD = 1 << 8,
+ AUTOREPEAAT = 1 << 9,
+ };
+
+ MockKeyboard();
+ ~MockKeyboard();
+
+ // Retrieves Unicode characters composed from the the specified keyboard
+ // layout, key code, and modifiers, i.e. characters returned when we type
+ // specified keys on a specified layout.
+ // This function returns the length of Unicode characters filled in the
+ // |output| parameter.
+ int GetCharacters(Layout layout,
+ int key_code,
+ Modifiers modifiers,
+ std::wstring* output);
+
+ private:
+ Layout keyboard_layout_;
+ Modifiers keyboard_modifiers_;
+
+#if defined(OS_WIN)
+ MockKeyboardDriverWin driver_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(MockKeyboard);
+};
+
+#endif // CHROME_RENDERER_MOCK_KEYBOARD_H_
diff --git a/chrome/renderer/mock_keyboard_driver_win.cc b/chrome/renderer/mock_keyboard_driver_win.cc
new file mode 100644
index 0000000..07792e9
--- /dev/null
+++ b/chrome/renderer/mock_keyboard_driver_win.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2009 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 "chrome/renderer/mock_keyboard_driver_win.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "chrome/renderer/mock_keyboard.h"
+
+MockKeyboardDriverWin::MockKeyboardDriverWin() {
+ // Save the keyboard layout and status of the application.
+ // This class changes the keyboard layout and status of this application.
+ // This change may break succeeding tests. To prevent this possible break, we
+ // should save the layout and status here to restore when this instance is
+ // destroyed.
+ original_keyboard_layout_ = GetKeyboardLayout(0);
+ GetKeyboardState(&original_keyboard_states_[0]);
+
+ keyboard_handle_ = NULL;
+ memset(&keyboard_states_[0], 0, sizeof(keyboard_states_));
+}
+
+MockKeyboardDriverWin::~MockKeyboardDriverWin() {
+ // Unload the keyboard-layout driver, restore the keyboard state, and reset
+ // the keyboard layout for succeeding tests.
+ if (keyboard_handle_)
+ UnloadKeyboardLayout(keyboard_handle_);
+ SetKeyboardState(&original_keyboard_states_[0]);
+ ActivateKeyboardLayout(original_keyboard_layout_, KLF_RESET);
+}
+
+bool MockKeyboardDriverWin::SetLayout(int layout) {
+ // Unload the current keyboard-layout driver and load a new keyboard-layout
+ // driver for mapping a virtual key-code to a Unicode character.
+ if (keyboard_handle_) {
+ UnloadKeyboardLayout(keyboard_handle_);
+ keyboard_handle_ = NULL;
+ }
+
+ // Scan the mapping table and retrieve a Language ID for the input layout.
+ // Load the keyboard-layout driver when we find a Language ID.
+ // This Language IDs are copied from the registry
+ // "HKLM\SYSTEM\CurrentControlSet\Control\Keyboard layouts".
+ // TODO(hbono): Add more keyboard-layout drivers.
+ static const struct {
+ const wchar_t* language;
+ MockKeyboard::Layout keyboard_layout;
+ } kLanguageIDs[] = {
+ {L"00000401", MockKeyboard::LAYOUT_ARABIC},
+ {L"00000402", MockKeyboard::LAYOUT_BULGARIAN},
+ {L"00000404", MockKeyboard::LAYOUT_CHINESE_TRADITIONAL},
+ {L"00000405", MockKeyboard::LAYOUT_CZECH},
+ {L"00000406", MockKeyboard::LAYOUT_DANISH},
+ {L"00000407", MockKeyboard::LAYOUT_GERMAN},
+ {L"00000408", MockKeyboard::LAYOUT_GREEK},
+ {L"00000409", MockKeyboard::LAYOUT_UNITED_STATES},
+ {L"0000040a", MockKeyboard::LAYOUT_SPANISH},
+ {L"0000040b", MockKeyboard::LAYOUT_FINNISH},
+ {L"0000040c", MockKeyboard::LAYOUT_FRENCH},
+ {L"0000040d", MockKeyboard::LAYOUT_HEBREW},
+ {L"0000040e", MockKeyboard::LAYOUT_HUNGARIAN},
+ {L"00000410", MockKeyboard::LAYOUT_ITALIAN},
+ {L"00000411", MockKeyboard::LAYOUT_JAPANESE},
+ {L"00000412", MockKeyboard::LAYOUT_KOREAN},
+ {L"00000415", MockKeyboard::LAYOUT_POLISH},
+ {L"00000416", MockKeyboard::LAYOUT_PORTUGUESE_BRAZILIAN},
+ {L"00000418", MockKeyboard::LAYOUT_ROMANIAN},
+ {L"00000419", MockKeyboard::LAYOUT_RUSSIAN},
+ {L"0000041a", MockKeyboard::LAYOUT_CROATIAN},
+ {L"0000041b", MockKeyboard::LAYOUT_SLOVAK},
+ {L"0000041e", MockKeyboard::LAYOUT_THAI},
+ {L"0000041d", MockKeyboard::LAYOUT_SWEDISH},
+ {L"0000041f", MockKeyboard::LAYOUT_TURKISH_Q},
+ {L"0000042a", MockKeyboard::LAYOUT_VIETNAMESE},
+ {L"00000439", MockKeyboard::LAYOUT_DEVANAGARI_INSCRIPT},
+ {L"00000816", MockKeyboard::LAYOUT_PORTUGUESE},
+ {L"00001409", MockKeyboard::LAYOUT_UNITED_STATES_DVORAK},
+ {L"00001009", MockKeyboard::LAYOUT_CANADIAN_FRENCH},
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLanguageIDs); ++i) {
+ if (layout == kLanguageIDs[i].keyboard_layout) {
+ keyboard_handle_ = LoadKeyboardLayout(kLanguageIDs[i].language,
+ KLF_ACTIVATE);
+ if (!keyboard_handle_)
+ return false;
+ return true;
+ }
+ }
+
+ // Return false if there are not any matching drivers.
+ return false;
+}
+
+bool MockKeyboardDriverWin::SetModifiers(int modifiers) {
+ // Over-write the keyboard status with our modifier-key status.
+ // WebInputEventFactory::keyboardEvent() uses GetKeyState() to retrive
+ // modifier-key status. So, we update the modifier-key status with this
+ // SetKeyboardState() call before creating NativeWebKeyboardEvent
+ // instances.
+ memset(&keyboard_states_[0], 0, sizeof(keyboard_states_));
+ static const struct {
+ int key_code;
+ int mask;
+ } kModifierMasks[] = {
+ {VK_SHIFT, MockKeyboard::LEFT_SHIFT | MockKeyboard::RIGHT_SHIFT},
+ {VK_CONTROL, MockKeyboard::LEFT_CONTROL | MockKeyboard::RIGHT_CONTROL},
+ {VK_MENU, MockKeyboard::LEFT_ALT | MockKeyboard::RIGHT_ALT},
+ {VK_LSHIFT, MockKeyboard::LEFT_SHIFT},
+ {VK_LCONTROL, MockKeyboard::LEFT_CONTROL},
+ {VK_LMENU, MockKeyboard::LEFT_ALT},
+ {VK_RSHIFT, MockKeyboard::RIGHT_SHIFT},
+ {VK_RCONTROL, MockKeyboard::RIGHT_CONTROL},
+ {VK_RMENU, MockKeyboard::RIGHT_ALT},
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kModifierMasks); ++i) {
+ const int kKeyDownMask = 0x80;
+ if (modifiers & kModifierMasks[i].mask)
+ keyboard_states_[kModifierMasks[i].key_code] = kKeyDownMask;
+ }
+ SetKeyboardState(&keyboard_states_[0]);
+
+ return true;
+}
+
+int MockKeyboardDriverWin::GetCharacters(int key_code,
+ std::wstring* output) {
+ // Retrieve Unicode characters composed from the input key-code and
+ // the mofifiers.
+ CHECK(output);
+ wchar_t code[16];
+ int length = ToUnicodeEx(key_code, MapVirtualKey(key_code, 0),
+ &keyboard_states_[0], &code[0],
+ ARRAYSIZE_UNSAFE(code), 0,
+ keyboard_handle_);
+ if (length > 0)
+ output->assign(code);
+ return length;
+}
diff --git a/chrome/renderer/mock_keyboard_driver_win.h b/chrome/renderer/mock_keyboard_driver_win.h
new file mode 100644
index 0000000..5ad0909
--- /dev/null
+++ b/chrome/renderer/mock_keyboard_driver_win.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 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.
+
+#ifndef CHROME_RENDERER_MOCK_KEYBOARD_DRIVER_WIN_H_
+#define CHROME_RENDERER_MOCK_KEYBOARD_DRIVER_WIN_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+
+// Implements the platform-dependent part of a pseudo keyboard device for
+// Windows.
+class MockKeyboardDriverWin {
+ public:
+ MockKeyboardDriverWin();
+ ~MockKeyboardDriverWin();
+
+ bool SetLayout(int layout);
+ bool SetModifiers(int modifiers);
+ int GetCharacters(int key_code, std::wstring* code);
+
+ private:
+ HKL original_keyboard_layout_;
+ BYTE original_keyboard_states_[256];
+
+ HKL keyboard_handle_;
+ BYTE keyboard_states_[256];
+
+ DISALLOW_COPY_AND_ASSIGN(MockKeyboardDriverWin);
+};
+
+#endif // CHROME_RENDERER_MOCK_KEYBOARD_DRIVER_WIN_H_
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index dcd2de1..3463ad8 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -383,6 +383,8 @@ class RenderView : public RenderWidget,
const gfx::Rect& resizer_rect);
private:
+ // For unit tests.
+ friend class RenderViewTest;
FRIEND_TEST(RenderViewTest, OnLoadAlternateHTMLText);
FRIEND_TEST(RenderViewTest, OnNavStateChanged);
FRIEND_TEST(RenderViewTest, OnImeStateChanged);
@@ -390,6 +392,7 @@ class RenderView : public RenderWidget,
FRIEND_TEST(RenderViewTest, OnSetTextDirection);
FRIEND_TEST(RenderViewTest, OnPrintPages);
FRIEND_TEST(RenderViewTest, OnHandleKeyboardEvent);
+ FRIEND_TEST(RenderViewTest, InsertCharacters);
explicit RenderView(RenderThreadBase* render_thread);
diff --git a/chrome/renderer/render_view_unittest.cc b/chrome/renderer/render_view_unittest.cc
index 8403746..8a2ed21 100644
--- a/chrome/renderer/render_view_unittest.cc
+++ b/chrome/renderer/render_view_unittest.cc
@@ -315,19 +315,14 @@ TEST_F(RenderViewTest, OnPrintPages) {
// through the RenderWidget::OnHandleInputEvent() function.
TEST_F(RenderViewTest, OnHandleKeyboardEvent) {
#if defined(OS_WIN)
- // Save the keyboard layout and the status.
- // This test changes the keyboard layout and status. This may break
- // succeeding tests. To prevent this possible break, we should save the
- // layout and status here to restore when this test is finished.
- HKL original_layout = GetKeyboardLayout(0);
- BYTE original_key_states[256];
- GetKeyboardState(&original_key_states[0]);
-
// Load an HTML page consisting of one <input> element and three
// contentediable <div> elements.
// The <input> element is used for sending keyboard events, and the <div>
// elements are used for writing DOM events in the following format:
- // "<keyCode>,<shiftKey>,<controlKey>,<altKey>,<metaKey>".
+ // "<keyCode>,<shiftKey>,<controlKey>,<altKey>".
+ // TODO(hbono): <http://crbug.com/2215> Our WebKit port set |ev.metaKey| to
+ // true when pressing an alt key, i.e. the |ev.metaKey| value is not
+ // trustworthy. We will check the |ev.metaKey| value when this issue is fixed.
view_->set_delay_seconds_for_form_state_sync(0);
LoadHTML("<html>"
"<head>"
@@ -339,8 +334,7 @@ TEST_F(RenderViewTest, OnHandleKeyboardEvent) {
" (ev.which || ev.keyCode) + ',' +"
" ev.shiftKey + ',' +"
" ev.ctrlKey + ',' +"
- " ev.altKey + ',' +"
- " ev.metaKey;"
+ " ev.altKey;"
" return true;"
"}"
"</script>"
@@ -362,24 +356,33 @@ TEST_F(RenderViewTest, OnHandleKeyboardEvent) {
ExecuteJavaScript("document.getElementById('test').focus();");
render_thread_.sink().ClearMessages();
- // Language IDs used in this test.
- // This test directly loads keyboard-layout drivers and use them for
- // emulating non-US keyboard layouts.
- static const wchar_t* kLanguageIDs[] = {
- L"00000401", // Arabic
- L"00000409", // United States
- L"0000040c", // French
- L"0000040d", // Hebrew
- L"00001009", // Canadian French
+ static const MockKeyboard::Layout kLayouts[] = {
+ MockKeyboard::LAYOUT_ARABIC,
+ MockKeyboard::LAYOUT_CANADIAN_FRENCH,
+ MockKeyboard::LAYOUT_FRENCH,
+ MockKeyboard::LAYOUT_HEBREW,
+ MockKeyboard::LAYOUT_RUSSIAN,
+ MockKeyboard::LAYOUT_UNITED_STATES,
};
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLanguageIDs); ++i) {
- // Load a keyboard-layout driver.
- HKL handle = LoadKeyboardLayout(kLanguageIDs[i], KLF_ACTIVATE);
- EXPECT_TRUE(handle != NULL);
-
- // For each key code, we send two keyboard events: one when we only press
- // the key, and one when we press the key and a shift key.
- for (int modifiers = 0; modifiers < 2; ++modifiers) {
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
+ // For each key code, we send three keyboard events.
+ // * we press only the key;
+ // * we press the key and a left-shift key, and;
+ // * we press the key and a right-alt (AltGr) key.
+ // For each modifiers, we need a string used for formatting its expected
+ // result. (See the above comment for its format.)
+ static const struct {
+ MockKeyboard::Modifiers modifiers;
+ const wchar_t* expected_result;
+ } kModifierData[] = {
+ {MockKeyboard::NONE, L"false,false,false"},
+ {MockKeyboard::LEFT_SHIFT, L"true,false,false"},
+ {MockKeyboard::RIGHT_ALT, L"false,false,true"},
+ };
+
+ MockKeyboard::Layout layout = kLayouts[i];
+ for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifierData); ++j) {
// Virtual key codes used for this test.
static const int kKeyCodes[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
@@ -401,72 +404,30 @@ TEST_F(RenderViewTest, OnHandleKeyboardEvent) {
VK_OEM_8,
};
- // Over-write the keyboard status with our modifier-key status.
- // WebInputEventFactory::keyboardEvent() uses GetKeyState() to retrive
- // modifier-key status. So, we update the modifier-key status with this
- // SetKeyboardState() call before creating NativeWebKeyboardEvent
- // instances.
- BYTE key_states[256];
- memset(&key_states[0], 0, sizeof(key_states));
- key_states[VK_SHIFT] = (modifiers & 0x01) ? 0x80 : 0;
- SetKeyboardState(&key_states[0]);
-
- for (size_t j = 0; j <= ARRAYSIZE_UNSAFE(kKeyCodes); ++j) {
- // Retrieve the Unicode character composed from the virtual-key code
- // and our modifier-key status from the keyboard-layout driver.
- // This character is used for creating a WM_CHAR message and an
- // expected result.
- int key_code = kKeyCodes[j];
- wchar_t codes[4];
- int length = ToUnicodeEx(key_code, MapVirtualKey(key_code, 0),
- &key_states[0], &codes[0],
- ARRAYSIZE_UNSAFE(codes), 0, handle);
- if (length != 1)
+ MockKeyboard::Modifiers modifiers = kModifierData[j].modifiers;
+ for (size_t k = 0; k <= ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
+ // Send a keyboard event to the RenderView object.
+ // We should test a keyboard event only when the given keyboard-layout
+ // driver is installed in a PC and the driver can assign a Unicode
+ // charcter for the given tuple (key-code and modifiers).
+ int key_code = kKeyCodes[k];
+ std::wstring char_code;
+ if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
continue;
- // Create IPC messages from Windows messages and send them to our
- // back-end.
- // A keyboard event of Windows consists of three Windows messages:
- // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
- // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
- // WM_CHAR sends a composed Unicode character.
- NativeWebKeyboardEvent keydown_event(NULL, WM_KEYDOWN, key_code, 0);
- scoped_ptr<IPC::Message> keydown_message(
- new ViewMsg_HandleInputEvent(0));
- keydown_message->WriteData(
- reinterpret_cast<const char*>(&keydown_event),
- sizeof(WebKit::WebKeyboardEvent));
- view_->OnHandleInputEvent(*keydown_message);
-
- NativeWebKeyboardEvent char_event(NULL, WM_CHAR, codes[0], 0);
- scoped_ptr<IPC::Message> char_message(new ViewMsg_HandleInputEvent(0));
- char_message->WriteData(reinterpret_cast<const char*>(&char_event),
- sizeof(WebKit::WebKeyboardEvent));
- view_->OnHandleInputEvent(*char_message);
-
- NativeWebKeyboardEvent keyup_event(NULL, WM_KEYUP, key_code, 0);
- scoped_ptr<IPC::Message> keyup_message(new ViewMsg_HandleInputEvent(0));
- keyup_message->WriteData(reinterpret_cast<const char*>(&keyup_event),
- sizeof(WebKit::WebKeyboardEvent));
- view_->OnHandleInputEvent(*keyup_message);
-
// Create an expected result from the virtual-key code, the character
// code, and the modifier-key status.
// We format a string that emulates a DOM-event string produced hy
// our JavaScript function. (See the above comment for the format.)
- static const wchar_t* kModifiers[] = {
- L"false,false,false,false",
- L"true,false,false,false",
- };
static wchar_t expected_result[1024];
wsprintf(&expected_result[0],
L"\x000A" // texts in the <input> element
L"%d,%s\x000A" // texts in the first <div> element
L"%d,%s\x000A" // texts in the second <div> element
L"%d,%s", // texts in the third <div> element
- key_code, kModifiers[modifiers],
- codes[0], kModifiers[modifiers],
- key_code, kModifiers[modifiers]);
+ key_code, kModifierData[j].expected_result,
+ char_code[0], kModifierData[j].expected_result,
+ key_code, kModifierData[j].expected_result);
// Retrieve the text in the test page and compare it with the expected
// text created from a virtual-key code, a character code, and the
@@ -478,13 +439,217 @@ TEST_F(RenderViewTest, OnHandleKeyboardEvent) {
EXPECT_EQ(expected_result, output);
}
}
-
- UnloadKeyboardLayout(handle);
}
+#else
+ NOTIMPLEMENTED();
+#endif
+}
- // Restore the keyboard layout and status.
- SetKeyboardState(&original_key_states[0]);
- ActivateKeyboardLayout(original_layout, KLF_RESET);
+// Test that our EditorClientImpl class can insert characters when we send
+// keyboard events through the RenderWidget::OnHandleInputEvent() function.
+// This test is for preventing regressions caused only when we use non-US
+// keyboards, such as Issue 10846.
+TEST_F(RenderViewTest, InsertCharacters) {
+#if defined(OS_WIN)
+ static const struct {
+ MockKeyboard::Layout layout;
+ const wchar_t* expected_result;
+ } kLayouts[] = {
+#if 0
+ // Disabled these keyboard layouts because buildbots do not have their
+ // keyboard-layout drivers installed.
+ {MockKeyboard::LAYOUT_ARABIC,
+ L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
+ L"\x0038\x0039\x0634\x0624\x064a\x062b\x0628\x0644"
+ L"\x0627\x0647\x062a\x0646\x0645\x0629\x0649\x062e"
+ L"\x062d\x0636\x0642\x0633\x0641\x0639\x0631\x0635"
+ L"\x0621\x063a\x0626\x0643\x003d\x0648\x002d\x0632"
+ L"\x0638\x0630\x062c\x005c\x062f\x0637\x0028\x0021"
+ L"\x0040\x0023\x0024\x0025\x005e\x0026\x002a\x0029"
+ L"\x0650\x007d\x005d\x064f\x005b\x0623\x00f7\x0640"
+ L"\x060c\x002f\x2019\x0622\x00d7\x061b\x064e\x064c"
+ L"\x064d\x2018\x007b\x064b\x0652\x0625\x007e\x003a"
+ L"\x002b\x002c\x005f\x002e\x061f\x0651\x003c\x007c"
+ L"\x003e\x0022\x0030\x0031\x0032\x0033\x0034\x0035"
+ L"\x0036\x0037\x0038\x0039\x0634\x0624\x064a\x062b"
+ L"\x0628\x0644\x0627\x0647\x062a\x0646\x0645\x0629"
+ L"\x0649\x062e\x062d\x0636\x0642\x0633\x0641\x0639"
+ L"\x0631\x0635\x0621\x063a\x0626\x0643\x003d\x0648"
+ L"\x002d\x0632\x0638\x0630\x062c\x005c\x062f\x0637"
+ },
+ {MockKeyboard::LAYOUT_HEBREW,
+ L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
+ L"\x0038\x0039\x05e9\x05e0\x05d1\x05d2\x05e7\x05db"
+ L"\x05e2\x05d9\x05df\x05d7\x05dc\x05da\x05e6\x05de"
+ L"\x05dd\x05e4\x002f\x05e8\x05d3\x05d0\x05d5\x05d4"
+ L"\x0027\x05e1\x05d8\x05d6\x05e3\x003d\x05ea\x002d"
+ L"\x05e5\x002e\x003b\x005d\x005c\x005b\x002c\x0028"
+ L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
+ L"\x0029\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
+ L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
+ L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
+ L"\x0058\x0059\x005a\x003a\x002b\x003e\x005f\x003c"
+ L"\x003f\x007e\x007d\x007c\x007b\x0022\x0030\x0031"
+ L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
+ L"\x05e9\x05e0\x05d1\x05d2\x05e7\x05db\x05e2\x05d9"
+ L"\x05df\x05d7\x05dc\x05da\x05e6\x05de\x05dd\x05e4"
+ L"\x002f\x05e8\x05d3\x05d0\x05d5\x05d4\x0027\x05e1"
+ L"\x05d8\x05d6\x05e3\x003d\x05ea\x002d\x05e5\x002e"
+ L"\x003b\x005d\x005c\x005b\x002c"
+ },
+#endif
+ {MockKeyboard::LAYOUT_CANADIAN_FRENCH,
+ L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
+ L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
+ L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
+ L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
+ L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
+ L"\x002e\x00e9\x003c\x0029\x0021\x0022\x002f\x0024"
+ L"\x0025\x003f\x0026\x002a\x0028\x0041\x0042\x0043"
+ L"\x0044\x0045\x0046\x0047\x0048\x0049\x004a\x004b"
+ L"\x004c\x004d\x004e\x004f\x0050\x0051\x0052\x0053"
+ L"\x0054\x0055\x0056\x0057\x0058\x0059\x005a\x003a"
+ L"\x002b\x0027\x005f\x002e\x00c9\x003e\x0030\x0031"
+ L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
+ L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
+ L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
+ L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
+ L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x00e9"
+ L"\x003c"
+ },
+ {MockKeyboard::LAYOUT_FRENCH,
+ L"\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d\x00e8"
+ L"\x005f\x00e7\x0061\x0062\x0063\x0064\x0065\x0066"
+ L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
+ L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
+ L"\x0077\x0078\x0079\x007a\x0024\x003d\x002c\x003b"
+ L"\x003a\x00f9\x0029\x002a\x0021\x0030\x0031\x0032"
+ L"\x0033\x0034\x0035\x0036\x0037\x0038\x0039\x0041"
+ L"\x0042\x0043\x0044\x0045\x0046\x0047\x0048\x0049"
+ L"\x004a\x004b\x004c\x004d\x004e\x004f\x0050\x0051"
+ L"\x0052\x0053\x0054\x0055\x0056\x0057\x0058\x0059"
+ L"\x005a\x00a3\x002b\x003f\x002e\x002f\x0025\x00b0"
+ L"\x00b5\x00e0\x0026\x00e9\x0022\x0027\x0028\x002d"
+ L"\x00e8\x005f\x00e7\x0061\x0062\x0063\x0064\x0065"
+ L"\x0066\x0067\x0068\x0069\x006a\x006b\x006c\x006d"
+ L"\x006e\x006f\x0070\x0071\x0072\x0073\x0074\x0075"
+ L"\x0076\x0077\x0078\x0079\x007a\x0024\x003d\x002c"
+ L"\x003b\x003a\x00f9\x0029\x002a\x0021"
+ },
+ {MockKeyboard::LAYOUT_RUSSIAN,
+ L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
+ L"\x0038\x0039\x0444\x0438\x0441\x0432\x0443\x0430"
+ L"\x043f\x0440\x0448\x043e\x043b\x0434\x044c\x0442"
+ L"\x0449\x0437\x0439\x043a\x044b\x0435\x0433\x043c"
+ L"\x0446\x0447\x043d\x044f\x0436\x003d\x0431\x002d"
+ L"\x044e\x002e\x0451\x0445\x005c\x044a\x044d\x0029"
+ L"\x0021\x0022\x2116\x003b\x0025\x003a\x003f\x002a"
+ L"\x0028\x0424\x0418\x0421\x0412\x0423\x0410\x041f"
+ L"\x0420\x0428\x041e\x041b\x0414\x042c\x0422\x0429"
+ L"\x0417\x0419\x041a\x042b\x0415\x0413\x041c\x0426"
+ L"\x0427\x041d\x042f\x0416\x002b\x0411\x005f\x042e"
+ L"\x002c\x0401\x0425\x002f\x042a\x042d\x0030\x0031"
+ L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
+ L"\x0444\x0438\x0441\x0432\x0443\x0430\x043f\x0440"
+ L"\x0448\x043e\x043b\x0434\x044c\x0442\x0449\x0437"
+ L"\x0439\x043a\x044b\x0435\x0433\x043c\x0446\x0447"
+ L"\x043d\x044f\x0436\x003d\x0431\x002d\x044e\x002e"
+ L"\x0451\x0445\x005c\x044a\x044d"
+ },
+ {MockKeyboard::LAYOUT_UNITED_STATES,
+ L"\x0030\x0031\x0032\x0033\x0034\x0035\x0036\x0037"
+ L"\x0038\x0039\x0061\x0062\x0063\x0064\x0065\x0066"
+ L"\x0067\x0068\x0069\x006a\x006b\x006c\x006d\x006e"
+ L"\x006f\x0070\x0071\x0072\x0073\x0074\x0075\x0076"
+ L"\x0077\x0078\x0079\x007a\x003b\x003d\x002c\x002d"
+ L"\x002e\x002f\x0060\x005b\x005c\x005d\x0027\x0029"
+ L"\x0021\x0040\x0023\x0024\x0025\x005e\x0026\x002a"
+ L"\x0028\x0041\x0042\x0043\x0044\x0045\x0046\x0047"
+ L"\x0048\x0049\x004a\x004b\x004c\x004d\x004e\x004f"
+ L"\x0050\x0051\x0052\x0053\x0054\x0055\x0056\x0057"
+ L"\x0058\x0059\x005a\x003a\x002b\x003c\x005f\x003e"
+ L"\x003f\x007e\x007b\x007c\x007d\x0022\x0030\x0031"
+ L"\x0032\x0033\x0034\x0035\x0036\x0037\x0038\x0039"
+ L"\x0061\x0062\x0063\x0064\x0065\x0066\x0067\x0068"
+ L"\x0069\x006a\x006b\x006c\x006d\x006e\x006f\x0070"
+ L"\x0071\x0072\x0073\x0074\x0075\x0076\x0077\x0078"
+ L"\x0079\x007a\x003b\x003d\x002c\x002d\x002e\x002f"
+ L"\x0060\x005b\x005c\x005d\x0027"
+ },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLayouts); ++i) {
+ // Load an HTML page consisting of one <div> element.
+ // This <div> element is used by the EditorClientImpl class to insert
+ // characters received through the RenderWidget::OnHandleInputEvent()
+ // function.
+ view_->set_delay_seconds_for_form_state_sync(0);
+ LoadHTML("<html>"
+ "<head>"
+ "<title></title>"
+ "</head>"
+ "<body>"
+ "<div id='test' contenteditable='true'>"
+ "</div>"
+ "</body>"
+ "</html>");
+ ExecuteJavaScript("document.getElementById('test').focus();");
+ render_thread_.sink().ClearMessages();
+
+ // For each key code, we send three keyboard events.
+ // * Pressing only the key;
+ // * Pressing the key and a left-shift key, and;
+ // * Pressing the key and a right-alt (AltGr) key.
+ static const MockKeyboard::Modifiers kModifiers[] = {
+ MockKeyboard::NONE,
+ MockKeyboard::LEFT_SHIFT,
+ MockKeyboard::RIGHT_ALT,
+ };
+
+ MockKeyboard::Layout layout = kLayouts[i].layout;
+ for (size_t j = 0; j < ARRAYSIZE_UNSAFE(kModifiers); ++j) {
+ // Virtual key codes used for this test.
+ static const int kKeyCodes[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+ 'W', 'X', 'Y', 'Z',
+ VK_OEM_1,
+ VK_OEM_PLUS,
+ VK_OEM_COMMA,
+ VK_OEM_MINUS,
+ VK_OEM_PERIOD,
+ VK_OEM_2,
+ VK_OEM_3,
+ VK_OEM_4,
+ VK_OEM_5,
+ VK_OEM_6,
+ VK_OEM_7,
+ VK_OEM_8,
+ };
+
+ MockKeyboard::Modifiers modifiers = kModifiers[j];
+ for (size_t k = 0; k <= ARRAYSIZE_UNSAFE(kKeyCodes); ++k) {
+ // Send a keyboard event to the RenderView object.
+ // We should test a keyboard event only when the given keyboard-layout
+ // driver is installed in a PC and the driver can assign a Unicode
+ // charcter for the given tuple (layout, key-code, and modifiers).
+ int key_code = kKeyCodes[k];
+ std::wstring char_code;
+ if (SendKeyEvent(layout, key_code, modifiers, &char_code) < 0)
+ continue;
+ }
+ }
+
+ // Retrieve the text in the test page and compare it with the expected
+ // text created from a virtual-key code, a character code, and the
+ // modifier-key status.
+ const int kMaxOutputCharacters = 4096;
+ std::wstring output;
+ GetMainFrame()->GetContentAsPlainText(kMaxOutputCharacters, &output);
+ EXPECT_EQ(kLayouts[i].expected_result, output);
+ }
#else
NOTIMPLEMENTED();
#endif
diff --git a/chrome/test/render_view_test.cc b/chrome/test/render_view_test.cc
index 9885334..4096238 100644
--- a/chrome/test/render_view_test.cc
+++ b/chrome/test/render_view_test.cc
@@ -4,12 +4,14 @@
#include "chrome/test/render_view_test.h"
+#include "chrome/common/native_web_keyboard_event.h"
#include "chrome/common/render_messages.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/renderer/js_only_v8_extensions.h"
+#include "webkit/api/public/WebInputEvent.h"
#include "webkit/api/public/WebKit.h"
#include "webkit/api/public/WebScriptSource.h"
#include "webkit/glue/weburlrequest.h"
@@ -74,6 +76,9 @@ void RenderViewTest::SetUp() {
view_ = RenderView::Create(&render_thread_, NULL, NULL, kOpenerId,
WebPreferences(),
new SharedRenderViewCounter(0), kRouteId);
+
+ // Attach a pseudo keyboard device to this object.
+ mock_keyboard_.reset(new MockKeyboard());
}
void RenderViewTest::TearDown() {
render_thread_.SendCloseMessage();
@@ -89,4 +94,53 @@ void RenderViewTest::TearDown() {
WebKit::shutdown();
msg_loop_.RunAllPending();
+
+ mock_keyboard_.reset();
+}
+
+int RenderViewTest::SendKeyEvent(MockKeyboard::Layout layout,
+ int key_code,
+ MockKeyboard::Modifiers modifiers,
+ std::wstring* output) {
+#if defined(OS_WIN)
+ // Retrieve the Unicode character for the given tuple (keyboard-layout,
+ // key-code, and modifiers).
+ // Exit when a keyboard-layout driver cannot assign a Unicode character to
+ // the tuple to prevent sending an invalid key code to the RenderView object.
+ CHECK(mock_keyboard_.get());
+ CHECK(output);
+ int length = mock_keyboard_->GetCharacters(layout, key_code, modifiers,
+ output);
+ if (length != 1)
+ return -1;
+
+ // Create IPC messages from Windows messages and send them to our
+ // back-end.
+ // A keyboard event of Windows consists of three Windows messages:
+ // WM_KEYDOWN, WM_CHAR, and WM_KEYUP.
+ // WM_KEYDOWN and WM_KEYUP sends virtual-key codes. On the other hand,
+ // WM_CHAR sends a composed Unicode character.
+ NativeWebKeyboardEvent keydown_event(NULL, WM_KEYDOWN, key_code, 0);
+ scoped_ptr<IPC::Message> keydown_message(new ViewMsg_HandleInputEvent(0));
+ keydown_message->WriteData(reinterpret_cast<const char*>(&keydown_event),
+ sizeof(WebKit::WebKeyboardEvent));
+ view_->OnHandleInputEvent(*keydown_message);
+
+ NativeWebKeyboardEvent char_event(NULL, WM_CHAR, (*output)[0], 0);
+ scoped_ptr<IPC::Message> char_message(new ViewMsg_HandleInputEvent(0));
+ char_message->WriteData(reinterpret_cast<const char*>(&char_event),
+ sizeof(WebKit::WebKeyboardEvent));
+ view_->OnHandleInputEvent(*char_message);
+
+ NativeWebKeyboardEvent keyup_event(NULL, WM_KEYUP, key_code, 0);
+ scoped_ptr<IPC::Message> keyup_message(new ViewMsg_HandleInputEvent(0));
+ keyup_message->WriteData(reinterpret_cast<const char*>(&keyup_event),
+ sizeof(WebKit::WebKeyboardEvent));
+ view_->OnHandleInputEvent(*keyup_message);
+
+ return length;
+#else
+ NOTIMPLEMENTED();
+ return L'\0';
+#endif
}
diff --git a/chrome/test/render_view_test.h b/chrome/test/render_view_test.h
index abda898..a399c7b 100644
--- a/chrome/test/render_view_test.h
+++ b/chrome/test/render_view_test.h
@@ -5,7 +5,10 @@
#ifndef CHROME_TEST_RENDER_VIEW_TEST_H_
#define CHROME_TEST_RENDER_VIEW_TEST_H_
+#include <string>
+
#include "base/scoped_ptr.h"
+#include "chrome/renderer/mock_keyboard.h"
#include "chrome/renderer/mock_render_process.h"
#include "chrome/renderer/mock_render_thread.h"
#include "chrome/renderer/render_view.h"
@@ -32,6 +35,12 @@ class RenderViewTest : public testing::Test {
// Loads the given HTML into the main frame as a data: URL.
void LoadHTML(const char* html);
+ // Sends IPC messages that emulates a key-press event.
+ int SendKeyEvent(MockKeyboard::Layout layout,
+ int key_code,
+ MockKeyboard::Modifiers key_modifiers,
+ std::wstring* output);
+
// testing::Test
virtual void SetUp();
@@ -42,6 +51,7 @@ class RenderViewTest : public testing::Test {
scoped_ptr<MockProcess> mock_process_;
scoped_refptr<RenderView> view_;
RendererWebKitClientImpl webkitclient_;
+ scoped_ptr<MockKeyboard> mock_keyboard_;
};
#endif // CHROME_TEST_RENDER_VIEW_TEST_H_
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index c0da965..08943c8 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -935,6 +935,22 @@
Name="test_infrastructure"
>
<File
+ RelativePath="..\..\renderer\mock_keyboard.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\renderer\mock_keyboard.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\renderer\mock_keyboard_driver_win.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\..\renderer\mock_keyboard_driver_win.h"
+ >
+ </File>
+ <File
RelativePath="..\..\renderer\mock_render_process.h"
>
</File>