Bug 852944 - Gamepad API IPC; r=ted, r=baku

This commit is contained in:
Kyle Machulis 2015-04-23 15:05:29 -07:00
parent 59fabc1d0f
commit 86d85d4437
33 changed files with 757 additions and 371 deletions

View File

@ -187,6 +187,7 @@
#include "mozilla/dom/StructuredCloneTags.h" #include "mozilla/dom/StructuredCloneTags.h"
#ifdef MOZ_GAMEPAD #ifdef MOZ_GAMEPAD
#include "mozilla/dom/Gamepad.h"
#include "mozilla/dom/GamepadService.h" #include "mozilla/dom/GamepadService.h"
#endif #endif
@ -13367,6 +13368,15 @@ void
nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad) nsGlobalWindow::AddGamepad(uint32_t aIndex, Gamepad* aGamepad)
{ {
MOZ_ASSERT(IsInnerWindow()); 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); mGamepads.Put(aIndex, aGamepad);
} }
@ -13374,6 +13384,12 @@ void
nsGlobalWindow::RemoveGamepad(uint32_t aIndex) nsGlobalWindow::RemoveGamepad(uint32_t aIndex)
{ {
MOZ_ASSERT(IsInnerWindow()); MOZ_ASSERT(IsInnerWindow());
nsRefPtr<Gamepad> 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); mGamepads.Remove(aIndex);
} }
@ -13384,8 +13400,8 @@ nsGlobalWindow::EnumGamepadsForGet(const uint32_t& aKey, Gamepad* aData,
{ {
nsTArray<nsRefPtr<Gamepad> >* array = nsTArray<nsRefPtr<Gamepad> >* array =
static_cast<nsTArray<nsRefPtr<Gamepad> >*>(aUserArg); static_cast<nsTArray<nsRefPtr<Gamepad> >*>(aUserArg);
array->EnsureLengthAtLeast(aKey + 1); array->EnsureLengthAtLeast(aData->Index() + 1);
(*array)[aKey] = aData; (*array)[aData->Index()] = aData;
return PL_DHASH_NEXT; return PL_DHASH_NEXT;
} }
@ -13404,6 +13420,7 @@ nsGlobalWindow::GetGamepad(uint32_t aIndex)
{ {
MOZ_ASSERT(IsInnerWindow()); MOZ_ASSERT(IsInnerWindow());
nsRefPtr<Gamepad> gamepad; nsRefPtr<Gamepad> gamepad;
if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) { if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
return gamepad.forget(); return gamepad.forget();
} }

View File

@ -52,6 +52,7 @@
#include "Units.h" #include "Units.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsSize.h" #include "nsSize.h"
#include "nsCheapSets.h"
#define DEFAULT_HOME_PAGE "www.mozilla.org" #define DEFAULT_HOME_PAGE "www.mozilla.org"
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage" #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
@ -1590,6 +1591,7 @@ protected:
// Indicates whether this window wants gamepad input events // Indicates whether this window wants gamepad input events
bool mHasGamepad : 1; bool mHasGamepad : 1;
#ifdef MOZ_GAMEPAD #ifdef MOZ_GAMEPAD
nsCheapSet<nsUint32HashKey> mGamepadIndexSet;
nsRefPtrHashtable<nsUint32HashKey, mozilla::dom::Gamepad> mGamepads; nsRefPtrHashtable<nsUint32HashKey, mozilla::dom::Gamepad> mGamepads;
bool mHasSeenGamepadInput; bool mHasSeenGamepadInput;
#endif #endif

View File

@ -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<class T>
void
NotifyGamepadChange(const T& aInfo)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
GamepadChangeEvent e(aInfo);
nsTArray<ContentParent*> 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<GamepadService> 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<GamepadAdded>(a);
return index;
}
void
RemoveGamepad(uint32_t aIndex)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
GamepadRemoved a(aIndex);
NotifyGamepadChange<GamepadRemoved>(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<GamepadButtonInformation>(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<GamepadAxisInformation>(a);
}
void
ResetGamepadIndexes()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
gGamepadIndex = 0;
}
} // namespace GamepadFunctions
} // namespace dom
} // namespace mozilla

View File

@ -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

View File

@ -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<ContentParent*> t;
ContentParent::GetAll(t);
for(uint32_t i = 0; i < t.Length(); ++i) {
if (t[i]->HasGamepadListener()) {
return;
}
}
StopGamepadMonitoring();
ResetGamepadIndexes();
}
} // namespace dom
} // namespace mozilla

View File

@ -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

View File

