ALT + DOWN arrow key does not open select
authorjhoneycutt@apple.com <jhoneycutt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jul 2011 23:49:53 +0000 (23:49 +0000)
committerjhoneycutt@apple.com <jhoneycutt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jul 2011 23:49:53 +0000 (23:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=14407
<rdar://problem/5319507>

Reviewed by Alexey Proskuryakov.

No test, because eventSender sends events to the WebView, rather than
the popup menu, so the popup isn't closed.

* WebCore.vcproj/WebCore.vcproj:
Add SelectElementWin.cpp to project.

* dom/SelectElement.cpp:
(WebCore::SelectElement::platformHandleKeydownEvent):
Moved ARROW_KEYS_POP_MENU code here. Updated to return whether the
function has handled the key, or whether the caller needs to process it
further.
(WebCore::SelectElement::menuListDefaultEventHandler):
Allow the platform the first chance at handling the keyboard event.

* dom/SelectElement.h:
Declare platformHandleKeydownEvent().
* dom/SelectElementWin.cpp: Added.
(WebCore::SelectElement::platformHandleKeyboardEvent):
Allow (Shift) F4 and (Ctrl/Shift) Alt/AltGr + Up/Down
arrow to show the popup. After the popup is dismissed, call
setSelectedIndex(), and report that we handled the event.

* platform/win/PopupMenuWin.cpp:
Declare HIGH_BIT_MASK_SHORT.
(WebCore::PopupMenuWin::show):
Forward WM_SYSKEYDOWN to the popup's HWND.
(WebCore::PopupMenuWin::wndProc):
Allow the same shortcuts that show the menu to hide it, matching
Firefox.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@91129 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/dom/SelectElement.cpp
Source/WebCore/dom/SelectElement.h
Source/WebCore/dom/SelectElementWin.cpp [new file with mode: 0644]
Source/WebCore/platform/win/PopupMenuWin.cpp

index 522fb7f..b3c4a04 100644 (file)
@@ -1,3 +1,42 @@
+2011-07-13  Jon Honeycutt  <jhoneycutt@apple.com>
+
+        ALT + DOWN arrow key does not open select
+
+        https://bugs.webkit.org/show_bug.cgi?id=14407
+        <rdar://problem/5319507>
+
+        Reviewed by Alexey Proskuryakov.
+
+        No test, because eventSender sends events to the WebView, rather than
+        the popup menu, so the popup isn't closed.
+
+        * WebCore.vcproj/WebCore.vcproj:
+        Add SelectElementWin.cpp to project.
+
+        * dom/SelectElement.cpp:
+        (WebCore::SelectElement::platformHandleKeydownEvent):
+        Moved ARROW_KEYS_POP_MENU code here. Updated to return whether the
+        function has handled the key, or whether the caller needs to process it
+        further.
+        (WebCore::SelectElement::menuListDefaultEventHandler):
+        Allow the platform the first chance at handling the keyboard event.
+
+        * dom/SelectElement.h:
+        Declare platformHandleKeydownEvent().
+        * dom/SelectElementWin.cpp: Added.
+        (WebCore::SelectElement::platformHandleKeyboardEvent):
+        Allow (Shift) F4 and (Ctrl/Shift) Alt/AltGr + Up/Down
+        arrow to show the popup. After the popup is dismissed, call
+        setSelectedIndex(), and report that we handled the event.
+
+        * platform/win/PopupMenuWin.cpp:
+        Declare HIGH_BIT_MASK_SHORT.
+        (WebCore::PopupMenuWin::show):
+        Forward WM_SYSKEYDOWN to the popup's HWND.
+        (WebCore::PopupMenuWin::wndProc):
+        Allow the same shortcuts that show the menu to hide it, matching
+        Firefox.
+
 2011-07-12  Jon Honeycutt  <jhoneycutt@apple.com>
 
         Ensure that a single select element's child option elements are
index 4acf0fe..c545b9f 100755 (executable)
                                >
                        </File>
                        <File
+                               RelativePath="..\dom\SelectElementWin.cpp"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\dom\SelectorNodeList.cpp"
                                >
                                <FileConfiguration
index aa9b924..e818d60 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -557,44 +558,57 @@ void SelectElement::reset(SelectElementData& data, Element* element)
     element->setNeedsStyleRecalc();
 }
 
