diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index b944165c5a4..1f6c08f2714 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -187,6 +187,7 @@ #include "mozilla/dom/StructuredCloneTags.h" #ifdef MOZ_GAMEPAD +#include "mozilla/dom/Gamepad.h" #include "mozilla/dom/GamepadService.h" #endif @@ -13367,6 +13368,15 @@ void nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad) { MOZ_ASSERT(IsInnerWindow()); + // Create the index we will present to content based on which indices are + // already taken, as required by the spec. + // https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index + int index = 0; + while(mGamepadIndexSet.Contains(index)) { + ++index; + } + mGamepadIndexSet.Put(index); + aGamepad->SetIndex(index); mGamepads.Put(aIndex, aGamepad); } @@ -13374,6 +13384,12 @@ void nsGlobalWindow::RemoveGamepad(uint32_t aIndex) { MOZ_ASSERT(IsInnerWindow()); + nsRefPtr gamepad; + if (!mGamepads.Get(aIndex, getter_AddRefs(gamepad))) { + return; + } + // Free up the index we were using so it can be reused + mGamepadIndexSet.Remove(gamepad->Index()); mGamepads.Remove(aIndex); } @@ -13384,8 +13400,8 @@ nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData, { nsTArray >* array = static_cast >*>(aUserArg); - array->EnsureLengthAtLeast(aKey + 1); - (*array)[aKey] = aData; + array->EnsureLengthAtLeast(aData->Index() + 1); + (*array)[aData->Index()] = aData; return PL_DHASH_NEXT; } @@ -13404,6 +13420,7 @@ nsGlobalWindow::GetGamepad(uint32_t aIndex) { MOZ_ASSERT(IsInnerWindow()); nsRefPtr gamepad; + if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) { return gamepad.forget(); } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 0597ce35d1b..bdb31d9656a 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -52,6 +52,7 @@ #include "Units.h" #include "nsComponentManagerUtils.h" #include "nsSize.h" +#include "nsCheapSets.h" #define DEFAULT_HOME_PAGE "www.mozilla.org" #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage" @@ -1590,6 +1591,7 @@ protected: // Indicates whether this window wants gamepad input events bool mHasGamepad : 1; #ifdef MOZ_GAMEPAD + nsCheapSet mGamepadIndexSet; nsRefPtrHashtable mGamepads; bool mHasSeenGamepadInput; #endif diff --git a/dom/gamepad/GamepadFunctions.cpp b/dom/gamepad/GamepadFunctions.cpp new file mode 100644 index 00000000000..26693b5b997 --- /dev/null +++ b/dom/gamepad/GamepadFunctions.cpp @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/GamepadFunctions.h" +#include "mozilla/dom/GamepadService.h" +#include "nsHashKeys.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/unused.h" + +namespace mozilla { +namespace dom { +namespace GamepadFunctions { + +namespace { +// Increments as gamepads are added +uint32_t gGamepadIndex = 0; +} + +template +void +NotifyGamepadChange(const T& aInfo) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + GamepadChangeEvent e(aInfo); + nsTArray t; + ContentParent::GetAll(t); + for(uint32_t i = 0; i < t.Length(); ++i) { + unused << t[i]->SendGamepadUpdate(e); + } + // If we have a GamepadService in the main process, send directly to it. + if (GamepadService::IsServiceRunning()) { + nsRefPtr svc = GamepadService::GetService(); + svc->Update(e); + } +} + +uint32_t +AddGamepad(const char* aID, + GamepadMappingType aMapping, + uint32_t aNumButtons, uint32_t aNumAxes) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + + int index = gGamepadIndex; + gGamepadIndex++; + GamepadAdded a(NS_ConvertUTF8toUTF16(nsDependentCString(aID)), index, + (uint32_t)aMapping, aNumButtons, aNumAxes); + gGamepadIndex++; + NotifyGamepadChange(a); + return index; +} + +void +RemoveGamepad(uint32_t aIndex) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + GamepadRemoved a(aIndex); + NotifyGamepadChange(a); +} + +void +NewButtonEvent(uint32_t aIndex, uint32_t aButton, + bool aPressed, double aValue) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + GamepadButtonInformation a(aIndex, aButton, aPressed, aValue); + NotifyGamepadChange(a); +} + +void +NewButtonEvent(uint32_t aIndex, uint32_t aButton, + bool aPressed) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + // When only a digital button is available the value will be synthesized. + NewButtonEvent(aIndex, aButton, aPressed, aPressed ? 1.0L : 0.0L); +} + +void +NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, + double aValue) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + GamepadAxisInformation a(aIndex, aAxis, aValue); + NotifyGamepadChange(a); +} + +void +ResetGamepadIndexes() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + gGamepadIndex = 0; +} + +} // namespace GamepadFunctions +} // namespace dom +} // namespace mozilla diff --git a/dom/gamepad/GamepadFunctions.h b/dom/gamepad/GamepadFunctions.h new file mode 100644 index 00000000000..6ac631ce84b --- /dev/null +++ b/dom/gamepad/GamepadFunctions.h @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_GamepadFunctions_h_ +#define mozilla_dom_GamepadFunctions_h_ + +#include "mozilla/dom/GamepadBinding.h" + +namespace mozilla { +namespace dom { +namespace GamepadFunctions { + +// Functions for building and transmitting IPDL messages through the HAL +// sandbox. Used by platform specific Gamepad implementations + +// Add a gamepad to the list of known gamepads, and return its index. +uint32_t AddGamepad(const char* aID, GamepadMappingType aMapping, + uint32_t aNumButtons, uint32_t aNumAxes); +// Remove the gamepad at |aIndex| from the list of known gamepads. +void RemoveGamepad(uint32_t aIndex); + +// Update the state of |aButton| for the gamepad at |aIndex| for all +// windows that are listening and visible, and fire one of +// a gamepadbutton{up,down} event at them as well. +// 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); + +// Update the state of |aAxis| for the gamepad at |aIndex| for all +// windows that are listening and visible, and fire a gamepadaxismove +// event at them as well. +void NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue); + +// When shutting down the platform communications for gamepad, also reset the +// indexes. +void ResetGamepadIndexes(); + +} // namespace GamepadFunctions +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/gamepad/GamepadMonitoring.cpp b/dom/gamepad/GamepadMonitoring.cpp new file mode 100644 index 00000000000..be94e5e5fe7 --- /dev/null +++ b/dom/gamepad/GamepadMonitoring.cpp @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/GamepadMonitoring.h" +#include "mozilla/dom/GamepadFunctions.h" +#include "mozilla/dom/PContentParent.h" + +namespace mozilla { +namespace dom { + +using namespace GamepadFunctions; + +void +MaybeStopGamepadMonitoring() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); + nsTArray t; + ContentParent::GetAll(t); + for(uint32_t i = 0; i < t.Length(); ++i) { + if (t[i]->HasGamepadListener()) { + return; + } + } + StopGamepadMonitoring(); + ResetGamepadIndexes(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/gamepad/GamepadMonitoring.h b/dom/gamepad/GamepadMonitoring.h new file mode 100644 index 00000000000..f088aba2617 --- /dev/null +++ b/dom/gamepad/GamepadMonitoring.h @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_GamepadMonitoring_h_ +#define mozilla_dom_GamepadMonitoring_h_ + +namespace mozilla { +namespace dom { +// Functions for platform specific gamepad monitoring. + +void MaybeStopGamepadMonitoring(); + +// These two functions are implemented in the platform specific service files +// (linux/LinuxGamepad.cpp, cocoa/CocoaGamepad.cpp, etc) +void StartGamepadMonitoring(); +void StopGamepadMonitoring(); + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/gamepad/GamepadService.cpp b/dom/gamepad/GamepadService.cpp index 236c9b641bf..17f5bd25e0d 100644 --- a/dom/gamepad/GamepadService.cpp +++ b/dom/gamepad/GamepadService.cpp @@ -2,13 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "mozilla/Hal.h" +#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/Gamepad.h" +#include "mozilla/dom/GamepadAxisMoveEvent.h" +#include "mozilla/dom/GamepadButtonEvent.h" +#include "mozilla/dom/GamepadEvent.h" +#include "mozilla/dom/GamepadMonitoring.h" + #include "mozilla/ClearOnShutdown.h" #include "mozilla/Preferences.h" #include "mozilla/StaticPtr.h" -#include "GamepadService.h" -#include "Gamepad.h" #include "nsAutoPtr.h" #include "nsIDOMEvent.h" #include "nsIDOMDocument.h" @@ -20,10 +25,6 @@ #include "nsThreadUtils.h" #include "mozilla/Services.h" -#include "mozilla/dom/GamepadAxisMoveEvent.h" -#include "mozilla/dom/GamepadButtonEvent.h" -#include "mozilla/dom/GamepadEvent.h" - #include namespace mozilla { @@ -82,7 +83,11 @@ GamepadService::BeginShutdown() mTimer->Cancel(); } if (mStarted) { - mozilla::hal::StopMonitoringGamepadStatus(); + if (XRE_GetProcessType() == GeckoProcessType_Default) { + MaybeStopGamepadMonitoring(); + } else { + ContentChild::GetSingleton()->SendGamepadListenerRemoved(); + } mStarted = false; } // Don't let windows call back to unregister during shutdown @@ -99,7 +104,6 @@ GamepadService::AddListener(nsGlobalWindow* aWindow) { MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow->IsInnerWindow()); - if (mShuttingDown) { return; } @@ -109,10 +113,13 @@ GamepadService::AddListener(nsGlobalWindow* aWindow) } if (!mStarted && mEnabled) { - mozilla::hal::StartMonitoringGamepadStatus(); + if (XRE_GetProcessType() == GeckoProcessType_Default) { + StartGamepadMonitoring(); + } else { + ContentChild::GetSingleton()->SendGamepadListenerAdded(); + } mStarted = true; } - mListeners.AppendElement(aWindow); } @@ -139,8 +146,20 @@ GamepadService::RemoveListener(nsGlobalWindow* aWindow) } } -uint32_t -GamepadService::AddGamepad(const char* aId, +already_AddRefed +GamepadService::GetGamepad(uint32_t aIndex) +{ + nsRefPtr gamepad; + if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) { + return gamepad.forget(); + } + + return nullptr; +} + +void +GamepadService::AddGamepad(uint32_t aIndex, + const nsAString& aId, GamepadMappingType aMapping, uint32_t aNumButtons, uint32_t aNumAxes) @@ -148,63 +167,40 @@ GamepadService::AddGamepad(const char* aId, //TODO: bug 852258: get initial button/axis state nsRefPtr gamepad = new Gamepad(nullptr, - NS_ConvertUTF8toUTF16(nsDependentCString(aId)), - 0, + aId, + 0, // index is set by global window aMapping, aNumButtons, aNumAxes); - int index = -1; - for (uint32_t i = 0; i < mGamepads.Length(); i++) { - if (!mGamepads[i]) { - mGamepads[i] = gamepad; - index = i; - break; - } - } - if (index == -1) { - mGamepads.AppendElement(gamepad); - index = mGamepads.Length() - 1; - } - gamepad->SetIndex(index); - NewConnectionEvent(index, true); - - return index; + // We store the gamepad related to its index given by the parent process. + mGamepads.Put(aIndex, gamepad); + NewConnectionEvent(aIndex, true); } void GamepadService::RemoveGamepad(uint32_t aIndex) { - if (aIndex < mGamepads.Length()) { - mGamepads[aIndex]->SetConnected(false); - NewConnectionEvent(aIndex, false); - // If this is the last entry in the list, just remove it. - if (aIndex == mGamepads.Length() - 1) { - mGamepads.RemoveElementAt(aIndex); - } else { - // Otherwise just null it out and leave it, so the - // indices of the following entries remain valid. - mGamepads[aIndex] = nullptr; - } + nsRefPtr gamepad = GetGamepad(aIndex); + if (!gamepad) { + NS_WARNING("Trying to delete gamepad with invalid index"); + return; } -} - -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); + gamepad->SetConnected(false); + NewConnectionEvent(aIndex, false); + mGamepads.Remove(aIndex); } void GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, double aValue) { - if (mShuttingDown || aIndex >= mGamepads.Length()) { + nsRefPtr gamepad = GetGamepad(aIndex); + if (mShuttingDown || !gamepad) { return; } - mGamepads[aIndex]->SetButton(aButton, aPressed, aValue); + gamepad->SetButton(aButton, aPressed, aValue); // Hold on to listeners in a separate array because firing events // can mutate the mListeners array. @@ -227,15 +223,15 @@ GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, first_time = true; } - nsRefPtr gamepad = listeners[i]->GetGamepad(aIndex); - if (gamepad) { - gamepad->SetButton(aButton, aPressed, aValue); + nsRefPtr listenerGamepad = listeners[i]->GetGamepad(aIndex); + if (listenerGamepad) { + listenerGamepad->SetButton(aButton, aPressed, aValue); if (first_time) { - FireConnectionEvent(listeners[i], gamepad, true); + FireConnectionEvent(listeners[i], listenerGamepad, true); } if (mNonstandardEventsEnabled) { // Fire event - FireButtonEvent(listeners[i], gamepad, aButton, aValue); + FireButtonEvent(listeners[i], listenerGamepad, aButton, aValue); } } } @@ -266,10 +262,11 @@ GamepadService::FireButtonEvent(EventTarget* aTarget, void GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue) { - if (mShuttingDown || aIndex >= mGamepads.Length()) { + nsRefPtr gamepad = GetGamepad(aIndex); + if (mShuttingDown || !gamepad) { return; } - mGamepads[aIndex]->SetAxis(aAxis, aValue); + gamepad->SetAxis(aAxis, aValue); // Hold on to listeners in a separate array because firing events // can mutate the mListeners array. @@ -292,15 +289,15 @@ GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue) first_time = true; } - nsRefPtr gamepad = listeners[i]->GetGamepad(aIndex); - if (gamepad) { - gamepad->SetAxis(aAxis, aValue); + nsRefPtr listenerGamepad = listeners[i]->GetGamepad(aIndex); + if (listenerGamepad) { + listenerGamepad->SetAxis(aAxis, aValue); if (first_time) { - FireConnectionEvent(listeners[i], gamepad, true); + FireConnectionEvent(listeners[i], listenerGamepad, true); } if (mNonstandardEventsEnabled) { // Fire event - FireAxisMoveEvent(listeners[i], gamepad, aAxis, aValue); + FireAxisMoveEvent(listeners[i], listenerGamepad, aAxis, aValue); } } } @@ -332,7 +329,9 @@ GamepadService::FireAxisMoveEvent(EventTarget* aTarget, void GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected) { - if (mShuttingDown || aIndex >= mGamepads.Length()) { + nsRefPtr gamepad = GetGamepad(aIndex); + + if (mShuttingDown || !gamepad) { return; } @@ -358,10 +357,10 @@ GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected) SetWindowHasSeenGamepad(listeners[i], aIndex); - nsRefPtr gamepad = listeners[i]->GetGamepad(aIndex); - if (gamepad) { + nsRefPtr listenerGamepad = listeners[i]->GetGamepad(aIndex); + if (listenerGamepad) { // Fire event - FireConnectionEvent(listeners[i], gamepad, aConnected); + FireConnectionEvent(listeners[i], listenerGamepad, aConnected); } } } else { @@ -374,11 +373,11 @@ GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected) // deal with the hassle of syncing the state of removed gamepads. if (WindowHasSeenGamepad(listeners[i], aIndex)) { - nsRefPtr gamepad = listeners[i]->GetGamepad(aIndex); - if (gamepad) { - gamepad->SetConnected(false); + nsRefPtr listenerGamepad = listeners[i]->GetGamepad(aIndex); + if (listenerGamepad) { + listenerGamepad->SetConnected(false); // Fire event - FireConnectionEvent(listeners[i], gamepad, false); + FireConnectionEvent(listeners[i], listenerGamepad, false); listeners[i]->RemoveGamepad(aIndex); } } @@ -409,11 +408,19 @@ GamepadService::FireConnectionEvent(EventTarget* aTarget, void GamepadService::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad) { - if (mShuttingDown || !mEnabled || aIndex > mGamepads.Length()) { + nsRefPtr gamepad = GetGamepad(aIndex); + if (mShuttingDown || !mEnabled || !gamepad) { return; } - aGamepad->SyncState(mGamepads[aIndex]); + aGamepad->SyncState(gamepad); +} + +// static +bool +GamepadService::IsServiceRunning() +{ + return !!gGamepadServiceSingleton; } // static @@ -461,8 +468,13 @@ GamepadService::SetWindowHasSeenGamepad(nsGlobalWindow* aWindow, if (aHasSeen) { aWindow->SetHasSeenGamepadInput(true); nsCOMPtr window = ToSupports(aWindow); - nsRefPtr gamepad = mGamepads[aIndex]->Clone(window); - aWindow->AddGamepad(aIndex, gamepad); + nsRefPtr gamepad = GetGamepad(aIndex); + MOZ_ASSERT(gamepad); + if (!gamepad) { + return; + } + nsRefPtr clonedGamepad = gamepad->Clone(window); + aWindow->AddGamepad(aIndex, clonedGamepad); } else { aWindow->RemoveGamepad(aIndex); } @@ -486,13 +498,16 @@ GamepadService::TimeoutHandler(nsITimer* aTimer, void* aClosure) } if (self->mListeners.Length() == 0) { - mozilla::hal::StopMonitoringGamepadStatus(); + if (XRE_GetProcessType() == GeckoProcessType_Default) { + MaybeStopGamepadMonitoring(); + } else { + ContentChild::GetSingleton()->SendGamepadListenerRemoved(); + } + self->mStarted = false; - if (!self->mGamepads.IsEmpty()) { self->mGamepads.Clear(); } } -} void GamepadService::StartCleanupTimer() @@ -510,71 +525,26 @@ GamepadService::StartCleanupTimer() } } -/* - * Implementation of the test service. This is just to provide a simple binding - * of the GamepadService to JavaScript via XPCOM so that we can write Mochitests - * that add and remove fake gamepads, avoiding the platform-specific backends. - */ -NS_IMPL_ISUPPORTS(GamepadServiceTest, nsIGamepadServiceTest) - -GamepadServiceTest* GamepadServiceTest::sSingleton = nullptr; - -// static -already_AddRefed -GamepadServiceTest::CreateService() +void +GamepadService::Update(const GamepadChangeEvent& aEvent) { - if (sSingleton == nullptr) { - sSingleton = new GamepadServiceTest(); + if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) { + const GamepadAdded& a = aEvent.get_GamepadAdded(); + AddGamepad(a.index(), a.id(), + static_cast(a.mapping()), + a.num_buttons(), a.num_axes()); + } else if (aEvent.type() == GamepadChangeEvent::TGamepadRemoved) { + const GamepadRemoved& a = aEvent.get_GamepadRemoved(); + RemoveGamepad(a.index()); + } else if (aEvent.type() == GamepadChangeEvent::TGamepadButtonInformation) { + const GamepadButtonInformation& a = aEvent.get_GamepadButtonInformation(); + NewButtonEvent(a.index(), a.button(), a.pressed(), a.value()); + } else if (aEvent.type() == GamepadChangeEvent::TGamepadAxisInformation) { + const GamepadAxisInformation& a = aEvent.get_GamepadAxisInformation(); + NewAxisMoveEvent(a.index(), a.axis(), a.value()); + } else { + MOZ_CRASH("We shouldn't be here!"); } - nsRefPtr service = sSingleton; - return service.forget(); -} - -GamepadServiceTest::GamepadServiceTest() -{ - /* member initializers and constructor code */ - nsRefPtr service = GamepadService::GetService(); -} - -/* uint32_t addGamepad (in string id, in unsigned long mapping, in unsigned long numButtons, in unsigned long numAxes); */ -NS_IMETHODIMP GamepadServiceTest::AddGamepad(const char* aID, - uint32_t aMapping, - uint32_t aNumButtons, - uint32_t aNumAxes, - uint32_t* aRetval) -{ - *aRetval = gGamepadServiceSingleton->AddGamepad(aID, - static_cast(aMapping), - aNumButtons, - aNumAxes); - return NS_OK; -} - -/* void removeGamepad (in uint32_t index); */ -NS_IMETHODIMP GamepadServiceTest::RemoveGamepad(uint32_t aIndex) -{ - gGamepadServiceSingleton->RemoveGamepad(aIndex); - return NS_OK; -} - -/* void newButtonEvent (in uint32_t index, in uint32_t button, - in boolean pressed); */ -NS_IMETHODIMP GamepadServiceTest::NewButtonEvent(uint32_t aIndex, - uint32_t aButton, - bool aPressed) -{ - gGamepadServiceSingleton->NewButtonEvent(aIndex, aButton, aPressed); - return NS_OK; -} - -/* void newAxisMoveEvent (in uint32_t index, in uint32_t axis, - in double value); */ -NS_IMETHODIMP GamepadServiceTest::NewAxisMoveEvent(uint32_t aIndex, - uint32_t aAxis, - double aValue) -{ - gGamepadServiceSingleton->NewAxisMoveEvent(aIndex, aAxis, aValue); - return NS_OK; } } // namespace dom diff --git a/dom/gamepad/GamepadService.h b/dom/gamepad/GamepadService.h index 29e44c0325b..77060c93c87 100644 --- a/dom/gamepad/GamepadService.h +++ b/dom/gamepad/GamepadService.h @@ -6,7 +6,6 @@ #define mozilla_dom_GamepadService_h_ #include -#include "Gamepad.h" #include "nsAutoPtr.h" #include "nsCOMArray.h" #include "nsIGamepadServiceTest.h" @@ -15,11 +14,14 @@ #include "nsIObserver.h" #include "nsITimer.h" #include "nsTArray.h" - +// Needed for GamepadMappingType +#include "mozilla/dom/GamepadBinding.h" namespace mozilla { namespace dom { class EventTarget; +class GamepadChangeEvent; +class Gamepad; class GamepadService : public nsIObserver { @@ -27,6 +29,8 @@ class GamepadService : public nsIObserver NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER + // Returns true if we actually have a service up and running + static bool IsServiceRunning(); // Get the singleton service static already_AddRefed GetService(); // Return true if the API is preffed on. @@ -39,9 +43,10 @@ class GamepadService : public nsIObserver // 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, GamepadMappingType aMapping, + // Add a gamepad to the list of known gamepads. + void AddGamepad(uint32_t aIndex, const nsAString& aID, GamepadMappingType aMapping, uint32_t aNumButtons, uint32_t aNumAxes); + // Remove the gamepad at |aIndex| from the list of known gamepads. void RemoveGamepad(uint32_t aIndex); @@ -51,8 +56,6 @@ class GamepadService : public nsIObserver // 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); // Update the state of |aAxis| for the gamepad at |aIndex| for all // windows that are listening and visible, and fire a gamepadaxismove @@ -62,6 +65,11 @@ class GamepadService : public nsIObserver // Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex| void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad); + // Returns gamepad object if index exists, null otherwise + already_AddRefed GetGamepad(uint32_t aIndex); + + // Receive GamepadChangeEvent messages from parent process to fire DOM events + void Update(const GamepadChangeEvent& aGamepadEvent); protected: GamepadService(); virtual ~GamepadService() {}; @@ -115,37 +123,13 @@ class GamepadService : public nsIObserver // Gamepads connected to the system. Copies of these are handed out // to each window. - nsTArray > mGamepads; + nsRefPtrHashtable mGamepads; // Inner windows that are listening for gamepad events. // has been sent to that window. nsTArray > mListeners; nsCOMPtr mTimer; - nsCOMPtr mFocusManager; - nsCOMPtr mObserver; -}; - -// Service for testing purposes -class GamepadServiceTest : public nsIGamepadServiceTest -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIGAMEPADSERVICETEST - - GamepadServiceTest(); - - static already_AddRefed CreateService(); - -private: - static GamepadServiceTest* sSingleton; - virtual ~GamepadServiceTest() {}; }; } // namespace dom } // namespace mozilla - -#define NS_GAMEPAD_TEST_CID \ -{ 0xfb1fcb57, 0xebab, 0x4cf4, \ -{ 0x96, 0x3b, 0x1e, 0x4d, 0xb8, 0x52, 0x16, 0x96 } } -#define NS_GAMEPAD_TEST_CONTRACTID "@mozilla.org/gamepad-test;1" - #endif // mozilla_dom_GamepadService_h_ diff --git a/dom/gamepad/GamepadServiceTest.cpp b/dom/gamepad/GamepadServiceTest.cpp new file mode 100644 index 00000000000..086408aa186 --- /dev/null +++ b/dom/gamepad/GamepadServiceTest.cpp @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "GamepadServiceTest.h" +#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/GamepadFunctions.h" + +using namespace mozilla::dom; + +/* + * Implementation of the test service. This is just to provide a simple binding + * of the GamepadService to JavaScript via XPCOM so that we can write Mochitests + * that add and remove fake gamepads, avoiding the platform-specific backends. + */ +NS_IMPL_ISUPPORTS(GamepadServiceTest, nsIGamepadServiceTest) + +GamepadServiceTest* GamepadServiceTest::sSingleton = nullptr; + +// static +already_AddRefed +GamepadServiceTest::CreateService() +{ + if (sSingleton == nullptr) { + sSingleton = new GamepadServiceTest(); + } + nsRefPtr service = sSingleton; + return service.forget(); +} + +GamepadServiceTest::GamepadServiceTest() : + mService(GamepadService::GetService()) +{ +} + +GamepadServiceTest::~GamepadServiceTest() +{ +} + +/* uint32_t addGamepad(in unsigned long index, in string id, in unsigned long mapping, in unsigned long numButtons, in unsigned long numAxes); */ +NS_IMETHODIMP +GamepadServiceTest::AddGamepad(const char* aID, + uint32_t aMapping, + uint32_t aNumButtons, + uint32_t aNumAxes, + uint32_t* aGamepadIndex) +{ + *aGamepadIndex = GamepadFunctions::AddGamepad(aID, + static_cast(aMapping), + aNumButtons, + aNumAxes); + return NS_OK; +} + +/* void removeGamepad (in uint32_t index); */ +NS_IMETHODIMP GamepadServiceTest::RemoveGamepad(uint32_t aIndex) +{ + GamepadFunctions::RemoveGamepad(aIndex); + return NS_OK; +} + +/* void newButtonEvent (in uint32_t index, in uint32_t button, + in boolean pressed); */ +NS_IMETHODIMP GamepadServiceTest::NewButtonEvent(uint32_t aIndex, + uint32_t aButton, + bool aPressed) +{ + GamepadFunctions::NewButtonEvent(aIndex, aButton, aPressed); + return NS_OK; +} + +/* void newButtonEvent (in uint32_t index, in uint32_t button, + in boolean pressed, double value); */ +NS_IMETHODIMP GamepadServiceTest::NewButtonValueEvent(uint32_t aIndex, + uint32_t aButton, + bool aPressed, + double aValue) +{ + GamepadFunctions::NewButtonEvent(aIndex, aButton, aPressed, aValue); + return NS_OK; +} + +/* void newAxisMoveEvent (in uint32_t index, in uint32_t axis, + in double value); */ +NS_IMETHODIMP GamepadServiceTest::NewAxisMoveEvent(uint32_t aIndex, + uint32_t aAxis, + double aValue) +{ + GamepadFunctions::NewAxisMoveEvent(aIndex, aAxis, aValue); + return NS_OK; +} + diff --git a/dom/gamepad/GamepadServiceTest.h b/dom/gamepad/GamepadServiceTest.h new file mode 100644 index 00000000000..1df45932c18 --- /dev/null +++ b/dom/gamepad/GamepadServiceTest.h @@ -0,0 +1,42 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_GamepadServiceTest_h_ +#define mozilla_dom_GamepadServiceTest_h_ + +#include "nsIGamepadServiceTest.h" + +namespace mozilla { +namespace dom { + +class GamepadService; + +// Service for testing purposes +class GamepadServiceTest : public nsIGamepadServiceTest +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIGAMEPADSERVICETEST + + GamepadServiceTest(); + + static already_AddRefed CreateService(); + +private: + static GamepadServiceTest* sSingleton; + // Hold a reference to the gamepad service so we don't have to worry about + // execution order in tests. + nsRefPtr mService; + virtual ~GamepadServiceTest(); +}; + +} // namespace dom +} // namespace mozilla + +#define NS_GAMEPAD_TEST_CID \ +{ 0xfb1fcb57, 0xebab, 0x4cf4, \ +{ 0x96, 0x3b, 0x1e, 0x4d, 0xb8, 0x52, 0x16, 0x96 } } +#define NS_GAMEPAD_TEST_CONTRACTID "@mozilla.org/gamepad-test;1" + +#endif diff --git a/hal/android/AndroidGamepad.cpp b/dom/gamepad/android/AndroidGamepad.cpp similarity index 72% rename from hal/android/AndroidGamepad.cpp rename to dom/gamepad/android/AndroidGamepad.cpp index b29df02ae5d..75e60bc9b92 100644 --- a/hal/android/AndroidGamepad.cpp +++ b/dom/gamepad/android/AndroidGamepad.cpp @@ -3,25 +3,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "Hal.h" #include "AndroidBridge.h" -using namespace mozilla::hal; - namespace mozilla { -namespace hal_impl { +namespace dom { -void -StartMonitoringGamepadStatus() +void StartGamepadMonitoring() { widget::GeckoAppShell::StartMonitoringGamepad(); } -void -StopMonitoringGamepadStatus() +void StopGamepadMonitoring() { widget::GeckoAppShell::StopMonitoringGamepad(); } -} // hal_impl -} // mozilla +} // namespace dom +} // namespace mozilla diff --git a/hal/cocoa/CocoaGamepad.cpp b/dom/gamepad/cocoa/CocoaGamepad.cpp similarity index 93% rename from hal/cocoa/CocoaGamepad.cpp rename to dom/gamepad/cocoa/CocoaGamepad.cpp index 67e40183391..454d5fc1850 100644 --- a/hal/cocoa/CocoaGamepad.cpp +++ b/dom/gamepad/cocoa/CocoaGamepad.cpp @@ -6,7 +6,8 @@ // mostly derived from the Allegro source code at: // http://alleg.svn.sourceforge.net/viewvc/alleg/allegro/branches/4.9/src/macosx/hidjoy.m?revision=13760&view=markup -#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/GamepadFunctions.h" +#include "mozilla/ArrayUtils.h" #include #include #include @@ -17,8 +18,8 @@ namespace { -using mozilla::dom::GamepadService; - +using namespace mozilla; +using namespace mozilla::dom::GamepadFunctions; using std::vector; struct Button { @@ -248,20 +249,18 @@ DarwinGamepadService::DeviceAdded(IOHIDDeviceRef device) sizeof(product_name), kCFStringEncodingASCII); char buffer[256]; sprintf(buffer, "%x-%x-%s", vendorId, productId, product_name); - nsRefPtr service(GamepadService::GetService()); - mGamepads[slot].mSuperIndex = service->AddGamepad(buffer, - mozilla::dom::GamepadMappingType::_empty, - (int)mGamepads[slot].numButtons(), - (int)mGamepads[slot].numAxes()); + mGamepads[slot].mSuperIndex = AddGamepad(buffer, + mozilla::dom::GamepadMappingType::_empty, + (int)mGamepads[slot].numButtons(), + (int)mGamepads[slot].numAxes()); } void DarwinGamepadService::DeviceRemoved(IOHIDDeviceRef device) { - nsRefPtr service(GamepadService::GetService()); for (size_t i = 0; i < mGamepads.size(); i++) { if (mGamepads[i] == device) { - service->RemoveGamepad(mGamepads[i].mSuperIndex); + RemoveGamepad(mGamepads[i].mSuperIndex); mGamepads[i].clear(); return; } @@ -316,7 +315,6 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value) // massive (30+ byte) values and crash IOHIDValueGetIntegerValue return; } - nsRefPtr service(GamepadService::GetService()); IOHIDElementRef element = IOHIDValueGetElement(value); IOHIDDeviceRef device = IOHIDElementGetDevice(element); for (unsigned i = 0; i < mGamepads.size(); i++) { @@ -332,7 +330,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value) const int numButtons = gamepad.numButtons(); for (unsigned b = 0; b < ArrayLength(newState); b++) { if (newState[b] != oldState[b]) { - service->NewButtonEvent(i, numButtons - 4 + b, newState[b]); + NewButtonEvent(i, numButtons - 4 + b, newState[b]); } } gamepad.setDpadState(newState); @@ -340,7 +338,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value) double d = IOHIDValueGetIntegerValue(value); double v = 2.0f * (d - axis->min) / (double)(axis->max - axis->min) - 1.0f; - service->NewAxisMoveEvent(i, axis->id, v); + NewAxisMoveEvent(i, axis->id, v); } else if (const Button* button = gamepad.lookupButton(element)) { int iv = IOHIDValueGetIntegerValue(value); bool pressed = iv != 0; @@ -351,7 +349,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value) } else { v = pressed ? 1.0 : 0.0; } - service->NewButtonEvent(i, button->id, pressed, v); + NewButtonEvent(i, button->id, pressed, v); } return; } @@ -495,28 +493,30 @@ void DarwinGamepadService::Shutdown() } // namespace namespace mozilla { -namespace hal_impl { +namespace dom { DarwinGamepadService* gService = nullptr; -void StartMonitoringGamepadStatus() +void StartGamepadMonitoring() { - if (gService) + if (gService) { return; + } gService = new DarwinGamepadService(); gService->Startup(); } -void StopMonitoringGamepadStatus() +void StopGamepadMonitoring() { - if (!gService) + if (!gService) { return; + } gService->Shutdown(); delete gService; gService = nullptr; } -} // namespace hal_impl +} // namespace dom } // namespace mozilla diff --git a/hal/fallback/FallbackGamepad.cpp b/dom/gamepad/fallback/FallbackGamepad.cpp similarity index 74% rename from hal/fallback/FallbackGamepad.cpp rename to dom/gamepad/fallback/FallbackGamepad.cpp index b6c8190d2af..ba8a1fe2449 100644 --- a/hal/fallback/FallbackGamepad.cpp +++ b/dom/gamepad/fallback/FallbackGamepad.cpp @@ -4,16 +4,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "Hal.h" namespace mozilla { -namespace hal_impl { +namespace dom { -void StartMonitoringGamepadStatus() -{} +void StartGamepadMonitoring() +{ +} -void StopMonitoringGamepadStatus() -{} +void StopGamepadMonitoring() +{ +} -} // hal_impl +} // namespace dom } // namespace mozilla diff --git a/hal/linux/LinuxGamepad.cpp b/dom/gamepad/linux/LinuxGamepad.cpp similarity index 89% rename from hal/linux/LinuxGamepad.cpp rename to dom/gamepad/linux/LinuxGamepad.cpp index 4f0c0a3db7f..56395066760 100644 --- a/hal/linux/LinuxGamepad.cpp +++ b/dom/gamepad/linux/LinuxGamepad.cpp @@ -16,14 +16,13 @@ #include #include #include - #include "nscore.h" -#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/GamepadFunctions.h" #include "udev.h" namespace { -using mozilla::dom::GamepadService; +using namespace mozilla::dom::GamepadFunctions; using mozilla::udev_lib; using mozilla::udev_device; using mozilla::udev_list_entry; @@ -138,11 +137,10 @@ LinuxGamepadService::AddDevice(struct udev_device* dev) ioctl(fd, JSIOCGBUTTONS, &numButtons); gamepad.numButtons = numButtons; - nsRefPtr service(GamepadService::GetService()); - gamepad.index = service->AddGamepad(gamepad.idstring, - mozilla::dom::GamepadMappingType::_empty, - gamepad.numButtons, - gamepad.numAxes); + gamepad.index = AddGamepad(gamepad.idstring, + mozilla::dom::GamepadMappingType::_empty, + gamepad.numButtons, + gamepad.numAxes); gamepad.source_id = g_io_add_watch(channel, @@ -162,11 +160,10 @@ LinuxGamepadService::RemoveDevice(struct udev_device* dev) return; } - nsRefPtr service(GamepadService::GetService()); for (unsigned int i = 0; i < mGamepads.Length(); i++) { if (strcmp(mGamepads[i].devpath, devpath) == 0) { g_source_remove(mGamepads[i].source_id); - service->RemoveGamepad(mGamepads[i].index); + RemoveGamepad(mGamepads[i].index); mGamepads.RemoveElementAt(i); break; } @@ -319,14 +316,13 @@ LinuxGamepadService::OnGamepadData(GIOChannel* source, continue; } - nsRefPtr service(GamepadService::GetService()); switch (event.type) { case JS_EVENT_BUTTON: - service->NewButtonEvent(index, event.number, !!event.value); + NewButtonEvent(index, event.number, !!event.value); break; case JS_EVENT_AXIS: - service->NewAxisMoveEvent(index, event.number, - ((float)event.value) / kMaxAxisValue); + NewAxisMoveEvent(index, event.number, + ((float)event.value) / kMaxAxisValue); break; } } @@ -350,24 +346,26 @@ LinuxGamepadService::OnUdevMonitor(GIOChannel* source, } // namespace namespace mozilla { -namespace hal_impl { +namespace dom { -void StartMonitoringGamepadStatus() -{ - if (!gService) { - gService = new LinuxGamepadService(); - gService->Startup(); - } -} - -void StopMonitoringGamepadStatus() +void StartGamepadMonitoring() { if (gService) { - gService->Shutdown(); - delete gService; - gService = nullptr; + return; } + gService = new LinuxGamepadService(); + gService->Startup(); } -} // namespace hal_impl +void StopGamepadMonitoring() +{ + if (!gService) { + return; + } + gService->Shutdown(); + delete gService; + gService = nullptr; +} + +} // namespace dom } // namespace mozilla diff --git a/hal/linux/udev.h b/dom/gamepad/linux/udev.h similarity index 100% rename from hal/linux/udev.h rename to dom/gamepad/linux/udev.h diff --git a/dom/gamepad/moz.build b/dom/gamepad/moz.build index 078707140c4..d4676c56658 100644 --- a/dom/gamepad/moz.build +++ b/dom/gamepad/moz.build @@ -7,13 +7,40 @@ EXPORTS.mozilla.dom += [ 'Gamepad.h', 'GamepadButton.h', + 'GamepadFunctions.h', + 'GamepadMonitoring.h', 'GamepadService.h', + 'GamepadServiceTest.h' ] UNIFIED_SOURCES = [ 'Gamepad.cpp', 'GamepadButton.cpp', + 'GamepadFunctions.cpp', + 'GamepadMonitoring.cpp', 'GamepadService.cpp', + 'GamepadServiceTest.cpp' + ] + +if CONFIG['MOZ_GAMEPAD_BACKEND'] == 'stub': + UNIFIED_SOURCES += [ + 'fallback/FallbackGamepad.cpp' + ] +elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'cocoa': + UNIFIED_SOURCES += [ + 'cocoa/CocoaGamepad.cpp' + ] +elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'windows': + UNIFIED_SOURCES += [ + 'windows/WindowsGamepad.cpp' + ] +elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'linux': + UNIFIED_SOURCES += [ + 'linux/LinuxGamepad.cpp' + ] +elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'android': + UNIFIED_SOURCES += [ + 'android/AndroidGamepad.cpp' ] FAIL_ON_WARNINGS = True @@ -25,3 +52,7 @@ LOCAL_INCLUDES += [ '/dom/base', ] +CFLAGS += CONFIG['GLIB_CFLAGS'] +CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] +CXXFLAGS += CONFIG['GLIB_CFLAGS'] +CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] diff --git a/hal/windows/WindowsGamepad.cpp b/dom/gamepad/windows/WindowsGamepad.cpp similarity index 92% rename from hal/windows/WindowsGamepad.cpp rename to dom/gamepad/windows/WindowsGamepad.cpp index 3419971d090..f76b58d1f13 100644 --- a/hal/windows/WindowsGamepad.cpp +++ b/dom/gamepad/windows/WindowsGamepad.cpp @@ -20,12 +20,13 @@ #include "nsITimer.h" #include "nsTArray.h" #include "mozilla/ArrayUtils.h" -#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/GamepadFunctions.h" #include "mozilla/Services.h" namespace { using namespace mozilla::dom; +using namespace mozilla::dom::GamepadFunctions; using mozilla::ArrayLength; // USB HID usage tables, page 1 (Hat switch) @@ -455,11 +456,6 @@ WindowsGamepadService::ScanForXInputDevices() { MOZ_ASSERT(mXInput, "XInput should be present!"); - nsRefPtr gamepadsvc(GamepadService::GetService()); - if (!gamepadsvc) { - return false; - } - bool found = false; for (int i = 0; i < XUSER_MAX_COUNT; i++) { XINPUT_STATE state = {}; @@ -480,10 +476,10 @@ WindowsGamepadService::ScanForXInputDevices() gamepad.userIndex = i; gamepad.numButtons = kStandardGamepadButtons; gamepad.numAxes = kStandardGamepadAxes; - gamepad.id = gamepadsvc->AddGamepad("xinput", - GamepadMappingType::Standard, - kStandardGamepadButtons, - kStandardGamepadAxes); + gamepad.id = AddGamepad("xinput", + GamepadMappingType::Standard, + kStandardGamepadButtons, + kStandardGamepadAxes); mGamepads.AppendElement(gamepad); } @@ -510,14 +506,10 @@ WindowsGamepadService::ScanForDevices() } } - nsRefPtr gamepadsvc(GamepadService::GetService()); - if (!gamepadsvc) { - return; - } // Look for devices that are no longer present and remove them. for (int i = mGamepads.Length() - 1; i >= 0; i--) { if (!mGamepads[i].present) { - gamepadsvc->RemoveGamepad(mGamepads[i].id); + RemoveGamepad(mGamepads[i].id); mGamepads.RemoveElementAt(i); } } @@ -552,17 +544,16 @@ WindowsGamepadService::PollXInput() void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad, XINPUT_STATE& state) { - nsRefPtr gamepadsvc(GamepadService::GetService()); // Handle digital buttons first for (size_t b = 0; b < kNumMappings; b++) { if (state.Gamepad.wButtons & kXIButtonMap[b].button && !(gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button)) { // Button pressed - gamepadsvc->NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, true); + NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, true); } else if (!(state.Gamepad.wButtons & kXIButtonMap[b].button) && gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button) { // Button released - gamepadsvc->NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, false); + NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, false); } } @@ -570,33 +561,33 @@ void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad, if (state.Gamepad.bLeftTrigger != gamepad.state.Gamepad.bLeftTrigger) { bool pressed = state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; - gamepadsvc->NewButtonEvent(gamepad.id, kButtonLeftTrigger, - pressed, state.Gamepad.bLeftTrigger / 255.0); + NewButtonEvent(gamepad.id, kButtonLeftTrigger, + pressed, state.Gamepad.bLeftTrigger / 255.0); } if (state.Gamepad.bRightTrigger != gamepad.state.Gamepad.bRightTrigger) { bool pressed = state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; - gamepadsvc->NewButtonEvent(gamepad.id, kButtonRightTrigger, - pressed, state.Gamepad.bRightTrigger / 255.0); + NewButtonEvent(gamepad.id, kButtonRightTrigger, + pressed, state.Gamepad.bRightTrigger / 255.0); } // Finally deal with analog sticks // TODO: bug 1001955 - Support deadzones. if (state.Gamepad.sThumbLX != gamepad.state.Gamepad.sThumbLX) { - gamepadsvc->NewAxisMoveEvent(gamepad.id, kLeftStickXAxis, - state.Gamepad.sThumbLX / 32767.0); + NewAxisMoveEvent(gamepad.id, kLeftStickXAxis, + state.Gamepad.sThumbLX / 32767.0); } if (state.Gamepad.sThumbLY != gamepad.state.Gamepad.sThumbLY) { - gamepadsvc->NewAxisMoveEvent(gamepad.id, kLeftStickYAxis, - -1.0 * state.Gamepad.sThumbLY / 32767.0); + NewAxisMoveEvent(gamepad.id, kLeftStickYAxis, + -1.0 * state.Gamepad.sThumbLY / 32767.0); } if (state.Gamepad.sThumbRX != gamepad.state.Gamepad.sThumbRX) { - gamepadsvc->NewAxisMoveEvent(gamepad.id, kRightStickXAxis, - state.Gamepad.sThumbRX / 32767.0); + NewAxisMoveEvent(gamepad.id, kRightStickXAxis, + state.Gamepad.sThumbRX / 32767.0); } if (state.Gamepad.sThumbRY != gamepad.state.Gamepad.sThumbRY) { - gamepadsvc->NewAxisMoveEvent(gamepad.id, kRightStickYAxis, - -1.0 * state.Gamepad.sThumbRY / 32767.0); + NewAxisMoveEvent(gamepad.id, kRightStickYAxis, + -1.0 * state.Gamepad.sThumbRY / 32767.0); } gamepad.state = state; } @@ -757,15 +748,10 @@ WindowsGamepadService::GetRawGamepad(HANDLE handle) gamepad.handle = handle; gamepad.present = true; - nsRefPtr gamepadsvc(GamepadService::GetService()); - if (!gamepadsvc) { - return false; - } - - gamepad.id = gamepadsvc->AddGamepad(gamepad_id, - GamepadMappingType::_empty, - gamepad.numButtons, - gamepad.numAxes); + gamepad.id = GamepadFunctions::AddGamepad(gamepad_id, + GamepadMappingType::_empty, + gamepad.numButtons, + gamepad.numAxes); mGamepads.AppendElement(gamepad); return true; } @@ -776,10 +762,6 @@ WindowsGamepadService::HandleRawInput(HRAWINPUT handle) if (!mHID) { return false; } - nsRefPtr gamepadsvc(GamepadService::GetService()); - if (!gamepadsvc) { - return false; - } // First, get data from the handle UINT size; @@ -838,7 +820,7 @@ WindowsGamepadService::HandleRawInput(HRAWINPUT handle) for (unsigned i = 0; i < gamepad->numButtons; i++) { if (gamepad->buttons[i] != buttons[i]) { - gamepadsvc->NewButtonEvent(gamepad->id, i, buttons[i]); + NewButtonEvent(gamepad->id, i, buttons[i]); gamepad->buttons[i] = buttons[i]; } } @@ -872,7 +854,7 @@ LONG value; gamepad->axes[i].caps.LogicalMax); } if (gamepad->axes[i].value != new_value) { - gamepadsvc->NewAxisMoveEvent(gamepad->id, i, new_value); + NewAxisMoveEvent(gamepad->id, i, new_value); gamepad->axes[i].value = new_value; } } @@ -977,9 +959,9 @@ GamepadWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } // namespace namespace mozilla { -namespace hal_impl { +namespace dom { -void StartMonitoringGamepadStatus() +void StartGamepadMonitoring() { if (gService) { return; @@ -1007,7 +989,7 @@ void StartMonitoringGamepadStatus() } } -void StopMonitoringGamepadStatus() +void StopGamepadMonitoring() { if (!gService) { return; @@ -1024,6 +1006,6 @@ void StopMonitoringGamepadStatus() gService = nullptr; } -} // namespace hal_impl +} // namespace dom } // namespace mozilla diff --git a/dom/interfaces/gamepad/nsIGamepadServiceTest.idl b/dom/interfaces/gamepad/nsIGamepadServiceTest.idl index 48f1dfd655f..170d2366b11 100644 --- a/dom/interfaces/gamepad/nsIGamepadServiceTest.idl +++ b/dom/interfaces/gamepad/nsIGamepadServiceTest.idl @@ -9,18 +9,21 @@ interface nsIVariant; /* * This interface is intended only for use in tests. */ -[scriptable, uuid(b6ed093c-6ea0-4141-a8eb-f99645162651)] +[scriptable, uuid(c03ec4ed-8a7e-40e7-99da-c609f1760d0c)] interface nsIGamepadServiceTest : nsISupports { const unsigned long NO_MAPPING = 0; const unsigned long STANDARD_MAPPING = 1; - unsigned long addGamepad(in string id, in unsigned long mapping, + unsigned long addGamepad(in string id, + in unsigned long mapping, in unsigned long numButtons, in unsigned long numAxes); void removeGamepad(in unsigned long index); void newButtonEvent(in unsigned long index, in unsigned long button, in boolean pressed); + void newButtonValueEvent(in unsigned long index, in unsigned long button, + in boolean pressed, in double value); void newAxisMoveEvent(in unsigned long index, in unsigned long axis, in double value); }; diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 2c63c88aa35..3cadcba5806 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -155,6 +155,10 @@ #include "ipc/Nuwa.h" #endif +#ifdef MOZ_GAMEPAD +#include "mozilla/dom/GamepadService.h" +#endif + #include "mozilla/dom/File.h" #include "mozilla/dom/cellbroadcast/CellBroadcastIPCService.h" #include "mozilla/dom/icc/IccChild.h" @@ -2775,6 +2779,18 @@ ContentChild::DeallocPContentPermissionRequestChild(PContentPermissionRequestChi return true; } +bool +ContentChild::RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) +{ +#ifdef MOZ_GAMEPAD + nsRefPtr svc(GamepadService::GetService()); + if (svc) { + svc->Update(aGamepadEvent); + } +#endif + return true; +} + // This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp // can't include ContentChild.h since it includes windows.h. diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index bb2d8d999a4..5e36150b43b 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -464,6 +464,8 @@ public: virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) override; + virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override; + private: virtual void ActorDestroy(ActorDestroyReason why) override; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index c82d6d4fa3a..304faa53b6e 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -226,6 +226,10 @@ using namespace mozilla::system; #include "nsIProfileSaveEvent.h" #endif +#ifdef MOZ_GAMEPAD +#include "mozilla/dom/GamepadMonitoring.h" +#endif + static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); using base::ChildPrivileges; @@ -2157,6 +2161,7 @@ ContentParent::ContentParent(mozIApplication* aApp, , mOpener(aOpener) , mIsForBrowser(aIsForBrowser) , mIsNuwaProcess(aIsNuwaProcess) + , mHasGamepadListener(false) { InitializeMembers(); // Perform common initialization. @@ -4990,6 +4995,34 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP return true; } +bool +ContentParent::RecvGamepadListenerAdded() +{ +#ifdef MOZ_GAMEPAD + if (mHasGamepadListener) { + NS_WARNING("Gamepad listener already started, cannot start again!"); + return false; + } + mHasGamepadListener = true; + StartGamepadMonitoring(); +#endif + return true; +} + +bool +ContentParent::RecvGamepadListenerRemoved() +{ +#ifdef MOZ_GAMEPAD + if (!mHasGamepadListener) { + NS_WARNING("Gamepad listener already stopped, cannot stop again!"); + return false; + } + mHasGamepadListener = false; + MaybeStopGamepadMonitoring(); +#endif + return true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 1e7e66d5ac2..251ed67d94b 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -377,6 +377,8 @@ public: virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) override; + bool HasGamepadListener() const { return mHasGamepadListener; } + protected: void OnChannelConnected(int32_t pid) override; virtual void ActorDestroy(ActorDestroyReason why) override; @@ -840,6 +842,10 @@ private: virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction, const uint32_t& aDropEffect) override; + + virtual bool RecvGamepadListenerAdded() override; + virtual bool RecvGamepadListenerRemoved() override; + // If you add strong pointers to cycle collected objects here, be sure to // release these objects in ShutDownProcess. See the comment there for more // details. @@ -884,6 +890,7 @@ private: bool mSendDataStoreInfos; bool mIsForBrowser; bool mIsNuwaProcess; + bool mHasGamepadListener; // These variables track whether we've called Close(), CloseWithError() // and KillHard() on our channel. diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 8e4cbb028b7..23fa3460589 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -368,6 +368,38 @@ struct DomainPolicyClone URIParams[] superWhitelist; }; +struct GamepadAdded { + nsString id; + uint32_t index; + uint32_t mapping; + uint32_t num_buttons; + uint32_t num_axes; +}; + +struct GamepadRemoved { + uint32_t index; +}; + +struct GamepadAxisInformation { + uint32_t index; + uint32_t axis; + double value; +}; + +struct GamepadButtonInformation { + uint32_t index; + uint32_t button; + bool pressed; + double value; +}; + +union GamepadChangeEvent { + GamepadAdded; + GamepadRemoved; + GamepadAxisInformation; + GamepadButtonInformation; +}; + prio(normal upto urgent) sync protocol PContent { parent spawns PPluginModule; @@ -605,6 +637,10 @@ child: */ async UpdateWindow(uintptr_t aChildId); + /** + * Send gamepad status update to child. + */ + GamepadUpdate(GamepadChangeEvent aGamepadEvent); parent: /** * Tell the parent process a new accessible document has been created. @@ -992,6 +1028,16 @@ parent: PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal, TabId tabId); + /* + * Tells the parent to start the gamepad listening service if it hasn't already. + */ + GamepadListenerAdded(); + + /** + * Tells the parent to stop the gamepad listening service if it hasn't already. + */ + GamepadListenerRemoved(); + both: AsyncMessage(nsString aMessage, ClonedMessageData aData, CpowEntry[] aCpows, Principal aPrincipal); diff --git a/dom/tests/mochitest/gamepad/mochitest.ini b/dom/tests/mochitest/gamepad/mochitest.ini index a4385aa6466..523f69f5f21 100644 --- a/dom/tests/mochitest/gamepad/mochitest.ini +++ b/dom/tests/mochitest/gamepad/mochitest.ini @@ -1,18 +1,13 @@ [DEFAULT] +skip-if=e10s || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage support-files = gamepad_frame.html gamepad_frame_state.html mock_gamepad.js [test_check_timestamp.html] -skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_gamepad.html] -skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_gamepad_connect_events.html] -skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_gamepad_frame_state_sync.html] -skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_gamepad_hidden_frame.html] -skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_navigator_gamepads.html] -skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage diff --git a/dom/tests/mochitest/gamepad/test_check_timestamp.html b/dom/tests/mochitest/gamepad/test_check_timestamp.html index a99c12ad0ff..338feafcc95 100644 --- a/dom/tests/mochitest/gamepad/test_check_timestamp.html +++ b/dom/tests/mochitest/gamepad/test_check_timestamp.html @@ -11,6 +11,7 @@ diff --git a/dom/tests/mochitest/gamepad/test_navigator_gamepads.html b/dom/tests/mochitest/gamepad/test_navigator_gamepads.html index df8940f97d3..8a64999e7c1 100644 --- a/dom/tests/mochitest/gamepad/test_navigator_gamepads.html +++ b/dom/tests/mochitest/gamepad/test_navigator_gamepads.html @@ -37,49 +37,61 @@ function disconnecthandler(e) { window.addEventListener("gamepadconnected", connecthandler); window.addEventListener("gamepaddisconnected", disconnecthandler); // Add a gamepad -var index1 = GamepadService.addGamepad("test gamepad 1", // id +var internal_index1 = GamepadService.addGamepad("test gamepad 1", // id SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING, 4, // buttons 2);// axes -var index2; +var content_index1 = 0; +var internal_index2; +var content_index2 = 1; // Press a button to make the gamepad visible to the page. -GamepadService.newButtonEvent(index1, 0, true); +GamepadService.newButtonEvent(internal_index1, 0, true); function check_first_gamepad(e) { + ok(true, "Checking first gamepad"); // First gamepad gets added. is(e.gamepad.id, "test gamepad 1", "correct gamepad name"); var gamepads = navigator.getGamepads(); is(gamepads.length, 1, "should have one gamepad exposed"); is(gamepads[e.gamepad.index], e.gamepad, "right gamepad exposed at index"); + is(gamepads[content_index1], e.gamepad, "gamepad counter working correctly"); // Add a second gamepad, should automatically show up. - index2 = GamepadService.addGamepad("test gamepad 2", // id + internal_index2 = GamepadService.addGamepad("test gamepad 2", // id SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING, 4, // buttons 2);// axes + ok(true, "Done checking first gamepad"); } function check_second_gamepad(e) { + ok(true, "Checking seceond gamepad"); // Second gamepad gets added. + is(e.gamepad.index, 1, "gamepad index should be 1") is(e.gamepad.id, "test gamepad 2", "correct gamepad name"); var gamepads = navigator.getGamepads(); is(gamepads.length, 2, "should have two gamepads exposed"); is(gamepads[e.gamepad.index], e.gamepad, "right gamepad exposed at index"); + is(gamepads[content_index2], e.gamepad, "gamepad counter working correctly"); // Now remove the first one. - GamepadService.removeGamepad(index1); + GamepadService.removeGamepad(internal_index1); + ok(true, "Done checking second gamepad"); } function check_gamepad_hole(e) { + ok(true, "Checking gamepad hole"); // First gamepad gets removed. var gamepads = navigator.getGamepads(); is(gamepads.length, 2, "gamepads should have two entries"); - is(gamepads[index1], null, "should be a hole in the gamepad list"); - isnot(gamepads[index2], null, "second gamepad should exist"); + is(gamepads[content_index1], null, "should be a hole in the gamepad list"); + isnot(gamepads[content_index2], null, "second gamepad should exist"); // Now remove the second one. - GamepadService.removeGamepad(index2); + GamepadService.removeGamepad(internal_index2); + ok(true, "Done checking gamepad hole"); } function check_no_gamepads(e) { + ok(true, "Checking no gamepads"); // Second gamepad gets removed. var gamepads = navigator.getGamepads(); is(gamepads.length, 0, "gamepads should be empty"); diff --git a/hal/Hal.cpp b/hal/Hal.cpp index 880a20bc2bb..7d59b0797a4 100644 --- a/hal/Hal.cpp +++ b/hal/Hal.cpp @@ -636,16 +636,6 @@ void StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs) PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs)); } -void StartMonitoringGamepadStatus() -{ - PROXY_IF_SANDBOXED(StartMonitoringGamepadStatus()); -} - -void StopMonitoringGamepadStatus() -{ - PROXY_IF_SANDBOXED(StopMonitoringGamepadStatus()); -} - void RegisterWakeLockObserver(WakeLockObserver* aObserver) { diff --git a/hal/Hal.h b/hal/Hal.h index ba256c3fe98..fe63de499b2 100644 --- a/hal/Hal.h +++ b/hal/Hal.h @@ -17,7 +17,6 @@ #include "mozilla/dom/battery/Types.h" #include "mozilla/dom/network/Types.h" #include "mozilla/dom/power/Types.h" -#include "mozilla/hal_sandbox/PHal.h" #include "mozilla/dom/ScreenOrientation.h" #include "mozilla/HalScreenConfiguration.h" @@ -598,16 +597,6 @@ void StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs); */ void FactoryReset(mozilla::dom::FactoryResetReason& aReason); -/** - * Start monitoring the status of gamepads attached to the system. - */ -void StartMonitoringGamepadStatus(); - -/** - * Stop monitoring the status of gamepads attached to the system. - */ -void StopMonitoringGamepadStatus(); - /** * Start monitoring disk space for low space situations. * diff --git a/hal/moz.build b/hal/moz.build index 55e02508f6b..5c5b033c6ca 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -32,27 +32,6 @@ SOURCES += [ 'Hal.cpp', ] -if CONFIG['MOZ_GAMEPAD_BACKEND'] == 'stub': - UNIFIED_SOURCES += [ - 'fallback/FallbackGamepad.cpp' - ] -elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'cocoa': - UNIFIED_SOURCES += [ - 'cocoa/CocoaGamepad.cpp' - ] -elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'windows': - UNIFIED_SOURCES += [ - 'windows/WindowsGamepad.cpp' - ] -elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'linux': - UNIFIED_SOURCES += [ - 'linux/LinuxGamepad.cpp' - ] -elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'android': - UNIFIED_SOURCES += [ - 'android/AndroidGamepad.cpp' - ] - if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': UNIFIED_SOURCES += [ 'android/AndroidSensor.cpp', diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index d863d5334c4..1485ae56427 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -271,13 +271,6 @@ DisableSensorNotifications(SensorType aSensor) { Hal()->SendDisableSensorNotifications(aSensor); } -//TODO: bug 852944 - IPC implementations of these -void StartMonitoringGamepadStatus() -{} - -void StopMonitoringGamepadStatus() -{} - void EnableWakeLockNotifications() { diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 2e122fd82d9..033bab332a4 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -209,7 +209,7 @@ static void Shutdown(); #include "nsGeolocation.h" #include "nsDeviceSensors.h" #ifdef MOZ_GAMEPAD -#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/GamepadServiceTest.h" #endif #include "mozilla/dom/nsCSPService.h" #include "mozilla/dom/nsCSPContext.h" diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index f07c3cac6b5..42546e3fb48 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -41,7 +41,8 @@ #include "mozilla/dom/ScreenOrientation.h" #ifdef MOZ_GAMEPAD -#include "mozilla/dom/GamepadService.h" +#include "mozilla/dom/GamepadFunctions.h" +#include "mozilla/dom/Gamepad.h" #endif #include "GeckoProfiler.h" @@ -656,19 +657,15 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) case AndroidGeckoEvent::GAMEPAD_ADDREMOVE: { #ifdef MOZ_GAMEPAD - nsRefPtr svc = - mozilla::dom::GamepadService::GetService(); - if (svc) { if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_ADDED) { - int svc_id = svc->AddGamepad("android", - mozilla::dom::GamepadMappingType::Standard, - mozilla::dom::kStandardGamepadButtons, - mozilla::dom::kStandardGamepadAxes); + int svc_id = dom::GamepadFunctions::AddGamepad("android", + dom::GamepadMappingType::Standard, + dom::kStandardGamepadButtons, + dom::kStandardGamepadAxes); widget::GeckoAppShell::GamepadAdded(curEvent->ID(), svc_id); } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_REMOVED) { - svc->RemoveGamepad(curEvent->ID()); - } + dom::GamepadFunctions::RemoveGamepad(curEvent->ID()); } #endif break; @@ -676,12 +673,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) case AndroidGeckoEvent::GAMEPAD_DATA: { #ifdef MOZ_GAMEPAD - nsRefPtr svc = - mozilla::dom::GamepadService::GetService(); - if (svc) { int id = curEvent->ID(); if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_BUTTON) { - svc->NewButtonEvent(id, curEvent->GamepadButton(), + dom::GamepadFunctions::NewButtonEvent(id, curEvent->GamepadButton(), curEvent->GamepadButtonPressed(), curEvent->GamepadButtonValue()); } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_AXES) { @@ -689,8 +683,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait) const nsTArray& values = curEvent->GamepadValues(); for (unsigned i = 0; i < values.Length(); i++) { if (valid & (1<NewAxisMoveEvent(id, i, values[i]); - } + dom::GamepadFunctions::NewAxisMoveEvent(id, i, values[i]); } } }