From 61d7f450908f134b7145e266a3a93135ab92b49a Mon Sep 17 00:00:00 2001 From: "suzhe@chromium.org" Date: Fri, 16 Oct 2009 09:54:49 +0000 Subject: Supports control characters, like what Windows does. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL fixes issue 21471 by implementing the support of control characters. For the reason of issue 21471, please refer to the code of EditorClientImpl::handleEditingKeyboardEvent() (webkit/glue/editor_client_impl.cc around line 601): ... // Here we need to filter key events. // On Gtk/Linux, it emits key events with ASCII text and ctrl on for ctrl-. // In Webkit, EditorClient::handleKeyboardEvent in // WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp drop such events. // On Mac, it emits key events with ASCII text and meta on for Command-. // These key events should not emit text insert event. // Alt key would be used to insert alternative character, so we should let // through. Also note that Ctrl-Alt combination equals to AltGr key which is // also used to insert alternative character. // http://code.google.com/p/chromium/issues/detail?id=10846 // Windows sets both alt and meta are on when "Alt" key pressed. // http://code.google.com/p/chromium/issues/detail?id=2215 // Also, we should not rely on an assumption that keyboards don't // send ASCII characters when pressing a control key on Windows, // which may be configured to do it so by user. // See also http://en.wikipedia.org/wiki/Keyboard_Layout // TODO(ukai): investigate more detail for various keyboard layout. if (evt->keyEvent()->text().length() == 1) { UChar ch = evt->keyEvent()->text()[0U]; // Don't insert null or control characters as they can result in // unexpected behaviour if (ch < ' ') return false; #if !defined(OS_WIN) // Don't insert ASCII character if ctrl w/o alt or meta is on. // On Mac, we should ignore events when meta is on (Command-). if (ch < 0x80) { if (evt->keyEvent()->ctrlKey() && !evt->keyEvent()->altKey()) return false; #if defined(OS_MACOSX) if (evt->keyEvent()->metaKey()) return false; #endif } #endif } if (!frame->editor()->canEdit()) return false; return frame->editor()->insertText(evt->keyEvent()->text(), evt); ... And gtk implementation of WebInputEventFactory::keyboardEvent() (webkit/api/src/gtk/WebInputEventFactory.cpp, line 225): ... // This should set text to 0 when it's not a real character. // FIXME: fix for non BMP chars // TODO(james.su@gmail.com): // Support control characters input like Windows. // See: http://en.wikipedia.org/wiki/Control_characters result.unmodifiedText[0] = result.text[0] = static_cast(gdk_keyval_to_unicode(event->keyval)); ... You can see that, on Linux, the text of a keyboard event is set to the unicode char corresponding to |event->keyval| which might be greater than 0x80 when using a non-English keyboard layout, even when ctrl key is pressed. In EditorClientImpl::handleEditKeyboardEvent(), the character will be inserted as text if ch >= 0x80, no matter if ctrl is pressed or not. That's why when using some non-English keyboard layout (eg. Russian), some unexpected characters will be input when press accelerator keys such as ctrl-l. On Windows, ctrl key combinations will generate control characters, see: http://en.wikipedia.org/wiki/Control_characters for details, especially the "How control characters map to keyboards" section. So rather than patching EditorClientImpl::handleEditingKeyboardEvent() to filter out such unexpected inputs, I choose to emulate the control characters behavior of Windows, to make sure no key event with ch >= 0x80 will be generated when ctrl is pressed. This approach not only fixes issue 21471, but also makes the behavior on Linux similar than on Windows. For EditorClientImpl::handleEditKeyboardEvent(), we might need to revise the logic of event filter to see if it has any other potential issues. But I think we can address it separately. BUG=21471: REGRESSION: Ctrl+F results in "а" added to the edit box in belarusian TEST=Switch keyboard layout to Russian or Belarusian, press ctrl-f in any edit box in a web page, search box should be opened and nothing should be input into the edit box. Review URL: http://codereview.chromium.org/195062 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29261 0039d316-1c4b-4281-b951-d872f2087c98 --- webkit/api/src/gtk/WebInputEventFactory.cpp | 74 +++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 15 deletions(-) (limited to 'webkit/api/src/gtk/WebInputEventFactory.cpp') diff --git a/webkit/api/src/gtk/WebInputEventFactory.cpp b/webkit/api/src/gtk/WebInputEventFactory.cpp index 27298bd..6dc9ebc 100644 --- a/webkit/api/src/gtk/WebInputEventFactory.cpp +++ b/webkit/api/src/gtk/WebInputEventFactory.cpp @@ -170,6 +170,52 @@ static int gdkEventToWindowsKeyCode(const GdkEventKey* event) return WebCore::windowsKeyCodeForKeyEvent(event->keyval); } +// Gets the corresponding control character of a specified key code. See: +// http://en.wikipedia.org/wiki/Control_characters +// We emulate Windows behavior here. +static WebUChar getControlCharacter(int windowsKeyCode, bool shift) +{ + if (windowsKeyCode >= WebCore::VKEY_A && windowsKeyCode <= WebCore::VKEY_Z) { + // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A + return windowsKeyCode - WebCore::VKEY_A + 1; + } + if (shift) { + // following graphics chars require shift key to input. + switch (windowsKeyCode) { + // ctrl-@ maps to \x00 (Null byte) + case WebCore::VKEY_2: + return 0; + // ctrl-^ maps to \x1E (Record separator, Information separator two) + case WebCore::VKEY_6: + return 0x1E; + // ctrl-_ maps to \x1F (Unit separator, Information separator one) + case WebCore::VKEY_OEM_MINUS: + return 0x1F; + // Returns 0 for all other keys to avoid inputting unexpected chars. + default: + return 0; + } + } else { + switch (windowsKeyCode) { + // ctrl-[ maps to \x1B (Escape) + case WebCore::VKEY_OEM_4: + return 0x1B; + // ctrl-\ maps to \x1C (File separator, Information separator four) + case WebCore::VKEY_OEM_5: + return 0x1C; + // ctrl-] maps to \x1D (Group separator, Information separator three) + case WebCore::VKEY_OEM_6: + return 0x1D; + // ctrl-Enter maps to \x0A (Line feed) + case WebCore::VKEY_RETURN: + return 0x0A; + // Returns 0 for all other keys to avoid inputting unexpected chars. + default: + return 0; + } + } +} + // WebKeyboardEvent ----------------------------------------------------------- WebKeyboardEvent WebInputEventFactory::keyboardEvent(const GdkEventKey* event) @@ -205,23 +251,21 @@ WebKeyboardEvent WebInputEventFactory::keyboardEvent(const GdkEventKey* event) result.windowsKeyCode = gdkEventToWindowsKeyCode(event); result.nativeKeyCode = event->hardware_keycode; - switch (event->keyval) { - // We need to treat the enter key as a key press of character \r. This - // is apparently just how webkit handles it and what it expects. - case GDK_ISO_Enter: - case GDK_KP_Enter: - case GDK_Return: - result.unmodifiedText[0] = result.text[0] = static_cast('\r'); - break; - default: - // This should set text to 0 when it's not a real character. + if (result.windowsKeyCode == WebCore::VKEY_RETURN) + // We need to treat the enter key as a key press of character \r. This + // is apparently just how webkit handles it and what it expects. + result.unmodifiedText[0] = '\r'; + else // FIXME: fix for non BMP chars - // TODO(james.su@gmail.com): - // Support control characters input like Windows. - // See: http://en.wikipedia.org/wiki/Control_characters - result.unmodifiedText[0] = result.text[0] = + result.unmodifiedText[0] = static_cast(gdk_keyval_to_unicode(event->keyval)); - } + + // If ctrl key is pressed down, then control character shall be input. + if (result.modifiers & WebInputEvent::ControlKey) + result.text[0] = getControlCharacter( + result.windowsKeyCode, result.modifiers & WebInputEvent::ShiftKey); + else + result.text[0] = result.unmodifiedText[0]; result.setKeyIdentifierFromWindowsKeyCode(); -- cgit v1.1