Index: Source/core/html/HTMLSelectElement.cpp |
diff --git a/Source/core/html/HTMLSelectElement.cpp b/Source/core/html/HTMLSelectElement.cpp |
index b0dc747ff14ab9cee6caa8a9264b2d0c2834ad1f..044311161804603c515e7f22c8abfb98bfdcc903 100644 |
--- a/Source/core/html/HTMLSelectElement.cpp |
+++ b/Source/core/html/HTMLSelectElement.cpp |
@@ -1114,47 +1114,62 @@ void HTMLSelectElement::resetImpl() |
setNeedsValidityCheck(); |
} |
-#if !OS(WIN) |
-bool HTMLSelectElement::platformHandleKeydownEvent(KeyboardEvent* event) |
+void HTMLSelectElement::handlePopupOpenKeyboardEvent(Event* event) |
{ |
- if (!RenderTheme::theme().popsMenuByArrowKeys()) |
- return false; |
+ focus(); |
+ // Calling focus() may cause us to lose our renderer. Return true so |
+ // that our caller doesn't process the event further, but don't set |
+ // the event as handled. |
+ if (!renderer() || !renderer()->isMenuList() || isDisabledFormControl()) |
+ return; |
+ // Save the selection so it can be compared to the new selection |
+ // when dispatching change events during selectOption, which |
+ // gets called from RenderMenuList::valueChanged, which gets called |
+ // after the user makes a selection from the menu. |
+ saveLastSelection(); |
+ if (RenderMenuList* menuList = toRenderMenuList(renderer())) |
+ menuList->showPopup(); |
+ int index = selectedIndex(); |
+ ASSERT(index >= 0); |
+ ASSERT_WITH_SECURITY_IMPLICATION(index < static_cast<int>(listItems().size())); |
+ setSelectedIndex(index); |
+ event->setDefaultHandled(); |
+ return; |
+} |
- if (!isSpatialNavigationEnabled(document().frame())) { |
- if (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up") { |
- focus(); |
- // Calling focus() may cause us to lose our renderer. Return true so |
- // that our caller doesn't process the event further, but don't set |
- // the event as handled. |
- if (!renderer() || !renderer()->isMenuList() || isDisabledFormControl()) |
- return true; |
+bool HTMLSelectElement::shouldOpenPopupForKeyDownEvent(KeyboardEvent* keyEvent) |
+{ |
+ const String& keyIdentifier = keyEvent->keyIdentifier(); |
+ RenderTheme& renderTheme = RenderTheme::theme(); |
- // Save the selection so it can be compared to the new selection |
- // when dispatching change events during selectOption, which |
- // gets called from RenderMenuList::valueChanged, which gets called |
- // after the user makes a selection from the menu. |
- saveLastSelection(); |
- if (RenderMenuList* menuList = toRenderMenuList(renderer())) |
- menuList->showPopup(); |
- event->setDefaultHandled(); |
- } |
- return true; |
- } |
+ if (isSpatialNavigationEnabled(document().frame())) |
+ return false; |
- return false; |
+ return ((renderTheme.popsMenuByArrowKeys() && (keyIdentifier == "Down" || keyIdentifier == "Up")) |
+ || (renderTheme.popsMenuByAltDownUpOrF4Key() && (keyIdentifier == "Down" || keyIdentifier == "Up") && (keyEvent->altKey() || keyEvent->altGraphKey())) |
+ || (renderTheme.popsMenuByAltDownUpOrF4Key() && (!keyEvent->altKey() && !keyEvent->ctrlKey() && keyIdentifier == "F4"))); |
} |
-#endif |
-void HTMLSelectElement::menuListDefaultEventHandler(Event* event) |
+bool HTMLSelectElement::shouldOpenPopupForKeyPressEvent(KeyboardEvent *event) |
{ |
RenderTheme& renderTheme = RenderTheme::theme(); |
+ int keyCode = event->keyCode(); |
+ |
+ return ((renderTheme.popsMenuBySpaceKey() && event->keyCode() == ' ') |
+ || (renderTheme.popsMenuByReturnKey() && keyCode == '\r')); |
+} |
+void HTMLSelectElement::menuListDefaultEventHandler(Event* event) |
+{ |
if (event->type() == EventTypeNames::keydown) { |
if (!renderer() || !event->isKeyboardEvent()) |
return; |
- if (platformHandleKeydownEvent(toKeyboardEvent(event))) |
+ KeyboardEvent* keyEvent = toKeyboardEvent(event); |
+ if (shouldOpenPopupForKeyDownEvent(keyEvent)) { |
+ handlePopupOpenKeyboardEvent(event); |
return; |
+ } |
// When using spatial navigation, we want to be able to navigate away |
// from the select element when the user hits any of the arrow keys, |
@@ -1164,7 +1179,11 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* event) |
return; |
} |
- const String& keyIdentifier = toKeyboardEvent(event)->keyIdentifier(); |
+ // The key handling below shouldn't be used for non spatial navigation mode Mac |
+ if (RenderTheme::theme().popsMenuByArrowKeys() && !isSpatialNavigationEnabled(document().frame())) |
+ return; |
+ |
+ const String& keyIdentifier = keyEvent->keyIdentifier(); |
bool handled = true; |
const WillBeHeapVector<RawPtrWillBeMember<HTMLElement> >& listItems = this->listItems(); |
int listIndex = optionToListIndex(selectedIndex()); |
@@ -1191,15 +1210,11 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* event) |
event->setDefaultHandled(); |
} |
- // Use key press event here since sending simulated mouse events |
- // on key down blocks the proper sending of the key press event. |
if (event->type() == EventTypeNames::keypress) { |
if (!renderer() || !event->isKeyboardEvent()) |
return; |
int keyCode = toKeyboardEvent(event)->keyCode(); |
- bool handled = false; |
- |
if (keyCode == ' ' && isSpatialNavigationEnabled(document().frame())) { |
// Use space to toggle arrow key handling for selection change or spatial navigation. |
m_activeSelectionState = !m_activeSelectionState; |
@@ -1207,51 +1222,18 @@ void HTMLSelectElement::menuListDefaultEventHandler(Event* event) |
return; |
} |
- if (renderTheme.popsMenuBySpaceOrReturn()) { |
- if (keyCode == ' ' || keyCode == '\r') { |
- focus(); |
- |
- // Calling focus() may remove the renderer or change the |
- // renderer type. |
- if (!renderer() || !renderer()->isMenuList() || isDisabledFormControl()) |
- return; |
- |
- // Save the selection so it can be compared to the new selection |
- // when dispatching change events during selectOption, which |
- // gets called from RenderMenuList::valueChanged, which gets called |
- // after the user makes a selection from the menu. |
- saveLastSelection(); |
- if (RenderMenuList* menuList = toRenderMenuList(renderer())) |
- menuList->showPopup(); |
- handled = true; |
- } |
- } else if (renderTheme.popsMenuByArrowKeys()) { |
- if (keyCode == ' ') { |
- focus(); |
- |
- // Calling focus() may remove the renderer or change the |
- // renderer type. |
- if (!renderer() || !renderer()->isMenuList() || isDisabledFormControl()) |
- return; |
- |
- // Save the selection so it can be compared to the new selection |
- // when dispatching change events during selectOption, which |
- // gets called from RenderMenuList::valueChanged, which gets called |
- // after the user makes a selection from the menu. |
- saveLastSelection(); |
- if (RenderMenuList* menuList = toRenderMenuList(renderer())) |
- menuList->showPopup(); |
- handled = true; |
- } else if (keyCode == '\r') { |
- if (form()) |
- form()->submitImplicitly(event, false); |
- dispatchInputAndChangeEventForMenuList(); |
- handled = true; |
- } |
+ KeyboardEvent* keyEvent = toKeyboardEvent(event); |
+ if (shouldOpenPopupForKeyPressEvent(keyEvent)) { |
+ handlePopupOpenKeyboardEvent(event); |
+ return; |
} |
- if (handled) |
+ if (!RenderTheme::theme().popsMenuByReturnKey() && keyCode == '\r') { |
+ if (form()) |
+ form()->submitImplicitly(event, false); |
+ dispatchInputAndChangeEventForMenuList(); |
event->setDefaultHandled(); |
+ } |
} |
if (event->type() == EventTypeNames::mousedown && event->isMouseEvent() && toMouseEvent(event)->button() == LeftButton) { |