babylon.gamepadManager.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. module BABYLON {
  2. export class GamepadManager {
  3. private _babylonGamepads: Array<Gamepad> = [];
  4. private _oneGamepadConnected: boolean = false;
  5. /** @hidden */
  6. public _isMonitoring: boolean = false;
  7. private _gamepadEventSupported: boolean;
  8. private _gamepadSupport: () => Array<any>;
  9. public onGamepadConnectedObservable: Observable<Gamepad>;
  10. public onGamepadDisconnectedObservable = new Observable<Gamepad>();
  11. private _onGamepadConnectedEvent: Nullable<(evt: any) => void>;
  12. private _onGamepadDisconnectedEvent: Nullable<(evt: any) => void>;
  13. constructor(private _scene?: Scene) {
  14. if (!Tools.IsWindowObjectExist()) {
  15. this._gamepadEventSupported = false;
  16. } else {
  17. this._gamepadEventSupported = 'GamepadEvent' in window;
  18. this._gamepadSupport = (navigator.getGamepads ||
  19. navigator.webkitGetGamepads || navigator.msGetGamepads || navigator.webkitGamepads);
  20. }
  21. this.onGamepadConnectedObservable = new Observable<Gamepad>((observer) => {
  22. // This will be used to raise the onGamepadConnected for all gamepads ALREADY connected
  23. for (var i in this._babylonGamepads) {
  24. let gamepad = this._babylonGamepads[i];
  25. if (gamepad && gamepad._isConnected) {
  26. this.onGamepadConnectedObservable.notifyObserver(observer, gamepad);
  27. }
  28. }
  29. });
  30. this._onGamepadConnectedEvent = (evt) => {
  31. let gamepad = evt.gamepad;
  32. if (gamepad.index in this._babylonGamepads) {
  33. if (this._babylonGamepads[gamepad.index].isConnected) {
  34. return;
  35. }
  36. }
  37. let newGamepad: Gamepad;
  38. if (this._babylonGamepads[gamepad.index]) {
  39. newGamepad = this._babylonGamepads[gamepad.index];
  40. newGamepad.browserGamepad = gamepad;
  41. newGamepad._isConnected = true;
  42. } else {
  43. newGamepad = this._addNewGamepad(gamepad);
  44. }
  45. this.onGamepadConnectedObservable.notifyObservers(newGamepad);
  46. this._startMonitoringGamepads();
  47. };
  48. this._onGamepadDisconnectedEvent = (evt) => {
  49. let gamepad = evt.gamepad;
  50. // Remove the gamepad from the list of gamepads to monitor.
  51. for (var i in this._babylonGamepads) {
  52. if (this._babylonGamepads[i].index === gamepad.index) {
  53. let disconnectedGamepad = this._babylonGamepads[i];
  54. disconnectedGamepad._isConnected = false;
  55. this.onGamepadDisconnectedObservable.notifyObservers(disconnectedGamepad);
  56. break;
  57. }
  58. }
  59. };
  60. if (this._gamepadSupport) {
  61. //first add already-connected gamepads
  62. this._updateGamepadObjects();
  63. if (this._babylonGamepads.length) {
  64. this._startMonitoringGamepads();
  65. }
  66. // Checking if the gamepad connected event is supported (like in Firefox)
  67. if (this._gamepadEventSupported) {
  68. window.addEventListener('gamepadconnected', this._onGamepadConnectedEvent, false);
  69. window.addEventListener('gamepaddisconnected', this._onGamepadDisconnectedEvent, false);
  70. }
  71. else {
  72. this._startMonitoringGamepads();
  73. }
  74. }
  75. }
  76. public get gamepads(): Gamepad[] {
  77. return this._babylonGamepads;
  78. }
  79. public getGamepadByType(type: number = Gamepad.XBOX): Nullable<Gamepad> {
  80. for (var gamepad of this._babylonGamepads) {
  81. if (gamepad && gamepad.type === type) {
  82. return gamepad;
  83. }
  84. }
  85. return null;
  86. }
  87. public dispose() {
  88. if (this._gamepadEventSupported) {
  89. if (this._onGamepadConnectedEvent) {
  90. window.removeEventListener('gamepadconnected', this._onGamepadConnectedEvent);
  91. }
  92. if (this._onGamepadDisconnectedEvent) {
  93. window.removeEventListener('gamepaddisconnected', this._onGamepadDisconnectedEvent);
  94. }
  95. this._onGamepadConnectedEvent = null;
  96. this._onGamepadDisconnectedEvent = null;
  97. }
  98. this._babylonGamepads.forEach((gamepad) => {
  99. gamepad.dispose();
  100. });
  101. this.onGamepadConnectedObservable.clear();
  102. this.onGamepadDisconnectedObservable.clear();
  103. this._oneGamepadConnected = false;
  104. this._stopMonitoringGamepads();
  105. this._babylonGamepads = [];
  106. }
  107. private _addNewGamepad(gamepad: any): Gamepad {
  108. if (!this._oneGamepadConnected) {
  109. this._oneGamepadConnected = true;
  110. }
  111. var newGamepad;
  112. var xboxOne: boolean = ((<string>gamepad.id).search("Xbox One") !== -1);
  113. if (xboxOne || (<string>gamepad.id).search("Xbox 360") !== -1 || (<string>gamepad.id).search("xinput") !== -1) {
  114. newGamepad = new Xbox360Pad(gamepad.id, gamepad.index, gamepad, xboxOne);
  115. }
  116. // if pose is supported, use the (WebVR) pose enabled controller
  117. else if (gamepad.pose) {
  118. newGamepad = PoseEnabledControllerHelper.InitiateController(gamepad);
  119. }
  120. else {
  121. newGamepad = new GenericPad(gamepad.id, gamepad.index, gamepad);
  122. }
  123. this._babylonGamepads[newGamepad.index] = newGamepad;
  124. return newGamepad;
  125. }
  126. private _startMonitoringGamepads() {
  127. if (!this._isMonitoring) {
  128. this._isMonitoring = true;
  129. //back-comp
  130. if (!this._scene) {
  131. this._checkGamepadsStatus();
  132. }
  133. }
  134. }
  135. private _stopMonitoringGamepads() {
  136. this._isMonitoring = false;
  137. }
  138. /** @hidden */
  139. public _checkGamepadsStatus() {
  140. // Hack to be compatible Chrome
  141. this._updateGamepadObjects();
  142. for (var i in this._babylonGamepads) {
  143. let gamepad = this._babylonGamepads[i];
  144. if (!gamepad || !gamepad.isConnected) {
  145. continue;
  146. }
  147. gamepad.update();
  148. }
  149. if (this._isMonitoring && !this._scene) {
  150. Tools.QueueNewFrame(() => { this._checkGamepadsStatus(); });
  151. }
  152. }
  153. // This function is called only on Chrome, which does not properly support
  154. // connection/disconnection events and forces you to recopy again the gamepad object
  155. private _updateGamepadObjects() {
  156. var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
  157. for (var i = 0; i < gamepads.length; i++) {
  158. let gamepad = gamepads[i];
  159. if (gamepad) {
  160. if (!this._babylonGamepads[gamepad.index]) {
  161. var newGamepad = this._addNewGamepad(gamepad);
  162. this.onGamepadConnectedObservable.notifyObservers(newGamepad);
  163. }
  164. else {
  165. // Forced to copy again this object for Chrome for unknown reason
  166. this._babylonGamepads[i].browserGamepad = gamepad;
  167. if (!this._babylonGamepads[i].isConnected) {
  168. this._babylonGamepads[i]._isConnected = true;
  169. this.onGamepadConnectedObservable.notifyObservers(this._babylonGamepads[i]);
  170. }
  171. }
  172. }
  173. }
  174. }
  175. }
  176. }