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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/input/KeyboardEventManager.cpp
diff --git a/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp b/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bce0b9adfa2c295bc2b3f453c6555e99415da53b
--- /dev/null
+++ b/third_party/WebKit/Source/core/input/KeyboardEventManager.cpp
@@ -0,0 +1,300 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "KeyboardEventManager.h"
+
+#include "core/dom/Element.h"
+#include "core/editing/Editor.h"
+#include "core/events/KeyboardEvent.h"
+#include "core/html/HTMLDialogElement.h"
+#include "core/input/EventHandler.h"
+#include "core/layout/LayoutObject.h"
+#include "core/layout/LayoutTextControlSingleLine.h"
+#include "core/loader/FrameLoaderClient.h"
+#include "core/page/ChromeClient.h"
+#include "core/page/FocusController.h"
+#include "core/page/Page.h"
+#include "core/page/SpatialNavigation.h"
+#include "platform/PlatformKeyboardEvent.h"
+#include "platform/UserGestureIndicator.h"
+#include "platform/WindowsKeyboardCodes.h"
+
+namespace blink {
+
+namespace {
+
+WebFocusType focusDirectionForKey(const AtomicString& keyIdentifier)
+{
+ DEFINE_STATIC_LOCAL(AtomicString, Down, ("Down"));
+ DEFINE_STATIC_LOCAL(AtomicString, Up, ("Up"));
+ DEFINE_STATIC_LOCAL(AtomicString, Left, ("Left"));
+ DEFINE_STATIC_LOCAL(AtomicString, Right, ("Right"));
+
+ WebFocusType retVal = WebFocusTypeNone;
+
+ if (keyIdentifier == Down)
+ retVal = WebFocusTypeDown;
+ else if (keyIdentifier == Up)
+ retVal = WebFocusTypeUp;
+ else if (keyIdentifier == Left)
+ retVal = WebFocusTypeLeft;
+ else if (keyIdentifier == Right)
+ retVal = WebFocusTypeRight;
+
+ return retVal;
+}
+
+} // namespace
+
+KeyboardEventManager::KeyboardEventManager(
+ LocalFrame* frame, ScrollManager* scrollManager)
+: m_frame(frame)
+, m_scrollManager(scrollManager)
+{
+}
+
+KeyboardEventManager::~KeyboardEventManager()
+{
+}
+
+bool KeyboardEventManager::handleAccessKey(const PlatformKeyboardEvent& evt)
+{
+ // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do.
+ // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and
+ // lower case variants are present in a document, the correct element is matched based on Shift key state.
+ // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively.
+ DCHECK(!(PlatformKeyboardEvent::accessKeyModifiers() & PlatformEvent::ShiftKey));
+ if ((evt.getModifiers() & (PlatformEvent::KeyModifiers & ~PlatformEvent::ShiftKey)) != PlatformKeyboardEvent::accessKeyModifiers())
+ return false;
+ String key = evt.unmodifiedText();
+ Element* elem = m_frame->document()->getElementByAccessKey(key.lower());
+ if (!elem)
+ return false;
+ elem->accessKeyAction(false);
+ return true;
+}
+
+WebInputEventResult KeyboardEventManager::keyEvent(
+ const PlatformKeyboardEvent& initialKeyEvent)
+{
+ m_frame->chromeClient().clearToolTip();
+
+ if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL)
+ capsLockStateMayHaveChanged();
+
+#if OS(WIN)
+ if (m_scrollManager->panScrollInProgress()) {
+ // If a key is pressed while the panScroll is in progress then we want to stop
+ if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent.type() == PlatformEvent::RawKeyDown)
+ m_scrollManager->stopAutoscroll();
+
+ // If we were in panscroll mode, we swallow the key event
+ return WebInputEventResult::HandledSuppressed;
+ }
+#endif
+
+ // Check for cases where we are too early for events -- possible unmatched key up
+ // from pressing return in the location bar.
+ Node* node = eventTargetNodeForDocument(m_frame->document());
+ if (!node)
+ return WebInputEventResult::NotHandled;
+
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
+ // In IE, access keys are special, they are handled after default keydown processing, but cannot be canceled - this is hard to match.
+ // On Mac OS X, we process them before dispatching keydown, as the default keydown handler implements Emacs key bindings, which may conflict
+ // with access keys. Then we dispatch keydown, but suppress its default handling.
+ // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatching a keypress event for WM_SYSCHAR messages.
+ // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events.
+ bool matchedAnAccessKey = false;
+ if (initialKeyEvent.type() == PlatformEvent::KeyDown)
+ matchedAnAccessKey = handleAccessKey(initialKeyEvent);
+
+ // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch.
+ if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char) {
+ KeyboardEvent* domEvent = KeyboardEvent::create(initialKeyEvent, m_frame->document()->domWindow());
+
+ return EventHandler::toWebInputEventResult(node->dispatchEvent(domEvent));
+ }
+
+ PlatformKeyboardEvent keyDownEvent = initialKeyEvent;
+ if (keyDownEvent.type() != PlatformEvent::RawKeyDown)
+ keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
+ KeyboardEvent* keydown = KeyboardEvent::create(keyDownEvent, m_frame->document()->domWindow());
+ if (matchedAnAccessKey)
+ keydown->setDefaultPrevented(true);
+ keydown->setTarget(node);
+
+ DispatchEventResult dispatchResult = node->dispatchEvent(keydown);
+ if (dispatchResult != DispatchEventResult::NotCanceled)
+ return EventHandler::toWebInputEventResult(dispatchResult);
+ // If frame changed as a result of keydown dispatch, then return early to avoid sending a subsequent keypress message to the new frame.
+ bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->focusController().focusedOrMainFrame();
+ if (changedFocusedFrame)
+ return WebInputEventResult::HandledSystem;
+
+ if (initialKeyEvent.type() == PlatformEvent::RawKeyDown)
+ return WebInputEventResult::NotHandled;
+
+ // Focus may have changed during keydown handling, so refetch node.
+ // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node.
+ node = eventTargetNodeForDocument(m_frame->document());
+ if (!node)
+ return WebInputEventResult::NotHandled;
+
+ PlatformKeyboardEvent keyPressEvent = initialKeyEvent;
+ keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char);
+ if (keyPressEvent.text().isEmpty())
+ return WebInputEventResult::NotHandled;
+ KeyboardEvent* keypress = KeyboardEvent::create(keyPressEvent, m_frame->document()->domWindow());
+ keypress->setTarget(node);
+ return EventHandler::toWebInputEventResult(node->dispatchEvent(keypress));
+}
+
+void KeyboardEventManager::capsLockStateMayHaveChanged()
+{
+ if (Element* element = m_frame->document()->focusedElement()) {
+ if (LayoutObject* r = element->layoutObject()) {
+ if (r->isTextField())
+ toLayoutTextControlSingleLine(r)->capsLockStateMayHaveChanged();
+ }
+ }
+}
+
+void KeyboardEventManager::defaultKeyboardEventHandler(
+ KeyboardEvent* event, Node* possibleFocusedNode)
+{
+ if (event->type() == EventTypeNames::keydown) {
+ // Clear caret blinking suspended state to make sure that caret blinks
+ // when we type again after long pressing on an empty input field.
+ if (m_frame && m_frame->selection().isCaretBlinkingSuspended())
+ m_frame->selection().setCaretBlinkingSuspended(false);
+
+ m_frame->editor().handleKeyboardEvent(event);
+ if (event->defaultHandled())
+ return;
+ if (event->keyIdentifier() == "U+0009") {
+ defaultTabEventHandler(event);
+ } else if (event->keyIdentifier() == "U+0008") {
+ defaultBackspaceEventHandler(event);
+ } else if (event->keyIdentifier() == "U+001B") {
+ defaultEscapeEventHandler(event);
+ } else {
+ WebFocusType type = focusDirectionForKey(AtomicString(event->keyIdentifier()));
+ if (type != WebFocusTypeNone)
+ defaultArrowEventHandler(type, event);
+ }
+ }
+ if (event->type() == EventTypeNames::keypress) {
+ m_frame->editor().handleKeyboardEvent(event);
+ if (event->defaultHandled())
+ return;
+ if (event->charCode() == ' ')
+ defaultSpaceEventHandler(event, possibleFocusedNode);
+ }
+}
+
+void KeyboardEventManager::defaultSpaceEventHandler(
+ KeyboardEvent* event, Node* possibleFocusedNode)
+{
+ DCHECK_EQ(event->type(), EventTypeNames::keypress);
+
+ if (event->ctrlKey() || event->metaKey() || event->altKey())
+ return;
+
+ ScrollDirection direction = event->shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward;
+
+ // FIXME: enable scroll customization in this case. See crbug.com/410974.
+ if (m_scrollManager->logicalScroll(direction, ScrollByPage, nullptr, possibleFocusedNode)) {
+ event->setDefaultHandled();
+ return;
+ }
+}
+
+void KeyboardEventManager::defaultBackspaceEventHandler(KeyboardEvent* event)
+{
+ DCHECK_EQ(event->type(), EventTypeNames::keydown);
+
+ if (!RuntimeEnabledFeatures::backspaceDefaultHandlerEnabled())
+ return;
+
+ if (event->ctrlKey() || event->metaKey() || event->altKey())
+ return;
+
+ if (!m_frame->editor().behavior().shouldNavigateBackOnBackspace())
+ return;
+ UseCounter::count(m_frame->document(), UseCounter::BackspaceNavigatedBack);
+ if (m_frame->page()->chromeClient().hadFormInteraction())
+ UseCounter::count(m_frame->document(), UseCounter::BackspaceNavigatedBackAfterFormInteraction);
+ bool handledEvent = m_frame->loader().client()->navigateBackForward(event->shiftKey() ? 1 : -1);
+ if (handledEvent)
+ event->setDefaultHandled();
+}
+
+void KeyboardEventManager::defaultArrowEventHandler(WebFocusType focusType, KeyboardEvent* event)
+{
+ DCHECK_EQ(event->type(), EventTypeNames::keydown);
+
+ if (event->ctrlKey() || event->metaKey() || event->shiftKey())
+ return;
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+
+ if (!isSpatialNavigationEnabled(m_frame))
+ return;
+
+ // Arrows and other possible directional navigation keys can be used in design
+ // mode editing.
+ if (m_frame->document()->inDesignMode())
+ return;
+
+ if (page->focusController().advanceFocus(focusType))
+ event->setDefaultHandled();
+}
+
+void KeyboardEventManager::defaultTabEventHandler(KeyboardEvent* event)
+{
+ DCHECK_EQ(event->type(), EventTypeNames::keydown);
+
+ // We should only advance focus on tabs if no special modifier keys are held down.
+ if (event->ctrlKey() || event->metaKey())
+ return;
+
+#if !OS(MACOSX)
+ // Option-Tab is a shortcut based on a system-wide preference on Mac but
+ // should be ignored on all other platforms.
+ if (event->altKey())
+ return;
+#endif
+
+ Page* page = m_frame->page();
+ if (!page)
+ return;
+ if (!page->tabKeyCyclesThroughElements())
+ return;
+
+ WebFocusType focusType = event->shiftKey() ? WebFocusTypeBackward : WebFocusTypeForward;
+
+ // Tabs can be used in design mode editing.
+ if (m_frame->document()->inDesignMode())
+ return;
+
+ if (page->focusController().advanceFocus(focusType, InputDeviceCapabilities::doesntFireTouchEventsSourceCapabilities()))
+ event->setDefaultHandled();
+}
+
+void KeyboardEventManager::defaultEscapeEventHandler(KeyboardEvent* event)
+{
+ if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog())
+ dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel));
+}
+
+DEFINE_TRACE(KeyboardEventManager)
+{
+ visitor->trace(m_frame);
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698