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
getEditorCommandsForKeyEvent(const KeyboardEvent * event,Vector<WTF::String> & pendingEditorCommands)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
executePendingEditorCommands(Frame * frame,Vector<WTF::String> pendingEditorCommands,bool allowTextInsertion)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
handleKeyboardEvent(KeyboardEvent * event)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
handleInputMethodKeydown(KeyboardEvent *)124 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
125 {
126 notImplemented();
127 }
128
129 }
130