Changeset 48964 in webkit


Ignore:
Timestamp:
Oct 1, 2009 2:02:30 AM (15 years ago)
Author:
eric@webkit.org
Message:

2009-10-01 Martin Robinson <martin.james.robinson@gmail.com>

Reviewed by Xan Lopez.

[GTK] GtkIMContext filtering interferes with DOM key events
https://bugs.webkit.org/show_bug.cgi?id=28733

Add new key event test ensuring that IME keypresses are handled.

  • GNUmakefile.am:

2009-10-01 Martin Robinson <martin.james.robinson@gmail.com>

Reviewed by Xan Lopez.

[GTK] GtkIMContext filtering interferes with DOM key events
https://bugs.webkit.org/show_bug.cgi?id=28733

Re-enable skipped tests which were previously failing.

  • platform/gtk/Skipped:

2009-10-01 Martin Robinson <martin.james.robinson@gmail.com>

Reviewed by Xan Lopez.

[GTK] GtkIMContext filtering interferes with DOM key events
https://bugs.webkit.org/show_bug.cgi?id=28733

Ensure that keyboard events filtered by the GtkIMContext still create
the proper DOM events.

No tests added. Instead previously skipped tests have been enabled.

  • platform/gtk/KeyEventGtk.cpp: (WebCore::keyIdentifierForGdkKeyCode): (WebCore::singleCharacterString):

2009-10-01 Martin Robinson <martin.james.robinson@gmail.com>

Reviewed by Xan Lopez.

[GTK] GtkIMContext filtering interferes with DOM key events
https://bugs.webkit.org/show_bug.cgi?id=28733

