Gamepad support shows wrong values for PS4 controllers (D-pad is missing).
authorbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Jan 2017 19:21:39 +0000 (19:21 +0000)
committerbeidson@apple.com <beidson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 26 Jan 2017 19:21:39 +0000 (19:21 +0000)
<rdar://problem/29578619> and https://bugs.webkit.org/show_bug.cgi?id=165588

Reviewed by Alex Christensen.

No new tests (Currently unable to test HID backend directly)

DPads report their HID type as "a button", but their HID usage is "Hatswitch".
This patch adds a new element type that maps a "hatswitch" value to 4 additional buttons.

* platform/gamepad/mac/HIDGamepad.cpp:
(WebCore::HIDGamepad::initElements):
(WebCore::HIDGamepad::initElementsFromArray):
(WebCore::HIDGamepad::maybeAddButton):
(WebCore::HIDGamepad::maybeAddDPad):
(WebCore::HIDGamepad::maybeAddAxis):
(WebCore::fillInButtonValues):
(WebCore::HIDGamepad::valueChanged):

* platform/gamepad/mac/HIDGamepad.h:
(WebCore::HIDGamepadElement::isDPad):
(WebCore::HIDGamepadDPad::HIDGamepadDPad):
(WebCore::HIDGamepadDPad::normalizedValue):

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

Source/WebCore/ChangeLog
Source/WebCore/platform/gamepad/mac/HIDGamepad.cpp
Source/WebCore/platform/gamepad/mac/HIDGamepad.h

index 3e65ed3..f504c34 100644 (file)
@@ -1,3 +1,29 @@
+2017-01-26  Brady Eidson  <beidson@apple.com>
+
+        Gamepad support shows wrong values for PS4 controllers (D-pad is missing).
+        <rdar://problem/29578619> and https://bugs.webkit.org/show_bug.cgi?id=165588
+
+        Reviewed by Alex Christensen.
+
+        No new tests (Currently unable to test HID backend directly)
+
+        DPads report their HID type as "a button", but their HID usage is "Hatswitch".
+        This patch adds a new element type that maps a "hatswitch" value to 4 additional buttons.
+        
+        * platform/gamepad/mac/HIDGamepad.cpp:
+        (WebCore::HIDGamepad::initElements):
+        (WebCore::HIDGamepad::initElementsFromArray):
+        (WebCore::HIDGamepad::maybeAddButton):
+        (WebCore::HIDGamepad::maybeAddDPad):
+        (WebCore::HIDGamepad::maybeAddAxis):
+        (WebCore::fillInButtonValues):
+        (WebCore::HIDGamepad::valueChanged):
+
+        * platform/gamepad/mac/HIDGamepad.h:
+        (WebCore::HIDGamepadElement::isDPad):
+        (WebCore::HIDGamepadDPad::HIDGamepadDPad):
+        (WebCore::HIDGamepadDPad::normalizedValue):
+
 2017-01-26  Antoine Quint  <graouts@apple.com>
 
         [Modern Media Controls] Hiding controls, changing their width and showing them again shows an incorrect layout
index 837a398..d2a754c 100644 (file)
@@ -79,13 +79,16 @@ void HIDGamepad::initElements()
     });
 
     m_axisValues.resize(m_axes.size());
-    m_buttonValues.resize(m_buttons.size());
+    m_buttonValues.resize(m_buttons.size() + (m_dPads.size() * 4));
 
     for (auto& button : m_buttons)
-        getCurrentValueForElement(*button);
+        getCurrentValueForElement(button.get());
+
+    for (auto& dPad : m_dPads)
+        getCurrentValueForElement(dPad.get());
 
     for (auto& axis : m_axes)
-        getCurrentValueForElement(*axis);
+        getCurrentValueForElement(axis.get());
 }
 
 void HIDGamepad::initElementsFromArray(CFArrayRef elements)
@@ -104,8 +107,12 @@ void HIDGamepad::initElementsFromArray(CFArrayRef elements)
 
         IOHIDElementType type = IOHIDElementGetType(element);
 