@ -2,13 +2,18 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * 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/. */ * 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/ClearOnShutdown.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
#include "GamepadService.h"
#include "Gamepad.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsIDOMEvent.h" #include "nsIDOMEvent.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
@ -20,10 +25,6 @@
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "mozilla/dom/GamepadAxisMoveEvent.h"
#include "mozilla/dom/GamepadButtonEvent.h"
#include "mozilla/dom/GamepadEvent.h"
#include <cstddef> #include <cstddef>
namespace mozilla { namespace mozilla {
@ -82,7 +83,11 @@ GamepadService::BeginShutdown()
mTimer->Cancel(); mTimer->Cancel();
} }
if (mStarted) { if (mStarted) {
mozilla::hal::StopMonitoringGamepadStatus(); if (XRE_GetProcessType() == GeckoProcessType_Default) {
MaybeStopGamepadMonitoring();
} else {
ContentChild::GetSingleton()->SendGamepadListenerRemoved();
}
mStarted = false; mStarted = false;
} }
// Don't let windows call back to unregister during shutdown // Don't let windows call back to unregister during shutdown
@ -99,7 +104,6 @@ GamepadService::AddListener(nsGlobalWindow* aWindow)
{ {
MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow()); MOZ_ASSERT(aWindow->IsInnerWindow());
if (mShuttingDown) { if (mShuttingDown) {
return; return;
} }
@ -109,10 +113,13 @@ GamepadService::AddListener(nsGlobalWindow* aWindow)
} }
if (!mStarted && mEnabled) { if (!mStarted && mEnabled) {
mozilla::hal::StartMonitoringGamepadStatus(); if (XRE_GetProcessType() == GeckoProcessType_Default) {
StartGamepadMonitoring();
} else {
ContentChild::GetSingleton()->SendGamepadListenerAdded();
}
mStarted = true; mStarted = true;
} }
mListeners.AppendElement(aWindow); mListeners.AppendElement(aWindow);
} }
@ -139,8 +146,20 @@ GamepadService::RemoveListener(nsGlobalWindow* aWindow)
} }
} }
uint32_t already_AddRefed<Gamepad>
GamepadService::AddGamepad(const char* aId, GamepadService::GetGamepad(uint32_t aIndex)
{
nsRefPtr<Gamepad> gamepad;
if (mGamepads.Get(aIndex, getter_AddRefs(gamepad))) {
return gamepad.forget();
}
return nullptr;
}
void
GamepadService::AddGamepad(uint32_t aIndex,
const nsAString& aId,
GamepadMappingType aMapping, GamepadMappingType aMapping,
uint32_t aNumButtons, uint32_t aNumButtons,
uint32_t aNumAxes) uint32_t aNumAxes)
@ -148,63 +167,40 @@ GamepadService::AddGamepad(const char* aId,
//TODO: bug 852258: get initial button/axis state //TODO: bug 852258: get initial button/axis state
nsRefPtr<Gamepad> gamepad = nsRefPtr<Gamepad> gamepad =
new Gamepad(nullptr, new Gamepad(nullptr,
NS_ConvertUTF8toUTF16(nsDependentCString(aId)), aId,
0, 0, // index is set by global window
aMapping, aMapping,
aNumButtons, aNumButtons,
aNumAxes); 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); // We store the gamepad related to its index given by the parent process.
NewConnectionEvent(index, true); mGamepads.Put(aIndex, gamepad);
NewConnectionEvent(aIndex, true);
return index;
} }
void void
GamepadService::RemoveGamepad(uint32_t aIndex) GamepadService::RemoveGamepad(uint32_t aIndex)
{ {
if (aIndex < mGamepads.Length()) { nsRefPtr<Gamepad> gamepad = GetGamepad(aIndex);
mGamepads[aIndex]->SetConnected(false); if (!gamepad) {
NS_WARNING("Trying to delete gamepad with invalid index");
return;
}
gamepad->SetConnected(false);
NewConnectionEvent(aIndex, false); NewConnectionEvent(aIndex, false);
// If this is the last entry in the list, just remove it. mGamepads.Remove(aIndex);
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;
}
}
}
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 void
GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
double aValue) double aValue)
{ {
if (mShuttingDown || aIndex >= mGamepads.Length()) { nsRefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !gamepad) {
return; return;
} }
mGamepads[aIndex]->SetButton(aButton, aPressed, aValue); gamepad->SetButton(aButton, aPressed, aValue);
// Hold on to listeners in a separate array because firing events // Hold on to listeners in a separate array because firing events
// can mutate the mListeners array. // can mutate the mListeners array.
@ -227,15 +223,15 @@ GamepadService::NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
first_time = true; first_time = true;
} }
nsRefPtr<Gamepad> gamepad = listeners[i]->GetGamepad(aIndex); nsRefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (gamepad) { if (listenerGamepad) {
gamepad->SetButton(aButton, aPressed, aValue); listenerGamepad->SetButton(aButton, aPressed, aValue);
if (first_time) { if (first_time) {
FireConnectionEvent(listeners[i], gamepad, true); FireConnectionEvent(listeners[i], listenerGamepad, true);
} }
if (mNonstandardEventsEnabled) { if (mNonstandardEventsEnabled) {
// Fire event // Fire event
FireButtonEvent(listeners[i], gamepad, aButton, aValue); FireButtonEvent(listeners[i], listenerGamepad, aButton, aValue);
} }
} }
} }
@ -266,10 +262,11 @@ GamepadService::FireButtonEvent(EventTarget* aTarget,
void void
GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue) GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue)
{ {
if (mShuttingDown || aIndex >= mGamepads.Length()) { nsRefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !gamepad) {
return; return;
} }
mGamepads[aIndex]->SetAxis(aAxis, aValue); gamepad->SetAxis(aAxis, aValue);
// Hold on to listeners in a separate array because firing events // Hold on to listeners in a separate array because firing events
// can mutate the mListeners array. // can mutate the mListeners array.
@ -292,15 +289,15 @@ GamepadService::NewAxisMoveEvent(uint32_t aIndex, uint32_t aAxis, double aValue)
first_time = true; first_time = true;
} }
nsRefPtr<Gamepad> gamepad = listeners[i]->GetGamepad(aIndex); nsRefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (gamepad) { if (listenerGamepad) {
gamepad->SetAxis(aAxis, aValue); listenerGamepad->SetAxis(aAxis, aValue);
if (first_time) { if (first_time) {
FireConnectionEvent(listeners[i], gamepad, true); FireConnectionEvent(listeners[i], listenerGamepad, true);
} }
if (mNonstandardEventsEnabled) { if (mNonstandardEventsEnabled) {
// Fire event // Fire event
FireAxisMoveEvent(listeners[i], gamepad, aAxis, aValue); FireAxisMoveEvent(listeners[i], listenerGamepad, aAxis, aValue);
} }
} }
} }
@ -332,7 +329,9 @@ GamepadService::FireAxisMoveEvent(EventTarget* aTarget,
void void
GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected) GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected)
{ {
if (mShuttingDown || aIndex >= mGamepads.Length()) { nsRefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !gamepad) {
return; return;
} }
@ -358,10 +357,10 @@ GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected)
SetWindowHasSeenGamepad(listeners[i], aIndex); SetWindowHasSeenGamepad(listeners[i], aIndex);
nsRefPtr<Gamepad> gamepad = listeners[i]->GetGamepad(aIndex); nsRefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (gamepad) { if (listenerGamepad) {
// Fire event // Fire event
FireConnectionEvent(listeners[i], gamepad, aConnected); FireConnectionEvent(listeners[i], listenerGamepad, aConnected);
} }
} }
} else { } else {
@ -374,11 +373,11 @@ GamepadService::NewConnectionEvent(uint32_t aIndex, bool aConnected)
// deal with the hassle of syncing the state of removed gamepads. // deal with the hassle of syncing the state of removed gamepads.
if (WindowHasSeenGamepad(listeners[i], aIndex)) { if (WindowHasSeenGamepad(listeners[i], aIndex)) {
nsRefPtr<Gamepad> gamepad = listeners[i]->GetGamepad(aIndex); nsRefPtr<Gamepad> listenerGamepad = listeners[i]->GetGamepad(aIndex);
if (gamepad) { if (listenerGamepad) {
gamepad->SetConnected(false); listenerGamepad->SetConnected(false);
// Fire event // Fire event
FireConnectionEvent(listeners[i], gamepad, false); FireConnectionEvent(listeners[i], listenerGamepad, false);
listeners[i]->RemoveGamepad(aIndex); listeners[i]->RemoveGamepad(aIndex);
} }
} }
@ -409,11 +408,19 @@ GamepadService::FireConnectionEvent(EventTarget* aTarget,
void void
GamepadService::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad) GamepadService::SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad)
{ {
if (mShuttingDown || !mEnabled || aIndex > mGamepads.Length()) { nsRefPtr<Gamepad> gamepad = GetGamepad(aIndex);
if (mShuttingDown || !mEnabled || !gamepad) {
return; return;
} }
aGamepad->SyncState(mGamepads[aIndex]); aGamepad->SyncState(gamepad);
}
// static
bool
GamepadService::IsServiceRunning()
{
return !!gGamepadServiceSingleton;
} }
// static // static
@ -461,8 +468,13 @@ GamepadService::SetWindowHasSeenGamepad(nsGlobalWindow* aWindow,
if (aHasSeen) { if (aHasSeen) {
aWindow->SetHasSeenGamepadInput(true); aWindow->SetHasSeenGamepadInput(true);
nsCOMPtr<nsISupports> window = ToSupports(aWindow); nsCOMPtr<nsISupports> window = ToSupports(aWindow);
nsRefPtr<Gamepad> gamepad = mGamepads[aIndex]->Clone(window); nsRefPtr<Gamepad> gamepad = GetGamepad(aIndex);
aWindow->AddGamepad(aIndex, gamepad); MOZ_ASSERT(gamepad);
if (!gamepad) {
return;
}
nsRefPtr<Gamepad> clonedGamepad = gamepad->Clone(window);
aWindow->AddGamepad(aIndex, clonedGamepad);
} else { } else {
aWindow->RemoveGamepad(aIndex); aWindow->RemoveGamepad(aIndex);
} }
@ -486,13 +498,16 @@ GamepadService::TimeoutHandler(nsITimer* aTimer, void* aClosure)
} }
if (self->mListeners.Length() == 0) { if (self->mListeners.Length() == 0) {
mozilla::hal::StopMonitoringGamepadStatus(); if (XRE_GetProcessType() == GeckoProcessType_Default) {
MaybeStopGamepadMonitoring();
} else {
ContentChild::GetSingleton()->SendGamepadListenerRemoved();
}
self->mStarted = false; self->mStarted = false;
if (!self->mGamepads.IsEmpty()) {
self->mGamepads.Clear(); self->mGamepads.Clear();
} }
} }
}
void void
GamepadService::StartCleanupTimer() GamepadService::StartCleanupTimer()
@ -510,71 +525,26 @@ GamepadService::StartCleanupTimer()
} }
} }
/* void
* Implementation of the test service. This is just to provide a simple binding GamepadService::Update(const GamepadChangeEvent& aEvent)
* 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>
GamepadServiceTest::CreateService()
{ {
if (sSingleton == nullptr) { if (aEvent.type() == GamepadChangeEvent::TGamepadAdded) {
sSingleton = new GamepadServiceTest(); const GamepadAdded& a = aEvent.get_GamepadAdded();
AddGamepad(a.index(), a.id(),
static_cast<GamepadMappingType>(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<GamepadServiceTest> service = sSingleton;
return service.forget();
}
GamepadServiceTest::GamepadServiceTest()
{
/* member initializers and constructor code */
nsRefPtr<GamepadService> 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<GamepadMappingType>(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 } // namespace dom