Ensure that keyboard events filtered by the GtkIMContext still create
the proper DOM events.

  • WebCoreSupport/EditorClientGtk.cpp: (WebKit::clearPendingIMData): (WebKit::imContextCommitted): (WebKit::imContextPreeditChanged): (WebKit::EditorClient::shouldBeginEditing): (WebKit::EditorClient::shouldEndEditing): (WebKit::interpretEditorCommandKeyEvent): (WebKit::handleCaretBrowsingKeyboardEvent): (WebKit::EditorClient::handleKeyboardEvent): (WebKit::EditorClient::handleInputMethodKeydown):
  • tests/testkeyevents.c: Added. (test_info_new): (test_info_destroy): (key_event_fixture_setup): (key_event_fixture_teardown): (key_press_event_cb): (key_release_event_cb): (load_status_cb): (map_event_cb): (test_keypress): (main):
Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r48963 r48964  
     12009-10-01  Martin Robinson  <martin.james.robinson@gmail.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [GTK] GtkIMContext filtering interferes with DOM key events
     6        https://bugs.webkit.org/show_bug.cgi?id=28733
     7
     8        Add new key event test ensuring that IME keypresses are handled.
     9
     10        * GNUmakefile.am:
     11
    1122009-10-01  Philippe Normand  <pnormand@igalia.com>
    213
  • trunk/GNUmakefile.am

    r48673 r48964  
    582582        Programs/unittests/testwebsettings \
    583583        Programs/unittests/testwebresource \
    584         Programs/unittests/testwebdatasource
     584        Programs/unittests/testwebdatasource \
     585        Programs/unittests/testkeyevents
    585586
    586587# Add additional tests here
     
    651652Programs_unittests_testhittestresult_CFLAGS = $(webkit_tests_cflags)
    652653Programs_unittests_testhittestresult_LDADD = $(webkit_tests_ldadd)
     654
     655Programs_unittests_testkeyevents_SOURCES = WebKit/gtk/tests/testkeyevents.c
     656Programs_unittests_testkeyevents_CFLAGS = $(webkit_tests_cflags)
     657Programs_unittests_testkeyevents_LDADD = $(webkit_tests_ldadd)
     658Programs_unittests_testkeyevents_LDFLAGS = $(webkit_tests_ldflags)
    653659
    654660# Autogenerated sources
  • trunk/LayoutTests/ChangeLog

    r48963 r48964  
     12009-10-01  Martin Robinson  <martin.james.robinson@gmail.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [GTK] GtkIMContext filtering interferes with DOM key events
     6        https://bugs.webkit.org/show_bug.cgi?id=28733
     7
     8        Re-enable skipped tests which were previously failing.
     9
     10        * platform/gtk/Skipped:
     11
    1122009-10-01  Philippe Normand  <pnormand@igalia.com>
    213
  • trunk/LayoutTests/platform/gtk/Skipped

    r48963 r48964  
    15951595fast/events/frame-tab-focus.html
    15961596fast/events/js-keyboard-event-creation.html
    1597 fast/events/key-events-in-input-button.html
    1598 fast/events/key-events-in-input-text.html
    1599 fast/events/keydown-keypress-focus-change.html
    1600 fast/events/keydown-keypress-preventDefault.html
    1601 fast/events/keypress-focus-change.html
    16021597fast/events/keypress-insert-tab.html
    16031598fast/events/mouse-click-events.html
     
    16191614fast/events/right-click-focus.html
    16201615fast/events/scrollbar-double-click.html
    1621 fast/events/special-key-events-in-input-text.html
    16221616fast/events/stop-load-in-unload-handler-using-document-write.html
    16231617fast/events/stop-load-in-unload-handler-using-window-stop.html
     
    55545548fast/events/drag-to-navigate.html
    55555549fast/events/prevent-drag-to-navigate.html
    5556 fast/events/keydown-function-keys.html
    55575550fast/forms/slider-delete-while-dragging-thumb.html
    55585551fast/events/tab-focus-anchor.html
  • trunk/WebCore/ChangeLog

    r48963 r48964  
     12009-10-01  Martin Robinson  <martin.james.robinson@gmail.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [GTK] GtkIMContext filtering interferes with DOM key events
     6        https://bugs.webkit.org/show_bug.cgi?id=28733
     7
     8        Ensure that keyboard events filtered by the GtkIMContext still create
     9        the proper DOM events.
     10
     11        No tests added. Instead previously skipped tests have been enabled.
     12
     13        * platform/gtk/KeyEventGtk.cpp:
     14        (WebCore::keyIdentifierForGdkKeyCode):
     15        (WebCore::singleCharacterString):
     16
    1172009-10-01  Philippe Normand  <pnormand@igalia.com>
    218
  • trunk/WebCore/platform/gtk/KeyEventGtk.cpp

    r48714 r48964  
    137137        case GDK_Delete:
    138138            return "U+007F";
     139        case GDK_BackSpace:
     140            return "U+0008";
    139141        case GDK_ISO_Left_Tab:
    140142        case GDK_3270_BackTab:
     
    504506        case GDK_Return:
    505507            return String("\r");
     508        case GDK_BackSpace:
     509            return String("\x8");
    506510        default:
    507511            gunichar c = gdk_keyval_to_unicode(val);
  • trunk/WebKit/gtk/ChangeLog

    r48877 r48964  
     12009-10-01  Martin Robinson  <martin.james.robinson@gmail.com>
     2
     3        Reviewed by Xan Lopez.
     4
     5        [GTK] GtkIMContext filtering interferes with DOM key events
     6        https://bugs.webkit.org/show_bug.cgi?id=28733
     7
     8        Ensure that keyboard events filtered by the GtkIMContext still create
     9        the proper DOM events.
     10
     11        * WebCoreSupport/EditorClientGtk.cpp:
     12        (WebKit::clearPendingIMData):
     13        (WebKit::imContextCommitted):
     14        (WebKit::imContextPreeditChanged):
     15        (WebKit::EditorClient::shouldBeginEditing):
     16        (WebKit::EditorClient::shouldEndEditing):
     17        (WebKit::interpretEditorCommandKeyEvent):
     18        (WebKit::handleCaretBrowsingKeyboardEvent):
     19        (WebKit::EditorClient::handleKeyboardEvent):
     20        (WebKit::EditorClient::handleInputMethodKeydown):
     21        * tests/testkeyevents.c: Added.
     22        (test_info_new):
     23        (test_info_destroy):
     24        (key_event_fixture_setup):
     25        (key_event_fixture_teardown):
     26        (key_press_event_cb):
     27        (key_release_event_cb):
     28        (load_status_cb):
     29        (map_event_cb):
     30        (test_keypress):
     31        (main):
     32
    1332009-09-29  Xan Lopez  <xlopez@igalia.com>
    234
  • trunk/WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp

    r48714 r48964  
    5050namespace WebKit {
    5151
     52static gchar* pendingComposition = 0;
     53static gchar* pendingPreedit = 0;
     54
     55static void clearPendingIMData()
     56{
     57    g_free(pendingComposition);
     58    pendingComposition = 0;
     59    g_free(pendingPreedit);
     60    pendingPreedit = 0;
     61}
    5262static void imContextCommitted(GtkIMContext* context, const gchar* str, EditorClient* client)
    5363{
    54     Frame* targetFrame = core(client->m_webView)->focusController()->focusedOrMainFrame();
    55 
    56     if (!targetFrame || !targetFrame->editor()->canEdit())
    57         return;
    58 
    59     Editor* editor = targetFrame->editor();
    60 
    61     String commitString = String::fromUTF8(str);
    62     editor->confirmComposition(commitString);
     64    ASSERT(!pendingComposition);
     65
     66    // This signal will fire during a keydown event. We want the contents of the
     67    // field to change right before the keyup event, so we wait until then to actually
     68    // commit this composition.
     69    pendingComposition = g_strdup(str);
    6370}
    6471
    6572static void imContextPreeditChanged(GtkIMContext* context, EditorClient* client)
    6673{
    67     Frame* frame = core(client->m_webView)->focusController()->focusedOrMainFrame();
    68     Editor* editor = frame->editor();
    69 
    70     gchar* preedit = NULL;
    71     gint cursorPos = 0;
     74    ASSERT(!pendingPreedit);
     75
    7276    // We ignore the provided PangoAttrList for now.
    73     gtk_im_context_get_preedit_string(context, &preedit, NULL, &cursorPos);
    74     String preeditString = String::fromUTF8(preedit);
    75     g_free(preedit);
    76 
    77     // setComposition() will replace the user selection if passed an empty
    78     // preedit. We don't want this to happen.
    79     if (preeditString.isEmpty() && !editor->hasComposition())
    80         return;
    81 
    82     Vector<CompositionUnderline> underlines;
    83     underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
    84     editor->setComposition(preeditString, underlines, cursorPos, 0);
     77    gtk_im_context_get_preedit_string(context, &pendingPreedit, NULL, NULL);
    8578}
    8679
     
    137130bool EditorClient::shouldBeginEditing(WebCore::Range*)
    138131{
     132    clearPendingIMData();
     133
    139134    notImplemented();
    140135    return true;
     
    143138bool EditorClient::shouldEndEditing(WebCore::Range*)
    144139{
     140    clearPendingIMData();
     141
    145142    notImplemented();
    146143    return true;
     
    422419};
    423420
    424 static const char* interpretKeyEvent(const KeyboardEvent* evt)
     421static const char* interpretEditorCommandKeyEvent(const KeyboardEvent* evt)
    425422{
    426423    ASSERT(evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent);
     
    457454}
    458455
    459 static bool handleEditingKeyboardEvent(KeyboardEvent* evt)
    460 {
    461     Node* node = evt->target()->toNode();
     456static bool handleCaretBrowsingKeyboardEvent(Frame* frame, const PlatformKeyboardEvent* keyEvent)
     457{
     458    switch (keyEvent->windowsVirtualKeyCode()) {
     459        case VK_LEFT:
     460            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
     461                    SelectionController::LEFT,
     462                    keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
     463                    true);
     464            return true;
     465        case VK_RIGHT:
     466            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
     467                    SelectionController::RIGHT,
     468                    keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
     469                    true);
     470            return true;
     471        case VK_UP:
     472            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
     473                    SelectionController::BACKWARD,
     474                    keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
     475                    true);
     476            return true;
     477        case VK_DOWN:
     478            frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
     479                    SelectionController::FORWARD,
     480                    keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
     481                    true);
     482            return true;
     483        default:
     484            return false; // Not a caret browswing keystroke, so continue processing.
     485    }
     486}
     487
     488void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
     489{
     490    Node* node = event->target()->toNode();
    462491    ASSERT(node);
    463492    Frame* frame = node->document()->frame();
    464493    ASSERT(frame);
    465494
    466     const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
    467     if (!keyEvent)
    468         return false;
     495    const PlatformKeyboardEvent* platformEvent = event->keyEvent();
     496    if (!platformEvent)
     497        return;
    469498
    470499    bool caretBrowsing = frame->settings()->caretBrowsingEnabled();
    471     if (caretBrowsing) {
    472         switch (keyEvent->windowsVirtualKeyCode()) {
    473             case VK_LEFT:
    474                 frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
    475                         SelectionController::LEFT,
    476                         keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
    477                         true);
    478                 return true;
    479             case VK_RIGHT:
    480                 frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
    481                         SelectionController::RIGHT,
    482                         keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
    483                         true);
    484                 return true;
    485             case VK_UP:
    486                 frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
    487                         SelectionController::BACKWARD,
    488                         keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
    489                         true);
    490                 return true;
    491             case VK_DOWN:
    492                 frame->selection()->modify(keyEvent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
    493                         SelectionController::FORWARD,
    494                         keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
    495                         true);
    496                 return true;
     500    if (caretBrowsing && handleCaretBrowsingKeyboardEvent(frame, platformEvent)) {
     501        // This was a caret browsing key event, so prevent it from bubbling up to the DOM.
     502        event->setDefaultHandled();
     503        return;
     504    }
     505
     506    // Don't allow editor commands or text insertion for nodes that cannot edit.
     507    if (!frame->editor()->canEdit())
     508        return;
     509
     510    const gchar* editorCommandString = interpretEditorCommandKeyEvent(event);
     511    if (editorCommandString) {
     512        Editor::Command command = frame->editor()->command(editorCommandString);
     513
     514        // On editor commands from key down events, we only want to let the event bubble up to
     515        // the DOM if it inserts text. If it doesn't insert text (e.g. Tab that changes focus)
     516        // we just want WebKit to handle it immediately without a DOM event.
     517        if (platformEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
     518            if (!command.isTextInsertion() && command.execute(event))
     519                event->setDefaultHandled();
     520
     521            return;
     522        } else if (command.execute(event)) {
     523            event->setDefaultHandled();
     524            return;
    497525        }
    498526    }
    499527
    500     Editor::Command command = frame->editor()->command(interpretKeyEvent(evt));
    501 
    502     if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
    503         // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
    504         // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
    505         // (e.g. Tab that inserts a Tab character, or Enter).
    506         return !command.isTextInsertion() && command.execute(evt);
    507     }
    508 
    509     if (command.execute(evt))
    510         return true;
    511 
    512     // Don't insert null or control characters as they can result in unexpected behaviour
    513     if (evt->charCode() < ' ')
    514         return false;
    515 
    516     // Don't insert anything if a modifier is pressed
    517     if (keyEvent->ctrlKey() || keyEvent->altKey())
    518         return false;
    519 
    520     return frame->editor()->insertText(evt->keyEvent()->text(), evt);
    521 }
    522 
    523 void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
    524 {
    525     if (handleEditingKeyboardEvent(event))
    526         event->setDefaultHandled();
     528    // This is just a normal text insertion, so wait to execute the insertion
     529    // until a keypress event happens. This will ensure that the insertion will not
     530    // be reflected in the contents of the field until the keyup DOM event.
     531    if (event->type() == eventNames().keypressEvent) {
     532
     533        if (pendingComposition) {
     534            String compositionString = String::fromUTF8(pendingComposition);
     535            frame->editor()->confirmComposition(compositionString);
     536
     537            clearPendingIMData();
     538            event->setDefaultHandled();
     539
     540        } else if (pendingPreedit) {
     541            String preeditString = String::fromUTF8(pendingPreedit);
     542
     543            // Don't use an empty preedit as it will destroy the current
     544            // selection, even if the composition is cancelled or fails later on.
     545            if (!preeditString.isEmpty()) {
     546                Vector<CompositionUnderline> underlines;
     547                underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
     548                frame->editor()->setComposition(preeditString, underlines, 0, 0);
     549            }
     550
     551            clearPendingIMData();
     552            event->setDefaultHandled();
     553
     554        } else {
     555            // Don't insert null or control characters as they can result in unexpected behaviour
     556            if (event->charCode() < ' ')
     557                return;
     558
     559            // Don't insert anything if a modifier is pressed
     560            if (platformEvent->ctrlKey() || platformEvent->altKey())
     561                return;
     562
     563            if (frame->editor()->insertText(platformEvent->text(), event))
     564                event->setDefaultHandled();
     565        }
     566    }
    527567}
    528568
     
    533573        return;
    534574
     575    // TODO: We need to decide which filtered keystrokes should be treated as IM
     576    // events and which should not.
    535577    WebKitWebViewPrivate* priv = m_webView->priv;
    536     // TODO: Dispatch IE-compatible text input events for IM events.
    537     if (gtk_im_context_filter_keypress(priv->imContext, event->keyEvent()->gdkEventKey()))
    538         event->setDefaultHandled();
     578    gtk_im_context_filter_keypress(priv->imContext, event->keyEvent()->gdkEventKey());
    539579}
    540580
Note: See TracChangeset for help on using the changeset viewer.