Make all ScriptWrappable IsoHeap-ed
[WebKit-https.git] / Source / WebCore / dom / KeyboardEvent.cpp
1 /*
2  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
3  * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
4  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5  * Copyright (C) 2003-2018 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "KeyboardEvent.h"
25
26 #include "DOMWindow.h"
27 #include "Document.h"
28 #include "Editor.h"
29 #include "EventHandler.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "PlatformKeyboardEvent.h"
33 #include "WindowsKeyboardCodes.h"
34 #include <wtf/IsoMallocInlines.h>
35
36 namespace WebCore {
37
38 WTF_MAKE_ISO_ALLOCATED_IMPL(KeyboardEvent);
39
40 static inline const AtomString& eventTypeForKeyboardEventType(PlatformEvent::Type type)
41 {
42     switch (type) {
43         case PlatformEvent::KeyUp:
44             return eventNames().keyupEvent;
45         case PlatformEvent::RawKeyDown:
46             return eventNames().keydownEvent;
47         case PlatformEvent::Char:
48             return eventNames().keypressEvent;
49         case PlatformEvent::KeyDown:
50             // The caller should disambiguate the combined event into RawKeyDown or Char events.
51             break;
52         default:
53             break;
54     }
55     ASSERT_NOT_REACHED();
56     return eventNames().keydownEvent;
57 }
58
59 static inline int windowsVirtualKeyCodeWithoutLocation(int keycode)
60 {
61     switch (keycode) {
62     case VK_LCONTROL:
63     case VK_RCONTROL:
64         return VK_CONTROL;
65     case VK_LSHIFT:
66     case VK_RSHIFT:
67         return VK_SHIFT;
68     case VK_LMENU:
69     case VK_RMENU:
70         return VK_MENU;
71     default:
72         return keycode;
73     }
74 }
75
76 static inline KeyboardEvent::KeyLocationCode keyLocationCode(const PlatformKeyboardEvent& key)
77 {
78     if (key.isKeypad())
79         return KeyboardEvent::DOM_KEY_LOCATION_NUMPAD;
80
81     switch (key.windowsVirtualKeyCode()) {
82     case VK_LCONTROL:
83     case VK_LSHIFT:
84     case VK_LMENU:
85     case VK_LWIN:
86         return KeyboardEvent::DOM_KEY_LOCATION_LEFT;
87     case VK_RCONTROL:
88     case VK_RSHIFT:
89     case VK_RMENU:
90     case VK_RWIN:
91         return KeyboardEvent::DOM_KEY_LOCATION_RIGHT;
92     default:
93         return KeyboardEvent::DOM_KEY_LOCATION_STANDARD;
94     }
95 }
96
97 inline KeyboardEvent::KeyboardEvent() = default;
98
99 inline KeyboardEvent::KeyboardEvent(const PlatformKeyboardEvent& key, RefPtr<WindowProxy>&& view)
100     : UIEventWithKeyState(eventTypeForKeyboardEventType(key.type()), CanBubble::Yes, IsCancelable::Yes, IsComposed::Yes,
101         key.timestamp().approximateMonotonicTime(), view.copyRef(), 0, key.modifiers(), IsTrusted::Yes)
102     , m_underlyingPlatformEvent(makeUnique<PlatformKeyboardEvent>(key))
103 #if ENABLE(KEYBOARD_KEY_ATTRIBUTE)
104     , m_key(key.key())
105 #endif
106 #if ENABLE(KEYBOARD_CODE_ATTRIBUTE)
107     , m_code(key.code())
108 #endif
109     , m_keyIdentifier(key.keyIdentifier())
110     , m_location(keyLocationCode(key))
111     , m_repeat(key.isAutoRepeat())
112     , m_isComposing(view && is<DOMWindow>(view->window()) && downcast<DOMWindow>(*view->window()).frame() && downcast<DOMWindow>(*view->window()).frame()->editor().hasComposition())
113 #if USE(APPKIT) || USE(UIKIT_KEYBOARD_ADDITIONS)
114     , m_handledByInputMethod(key.handledByInputMethod())
115 #endif
116 #if USE(APPKIT)
117     , m_keypressCommands(key.commands())
118 #endif
119 {
120 }
121
122 inline KeyboardEvent::KeyboardEvent(const AtomString& eventType, const Init& initializer)
123     : UIEventWithKeyState(eventType, initializer)
124 #if ENABLE(KEYBOARD_KEY_ATTRIBUTE)
125     , m_key(initializer.key)
126 #endif
127 #if ENABLE(KEYBOARD_CODE_ATTRIBUTE)
128     , m_code(initializer.code)
129 #endif
130     , m_keyIdentifier(initializer.keyIdentifier)
131     , m_location(initializer.keyLocation ? *initializer.keyLocation : initializer.location)
132     , m_repeat(initializer.repeat)
133     , m_isComposing(initializer.isComposing)
134     , m_charCode(initializer.charCode)
135     , m_keyCode(initializer.keyCode)
136     , m_which(initializer.which)
137 {
138 }
139
140 KeyboardEvent::~KeyboardEvent() = default;
141
142 Ref<KeyboardEvent> KeyboardEvent::create(const PlatformKeyboardEvent& platformEvent, RefPtr<WindowProxy>&& view)
143 {
144     return adoptRef(*new KeyboardEvent(platformEvent, WTFMove(view)));
145 }
146
147 Ref<KeyboardEvent> KeyboardEvent::createForBindings()
148 {
149     return adoptRef(*new KeyboardEvent);
150 }
151
152 Ref<KeyboardEvent> KeyboardEvent::create(const AtomString& type, const Init& initializer)
153 {
154     return adoptRef(*new KeyboardEvent(type, initializer));
155 }
156
157 void KeyboardEvent::initKeyboardEvent(const AtomString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&& view,
158     const String& keyIdentifier, unsigned location, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey)
159 {
160     if (isBeingDispatched())
161         return;
162
163     initUIEvent(type, canBubble, cancelable, WTFMove(view), 0);
164
165     m_keyIdentifier = keyIdentifier;
166     m_location = location;
167
168     setModifierKeys(ctrlKey, altKey, shiftKey, metaKey, altGraphKey);
169
170     m_charCode = WTF::nullopt;
171     m_isComposing = false;
172     m_keyCode = WTF::nullopt;
173     m_repeat = false;
174     m_underlyingPlatformEvent = nullptr;
175     m_which = WTF::nullopt;
176
177 #if ENABLE(KEYBOARD_CODE_ATTRIBUTE)
178     m_code = { };
179 #endif
180
181 #if ENABLE(KEYBOARD_KEY_ATTRIBUTE)
182     m_key = { };
183 #endif
184
185 #if PLATFORM(COCOA)
186     m_handledByInputMethod = false;
187     m_keypressCommands = { };
188 #endif
189 }
190
191 int KeyboardEvent::keyCode() const
192 {
193     if (m_keyCode)
194         return m_keyCode.value();
195
196     // IE: virtual key code for keyup/keydown, character code for keypress
197     // Firefox: virtual key code for keyup/keydown, zero for keypress
198     // We match IE.
199     if (!m_underlyingPlatformEvent)
200         return 0;
201     if (type() == eventNames().keydownEvent || type() == eventNames().keyupEvent)
202         return windowsVirtualKeyCodeWithoutLocation(m_underlyingPlatformEvent->windowsVirtualKeyCode());
203
204     return charCode();
205 }
206
207 int KeyboardEvent::charCode() const
208 {
209     if (m_charCode)
210         return m_charCode.value();
211
212     // IE: not supported
213     // Firefox: 0 for keydown/keyup events, character code for keypress
214     // We match Firefox, unless in backward compatibility mode, where we always return the character code.
215     bool backwardCompatibilityMode = false;
216     auto* window = view() ? view()->window() : nullptr;
217     if (is<DOMWindow>(window) && downcast<DOMWindow>(*window).frame())
218         backwardCompatibilityMode = downcast<DOMWindow>(*window).frame()->eventHandler().needsKeyboardEventDisambiguationQuirks();
219
220     if (!m_underlyingPlatformEvent || (type() != eventNames().keypressEvent && !backwardCompatibilityMode))
221         return 0;
222     return m_underlyingPlatformEvent->text().characterStartingAt(0);
223 }
224
225 EventInterface KeyboardEvent::eventInterface() const
226 {
227     return KeyboardEventInterfaceType;
228 }
229
230 bool KeyboardEvent::isKeyboardEvent() const
231 {
232     return true;
233 }
234
235 int KeyboardEvent::which() const
236 {
237     // Netscape's "which" returns a virtual key code for keydown and keyup, and a character code for keypress.
238     // That's exactly what IE's "keyCode" returns. So they are the same for keyboard events.
239     if (m_which)
240         return m_which.value();
241     return keyCode();
242 }
243
244 } // namespace WebCore