bug 860409 - Allow passing both an analog and digital value for buttons. r=smaug
authorTed Mielczarek <ted@mielczarek.org>
Tue, 09 Apr 2013 08:43:25 -0400
changeset 147178 231754e0dbcf5fd4337683bca30f20512dd1e8f2
parent 147177 7a159e3dad7b2bd0fd3d3ea1cbba55c9ced31348
child 147179 189e40137b04142bebbad382918c7805740ce2aa
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs860409
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 860409 - Allow passing both an analog and digital value for buttons. r=smaug
dom/gamepad/Gamepad.cpp
dom/gamepad/Gamepad.h
dom/gamepad/GamepadService.cpp
dom/gamepad/GamepadService.h
--- a/dom/gamepad/Gamepad.cpp
+++ b/dom/gamepad/Gamepad.cpp
@@ -27,37 +27,38 @@ Gamepad::Gamepad(nsISupports* aParent,
                  const nsAString& aID, uint32_t aIndex,
                  uint32_t aNumButtons, uint32_t aNumAxes)
   : mParent(aParent),
     mID(aID),
     mIndex(aIndex),
     mConnected(true)
 {
   SetIsDOMBinding();
-  mButtons.InsertElementsAt(0, aNumButtons, 0);
+  mButtons.InsertElementsAt(0, aNumButtons);
   mAxes.InsertElementsAt(0, aNumAxes, 0.0f);
 }
 
 void
 Gamepad::SetIndex(uint32_t aIndex)
 {
   mIndex = aIndex;
 }
 
 void
 Gamepad::SetConnected(bool aConnected)
 {
   mConnected = aConnected;
 }
 
 void
-Gamepad::SetButton(uint32_t aButton, double aValue)
+Gamepad::SetButton(uint32_t aButton, bool aPressed, double aValue)
 {
   MOZ_ASSERT(aButton < mButtons.Length());
-  mButtons[aButton] = aValue;
+  mButtons[aButton].pressed = aPressed;
+  mButtons[aButton].value = aValue;
 }
 
 void
 Gamepad::SetAxis(uint32_t aAxis, double aValue)
 {
   MOZ_ASSERT(aAxis < mAxes.Length());
   mAxes[aAxis] = aValue;
 }
@@ -73,17 +74,17 @@ Gamepad::GetButtons(nsIVariant** aButton
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     // Note: The resulting nsIVariant dupes both the array and its elements.
     double* array = reinterpret_cast<double*>
                       (NS_Alloc(mButtons.Length() * sizeof(double)));
     NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
 
     for (uint32_t i = 0; i < mButtons.Length(); ++i) {
-      array[i] = mButtons[i];
+      array[i] = mButtons[i].value;
     }
 
     nsresult rv = out->SetAsArray(nsIDataType::VTYPE_DOUBLE,
                                   nullptr,
                                   mButtons.Length(),
                                   reinterpret_cast<void*>(array));
     NS_Free(array);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/gamepad/Gamepad.h
+++ b/dom/gamepad/Gamepad.h
@@ -12,28 +12,38 @@
 #include "nsIVariant.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 
 namespace mozilla {
 namespace dom {
 
+// TODO: fix the spec to expose both pressed and value:
+// https://www.w3.org/Bugs/Public/show_bug.cgi?id=21388
+struct GamepadButton
+{
+  bool pressed;
+  double value;
+
+  GamepadButton(): pressed(false), value(0.0) {}
+};
+
 class Gamepad : public nsIDOMGamepad
               , public nsWrapperCache
 {
 public:
   Gamepad(nsISupports* aParent,
           const nsAString& aID, uint32_t aIndex,
           uint32_t aNumButtons, uint32_t aNumAxes);
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Gamepad)
 
   void SetConnected(bool aConnected);
-  void SetButton(uint32_t aButton, double aValue);
+  void SetButton(uint32_t aButton, bool aPressed, double aValue);
   void SetAxis(uint32_t aAxis, double aValue);
   void SetIndex(uint32_t aIndex);
 
   // Make the state of this gamepad equivalent to other.
   void SyncState(Gamepad* aOther);
 
   // Return a new Gamepad containing the same data as this object,
   // parented to aParent.
@@ -86,16 +96,16 @@ protected:
   nsCOMPtr<nsISupports> mParent;
   nsString mID;
   uint32_t mIndex;
 
   // true if this gamepad is currently connected.
   bool mConnected;
 
   // Current state of buttons, axes.
-  nsTArray<double> mButtons;
+  nsTArray<GamepadButton> mButtons;
   nsTArray<double> mAxes;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_gamepad_Gamepad_h
--- a/dom/gamepad/GamepadService.cpp
+++ b/dom/gamepad/GamepadService.cpp
@@ -175,22 +175,29 @@ GamepadService::RemoveGamepad(uint32_t a
       mGamepads[aIndex] = nullptr;
     }
   }
 }
 
 void
 GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed)
 {
+  // Synthesize a value: 1.0 for pressed, 0.0 for unpressed.
+  NewButtonEvent(aIndex, aButton, aPressed, aPressed ? 1.0L : 0.0L);
+}
+
+void
+GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
+                               double aValue)
+{
   if (mShuttingDown || aIndex >= mGamepads.Length()) {
     return;
   }
 
-  double value = aPressed ? 1.0L : 0.0L;
-  mGamepads[aIndex]->SetButton(aButton, value);
+  mGamepads[aIndex]->SetButton(aButton, aPressed, aValue);
 
   // Hold on to listeners in a separate array because firing events
   // can mutate the mListeners array.
   nsTArray<nsRefPtr<nsGlobalWindow> > listeners(mListeners);
 
   for (uint32_t i = listeners.Length(); i > 0 ; ) {
     --i;
 
@@ -204,19 +211,19 @@ GamepadService::NewButtonEvent(uint32_t 
       SetWindowHasSeenGamepad(listeners[i], aIndex);
       // This window hasn't seen this gamepad before, so
       // send a connection event first.
       NewConnectionEvent(aIndex, true);
     }
 
     nsRefPtr<Gamepad> gamepad = listeners[i]->GetGamepad(aIndex);
     if (gamepad) {
-      gamepad->SetButton(aButton, value);
+      gamepad->SetButton(aButton, aPressed, aValue);
       // Fire event
-      FireButtonEvent(listeners[i], gamepad, aButton, value);
+      FireButtonEvent(listeners[i], gamepad, aButton, aValue);
     }
   }
 }
 
 void
 GamepadService::FireButtonEvent(EventTarget* aTarget,
                                 Gamepad* aGamepad,
                                 uint32_t aButton,
--- a/dom/gamepad/GamepadService.h
+++ b/dom/gamepad/GamepadService.h
@@ -41,18 +41,20 @@ class GamepadService : public nsIObserve
   // Indicate that |aWindow| should no longer receive gamepad events.
   void RemoveListener(nsGlobalWindow* aWindow);
 
   // Add a gamepad to the list of known gamepads, and return its index.
   uint32_t AddGamepad(const char* aID, uint32_t aNumButtons, uint32_t aNumAxes);
   // Remove the gamepad at |aIndex| from the list of known gamepads.
   void RemoveGamepad(uint32_t aIndex);
 
-  //TODO: the spec uses double values for buttons, to allow for analog
-  // buttons.
+  // aPressed is used for digital buttons, aValue is for analog buttons.
+  void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
+                      double aValue);
+  // When only a digital button is available the value will be synthesized.
   void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
   void NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue);
 
   // Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex|
   void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad);
 
  protected:
   GamepadService();