+#if !PLATFORM(WIN)
+bool SelectElement::platformHandleKeydownEvent(SelectElementData& data, Element* element, KeyboardEvent* event)
+{
+#if ARROW_KEYS_POP_MENU
+    if (!isSpatialNavigationEnabled(element->document()->frame())) {
+        if (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up") {
+            element->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 (!element->renderer())
+                return true;
+
+            // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
+            // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
+            saveLastSelection(data, element);
+            if (RenderMenuList* menuList = toRenderMenuList(element->renderer()))
+                menuList->showPopup();
+            event->setDefaultHandled();
+        }
+        return true;
+    }
+#endif
+    return false;
+}
+#endif
+
 void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm)
 {
     if (event->type() == eventNames().keydownEvent) {
         if (!element->renderer() || !event->isKeyboardEvent())
             return;
 
-        const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
-        bool handled = false;
-
-#if ARROW_KEYS_POP_MENU
-        if (!isSpatialNavigationEnabled(element->document()->frame())) {
-            if (keyIdentifier == "Down" || keyIdentifier == "Up") {
-                element->focus();
-
-                if (!element->renderer()) // Calling focus() may cause us to lose our renderer, in which case do not want to handle the event.
-                    return;
-
-                // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
-                // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
-                saveLastSelection(data, element);
-                if (RenderMenuList* menuList = toRenderMenuList(element->renderer()))
-                    menuList->showPopup();
-
-                event->setDefaultHandled();
-            }
+        if (platformHandleKeydownEvent(data, element, static_cast<KeyboardEvent*>(event)))
             return;
-        }
-#endif
+
         // 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, instead of changing the selection.
-        if (isSpatialNavigationEnabled(element->document()->frame()))
+        if (isSpatialNavigationEnabled(element->document()->frame())) {
             if (!data.activeSelectionState())
                 return;
+        }
+
+        const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
+        bool handled = false;
 
         UNUSED_PARAM(htmlForm);
         const Vector<Element*>& listItems = data.listItems(element);
 
         int listIndex = optionToListIndex(data, element, selectedIndex(data, element));
+
         if (keyIdentifier == "Down" || keyIdentifier == "Right") {
             listIndex = nextValidIndex(listItems, listIndex, SkipForwards, 1);
             handled = true;
index cba17d4..7a26cc0 100644 (file)
@@ -106,6 +106,7 @@ protected:
  
 private:
     static void menuListDefaultEventHandler(SelectElementData&, Element*, Event*, HTMLFormElement*);
+    static bool platformHandleKeydownEvent(SelectElementData&, Element*, KeyboardEvent*);
     static void listBoxDefaultEventHandler(SelectElementData&, Element*, Event*, HTMLFormElement*);
     static void setOptionsChangedOnRenderer(SelectElementData&, Element*);
 };
diff --git a/Source/WebCore/dom/SelectElementWin.cpp b/Source/WebCore/dom/SelectElementWin.cpp
new file mode 100644 (file)
index 0000000..ec8f843
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SelectElement.h"
+
+#include "Element.h"
+#include "KeyboardEvent.h"
+#include "RenderMenuList.h"
+
+namespace WebCore {
+
+bool SelectElement::platformHandleKeydownEvent(SelectElementData& data, Element* element, KeyboardEvent* event)
+{
+    // Allow (Shift) F4 and (Ctrl/Shift) Alt/AltGr + Up/Down arrow to pop the menu, matching Firefox.
+    bool eventShowsMenu = (!event->altKey() && !event->ctrlKey() && event->keyIdentifier() == "F4")
+        || ((event->altGraphKey() || event->altKey()) && (event->keyIdentifier() == "Down" || event->keyIdentifier() == "Up"));
+    if (!eventShowsMenu)
+        return false;
+
+    // Save the selection so it can be compared to the new selection when dispatching change events during setSelectedIndex,
+    // which gets called from RenderMenuList::valueChanged, which gets called after the user makes a selection from the menu.
+    saveLastSelection(data, element);
+    if (RenderMenuList* menuList = toRenderMenuList(element->renderer()))
+        menuList->showPopup();
+
+    int index = selectedIndex(data, element);
+    ASSERT(index >= 0);
+    ASSERT(index < data.listItems(element).size());
+    setSelectedIndex(data, element, index);
+    event->setDefaultHandled();
+    return true;
+}
+
+}
index d36ac56..44a896e 100644 (file)
@@ -49,6 +49,8 @@
 #define MAKEPOINTS(l) (*((POINTS FAR *)&(l)))
 #endif
 
+#define HIGH_BIT_MASK_SHORT 0x8000
+
 using std::min;
 
 namespace WebCore {
@@ -244,6 +246,7 @@ void PopupMenuWin::show(const IntRect& r, FrameView* view, int index)
             case WM_KEYUP:
             case WM_CHAR:
             case WM_DEADCHAR:
+            case WM_SYSKEYDOWN:
             case WM_SYSKEYUP:
             case WM_SYSCHAR:
             case WM_SYSDEADCHAR:
@@ -809,17 +812,46 @@ LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
 
             break;
         }
-        case WM_KEYDOWN:
+        case WM_SYSKEYDOWN:
+        case WM_KEYDOWN: {
             if (!client())
                 break;
 
+            bool altKeyPressed = GetKeyState(VK_MENU) & HIGH_BIT_MASK_SHORT;
+            bool ctrlKeyPressed = GetKeyState(VK_CONTROL) & HIGH_BIT_MASK_SHORT;
+
             lResult = 0;
             switch (LOWORD(wParam)) {
+                case VK_F4: {
+                    if (!altKeyPressed && !ctrlKeyPressed) {
+                        int index = focusedIndex();
+                        ASSERT(index >= 0);
+                        client()->valueChanged(index);
+                        hide();
+                    }
+                    break;
+                }
                 case VK_DOWN:
+                    if (altKeyPressed) {
+                        int index = focusedIndex();
+                        ASSERT(index >= 0);
+                        client()->valueChanged(index);
+                        hide();
+                    } else
+                        down();
+                    break;
                 case VK_RIGHT:
                     down();
                     break;
                 case VK_UP:
+                    if (altKeyPressed) {
+                        int index = focusedIndex();
+                        ASSERT(index >= 0);
+                        client()->valueChanged(index);
+                        hide();
+                    } else
+                        up();
+                    break;
                 case VK_LEFT:
                     up();
                     break;
@@ -869,6 +901,7 @@ LRESULT PopupMenuWin::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPa
                     break;
             }
             break;
+        }
         case WM_CHAR: {
             if (!client())
                 break;