Home | History | Annotate | Download | only in gtk
      1 /*
      2  *  Copyright (C) 2011 Igalia S.L.
      3  *
      4  *  This library is free software; you can redistribute it and/or
      5  *  modify it under the terms of the GNU Lesser General Public License
      6  *  as published by the Free Software Foundation; either version 2 of
      7  *  the License, or (at your option) any later version.
      8  *
      9  *  This library is distributed in the hope that it will be useful,
     10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  *  Lesser General Public License for more details.
     13  *
     14  *  You should have received a copy of the GNU Lesser General Public
     15  *  License along with this library; if not, write to the Free
     16  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  *  Boston, MA 02110-1301 USA
     18  */
     19 
     20 #include "config.h"
     21 #include "WebEditorClient.h"
     22 
     23 #include "Frame.h"
     24 #include "PlatformKeyboardEvent.h"
     25 #include "WebPage.h"
     26 #include "WebPageProxyMessages.h"
     27 #include "WebProcess.h"
     28 #include <WebCore/KeyboardEvent.h>
     29 #include <WebCore/NotImplemented.h>
     30 
     31 using namespace WebCore;
     32 
     33 namespace WebKit {
     34 
     35 void WebEditorClient::getEditorCommandsForKeyEvent(const KeyboardEvent* event, Vector<WTF::String>& pendingEditorCommands)
     36 {
     37     ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
     38 
     39     // First try to interpret the command in the UI and get the commands.
     40     WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::GetEditorCommandsForKeyEvent(),
     41                                                 Messages::WebPageProxy::GetEditorCommandsForKeyEvent::Reply(pendingEditorCommands),
     42                                                 m_page->pageID(), CoreIPC::Connection::NoTimeout);
     43 }
     44 
     45 bool WebEditorClient::executePendingEditorCommands(Frame* frame, Vector<WTF::String> pendingEditorCommands, bool allowTextInsertion)
     46 {
     47     Vector<Editor::Command> commands;
     48     for (size_t i = 0; i < pendingEditorCommands.size(); i++) {
     49         Editor::Command command = frame->editor()->command(pendingEditorCommands.at(i).utf8().data());
     50         if (command.isTextInsertion() && !allowTextInsertion)
     51             return false;
     52 
     53         commands.append(command);
     54     }
     55 
     56     for (size_t i = 0; i < commands.size(); i++) {
     57         if (!commands.at(i).execute())
     58             return false;
     59     }
     60 
     61     return true;
     62 }
     63 
     64 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
     65 {
     66     Node* node = event->target()->toNode();
     67     ASSERT(node);
     68     Frame* frame = node->document()->frame();
     69     ASSERT(frame);
     70 
     71     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
     72     if (!platformEvent)
     73         return;
     74 
     75     Vector<WTF::String> pendingEditorCommands;
     76     getEditorCommandsForKeyEvent(event, pendingEditorCommands);
     77     if (!pendingEditorCommands.isEmpty()) {
     78 
     79         // During RawKeyDown events if an editor command will insert text, defer
     80         // the insertion until the keypress event. We want keydown to bubble up
     81         // through the DOM first.
     82         if (platformEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
     83             if (executePendingEditorCommands(frame, pendingEditorCommands, false))
     84                 event->setDefaultHandled();
     85 
     86             return;
     87         }
     88 
     89         // Only allow text insertion commands if the current node is editable.
     90         if (executePendingEditorCommands(frame, pendingEditorCommands, frame->editor()->canEdit())) {
     91             event->setDefaultHandled();
     92             return;
     93         }
     94     }
     95 
     96     // Don't allow text insertion for nodes that cannot edit.
     97     if (!frame->editor()->canEdit())
     98         return;
     99 
    100     // This is just a normal text insertion, so wait to execute the insertion
    101     // until a keypress event happens. This will ensure that the insertion will not
    102     // be reflected in the contents of the field until the keyup DOM event.
    103     if (event->type() == eventNames().keypressEvent) {
    104 
    105         // FIXME: Add IM support
    106         // https://bugs.webkit.org/show_bug.cgi?id=55946
    107         frame->editor()->insertText(platformEvent->text(), event);
    108         event->setDefaultHandled();
    109 
    110     } else {
    111         // Don't insert null or control characters as they can result in unexpected behaviour
    112         if (event->charCode() < ' ')
    113             return;
    114 
    115         // Don't insert anything if a modifier is pressed
    116         if (platformEvent->ctrlKey() || platformEvent->altKey())
    117             return;
    118 
    119         if (frame->editor()->insertText(platformEvent->text(), event))
    120             event->setDefaultHandled();
    121     }
    122 }
    123 
    124 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
    125 {
    126     notImplemented();
    127 }
    128 
    129 }
    130