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

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

Powered by Google App Engine
This is Rietveld 408576698