Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: third_party/WebKit/Source/core/input/KeyboardEventManager.cpp

Issue 2036643003: Creat a KeyboardEventManager class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "KeyboardEventManager.h"
6
7 #include "core/dom/Element.h"
8 #include "core/editing/Editor.h"
9 #include "core/events/KeyboardEvent.h"
10 #include "core/html/HTMLDialogElement.h"
11 #include "core/input/EventHandler.h"
12 #include "core/layout/LayoutObject.h"
13 #include "core/layout/LayoutTextControlSingleLine.h"
14 #include "core/loader/FrameLoaderClient.h"
15 #include "core/page/ChromeClient.h"
16 #include "core/page/FocusController.h"
17 #include "core/page/Page.h"
18 #include "core/page/SpatialNavigation.h"
19 #include "platform/PlatformKeyboardEvent.h"
20 #include "platform/UserGestureIndicator.h"
21 #include "platform/WindowsKeyboardCodes.h"
22
23 namespace blink {
24
25 namespace {
26
27 WebFocusType focusDirectionForKey(const AtomicString& keyIdentifier)
28 {
29 DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
30 DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
31 DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
32 DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
33
34 WebFocusType retVal = WebFocusTypeNone;
35
36 if (keyIdentifier == Down)
37 retVal = WebFocusTypeDown;
38 else if (keyIdentifier == Up)
39 retVal = WebFocusTypeUp;
40 else if (keyIdentifier == Left)
41 retVal = WebFocusTypeLeft;
42 else if (keyIdentifier == Right)
43 retVal = WebFocusTypeRight;
44
45 return retVal;
46 }
47
48 } // namespace
49
50 KeyboardEventManager::KeyboardEventManager(
51 LocalFrame* frame, ScrollManager* scrollManager)
52 : m_frame(frame)
53 , m_scrollManager(scrollManager)
54 {
55 }
56
57 KeyboardEventManager::~KeyboardEventManager()
58 {
59 }
60
61 bool KeyboardEventManager::handleAccessKey(const PlatformKeyboardEvent& evt)
62 {
63 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
64 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
65 // lower case variants are present in a document, the correct element is mat ched based on Shift key state.
66 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
67 DCHECK(!(PlatformKeyboardEvent::accessKeyModifiers() & PlatformEvent::ShiftK ey));
68 if ((evt.getModifiers() & (PlatformEvent::KeyModifiers & ~PlatformEvent::Shi ftKey)) != PlatformKeyboardEvent::accessKeyModifiers())
69 return false;
70 String key = evt.unmodifiedText();
71 Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
72 if (!elem)
73 return false;
74 elem->accessKeyAction(false);
75 return true;
76 }
77
78 WebInputEventResult KeyboardEventManager::keyEvent(
79 const PlatformKeyboardEvent& initialKeyEvent)
80 {
81 m_frame->chromeClient().clearToolTip();
82
83 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
84 capsLockStateMayHaveChanged();
85
86 #if OS(WIN)
87 if (m_scrollManager->panScrollInProgress()) {
88 // If a key is pressed while the panScroll is in progress then we want t o stop
89 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent. type() == PlatformEvent::RawKeyDown)
90 m_scrollManager->stopAutoscroll();
91
92 // If we were in panscroll mode, we swallow the key event
93 return WebInputEventResult::HandledSuppressed;
94 }
95 #endif
96
97 // Check for cases where we are too early for events -- possible unmatched k ey up
98 // from pressing return in the location bar.
99 Node* node = eventTargetNodeForDocument(m_frame->document());
100 if (!node)
101 return WebInputEventResult::NotHandled;
102
103 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
104
105 // In IE, access keys are special, they are handled after default keydown pr ocessing, but cannot be canceled - this is hard to match.
106 // On Mac OS X, we process them before dispatching keydown, as the default k eydown handler implements Emacs key bindings, which may conflict
107 // with access keys. Then we dispatch keydown, but suppress its default hand ling.
108 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatch ing a keypress event for WM_SYSCHAR messages.
109 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
110 bool matchedAnAccessKey = false;
111 if (initialKeyEvent.type() == PlatformEvent::KeyDown)
112 matchedAnAccessKey = handleAccessKey(initialKeyEvent);
113
114 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
115 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char) {
116 KeyboardEvent* domEvent = KeyboardEvent::create(initialKeyEvent, m_frame ->document()->domWindow());
117
118 return EventHandler::toWebInputEventResult(node->dispatchEvent(domEvent) );
119 }
120
121 PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
122 if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
123 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
124 KeyboardEvent* keydown = KeyboardEvent::create(keyDownEvent, m_frame->docume nt()->domWindow());
125 if (matchedAnAccessKey)
126 keydown->setDefaultPrevented(true);
127 keydown->setTarget(node);
128
129 DispatchEventResult dispatchResult = node->dispatchEvent(keydown);
130 if (dispatchResult != DispatchEventResult::NotCanceled)
131 return EventHandler::toWebInputEventResult(dispatchResult);
132 // If frame changed as a result of keydown dispatch, then return early to av oid sending a subsequent keypress message to the new frame.
133 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->fo cusController().focusedOrMainFrame();
134 if (changedFocusedFrame)
135 return WebInputEventResult::HandledSystem;
136
137 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown)
138 return WebInputEventResult::NotHandled;
139
140 // Focus may have changed during keydown handling, so refetch node.
141 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
142 node = eventTargetNodeForDocument(m_frame->document());
143 if (!node)
144 return WebInputEventResult::NotHandled;
145
146 PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
147 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
148 if (keyPressEvent.text().isEmpty())
149 return WebInputEventResult::NotHandled;
150 KeyboardEvent* keypress = KeyboardEvent::create(keyPressEvent, m_frame->docu ment()->domWindow());
151 keypress->setTarget(node);
152 return EventHandler::toWebInputEventResult(node->dispatchEvent(keypress));
153 }
154
155 void KeyboardEventManager::capsLockStateMayHaveChanged()
156 {
157 if (Element* element = m_frame->document()->focusedElement()) {
158 if (LayoutObject* r = element->layoutObject()) {
159 if (r->isTextField())
160 toLayoutTextControlSingleLine(r)->capsLockStateMayHaveChanged();
161 }
162 }
163 }
164
165 void KeyboardEventManager::defaultKeyboardEventHandler(
166 KeyboardEvent* event, Node* possibleFocusedNode)
167 {
168 if (event->type() == EventTypeNames::keydown) {
169 // Clear caret blinking suspended state to make sure that caret blinks
170 // when we type again after long pressing on an empty input field.
171 if (m_frame && m_frame->selection().isCaretBlinkingSuspended())
172 m_frame->selection().setCaretBlinkingSuspended(false);
173
174 m_frame->editor().handleKeyboardEvent(event);
175 if (event->defaultHandled())
176 return;
177 if (event->keyIdentifier() == "U+0009") {
178 defaultTabEventHandler(event);
179 } else if (event->keyIdentifier() == "U+0008") {
180 defaultBackspaceEventHandler(event);
181 } else if (event->keyIdentifier() == "U+001B") {
182 defaultEscapeEventHandler(event);
183 } else {
184 WebFocusType type = focusDirectionForKey(AtomicString(event->keyIden tifier()));
185 if (type != WebFocusTypeNone)
186 defaultArrowEventHandler(type, event);
187 }
188 }
189 if (event->type() == EventTypeNames::keypress) {
190 m_frame->editor().handleKeyboardEvent(event);
191 if (event->defaultHandled())
192 return;
193 if (event->charCode() == ' ')
194 defaultSpaceEventHandler(event, possibleFocusedNode);
195 }
196 }
197
198 void KeyboardEventManager::defaultSpaceEventHandler(
199 KeyboardEvent* event, Node* possibleFocusedNode)
200 {
201 DCHECK_EQ(event->type(), EventTypeNames::keypress);
202
203 if (event->ctrlKey() || event->metaKey() || event->altKey())
204 return;
205
206 ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
207
208 // FIXME: enable scroll customization in this case. See crbug.com/410974.
209 if (m_scrollManager->logicalScroll(direction, ScrollByPage, nullptr, possibl eFocusedNode)) {
210 event->setDefaultHandled();
211 return;
212 }
213 }
214
215 void KeyboardEventManager::defaultBackspaceEventHandler(KeyboardEvent* event)
216 {
217 DCHECK_EQ(event->type(), EventTypeNames::keydown);
218
219 if (!RuntimeEnabledFeatures::backspaceDefaultHandlerEnabled())
220 return;
221
222 if (event->ctrlKey() || event->metaKey() || event->altKey())
223 return;
224
225 if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
226 return;
227 UseCounter::count(m_frame->document(), UseCounter::BackspaceNavigatedBack);
228 if (m_frame->page()->chromeClient().hadFormInteraction())
229 UseCounter::count(m_frame->document(), UseCounter::BackspaceNavigatedBac kAfterFormInteraction);
230 bool handledEvent = m_frame->loader().client()->navigateBackForward(event->s hiftKey() ? 1 : -1);
231 if (handledEvent)
232 event->setDefaultHandled();
233 }
234
235 void KeyboardEventManager::defaultArrowEventHandler(WebFocusType focusType, Keyb oardEvent* event)
236 {
237 DCHECK_EQ(event->type(), EventTypeNames::keydown);
238
239 if (event->ctrlKey() || event->metaKey() || event->shiftKey())
240 return;
241
242 Page* page = m_frame->page();
243 if (!page)
244 return;
245
246 if (!isSpatialNavigationEnabled(m_frame))
247 return;
248
249 // Arrows and other possible directional navigation keys can be used in desi gn
250 // mode editing.
251 if (m_frame->document()->inDesignMode())
252 return;
253
254 if (page->focusController().advanceFocus(focusType))
255 event->setDefaultHandled();
256 }
257
258 void KeyboardEventManager::defaultTabEventHandler(KeyboardEvent* event)
259 {
260 DCHECK_EQ(event->type(), EventTypeNames::keydown);
261
262 // We should only advance focus on tabs if no special modifier keys are held down.
263 if (event->ctrlKey() || event->metaKey())
264 return;
265
266 #if !OS(MACOSX)
267 // Option-Tab is a shortcut based on a system-wide preference on Mac but
268 // should be ignored on all other platforms.
269 if (event->altKey())
270 return;
271 #endif
272
273 Page* page = m_frame->page();
274 if (!page)
275 return;
276 if (!page->tabKeyCyclesThroughElements())
277 return;
278
279 WebFocusType focusType = event->shiftKey() ? WebFocusTypeBackward : WebFocus TypeForward;
280
281 // Tabs can be used in design mode editing.
282 if (m_frame->document()->inDesignMode())
283 return;
284
285 if (page->focusController().advanceFocus(focusType, InputDeviceCapabilities: :doesntFireTouchEventsSourceCapabilities()))
286 event->setDefaultHandled();
287 }
288
289 void KeyboardEventManager::defaultEscapeEventHandler(KeyboardEvent* event)
290 {
291 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
292 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
293 }
294
295 DEFINE_TRACE(KeyboardEventManager)
296 {
297 visitor->trace(m_frame);
298 }
299
300 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698