-        if ((type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Button) && maybeAddButton(element))
-            continue;
+        if ((type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Button)) {
+            if (maybeAddButton(element))
+                continue;
+            if (maybeAddDPad(element))
+                continue;
+        }
 
         if ((type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis) && maybeAddAxis(element))
             continue;
@@ -128,10 +135,31 @@ bool HIDGamepad::maybeAddButton(IOHIDElementRef element)
     CFIndex min = IOHIDElementGetLogicalMin(element);
     CFIndex max = IOHIDElementGetLogicalMax(element);
 
-    m_buttons.append(std::make_unique<HIDGamepadButton>(usage, min, max, element));
+    m_buttons.append(makeUniqueRef<HIDGamepadButton>(usage, min, max, element));
 
     IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
-    m_elementMap.set(cookie, m_buttons.last().get());
+    m_elementMap.set(cookie, &m_buttons.last().get());
+
+    return true;
+}
+
+bool HIDGamepad::maybeAddDPad(IOHIDElementRef element)
+{
+    uint32_t usagePage = IOHIDElementGetUsagePage(element);
+    if (usagePage != kHIDPage_GenericDesktop)
+        return false;
+
+    uint32_t usage = IOHIDElementGetUsage(element);
+    if (!usage || usage != kHIDUsage_GD_Hatswitch)
+        return false;
+
+    CFIndex min = IOHIDElementGetLogicalMin(element);
+    CFIndex max = IOHIDElementGetLogicalMax(element);
+
+    m_dPads.append(makeUniqueRef<HIDGamepadDPad>(min, max, element));
+
+    IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
+    m_elementMap.set(cookie, &m_dPads.last().get());
 
     return true;
 }
@@ -150,14 +178,46 @@ bool HIDGamepad::maybeAddAxis(IOHIDElementRef element)
     CFIndex min = IOHIDElementGetPhysicalMin(element);
     CFIndex max = IOHIDElementGetPhysicalMax(element);
 
-    m_axes.append(std::make_unique<HIDGamepadAxis>(min, max, element));
+    m_axes.append(makeUniqueRef<HIDGamepadAxis>(min, max, element));
 
     IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
-    m_elementMap.set(cookie, m_axes.last().get());
+    m_elementMap.set(cookie, &m_axes.last().get());
 
     return true;
 }
 
