deviceSourceManager.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { DeviceInputSystem } from '../deviceInputSystem';
  2. import { Engine } from '../../Engines/engine';
  3. import { IDisposable } from '../../scene';
  4. import { DeviceType } from './deviceEnums';
  5. import { Nullable } from '../../types';
  6. import { Observable } from '../../Misc/observable';
  7. import { DeviceInput } from './deviceTypes';
  8. /**
  9. * Class that handles all input for a specific device
  10. */
  11. export class DeviceSource<T extends DeviceType> {
  12. // Public Members
  13. /**
  14. * Observable to handle device input changes per device
  15. */
  16. public readonly onInputChangedObservable = new Observable<{ inputIndex: DeviceInput<T>, previousState: Nullable<number>, currentState: Nullable<number> }>();
  17. // Private Members
  18. private readonly _deviceInputSystem: DeviceInputSystem;
  19. /**
  20. * Default Constructor
  21. * @param deviceInputSystem Reference to DeviceInputSystem
  22. * @param deviceType Type of device
  23. * @param deviceSlot "Slot" or index that device is referenced in
  24. */
  25. constructor(deviceInputSystem: DeviceInputSystem,
  26. /** Type of device */
  27. public readonly deviceType: DeviceType,
  28. /** "Slot" or index that device is referenced in */
  29. public readonly deviceSlot: number = 0) {
  30. this._deviceInputSystem = deviceInputSystem;
  31. }
  32. /**
  33. * Get input for specific input
  34. * @param inputIndex index of specific input on device
  35. * @returns Input value from DeviceInputSystem
  36. */
  37. public getInput(inputIndex: DeviceInput<T>): Nullable<number> {
  38. return this._deviceInputSystem.pollInput(this.deviceType, this.deviceSlot, inputIndex);
  39. }
  40. }
  41. /**
  42. * Class to keep track of devices
  43. */
  44. export class DeviceSourceManager implements IDisposable {
  45. // Public Members
  46. /**
  47. * Observable to be triggered when before a device is connected
  48. */
  49. public readonly onBeforeDeviceConnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
  50. /**
  51. * Observable to be triggered when before a device is disconnected
  52. */
  53. public readonly onBeforeDeviceDisconnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
  54. /**
  55. * Observable to be triggered when after a device is connected
  56. */
  57. public readonly onAfterDeviceConnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
  58. /**
  59. * Observable to be triggered when after a device is disconnected
  60. */
  61. public readonly onAfterDeviceDisconnectedObservable = new Observable<{ deviceType: DeviceType, deviceSlot: number }>();
  62. // Private Members
  63. private readonly _devices: Array<Array<DeviceSource<DeviceType>>>;
  64. private readonly _firstDevice: Array<number>;
  65. private readonly _deviceInputSystem: DeviceInputSystem;
  66. /**
  67. * Default Constructor
  68. * @param engine engine to pull input element from
  69. */
  70. constructor(engine: Engine) {
  71. const numberOfDeviceTypes = Object.keys(DeviceType).length / 2;
  72. this._devices = new Array<Array<DeviceSource<DeviceType>>>(numberOfDeviceTypes);
  73. this._firstDevice = new Array<number>(numberOfDeviceTypes);
  74. this._deviceInputSystem = DeviceInputSystem.Create(engine);
  75. this._deviceInputSystem.onDeviceConnected = (deviceType, deviceSlot) => {
  76. this.onBeforeDeviceConnectedObservable.notifyObservers({ deviceType, deviceSlot });
  77. this._addDevice(deviceType, deviceSlot);
  78. this.onAfterDeviceConnectedObservable.notifyObservers({ deviceType, deviceSlot });
  79. };
  80. this._deviceInputSystem.onDeviceDisconnected = (deviceType, deviceSlot) => {
  81. this.onBeforeDeviceDisconnectedObservable.notifyObservers({ deviceType, deviceSlot });
  82. this._removeDevice(deviceType, deviceSlot);
  83. this.onAfterDeviceDisconnectedObservable.notifyObservers({ deviceType, deviceSlot });
  84. };
  85. if (!this._deviceInputSystem.onInputChanged) {
  86. this._deviceInputSystem.onInputChanged = (deviceType, deviceSlot, inputIndex, previousState, currentState) => {
  87. this.getDeviceSource(deviceType, deviceSlot)?.onInputChangedObservable.notifyObservers({ inputIndex, previousState, currentState });
  88. };
  89. }
  90. }
  91. // Public Functions
  92. /**
  93. * Gets a DeviceSource, given a type and slot
  94. * @param deviceType Enum specifying device type
  95. * @param deviceSlot "Slot" or index that device is referenced in
  96. * @returns DeviceSource object
  97. */
  98. public getDeviceSource<T extends DeviceType>(deviceType: T, deviceSlot?: number): Nullable<DeviceSource<T>> {
  99. if (deviceSlot === undefined) {
  100. if (this._firstDevice[deviceType] === undefined) {
  101. return null;
  102. }
  103. deviceSlot = this._firstDevice[deviceType];
  104. }
  105. if (!this._devices[deviceType] || this._devices[deviceType][deviceSlot] === undefined) {
  106. return null;
  107. }
  108. return this._devices[deviceType][deviceSlot];
  109. }
  110. /**
  111. * Gets an array of DeviceSource objects for a given device type
  112. * @param deviceType Enum specifying device type
  113. * @returns Array of DeviceSource objects
  114. */
  115. public getDeviceSources<T extends DeviceType>(deviceType: T): ReadonlyArray<DeviceSource<T>> {
  116. return this._devices[deviceType];
  117. }
  118. /**
  119. * Dispose of DeviceInputSystem and other parts
  120. */
  121. public dispose() {
  122. this._deviceInputSystem.dispose();
  123. }
  124. // Private Functions
  125. /**
  126. * Function to add device name to device list
  127. * @param deviceType Enum specifying device type
  128. * @param deviceSlot "Slot" or index that device is referenced in
  129. */
  130. private _addDevice(deviceType: DeviceType, deviceSlot: number) {
  131. if (!this._devices[deviceType]) {
  132. this._devices[deviceType] = new Array<DeviceSource<DeviceType>>();
  133. }
  134. this._devices[deviceType][deviceSlot] = new DeviceSource(this._deviceInputSystem, deviceType, deviceSlot);
  135. this._updateFirstDevices(deviceType);
  136. }
  137. /**
  138. * Function to remove device name to device list
  139. * @param deviceType Enum specifying device type
  140. * @param deviceSlot "Slot" or index that device is referenced in
  141. */
  142. private _removeDevice(deviceType: DeviceType, deviceSlot: number) {
  143. delete this._devices[deviceType][deviceSlot];
  144. this._updateFirstDevices(deviceType);
  145. }
  146. /**
  147. * Updates array storing first connected device of each type
  148. * @param type Type of Device
  149. */
  150. private _updateFirstDevices(type: DeviceType) {
  151. switch (type) {
  152. case DeviceType.Keyboard:
  153. case DeviceType.Mouse:
  154. this._firstDevice[type] = 0;
  155. break;
  156. case DeviceType.Touch:
  157. case DeviceType.DualShock:
  158. case DeviceType.Xbox:
  159. case DeviceType.Switch:
  160. case DeviceType.Generic:
  161. const devices = this._devices[type];
  162. delete this._firstDevice[type];
  163. for (let i = 0; i < devices.length; i++) {
  164. if (devices[i]) {
  165. this._firstDevice[type] = i;
  166. break;
  167. }
  168. }
  169. break;
  170. }
  171. }
  172. }