diff options
author | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-04 21:04:04 +0000 |
---|---|---|
committer | avi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-04 21:04:04 +0000 |
commit | 3ebf9af0cd55de5d312f0df5254580ab60ac0c64 (patch) | |
tree | 9d332e0833925545f0cdce851e349a9b109626b6 | |
parent | 076bf0b69eafa42accb20e5ccfe23805ed91655d (diff) | |
download | chromium_src-3ebf9af0cd55de5d312f0df5254580ab60ac0c64.zip chromium_src-3ebf9af0cd55de5d312f0df5254580ab60ac0c64.tar.gz chromium_src-3ebf9af0cd55de5d312f0df5254580ab60ac0c64.tar.bz2 |
Fixing WebKeyboardEvent.
Review URL: http://codereview.chromium.org/39075
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10918 0039d316-1c4b-4281-b951-d872f2087c98
21 files changed, 280 insertions, 334 deletions
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index f4349a1..9f174fa 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1211,7 +1211,8 @@ void RenderViewHost::UnhandledKeyboardEvent(const WebKeyboardEvent& event) { // TODO(brettw) why do we have to filter these types of events here. Can't // the renderer just send us the ones we care abount, or maybe the view // should be able to decide which ones it wants or not? - if ((event.type == WebInputEvent::KEY_DOWN) || + if ((event.type == WebInputEvent::RAW_KEY_DOWN) || + (event.type == WebInputEvent::KEY_DOWN) || (event.type == WebInputEvent::CHAR)) { view->HandleKeyboardEvent(event); } diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 1050ec7..6951e3d 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -293,8 +293,8 @@ void RenderWidgetHost::ForwardWheelEvent( void RenderWidgetHost::ForwardKeyboardEvent(const WebKeyboardEvent& key_event) { if (key_event.type == WebKeyboardEvent::CHAR && - (key_event.key_code == base::VKEY_RETURN || - key_event.key_code == base::VKEY_SPACE)) { + (key_event.windows_key_code == base::VKEY_RETURN || + key_event.windows_key_code == base::VKEY_SPACE)) { OnEnterOrSpace(); } diff --git a/chrome/browser/renderer_host/render_widget_host_unittest.cc b/chrome/browser/renderer_host/render_widget_host_unittest.cc index ad677c1..da37f01 100644 --- a/chrome/browser/renderer_host/render_widget_host_unittest.cc +++ b/chrome/browser/renderer_host/render_widget_host_unittest.cc @@ -330,7 +330,7 @@ TEST_F(RenderWidgetHostTest, HandleKeyEventsWeSent) { WebKeyboardEvent key_event; key_event.type = WebInputEvent::KEY_DOWN; key_event.modifiers = WebInputEvent::CTRL_KEY; - key_event.key_code = base::VKEY_L; // non-null made up value. + key_event.windows_key_code = base::VKEY_L; // non-null made up value. host_->ForwardKeyboardEvent(key_event); diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index 750cb48f..13c1eb2 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -77,13 +77,6 @@ class RenderWidgetHostViewGtkWidget { RenderWidgetHostViewGtk* host_view) { WebKeyboardEvent wke(event); host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); - - // See note in webwidget_host_gtk.cc::HandleKeyPress(). - if (event->type == GDK_KEY_PRESS) { - wke.type = WebKeyboardEvent::CHAR; - host_view->GetRenderWidgetHost()->ForwardKeyboardEvent(wke); - } - return FALSE; } diff --git a/chrome/browser/tab_contents/web_contents_view_win.cc b/chrome/browser/tab_contents/web_contents_view_win.cc index bdbf89c..c66d339 100644 --- a/chrome/browser/tab_contents/web_contents_view_win.cc +++ b/chrome/browser/tab_contents/web_contents_view_win.cc @@ -249,7 +249,7 @@ void WebContentsViewWin::TakeFocus(bool reverse) { void WebContentsViewWin::HandleKeyboardEvent(const WebKeyboardEvent& event) { // Previous calls to TranslateMessage can generate CHAR events as well as - // KEY_DOWN events, even if the latter triggered an accelerator. In these + // RAW_KEY_DOWN events, even if the latter triggered an accelerator. In these // cases, we discard the CHAR events. if (event.type == WebInputEvent::CHAR && ignore_next_char_event_) { ignore_next_char_event_ = false; @@ -259,13 +259,13 @@ void WebContentsViewWin::HandleKeyboardEvent(const WebKeyboardEvent& event) { // The renderer returned a keyboard event it did not process. This may be // a keyboard shortcut that we have to process. - if (event.type == WebInputEvent::KEY_DOWN) { + if (event.type == WebInputEvent::RAW_KEY_DOWN) { views::FocusManager* focus_manager = views::FocusManager::GetFocusManager(GetHWND()); // We may not have a focus_manager at this point (if the tab has been // switched by the time this message returned). if (focus_manager) { - views::Accelerator accelerator(event.key_code, + views::Accelerator accelerator(event.windows_key_code, (event.modifiers & WebInputEvent::SHIFT_KEY) == WebInputEvent::SHIFT_KEY, (event.modifiers & WebInputEvent::CTRL_KEY) == diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index e91bdf0..582bf3a 100755 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -495,6 +495,9 @@ struct ParamTraits<WebInputEvent::Type> { case WebInputEvent::MOUSE_WHEEL: type = L"MOUSE_WHEEL"; break; + case WebInputEvent::RAW_KEY_DOWN: + type = L"RAW_KEY_DOWN"; + break; case WebInputEvent::KEY_DOWN: type = L"KEY_DOWN"; break; diff --git a/webkit/glue/SConscript b/webkit/glue/SConscript index 8e2bdf3..a06bfe1 100644 --- a/webkit/glue/SConscript +++ b/webkit/glue/SConscript @@ -127,6 +127,7 @@ elif env.Bit('linux'): 'plugins/webplugin_delegate_impl_gtk.cc', 'webcursor_gtk.cc', 'webinputevent_linux.cc', + 'webinputevent_util.cc', 'webkit_glue_gtk.cc', ]) elif env.Bit('mac'): diff --git a/webkit/glue/event_conversion.cc b/webkit/glue/event_conversion.cc index 0902778..39cdc90 100644 --- a/webkit/glue/event_conversion.cc +++ b/webkit/glue/event_conversion.cc @@ -22,6 +22,7 @@ MSVC_POP_WARNING(); #include "base/gfx/point.h" #include "base/logging.h" #include "webkit/glue/event_conversion.h" +#include "webkit/glue/glue_util.h" #include "webkit/glue/webinputevent.h" #include "webkit/glue/webkit_glue.h" @@ -141,6 +142,8 @@ static inline const PlatformKeyboardEvent::Type ToPlatformKeyboardEventType( return PlatformKeyboardEvent::KeyUp; case WebInputEvent::KEY_DOWN: return PlatformKeyboardEvent::KeyDown; + case WebInputEvent::RAW_KEY_DOWN: + return PlatformKeyboardEvent::RawKeyDown; case WebInputEvent::CHAR: return PlatformKeyboardEvent::Char; default: @@ -149,175 +152,21 @@ static inline const PlatformKeyboardEvent::Type ToPlatformKeyboardEventType( return PlatformKeyboardEvent::KeyDown; } -static inline String ToSingleCharacterString(UChar c) { - return String(&c, 1); -} - -#if !defined(OS_MACOSX) -// This function is not used on Mac OS X, and gcc complains. -static String GetKeyIdentifierForWindowsKeyCode(unsigned short keyCode) { - switch (keyCode) { - case VKEY_MENU: - return "Alt"; - case VKEY_CONTROL: - return "Control"; - case VKEY_SHIFT: - return "Shift"; - case VKEY_CAPITAL: - return "CapsLock"; - case VKEY_LWIN: - case VKEY_RWIN: - return "Win"; - case VKEY_CLEAR: - return "Clear"; - case VKEY_DOWN: - return "Down"; - // "End" - case VKEY_END: - return "End"; - // "Enter" - case VKEY_RETURN: - return "Enter"; - case VKEY_EXECUTE: - return "Execute"; - case VKEY_F1: - return "F1"; - case VKEY_F2: - return "F2"; - case VKEY_F3: - return "F3"; - case VKEY_F4: - return "F4"; - case VKEY_F5: - return "F5"; - case VKEY_F6: - return "F6"; - case VKEY_F7: - return "F7"; - case VKEY_F8: - return "F8"; - case VKEY_F9: - return "F9"; - case VKEY_F10: - return "F11"; - case VKEY_F12: - return "F12"; - case VKEY_F13: - return "F13"; - case VKEY_F14: - return "F14"; - case VKEY_F15: - return "F15"; - case VKEY_F16: - return "F16"; - case VKEY_F17: - return "F17"; - case VKEY_F18: - return "F18"; - case VKEY_F19: - return "F19"; - case VKEY_F20: - return "F20"; - case VKEY_F21: - return "F21"; - case VKEY_F22: - return "F22"; - case VKEY_F23: - return "F23"; - case VKEY_F24: - return "F24"; - case VKEY_HELP: - return "Help"; - case VKEY_HOME: - return "Home"; - case VKEY_INSERT: - return "Insert"; - case VKEY_LEFT: - return "Left"; - case VKEY_NEXT: - return "PageDown"; - case VKEY_PRIOR: - return "PageUp"; - case VKEY_PAUSE: - return "Pause"; - case VKEY_SNAPSHOT: - return "PrintScreen"; - case VKEY_RIGHT: - return "Right"; - case VKEY_SCROLL: - return "Scroll"; - case VKEY_SELECT: - return "Select"; - case VKEY_UP: - return "Up"; - // Standard says that DEL becomes U+007F. - case VKEY_DELETE: - return "U+007F"; - default: - return String::format("U+%04X", toupper(keyCode)); - } -} -#endif // !defined(OS_MACOSX) - -MakePlatformKeyboardEvent::MakePlatformKeyboardEvent(const WebKeyboardEvent& e) - { +MakePlatformKeyboardEvent::MakePlatformKeyboardEvent( + const WebKeyboardEvent& e) { m_type = ToPlatformKeyboardEventType(e.type); - if (m_type == Char || m_type == KeyDown) { -#if defined(OS_MACOSX) - m_text = &e.text[0]; - m_unmodifiedText = &e.unmodified_text[0]; - m_keyIdentifier = &e.key_identifier[0]; - - // Always use 13 for Enter/Return -- we don't want to use AppKit's - // different character for Enter. - if (m_windowsVirtualKeyCode == '\r') { - m_text = "\r"; - m_unmodifiedText = "\r"; - } - - // The adjustments below are only needed in backward compatibility mode, - // but we cannot tell what mode we are in from here. - - // Turn 0x7F into 8, because backspace needs to always be 8. - if (m_text == "\x7F") - m_text = "\x8"; - if (m_unmodifiedText == "\x7F") - m_unmodifiedText = "\x8"; - // Always use 9 for tab -- we don't want to use AppKit's different character for shift-tab. - if (m_windowsVirtualKeyCode == 9) { - m_text = "\x9"; - m_unmodifiedText = "\x9"; - } -#elif defined(OS_WIN) - m_text = m_unmodifiedText = ToSingleCharacterString(e.key_code); -#elif defined(OS_LINUX) - m_text = m_unmodifiedText = ToSingleCharacterString(e.text); -#endif - } -#if defined(OS_WIN) || defined(OS_LINUX) - if (m_type != Char) - m_keyIdentifier = GetKeyIdentifierForWindowsKeyCode(e.key_code); -#endif - if (m_type == Char || m_type == KeyDown || m_type == KeyUp || - m_type == RawKeyDown) { - m_windowsVirtualKeyCode = e.key_code; - } else { - m_windowsVirtualKeyCode = 0; - } + m_text = WebCore::String(e.text); + m_unmodifiedText = WebCore::String(e.unmodified_text); + m_keyIdentifier = WebCore::String(e.key_identifier); m_autoRepeat = (e.modifiers & WebInputEvent::IS_AUTO_REPEAT) != 0; + m_windowsVirtualKeyCode = e.windows_key_code; + m_nativeVirtualKeyCode = e.native_key_code; m_isKeypad = (e.modifiers & WebInputEvent::IS_KEYPAD) != 0; m_shiftKey = (e.modifiers & WebInputEvent::SHIFT_KEY) != 0; m_ctrlKey = (e.modifiers & WebInputEvent::CTRL_KEY) != 0; m_altKey = (e.modifiers & WebInputEvent::ALT_KEY) != 0; m_metaKey = (e.modifiers & WebInputEvent::META_KEY) != 0; -#if defined(OS_WIN) m_isSystemKey = e.system_key; -// TODO(port): set this field properly for linux and mac. -#elif defined(OS_LINUX) - m_isSystemKey = m_altKey; -#else - m_isSystemKey = false; -#endif } void MakePlatformKeyboardEvent::SetKeyType(Type type) { diff --git a/webkit/glue/glue.vcproj b/webkit/glue/glue.vcproj index 34a6b0b..b212649 100644 --- a/webkit/glue/glue.vcproj +++ b/webkit/glue/glue.vcproj @@ -641,6 +641,14 @@ >
</File>
<File
+ RelativePath=".\webinputevent_util.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\webinputevent_util.h"
+ >
+ </File>
+ <File
RelativePath=".\webkitclient_impl.cc"
>
</File>
diff --git a/webkit/glue/webinputevent.h b/webkit/glue/webinputevent.h index 5565478..dbfe456 100644 --- a/webkit/glue/webinputevent.h +++ b/webkit/glue/webinputevent.h @@ -6,11 +6,11 @@ #define WEBKIT_GLUE_WEBINPUTEVENT_H_ #include "base/basictypes.h" +#include "base/string16.h" #if defined(OS_WIN) #include <windows.h> #elif defined(OS_MACOSX) -#include <vector> #ifdef __OBJC__ @class NSEvent; @class NSView; @@ -19,6 +19,7 @@ class NSEvent; class NSView; #endif // __OBJC__ #elif defined(OS_LINUX) +#include <glib.h> typedef struct _GdkEventButton GdkEventButton; typedef struct _GdkEventMotion GdkEventMotion; typedef struct _GdkEventScroll GdkEventScroll; @@ -31,6 +32,10 @@ typedef struct _GdkEventKey GdkEventKey; // // The fields of these event classes roughly correspond to the fields required // by WebCore's platform event classes. +// +// WARNING! These classes must remain PODs (plain old data). They will be +// "serialized" by shipping their raw bytes across the wire, so they must not +// contain any non-bit-copyable member variables! // WebInputEvent -------------------------------------------------------------- @@ -38,6 +43,17 @@ class WebInputEvent { public: WebInputEvent() : modifiers(0) { } + // There are two schemes used for keyboard input. On Windows (and, + // interestingly enough, on Mac Carbon) there are two events for a keypress. + // One is a raw keydown, which provides the keycode only. If the app doesn't + // handle that, then the system runs key translation to create an event + // containing the generated character and pumps that event. In such a scheme, + // those two events are translated to RAW_KEY_DOWN and CHAR events + // respectively. In Cocoa and Gtk, key events contain both the keycode and any + // translation into actual text. In such a case, WebCore will eventually need + // to split the events (see disambiguateKeyDownEvent and its callers) but we + // don't worry about that here. We just use a different type (KEY_DOWN) to + // indicate this. enum Type { // WebMouseEvent MOUSE_DOWN, @@ -50,6 +66,7 @@ class WebInputEvent { MOUSE_WHEEL, // WebKeyboardEvent + RAW_KEY_DOWN, KEY_DOWN, KEY_UP, CHAR @@ -72,7 +89,10 @@ class WebInputEvent { // Returns true if the WebInputEvent |type| is a keyboard event. static bool IsKeyboardEventType(int type) { - return type == KEY_DOWN || type == KEY_UP || type == CHAR; + return type == RAW_KEY_DOWN || + type == KEY_DOWN || + type == KEY_UP || + type == CHAR; } }; @@ -126,53 +146,68 @@ class WebMouseWheelEvent : public WebMouseEvent { // WebKeyboardEvent ----------------------------------------------------------- +// Caps on string lengths so we can make them static arrays and keep them PODs. +const size_t kTextLengthCap = 4; +// http://www.w3.org/TR/DOM-Level-3-Events/keyset.html lists the identifiers. +// The longest is 18 characters, so we'll round up to the next multiple of 4. +const size_t kIdentifierLengthCap = 20; + class WebKeyboardEvent : public WebInputEvent { public: - // The key_code field is the Windows key code associated with this key event. - // This sometimes matches the ASCII value of the key (for e.g. a-z) but - // officially ignores case, and has its own set of codes for control keys as - // well as other visible letters like punctuation. - // webkit/port/platform/chromium/KeyboardCodes* is an attempt at defining all - // of these keys, but it's not all the way there yet. (E.g., the Windows - // implementation there just passes through the code from the windows message - // directly.) - int key_code; - -#if defined(OS_MACOSX) - // text arrays extracted from the native event. On Mac, there may be - // multiple keys sent as a single event if the flags don't change. - std::vector<unsigned short> text; - std::vector<unsigned short> unmodified_text; - std::vector<unsigned short> key_identifier; -#elif defined(OS_WIN) - bool system_key; // Set if we receive a SYSKEYDOWN/WM_SYSKEYUP message. - MSG actual_message; // Set to the current keyboard message. -#elif defined(OS_LINUX) - // The unicode character, if available, corresponding to this key event. - // TODO(evanm): temporary hack for test_shell. Ideally we'd either manage - // to stuff everything into key_code, or make this field shared by all - // implementations, but this will have to do for now. - wchar_t text; + // |windows_key_code| is the Windows key code associated with this key event. + // Sometimes it's direct from the event (i.e. on Windows), sometimes it's via + // a mapping function. If you want a list, see + // webkit/port/platform/chromium/KeyboardCodes* . + int windows_key_code; + + // The actual key code genenerated by the platform. The DOM spec runs on + // Windows-equivalent codes (thus |windows_key_code| above) but it doesn't + // hurt to have this one around. + int native_key_code; + + // |text| is the text generated by this keystroke. |unmodified_text| is + // |text|, but unmodified by an concurrently-held modifiers (except shift). + // This is useful for working out shortcut keys. Linux and Windows guarantee + // one character per event. The Mac does not, but in reality that's all it + // ever gives. We're generous, and cap it a bit longer. + char16 text[kTextLengthCap]; + char16 unmodified_text[kTextLengthCap]; + + // This is a string identifying the key pressed. + char key_identifier[kIdentifierLengthCap]; + + // This identifies whether this event was tagged by the system as being a + // "system key" event (see + // http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx for details). + // Other platforms don't have this concept, but it's just easier to leave it + // always false than ifdef. + + bool system_key; + + // References to the original event. +#if defined(OS_WIN) + MSG actual_message; // Set to the current keyboard message. TODO(avi): remove #endif - WebKeyboardEvent() - : key_code(0) + WebKeyboardEvent() : windows_key_code(0), + native_key_code(0), + system_key(false) { + memset(&text, 0, sizeof(text)); + memset(&unmodified_text, 0, sizeof(unmodified_text)); + memset(&key_identifier, 0, sizeof(key_identifier)); #if defined(OS_WIN) - , system_key(false) { memset(&actual_message, 0, sizeof(actual_message)); - } -#else - {} #endif + } #if defined(OS_WIN) - WebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); + explicit WebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, + LPARAM lparam); #elif defined(OS_MACOSX) - WebKeyboardEvent(NSEvent *event); + explicit WebKeyboardEvent(NSEvent *event); #elif defined(OS_LINUX) explicit WebKeyboardEvent(const GdkEventKey* event); #endif }; - #endif // WEBKIT_GLUE_WEBINPUTEVENT_H_ diff --git a/webkit/glue/webinputevent_linux.cc b/webkit/glue/webinputevent_linux.cc index 328dafe..6ef85aa 100644 --- a/webkit/glue/webinputevent_linux.cc +++ b/webkit/glue/webinputevent_linux.cc @@ -9,12 +9,9 @@ #include "KeyboardCodes.h" #include "KeyCodeConversion.h" -#include "webkit/glue/event_conversion.h" - -// This header is out of alphabetical order, but event_conversion.h pulls -// in more webkit headers that redefine LOG so I need to undef afterwards. -#undef LOG #include "base/logging.h" +#include "base/string_util.h" +#include "webkit/glue/webinputevent_util.h" #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> @@ -66,7 +63,7 @@ WebMouseEvent::WebMouseEvent(const GdkEventButton* event) { break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); }; button = BUTTON_NONE; @@ -92,7 +89,7 @@ WebMouseEvent::WebMouseEvent(const GdkEventMotion* event) { type = MOUSE_MOVE; break; default: - ASSERT_NOT_REACHED(); + NOTREACHED(); } button = BUTTON_NONE; @@ -149,13 +146,9 @@ WebMouseWheelEvent::WebMouseWheelEvent(const GdkEventScroll* event) { } WebKeyboardEvent::WebKeyboardEvent(const GdkEventKey* event) { + system_key = false; modifiers = GdkStateToWebEventModifiers(event->state); - // GDK only exposes key press and release events. By contrast, - // WebKeyboardEvent matches Windows and wants key down/up events along with a - // separate CHAR event. - // We require the caller to simulate the CHAR event manually. See - // test_shell's webwidget_host for an example. switch (event->type) { case GDK_KEY_RELEASE: type = KEY_UP; @@ -171,7 +164,12 @@ WebKeyboardEvent::WebKeyboardEvent(const GdkEventKey* event) { // The key code tells us which physical key was pressed (for example, the // A key went down or up). It does not determine whether A should be lower // or upper case. This is what text does, which should be the keyval. - key_code = WebCore::windowsKeyCodeForKeyEvent(event->keyval); + windows_key_code = WebCore::windowsKeyCodeForKeyEvent(event->keyval); + native_key_code = event->hardware_keycode; + + memset(&text, 0, sizeof(text)); + memset(&unmodified_text, 0, sizeof(unmodified_text)); + memset(&key_identifier, 0, sizeof(key_identifier)); switch (event->keyval) { // We need to treat the enter key as a key press of character \r. This @@ -179,13 +177,20 @@ WebKeyboardEvent::WebKeyboardEvent(const GdkEventKey* event) { case GDK_ISO_Enter: case GDK_KP_Enter: case GDK_Return: - text = '\r'; + unmodified_text[0] = text[0] = static_cast<char16>('\r'); break; default: // This should set text to 0 when it's not a real character. - text = gdk_keyval_to_unicode(event->keyval); + // TODO(avi): fix for non BMP chars + unmodified_text[0] = text[0] = + static_cast<char16>(gdk_keyval_to_unicode(event->keyval)); break; } + std::string key_identifier_str = + webkit_glue::GetKeyIdentifierForWindowsKeyCode(windows_key_code); + base::strlcpy(key_identifier, key_identifier_str.c_str(), + kIdentifierLengthCap); + // TODO(tc): Do we need to set IS_AUTO_REPEAT or IS_KEYPAD? } diff --git a/webkit/glue/webinputevent_mac.mm b/webkit/glue/webinputevent_mac.mm index 3090d96..d553828 100644 --- a/webkit/glue/webinputevent_mac.mm +++ b/webkit/glue/webinputevent_mac.mm @@ -1,6 +1,28 @@ -// Copyright (c) 2006-2008 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. +/* + * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006-2009 Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #import <Cocoa/Cocoa.h> @@ -141,7 +163,7 @@ WebMouseWheelEvent::WebMouseWheelEvent(NSEvent *event, NSView* view) { // that. As a result we have to use NSString here exclusively and thus tweak // the code so it's not re-usable as-is. One possiblity would be to make the // upstream code only use NSString, but I'm not certain how far that change -// would propageage +// would propagate. namespace WebCore { @@ -923,18 +945,8 @@ static NSString* keyIdentifierForKeyEvent(NSEvent* event) // End Apple code. // --------------------------------------------------------------------- -// Helper that copies the unichar characters of a NSString into a suitably -// resized vector. The vector will be null terminated and thus even if the -// string is empty or nil, it array will have a NUL. -static void FillVectorFromNSString(std::vector<unsigned short>* v, - NSString* str) { - const unsigned int length = [str length]; - v->reserve(length + 1); - [str getCharacters:&(*v)[0]]; - (*v)[length] = '\0'; -} - WebKeyboardEvent::WebKeyboardEvent(NSEvent *event) { + system_key = false; type = WebCore::isKeyUpEvent(event) ? KEY_UP : KEY_DOWN; if ([event modifierFlags] & NSControlKeyMask) @@ -952,12 +964,51 @@ WebKeyboardEvent::WebKeyboardEvent(NSEvent *event) { if (([event type] != NSFlagsChanged) && [event isARepeat]) modifiers |= IS_AUTO_REPEAT; - NSString* textString = WebCore::textFromEvent(event); - NSString* unmodifiedStr = WebCore::unmodifiedTextFromEvent(event); - NSString* identStr = WebCore::keyIdentifierForKeyEvent(event); - FillVectorFromNSString(&text, textString); - FillVectorFromNSString(&unmodified_text, unmodifiedStr); - FillVectorFromNSString(&key_identifier, identStr); + windows_key_code = WebCore::windowsKeyCodeForKeyEvent(event); + native_key_code = [event keyCode]; - key_code = WebCore::windowsKeyCodeForKeyEvent(event); + NSString* text_str = WebCore::textFromEvent(event); + NSString* unmodified_str = WebCore::unmodifiedTextFromEvent(event); + NSString* identifier_str = WebCore::keyIdentifierForKeyEvent(event); + + // Begin Apple code, copied from KeyEventMac.mm + + // Always use 13 for Enter/Return -- we don't want to use AppKit's + // different character for Enter. + if (windows_key_code == '\r') { + text_str = @"\r"; + unmodified_str = @"\r"; + } + + // The adjustments below are only needed in backward compatibility mode, + // but we cannot tell what mode we are in from here. + + // Turn 0x7F into 8, because backspace needs to always be 8. + if ([text_str isEqualToString:@"\x7F"]) + text_str = @"\x8"; + if ([unmodified_str isEqualToString:@"\x7F"]) + unmodified_str = @"\x8"; + // Always use 9 for tab -- we don't want to use AppKit's different character + // for shift-tab. + if (windows_key_code == 9) { + text_str = @"\x9"; + unmodified_str = @"\x9"; + } + + // End Apple code. + + memset(&text, 0, sizeof(text)); + memset(&unmodified_text, 0, sizeof(unmodified_text)); + memset(&key_identifier, 0, sizeof(key_identifier)); + + if ([text_str length] < kTextLengthCap && + [unmodified_str length] < kTextLengthCap) { + [text_str getCharacters:&text[0]]; + [unmodified_str getCharacters:&unmodified_text[0]]; + } else { + LOG(ERROR) << "Event had text too long; dropped"; + } + [identifier_str getCString:&key_identifier[0] + maxLength:kIdentifierLengthCap + encoding:NSASCIIStringEncoding]; } diff --git a/webkit/glue/webinputevent_win.cc b/webkit/glue/webinputevent_win.cc index bcf573c..3588154 100644 --- a/webkit/glue/webinputevent_win.cc +++ b/webkit/glue/webinputevent_win.cc @@ -6,10 +6,9 @@ #include "webkit/glue/webinputevent.h" -#include "webkit/glue/event_conversion.h" - -#undef LOG #include "base/logging.h" +#include "base/string_util.h" +#include "webkit/glue/webinputevent_util.h" static const unsigned long kDefaultScrollLinesPerWheelDelta = 3; @@ -177,9 +176,9 @@ WebMouseWheelEvent::WebMouseWheelEvent(HWND hwnd, UINT message, WPARAM wparam, // message == WM_HSCROLL, wparam == SB_LINELEFT (== SB_LINEUP). // * Scrolling right // message == WM_HSCROLL, wparam == SB_LINERIGHT (== SB_LINEDOWN). - if (WM_HSCROLL == message) { - key_state |= MK_SHIFT; - wheel_delta = -wheel_delta; + if (WM_HSCROLL == message) { + key_state |= MK_SHIFT; + wheel_delta = -wheel_delta; } // Use GetAsyncKeyState for key state since we are synthesizing @@ -310,13 +309,13 @@ WebKeyboardEvent::WebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, actual_message.wParam = wparam; actual_message.lParam = lparam; - key_code = static_cast<int>(wparam); + windows_key_code = native_key_code = static_cast<int>(wparam); switch (message) { case WM_SYSKEYDOWN: system_key = true; case WM_KEYDOWN: - type = KEY_DOWN; + type = RAW_KEY_DOWN; break; case WM_SYSKEYUP: system_key = true; @@ -336,6 +335,21 @@ WebKeyboardEvent::WebKeyboardEvent(HWND hwnd, UINT message, WPARAM wparam, NOTREACHED() << "unexpected native message: " << message; } + memset(&text, 0, sizeof(text)); + memset(&unmodified_text, 0, sizeof(unmodified_text)); + memset(&key_identifier, 0, sizeof(key_identifier)); + + if (type == CHAR || type == RAW_KEY_DOWN) { + text[0] = windows_key_code; + unmodified_text[0] = windows_key_code; + } + if (type != CHAR) { + std::string key_identifier_str = + webkit_glue::GetKeyIdentifierForWindowsKeyCode(windows_key_code); + base::strlcpy(key_identifier, key_identifier_str.c_str(), + kIdentifierLengthCap); + } + if (GetKeyState(VK_SHIFT) & 0x8000) modifiers |= SHIFT_KEY; if (GetKeyState(VK_CONTROL) & 0x8000) diff --git a/webkit/glue/webview_impl.cc b/webkit/glue/webview_impl.cc index 2fac917..b81f0cd 100644 --- a/webkit/glue/webview_impl.cc +++ b/webkit/glue/webview_impl.cc @@ -480,7 +480,8 @@ void WebViewImpl::MouseWheel(const WebMouseWheelEvent& event) { } bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { - DCHECK((event.type == WebInputEvent::KEY_DOWN) || + DCHECK((event.type == WebInputEvent::RAW_KEY_DOWN) || + (event.type == WebInputEvent::KEY_DOWN) || (event.type == WebInputEvent::KEY_UP)); // Please refer to the comments explaining the suppress_next_keypress_event_ @@ -505,9 +506,9 @@ bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { #if defined(OS_WIN) // TODO(pinkerton): figure out these keycodes on non-windows - if (((event.modifiers == 0) && (event.key_code == VK_APPS)) || + if (((event.modifiers == 0) && (event.windows_key_code == VK_APPS)) || ((event.modifiers == WebInputEvent::SHIFT_KEY) && - (event.key_code == VK_F10))) { + (event.windows_key_code == VK_F10))) { SendContextMenuEvent(event); return true; } @@ -515,11 +516,8 @@ bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { MakePlatformKeyboardEvent evt(event); -#if !defined(OS_MACOSX) - if (WebInputEvent::KEY_DOWN == event.type) { - MakePlatformKeyboardEvent evt_rawkeydown = evt; - evt_rawkeydown.SetKeyType(WebCore::PlatformKeyboardEvent::RawKeyDown); - if (handler->keyEvent(evt_rawkeydown) && !evt_rawkeydown.isSystemKey()) { + if (WebInputEvent::RAW_KEY_DOWN == event.type) { + if (handler->keyEvent(evt) && !evt.isSystemKey()) { suppress_next_keypress_event_ = true; return true; } @@ -528,19 +526,6 @@ bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { return true; } } -#else - // Windows and Cocoa handle events in rather different ways. On Windows, - // you get two events: WM_KEYDOWN/WM_KEYUP and WM_CHAR. In - // PlatformKeyboardEvent, RawKeyDown represents the raw messages. When - // processing them, we don't process text editing events, since we'll be - // getting the data soon enough. In Cocoa, we get one event with both the - // raw and processed data. Therefore we need to keep the type as KeyDown, so - // that we'll know that this is the only time we'll have the event and that - // we need to do our thing. - if (handler->keyEvent(evt)) { - return true; - } -#endif return KeyEventDefault(event); } @@ -548,18 +533,19 @@ bool WebViewImpl::KeyEvent(const WebKeyboardEvent& event) { bool WebViewImpl::AutocompleteHandleKeyEvent(const WebKeyboardEvent& event) { if (!autocomplete_popup_showing_ || // Home and End should be left to the text field to process. - event.key_code == base::VKEY_HOME || event.key_code == base::VKEY_END) { + event.windows_key_code == base::VKEY_HOME || + event.windows_key_code == base::VKEY_END) { return false; } - if (!autocomplete_popup_->isInterestedInEventForKey(event.key_code)) + if (!autocomplete_popup_->isInterestedInEventForKey(event.windows_key_code)) return false; if (autocomplete_popup_->handleKeyEvent(MakePlatformKeyboardEvent(event))) { #if defined(OS_WIN) // We need to ignore the next CHAR event after this otherwise pressing // enter when selecting an item in the menu will go to the page. - if (WebInputEvent::KEY_DOWN == event.type) + if (WebInputEvent::RAW_KEY_DOWN == event.type) suppress_next_keypress_event_ = true; #endif return true; @@ -693,7 +679,7 @@ bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) { case WebInputEvent::CHAR: { #if defined(OS_WIN) // TODO(pinkerton): hook this up for non-win32 - if (event.key_code == VK_SPACE) { + if (event.windows_key_code == VK_SPACE) { int key_code = ((event.modifiers & WebInputEvent::SHIFT_KEY) ? VK_PRIOR : VK_NEXT); return ScrollViewWithKeyboard(key_code); @@ -702,9 +688,9 @@ bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) { break; } - case WebInputEvent::KEY_DOWN: { + case WebInputEvent::RAW_KEY_DOWN: { if (event.modifiers == WebInputEvent::CTRL_KEY) { - switch (event.key_code) { + switch (event.windows_key_code) { case 'A': GetFocusedFrame()->SelectAll(); return true; @@ -729,7 +715,7 @@ bool WebViewImpl::KeyEventDefault(const WebKeyboardEvent& event) { } #if defined(OS_WIN) if (!event.system_key) { - return ScrollViewWithKeyboard(event.key_code); + return ScrollViewWithKeyboard(event.windows_key_code); } #endif break; @@ -974,6 +960,7 @@ bool WebViewImpl::HandleInputEvent(const WebInputEvent* input_event) { MouseUp(*static_cast<const WebMouseEvent*>(input_event)); break; + case WebInputEvent::RAW_KEY_DOWN: case WebInputEvent::KEY_DOWN: case WebInputEvent::KEY_UP: handled = KeyEvent(*static_cast<const WebKeyboardEvent*>(input_event)); @@ -1232,15 +1219,12 @@ void WebViewImpl::SetInitialFocus(bool reverse) { // Since we don't have a keyboard event, we'll create one. WebKeyboardEvent keyboard_event; - keyboard_event.type = WebInputEvent::KEY_DOWN; + keyboard_event.type = WebInputEvent::RAW_KEY_DOWN; if (reverse) keyboard_event.modifiers = WebInputEvent::SHIFT_KEY; // VK_TAB which is only defined on Windows. - keyboard_event.key_code = 0x09; + keyboard_event.windows_key_code = 0x09; MakePlatformKeyboardEvent platform_event(keyboard_event); - // We have to set the key type explicitly to avoid an assert in the - // KeyboardEvent constructor. - platform_event.SetKeyType(PlatformKeyboardEvent::RawKeyDown); RefPtr<KeyboardEvent> webkit_event = KeyboardEvent::create(platform_event, NULL); page()->focusController()->setInitialFocus( diff --git a/webkit/glue/webwidget_impl.cc b/webkit/glue/webwidget_impl.cc index 721bbd3..b745a66 100644 --- a/webkit/glue/webwidget_impl.cc +++ b/webkit/glue/webwidget_impl.cc @@ -172,6 +172,7 @@ bool WebWidgetImpl::HandleInputEvent(const WebInputEvent* input_event) { MouseUp(*static_cast<const WebMouseEvent*>(input_event)); return true; + case WebInputEvent::RAW_KEY_DOWN: case WebInputEvent::KEY_DOWN: case WebInputEvent::KEY_UP: return KeyEvent(*static_cast<const WebKeyboardEvent*>(input_event)); diff --git a/webkit/tools/test_shell/event_sending_controller.cc b/webkit/tools/test_shell/event_sending_controller.cc index 76e8a06..fc4934e 100644 --- a/webkit/tools/test_shell/event_sending_controller.cc +++ b/webkit/tools/test_shell/event_sending_controller.cc @@ -29,6 +29,7 @@ #include "base/ref_counted.h" #include "base/string_util.h" #include "base/time.h" +#include "webkit/glue/webinputevent_util.h" #include "webkit/glue/webview.h" #include "webkit/tools/test_shell/test_shell.h" @@ -373,26 +374,32 @@ void EventSendingController::keyDown( } else { DCHECK(code_str.length() == 1); code = code_str[0]; - needs_shift_key_modifier = NeedsShiftModifer(code); + needs_shift_key_modifier = NeedsShiftModifier(code); generate_char = true; } - // NOTE(jnd):For one keydown event, we need to generate - // keyDown/keyUp pair, refer EventSender.cpp in - // WebKit/WebKitTools/DumpRenderTree/win. We may also need - // to generate a keyChar event in certain cases. + // For one generated keyboard event, we need to generate a keyDown/keyUp + // pair; refer to EventSender.cpp in WebKit/WebKitTools/DumpRenderTree/win. + // On Windows, we might also need to generate a char event to mimic the + // Windows event flow; on other platforms we create a merged event and test + // the event flow that that platform provides. WebKeyboardEvent event_down, event_up; +#if defined(OS_WIN) + event_down.type = WebInputEvent::RAW_KEY_DOWN; +#else event_down.type = WebInputEvent::KEY_DOWN; - event_down.modifiers = 0; - event_down.key_code = code; -#if defined(OS_LINUX) - // TODO(deanm): This code is a confusing mix of different platform key - // codes. Since we're not working with a GDK event, we can't use our - // GDK -> WebKit converter, which means the Linux specific extra |text| - // field goes uninitialized. I don't know how to correctly calculate this - // field, but for now we will at least initialize it, even if it's wrong. - event_down.text = code; #endif + event_down.modifiers = 0; + event_down.windows_key_code = code; + if (generate_char) { + event_down.text[0] = code; + event_down.unmodified_text[0] = code; + } + std::string key_identifier_str = + webkit_glue::GetKeyIdentifierForWindowsKeyCode(code); + + base::strlcpy(event_down.key_identifier, key_identifier_str.c_str(), + kIdentifierLengthCap); if (args.size() >= 2 && (args[1].isObject() || args[1].isString())) ApplyKeyModifiers(&(args[1]), &event_down); @@ -408,11 +415,14 @@ void EventSendingController::keyDown( webview()->HandleInputEvent(&event_down); +#if defined(OS_WIN) if (generate_char) { WebKeyboardEvent event_char = event_down; event_char.type = WebInputEvent::CHAR; + event_char.key_identifier[0] = '\0'; webview()->HandleInputEvent(&event_char); } +#endif webview()->HandleInputEvent(&event_up); } @@ -444,7 +454,7 @@ void EventSendingController::dispatchMessage( #endif } -bool EventSendingController::NeedsShiftModifer(int key_code) { +bool EventSendingController::NeedsShiftModifier(int key_code) { // If code is an uppercase letter, assign a SHIFT key to // event_down.modifier, this logic comes from // WebKit/WebKitTools/DumpRenderTree/Win/EventSender.cpp diff --git a/webkit/tools/test_shell/event_sending_controller.h b/webkit/tools/test_shell/event_sending_controller.h index cd3bf78..aaa7a74 100644 --- a/webkit/tools/test_shell/event_sending_controller.h +++ b/webkit/tools/test_shell/event_sending_controller.h @@ -91,7 +91,7 @@ class EventSendingController : public CppBoundClass { // Returns true if the key_code passed in needs a shift key modifier to // be passed into the generated event. - bool NeedsShiftModifer(int key_code); + bool NeedsShiftModifier(int key_code); ScopedRunnableMethodFactory<EventSendingController> method_factory_; diff --git a/webkit/tools/test_shell/keyboard_unittest.cc b/webkit/tools/test_shell/keyboard_unittest.cc index 673edd1..03f1b15 100644 --- a/webkit/tools/test_shell/keyboard_unittest.cc +++ b/webkit/tools/test_shell/keyboard_unittest.cc @@ -14,9 +14,11 @@ MSVC_POP_WARNING(); #undef LOG +#include "base/string_util.h" #include "webkit/glue/editor_client_impl.h" #include "webkit/glue/event_conversion.h" #include "webkit/glue/webinputevent.h" +#include "webkit/glue/webinputevent_util.h" #include "testing/gtest/include/gtest/gtest.h" using WebCore::PlatformKeyboardEvent; @@ -46,15 +48,14 @@ class KeyboardTest : public testing::Test { void SetupKeyDownEvent(WebKeyboardEvent* keyboard_event, char key_code, int modifiers) { - keyboard_event->key_code = key_code; + keyboard_event->windows_key_code = key_code; keyboard_event->modifiers = modifiers; keyboard_event->type = WebInputEvent::KEY_DOWN; -#if defined(OS_LINUX) - keyboard_event->text = key_code; -#elif defined(OS_MACOSX) - keyboard_event->text.clear(); - keyboard_event->text.push_back(key_code); -#endif + keyboard_event->text[0] = key_code; + std::string key_identifier_str = + webkit_glue::GetKeyIdentifierForWindowsKeyCode(key_code); + base::strlcpy(keyboard_event->key_identifier, key_identifier_str.c_str(), + kIdentifierLengthCap); } // Like InterpretKeyEvent, but with pressing down OSModifier+|key_code|. diff --git a/webkit/tools/test_shell/mac/webwidget_host.mm b/webkit/tools/test_shell/mac/webwidget_host.mm index dc1b6c6..b99aca7 100644 --- a/webkit/tools/test_shell/mac/webwidget_host.mm +++ b/webkit/tools/test_shell/mac/webwidget_host.mm @@ -221,15 +221,7 @@ void WebWidgetHost::MouseEvent(NSEvent *event) { case WebInputEvent::MOUSE_LEAVE: TrackMouseLeave(false); break; - case WebInputEvent::MOUSE_DOWN: - break; - case WebInputEvent::MOUSE_UP: - break; - case WebInputEvent::MOUSE_DOUBLE_CLICK: - case WebInputEvent::MOUSE_WHEEL: - case WebInputEvent::KEY_DOWN: - case WebInputEvent::KEY_UP: - case WebInputEvent::CHAR: + default: break; } webwidget_->HandleInputEvent(&web_event); diff --git a/webkit/tools/test_shell/test_shell.gyp b/webkit/tools/test_shell/test_shell.gyp index ba4c145..cefe517 100644 --- a/webkit/tools/test_shell/test_shell.gyp +++ b/webkit/tools/test_shell/test_shell.gyp @@ -82,7 +82,15 @@ ], 'conditions': [ ['OS!="linux"', {'sources/': [['exclude', '_gtk\\.cc$']]}], - ['OS!="mac"', { + ['OS=="mac"', { + 'sources': [ + # Windows/Linux use this code normally when constructing events, so + # in test_shell they get it from glue. The Mac has its own code for + # accomplishing it, so in test_shell, where events are constructed + # from scratch, we need to pull this in. + '../../glue/webinputevent_util.cc', + ] + }, { # else: OS!=mac 'sources/': [ ['exclude', 'mac/[^/]*\\.(cc|mm?)$'], ['exclude', '_mac\\.(cc|mm?)$'], @@ -98,7 +106,7 @@ 'dependencies': [ '../../../breakpad/breakpad.gyp:breakpad_handler', ], - }, { # OS!=win + }, { # else: OS!=win 'sources/': [ ['exclude', '_win\\.cc$'] ], @@ -191,7 +199,7 @@ }], ['OS=="win"', { 'msvs_disabled_warnings': [ 4800 ], - }, { # OS!=win + }, { # else: OS!=win 'sources!': [ '../../../skia/ext/vector_canvas_unittest.cc', '../webcore_unit_tests/UniscribeHelper_unittest.cpp', diff --git a/webkit/tools/test_shell/webwidget_host_gtk.cc b/webkit/tools/test_shell/webwidget_host_gtk.cc index c3b5cb6..57d88d8 100644 --- a/webkit/tools/test_shell/webwidget_host_gtk.cc +++ b/webkit/tools/test_shell/webwidget_host_gtk.cc @@ -148,16 +148,6 @@ class WebWidgetHostGtkWidget { WebKeyboardEvent wke(event); host->webwidget()->HandleInputEvent(&wke); - // The WebKeyboardEvent model, when holding down a key, is: - // KEY_DOWN, CHAR, (repeated CHAR as key repeats,) KEY_UP - // The GDK model for the same sequence is just: - // KEY_PRESS, (repeated KEY_PRESS as key repeats,) KEY_RELEASE - // So we must simulate a CHAR event for every key press. - if (event->type == GDK_KEY_PRESS) { - wke.type = WebKeyboardEvent::CHAR; - host->webwidget()->HandleInputEvent(&wke); - } - return FALSE; } |