Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "KeyboardEventManager.h" | 5 #include "KeyboardEventManager.h" |
| 6 | 6 |
| 7 #include "core/dom/Element.h" | 7 #include "core/dom/Element.h" |
| 8 #include "core/editing/Editor.h" | 8 #include "core/editing/Editor.h" |
| 9 #include "core/events/KeyboardEvent.h" | 9 #include "core/events/KeyboardEvent.h" |
| 10 #include "core/html/HTMLDialogElement.h" | 10 #include "core/html/HTMLDialogElement.h" |
| 11 #include "core/input/EventHandler.h" | 11 #include "core/input/EventHandler.h" |
| 12 #include "core/layout/LayoutObject.h" | 12 #include "core/layout/LayoutObject.h" |
| 13 #include "core/layout/LayoutTextControlSingleLine.h" | 13 #include "core/layout/LayoutTextControlSingleLine.h" |
| 14 #include "core/loader/FrameLoaderClient.h" | 14 #include "core/loader/FrameLoaderClient.h" |
| 15 #include "core/page/ChromeClient.h" | 15 #include "core/page/ChromeClient.h" |
| 16 #include "core/page/FocusController.h" | 16 #include "core/page/FocusController.h" |
| 17 #include "core/page/Page.h" | 17 #include "core/page/Page.h" |
| 18 #include "core/page/SpatialNavigation.h" | 18 #include "core/page/SpatialNavigation.h" |
| 19 #include "platform/PlatformKeyboardEvent.h" | |
| 20 #include "platform/UserGestureIndicator.h" | 19 #include "platform/UserGestureIndicator.h" |
| 21 #include "platform/WindowsKeyboardCodes.h" | 20 #include "platform/WindowsKeyboardCodes.h" |
| 21 #include "public/platform/WebInputEvent.h" | |
| 22 | |
| 23 #if OS(WIN) | |
| 24 #include <windows.h> | |
| 25 #elif OS(MACOSX) | |
| 26 #import <Carbon/Carbon.h> | |
| 27 #endif | |
| 22 | 28 |
| 23 namespace blink { | 29 namespace blink { |
| 24 | 30 |
| 25 namespace { | 31 namespace { |
| 26 | 32 |
| 33 #if OS(WIN) | |
| 34 static const unsigned short HIGHBITMASKSHORT = 0x8000; | |
| 35 #endif | |
| 36 | |
| 27 const int kVKeyProcessKey = 229; | 37 const int kVKeyProcessKey = 229; |
| 28 | 38 |
| 29 WebFocusType focusDirectionForKey(const String& key) | 39 WebFocusType focusDirectionForKey(const String& key) |
| 30 { | 40 { |
| 31 WebFocusType retVal = WebFocusTypeNone; | 41 WebFocusType retVal = WebFocusTypeNone; |
| 32 if (key == "ArrowDown") | 42 if (key == "ArrowDown") |
| 33 retVal = WebFocusTypeDown; | 43 retVal = WebFocusTypeDown; |
| 34 else if (key == "ArrowUp") | 44 else if (key == "ArrowUp") |
| 35 retVal = WebFocusTypeUp; | 45 retVal = WebFocusTypeUp; |
| 36 else if (key == "ArrowLeft") | 46 else if (key == "ArrowLeft") |
| 37 retVal = WebFocusTypeLeft; | 47 retVal = WebFocusTypeLeft; |
| 38 else if (key == "ArrowRight") | 48 else if (key == "ArrowRight") |
| 39 retVal = WebFocusTypeRight; | 49 retVal = WebFocusTypeRight; |
| 40 return retVal; | 50 return retVal; |
| 41 } | 51 } |
| 42 | 52 |
| 43 } // namespace | 53 } // namespace |
| 44 | 54 |
| 45 KeyboardEventManager::KeyboardEventManager( | 55 KeyboardEventManager::KeyboardEventManager( |
| 46 LocalFrame* frame, ScrollManager* scrollManager) | 56 LocalFrame* frame, ScrollManager* scrollManager) |
| 47 : m_frame(frame) | 57 : m_frame(frame) |
| 48 , m_scrollManager(scrollManager) | 58 , m_scrollManager(scrollManager) |
| 49 { | 59 { |
| 50 } | 60 } |
| 51 | 61 |
| 52 KeyboardEventManager::~KeyboardEventManager() | 62 KeyboardEventManager::~KeyboardEventManager() |
| 53 { | 63 { |
| 54 } | 64 } |
| 55 | 65 |
| 56 bool KeyboardEventManager::handleAccessKey(const PlatformKeyboardEvent& evt) | 66 bool KeyboardEventManager::handleAccessKey(const WebKeyboardEvent& evt) |
| 57 { | 67 { |
| 58 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. | 68 // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. |
| 59 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and | 69 // IE matches lower and upper case access keys regardless of Shift key state - but if both upper and |
| 60 // lower case variants are present in a document, the correct element is mat ched based on Shift key state. | 70 // lower case variants are present in a document, the correct element is mat ched based on Shift key state. |
| 61 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively. | 71 // Firefox only matches an access key if Shift is not pressed, and does that case-insensitively. |
| 62 DCHECK(!(PlatformKeyboardEvent::accessKeyModifiers() & PlatformEvent::ShiftK ey)); | 72 DCHECK(!(kAccessKeyModifiers & WebInputEvent::ShiftKey)); |
| 63 if ((evt.getModifiers() & (PlatformEvent::KeyModifiers & ~PlatformEvent::Shi ftKey)) != PlatformKeyboardEvent::accessKeyModifiers()) | 73 if ((evt.modifiers & (WebKeyboardEvent::KeyModifiers & ~WebInputEvent::Shift Key)) != kAccessKeyModifiers) |
| 64 return false; | 74 return false; |
| 65 String key = evt.unmodifiedText(); | 75 String key = String(evt.unmodifiedText); |
| 66 Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); | 76 Element* elem = m_frame->document()->getElementByAccessKey(key.lower()); |
| 67 if (!elem) | 77 if (!elem) |
| 68 return false; | 78 return false; |
| 69 elem->accessKeyAction(false); | 79 elem->accessKeyAction(false); |
| 70 return true; | 80 return true; |
| 71 } | 81 } |
| 72 | 82 |
| 73 WebInputEventResult KeyboardEventManager::keyEvent( | 83 WebInputEventResult KeyboardEventManager::keyEvent( |
| 74 const PlatformKeyboardEvent& initialKeyEvent) | 84 const WebKeyboardEvent& initialKeyEvent) |
| 75 { | 85 { |
| 76 m_frame->chromeClient().clearToolTip(); | 86 m_frame->chromeClient().clearToolTip(); |
| 77 | 87 |
| 78 if (initialKeyEvent.windowsVirtualKeyCode() == VK_CAPITAL) | 88 if (initialKeyEvent.windowsKeyCode == VK_CAPITAL) |
| 79 capsLockStateMayHaveChanged(); | 89 capsLockStateMayHaveChanged(); |
| 80 | 90 |
| 81 #if OS(WIN) | 91 #if OS(WIN) |
| 82 if (m_scrollManager->panScrollInProgress()) { | 92 if (m_scrollManager->panScrollInProgress()) { |
| 83 // If a key is pressed while the panScroll is in progress then we want t o stop | 93 // If a key is pressed while the panScroll is in progress then we want t o stop |
| 84 if (initialKeyEvent.type() == PlatformEvent::KeyDown || initialKeyEvent. type() == PlatformEvent::RawKeyDown) | 94 if (initialKeyEvent.type == WebInputEvent::KeyDown || initialKeyEvent.ty pe == WebInputEvent::RawKeyDown) |
| 85 m_scrollManager->stopAutoscroll(); | 95 m_scrollManager->stopAutoscroll(); |
| 86 | 96 |
| 87 // If we were in panscroll mode, we swallow the key event | 97 // If we were in panscroll mode, we swallow the key event |
| 88 return WebInputEventResult::HandledSuppressed; | 98 return WebInputEventResult::HandledSuppressed; |
| 89 } | 99 } |
| 90 #endif | 100 #endif |
| 91 | 101 |
| 92 // Check for cases where we are too early for events -- possible unmatched k ey up | 102 // Check for cases where we are too early for events -- possible unmatched k ey up |
| 93 // from pressing return in the location bar. | 103 // from pressing return in the location bar. |
| 94 Node* node = eventTargetNodeForDocument(m_frame->document()); | 104 Node* node = eventTargetNodeForDocument(m_frame->document()); |
| 95 if (!node) | 105 if (!node) |
| 96 return WebInputEventResult::NotHandled; | 106 return WebInputEventResult::NotHandled; |
| 97 | 107 |
| 98 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); | 108 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture); |
| 99 | 109 |
| 100 // In IE, access keys are special, they are handled after default keydown pr ocessing, but cannot be canceled - this is hard to match. | 110 // In IE, access keys are special, they are handled after default keydown pr ocessing, but cannot be canceled - this is hard to match. |
| 101 // On Mac OS X, we process them before dispatching keydown, as the default k eydown handler implements Emacs key bindings, which may conflict | 111 // On Mac OS X, we process them before dispatching keydown, as the default k eydown handler implements Emacs key bindings, which may conflict |
| 102 // with access keys. Then we dispatch keydown, but suppress its default hand ling. | 112 // with access keys. Then we dispatch keydown, but suppress its default hand ling. |
| 103 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatch ing a keypress event for WM_SYSCHAR messages. | 113 // On Windows, WebKit explicitly calls handleAccessKey() instead of dispatch ing a keypress event for WM_SYSCHAR messages. |
| 104 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events. | 114 // Other platforms currently match either Mac or Windows behavior, depending on whether they send combined KeyDown events. |
| 105 bool matchedAnAccessKey = false; | 115 bool matchedAnAccessKey = false; |
| 106 if (initialKeyEvent.type() == PlatformEvent::KeyDown) | 116 if (initialKeyEvent.type == WebInputEvent::KeyDown) |
| 107 matchedAnAccessKey = handleAccessKey(initialKeyEvent); | 117 matchedAnAccessKey = handleAccessKey(initialKeyEvent); |
| 108 | 118 |
| 109 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch. | 119 // FIXME: it would be fair to let an input method handle KeyUp events before DOM dispatch. |
| 110 if (initialKeyEvent.type() == PlatformEvent::KeyUp || initialKeyEvent.type() == PlatformEvent::Char) { | 120 if (initialKeyEvent.type == WebInputEvent::KeyUp || initialKeyEvent.type == WebInputEvent::Char) { |
| 111 KeyboardEvent* domEvent = KeyboardEvent::create(initialKeyEvent, m_frame ->document()->domWindow()); | 121 KeyboardEvent* domEvent = KeyboardEvent::create(initialKeyEvent, m_frame ->document()->domWindow()); |
| 112 | 122 |
| 113 return EventHandler::toWebInputEventResult(node->dispatchEvent(domEvent) ); | 123 return EventHandler::toWebInputEventResult(node->dispatchEvent(domEvent) ); |
| 114 } | 124 } |
| 115 | 125 |
| 116 PlatformKeyboardEvent keyDownEvent = initialKeyEvent; | 126 WebKeyboardEvent keyDownEvent = initialKeyEvent; |
| 117 if (keyDownEvent.type() != PlatformEvent::RawKeyDown) | 127 if (keyDownEvent.type != WebInputEvent::RawKeyDown) |
| 118 keyDownEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown); | 128 keyDownEvent.type = WebInputEvent::RawKeyDown; |
| 119 KeyboardEvent* keydown = KeyboardEvent::create(keyDownEvent, m_frame->docume nt()->domWindow()); | 129 KeyboardEvent* keydown = KeyboardEvent::create(keyDownEvent, m_frame->docume nt()->domWindow()); |
| 120 if (matchedAnAccessKey) | 130 if (matchedAnAccessKey) |
| 121 keydown->setDefaultPrevented(true); | 131 keydown->setDefaultPrevented(true); |
| 122 keydown->setTarget(node); | 132 keydown->setTarget(node); |
| 123 | 133 |
| 124 DispatchEventResult dispatchResult = node->dispatchEvent(keydown); | 134 DispatchEventResult dispatchResult = node->dispatchEvent(keydown); |
| 125 if (dispatchResult != DispatchEventResult::NotCanceled) | 135 if (dispatchResult != DispatchEventResult::NotCanceled) |
| 126 return EventHandler::toWebInputEventResult(dispatchResult); | 136 return EventHandler::toWebInputEventResult(dispatchResult); |
| 127 // If frame changed as a result of keydown dispatch, then return early to av oid sending a subsequent keypress message to the new frame. | 137 // If frame changed as a result of keydown dispatch, then return early to av oid sending a subsequent keypress message to the new frame. |
| 128 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->fo cusController().focusedOrMainFrame(); | 138 bool changedFocusedFrame = m_frame->page() && m_frame != m_frame->page()->fo cusController().focusedOrMainFrame(); |
| 129 if (changedFocusedFrame) | 139 if (changedFocusedFrame) |
| 130 return WebInputEventResult::HandledSystem; | 140 return WebInputEventResult::HandledSystem; |
| 131 | 141 |
| 132 if (initialKeyEvent.type() == PlatformEvent::RawKeyDown) | 142 if (initialKeyEvent.type == WebInputEvent::RawKeyDown) |
| 133 return WebInputEventResult::NotHandled; | 143 return WebInputEventResult::NotHandled; |
| 134 | 144 |
| 135 // Focus may have changed during keydown handling, so refetch node. | 145 // Focus may have changed during keydown handling, so refetch node. |
| 136 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node. | 146 // But if we are dispatching a fake backward compatibility keypress, then we pretend that the keypress happened on the original node. |
| 137 node = eventTargetNodeForDocument(m_frame->document()); | 147 node = eventTargetNodeForDocument(m_frame->document()); |
| 138 if (!node) | 148 if (!node) |
| 139 return WebInputEventResult::NotHandled; | 149 return WebInputEventResult::NotHandled; |
| 140 | 150 |
| 141 PlatformKeyboardEvent keyPressEvent = initialKeyEvent; | 151 #if OS(MACOSX) |
| 142 keyPressEvent.disambiguateKeyDownEvent(PlatformEvent::Char); | 152 // According to NSEvents.h, OpenStep reserves the range 0xF700-0xF8FF for |
| 143 if (keyPressEvent.text().isEmpty()) | 153 // function keys. However, some actual private use characters happen to be |
| 154 // in this range, e.g. the Apple logo (Option+Shift+K). 0xF7FF is an | |
| 155 // arbitrary cut-off. | |
| 156 if (initialKeyEvent.text[0U] >= 0xF700 && initialKeyEvent.text[0U] <= 0xF7FF ) { | |
| 157 return WebInputEventResult::NotHandled; | |
| 158 } | |
| 159 #endif | |
| 160 | |
| 161 WebKeyboardEvent keyPressEvent = initialKeyEvent; | |
| 162 keyPressEvent.type = WebInputEvent::Char; | |
| 163 if (keyPressEvent.text[0] == 0) | |
| 144 return WebInputEventResult::NotHandled; | 164 return WebInputEventResult::NotHandled; |
| 145 KeyboardEvent* keypress = KeyboardEvent::create(keyPressEvent, m_frame->docu ment()->domWindow()); | 165 KeyboardEvent* keypress = KeyboardEvent::create(keyPressEvent, m_frame->docu ment()->domWindow()); |
| 146 keypress->setTarget(node); | 166 keypress->setTarget(node); |
| 147 return EventHandler::toWebInputEventResult(node->dispatchEvent(keypress)); | 167 return EventHandler::toWebInputEventResult(node->dispatchEvent(keypress)); |
| 148 } | 168 } |
| 149 | 169 |
| 150 void KeyboardEventManager::capsLockStateMayHaveChanged() | 170 void KeyboardEventManager::capsLockStateMayHaveChanged() |
| 151 { | 171 { |
| 152 if (Element* element = m_frame->document()->focusedElement()) { | 172 if (Element* element = m_frame->document()->focusedElement()) { |
| 153 if (LayoutObject* r = element->layoutObject()) { | 173 if (LayoutObject* r = element->layoutObject()) { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 { | 305 { |
| 286 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog()) | 306 if (HTMLDialogElement* dialog = m_frame->document()->activeModalDialog()) |
| 287 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel)); | 307 dialog->dispatchEvent(Event::createCancelable(EventTypeNames::cancel)); |
| 288 } | 308 } |
| 289 | 309 |
| 290 DEFINE_TRACE(KeyboardEventManager) | 310 DEFINE_TRACE(KeyboardEventManager) |
| 291 { | 311 { |
| 292 visitor->trace(m_frame); | 312 visitor->trace(m_frame); |
| 293 } | 313 } |
| 294 | 314 |
| 315 static OverrideCapsLockState s_overrideCapsLockState; | |
| 316 | |
| 317 void KeyboardEventManager::setCurrentCapsLockState(OverrideCapsLockState state) { s_overrideCapsLockState = state; } | |
| 318 | |
| 319 bool KeyboardEventManager::currentCapsLockState() | |
| 320 { | |
| 321 switch (s_overrideCapsLockState) { | |
| 322 case OverrideCapsLockState::Default: | |
| 323 #if OS(WIN) | |
| 324 // FIXME: Does this even work inside the sandbox? | |
| 325 return GetKeyState(VK_CAPITAL) & 1; | |
|
esprehn
2016/08/30 20:30:28
I hope we have test coverage for all this platform
| |
| 326 #elif OS(MACOSX) | |
| 327 return GetCurrentKeyModifiers() & alphaLock; | |
| 328 #else | |
| 329 NOTIMPLEMENTED(); | |
| 330 return false; | |
| 331 #endif | |
| 332 case OverrideCapsLockState::On: | |
| 333 return true; | |
| 334 case OverrideCapsLockState::Off: | |
| 335 default: | |
| 336 return false; | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 WebInputEvent::Modifiers KeyboardEventManager::getCurrentModifierState() | |
| 341 { | |
| 342 unsigned modifiers = 0; | |
| 343 #if OS(WIN) | |
| 344 if (GetKeyState(VK_SHIFT) & HIGHBITMASKSHORT) | |
| 345 modifiers |= WebInputEvent::ShiftKey; | |
| 346 if (GetKeyState(VK_CONTROL) & HIGHBITMASKSHORT) | |
| 347 modifiers |= WebInputEvent::ControlKey; | |
| 348 if (GetKeyState(VK_MENU) & HIGHBITMASKSHORT) | |
| 349 modifiers |= WebInputEvent::AltKey; | |
| 350 #elif OS(MACOSX) | |
| 351 UInt32 currentModifiers = GetCurrentKeyModifiers(); | |
| 352 if (currentModifiers & ::shiftKey) | |
| 353 modifiers |= WebInputEvent::ShiftKey; | |
| 354 if (currentModifiers & ::controlKey) | |
| 355 modifiers |= WebInputEvent::ControlKey; | |
| 356 if (currentModifiers & ::optionKey) | |
| 357 modifiers |= WebInputEvent::AltKey; | |
| 358 if (currentModifiers & ::cmdKey) | |
| 359 modifiers |= WebInputEvent::MetaKey; | |
| 360 #else | |
| 361 // TODO(crbug.com/538289): Implement on other platforms. | |
| 362 return static_cast<WebInputEvent::Modifiers>(0); | |
| 363 #endif | |
| 364 return static_cast<WebInputEvent::Modifiers>(modifiers); | |
| 365 } | |
| 366 | |
| 295 } // namespace blink | 367 } // namespace blink |
| OLD | NEW |