2 * Copyright (C) 2006, 2007 Apple, Inc. All rights reserved.
3 * Copyright (C) 2012 Google, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "core/editing/EditingBehavior.h"
30 #include "core/events/KeyboardEvent.h"
31 #include "platform/KeyboardCodes.h"
32 #include "platform/PlatformKeyboardEvent.h"
37 // The below code was adapted from the WebKit file webview.cpp
40 static const unsigned CtrlKey
= 1 << 0;
41 static const unsigned AltKey
= 1 << 1;
42 static const unsigned ShiftKey
= 1 << 2;
43 static const unsigned MetaKey
= 1 << 3;
45 // Aliases for the generic key defintions to make kbd shortcuts definitions more
47 static const unsigned OptionKey
= AltKey
;
49 // Do not use this constant for anything but cursor movement commands. Keys
50 // with cmd set have their |isSystemKey| bit set, so chances are the shortcut
51 // will not be executed. Another, less important, reason is that shortcuts
52 // defined in the layoutObject do not blink the menu item that they triggered. See
53 // http://crbug.com/25856 and the bugs linked from there for details.
54 static const unsigned CommandKey
= MetaKey
;
57 // Keys with special meaning. These will be delegated to the editor using
58 // the execCommand() method
65 struct KeyPressEntry
{
71 // Key bindings with command key on Mac and alt key on other platforms are
72 // marked as system key events and will be ignored (with the exception
73 // of Command-B and Command-I) so they shouldn't be added here.
74 static const KeyDownEntry keyDownEntries
[] = {
75 { VKEY_LEFT
, 0, "MoveLeft" },
76 { VKEY_LEFT
, ShiftKey
, "MoveLeftAndModifySelection" },
78 { VKEY_LEFT
, OptionKey
, "MoveWordLeft" },
79 { VKEY_LEFT
, OptionKey
| ShiftKey
,
80 "MoveWordLeftAndModifySelection" },
82 { VKEY_LEFT
, CtrlKey
, "MoveWordLeft" },
83 { VKEY_LEFT
, CtrlKey
| ShiftKey
,
84 "MoveWordLeftAndModifySelection" },
86 { VKEY_RIGHT
, 0, "MoveRight" },
87 { VKEY_RIGHT
, ShiftKey
, "MoveRightAndModifySelection" },
89 { VKEY_RIGHT
, OptionKey
, "MoveWordRight" },
90 { VKEY_RIGHT
, OptionKey
| ShiftKey
, "MoveWordRightAndModifySelection" },
92 { VKEY_RIGHT
, CtrlKey
, "MoveWordRight" },
93 { VKEY_RIGHT
, CtrlKey
| ShiftKey
, "MoveWordRightAndModifySelection" },
95 { VKEY_UP
, 0, "MoveUp" },
96 { VKEY_UP
, ShiftKey
, "MoveUpAndModifySelection" },
97 { VKEY_PRIOR
, ShiftKey
, "MovePageUpAndModifySelection" },
98 { VKEY_DOWN
, 0, "MoveDown" },
99 { VKEY_DOWN
, ShiftKey
, "MoveDownAndModifySelection" },
100 { VKEY_NEXT
, ShiftKey
, "MovePageDownAndModifySelection" },
102 { VKEY_UP
, CtrlKey
, "MoveParagraphBackward" },
103 { VKEY_UP
, CtrlKey
| ShiftKey
, "MoveParagraphBackwardAndModifySelection" },
104 { VKEY_DOWN
, CtrlKey
, "MoveParagraphForward" },
105 { VKEY_DOWN
, CtrlKey
| ShiftKey
, "MoveParagraphForwardAndModifySelection" },
106 { VKEY_PRIOR
, 0, "MovePageUp" },
107 { VKEY_NEXT
, 0, "MovePageDown" },
109 { VKEY_HOME
, 0, "MoveToBeginningOfLine" },
110 { VKEY_HOME
, ShiftKey
,
111 "MoveToBeginningOfLineAndModifySelection" },
113 { VKEY_PRIOR
, OptionKey
, "MovePageUp" },
114 { VKEY_NEXT
, OptionKey
, "MovePageDown" },
117 { VKEY_HOME
, CtrlKey
, "MoveToBeginningOfDocument" },
118 { VKEY_HOME
, CtrlKey
| ShiftKey
,
119 "MoveToBeginningOfDocumentAndModifySelection" },
121 { VKEY_END
, 0, "MoveToEndOfLine" },
122 { VKEY_END
, ShiftKey
, "MoveToEndOfLineAndModifySelection" },
124 { VKEY_END
, CtrlKey
, "MoveToEndOfDocument" },
125 { VKEY_END
, CtrlKey
| ShiftKey
,
126 "MoveToEndOfDocumentAndModifySelection" },
128 { VKEY_BACK
, 0, "DeleteBackward" },
129 { VKEY_BACK
, ShiftKey
, "DeleteBackward" },
130 { VKEY_DELETE
, 0, "DeleteForward" },
132 { VKEY_BACK
, OptionKey
, "DeleteWordBackward" },
133 { VKEY_DELETE
, OptionKey
, "DeleteWordForward" },
135 { VKEY_BACK
, CtrlKey
, "DeleteWordBackward" },
136 { VKEY_DELETE
, CtrlKey
, "DeleteWordForward" },
139 { 'B', CommandKey
, "ToggleBold" },
140 { 'I', CommandKey
, "ToggleItalic" },
142 { 'B', CtrlKey
, "ToggleBold" },
143 { 'I', CtrlKey
, "ToggleItalic" },
145 { 'U', CtrlKey
, "ToggleUnderline" },
146 { VKEY_ESCAPE
, 0, "Cancel" },
147 { VKEY_OEM_PERIOD
, CtrlKey
, "Cancel" },
148 { VKEY_TAB
, 0, "InsertTab" },
149 { VKEY_TAB
, ShiftKey
, "InsertBacktab" },
150 { VKEY_RETURN
, 0, "InsertNewline" },
151 { VKEY_RETURN
, CtrlKey
, "InsertNewline" },
152 { VKEY_RETURN
, AltKey
, "InsertNewline" },
153 { VKEY_RETURN
, AltKey
| ShiftKey
, "InsertNewline" },
154 { VKEY_RETURN
, ShiftKey
, "InsertLineBreak" },
155 { VKEY_INSERT
, CtrlKey
, "Copy" },
156 { VKEY_INSERT
, ShiftKey
, "Paste" },
157 { VKEY_DELETE
, ShiftKey
, "Cut" },
159 // On OS X, we pipe these back to the browser, so that it can do menu item
161 { 'C', CtrlKey
, "Copy" },
162 { 'V', CtrlKey
, "Paste" },
163 { 'V', CtrlKey
| ShiftKey
, "PasteAndMatchStyle" },
164 { 'X', CtrlKey
, "Cut" },
165 { 'A', CtrlKey
, "SelectAll" },
166 { 'Z', CtrlKey
, "Undo" },
167 { 'Z', CtrlKey
| ShiftKey
, "Redo" },
168 { 'Y', CtrlKey
, "Redo" },
170 { VKEY_INSERT
, 0, "OverWrite" },
173 static const KeyPressEntry keyPressEntries
[] = {
174 { '\t', 0, "InsertTab" },
175 { '\t', ShiftKey
, "InsertBacktab" },
176 { '\r', 0, "InsertNewline" },
177 { '\r', CtrlKey
, "InsertNewline" },
178 { '\r', ShiftKey
, "InsertLineBreak" },
179 { '\r', AltKey
, "InsertNewline" },
180 { '\r', AltKey
| ShiftKey
, "InsertNewline" },
183 const char* EditingBehavior::interpretKeyEvent(const KeyboardEvent
& event
) const
185 const PlatformKeyboardEvent
* keyEvent
= event
.keyEvent();
189 static HashMap
<int, const char*>* keyDownCommandsMap
= nullptr;
190 static HashMap
<int, const char*>* keyPressCommandsMap
= nullptr;
192 if (!keyDownCommandsMap
) {
193 keyDownCommandsMap
= new HashMap
<int, const char*>;
194 keyPressCommandsMap
= new HashMap
<int, const char*>;
196 for (unsigned i
= 0; i
< arraysize(keyDownEntries
); i
++) {
197 keyDownCommandsMap
->set(keyDownEntries
[i
].modifiers
<< 16 | keyDownEntries
[i
].virtualKey
, keyDownEntries
[i
].name
);
200 for (unsigned i
= 0; i
< arraysize(keyPressEntries
); i
++) {
201 keyPressCommandsMap
->set(keyPressEntries
[i
].modifiers
<< 16 | keyPressEntries
[i
].charCode
, keyPressEntries
[i
].name
);
205 unsigned modifiers
= 0;
206 if (keyEvent
->shiftKey())
207 modifiers
|= ShiftKey
;
208 if (keyEvent
->altKey())
210 if (keyEvent
->ctrlKey())
211 modifiers
|= CtrlKey
;
212 if (keyEvent
->metaKey())
213 modifiers
|= MetaKey
;
215 if (keyEvent
->type() == PlatformEvent::RawKeyDown
) {
216 int mapKey
= modifiers
<< 16 | event
.keyCode();
217 return mapKey
? keyDownCommandsMap
->get(mapKey
) : 0;
220 int mapKey
= modifiers
<< 16 | event
.charCode();
221 return mapKey
? keyPressCommandsMap
->get(mapKey
) : 0;
224 bool EditingBehavior::shouldInsertCharacter(const KeyboardEvent
& event
) const
226 if (event
.keyEvent()->text().length() != 1)
229 // On Gtk/Linux, it emits key events with ASCII text and ctrl on for ctrl-<x>.
230 // In Webkit, EditorClient::handleKeyboardEvent in
231 // WebKit/gtk/WebCoreSupport/EditorClientGtk.cpp drop such events.
232 // On Mac, it emits key events with ASCII text and meta on for Command-<x>.
233 // These key events should not emit text insert event.
234 // Alt key would be used to insert alternative character, so we should let
235 // through. Also note that Ctrl-Alt combination equals to AltGr key which is
236 // also used to insert alternative character.
237 // http://code.google.com/p/chromium/issues/detail?id=10846
238 // Windows sets both alt and meta are on when "Alt" key pressed.
239 // http://code.google.com/p/chromium/issues/detail?id=2215
240 // Also, we should not rely on an assumption that keyboards don't
241 // send ASCII characters when pressing a control key on Windows,
242 // which may be configured to do it so by user.
243 // See also http://en.wikipedia.org/wiki/Keyboard_Layout
244 // FIXME(ukai): investigate more detail for various keyboard layout.
245 UChar ch
= event
.keyEvent()->text()[0U];
247 // Don't insert null or control characters as they can result in
248 // unexpected behaviour
252 // Don't insert ASCII character if ctrl w/o alt or meta is on.
253 // On Mac, we should ignore events when meta is on (Command-<x>).
255 if (event
.keyEvent()->ctrlKey() && !event
.keyEvent()->altKey())
258 if (event
.keyEvent()->metaKey())