/* * Copyright (C) 2011 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #include "config.h" #include "WebEditorClient.h" #include "Frame.h" #include "PlatformKeyboardEvent.h" #include "WebPage.h" #include "WebPageProxyMessages.h" #include "WebProcess.h" #include #include using namespace WebCore; namespace WebKit { void WebEditorClient::getEditorCommandsForKeyEvent(const KeyboardEvent* event, Vector& pendingEditorCommands) { ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent); // First try to interpret the command in the UI and get the commands. WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::GetEditorCommandsForKeyEvent(), Messages::WebPageProxy::GetEditorCommandsForKeyEvent::Reply(pendingEditorCommands), m_page->pageID(), CoreIPC::Connection::NoTimeout); } bool WebEditorClient::executePendingEditorCommands(Frame* frame, Vector pendingEditorCommands, bool allowTextInsertion) { Vector commands; for (size_t i = 0; i < pendingEditorCommands.size(); i++) { Editor::Command command = frame->editor()->command(pendingEditorCommands.at(i).utf8().data()); if (command.isTextInsertion() && !allowTextInsertion) return false; commands.append(command); } for (size_t i = 0; i < commands.size(); i++) { if (!commands.at(i).execute()) return false; } return true; } void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event) { Node* node = event->target()->toNode(); ASSERT(node); Frame* frame = node->document()->frame(); ASSERT(frame); const PlatformKeyboardEvent* platformEvent = event->keyEvent(); if (!platformEvent) return; Vector pendingEditorCommands; getEditorCommandsForKeyEvent(event, pendingEditorCommands); if (!pendingEditorCommands.isEmpty()) { // During RawKeyDown events if an editor command will insert text, defer // the insertion until the keypress event. We want keydown to bubble up // through the DOM first. if (platformEvent->type() == PlatformKeyboardEvent::RawKeyDown) { if (executePendingEditorCommands(frame, pendingEditorCommands, false)) event->setDefaultHandled(); return; } // Only allow text insertion commands if the current node is editable. if (executePendingEditorCommands(frame, pendingEditorCommands, frame->editor()->canEdit())) { event->setDefaultHandled(); return; } } // Don't allow text insertion for nodes that cannot edit. if (!frame->editor()->canEdit()) return; // This is just a normal text insertion, so wait to execute the insertion // until a keypress 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().keypressEvent) { // FIXME: Add IM support // https://bugs.webkit.org/show_bug.cgi?id=55946 frame->editor()->insertText(platformEvent->text(), event); event->setDefaultHandled(); } else { // Don't insert null or control characters as they can result in unexpected behaviour if (event->charCode() < ' ') return; // Don't insert anything if a modifier is pressed if (platformEvent->ctrlKey() || platformEvent->altKey()) return; if (frame->editor()->insertText(platformEvent->text(), event)) event->setDefaultHandled(); } } void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*) { notImplemented(); } }