summaryrefslogtreecommitdiffstats
path: root/dom/gamepad/GamepadManager.h
blob: 794c0d1ca472a00f5033e2a9a31c8a5d9d50ef03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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_GamepadManager_h_
#define mozilla_dom_GamepadManager_h_

#include "nsIObserver.h"
#include "nsRefPtrHashtable.h"
// Needed for GamepadMappingType
#include "mozilla/dom/GamepadBinding.h"
#include "mozilla/dom/GamepadHandle.h"
#include <utility>

class nsGlobalWindowInner;
class nsIGlobalObject;

namespace mozilla {
namespace gfx {
class VRManagerChild;
}  // namespace gfx
namespace dom {

class EventTarget;
class Gamepad;
class GamepadChangeEvent;
class GamepadEventChannelChild;

class GamepadManager final : public nsIObserver {
 public:
  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<GamepadManager> GetService();

  void BeginShutdown();
  void StopMonitoring();

  // Indicate that |aWindow| wants to receive gamepad events.
  void AddListener(nsGlobalWindowInner* aWindow);
  // Indicate that |aWindow| should no longer receive gamepad events.
  void RemoveListener(nsGlobalWindowInner* aWindow);

  // Add a gamepad to the list of known gamepads.
  void AddGamepad(GamepadHandle aHandle, const nsAString& aID,
                  GamepadMappingType aMapping, GamepadHand aHand,
                  uint32_t aDisplayID, uint32_t aNumButtons, uint32_t aNumAxes,
                  uint32_t aNumHaptics, uint32_t aNumLightIndicator,
                  uint32_t aNumTouchEvents);

  // Remove the gamepad at |aIndex| from the list of known gamepads.
  void RemoveGamepad(GamepadHandle aHandle);

  // Synchronize the state of |aGamepad| to match the gamepad stored at |aIndex|
  void SyncGamepadState(GamepadHandle aHandle, nsGlobalWindowInner* aWindow,
                        Gamepad* aGamepad);

  // Returns gamepad object if index exists, null otherwise
  already_AddRefed<Gamepad> GetGamepad(GamepadHandle aHandle) const;

  // Receive GamepadChangeEvent messages from parent process to fire DOM events
  void Update(const GamepadChangeEvent& aGamepadEvent);

  // Trigger vibrate haptic event to gamepad channels.
  already_AddRefed<Promise> VibrateHaptic(GamepadHandle aHandle,
                                          uint32_t aHapticIndex,
                                          double aIntensity, double aDuration,
                                          nsIGlobalObject* aGlobal,
                                          ErrorResult& aRv);
  // Send stop haptic events to gamepad channels.
  void StopHaptics();

  // Set light indicator color event to gamepad channels.
  already_AddRefed<Promise> SetLightIndicatorColor(GamepadHandle aHandle,
                                                   uint32_t aLightColorIndex,
                                                   uint8_t aRed, uint8_t aGreen,
                                                   uint8_t aBlue,
                                                   nsIGlobalObject* aGlobal,
                                                   ErrorResult& aRv);

 protected:
  GamepadManager();
  ~GamepadManager() = default;

  // Fire a gamepadconnected or gamepaddisconnected event for the gamepad
  // at |aIndex| to all windows that are listening and have received
  // gamepad input.
  void NewConnectionEvent(GamepadHandle aHandle, bool aConnected);

  // Fire a gamepadaxismove event to the window at |aTarget| for |aGamepad|.
  void FireAxisMoveEvent(EventTarget* aTarget, Gamepad* aGamepad, uint32_t axis,
                         double value);

  // Fire one of gamepadbutton{up,down} event at the window at |aTarget| for
  // |aGamepad|.
  void FireButtonEvent(EventTarget* aTarget, Gamepad* aGamepad,
                       uint32_t aButton, double aValue);

  // Fire one of gamepad{connected,disconnected} event at the window at
  // |aTarget| for |aGamepad|.
  void FireConnectionEvent(EventTarget* aTarget, Gamepad* aGamepad,
                           bool aConnected);

  // true if this feature is enabled in preferences
  bool mEnabled;
  // true if non-standard events are enabled in preferences
  bool mNonstandardEventsEnabled;
  // true when shutdown has begun
  bool mShuttingDown;

  RefPtr<GamepadEventChannelChild> mChannelChild;

 private:
  nsresult Init();

  void MaybeConvertToNonstandardGamepadEvent(const GamepadChangeEvent& aEvent,
                                             nsGlobalWindowInner* aWindow);

  bool SetGamepadByEvent(const GamepadChangeEvent& aEvent,
                         nsGlobalWindowInner* aWindow = nullptr);
  // To avoid unintentionally causing the gamepad be activated.
  // Returns false if this gamepad hasn't been seen by this window
  // and the axis move data is less than AXIS_FIRST_INTENT_THRESHOLD_VALUE.
  bool AxisMoveIsFirstIntent(nsGlobalWindowInner* aWindow,
                             GamepadHandle aHandle,
                             const GamepadChangeEvent& aEvent);
  bool MaybeWindowHasSeenGamepad(nsGlobalWindowInner* aWindow,
                                 GamepadHandle aHandle);
  // Returns true if we have already sent data from this gamepad
  // to this window. This should only return true if the user
  // explicitly interacted with a gamepad while this window
  // was focused, by pressing buttons or similar actions.
  bool WindowHasSeenGamepad(nsGlobalWindowInner* aWindow,
                            GamepadHandle aHandle) const;
  // Indicate that a window has received data from a gamepad.
  void SetWindowHasSeenGamepad(nsGlobalWindowInner* aWindow,
                               GamepadHandle aHandle, bool aHasSeen = true);

  // Gamepads connected to the system. Copies of these are handed out
  // to each window.
  nsRefPtrHashtable<nsGenericHashKey<GamepadHandle>, Gamepad> mGamepads;
  // Inner windows that are listening for gamepad events.
  // has been sent to that window.
  nsTArray<RefPtr<nsGlobalWindowInner>> mListeners;
  uint32_t mPromiseID;
};

}  // namespace dom
}  // namespace mozilla

#endif  // mozilla_dom_GamepadManager_h_