View File

@ -6,7 +6,6 @@
#define mozilla_dom_GamepadService_h_ #define mozilla_dom_GamepadService_h_
#include <stdint.h> #include <stdint.h>
#include "Gamepad.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsCOMArray.h" #include "nsCOMArray.h"
#include "nsIGamepadServiceTest.h" #include "nsIGamepadServiceTest.h"
@ -15,11 +14,14 @@
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsITimer.h" #include "nsITimer.h"
#include "nsTArray.h" #include "nsTArray.h"
// Needed for GamepadMappingType
#include "mozilla/dom/GamepadBinding.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
class EventTarget; class EventTarget;
class GamepadChangeEvent;
class Gamepad;
class GamepadService : public nsIObserver class GamepadService : public nsIObserver
{ {
@ -27,6 +29,8 @@ class GamepadService : public nsIObserver
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
// Returns true if we actually have a service up and running
static bool IsServiceRunning();
// Get the singleton service // Get the singleton service
static already_AddRefed<GamepadService> GetService(); static already_AddRefed<GamepadService> GetService();
// Return true if the API is preffed on. // 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. // Indicate that |aWindow| should no longer receive gamepad events.
void RemoveListener(nsGlobalWindow* aWindow); void RemoveListener(nsGlobalWindow* aWindow);
// Add a gamepad to the list of known gamepads, and return its index. // Add a gamepad to the list of known gamepads.
uint32_t AddGamepad(const char* aID, GamepadMappingType aMapping, void AddGamepad(uint32_t aIndex, const nsAString& aID, GamepadMappingType aMapping,
uint32_t aNumButtons, uint32_t aNumAxes); uint32_t aNumButtons, uint32_t aNumAxes);
// Remove the gamepad at |aIndex| from the list of known gamepads. // Remove the gamepad at |aIndex| from the list of known gamepads.
void RemoveGamepad(uint32_t aIndex); void RemoveGamepad(uint32_t aIndex);
@ -51,8 +56,6 @@ class GamepadService : public nsIObserver
// aPressed is used for digital buttons, aValue is for analog buttons. // aPressed is used for digital buttons, aValue is for analog buttons.
void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed, void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed,
double aValue); 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 // Update the state of |aAxis| for the gamepad at |aIndex| for all
// windows that are listening and visible, and fire a gamepadaxismove // 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| // Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex|
void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad); void SyncGamepadState(uint32_t aIndex, Gamepad* aGamepad);
// Returns gamepad object if index exists, null otherwise
already_AddRefed<Gamepad> GetGamepad(uint32_t aIndex);
// Receive GamepadChangeEvent messages from parent process to fire DOM events
void Update(const GamepadChangeEvent& aGamepadEvent);
protected: protected:
GamepadService(); GamepadService();
virtual ~GamepadService() {}; virtual ~GamepadService() {};
@ -115,37 +123,13 @@ class GamepadService : public nsIObserver
// Gamepads connected to the system. Copies of these are handed out // Gamepads connected to the system. Copies of these are handed out
// to each window. // to each window.
nsTArray<nsRefPtr<Gamepad> > mGamepads; nsRefPtrHashtable<nsUint32HashKey, Gamepad> mGamepads;
// Inner windows that are listening for gamepad events. // Inner windows that are listening for gamepad events.
// has been sent to that window. // has been sent to that window.
nsTArray<nsRefPtr<nsGlobalWindow> > mListeners; nsTArray<nsRefPtr<nsGlobalWindow> > mListeners;
nsCOMPtr<nsITimer> mTimer; nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsIFocusManager> mFocusManager;
nsCOMPtr<nsIObserver> mObserver;
};
// Service for testing purposes
class GamepadServiceTest : public nsIGamepadServiceTest
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIGAMEPADSERVICETEST
GamepadServiceTest();
static already_AddRefed<GamepadServiceTest> CreateService();
private:
static GamepadServiceTest* sSingleton;
virtual ~GamepadServiceTest() {};
}; };
} // namespace dom } // namespace dom
} // namespace mozilla } // 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_ #endif // mozilla_dom_GamepadService_h_

View File