+static void fillInButtonValues(int value, double& button0, double& button1, double& button2, double& button3)
+{
+    // Standard DPads have 8 possible position values, moving around a circle:
+    // 0 - Up
+    // 1 - Up + right
+    // 2 - Right
+    // 3 - Down + right
+    // 4 - Down
+    // 5 - Down + left
+    // 6 - Left
+    // 7 - Up and Left
+    // These 8 positions are mapped on to 4 button positions:
+    // 0 - Up
+    // 1 - Down
+    // 2 - Left
+    // 3 - Right
+
+    if (value < 0 || value > 7) {
+        // Handle an invalid input value that we don't know how to interpret.
+        button0 = 0.0;
+        button1 = 0.0;
+        button2 = 0.0;
+        button3 = 0.0;
+        return;
+    }
+
+    button0 = value < 2 || value == 7 ? 1.0 : 0.0;
+    button1 = value > 2 && value < 6 ? 1.0 : 0.0;
+    button2 = value > 4 ? 1.0 : 0.0;
+    button3 = value > 0 && value < 4 ? 1.0 : 0.0;
+}
+
 HIDInputType HIDGamepad::valueChanged(IOHIDValueRef value)
 {
     IOHIDElementCookie cookie = IOHIDElementGetCookie(IOHIDValueGetElement(value));
@@ -171,13 +231,30 @@ HIDInputType HIDGamepad::valueChanged(IOHIDValueRef value)
 
     if (element->isButton()) {
         for (unsigned i = 0; i < m_buttons.size(); ++i) {
-            if (m_buttons[i].get() == element)
+            if (&m_buttons[i].get() == element) {
                 m_buttonValues[i] = element->normalizedValue();
+                break;
+            }
         }
     } else if (element->isAxis()) {
         for (unsigned i = 0; i < m_axes.size(); ++i) {
-            if (m_axes[i].get() == element)
+            if (&m_axes[i].get() == element) {
                 m_axisValues[i] = element->normalizedValue();
+                break;
+            }
+        }
+    } else if (element->isDPad()) {
+        int intValue = IOHIDValueGetIntegerValue(value) - element->min;
+        for (unsigned i = 0; i < m_dPads.size(); ++i) {
+            if (&m_dPads[i].get() != element)
+                continue;
+
+            // Each DPad represents 4 button values which are tacked on to the end of the values from non-DPad buttons.
+            unsigned firstButtonValue = m_buttons.size() + i * 4;
+
+            ASSERT(m_buttonValues.size() > firstButtonValue + 3);
+
+            fillInButtonValues(intValue, m_buttonValues[firstButtonValue], m_buttonValues[firstButtonValue + 1], m_buttonValues[firstButtonValue + 2], m_buttonValues[firstButtonValue + 3]);
         }
     } else
         ASSERT_NOT_REACHED();
index 43ae749..15f04c7 100644 (file)
@@ -31,6 +31,7 @@
 #include <IOKit/hid/IOHIDDevice.h>
 #include <wtf/HashMap.h>
 #include <wtf/RetainPtr.h>
+#include <wtf/UniqueRef.h>
 
 namespace WebCore {
 
@@ -54,6 +55,7 @@ struct HIDGamepadElement {
 
     virtual bool isButton() const { return false; }
     virtual bool isAxis() const { return false; }
+    virtual bool isDPad() const { return false; }
 
     virtual double normalizedValue() = 0;
 };
@@ -67,7 +69,7 @@ struct HIDGamepadButton : HIDGamepadElement {
 
     uint32_t priority;
 
-    bool isButton() const override { return true; }
+    bool isButton() const final { return true; }
 
     // Buttons normalize to the range (0.0) - (1.0)
     double normalizedValue() override
@@ -82,7 +84,7 @@ struct HIDGamepadAxis : HIDGamepadElement {
     {
     }
 
-    bool isAxis() const override { return true; }
+    bool isAxis() const final { return true; }
 
     // Axes normalize to the range (-1.0) - (1.0)
     double normalizedValue() override
@@ -91,6 +93,17 @@ struct HIDGamepadAxis : HIDGamepadElement {
     }
 };
 
+struct HIDGamepadDPad : HIDGamepadElement {
+    HIDGamepadDPad(double min, double max, IOHIDElementRef element)
+        : HIDGamepadElement(min, max, element)
+    {
+    }
+
+    bool isDPad() const final { return true; }
+
+    virtual double normalizedValue() { RELEASE_ASSERT_NOT_REACHED(); }
+};
+
 enum class HIDInputType {
     ButtonPress,
     NotAButtonPress,
@@ -112,6 +125,7 @@ private:
     void initElementsFromArray(CFArrayRef);
 
     bool maybeAddButton(IOHIDElementRef);
+    bool maybeAddDPad(IOHIDElementRef);
     bool maybeAddAxis(IOHIDElementRef);
 
     void getCurrentValueForElement(const HIDGamepadElement&);
@@ -120,8 +134,9 @@ private:
 
     HashMap<IOHIDElementCookie, HIDGamepadElement*> m_elementMap;
 
-    Vector<std::unique_ptr<HIDGamepadButton>> m_buttons;
-    Vector<std::unique_ptr<HIDGamepadAxis>> m_axes;
+    Vector<UniqueRef<HIDGamepadButton>> m_buttons;
+    Vector<UniqueRef<HIDGamepadAxis>> m_axes;
+    Vector<UniqueRef<HIDGamepadDPad>> m_dPads;
     Vector<double> m_buttonValues;
     Vector<double> m_axisValues;
 };