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 31using namespace WebCore; 32 33namespace WebKit { 34 35void 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 45bool 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 64void 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 124void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*) 125{ 126 notImplemented(); 127} 128 129} 130