|
@@ -1,22 +1,7 @@
|
|
|
import { Engine } from '../Engines/engine';
|
|
|
import { IDisposable } from '../scene';
|
|
|
import { Nullable } from '../types';
|
|
|
-
|
|
|
-/**
|
|
|
- * POINTER_DEVICE
|
|
|
- * @hidden
|
|
|
- */
|
|
|
-export const POINTER_DEVICE: string = "Pointer";
|
|
|
-/**
|
|
|
- * KEYBOARD_DEVICE
|
|
|
- * @hidden
|
|
|
- */
|
|
|
-export const KEYBOARD_DEVICE: string = "Keyboard";
|
|
|
-/**
|
|
|
- * MOUSE_DEVICE
|
|
|
- * @hidden
|
|
|
- */
|
|
|
-export const MOUSE_DEVICE: string = "Mouse";
|
|
|
+import { DeviceType } from './InputDevices/deviceEnums';
|
|
|
|
|
|
/**
|
|
|
* This class will take all inputs from Keyboard, Pointer, and
|
|
@@ -28,21 +13,21 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
/**
|
|
|
* Callback to be triggered when a device is connected
|
|
|
*/
|
|
|
- public onDeviceConnected: (deviceName: string) => void;
|
|
|
+ public onDeviceConnected: (deviceType: DeviceType, deviceSlot: number) => void = () => {};
|
|
|
|
|
|
/**
|
|
|
* Callback to be triggered when a device is disconnected
|
|
|
*/
|
|
|
- public onDeviceDisconnected: (deviceName: string) => void;
|
|
|
+ public onDeviceDisconnected: (deviceType: DeviceType, deviceSlot: number) => void = () => {};
|
|
|
|
|
|
/**
|
|
|
* Callback to be triggered when event driven input is updated
|
|
|
*/
|
|
|
- public onInputChanged: (deviceName: string, inputIndex: number, previousState: Nullable<number>, currentState: Nullable<number>) => void;
|
|
|
+ public onInputChanged: (deviceType: DeviceType, deviceSlot: number, inputIndex: number, previousState: Nullable<number>, currentState: Nullable<number>) => void;
|
|
|
|
|
|
// Private Members
|
|
|
- private _inputs: { [key: string]: Array<Nullable<number>> } = {};
|
|
|
- private _gamepads: Array<string>;
|
|
|
+ private _inputs: Array<Array<Array<Nullable<number>>>> = [];
|
|
|
+ private _gamepads: Array<DeviceType>;
|
|
|
private _keyboardActive: boolean = false;
|
|
|
private _pointerActive: boolean = false;
|
|
|
private _elementToAttachTo: HTMLElement;
|
|
@@ -81,17 +66,17 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
* @param inputIndex Index of device input
|
|
|
* @returns Current value of input
|
|
|
*/
|
|
|
- public pollInput(deviceName: string, inputIndex: number): Nullable<number> {
|
|
|
- const device = this._inputs[deviceName];
|
|
|
+ public pollInput(deviceType: DeviceType, deviceSlot: number, inputIndex: number): Nullable<number> {
|
|
|
+ const device = this._inputs[deviceType][deviceSlot];
|
|
|
|
|
|
if (!device) {
|
|
|
- return null;
|
|
|
+ throw `Unable to find device ${DeviceType[deviceType]}`;
|
|
|
}
|
|
|
|
|
|
- this._updateDevice(deviceName, inputIndex);
|
|
|
+ this._updateDevice(deviceType, deviceSlot, inputIndex);
|
|
|
|
|
|
if (device[inputIndex] === undefined) {
|
|
|
- throw `Unable to find input ${inputIndex} on device ${deviceName}`;
|
|
|
+ throw `Unable to find input ${inputIndex} for device ${DeviceType[deviceType]} in slot ${deviceSlot}`;
|
|
|
}
|
|
|
|
|
|
return device[inputIndex];
|
|
@@ -125,16 +110,20 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
* @param deviceName Assigned name of device (may be SN)
|
|
|
* @param numberOfInputs Number of input entries to create for given device
|
|
|
*/
|
|
|
- private _registerDevice(deviceName: string, numberOfInputs: number) {
|
|
|
- if (!this._inputs[deviceName]) {
|
|
|
+ private _registerDevice(deviceType: DeviceType, deviceSlot: number, numberOfInputs: number) {
|
|
|
+ if (!this._inputs[deviceType]) {
|
|
|
+ this._inputs[deviceType] = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!this._inputs[deviceType][deviceSlot]) {
|
|
|
const device = new Array<Nullable<number>>(numberOfInputs);
|
|
|
|
|
|
for (let i = 0; i < numberOfInputs; i++) {
|
|
|
device[i] = null;
|
|
|
}
|
|
|
|
|
|
- this._inputs[deviceName] = device;
|
|
|
- this.onDeviceConnected(deviceName);
|
|
|
+ this._inputs[deviceType][deviceSlot] = device;
|
|
|
+ this.onDeviceConnected(deviceType, deviceSlot);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -142,10 +131,10 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
* Given a specific device name, remove that device from the device map
|
|
|
* @param deviceName Name of device to be removed
|
|
|
*/
|
|
|
- private _unregisterDevice(deviceName: string) {
|
|
|
- if (this._inputs[deviceName]) {
|
|
|
- delete this._inputs[deviceName];
|
|
|
- this.onDeviceDisconnected(deviceName);
|
|
|
+ private _unregisterDevice(deviceType: DeviceType, deviceSlot: number) {
|
|
|
+ if (this._inputs[deviceType][deviceSlot]) {
|
|
|
+ delete this._inputs[deviceType][deviceSlot];
|
|
|
+ this.onDeviceDisconnected(deviceType, deviceSlot);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -156,23 +145,23 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
this._keyboardDownEvent = ((evt) => {
|
|
|
if (!this._keyboardActive) {
|
|
|
this._keyboardActive = true;
|
|
|
- this._registerDevice(KEYBOARD_DEVICE, DeviceInputSystem._MAX_KEYCODES);
|
|
|
+ this._registerDevice(DeviceType.Keyboard, 0, DeviceInputSystem._MAX_KEYCODES);
|
|
|
}
|
|
|
|
|
|
- const kbKey = this._inputs[KEYBOARD_DEVICE];
|
|
|
+ const kbKey = this._inputs[DeviceType.Keyboard][0];
|
|
|
if (kbKey) {
|
|
|
if (this.onInputChanged) {
|
|
|
- this.onInputChanged(KEYBOARD_DEVICE, evt.keyCode, kbKey[evt.keyCode], 1);
|
|
|
+ this.onInputChanged(DeviceType.Keyboard, 0, evt.keyCode, kbKey[evt.keyCode], 1);
|
|
|
}
|
|
|
kbKey[evt.keyCode] = 1;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
this._keyboardUpEvent = ((evt) => {
|
|
|
- const kbKey = this._inputs[KEYBOARD_DEVICE];
|
|
|
+ const kbKey = this._inputs[DeviceType.Keyboard][0];
|
|
|
if (kbKey) {
|
|
|
if (this.onInputChanged) {
|
|
|
- this.onInputChanged(KEYBOARD_DEVICE, evt.keyCode, kbKey[evt.keyCode], 0);
|
|
|
+ this.onInputChanged(DeviceType.Keyboard, 0, evt.keyCode, kbKey[evt.keyCode], 0);
|
|
|
}
|
|
|
kbKey[evt.keyCode] = 0;
|
|
|
}
|
|
@@ -187,18 +176,23 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
*/
|
|
|
private _handlePointerActions() {
|
|
|
this._pointerMoveEvent = ((evt) => {
|
|
|
- const deviceName = (evt.pointerType == "mouse") ? MOUSE_DEVICE : `${POINTER_DEVICE}-${evt.pointerId}`;
|
|
|
+ const deviceType = (evt.pointerType == "mouse") ? DeviceType.Mouse : DeviceType.Touch;
|
|
|
+ const deviceSlot = (evt.pointerType == "mouse") ? 0 : evt.pointerId;
|
|
|
+
|
|
|
+ if (!this._inputs[deviceType]) {
|
|
|
+ this._inputs[deviceType] = [];
|
|
|
+ }
|
|
|
|
|
|
- if (!this._inputs[deviceName]) {
|
|
|
+ if (!this._inputs[deviceType][deviceSlot]) {
|
|
|
this._pointerActive = true;
|
|
|
- this._registerDevice(deviceName, DeviceInputSystem._MAX_POINTER_INPUTS);
|
|
|
+ this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
|
|
|
}
|
|
|
|
|
|
- const pointer = this._inputs[deviceName];
|
|
|
+ const pointer = this._inputs[deviceType][deviceSlot];
|
|
|
if (pointer) {
|
|
|
if (this.onInputChanged) {
|
|
|
- this.onInputChanged(deviceName, 0, pointer[0], evt.clientX);
|
|
|
- this.onInputChanged(deviceName, 1, pointer[1], evt.clientY);
|
|
|
+ this.onInputChanged(deviceType, deviceSlot, 0, pointer[0], evt.clientX);
|
|
|
+ this.onInputChanged(deviceType, deviceSlot, 1, pointer[1], evt.clientY);
|
|
|
}
|
|
|
pointer[0] = evt.clientX;
|
|
|
pointer[1] = evt.clientY;
|
|
@@ -206,19 +200,24 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
});
|
|
|
|
|
|
this._pointerDownEvent = ((evt) => {
|
|
|
+ const deviceType = (evt.pointerType == "mouse") ? DeviceType.Mouse : DeviceType.Touch;
|
|
|
+ const deviceSlot = (evt.pointerType == "mouse") ? 0 : evt.pointerId;
|
|
|
+
|
|
|
+ if (!this._inputs[deviceType]) {
|
|
|
+ this._inputs[deviceType] = [];
|
|
|
+ }
|
|
|
|
|
|
- const deviceName = (evt.pointerType == "mouse") ? MOUSE_DEVICE : `${POINTER_DEVICE}-${evt.pointerId}`;
|
|
|
- if (!this._inputs[deviceName]) {
|
|
|
+ if (!this._inputs[deviceType][deviceSlot]) {
|
|
|
this._pointerActive = true;
|
|
|
- this._registerDevice(deviceName, DeviceInputSystem._MAX_POINTER_INPUTS);
|
|
|
+ this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
|
|
|
}
|
|
|
|
|
|
- const pointer = this._inputs[deviceName];
|
|
|
+ const pointer = this._inputs[deviceType][deviceSlot];
|
|
|
if (pointer) {
|
|
|
if (this.onInputChanged) {
|
|
|
- this.onInputChanged(deviceName, 0, pointer[0], evt.clientX);
|
|
|
- this.onInputChanged(deviceName, 1, pointer[1], evt.clientY);
|
|
|
- this.onInputChanged(deviceName, evt.button + 2, pointer[evt.button + 2], 1);
|
|
|
+ this.onInputChanged(deviceType, deviceSlot, 0, pointer[0], evt.clientX);
|
|
|
+ this.onInputChanged(deviceType, deviceSlot, 1, pointer[1], evt.clientY);
|
|
|
+ this.onInputChanged(deviceType, deviceSlot, evt.button + 2, pointer[evt.button + 2], 1);
|
|
|
}
|
|
|
pointer[0] = evt.clientX;
|
|
|
pointer[1] = evt.clientY;
|
|
@@ -227,19 +226,20 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
});
|
|
|
|
|
|
this._pointerUpEvent = ((evt) => {
|
|
|
- const deviceName = (evt.pointerType == "mouse") ? MOUSE_DEVICE : `${POINTER_DEVICE}-${evt.pointerId}`;
|
|
|
+ const deviceType = (evt.pointerType == "mouse") ? DeviceType.Mouse : DeviceType.Touch;
|
|
|
+ const deviceSlot = (evt.pointerType == "mouse") ? 0 : evt.pointerId;
|
|
|
|
|
|
- const pointer = this._inputs[deviceName];
|
|
|
+ const pointer = this._inputs[deviceType][deviceSlot];
|
|
|
if (pointer) {
|
|
|
if (this.onInputChanged) {
|
|
|
- this.onInputChanged(deviceName, evt.button + 2, pointer[evt.button + 2], 0);
|
|
|
+ this.onInputChanged(deviceType, deviceSlot, evt.button + 2, pointer[evt.button + 2], 0);
|
|
|
}
|
|
|
pointer[evt.button + 2] = 0;
|
|
|
}
|
|
|
// We don't want to unregister the mouse because we may miss input data when a mouse is moving after a click
|
|
|
if (evt.pointerType != "mouse")
|
|
|
{
|
|
|
- this._unregisterDevice(deviceName);
|
|
|
+ this._unregisterDevice(deviceType, deviceSlot);
|
|
|
}
|
|
|
|
|
|
});
|
|
@@ -254,17 +254,21 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
*/
|
|
|
private _handleGamepadActions() {
|
|
|
this._gamepadConnectedEvent = ((evt: any) => {
|
|
|
- const deviceName = `${evt.gamepad.id}-${evt.gamepad.index}`;
|
|
|
- this._registerDevice(deviceName, evt.gamepad.buttons.length + evt.gamepad.axes.length);
|
|
|
+ const deviceType = this._getGamepadDeviceType(evt.gamepad.id);
|
|
|
+ const deviceSlot = evt.gamepad.index;
|
|
|
+
|
|
|
+ this._registerDevice(deviceType, deviceSlot, evt.gamepad.buttons.length + evt.gamepad.axes.length);
|
|
|
this._gamepads = this._gamepads || new Array<string>(evt.gamepad.index + 1);
|
|
|
- this._gamepads[evt.gamepad.index] = deviceName;
|
|
|
+ this._gamepads[deviceSlot] = deviceType;
|
|
|
});
|
|
|
|
|
|
this._gamepadDisconnectedEvent = ((evt: any) => {
|
|
|
if (this._gamepads) {
|
|
|
- const deviceName = this._gamepads[evt.gamepad.index];
|
|
|
- this._unregisterDevice(deviceName);
|
|
|
- delete this._gamepads[evt.gamepad.index];
|
|
|
+ const deviceType = this._getGamepadDeviceType(evt.gamepad.id);
|
|
|
+ const deviceSlot = evt.gamepad.index;
|
|
|
+
|
|
|
+ this._unregisterDevice(deviceType, deviceSlot);
|
|
|
+ delete this._gamepads[deviceSlot];
|
|
|
}
|
|
|
});
|
|
|
|
|
@@ -275,22 +279,38 @@ export class DeviceInputSystem implements IDisposable {
|
|
|
/**
|
|
|
* Update all non-event based devices with each frame
|
|
|
*/
|
|
|
- private _updateDevice(deviceName: string, inputIndex: number) {
|
|
|
+ private _updateDevice(deviceType: DeviceType, deviceSlot: number, inputIndex: number) {
|
|
|
// Gamepads
|
|
|
- const gamepads = navigator.getGamepads();
|
|
|
+ const gp = navigator.getGamepads()[deviceSlot];
|
|
|
|
|
|
- // Look for current gamepad and get updated values
|
|
|
- for (const gp of gamepads) {
|
|
|
- if (gp && deviceName == this._gamepads[gp.index]) {
|
|
|
- const device = this._inputs[deviceName];
|
|
|
+ if (gp && deviceType == this._gamepads[deviceSlot]) {
|
|
|
+ const device = this._inputs[deviceType][deviceSlot];
|
|
|
|
|
|
- if (inputIndex >= gp.buttons.length) {
|
|
|
- device[inputIndex] = gp.axes[inputIndex - gp.buttons.length].valueOf();
|
|
|
- }
|
|
|
- else {
|
|
|
- device[inputIndex] = gp.buttons[inputIndex].value;
|
|
|
- }
|
|
|
+ if (inputIndex >= gp.buttons.length) {
|
|
|
+ device[inputIndex] = gp.axes[inputIndex - gp.buttons.length].valueOf();
|
|
|
}
|
|
|
+ else {
|
|
|
+ device[inputIndex] = gp.buttons[inputIndex].value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets DeviceType from the device name
|
|
|
+ * @param deviceName Name of Device from DeviceInputSystem
|
|
|
+ * @returns DeviceType enum value
|
|
|
+ */
|
|
|
+ private _getGamepadDeviceType(deviceName: string): DeviceType {
|
|
|
+ if (deviceName.indexOf("054c") !== -1) { // DualShock 4 Gamepad
|
|
|
+ return DeviceType.DualShock;
|
|
|
}
|
|
|
+ else if (deviceName.indexOf("Xbox One") !== -1 || deviceName.search("Xbox 360") !== -1 || deviceName.search("xinput") !== -1) { // Xbox Gamepad
|
|
|
+ return DeviceType.Xbox;
|
|
|
+ }
|
|
|
+ else if (deviceName.indexOf("057e") !== -1) { // Switch Gamepad
|
|
|
+ return DeviceType.Switch;
|
|
|
+ }
|
|
|
+
|
|
|
+ return DeviceType.Generic;
|
|
|
}
|
|
|
}
|