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 | |
35 | namespace WebCore { |
36 | |
37 | static inline const AtomicString& eventTypeForKeyboardEventType(PlatformEvent::Type type) |
38 | { |
39 | switch (type) { |
40 | case PlatformEvent::KeyUp: |
41 | return eventNames().keyupEvent; |
42 | case PlatformEvent::RawKeyDown: |
43 | return eventNames().keydownEvent; |
44 | case PlatformEvent::Char: |
45 | return eventNames().keypressEvent; |
46 | case PlatformEvent::KeyDown: |
47 | // The caller should disambiguate the combined event into RawKeyDown or Char events. |
48 | break; |
49 | default: |
50 | break; |
51 | } |
52 | ASSERT_NOT_REACHED(); |
53 | return eventNames().keydownEvent; |
54 | } |
55 | |
56 | static inline int windowsVirtualKeyCodeWithoutLocation(int keycode) |
57 | { |
58 | switch (keycode) { |
59 | case VK_LCONTROL: |
60 | case VK_RCONTROL: |
61 | return VK_CONTROL; |
62 | case VK_LSHIFT: |
63 | case VK_RSHIFT: |
64 | return VK_SHIFT; |
65 | case VK_LMENU: |
66 | case VK_RMENU: |
67 | return VK_MENU; |
68 | default: |
69 | return keycode; |
70 | } |
71 | } |
72 | |
73 | static inline KeyboardEvent::KeyLocationCode keyLocationCode(const PlatformKeyboardEvent& key) |
74 | { |
75 | if (key.isKeypad()) |
76 | return KeyboardEvent::DOM_KEY_LOCATION_NUMPAD; |
77 | |
78 | switch (key.windowsVirtualKeyCode()) { |
79 | case VK_LCONTROL: |
80 | case VK_LSHIFT: |
81 | case VK_LMENU: |
82 | case VK_LWIN: |
83 | return KeyboardEvent::DOM_KEY_LOCATION_LEFT; |
84 | case VK_RCONTROL: |
85 | case VK_RSHIFT: |
86 | case VK_RMENU: |
87 | case VK_RWIN: |
88 | return KeyboardEvent::DOM_KEY_LOCATION_RIGHT; |
89 | default: |
90 | return KeyboardEvent::DOM_KEY_LOCATION_STANDARD; |
91 | } |
92 | } |
93 | |
94 | inline KeyboardEvent::KeyboardEvent() = default; |
95 | |
96 | inline KeyboardEvent::KeyboardEvent(const PlatformKeyboardEvent& key, RefPtr<WindowProxy>&& view) |
97 | : UIEventWithKeyState(eventTypeForKeyboardEventType(key.type()), CanBubble::Yes, IsCancelable::Yes, IsComposed::Yes, |
98 | key.timestamp().approximateMonotonicTime(), view.copyRef(), 0, key.modifiers(), IsTrusted::Yes) |
99 | , m_underlyingPlatformEvent(std::make_unique<PlatformKeyboardEvent>(key)) |
100 | #if ENABLE(KEYBOARD_KEY_ATTRIBUTE) |
101 | , m_key(key.key()) |
102 | #endif |
103 | #if ENABLE(KEYBOARD_CODE_ATTRIBUTE) |
104 | , m_code(key.code()) |
105 | #endif |
106 | , m_keyIdentifier(key.keyIdentifier()) |
107 | , m_location(keyLocationCode(key)) |
108 | , m_repeat(key.isAutoRepeat()) |
109 | , m_isComposing(view && is<DOMWindow>(view->window()) && downcast<DOMWindow>(*view->window()).frame() && downcast<DOMWindow>(*view->window()).frame()->editor().hasComposition()) |
110 | #if USE(APPKIT) || USE(UIKIT_KEYBOARD_ADDITIONS) |
111 | , m_handledByInputMethod(key.handledByInputMethod()) |
112 | #endif |
113 | #if USE(APPKIT) |
114 | , m_keypressCommands(key.commands()) |
115 | #endif |
116 | { |
117 | } |
118 | |
119 | inline KeyboardEvent::KeyboardEvent(const AtomicString& eventType, const Init& initializer) |
120 | : UIEventWithKeyState(eventType, initializer) |
121 | #if ENABLE(KEYBOARD_KEY_ATTRIBUTE) |
122 | , m_key(initializer.key) |
123 | #endif |
124 | #if ENABLE(KEYBOARD_CODE_ATTRIBUTE) |
125 | , m_code(initializer.code) |
126 | #endif |
127 | , m_keyIdentifier(initializer.keyIdentifier) |
128 | , m_location(initializer.keyLocation ? *initializer.keyLocation : initializer.location) |
129 | , m_repeat(initializer.repeat) |
130 | , m_isComposing(initializer.isComposing) |
131 | , m_charCode(initializer.charCode) |
132 | , m_keyCode(initializer.keyCode) |
133 | , m_which(initializer.which) |
134 | { |
135 | } |
136 | |
137 | KeyboardEvent::~KeyboardEvent() = default; |
138 | |
139 | Ref<KeyboardEvent> KeyboardEvent::create(const PlatformKeyboardEvent& platformEvent, RefPtr<WindowProxy>&& view) |
140 | { |
141 | return adoptRef(*new KeyboardEvent(platformEvent, WTFMove(view))); |
142 | } |
143 | |
144 | Ref<KeyboardEvent> KeyboardEvent::createForBindings() |
145 | { |
146 | return adoptRef(*new KeyboardEvent); |
147 | } |
148 | |
149 | Ref<KeyboardEvent> KeyboardEvent::create(const AtomicString& type, const Init& initializer) |
150 | { |
151 | return adoptRef(*new KeyboardEvent(type, initializer)); |
152 | } |
153 | |
154 | void KeyboardEvent::initKeyboardEvent(const AtomicString& type, bool canBubble, bool cancelable, RefPtr<WindowProxy>&& view, |
155 | const String& keyIdentifier, unsigned location, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey) |
156 | { |
157 | if (isBeingDispatched()) |
158 | return; |
159 | |
160 | initUIEvent(type, canBubble, cancelable, WTFMove(view), 0); |
161 | |
162 | m_keyIdentifier = keyIdentifier; |
163 | m_location = location; |
164 | |
165 | setModifierKeys(ctrlKey, altKey, shiftKey, metaKey, altGraphKey); |
166 | |
167 | m_charCode = WTF::nullopt; |
168 | m_isComposing = false; |
169 | m_keyCode = WTF::nullopt; |
170 | m_repeat = false; |
171 | m_underlyingPlatformEvent = nullptr; |
172 | m_which = WTF::nullopt; |
173 | |
174 | #if ENABLE(KEYBOARD_CODE_ATTRIBUTE) |
175 | m_code = { }; |
176 | #endif |
177 | |
178 | #if ENABLE(KEYBOARD_KEY_ATTRIBUTE) |
179 | m_key = { }; |
180 | #endif |
181 | |
182 | #if PLATFORM(COCOA) |
183 | m_handledByInputMethod = false; |
184 | m_keypressCommands = { }; |
185 | #endif |
186 | } |
187 | |
188 | int KeyboardEvent::keyCode() const |
189 | { |
190 | if (m_keyCode) |
191 | return m_keyCode.value(); |
192 | |
193 | // IE: virtual key code for keyup/keydown, character code for keypress |
194 | // Firefox: virtual key code for keyup/keydown, zero for keypress |
195 | // We match IE. |
196 | if (!m_underlyingPlatformEvent) |
197 | return 0; |
198 | if (type() == eventNames().keydownEvent || type() == eventNames().keyupEvent) |
199 | return windowsVirtualKeyCodeWithoutLocation(m_underlyingPlatformEvent->windowsVirtualKeyCode()); |
200 | |
201 | return charCode(); |
202 | } |
203 | |
204 | int KeyboardEvent::charCode() const |
205 | { |
206 | if (m_charCode) |
207 | return m_charCode.value(); |
208 | |
209 | // IE: not supported |
210 | // Firefox: 0 for keydown/keyup events, character code for keypress |
211 | // We match Firefox, unless in backward compatibility mode, where we always return the character code. |
212 | bool backwardCompatibilityMode = false; |
213 | auto* window = view() ? view()->window() : nullptr; |
214 | if (is<DOMWindow>(window) && downcast<DOMWindow>(*window).frame()) |
215 | backwardCompatibilityMode = downcast<DOMWindow>(*window).frame()->eventHandler().needsKeyboardEventDisambiguationQuirks(); |
216 | |
217 | if (!m_underlyingPlatformEvent || (type() != eventNames().keypressEvent && !backwardCompatibilityMode)) |
218 | return 0; |
219 | return m_underlyingPlatformEvent->text().characterStartingAt(0); |
220 | } |
221 | |
222 | EventInterface KeyboardEvent::eventInterface() const |
223 | { |
224 | return KeyboardEventInterfaceType; |
225 | } |
226 | |
227 | bool KeyboardEvent::isKeyboardEvent() const |
228 | { |
229 | return true; |
230 | } |
231 | |
232 | int KeyboardEvent::which() const |
233 | { |
234 | // Netscape's "which" returns a virtual key code for keydown and keyup, and a character code for keypress. |
235 | // That's exactly what IE's "keyCode" returns. So they are the same for keyboard events. |
236 | if (m_which) |
237 | return m_which.value(); |
238 | return keyCode(); |
239 | } |
240 | |
241 | } // namespace WebCore |
242 | |