浏览代码

Initial commit for DeviceSourceManager

Dave Solares 5 年之前
父节点
当前提交
a7485e32ce

+ 1 - 0
dist/preview release/what's new.md

@@ -15,6 +15,7 @@
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
 - Added initial code for DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
 - Added support for `material.disableColorWrite` ([Deltakosh](https://github.com/deltakosh))
+- Added initial code for user facing DeviceSourceManager ([PolygonalSun](https://github.com/PolygonalSun))
 
 ### Engine
 

+ 189 - 0
src/DeviceInput/InputDevices/deviceEnums.ts

@@ -0,0 +1,189 @@
+/**
+ * Enum for Device Types
+ */
+export enum DeviceType {
+    /** Keyboard */
+    Keyboard = 0,
+    /** Mouse */
+    Mouse = 1,
+    /** Touch Pointers */
+    Touch = 2,
+    /** PS4 Dual Shock */
+    DualShock = 3,
+    /** Xbox */
+    Xbox = 4,
+    /** Switch Controller */
+    Switch = 5,
+    /** Generic Device */
+    GenericDevice = 6
+}
+
+// Device Enums
+/**
+ * Enum for All Pointers (Touch/Mouse)
+ */
+export enum PointerInputs
+{
+    /** Horizontal Axis */
+    Horizontal = 0,
+    /** Vertical Axis */
+    Vertical = 1,
+    /** Left Click or Touch */
+    LeftClick = 2,
+    /** Middle Click */
+    MiddleClick = 3,
+    /** Right Click */
+    RightClick = 4,
+    /** Browser Back */
+    BrowserBack = 5,
+    /** Browser Forward */
+    BrowserForward = 6
+}
+
+/**
+ * Enum for Dual Shock Gamepad
+ */
+export enum DualShockInputs {
+    /** Cross */
+    Cross = 0,
+    /** Circle */
+    Circle = 1,
+    /** Square */
+    Square = 2,
+    /** Triangle */
+    Triangle = 3,
+    /** L1 */
+    L1 = 4,
+    /** R1 */
+    R1 = 5,
+    /** L2 */
+    L2 = 6,
+    /** R2 */
+    R2 = 7,
+    /** Share */
+    Share = 8,
+    /** Options */
+    Options = 9,
+    /** L3 */
+    L3 = 10,
+    /** R3 */
+    R3 = 11,
+    /** DPadUp */
+    DPadUp = 12,
+    /** DPadDown */
+    DPadDown = 13,
+    /** DPadLeft */
+    DPadLeft = 14,
+    /** DRight */
+    DPadRight = 15,
+    /** Home */
+    Home = 16,
+    /** TouchPad */
+    TouchPad = 17,
+    /** LStickXAxis */
+    LStickXAxis = 18,
+    /** LStickYAxis */
+    LStickYAxis = 19,
+    /** RStickXAxis */
+    RStickXAxis = 20,
+    /** RStickYAxis */
+    RStickYAxis = 21
+}
+
+/**
+ * Enum for Xbox Gamepad
+ */
+export enum XboxInputs {
+    /** A */
+    A = 0,
+    /** B */
+    B = 1,
+    /** X */
+    X = 2,
+    /** Y */
+    Y = 3,
+    /** LB */
+    LB = 4,
+    /** RB */
+    RB = 5,
+    /** LT */
+    LT = 6,
+    /** RT */
+    RT = 7,
+    /** Back */
+    Back = 8,
+    /** Start */
+    Start = 9,
+    /** LS */
+    LS = 10,
+    /** RS */
+    RS = 11,
+    /** DPadUp */
+    DPadUp = 12,
+    /** DPadDown */
+    DPadDown = 13,
+    /** DPadLeft */
+    DPadLeft = 14,
+    /** DRight */
+    DPadRight = 15,
+    /** Home */
+    Home = 16,
+    /** LStickXAxis */
+    LStickXAxis = 17,
+    /** LStickYAxis */
+    LStickYAxis = 18,
+    /** RStickXAxis */
+    RStickXAxis = 19,
+    /** RStickYAxis */
+    RStickYAxis = 20
+}
+
+/**
+ * Enum for Switch (Pro/JoyCon L+R) Gamepad
+ */
+export enum SwitchInputs {
+    /** B */
+    B = 0,
+    /** A */
+    A = 1,
+    /** Y */
+    Y = 2,
+    /** X */
+    X = 3,
+    /** L */
+    L = 4,
+    /** R */
+    R = 5,
+    /** ZL */
+    ZL = 6,
+    /** ZR */
+    ZR = 7,
+    /** Minus */
+    Minus = 8,
+    /** Plus */
+    Plus = 9,
+    /** LS */
+    LS = 10,
+    /** RS */
+    RS = 11,
+    /** DPadUp */
+    DPadUp = 12,
+    /** DPadDown */
+    DPadDown = 13,
+    /** DPadLeft */
+    DPadLeft = 14,
+    /** DRight */
+    DPadRight = 15,
+    /** Home */
+    Home = 16,
+    /** Capture */
+    Capture = 17,
+    /** LStickXAxis */
+    LStickXAxis = 18,
+    /** LStickYAxis */
+    LStickYAxis = 19,
+    /** RStickXAxis */
+    RStickXAxis = 20,
+    /** RStickYAxis */
+    RStickYAxis = 21
+}

+ 218 - 0
src/DeviceInput/InputDevices/deviceSourceManager.ts

@@ -0,0 +1,218 @@
+import { DeviceInputSystem } from '../deviceInputSystem';
+import { Engine } from '../../Engines/engine';
+import { IDisposable } from '../../scene';
+import { DeviceType } from './deviceEnums';
+import { Nullable } from '../../types';
+import { Observable } from '../../Misc/observable';
+
+/**
+ * Class to keep track of devices
+ */
+export class DeviceSourceManager implements IDisposable {
+    // Public Members
+    /**
+     * Observable to be triggered when before a device is connected
+     */
+    public onBeforeDeviceConnectedObservable = new Observable<string>();
+
+    /**
+     * Observable to be triggered when before a device is disconnected
+     */
+    public onBeforeDeviceDisconnectedObservable = new Observable<string>();
+
+    /**
+     * Observable to be triggered when after a device is connected
+     */
+    public onAfterDeviceConnectedObservable = new Observable<string>();
+
+    /**
+     * Observable to be triggered when after a device is disconnected
+     */
+    public onAfterDeviceDisconnectedObservable = new Observable<string>();
+
+    // Private Members
+    private _devices: Array<Array<string>>;
+    private _touchPoints: Array<string>;
+    private _firstDevice: Array<number>;
+    private _deviceInputSystem: DeviceInputSystem;
+
+    /**
+     * Default Constructor
+     * @param engine - engine to pull input element from
+     */
+    constructor(engine: Engine) {
+        const numberOfDeviceTypes = Object.keys(DeviceType).length / 2;
+        this._devices = new Array<Array<string>>(numberOfDeviceTypes);
+        this._firstDevice = new Array<number>(numberOfDeviceTypes);
+        this._deviceInputSystem = new DeviceInputSystem(engine);
+
+        this._deviceInputSystem.onDeviceConnectedObservable.add((deviceName) => {
+            this.onBeforeDeviceConnectedObservable.notifyObservers(deviceName);
+            this._addDevice(deviceName);
+            this.onAfterDeviceConnectedObservable.notifyObservers(deviceName);
+        });
+        this._deviceInputSystem.onDeviceDisconnectedObservable.add((deviceName) => {
+            this.onBeforeDeviceDisconnectedObservable.notifyObservers(deviceName);
+            this._removeDevice(deviceName);
+            this.onAfterDeviceDisconnectedObservable.notifyObservers(deviceName);
+        });
+    }
+
+    // Public Functions
+    /**
+     * Checks for current device input value, given DeviceType, slot, and inputIndex
+     * @param type Enum specifiying device type
+     * @param deviceSlot "Slot" or index that device is referenced in
+     * @param inputIndex Index of device input
+     * @returns Current value of input
+     */
+    public getInput(type: DeviceType, inputIndex: number, deviceSlot: number = this._firstDevice[type]): Nullable<number> {
+        if (!this._devices[type] || this._firstDevice[type] === undefined)
+        {
+            return null;
+        }
+        else if (type == DeviceType.Touch)
+        {
+            return this._deviceInputSystem.pollInput(this._touchPoints[deviceSlot], inputIndex);
+        }
+
+        return this._deviceInputSystem.pollInput(this._devices[type][deviceSlot], inputIndex);
+    }
+
+    /**
+     * Dispose of DeviceInputSystem and other parts
+     */
+    public dispose() {
+        this._deviceInputSystem.dispose();
+    }
+
+    // Private Functions
+    /**
+     * Function to add device name to device list
+     * @param deviceName Name of Device
+     */
+    private _addDevice(deviceName: string) {
+        const deviceSlot = this._getDeviceSlot(deviceName);
+        const deviceType = this._getDeviceTypeFromName(deviceName);
+
+        if (!this._devices[deviceType])
+        {
+            this._devices[deviceType] = new Array<string>();
+
+            if(deviceType == DeviceType.Touch)
+            {
+                this._touchPoints = new Array<string>();
+                this._devices[deviceType][deviceSlot] = DeviceInputSystem.POINTER_DEVICE;
+            }
+        }
+
+        // If device is a touch device, update only touch points.  Otherwise, add new device.
+        if (deviceType == DeviceType.Touch)
+        {
+            this._touchPoints.push(deviceName);
+        }
+        else
+        {
+            this._devices[deviceType][deviceSlot] = deviceName;
+        }
+        
+        this._updateFirstDevices(deviceType);
+    }
+
+    /**
+     * Function to remove device name to device list
+     * @param deviceName Name of Device
+     */
+    private _removeDevice(deviceName: string) {
+        const deviceSlot = this._getDeviceSlot(deviceName);
+        const deviceType = this._getDeviceTypeFromName(deviceName);
+
+        if (deviceType == DeviceType.Touch)
+        {
+            const touchIndex = this._touchPoints.indexOf(deviceName);
+            this._touchPoints.splice(touchIndex, 1);
+        }
+        else
+        {
+            delete this._devices[deviceType][deviceSlot];
+        }
+    }
+
+    /**
+     * Get slot for a given input
+     * @param deviceName Name of Device
+     * @returns Slot Number
+     */
+    private _getDeviceSlot(deviceName: string): number {
+        const splitName = deviceName.split("-");
+        const deviceSlot = parseInt(splitName[splitName.length - 1]);
+
+        if (deviceSlot) {
+            return deviceSlot;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Updates array storing first connected device of each type
+     * @param type Type of Device
+     */
+    private _updateFirstDevices(type: DeviceType) {
+        switch (type)
+        {
+            case DeviceType.Keyboard:
+            case DeviceType.Mouse:
+            case DeviceType.Touch:
+                this._firstDevice[type] = 0;
+                break;
+            case DeviceType.DualShock:
+            case DeviceType.Xbox:
+            case DeviceType.Switch:
+            case DeviceType.GenericDevice:
+                let i = 0;
+                let first = -1;
+
+                while (first < 0 && i < this._devices[type].length)
+                {
+                    if (this._devices[type][i])
+                    {
+                        first = i;
+                    }
+                    i++;
+                }
+
+                this._firstDevice[type] = first;
+                break;
+        }
+    }
+
+    /**
+     * Gets DeviceType from the device name
+     * @param deviceName Name of Device from DeviceInputSystem
+     * @returns DeviceType enum value
+     */
+    private _getDeviceTypeFromName(deviceName: string): DeviceType
+    {
+        if (deviceName == DeviceInputSystem.KEYBOARD_DEVICE) {
+            return DeviceType.Keyboard;
+        }
+        else if (deviceName == DeviceInputSystem.MOUSE_DEVICE) {
+            return DeviceType.Mouse;
+        }
+        else if (deviceName.search(DeviceInputSystem.POINTER_DEVICE) !== -1) {
+            return DeviceType.Touch;
+        }
+        else if (deviceName.search("054c") !== -1) { // DualShock 4 Gamepad
+            return DeviceType.DualShock;
+        }
+        else if (deviceName.search("Xbox One") !== -1 || deviceName.search("Xbox 360") !== -1 || deviceName.search("xinput") !== -1) { // Xbox Gamepad
+            return DeviceType.Xbox;
+        }
+        else if (deviceName.search("057e") !== -1) { // Switch Gamepad
+            return DeviceType.Switch;
+        }
+
+        return DeviceType.GenericDevice;
+    }
+}

+ 17 - 11
src/DeviceInput/deviceInputSystem.ts

@@ -15,6 +15,8 @@ export class DeviceInputSystem implements IDisposable {
     public static readonly POINTER_DEVICE: string = "Pointer";
     /** KEYBOARD_DEVICE */
     public static readonly KEYBOARD_DEVICE: string = "Keyboard";
+    /** MOUSE_DEVICE */
+    public static readonly MOUSE_DEVICE: string = "Mouse";
 
     /**
      * Observable to be triggered when a device is connected
@@ -43,7 +45,7 @@ export class DeviceInputSystem implements IDisposable {
     private _gamepadConnectedEvent = (evt: any) => { };
     private _gamepadDisconnectedEvent = (evt: any) => { };
 
-    private static _MAX_KEYCODES: number = 222;
+    private static _MAX_KEYCODES: number = 255;
     private static _MAX_POINTER_INPUTS: number = 7;
 
     /**
@@ -71,7 +73,7 @@ export class DeviceInputSystem implements IDisposable {
         const device = this._inputs[deviceName];
 
         if (!device) {
-            throw `Unable to find device ${deviceName}`;
+            return null;
         }
 
         this._updateDevice(deviceName, inputIndex);
@@ -79,6 +81,7 @@ export class DeviceInputSystem implements IDisposable {
         if (device[inputIndex] === undefined) {
             throw `Unable to find input ${inputIndex} on device ${deviceName}`;
         }
+
         return device[inputIndex];
     }
 
@@ -169,8 +172,9 @@ export class DeviceInputSystem implements IDisposable {
      */
     private _handlePointerActions() {
         this._pointerMoveEvent = ((evt) => {
-            const deviceName = `${DeviceInputSystem.POINTER_DEVICE}-${evt.pointerId}`;
-            if (!this._pointerActive) {
+            const deviceName = (evt.pointerType == "mouse") ? DeviceInputSystem.MOUSE_DEVICE : `${DeviceInputSystem.POINTER_DEVICE}-${evt.pointerId}`;
+
+            if (!this._inputs[deviceName]) {
                 this._pointerActive = true;
                 this._registerDevice(deviceName, DeviceInputSystem._MAX_POINTER_INPUTS);
             }
@@ -184,8 +188,8 @@ export class DeviceInputSystem implements IDisposable {
 
         this._pointerDownEvent = ((evt) => {
 
-            const deviceName = `${DeviceInputSystem.POINTER_DEVICE}-${evt.pointerId}`;
-            if (!this._pointerActive) {
+            const deviceName = (evt.pointerType == "mouse") ? DeviceInputSystem.MOUSE_DEVICE : `${DeviceInputSystem.POINTER_DEVICE}-${evt.pointerId}`;
+            if (!this._inputs[deviceName]) {
                 this._pointerActive = true;
                 this._registerDevice(deviceName, DeviceInputSystem._MAX_POINTER_INPUTS);
             }
@@ -199,13 +203,13 @@ export class DeviceInputSystem implements IDisposable {
         });
 
         this._pointerUpEvent = ((evt) => {
-            const deviceName = `${DeviceInputSystem.POINTER_DEVICE}-${evt.pointerId}`;
+            const deviceName = (evt.pointerType == "mouse") ? DeviceInputSystem.MOUSE_DEVICE : `${DeviceInputSystem.POINTER_DEVICE}-${evt.pointerId}`;
 
             const pointer = this._inputs[deviceName];
             if (pointer) {
                 pointer[evt.button + 2] = 0;
             }
-            if (evt.pointerId != 1) // Don't unregister the mouse
+            if (evt.pointerType != "mouse") // Don't unregister the mouse
             {
                 this._unregisterDevice(deviceName);
             }
@@ -229,9 +233,11 @@ export class DeviceInputSystem implements IDisposable {
         });
 
         this._gamepadDisconnectedEvent = ((evt: any) => {
-            const deviceName = this._gamepads[evt.gamepad.index];
-            this._unregisterDevice(deviceName);
-            delete this._gamepads[evt.gamepad.index];
+            if (this._gamepads) {
+                const deviceName = this._gamepads[evt.gamepad.index];
+                this._unregisterDevice(deviceName);
+                delete this._gamepads[evt.gamepad.index];
+            }
         });
 
         window.addEventListener("gamepadconnected", this._gamepadConnectedEvent);

+ 2 - 0
src/DeviceInput/index.ts

@@ -1 +1,3 @@
 export * from "./deviceInputSystem";
+export * from "./InputDevices/deviceEnums";
+export * from "./InputDevices/deviceSourceManager";