@ -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>
GamepadServiceTest::CreateService()
{
if (sSingleton == nullptr) {
sSingleton = new GamepadServiceTest();
}
nsRefPtr<GamepadServiceTest> 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<GamepadMappingType>(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;
}

View File

@ -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<GamepadServiceTest> 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<GamepadService> 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

View File

@ -3,25 +3,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
#include "AndroidBridge.h" #include "AndroidBridge.h"
using namespace mozilla::hal;
namespace mozilla { namespace mozilla {
namespace hal_impl { namespace dom {
void void StartGamepadMonitoring()
StartMonitoringGamepadStatus()
{ {
widget::GeckoAppShell::StartMonitoringGamepad(); widget::GeckoAppShell::StartMonitoringGamepad();
} }
void void StopGamepadMonitoring()
StopMonitoringGamepadStatus()
{ {
widget::GeckoAppShell::StopMonitoringGamepad(); widget::GeckoAppShell::StopMonitoringGamepad();
} }
} // hal_impl } // namespace dom
} // mozilla } // namespace mozilla

View File

@ -6,7 +6,8 @@
// mostly derived from the Allegro source code at: // 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 // 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 <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDBase.h> #include <IOKit/hid/IOHIDBase.h>
#include <IOKit/hid/IOHIDKeys.h> #include <IOKit/hid/IOHIDKeys.h>
@ -17,8 +18,8 @@
namespace { namespace {
using mozilla::dom::GamepadService; using namespace mozilla;
using namespace mozilla::dom::GamepadFunctions;
using std::vector; using std::vector;
struct Button { struct Button {
@ -248,8 +249,7 @@ DarwinGamepadService::DeviceAdded(IOHIDDeviceRef device)
sizeof(product_name), kCFStringEncodingASCII); sizeof(product_name), kCFStringEncodingASCII);
char buffer[256]; char buffer[256];
sprintf(buffer, "%x-%x-%s", vendorId, productId, product_name); sprintf(buffer, "%x-%x-%s", vendorId, productId, product_name);
nsRefPtr<GamepadService> service(GamepadService::GetService()); mGamepads[slot].mSuperIndex = AddGamepad(buffer,
mGamepads[slot].mSuperIndex = service->AddGamepad(buffer,
mozilla::dom::GamepadMappingType::_empty, mozilla::dom::GamepadMappingType::_empty,
(int)mGamepads[slot].numButtons(), (int)mGamepads[slot].numButtons(),
(int)mGamepads[slot].numAxes()); (int)mGamepads[slot].numAxes());
@ -258,10 +258,9 @@ DarwinGamepadService::DeviceAdded(IOHIDDeviceRef device)
void void
DarwinGamepadService::DeviceRemoved(IOHIDDeviceRef device) DarwinGamepadService::DeviceRemoved(IOHIDDeviceRef device)
{ {
nsRefPtr<GamepadService> service(GamepadService::GetService());
for (size_t i = 0; i < mGamepads.size(); i++) { for (size_t i = 0; i < mGamepads.size(); i++) {
if (mGamepads[i] == device) { if (mGamepads[i] == device) {
service->RemoveGamepad(mGamepads[i].mSuperIndex); RemoveGamepad(mGamepads[i].mSuperIndex);
mGamepads[i].clear(); mGamepads[i].clear();
return; return;
} }
@ -316,7 +315,6 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
// massive (30+ byte) values and crash IOHIDValueGetIntegerValue // massive (30+ byte) values and crash IOHIDValueGetIntegerValue
return; return;
} }
nsRefPtr<GamepadService> service(GamepadService::GetService());
IOHIDElementRef element = IOHIDValueGetElement(value); IOHIDElementRef element = IOHIDValueGetElement(value);
IOHIDDeviceRef device = IOHIDElementGetDevice(element); IOHIDDeviceRef device = IOHIDElementGetDevice(element);
for (unsigned i = 0; i < mGamepads.size(); i++) { for (unsigned i = 0; i < mGamepads.size(); i++) {
@ -332,7 +330,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
const int numButtons = gamepad.numButtons(); const int numButtons = gamepad.numButtons();
for (unsigned b = 0; b < ArrayLength(newState); b++) { for (unsigned b = 0; b < ArrayLength(newState); b++) {
if (newState[b] != oldState[b]) { if (newState[b] != oldState[b]) {
service->NewButtonEvent(i, numButtons - 4 + b, newState[b]); NewButtonEvent(i, numButtons - 4 + b, newState[b]);
} }
} }
gamepad.setDpadState(newState); gamepad.setDpadState(newState);
@ -340,7 +338,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
double d = IOHIDValueGetIntegerValue(value); double d = IOHIDValueGetIntegerValue(value);
double v = 2.0f * (d - axis->min) / double v = 2.0f * (d - axis->min) /
(double)(axis->max - axis->min) - 1.0f; (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)) { } else if (const Button* button = gamepad.lookupButton(element)) {
int iv = IOHIDValueGetIntegerValue(value); int iv = IOHIDValueGetIntegerValue(value);
bool pressed = iv != 0; bool pressed = iv != 0;
@ -351,7 +349,7 @@ DarwinGamepadService::InputValueChanged(IOHIDValueRef value)
} else { } else {
v = pressed ? 1.0 : 0.0; v = pressed ? 1.0 : 0.0;
} }
service->NewButtonEvent(i, button->id, pressed, v); NewButtonEvent(i, button->id, pressed, v);
} }
return; return;
} }
@ -495,28 +493,30 @@ void DarwinGamepadService::Shutdown()
} // namespace } // namespace
namespace mozilla { namespace mozilla {
namespace hal_impl { namespace dom {
DarwinGamepadService* gService = nullptr; DarwinGamepadService* gService = nullptr;
void StartMonitoringGamepadStatus() void StartGamepadMonitoring()
{ {
if (gService) if (gService) {
return; return;
}
gService = new DarwinGamepadService(); gService = new DarwinGamepadService();
gService->Startup(); gService->Startup();
} }
void StopMonitoringGamepadStatus() void StopGamepadMonitoring()
{ {
if (!gService) if (!gService) {
return; return;
}
gService->Shutdown(); gService->Shutdown();
delete gService; delete gService;
gService = nullptr; gService = nullptr;
} }
} // namespace hal_impl } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -4,16 +4,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file, * 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/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
namespace mozilla { namespace mozilla {
namespace hal_impl { namespace dom {
void StartMonitoringGamepadStatus() void StartGamepadMonitoring()
{} {
}
void StopMonitoringGamepadStatus() void StopGamepadMonitoring()
{} {
}
} // hal_impl } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -16,14 +16,13 @@
#include <stdint.h> #include <stdint.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
#include "nscore.h" #include "nscore.h"
#include "mozilla/dom/GamepadService.h" #include "mozilla/dom/GamepadFunctions.h"
#include "udev.h" #include "udev.h"
namespace { namespace {
using mozilla::dom::GamepadService; using namespace mozilla::dom::GamepadFunctions;
using mozilla::udev_lib; using mozilla::udev_lib;
using mozilla::udev_device; using mozilla::udev_device;
using mozilla::udev_list_entry; using mozilla::udev_list_entry;
@ -138,8 +137,7 @@ LinuxGamepadService::AddDevice(struct udev_device* dev)
ioctl(fd, JSIOCGBUTTONS, &numButtons); ioctl(fd, JSIOCGBUTTONS, &numButtons);
gamepad.numButtons = numButtons; gamepad.numButtons = numButtons;
nsRefPtr<GamepadService> service(GamepadService::GetService()); gamepad.index = AddGamepad(gamepad.idstring,
gamepad.index = service->AddGamepad(gamepad.idstring,
mozilla::dom::GamepadMappingType::_empty, mozilla::dom::GamepadMappingType::_empty,
gamepad.numButtons, gamepad.numButtons,
gamepad.numAxes); gamepad.numAxes);
@ -162,11 +160,10 @@ LinuxGamepadService::RemoveDevice(struct udev_device* dev)
return; return;
} }
nsRefPtr<GamepadService> service(GamepadService::GetService());
for (unsigned int i = 0; i < mGamepads.Length(); i++) { for (unsigned int i = 0; i < mGamepads.Length(); i++) {
if (strcmp(mGamepads[i].devpath, devpath) == 0) { if (strcmp(mGamepads[i].devpath, devpath) == 0) {
g_source_remove(mGamepads[i].source_id); g_source_remove(mGamepads[i].source_id);
service->RemoveGamepad(mGamepads[i].index); RemoveGamepad(mGamepads[i].index);
mGamepads.RemoveElementAt(i); mGamepads.RemoveElementAt(i);
break; break;
} }
@ -319,13 +316,12 @@ LinuxGamepadService::OnGamepadData(GIOChannel* source,
continue; continue;
} }
nsRefPtr<GamepadService> service(GamepadService::GetService());
switch (event.type) { switch (event.type) {
case JS_EVENT_BUTTON: case JS_EVENT_BUTTON:
service->NewButtonEvent(index, event.number, !!event.value); NewButtonEvent(index, event.number, !!event.value);
break; break;
case JS_EVENT_AXIS: case JS_EVENT_AXIS:
service->NewAxisMoveEvent(index, event.number, NewAxisMoveEvent(index, event.number,
((float)event.value) / kMaxAxisValue); ((float)event.value) / kMaxAxisValue);
break; break;
} }
@ -350,24 +346,26 @@ LinuxGamepadService::OnUdevMonitor(GIOChannel* source,
} // namespace } // namespace
namespace mozilla { namespace mozilla {
namespace hal_impl { namespace dom {
void StartMonitoringGamepadStatus() void StartGamepadMonitoring()
{
if (!gService) {
gService = new LinuxGamepadService();
gService->Startup();
}
}
void StopMonitoringGamepadStatus()
{ {
if (gService) { if (gService) {
return;
}
gService = new LinuxGamepadService();
gService->Startup();
}
void StopGamepadMonitoring()
{
if (!gService) {
return;
}
gService->Shutdown(); gService->Shutdown();
delete gService; delete gService;
gService = nullptr; gService = nullptr;
}
} }
} // namespace hal_impl } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -7,13 +7,40 @@
EXPORTS.mozilla.dom += [ EXPORTS.mozilla.dom += [
'Gamepad.h', 'Gamepad.h',
'GamepadButton.h', 'GamepadButton.h',
'GamepadFunctions.h',
'GamepadMonitoring.h',
'GamepadService.h', 'GamepadService.h',
'GamepadServiceTest.h'
] ]
UNIFIED_SOURCES = [ UNIFIED_SOURCES = [
'Gamepad.cpp', 'Gamepad.cpp',
'GamepadButton.cpp', 'GamepadButton.cpp',
'GamepadFunctions.cpp',
'GamepadMonitoring.cpp',
'GamepadService.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 FAIL_ON_WARNINGS = True
@ -25,3 +52,7 @@ LOCAL_INCLUDES += [
'/dom/base', '/dom/base',
] ]
CFLAGS += CONFIG['GLIB_CFLAGS']
CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
CXXFLAGS += CONFIG['GLIB_CFLAGS']
CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']

View File

@ -20,12 +20,13 @@
#include "nsITimer.h" #include "nsITimer.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/dom/GamepadService.h" #include "mozilla/dom/GamepadFunctions.h"
#include "mozilla/Services.h" #include "mozilla/Services.h"
namespace { namespace {
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::dom::GamepadFunctions;
using mozilla::ArrayLength; using mozilla::ArrayLength;
// USB HID usage tables, page 1 (Hat switch) // USB HID usage tables, page 1 (Hat switch)
@ -455,11 +456,6 @@ WindowsGamepadService::ScanForXInputDevices()
{ {
MOZ_ASSERT(mXInput, "XInput should be present!"); MOZ_ASSERT(mXInput, "XInput should be present!");
nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
if (!gamepadsvc) {
return false;
}
bool found = false; bool found = false;
for (int i = 0; i < XUSER_MAX_COUNT; i++) { for (int i = 0; i < XUSER_MAX_COUNT; i++) {
XINPUT_STATE state = {}; XINPUT_STATE state = {};
@ -480,7 +476,7 @@ WindowsGamepadService::ScanForXInputDevices()
gamepad.userIndex = i; gamepad.userIndex = i;
gamepad.numButtons = kStandardGamepadButtons; gamepad.numButtons = kStandardGamepadButtons;
gamepad.numAxes = kStandardGamepadAxes; gamepad.numAxes = kStandardGamepadAxes;
gamepad.id = gamepadsvc->AddGamepad("xinput", gamepad.id = AddGamepad("xinput",
GamepadMappingType::Standard, GamepadMappingType::Standard,
kStandardGamepadButtons, kStandardGamepadButtons,
kStandardGamepadAxes); kStandardGamepadAxes);
@ -510,14 +506,10 @@ WindowsGamepadService::ScanForDevices()
} }
} }
nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
if (!gamepadsvc) {
return;
}
// Look for devices that are no longer present and remove them. // Look for devices that are no longer present and remove them.
for (int i = mGamepads.Length() - 1; i >= 0; i--) { for (int i = mGamepads.Length() - 1; i >= 0; i--) {
if (!mGamepads[i].present) { if (!mGamepads[i].present) {
gamepadsvc->RemoveGamepad(mGamepads[i].id); RemoveGamepad(mGamepads[i].id);
mGamepads.RemoveElementAt(i); mGamepads.RemoveElementAt(i);
} }
} }
@ -552,17 +544,16 @@ WindowsGamepadService::PollXInput()
void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad, void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad,
XINPUT_STATE& state) { XINPUT_STATE& state) {
nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
// Handle digital buttons first // Handle digital buttons first
for (size_t b = 0; b < kNumMappings; b++) { for (size_t b = 0; b < kNumMappings; b++) {
if (state.Gamepad.wButtons & kXIButtonMap[b].button && if (state.Gamepad.wButtons & kXIButtonMap[b].button &&
!(gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button)) { !(gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button)) {
// Button pressed // 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) && } else if (!(state.Gamepad.wButtons & kXIButtonMap[b].button) &&
gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button) { gamepad.state.Gamepad.wButtons & kXIButtonMap[b].button) {
// Button released // Button released
gamepadsvc->NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, false); NewButtonEvent(gamepad.id, kXIButtonMap[b].mapped, false);
} }
} }
@ -570,32 +561,32 @@ void WindowsGamepadService::CheckXInputChanges(Gamepad& gamepad,
if (state.Gamepad.bLeftTrigger != gamepad.state.Gamepad.bLeftTrigger) { if (state.Gamepad.bLeftTrigger != gamepad.state.Gamepad.bLeftTrigger) {
bool pressed = bool pressed =
state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; state.Gamepad.bLeftTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
gamepadsvc->NewButtonEvent(gamepad.id, kButtonLeftTrigger, NewButtonEvent(gamepad.id, kButtonLeftTrigger,
pressed, state.Gamepad.bLeftTrigger / 255.0); pressed, state.Gamepad.bLeftTrigger / 255.0);
} }
if (state.Gamepad.bRightTrigger != gamepad.state.Gamepad.bRightTrigger) { if (state.Gamepad.bRightTrigger != gamepad.state.Gamepad.bRightTrigger) {
bool pressed = bool pressed =
state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD; state.Gamepad.bRightTrigger >= XINPUT_GAMEPAD_TRIGGER_THRESHOLD;
gamepadsvc->NewButtonEvent(gamepad.id, kButtonRightTrigger, NewButtonEvent(gamepad.id, kButtonRightTrigger,
pressed, state.Gamepad.bRightTrigger / 255.0); pressed, state.Gamepad.bRightTrigger / 255.0);
} }
// Finally deal with analog sticks // Finally deal with analog sticks
// TODO: bug 1001955 - Support deadzones. // TODO: bug 1001955 - Support deadzones.
if (state.Gamepad.sThumbLX != gamepad.state.Gamepad.sThumbLX) { if (state.Gamepad.sThumbLX != gamepad.state.Gamepad.sThumbLX) {
gamepadsvc->NewAxisMoveEvent(gamepad.id, kLeftStickXAxis, NewAxisMoveEvent(gamepad.id, kLeftStickXAxis,
state.Gamepad.sThumbLX / 32767.0); state.Gamepad.sThumbLX / 32767.0);
} }
if (state.Gamepad.sThumbLY != gamepad.state.Gamepad.sThumbLY) { if (state.Gamepad.sThumbLY != gamepad.state.Gamepad.sThumbLY) {
gamepadsvc->NewAxisMoveEvent(gamepad.id, kLeftStickYAxis, NewAxisMoveEvent(gamepad.id, kLeftStickYAxis,
-1.0 * state.Gamepad.sThumbLY / 32767.0); -1.0 * state.Gamepad.sThumbLY / 32767.0);
} }
if (state.Gamepad.sThumbRX != gamepad.state.Gamepad.sThumbRX) { if (state.Gamepad.sThumbRX != gamepad.state.Gamepad.sThumbRX) {
gamepadsvc->NewAxisMoveEvent(gamepad.id, kRightStickXAxis, NewAxisMoveEvent(gamepad.id, kRightStickXAxis,
state.Gamepad.sThumbRX / 32767.0); state.Gamepad.sThumbRX / 32767.0);
} }
if (state.Gamepad.sThumbRY != gamepad.state.Gamepad.sThumbRY) { if (state.Gamepad.sThumbRY != gamepad.state.Gamepad.sThumbRY) {
gamepadsvc->NewAxisMoveEvent(gamepad.id, kRightStickYAxis, NewAxisMoveEvent(gamepad.id, kRightStickYAxis,
-1.0 * state.Gamepad.sThumbRY / 32767.0); -1.0 * state.Gamepad.sThumbRY / 32767.0);
} }
gamepad.state = state; gamepad.state = state;
@ -757,12 +748,7 @@ WindowsGamepadService::GetRawGamepad(HANDLE handle)
gamepad.handle = handle; gamepad.handle = handle;
gamepad.present = true; gamepad.present = true;
nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService()); gamepad.id = GamepadFunctions::AddGamepad(gamepad_id,
if (!gamepadsvc) {
return false;
}
gamepad.id = gamepadsvc->AddGamepad(gamepad_id,
GamepadMappingType::_empty, GamepadMappingType::_empty,
gamepad.numButtons, gamepad.numButtons,
gamepad.numAxes); gamepad.numAxes);
@ -776,10 +762,6 @@ WindowsGamepadService::HandleRawInput(HRAWINPUT handle)
if (!mHID) { if (!mHID) {
return false; return false;
} }
nsRefPtr<GamepadService> gamepadsvc(GamepadService::GetService());
if (!gamepadsvc) {
return false;
}
// First, get data from the handle // First, get data from the handle
UINT size; UINT size;
@ -838,7 +820,7 @@ WindowsGamepadService::HandleRawInput(HRAWINPUT handle)
for (unsigned i = 0; i < gamepad->numButtons; i++) { for (unsigned i = 0; i < gamepad->numButtons; i++) {
if (gamepad->buttons[i] != buttons[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]; gamepad->buttons[i] = buttons[i];
} }
} }
@ -872,7 +854,7 @@ LONG value;
gamepad->axes[i].caps.LogicalMax); gamepad->axes[i].caps.LogicalMax);
} }
if (gamepad->axes[i].value != new_value) { 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; gamepad->axes[i].value = new_value;
} }
} }
@ -977,9 +959,9 @@ GamepadWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
} // namespace } // namespace
namespace mozilla { namespace mozilla {
namespace hal_impl { namespace dom {
void StartMonitoringGamepadStatus() void StartGamepadMonitoring()
{ {
if (gService) { if (gService) {
return; return;
@ -1007,7 +989,7 @@ void StartMonitoringGamepadStatus()
} }
} }
void StopMonitoringGamepadStatus() void StopGamepadMonitoring()
{ {
if (!gService) { if (!gService) {
return; return;
@ -1024,6 +1006,6 @@ void StopMonitoringGamepadStatus()
gService = nullptr; gService = nullptr;
} }
} // namespace hal_impl } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -9,18 +9,21 @@ interface nsIVariant;
/* /*
* This interface is intended only for use in tests. * 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 interface nsIGamepadServiceTest : nsISupports
{ {
const unsigned long NO_MAPPING = 0; const unsigned long NO_MAPPING = 0;
const unsigned long STANDARD_MAPPING = 1; 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 numButtons,
in unsigned long numAxes); in unsigned long numAxes);
void removeGamepad(in unsigned long index); void removeGamepad(in unsigned long index);
void newButtonEvent(in unsigned long index, in unsigned long button, void newButtonEvent(in unsigned long index, in unsigned long button,
in boolean pressed); 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, void newAxisMoveEvent(in unsigned long index, in unsigned long axis,
in double value); in double value);
}; };

View File

@ -155,6 +155,10 @@
#include "ipc/Nuwa.h" #include "ipc/Nuwa.h"
#endif #endif
#ifdef MOZ_GAMEPAD
#include "mozilla/dom/GamepadService.h"
#endif
#include "mozilla/dom/File.h" #include "mozilla/dom/File.h"
#include "mozilla/dom/cellbroadcast/CellBroadcastIPCService.h" #include "mozilla/dom/cellbroadcast/CellBroadcastIPCService.h"
#include "mozilla/dom/icc/IccChild.h" #include "mozilla/dom/icc/IccChild.h"
@ -2775,6 +2779,18 @@ ContentChild::DeallocPContentPermissionRequestChild(PContentPermissionRequestChi
return true; return true;
} }
bool
ContentChild::RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent)
{
#ifdef MOZ_GAMEPAD
nsRefPtr<GamepadService> svc(GamepadService::GetService());
if (svc) {
svc->Update(aGamepadEvent);
}
#endif
return true;
}
// This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp // This code goes here rather than nsGlobalWindow.cpp because nsGlobalWindow.cpp
// can't include ContentChild.h since it includes windows.h. // can't include ContentChild.h since it includes windows.h.

View File

@ -464,6 +464,8 @@ public:
virtual bool virtual bool
DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) override; DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor) override;
virtual bool RecvGamepadUpdate(const GamepadChangeEvent& aGamepadEvent) override;
private: private:
virtual void ActorDestroy(ActorDestroyReason why) override; virtual void ActorDestroy(ActorDestroyReason why) override;

View File

@ -226,6 +226,10 @@ using namespace mozilla::system;
#include "nsIProfileSaveEvent.h" #include "nsIProfileSaveEvent.h"
#endif #endif
#ifdef MOZ_GAMEPAD
#include "mozilla/dom/GamepadMonitoring.h"
#endif
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
using base::ChildPrivileges; using base::ChildPrivileges;
@ -2157,6 +2161,7 @@ ContentParent::ContentParent(mozIApplication* aApp,
, mOpener(aOpener) , mOpener(aOpener)
, mIsForBrowser(aIsForBrowser) , mIsForBrowser(aIsForBrowser)
, mIsNuwaProcess(aIsNuwaProcess) , mIsNuwaProcess(aIsNuwaProcess)
, mHasGamepadListener(false)
{ {
InitializeMembers(); // Perform common initialization. InitializeMembers(); // Perform common initialization.
@ -4990,6 +4995,34 @@ ContentParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestP
return true; 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 dom
} // namespace mozilla } // namespace mozilla

View File

@ -377,6 +377,8 @@ public:
virtual bool virtual bool
DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) override; DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) override;
bool HasGamepadListener() const { return mHasGamepadListener; }
protected: protected:
void OnChannelConnected(int32_t pid) override; void OnChannelConnected(int32_t pid) override;
virtual void ActorDestroy(ActorDestroyReason why) override; virtual void ActorDestroy(ActorDestroyReason why) override;
@ -840,6 +842,10 @@ private:
virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction, virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect) override; 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 // If you add strong pointers to cycle collected objects here, be sure to
// release these objects in ShutDownProcess. See the comment there for more // release these objects in ShutDownProcess. See the comment there for more
// details. // details.
@ -884,6 +890,7 @@ private:
bool mSendDataStoreInfos; bool mSendDataStoreInfos;
bool mIsForBrowser; bool mIsForBrowser;
bool mIsNuwaProcess; bool mIsNuwaProcess;
bool mHasGamepadListener;
// These variables track whether we've called Close(), CloseWithError() // These variables track whether we've called Close(), CloseWithError()
// and KillHard() on our channel. // and KillHard() on our channel.

View File

@ -368,6 +368,38 @@ struct DomainPolicyClone
URIParams[] superWhitelist; 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 prio(normal upto urgent) sync protocol PContent
{ {
parent spawns PPluginModule; parent spawns PPluginModule;
@ -605,6 +637,10 @@ child:
*/ */
async UpdateWindow(uintptr_t aChildId); async UpdateWindow(uintptr_t aChildId);
/**
* Send gamepad status update to child.
*/
GamepadUpdate(GamepadChangeEvent aGamepadEvent);
parent: parent:
/** /**
* Tell the parent process a new accessible document has been created. * Tell the parent process a new accessible document has been created.
@ -992,6 +1028,16 @@ parent:
PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal, PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
TabId tabId); 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: both:
AsyncMessage(nsString aMessage, ClonedMessageData aData, AsyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal); CpowEntry[] aCpows, Principal aPrincipal);

View File

@ -1,18 +1,13 @@
[DEFAULT] [DEFAULT]
skip-if=e10s || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
support-files = support-files =
gamepad_frame.html gamepad_frame.html
gamepad_frame_state.html gamepad_frame_state.html
mock_gamepad.js mock_gamepad.js
[test_check_timestamp.html] [test_check_timestamp.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
[test_gamepad.html] [test_gamepad.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
[test_gamepad_connect_events.html] [test_gamepad_connect_events.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
[test_gamepad_frame_state_sync.html] [test_gamepad_frame_state_sync.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
[test_gamepad_hidden_frame.html] [test_gamepad_hidden_frame.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
[test_navigator_gamepads.html] [test_navigator_gamepads.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage

View File

@ -11,6 +11,7 @@
<script type="text/javascript" src="mock_gamepad.js"></script> <script type="text/javascript" src="mock_gamepad.js"></script>
<script class="testbody" type="text/javascript"> <script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
var index = GamepadService.addGamepad("test gamepad", // id var index = GamepadService.addGamepad("test gamepad", // id
SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING, SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
4, // buttons 4, // buttons

View File

@ -17,19 +17,29 @@ var index = GamepadService.addGamepad("test gamepad", // id
SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING, SpecialPowers.Ci.nsIGamepadServiceTest.STANDARD_MAPPING,
4, // buttons 4, // buttons
2);// axes 2);// axes
// Press a button
GamepadService.newButtonEvent(index, 0, true); GamepadService.newButtonEvent(index, 0, true);
function connecthandler(e) { function connecthandler(e) {
ok(e.gamepad.timestamp <= performance.now()); ok(e.gamepad.timestamp <= performance.now());
is(e.gamepad.index, 0, "correct gamepad index");
is(e.gamepad.id, "test gamepad", "correct gamepad name"); is(e.gamepad.id, "test gamepad", "correct gamepad name");
is(e.gamepad.mapping, "standard", "standard mapping"); is(e.gamepad.mapping, "standard", "standard mapping");
is(e.gamepad.buttons.length, 4, "correct number of buttons"); is(e.gamepad.buttons.length, 4, "correct number of buttons");
is(e.gamepad.axes.length, 2, "correct number of axes"); is(e.gamepad.axes.length, 2, "correct number of axes");
// Press a button
GamepadService.newButtonEvent(index, 0, true);
gamepads = navigator.getGamepads();
is(gamepads[0].buttons[0].pressed, true, "gamepad button should register as pressed")
GamepadService.newButtonValueEvent(index, 1, true, 0.5);
gamepads = navigator.getGamepads();
is(gamepads[0].buttons[1].pressed, true, "gamepad button should register as pressed")
is(gamepads[0].buttons[1].value, 0.5, "gamepad button value should be 0.5")
SimpleTest.executeSoon(function() { SimpleTest.executeSoon(function() {
GamepadService.removeGamepad(index); GamepadService.removeGamepad(index);
SimpleTest.finish(); SimpleTest.finish();
}); });
} }
</script> </script>
</body> </body>
</html> </html>

View File

@ -37,49 +37,61 @@ function disconnecthandler(e) {
window.addEventListener("gamepadconnected", connecthandler); window.addEventListener("gamepadconnected", connecthandler);
window.addEventListener("gamepaddisconnected", disconnecthandler); window.addEventListener("gamepaddisconnected", disconnecthandler);
// Add a gamepad // 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, SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
4, // buttons 4, // buttons
2);// axes 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. // 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) { function check_first_gamepad(e) {
ok(true, "Checking first gamepad");
// First gamepad gets added. // First gamepad gets added.
is(e.gamepad.id, "test gamepad 1", "correct gamepad name"); is(e.gamepad.id, "test gamepad 1", "correct gamepad name");
var gamepads = navigator.getGamepads(); var gamepads = navigator.getGamepads();
is(gamepads.length, 1, "should have one gamepad exposed"); is(gamepads.length, 1, "should have one gamepad exposed");
is(gamepads[e.gamepad.index], e.gamepad, "right gamepad exposed at index"); 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. // 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, SpecialPowers.Ci.nsIGamepadServiceTest.NO_MAPPING,
4, // buttons 4, // buttons
2);// axes 2);// axes
ok(true, "Done checking first gamepad");
} }
function check_second_gamepad(e) { function check_second_gamepad(e) {
ok(true, "Checking seceond gamepad");
// Second gamepad gets added. // Second gamepad gets added.
is(e.gamepad.index, 1, "gamepad index should be 1")
is(e.gamepad.id, "test gamepad 2", "correct gamepad name"); is(e.gamepad.id, "test gamepad 2", "correct gamepad name");
var gamepads = navigator.getGamepads(); var gamepads = navigator.getGamepads();
is(gamepads.length, 2, "should have two gamepads exposed"); is(gamepads.length, 2, "should have two gamepads exposed");
is(gamepads[e.gamepad.index], e.gamepad, "right gamepad exposed at index"); 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. // Now remove the first one.
GamepadService.removeGamepad(index1); GamepadService.removeGamepad(internal_index1);
ok(true, "Done checking second gamepad");
} }
function check_gamepad_hole(e) { function check_gamepad_hole(e) {
ok(true, "Checking gamepad hole");
// First gamepad gets removed. // First gamepad gets removed.
var gamepads = navigator.getGamepads(); var gamepads = navigator.getGamepads();
is(gamepads.length, 2, "gamepads should have two entries"); is(gamepads.length, 2, "gamepads should have two entries");
is(gamepads[index1], null, "should be a hole in the gamepad list"); is(gamepads[content_index1], null, "should be a hole in the gamepad list");
isnot(gamepads[index2], null, "second gamepad should exist"); isnot(gamepads[content_index2], null, "second gamepad should exist");
// Now remove the second one. // Now remove the second one.
GamepadService.removeGamepad(index2); GamepadService.removeGamepad(internal_index2);
ok(true, "Done checking gamepad hole");
} }
function check_no_gamepads(e) { function check_no_gamepads(e) {
ok(true, "Checking no gamepads");
// Second gamepad gets removed. // Second gamepad gets removed.
var gamepads = navigator.getGamepads(); var gamepads = navigator.getGamepads();
is(gamepads.length, 0, "gamepads should be empty"); is(gamepads.length, 0, "gamepads should be empty");

View File

@ -636,16 +636,6 @@ void StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs)
PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs)); PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs));
} }
void StartMonitoringGamepadStatus()
{
PROXY_IF_SANDBOXED(StartMonitoringGamepadStatus());
}
void StopMonitoringGamepadStatus()
{
PROXY_IF_SANDBOXED(StopMonitoringGamepadStatus());
}
void void
RegisterWakeLockObserver(WakeLockObserver* aObserver) RegisterWakeLockObserver(WakeLockObserver* aObserver)
{ {

View File

@ -17,7 +17,6 @@
#include "mozilla/dom/battery/Types.h" #include "mozilla/dom/battery/Types.h"
#include "mozilla/dom/network/Types.h" #include "mozilla/dom/network/Types.h"
#include "mozilla/dom/power/Types.h" #include "mozilla/dom/power/Types.h"
#include "mozilla/hal_sandbox/PHal.h"
#include "mozilla/dom/ScreenOrientation.h" #include "mozilla/dom/ScreenOrientation.h"
#include "mozilla/HalScreenConfiguration.h" #include "mozilla/HalScreenConfiguration.h"
@ -598,16 +597,6 @@ void StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs);
*/ */
void FactoryReset(mozilla::dom::FactoryResetReason& aReason); 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. * Start monitoring disk space for low space situations.
* *

View File

@ -32,27 +32,6 @@ SOURCES += [
'Hal.cpp', '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': if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
UNIFIED_SOURCES += [ UNIFIED_SOURCES += [
'android/AndroidSensor.cpp', 'android/AndroidSensor.cpp',

View File

@ -271,13 +271,6 @@ DisableSensorNotifications(SensorType aSensor) {
Hal()->SendDisableSensorNotifications(aSensor); Hal()->SendDisableSensorNotifications(aSensor);
} }
//TODO: bug 852944 - IPC implementations of these
void StartMonitoringGamepadStatus()
{}
void StopMonitoringGamepadStatus()
{}
void void
EnableWakeLockNotifications() EnableWakeLockNotifications()
{ {

View File

@ -209,7 +209,7 @@ static void Shutdown();
#include "nsGeolocation.h" #include "nsGeolocation.h"
#include "nsDeviceSensors.h" #include "nsDeviceSensors.h"
#ifdef MOZ_GAMEPAD #ifdef MOZ_GAMEPAD
#include "mozilla/dom/GamepadService.h" #include "mozilla/dom/GamepadServiceTest.h"
#endif #endif
#include "mozilla/dom/nsCSPService.h" #include "mozilla/dom/nsCSPService.h"
#include "mozilla/dom/nsCSPContext.h" #include "mozilla/dom/nsCSPContext.h"

View File

@ -41,7 +41,8 @@
#include "mozilla/dom/ScreenOrientation.h" #include "mozilla/dom/ScreenOrientation.h"
#ifdef MOZ_GAMEPAD #ifdef MOZ_GAMEPAD
#include "mozilla/dom/GamepadService.h" #include "mozilla/dom/GamepadFunctions.h"
#include "mozilla/dom/Gamepad.h"
#endif #endif
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
@ -656,19 +657,15 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
case AndroidGeckoEvent::GAMEPAD_ADDREMOVE: { case AndroidGeckoEvent::GAMEPAD_ADDREMOVE: {
#ifdef MOZ_GAMEPAD #ifdef MOZ_GAMEPAD
nsRefPtr<mozilla::dom::GamepadService> svc =
mozilla::dom::GamepadService::GetService();
if (svc) {
if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_ADDED) { if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_ADDED) {
int svc_id = svc->AddGamepad("android", int svc_id = dom::GamepadFunctions::AddGamepad("android",
mozilla::dom::GamepadMappingType::Standard, dom::GamepadMappingType::Standard,
mozilla::dom::kStandardGamepadButtons, dom::kStandardGamepadButtons,
mozilla::dom::kStandardGamepadAxes); dom::kStandardGamepadAxes);
widget::GeckoAppShell::GamepadAdded(curEvent->ID(), widget::GeckoAppShell::GamepadAdded(curEvent->ID(),
svc_id); svc_id);
} else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_REMOVED) { } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_REMOVED) {
svc->RemoveGamepad(curEvent->ID()); dom::GamepadFunctions::RemoveGamepad(curEvent->ID());
}
} }
#endif #endif
break; break;
@ -676,12 +673,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
case AndroidGeckoEvent::GAMEPAD_DATA: { case AndroidGeckoEvent::GAMEPAD_DATA: {
#ifdef MOZ_GAMEPAD #ifdef MOZ_GAMEPAD
nsRefPtr<mozilla::dom::GamepadService> svc =
mozilla::dom::GamepadService::GetService();
if (svc) {
int id = curEvent->ID(); int id = curEvent->ID();
if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_BUTTON) { if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_BUTTON) {
svc->NewButtonEvent(id, curEvent->GamepadButton(), dom::GamepadFunctions::NewButtonEvent(id, curEvent->GamepadButton(),
curEvent->GamepadButtonPressed(), curEvent->GamepadButtonPressed(),
curEvent->GamepadButtonValue()); curEvent->GamepadButtonValue());
} else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_AXES) { } else if (curEvent->Action() == AndroidGeckoEvent::ACTION_GAMEPAD_AXES) {
@ -689,8 +683,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
const nsTArray<float>& values = curEvent->GamepadValues(); const nsTArray<float>& values = curEvent->GamepadValues();
for (unsigned i = 0; i < values.Length(); i++) { for (unsigned i = 0; i < values.Length(); i++) {
if (valid & (1<<i)) { if (valid & (1<<i)) {
svc->NewAxisMoveEvent(id, i, values[i]); dom::GamepadFunctions::NewAxisMoveEvent(id, i, values[i]);
}
} }
} }
} }