[Webkit-unassigned] [Bug 28733] [GTK] GtkIMContext filtering interferes with DOM key events
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Mon Sep 21 23:12:43 PDT 2009
https://bugs.webkit.org/show_bug.cgi?id=28733
Xan Lopez <xan.lopez at gmail.com> changed:
What |Removed |Added
----------------------------------------------------------------------------
Attachment #39634|review? |review-
Flag| |
--- Comment #6 from Xan Lopez <xan.lopez at gmail.com> 2009-09-21 23:12:43 PDT ---
(From update of attachment 39634)
> From 577ffcebd4918a23912543b9b401e4beabb90e72 Mon Sep 17 00:00:00 2001
> From: Martin Robinson <martin.james.robinson at gmail.com>
> Date: Tue, 15 Sep 2009 21:38:25 -0700
> Subject: [PATCH] Ensure that even when GTKSimpleIMContext filters non-IME keystrokes, keyboard events are fired properly.
>
> ---
> LayoutTests/ChangeLog | 11 ++
> LayoutTests/platform/gtk/Skipped | 8 -
> WebCore/ChangeLog | 13 ++
> WebCore/platform/gtk/KeyEventGtk.cpp | 4 +
> WebKit/gtk/ChangeLog | 20 +++
> WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp | 209 +++++++++++++++----------
> 6 files changed, 171 insertions(+), 94 deletions(-)
>
> diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
> index b57082c..f314fe6 100644
> --- a/LayoutTests/ChangeLog
> +++ b/LayoutTests/ChangeLog
> @@ -1,3 +1,14 @@
> +2009-09-15 Martin Robinson <martin.james.robinson at gmail.com>
> +
> + Reviewed by NOBODY (OOPS!).
> +
> + [GTK] GtkIMContext filtering interferes with DOM key events
> + https://bugs.webkit.org/show_bug.cgi?id=28733
> +
> + Enable tests which are now passing because of key event fixes.
> +
> + * platform/gtk/Skipped:
> +
> 2009-09-15 Chris Fleizach <cfleizach at apple.com>
>
> Layout test fix.
> diff --git a/LayoutTests/platform/gtk/Skipped b/LayoutTests/platform/gtk/Skipped
> index 8db2ec5..e8a796c 100644
> --- a/LayoutTests/platform/gtk/Skipped
> +++ b/LayoutTests/platform/gtk/Skipped
> @@ -1605,12 +1605,6 @@ fast/events/dblclick-addEventListener.html
> fast/events/drag-in-frames.html
> fast/events/frame-tab-focus.html
> fast/events/js-keyboard-event-creation.html
> -fast/events/key-events-in-input-button.html
> -fast/events/key-events-in-input-text.html
> -fast/events/keydown-keypress-focus-change.html
> -fast/events/keydown-keypress-preventDefault.html
> -fast/events/keypress-focus-change.html
> -fast/events/keypress-insert-tab.html
> fast/events/mouse-click-events.html
> fast/events/mouseclick-target-and-positioning.html
> fast/events/mouseup-from-button2.html
> @@ -1629,7 +1623,6 @@ fast/events/pointer-events-2.html
> fast/events/popup-blocking-click-in-iframe.html
> fast/events/right-click-focus.html
> fast/events/scrollbar-double-click.html
> -fast/events/special-key-events-in-input-text.html
> fast/events/stop-load-in-unload-handler-using-document-write.html
> fast/events/stop-load-in-unload-handler-using-window-stop.html
> fast/events/tabindex-focus-blur-all.html
> @@ -5582,7 +5575,6 @@ editing/pasteboard/files-during-page-drags.html
> editing/selection/extend-selection-after-double-click.html
> fast/events/drag-to-navigate.html
> fast/events/prevent-drag-to-navigate.html
> -fast/events/keydown-function-keys.html
> fast/forms/slider-delete-while-dragging-thumb.html
> fast/events/tab-focus-anchor.html
> http/tests/local/drag-over-remote-content.html
> diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
> index 4b19fb1..dfca55a 100644
> --- a/WebCore/ChangeLog
> +++ b/WebCore/ChangeLog
> @@ -1,3 +1,16 @@
> +2009-09-15 Martin Robinson <martin.james.robinson at gmail.com>
> +
> + Reviewed by NOBODY (OOPS!).
> +
> + [GTK] GtkIMContext filtering interferes with DOM key events
> + https://bugs.webkit.org/show_bug.cgi?id=28733
> +
> + Give GDK_Backspace key events the proper text properties.
> +
> + * platform/gtk/KeyEventGtk.cpp:
> + (WebCore::keyIdentifierForGdkKeyCode):
> + (WebCore::singleCharacterString):
> +
> 2009-09-15 Geoffrey Garen <ggaren at apple.com>
>
> Reviewed by Sam Weinig.
> diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp
> index 5875547..4186c2f 100644
> --- a/WebCore/platform/gtk/KeyEventGtk.cpp
> +++ b/WebCore/platform/gtk/KeyEventGtk.cpp
> @@ -136,6 +136,8 @@ static String keyIdentifierForGdkKeyCode(guint keyCode)
> // Standard says that DEL becomes U+007F.
> case GDK_Delete:
> return "U+007F";
> + case GDK_BackSpace:
> + return "U+0008";
> case GDK_ISO_Left_Tab:
> case GDK_3270_BackTab:
> case GDK_Tab:
> @@ -503,6 +505,8 @@ static String singleCharacterString(guint val)
> case GDK_KP_Enter:
> case GDK_Return:
> return String("\r");
> + case GDK_BackSpace:
> + return String("\x8");
> default:
> gunichar c = gdk_keyval_to_unicode(val);
> glong nwc;
> diff --git a/WebKit/gtk/ChangeLog b/WebKit/gtk/ChangeLog
> index ea3c0c2..863bc45 100644
> --- a/WebKit/gtk/ChangeLog
> +++ b/WebKit/gtk/ChangeLog
> @@ -1,3 +1,23 @@
> +2009-09-15 Martin Robinson <martin.james.robinson at gmail.com>
> +
> + Reviewed by NOBODY (OOPS!).
> +
> + [GTK] GtkIMContext filtering interferes with DOM key events
> + https://bugs.webkit.org/show_bug.cgi?id=28733
> +
> + Ensure that even when GTKSimpleIMContext filters non-IME keystrokes,
> + keyboard events are fired properly.
> +
> + * WebCoreSupport/EditorClientGtk.cpp:
> + (WebKit::imContextCommitted):
> + (WebKit::imContextPreeditChanged):
> + (WebKit::EditorClient::shouldBeginEditing):
> + (WebKit::EditorClient::shouldEndEditing):
> + (WebKit::interpretEditorCommandKeyEvent):
> + (WebKit::handleCaretBrowsingKeyboardEvent):
> + (WebKit::EditorClient::handleKeyboardEvent):
> + (WebKit::EditorClient::handleInputMethodKeydown):
> +
> 2009-09-14 Gustavo Noronha Silva <gustavo.noronha at collabora.co.uk>
>
> Reviewed by Xan Lopez and Jan Alonzo.
> diff --git a/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp b/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp
> index 71a7c1a..04f6d4d 100644
> --- a/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp
> +++ b/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp
> @@ -49,39 +49,22 @@ using namespace WebCore;
>
> namespace WebKit {
>
> +static gchar* pendingComposition = 0;
> +static gchar* pendingPreedit = 0;
> +
> static void imContextCommitted(GtkIMContext* context, const gchar* str, EditorClient* client)
> {
> - Frame* targetFrame = core(client->m_webView)->focusController()->focusedOrMainFrame();
> -
> - if (!targetFrame || !targetFrame->editor()->canEdit())
> - return;
> -
> - Editor* editor = targetFrame->editor();
> -
> - String commitString = String::fromUTF8(str);
> - editor->confirmComposition(commitString);
> + // This signal will fire during a keydown event. We want to the contents of the
s/We want to the/We want the/ ?
> + // field to change right before the keyup event, so we wait until then to actually
> + // commit this composition.
> + pendingComposition = g_strdup(str);
Since you seem assume pendingComposition must be always clear at this point I
guess it would be good to add an ASSERT(!pendingComposition).
> }
>
> static void imContextPreeditChanged(GtkIMContext* context, EditorClient* client)
> {
> - Frame* frame = core(client->m_webView)->focusController()->focusedOrMainFrame();
> - Editor* editor = frame->editor();
> -
> - gchar* preedit = NULL;
> - gint cursorPos = 0;
> // We ignore the provided PangoAttrList for now.
> - gtk_im_context_get_preedit_string(context, &preedit, NULL, &cursorPos);
> - String preeditString = String::fromUTF8(preedit);
> - g_free(preedit);
> -
> - // setComposition() will replace the user selection if passed an empty
> - // preedit. We don't want this to happen.
> - if (preeditString.isEmpty() && !editor->hasComposition())
> - return;
> -
> - Vector<CompositionUnderline> underlines;
> - underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
> - editor->setComposition(preeditString, underlines, cursorPos, 0);
> + gint cursorPos = 0;
> + gtk_im_context_get_preedit_string(context, &pendingPreedit, NULL, &cursorPos);
cursorPos can be just NULL here, the functions seem to check the value before
assigning.
And another ASSERT for pendingPreedit? :)
> }
>
> void EditorClient::setInputMethodState(bool active)
> @@ -136,12 +119,22 @@ int EditorClient::spellCheckerDocumentTag()
>
> bool EditorClient::shouldBeginEditing(WebCore::Range*)
> {
> + g_free(pendingComposition);
> + pendingComposition = 0;
> + g_free(pendingPreedit);
> + pendingPreedit = 0;
> +
As I said in a previous comment, I think it's worth to put this in a
'clearPendingVariables()' function or something, since it's repeated three/four
times.
> notImplemented();
> return true;
> }
>
> bool EditorClient::shouldEndEditing(WebCore::Range*)
> {
> + g_free(pendingComposition);
> + pendingComposition = 0;
> + g_free(pendingPreedit);
> + pendingPreedit = 0;
> +
> notImplemented();
> return true;
> }
> @@ -421,7 +414,7 @@ static const KeyPressEntry keyPressEntries[] = {
> { '\r', AltKey | ShiftKey, "InsertNewline" },
> };
>
> -static const char* interpretKeyEvent(const KeyboardEvent* evt)
> +static const char* interpretEditorCommandKeyEvent(const KeyboardEvent* evt)
> {
> ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
>
> @@ -456,74 +449,120 @@ static const char* interpretKeyEvent(const KeyboardEvent* evt)
> return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
> }
>
> -static bool handleEditingKeyboardEvent(KeyboardEvent* evt)
> +static bool handleCaretBrowsingKeyboardEvent(Frame* frame, const PlatformKeyboardEvent* keyEvent)
> +{
> + switch (keyEvent->windowsVirtualKeyCode()) {
> + case VK_LEFT:
> + frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> + SelectionController::LEFT,
> + keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
> + true);
> + return true;
> + case VK_RIGHT:
> + frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> + SelectionController::RIGHT,
> + keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
> + true);
> + return true;
> + case VK_UP:
> + frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> + SelectionController::BACKWARD,
> + keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
> + true);
> + return true;
> + case VK_DOWN:
> + frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> + SelectionController::FORWARD,
> + keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
> + true);
> + return true;
> + default:
> + return false; // Not a caret browswing keystroke, so continue processing.
> + }
> +}
> +
> +void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
> {
> - Node* node = evt->target()->toNode();
> + Node* node = event->target()->toNode();
> ASSERT(node);
> Frame* frame = node->document()->frame();
> ASSERT(frame);
>
> - const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
> - if (!keyEvent)
> - return false;
> + const PlatformKeyboardEvent* platformEvent = event->keyEvent();
> + if (!platformEvent)
> + return;
>
> bool caretBrowsing = frame->settings()->caretBrowsingEnabled();
> - if (caretBrowsing) {
> - switch (keyEvent->windowsVirtualKeyCode()) {
> - case VK_LEFT:
> - frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> - SelectionController::LEFT,
> - keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
> - true);
> - return true;
> - case VK_RIGHT:
> - frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> - SelectionController::RIGHT,
> - keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
> - true);
> - return true;
> - case VK_UP:
> - frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> - SelectionController::BACKWARD,
> - keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
> - true);
> - return true;
> - case VK_DOWN:
> - frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
> - SelectionController::FORWARD,
> - keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
> - true);
> - return true;
> - }
> + if (caretBrowsing && handleCaretBrowsingKeyboardEvent(frame, platformEvent)) {
> + // This was a caret browsing key event, so prevent it from bubbling up to the DOM.
> + event->setDefaultHandled();
> + return;
> }
>
> - Editor::Command command = frame->editor()->command(interpretKeyEvent(evt));
> + // Don't allow editor commands or text insertion for nodes that cannot edit.
> + if (!frame->editor()->canEdit())
> + return;
>
> - if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
> - // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
> - // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
> - // (e.g. Tab that inserts a Tab character, or Enter).
> - return !command.isTextInsertion() && command.execute(evt);
> + const gchar* editorCommandString = interpretEditorCommandKeyEvent(event);
> + if (editorCommandString)
> + {
The brace is wrong.
> + Editor::Command command = frame->editor()->command(editorCommandString);
> +
> + // On editor commands from key down events, we only want to let the event bubble up to
> + // the DOM if it inserts text. If it doesn't insert text (e.g. Tab that changes focus)
> + // we just want WebKit to handle it immediately without a DOM event.
> + if (platformEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
> + if (!command.isTextInsertion() && command.execute(event))
> + event->setDefaultHandled();
> +
> + return;
> + } else if (command.execute(event)) {
> + event->setDefaultHandled();
> + return;
> + }
> }
>
> - if (command.execute(evt))
> - return true;
> + // This is just a normal text insertion, so wait to execute the insertion
> + // until a keyup event happens. This will ensure that the insertion will not
> + // be reflected in the contents of the field until the keyup DOM event.
> + if (event->type() != eventNames().keydownEvent) {
> +
> + if (pendingComposition) {
> + String compositionString = String::fromUTF8(pendingComposition);
> + frame->editor()->confirmComposition(compositionString);
> +
> + g_free(pendingComposition);
> + pendingComposition = 0;
> + g_free(pendingPreedit);
> + pendingPreedit = 0;
> +
> + } else if (pendingPreedit) {
> + String preeditString = String::fromUTF8(pendingPreedit);
> +
> + // Don't use an empty preedit as it will destroy the current
> + // selection, even if the composition is cancelled or fails later on.
> + if (!preeditString.isEmpty()) {
> + Vector<CompositionUnderline> underlines;
> + underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
> + frame->editor()->setComposition(preeditString, underlines, 0, 0);
> + }
>
> - // Don't insert null or control characters as they can result in unexpected behaviour
> - if (evt->charCode() < ' ')
> - return false;
> + g_free(pendingPreedit);
> + pendingPreedit = 0;
>
> - // Don't insert anything if a modifier is pressed
> - if (keyEvent->ctrlKey() || keyEvent->altKey())
> - return false;
> + } else {
> + // Don't insert null or control characters as they can result in unexpected behaviour
> + if (event->charCode() < ' ')
> + return;
>
> - return frame->editor()->insertText(evt->keyEvent()->text(), evt);
> -}
> + // Don't insert anything if a modifier is pressed
> + if (platformEvent->ctrlKey() || platformEvent->altKey())
> + return;
>
> -void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
> -{
> - if (handleEditingKeyboardEvent(event))
> - event->setDefaultHandled();
> + if (frame->editor()->insertText(platformEvent->text(), event))
> + event->setDefaultHandled();
> + }
> + }
> }
>
> void EditorClient::handleInputMethodKeydown(KeyboardEvent* event)
> @@ -533,9 +572,7 @@ void EditorClient::handleInputMethodKeydown(KeyboardEvent* event)
> return;
>
> WebKitWebViewPrivate* priv = m_webView->priv;
> - // TODO: Dispatch IE-compatible text input events for IM events.
> - if (gtk_im_context_filter_keypress(priv->imContext, event->keyEvent()->gdkEventKey()))
> - event->setDefaultHandled();
> + gtk_im_context_filter_keypress(priv->imContext, event->keyEvent()->gdkEventKey());
> }
>
> EditorClient::EditorClient(WebKitWebView* webView)
> --
> 1.6.0.4
>
Looks good to me, but marking r- to fix those small details.
--
Configure bugmail: https://bugs.webkit.org/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.
More information about the webkit-unassigned
mailing list