Browse Source

Merge pull request #9789 from PolygonalSun/PolygonalSun/Add-DSM-InputManager

Add DeviceInputSystem to Input Manager
David Catuhe 4 years ago
parent
commit
dd6ca6dba0

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"thinEngineOnly":130230,"engineOnly":167557,"sceneOnly":523120,"minGridMaterial":699118,"minStandardMaterial":862977}
+{"thinEngineOnly":130254,"engineOnly":167581,"sceneOnly":533427,"minGridMaterial":709426,"minStandardMaterial":873285}

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

@@ -17,6 +17,7 @@
 - Moved sharedUI component to shared UI folder. ([msDestiny14](https://github.com/msDestiny14))
 - Added encapsulate and encapsulateBoundingInfo methods to BoundingInfo. ([Tolo789](https://github.com/Tolo789))
 - Added onLoadObservable to the textureDome class(es) ([RaananW](https://github.com/RaananW))
+- Modified InputManager to use DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
 
 ### Engine
 

+ 8 - 7
gui/src/2D/advancedDynamicTexture.ts

@@ -23,6 +23,7 @@ import { Constants } from 'babylonjs/Engines/constants';
 import { Viewport } from 'babylonjs/Maths/math.viewport';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { WebRequest } from "babylonjs/Misc/webRequest";
+import { IPointerEvent, IWheelEvent } from 'babylonjs/Events/deviceInputEvents';
 
 /**
 * Class used to create texture to support 2D GUI elements
@@ -41,7 +42,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
     private _preKeyboardObserver: Nullable<Observer<KeyboardInfoPre>>;
     private _pointerMoveObserver: Nullable<Observer<PointerInfoPre>>;
     private _pointerObserver: Nullable<Observer<PointerInfo>>;
-    private _canvasPointerOutObserver: Nullable<Observer<PointerEvent>>;
+    private _canvasPointerOutObserver: Nullable<Observer<IPointerEvent>>;
     private _canvasBlurObserver: Nullable<Observer<Engine>>;
     private _background: string;
     /** @hidden */
@@ -711,7 +712,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         let tempViewport = new Viewport(0, 0, 0, 0);
 
         this._pointerMoveObserver = scene.onPrePointerObservable.add((pi, state) => {
-            if (scene!.isPointerCaptured((<PointerEvent>(pi.event)).pointerId)) {
+            if (scene!.isPointerCaptured((<IPointerEvent>(pi.event)).pointerId)) {
                 return;
             }
             if (pi.type !== PointerEventTypes.POINTERMOVE
@@ -724,8 +725,8 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 return;
             }
 
-            if (pi.type === PointerEventTypes.POINTERMOVE && (pi.event as PointerEvent).pointerId) {
-                this._defaultMousePointerId = (pi.event as PointerEvent).pointerId; // This is required to make sure we have the correct pointer ID for wheel
+            if (pi.type === PointerEventTypes.POINTERMOVE && (pi.event as IPointerEvent).pointerId) {
+                this._defaultMousePointerId = (pi.event as IPointerEvent).pointerId; // This is required to make sure we have the correct pointer ID for wheel
             }
 
             let camera = scene.cameraToUseForPointers || scene.activeCamera;
@@ -744,8 +745,8 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             let y = scene.pointerY / engine.getHardwareScalingLevel() - (engine.getRenderHeight() - tempViewport.y - tempViewport.height);
             this._shouldBlockPointer = false;
             // Do picking modifies _shouldBlockPointer
-            let pointerId = (pi.event as PointerEvent).pointerId || this._defaultMousePointerId;
-            this._doPicking(x, y, pi, pi.type, pointerId, pi.event.button, (<MouseWheelEvent>pi.event).deltaX, (<MouseWheelEvent>pi.event).deltaY);
+            let pointerId = (pi.event as IPointerEvent).pointerId || this._defaultMousePointerId;
+            this._doPicking(x, y, pi, pi.type, pointerId, pi.event.button, (<IWheelEvent>pi.event).deltaX, (<IWheelEvent>pi.event).deltaY);
             // Avoid overwriting a true skipOnPointerObservable to false
             if (this._shouldBlockPointer) {
                 pi.skipOnPointerObservable = this._shouldBlockPointer;
@@ -808,7 +809,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 return;
             }
 
-            var pointerId = (pi.event as PointerEvent).pointerId || this._defaultMousePointerId;
+            var pointerId = (pi.event as IPointerEvent).pointerId || this._defaultMousePointerId;
             if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                 var uv = pi.pickInfo.getTextureCoordinates();
                 if (uv) {

+ 3 - 2
gui/src/2D/controls/focusableButton.ts

@@ -7,6 +7,7 @@ import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
 import { IFocusableControl } from "./focusableControl";
 import { Observable } from 'babylonjs/Misc/observable';
+import { IKeyboardEvent } from "babylonjs/Events/deviceInputEvents";
 
 /**
  * Class used to create a focusable button that can easily handle keyboard events
@@ -22,7 +23,7 @@ export class FocusableButton extends Button implements IFocusableControl {
     /** Observable raised when the control loses the focus */
     public onBlurObservable = new Observable<Button>();
     /** Observable raised when a key event was processed */
-    public onKeyboardEventProcessedObservable = new Observable<KeyboardEvent>();
+    public onKeyboardEventProcessedObservable = new Observable<IKeyboardEvent>();
 
     constructor(public name?: string) {
         super(name);
@@ -80,7 +81,7 @@ export class FocusableButton extends Button implements IFocusableControl {
      * Handles the keyboard event
      * @param evt Defines the KeyboardEvent
      */
-    public processKeyboard(evt: KeyboardEvent): void {
+    public processKeyboard(evt: IKeyboardEvent): void {
         this.onKeyboardEventProcessedObservable.notifyObservers(evt, -1, this);
     }
 

+ 2 - 1
gui/src/2D/controls/focusableControl.ts

@@ -1,3 +1,4 @@
+import { IKeyboardEvent } from "babylonjs/Events/deviceInputEvents";
 import { Nullable } from "babylonjs/types";
 import { Control } from "./control";
 
@@ -17,7 +18,7 @@ export interface IFocusableControl {
      * Function called to let the control handle keyboard events
      * @param evt defines the current keyboard event
      */
-    processKeyboard(evt: KeyboardEvent): void;
+    processKeyboard(evt: IKeyboardEvent): void;
     /**
     * Function called to get the list of controls that should not steal the focus from this control
     * @returns an array of controls

+ 4 - 3
gui/src/2D/controls/inputText.ts

@@ -12,6 +12,7 @@ import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Measure } from '../measure';
 import { TextWrapper } from './textWrapper';
 import { serialize } from 'babylonjs/Misc/decorators';
+import { IKeyboardEvent } from 'babylonjs/Events/deviceInputEvents';
 
 /**
  * Class used to create input text control
@@ -76,7 +77,7 @@ export class InputText extends Control implements IFocusableControl {
     /** Observable raised when paste event is triggered */
     public onTextPasteObservable = new Observable<InputText>();
     /** Observable raised when a key event was processed */
-    public onKeyboardEventProcessedObservable = new Observable<KeyboardEvent>();
+    public onKeyboardEventProcessedObservable = new Observable<IKeyboardEvent>();
 
     /** Gets or sets the maximum width allowed by the control */
     @serialize()
@@ -474,7 +475,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** @hidden */
-    public processKey(keyCode: number, key?: string, evt?: KeyboardEvent) {
+    public processKey(keyCode: number, key?: string, evt?: IKeyboardEvent) {
 
         //return if clipboard event keys (i.e -ctr/cmd + c,v,x)
         if (evt && (evt.ctrlKey || evt.metaKey) && (keyCode === 67 || keyCode === 86 || keyCode === 88)) {
@@ -792,7 +793,7 @@ export class InputText extends Control implements IFocusableControl {
      * Handles the keyboard event
      * @param evt Defines the KeyboardEvent
      */
-    public processKeyboard(evt: KeyboardEvent): void {
+    public processKeyboard(evt: IKeyboardEvent): void {
         // process pressed key
         this.processKey(evt.keyCode, evt.key, evt);
 

+ 3 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/materials/textures/textureCanvasManager.ts

@@ -31,6 +31,8 @@ import { IMetadata } from './textureEditorComponent';
 
 import { canvasShader } from './canvasShader';
 
+import { IWheelEvent } from 'babylonjs/Events/deviceInputEvents';
+
 export interface IPixelData {
     x? : number;
     y? : number;
@@ -267,7 +269,7 @@ export class TextureCanvasManager {
         this._scene.onPointerObservable.add((pointerInfo) => {
             switch (pointerInfo.type) {
                 case PointerEventTypes.POINTERWHEEL:
-                    const event = pointerInfo.event as MouseWheelEvent;
+                    const event = pointerInfo.event as IWheelEvent;
                     this._scale -= (event.deltaY * this.ZOOM_MOUSE_SPEED * this._scale);
                     break;
                 case PointerEventTypes.POINTERDOWN:

+ 4 - 3
src/Actions/actionEvent.ts

@@ -3,6 +3,7 @@ import { Nullable } from "../types";
 import { Sprite } from "../Sprites/sprite";
 import { Scene } from "../scene";
 import { Vector2 } from "../Maths/math.vector";
+import { IEvent } from "../Events/deviceInputEvents";
 
 /**
  * Interface used to define ActionEvent
@@ -57,7 +58,7 @@ export class ActionEvent implements IActionEvent {
      * @param additionalData additional data for the event
      * @returns the new ActionEvent
      */
-    public static CreateNew(source: AbstractMesh, evt?: Event, additionalData?: any): ActionEvent {
+    public static CreateNew(source: AbstractMesh, evt?: IEvent, additionalData?: any): ActionEvent {
         var scene = source.getScene();
         return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer || source, evt, additionalData);
     }
@@ -70,7 +71,7 @@ export class ActionEvent implements IActionEvent {
      * @param additionalData additional data for the event
      * @returns the new ActionEvent
      */
-    public static CreateNewFromSprite(source: Sprite, scene: Scene, evt?: Event, additionalData?: any): ActionEvent {
+    public static CreateNewFromSprite(source: Sprite, scene: Scene, evt?: IEvent, additionalData?: any): ActionEvent {
         return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt, additionalData);
     }
 
@@ -80,7 +81,7 @@ export class ActionEvent implements IActionEvent {
      * @param evt The original (browser) event
      * @returns the new ActionEvent
      */
-    public static CreateNewFromScene(scene: Scene, evt: Event): ActionEvent {
+    public static CreateNewFromScene(scene: Scene, evt: IEvent): ActionEvent {
         return new ActionEvent(null, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt);
     }
 

+ 3 - 2
src/Cameras/Inputs/BaseCameraMouseWheelInput.ts

@@ -5,6 +5,7 @@ import { Camera } from "../../Cameras/camera";
 import { ICameraInput } from "../../Cameras/cameraInputsManager";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Tools } from "../../Misc/tools";
+import { EventConstants, IWheelEvent } from "../../Events/deviceInputEvents";
 
 /**
  * Base class for mouse wheel input..
@@ -61,9 +62,9 @@ export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera>
                 return;
             }
 
-            const event = <MouseWheelEvent>pointer.event;
+            const event = <IWheelEvent>pointer.event;
 
-            const platformScale = event.deltaMode === WheelEvent.DOM_DELTA_LINE ? this._ffMultiplier : 1;
+            const platformScale = event.deltaMode === EventConstants.DOM_DELTA_LINE ? this._ffMultiplier : 1;  // If this happens to be set to DOM_DELTA_LINE, adjust accordingly
 
             if (event.deltaY !== undefined) {
                 // Most recent browsers versions have delta properties.

+ 8 - 7
src/Cameras/Inputs/BaseCameraPointersInput.ts

@@ -5,6 +5,7 @@ import { Tools } from "../../Misc/tools";
 import { Camera } from "../../Cameras/camera";
 import { ICameraInput } from "../../Cameras/cameraInputsManager";
 import { PointerInfo, PointerEventTypes, PointerTouch } from "../../Events/pointerEvents";
+import { IPointerEvent } from "../../Events/deviceInputEvents";
 
 /**
  * Base class for Camera Pointer Inputs.
@@ -59,7 +60,7 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
         this._buttonsPressed = 0;
 
         this._pointerInput = (p, s) => {
-            var evt = <PointerEvent>p.event;
+            var evt = <IPointerEvent>p.event;
             let isTouch = evt.pointerType === "touch";
 
             if (engine.isInVRExclusivePointerMode) {
@@ -80,12 +81,12 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
             this._buttonsPressed = evt.buttons;
 
             if (engine.isPointerLock) {
-                var offsetX = evt.movementX ||
+                const offsetX = evt.movementX ||
                               evt.mozMovementX ||
                               evt.webkitMovementX ||
                               evt.msMovementX ||
                               0;
-                var offsetY = evt.movementY ||
+                const offsetY = evt.movementY ||
                               evt.mozMovementY ||
                               evt.webkitMovementY ||
                               evt.msMovementY ||
@@ -180,8 +181,8 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
 
                 // One button down
                 if (this.pointA && this.pointB === null) {
-                    var offsetX = evt.clientX - this.pointA.x;
-                    var offsetY = evt.clientY - this.pointA.y;
+                    const offsetX = evt.clientX - this.pointA.x;
+                    const offsetY = evt.clientY - this.pointA.y;
                     this.onTouch(this.pointA, offsetX, offsetY);
 
                     this.pointA.x = evt.clientX;
@@ -334,7 +335,7 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
      * press.
      * Override this method to provide functionality.
      */
-    protected onButtonDown(evt: PointerEvent): void {
+    protected onButtonDown(evt: IPointerEvent): void {
     }
 
     /**
@@ -342,7 +343,7 @@ export abstract class BaseCameraPointersInput implements ICameraInput<Camera> {
      * release.
      * Override this method to provide functionality.
      */
-    protected onButtonUp(evt: PointerEvent): void {
+    protected onButtonUp(evt: IPointerEvent): void {
     }
 
     /**

+ 2 - 1
src/Cameras/Inputs/arcRotateCameraMouseWheelInput.ts

@@ -6,6 +6,7 @@ import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManage
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Scalar } from '../../Maths/math.scalar';
 import { Tools } from '../../Misc/tools';
+import { IWheelEvent } from "../../Events/deviceInputEvents";
 
 /**
  * Manage the mouse wheel inputs to control an arc rotate camera.
@@ -53,7 +54,7 @@ export class ArcRotateCameraMouseWheelInput implements ICameraInput<ArcRotateCam
         this._wheel = (p, s) => {
             //sanity check - this should be a PointerWheel event.
             if (p.type !== PointerEventTypes.POINTERWHEEL) { return; }
-            var event = <MouseWheelEvent>p.event;
+            var event = <IWheelEvent>p.event;
             var delta = 0;
 
             let mouseWheelLegacyEvent = event as any;

+ 3 - 2
src/Cameras/Inputs/arcRotateCameraPointersInput.ts

@@ -4,6 +4,7 @@ import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
 import { CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { BaseCameraPointersInput } from "../../Cameras/Inputs/BaseCameraPointersInput";
 import { PointerTouch } from "../../Events/pointerEvents";
+import { IPointerEvent } from "../../Events/deviceInputEvents";
 
 /**
  * Manage the pointers inputs to control an arc rotate camera.
@@ -223,7 +224,7 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
      * Called each time a new POINTERDOWN event occurs. Ie, for each button
      * press.
      */
-    protected onButtonDown(evt: PointerEvent): void {
+    protected onButtonDown(evt: IPointerEvent): void {
         this._isPanClick = evt.button === this.camera._panningMouseButton;
     }
 
@@ -231,7 +232,7 @@ export class ArcRotateCameraPointersInput extends BaseCameraPointersInput {
      * Called each time a new POINTERUP event occurs. Ie, for each button
      * release.
      */
-    protected onButtonUp(evt: PointerEvent): void {
+    protected onButtonUp(evt: IPointerEvent): void {
         this._twoFingerActivityCount = 0;
         this._isPinching = false;
     }

+ 2 - 1
src/Cameras/Inputs/flyCameraMouseInput.ts

@@ -8,6 +8,7 @@ import { Scene } from "../../scene";
 import { Quaternion } from "../../Maths/math.vector";
 import { Axis } from '../../Maths/math.axis';
 import { Tools } from '../../Misc/tools';
+import { IPointerEvent } from "../../Events/deviceInputEvents";
 /**
  * Listen to mouse events to control the camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -139,7 +140,7 @@ export class FlyCameraMouseInput implements ICameraInput<FlyCamera> {
 
     // Track mouse movement, when the pointer is not locked.
     private _pointerInput(p: any, s: any): void {
-        var e = <PointerEvent>p.event;
+        var e = <IPointerEvent>p.event;
 
         let camera = this.camera;
         let engine = camera.getEngine();

+ 2 - 1
src/Cameras/Inputs/followCameraMouseWheelInput.ts

@@ -5,6 +5,7 @@ import { FollowCamera } from "../../Cameras/followCamera";
 import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Tools } from '../../Misc/tools';
+import { IWheelEvent } from "../../Events/deviceInputEvents";
 
 /**
  * Manage the mouse wheel inputs to control a follow camera.
@@ -60,7 +61,7 @@ export class FollowCameraMouseWheelInput implements ICameraInput<FollowCamera> {
         this._wheel = (p, s) => {
             // sanity check - this should be a PointerWheel event.
             if (p.type !== PointerEventTypes.POINTERWHEEL) { return; }
-            var event = <MouseWheelEvent>p.event;
+            var event = <IWheelEvent>p.event;
             var delta = 0;
 
             // Chrome, Safari: event.deltaY

+ 4 - 3
src/Cameras/Inputs/freeCameraMouseInput.ts

@@ -5,6 +5,7 @@ import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManage
 import { FreeCamera } from "../../Cameras/freeCamera";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Tools } from "../../Misc/tools";
+import { IMouseEvent, IPointerEvent } from "../../Events/deviceInputEvents";
 /**
  * Manage the mouse inputs to control the movement of a free camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -28,7 +29,7 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
     public angularSensibility = 2000.0;
 
     private _pointerInput: (p: PointerInfo, s: EventState) => void;
-    private _onMouseMove: Nullable<(e: MouseEvent) => any>;
+    private _onMouseMove: Nullable<(e: IMouseEvent) => any>;
     private _observer: Nullable<Observer<PointerInfo>>;
     private previousPosition: Nullable<{ x: number; y: number }> = null;
 
@@ -64,7 +65,7 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
 
         if (!this._pointerInput) {
             this._pointerInput = (p) => {
-                var evt = <PointerEvent>p.event;
+                var evt = <IPointerEvent>p.event;
 
                 if (engine.isInVRExclusivePointerMode) {
                     return;
@@ -178,7 +179,7 @@ export class FreeCameraMouseInput implements ICameraInput<FreeCamera> {
 
         this._observer = this.camera.getScene().onPointerObservable.add(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE);
 
-        element && element.addEventListener("contextmenu", <EventListener>this.onContextMenu.bind(this), false);
+        element && element.addEventListener("contextmenu", <EventListener>this.onContextMenu.bind(this), false); // TODO: We need to figure out how to handle this for Native
     }
 
     /**

+ 2 - 1
src/Cameras/Inputs/freeCameraTouchInput.ts

@@ -6,6 +6,7 @@ import { FreeCamera } from "../../Cameras/freeCamera";
 import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
 import { Matrix, Vector3 } from "../../Maths/math.vector";
 import { Tools } from "../../Misc/tools";
+import { IPointerEvent } from "../../Events/deviceInputEvents";
 /**
  * Manage the touch inputs to control the movement of a free camera.
  * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
@@ -65,7 +66,7 @@ export class FreeCameraTouchInput implements ICameraInput<FreeCamera> {
             };
 
             this._pointerInput = (p) => {
-                var evt = <PointerEvent>p.event;
+                var evt = <IPointerEvent>p.event;
 
                 let isMouseEvent = !this.camera.getEngine().hostInformation.isMobile && evt instanceof MouseEvent;
                 if (!this.allowMouse && (evt.pointerType === "mouse" || isMouseEvent)) {

+ 11 - 1
src/DeviceInput/InputDevices/deviceEnums.ts

@@ -36,7 +36,17 @@ export enum PointerInput {
     /** Browser Back */
     BrowserBack = 5,
     /** Browser Forward */
-    BrowserForward = 6
+    BrowserForward = 6,
+    /** Mouse Wheel X */
+    MouseWheelX = 7,
+    /** Mouse Wheel Y */
+    MouseWheelY = 8,
+    /** Mouse Wheel Z */
+    MouseWheelZ = 9,
+    /** Delta X */
+    DeltaHorizontal = 10,
+    /** Delta Y */
+    DeltaVertical = 11
 }
 
 /**

+ 165 - 35
src/DeviceInput/deviceInputSystem.ts

@@ -1,7 +1,8 @@
 import { Engine } from '../Engines/engine';
+import { Tools } from '../Misc/tools';
 import { IDisposable } from '../scene';
 import { Nullable } from '../types';
-import { DeviceType } from './InputDevices/deviceEnums';
+import { DeviceType, PointerInput } from './InputDevices/deviceEnums';
 
 /** @hidden */
 declare const _native: any;
@@ -62,6 +63,8 @@ export class DeviceInputSystem implements IDisposable {
     private _pointerMoveEvent = (evt: any) => { };
     private _pointerDownEvent = (evt: any) => { };
     private _pointerUpEvent = (evt: any) => { };
+    private _pointerWheelEvent = (evt: any) => { };
+    private _wheelEventName: string;
 
     private _gamepadConnectedEvent = (evt: any) => { };
     private _gamepadDisconnectedEvent = (evt: any) => { };
@@ -69,10 +72,13 @@ export class DeviceInputSystem implements IDisposable {
     private _onDeviceConnected: (deviceType: DeviceType, deviceSlot: number) => void = () => { };
 
     private static _MAX_KEYCODES: number = 255;
-    private static _MAX_POINTER_INPUTS: number = 7;
+    private static _MAX_POINTER_INPUTS: number = Object.keys(PointerInput).length / 2;
+
+    private _eventPrefix: string;
 
     private constructor(engine: Engine) {
         const inputElement = engine.getInputElement();
+        this._eventPrefix = Tools.GetPointerPrefix(engine);
 
         if (inputElement) {
             this._elementToAttachTo = inputElement;
@@ -127,10 +133,28 @@ export class DeviceInputSystem implements IDisposable {
             throw `Unable to find input ${inputIndex} for device ${DeviceType[deviceType]} in slot ${deviceSlot}`;
         }
 
+        // When the mouse wheel is moved, only clear the value if that input is polled for
+        if (deviceType === DeviceType.Mouse && (inputIndex >= PointerInput.MouseWheelX && inputIndex <= PointerInput.MouseWheelZ)) {
+            const currentValue = device[inputIndex];
+
+            device[inputIndex] = 0;
+
+            return currentValue;
+        }
+
         return device[inputIndex];
     }
 
     /**
+     * Check for a specific device in the DeviceInputSystem
+     * @param deviceType Type of device to check for
+     * @returns bool with status of device's existence
+     */
+    public isDeviceAvailable(deviceType: DeviceType) {
+        return (this._inputs[deviceType] !== undefined);
+    }
+
+    /**
      * Dispose of all the eventlisteners
      */
     public dispose() {
@@ -142,9 +166,10 @@ export class DeviceInputSystem implements IDisposable {
 
         // Pointer Events
         if (this._pointerActive) {
-            this._elementToAttachTo.removeEventListener("pointermove", this._pointerMoveEvent);
-            this._elementToAttachTo.removeEventListener("pointerdown", this._pointerDownEvent);
-            this._elementToAttachTo.removeEventListener("pointerup", this._pointerUpEvent);
+            this._elementToAttachTo.removeEventListener(this._eventPrefix + "move", this._pointerMoveEvent);
+            this._elementToAttachTo.removeEventListener(this._eventPrefix + "down", this._pointerDownEvent);
+            this._elementToAttachTo.removeEventListener(this._eventPrefix + "up", this._pointerUpEvent);
+            this._elementToAttachTo.removeEventListener(this._wheelEventName, this._pointerWheelEvent);
         }
 
         // Gamepad Events
@@ -249,20 +274,20 @@ export class DeviceInputSystem implements IDisposable {
 
             const kbKey = this._inputs[DeviceType.Keyboard][0];
             if (kbKey) {
+                kbKey[evt.keyCode] = 1;
                 if (this.onInputChanged) {
-                    this.onInputChanged(DeviceType.Keyboard, 0, evt.keyCode, kbKey[evt.keyCode], 1);
+                    this.onInputChanged(DeviceType.Keyboard, 0, evt.keyCode, 0, kbKey[evt.keyCode]);
                 }
-                kbKey[evt.keyCode] = 1;
             }
         });
 
         this._keyboardUpEvent = ((evt) => {
             const kbKey = this._inputs[DeviceType.Keyboard][0];
             if (kbKey) {
+                kbKey[evt.keyCode] = 0;
                 if (this.onInputChanged) {
-                    this.onInputChanged(DeviceType.Keyboard, 0, evt.keyCode, kbKey[evt.keyCode], 0);
+                    this.onInputChanged(DeviceType.Keyboard, 0, evt.keyCode, 1, kbKey[evt.keyCode]);
                 }
-                kbKey[evt.keyCode] = 0;
             }
         });
 
@@ -275,8 +300,8 @@ export class DeviceInputSystem implements IDisposable {
      */
     private _handlePointerActions() {
         this._pointerMoveEvent = ((evt) => {
-            const deviceType = (evt.pointerType == "mouse") ? DeviceType.Mouse : DeviceType.Touch;
-            const deviceSlot = (evt.pointerType == "mouse") ? 0 : 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] = [];
@@ -288,18 +313,37 @@ export class DeviceInputSystem implements IDisposable {
 
             const pointer = this._inputs[deviceType][deviceSlot];
             if (pointer) {
+                // Store previous values for event
+                const previousHorizontal = pointer[PointerInput.Horizontal];
+                const previousVertical = pointer[PointerInput.Vertical];
+                const previousDeltaHorizontal = pointer[PointerInput.DeltaHorizontal];
+                const previousDeltaVertical = pointer[PointerInput.DeltaVertical];
+
+                pointer[PointerInput.Horizontal] = evt.clientX;
+                pointer[PointerInput.Vertical] = evt.clientY;
+                pointer[PointerInput.DeltaHorizontal] = evt.movementX;
+                pointer[PointerInput.DeltaVertical] = evt.movementY;
+
                 if (this.onInputChanged) {
-                    this.onInputChanged(deviceType, deviceSlot, 0, pointer[0], evt.clientX);
-                    this.onInputChanged(deviceType, deviceSlot, 1, pointer[1], evt.clientY);
+                    if (previousHorizontal !== evt.clientX) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.Horizontal, previousHorizontal, pointer[PointerInput.Horizontal]);
+                    }
+                    if (previousVertical !== evt.clientY) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.Vertical, previousVertical, pointer[PointerInput.Vertical]);
+                    }
+                    if (pointer[PointerInput.DeltaHorizontal] !== 0) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.DeltaHorizontal, previousDeltaHorizontal, pointer[PointerInput.DeltaHorizontal]);
+                    }
+                    if (pointer[PointerInput.DeltaVertical] !== 0) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.DeltaVertical, previousDeltaVertical, pointer[PointerInput.DeltaVertical]);
+                    }
                 }
-                pointer[0] = evt.clientX;
-                pointer[1] = evt.clientY;
             }
         });
 
         this._pointerDownEvent = ((evt) => {
-            const deviceType = (evt.pointerType == "mouse") ? DeviceType.Mouse : DeviceType.Touch;
-            const deviceSlot = (evt.pointerType == "mouse") ? 0 : 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] = [];
@@ -311,41 +355,127 @@ export class DeviceInputSystem implements IDisposable {
 
             const pointer = this._inputs[deviceType][deviceSlot];
             if (pointer) {
+                const previousHorizontal = pointer[PointerInput.Horizontal];
+                const previousVertical = pointer[PointerInput.Vertical];
+                const previousButton = pointer[evt.button + 2];
+
+                pointer[PointerInput.Horizontal] = evt.clientX;
+                pointer[PointerInput.Vertical] = evt.clientY;
+                pointer[evt.button + 2] = 1;
+
                 if (this.onInputChanged) {
-                    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);
+                    if (previousHorizontal !== evt.clientX) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.Horizontal, previousHorizontal, pointer[PointerInput.Horizontal]);
+                    }
+                    if (previousVertical !== evt.clientY) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.Vertical, previousVertical, pointer[PointerInput.Vertical]);
+                    }
+                    this.onInputChanged(deviceType, deviceSlot, evt.button + 2, previousButton, pointer[evt.button + 2]);
                 }
-                pointer[0] = evt.clientX;
-                pointer[1] = evt.clientY;
-                pointer[evt.button + 2] = 1;
             }
         });
 
         this._pointerUpEvent = ((evt) => {
-            const deviceType = (evt.pointerType == "mouse") ? DeviceType.Mouse : DeviceType.Touch;
-            const deviceSlot = (evt.pointerType == "mouse") ? 0 : evt.pointerId;
+            const deviceType = (evt.pointerType === "mouse") ? DeviceType.Mouse : DeviceType.Touch;
+            const deviceSlot = (evt.pointerType === "mouse") ? 0 : evt.pointerId;
 
             const pointer = this._inputs[deviceType][deviceSlot];
             if (pointer) {
-                if (this.onInputChanged) {
-                    this.onInputChanged(deviceType, deviceSlot, evt.button + 2, pointer[evt.button + 2], 0);
-                }
+                const previousHorizontal = pointer[PointerInput.Horizontal];
+                const previousVertical = pointer[PointerInput.Vertical];
+                const previousButton = pointer[evt.button + 2];
 
-                pointer[0] = evt.clientX;
-                pointer[1] = evt.clientY;
+                pointer[PointerInput.Horizontal] = evt.clientX;
+                pointer[PointerInput.Vertical] = evt.clientY;
                 pointer[evt.button + 2] = 0;
+
+                if (this.onInputChanged) {
+                    if (previousHorizontal !== evt.clientX) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.Horizontal, previousHorizontal, pointer[PointerInput.Horizontal]);
+                    }
+                    if (previousVertical !== evt.clientY) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.Vertical, previousVertical, pointer[PointerInput.Vertical]);
+                    }
+                    this.onInputChanged(deviceType, deviceSlot, evt.button + 2, previousButton, pointer[evt.button + 2]);
+                }
             }
             // 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") {
+            if (evt.pointerType !== "mouse") {
                 this._unregisterDevice(deviceType, deviceSlot);
             }
 
         });
 
-        this._elementToAttachTo.addEventListener("pointermove", this._pointerMoveEvent);
-        this._elementToAttachTo.addEventListener("pointerdown", this._pointerDownEvent);
-        this._elementToAttachTo.addEventListener("pointerup", this._pointerUpEvent);
+        // Set Wheel Event Name, code originally from scene.inputManager
+        this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" :       // Modern browsers support "wheel"
+            (<any>document).onmousewheel !== undefined ? "mousewheel" :                     // Webkit and IE support at least "mousewheel"
+                "DOMMouseScroll";                                                           // let's assume that remaining browsers are older Firefox
+
+        // Code originally in scene.inputManager.ts
+        // Chrome reports warning in console if wheel listener doesn't set an explicit passive option.
+        // IE11 only supports captureEvent:boolean, not options:object, and it defaults to false.
+        // Feature detection technique copied from: https://github.com/github/eventlistener-polyfill (MIT license)
+        let passiveSupported = false;
+        const noop = function () { };
+
+        try {
+            const options: object = {
+                passive: {
+                    get: function () {
+                        passiveSupported = true;
+                    }
+                }
+            };
+
+            this._elementToAttachTo.addEventListener("test", noop, options);
+            this._elementToAttachTo.removeEventListener("test", noop, options);
+        }
+        catch (e) {
+            /* */
+        }
+
+        this._pointerWheelEvent = ((evt) => {
+            const deviceType = DeviceType.Mouse;
+            const deviceSlot = 0;
+
+            if (!this._inputs[deviceType]) {
+                this._inputs[deviceType] = [];
+            }
+
+            if (!this._inputs[deviceType][deviceSlot]) {
+                this._pointerActive = true;
+                this._registerDevice(deviceType, deviceSlot, DeviceInputSystem._MAX_POINTER_INPUTS);
+            }
+
+            const pointer = this._inputs[deviceType][deviceSlot];
+            if (pointer) {
+                // Store previous values for event
+                let previousWheelScrollX = pointer[PointerInput.MouseWheelX];
+                let previousWheelScrollY = pointer[PointerInput.MouseWheelY];
+                let previousWheelScrollZ = pointer[PointerInput.MouseWheelZ];
+
+                pointer[PointerInput.MouseWheelX] = evt.deltaX;
+                pointer[PointerInput.MouseWheelY] = evt.deltaY;
+                pointer[PointerInput.MouseWheelZ] = evt.deltaZ;
+
+                if (this.onInputChanged) {
+                    if (evt.deltaX !== 0) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.MouseWheelX, previousWheelScrollX, pointer[PointerInput.MouseWheelX]);
+                    }
+                    if (evt.deltaY !== 0) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.MouseWheelY, previousWheelScrollY, pointer[PointerInput.MouseWheelY]);
+                    }
+                    if (evt.deltaZ !== 0) {
+                        this.onInputChanged(deviceType, deviceSlot, PointerInput.MouseWheelZ, previousWheelScrollZ, pointer[PointerInput.MouseWheelZ]);
+                    }
+                }
+            }
+        });
+
+        this._elementToAttachTo.addEventListener(this._eventPrefix + "move", this._pointerMoveEvent);
+        this._elementToAttachTo.addEventListener(this._eventPrefix + "down", this._pointerDownEvent);
+        this._elementToAttachTo.addEventListener(this._eventPrefix + "up", this._pointerUpEvent);
+        this._elementToAttachTo.addEventListener(this._wheelEventName, this._pointerWheelEvent, passiveSupported ? { passive: false } : false);
     }
 
     /**
@@ -380,7 +510,7 @@ export class DeviceInputSystem implements IDisposable {
         // Gamepads
         const gp = navigator.getGamepads()[deviceSlot];
 
-        if (gp && deviceType == this._gamepads[deviceSlot]) {
+        if (gp && deviceType === this._gamepads[deviceSlot]) {
             const device = this._inputs[deviceType][deviceSlot];
 
             if (inputIndex >= gp.buttons.length) {

+ 30 - 0
src/Engines/constants.ts

@@ -556,4 +556,34 @@ export class Constants {
      * Prefixes used by the engine for custom effects
      */
     public static readonly CUSTOMEFFECT_PREFIX_SHADOWGENERATOR = "bjs_shadowgenerator_";
+
+    /**
+     * Constant used as key code for Alt key
+     */
+    public static readonly INPUT_ALT_KEY = 18;
+
+    /**
+     * Constant used as key code for Ctrl key
+     */
+    public static readonly INPUT_CTRL_KEY = 17;
+
+    /**
+     * Constant used as key code for Meta key (Left Win, Left Cmd)
+     */
+    public static readonly INPUT_META_KEY1 = 91;
+
+    /**
+     * Constant used as key code for Meta key (Right Win)
+     */
+    public static readonly INPUT_META_KEY2 = 92;
+
+    /**
+     * Constant used as key code for Meta key (Right Win, Right Cmd)
+     */
+    public static readonly INPUT_META_KEY3 = 93;
+
+    /**
+     * Constant used as key code for Shift key
+     */
+    public static readonly INPUT_SHIFT_KEY = 16;
 }

+ 2 - 1
src/Engines/engine.ts

@@ -24,6 +24,7 @@ import "./Extensions/engine.alpha";
 import "./Extensions/engine.readTexture";
 import "./Extensions/engine.dynamicBuffer";
 import { IAudioEngine } from '../Audio/Interfaces/IAudioEngine';
+import { IPointerEvent } from "../Events/deviceInputEvents";
 
 declare type Material = import("../Materials/material").Material;
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
@@ -371,7 +372,7 @@ export class Engine extends ThinEngine {
     /**
      * Observable event triggered each time the canvas receives pointerout event
      */
-    public onCanvasPointerOutObservable = new Observable<PointerEvent>();
+    public onCanvasPointerOutObservable = new Observable<IPointerEvent>();
 
     /**
      * Observable raised when the engine begins a new frame

+ 16 - 0
src/Engines/nativeEngine.ts

@@ -1163,6 +1163,22 @@ export class NativeEngine extends Engine {
     }
 
     /**
+     * Gets the client rect of native canvas.  Needed for InputManager.
+     * @returns a client rectangle
+     */
+    public getInputElementClientRect(): Nullable<ClientRect> {
+        const rect = {
+            bottom: this.getRenderHeight(),
+            height: this.getRenderHeight(),
+            left: 0,
+            right: this.getRenderWidth(),
+            top: 0,
+            width: this.getRenderWidth()
+        };
+        return rect;
+    }
+
+    /**
      * Set the z offset to apply to current rendering
      * @param value defines the offset to apply
      */

+ 281 - 0
src/Events/deviceInputEvents.ts

@@ -0,0 +1,281 @@
+/**
+ * Event Types
+ */
+export enum DeviceInputEventType {
+    // Pointers
+    /** PointerMove */
+    PointerMove,
+    /** PointerDown */
+    PointerDown,
+    /** PointerUp */
+    PointerUp
+}
+
+/**
+ * Native friendly interface for Event Object
+ */
+export interface IEvent {
+    // Properties
+    /**
+     * Current target for an event
+     */
+    currentTarget?: any;
+
+    /**
+     * Alias for target
+     * @deprecated
+     */
+    srcElement?: any;
+
+    /**
+     * Type of event
+     */
+    type: string;
+
+    /**
+     * Reference to object where object was dispatched
+     */
+    target: any;
+
+    // Methods
+    /**
+     * Tells user agent what to do when not explicitly handled
+     */
+    preventDefault: () => void;
+}
+
+/**
+ * Native friendly interface for UIEvent Object
+ */
+export interface IUIEvent extends IEvent {
+    // Properties
+    /**
+     * Provides current click count
+     */
+    detail: number;
+
+    /**
+     * Horizontal coordinate of event
+     */
+    pageX: number;
+
+    /**
+     * Vertical coordinate of event
+     */
+    pageY: number;
+}
+
+/**
+ * Native friendly interface for KeyboardEvent Object
+ */
+export interface IKeyboardEvent extends IUIEvent {
+    // Properties
+    /**
+     * Status of Alt key being pressed
+     */
+    altKey: boolean;
+
+    /**
+     * Unicode value of character pressed
+     * @deprecated
+     */
+    charCode?: number;
+
+    /**
+     * Code for key based on layout
+     */
+    code: string;
+
+    /**
+     * Status of Ctrl key being pressed
+     */
+    ctrlKey: boolean;
+
+    /**
+     * String representation of key
+     */
+    key: string;
+    /**
+     * ASCII value of key
+     * @deprecated
+     */
+    keyCode: number;
+
+    /**
+     * Status of Meta key (eg. Windows key) being pressed
+     */
+    metaKey: boolean;
+
+    /**
+     * Status of Shift key being pressed
+     */
+    shiftKey: boolean;
+}
+
+/**
+ * Native friendly interface for MouseEvent Object
+ */
+export interface IMouseEvent extends IUIEvent{
+    // Properties
+    /**
+     * Status of Alt key being pressed
+     */
+    altKey: boolean;
+
+    /**
+     * Value of single mouse button pressed
+     */
+    button: number;
+
+    /**
+     * Value of all mouse buttons pressed
+     */
+    buttons: number;
+
+    /**
+     * Current X coordinate
+     */
+    clientX: number;
+
+    /**
+     * Current Y coordinate
+     */
+    clientY: number;
+
+    /**
+     * Status of Ctrl key being pressed
+     */
+    ctrlKey: boolean;
+
+    /**
+     * Status of Meta key (eg. Windows key) being pressed
+     */
+    metaKey: boolean;
+
+    /**
+     * Delta of movement on X axis
+     */
+    movementX: number;
+
+    /**
+     * Delta of movement on Y axis
+     */
+    movementY: number;
+
+    /**
+     * Delta of movement on X axis
+     */
+    mozMovementX?: number;
+
+    /**
+     * Delta of movement on Y axis
+     */
+    mozMovementY?: number;
+
+    /**
+     * Delta of movement on X axis
+     */
+    msMovementX?: any;
+
+    /**
+     * Delta of movement on Y axis
+     */
+    msMovementY?: any;
+
+    /**
+     * Current coordinate of X within container
+     */
+    offsetX: number;
+
+    /**
+     * Current coordinate of Y within container
+     */
+    offsetY: number;
+
+    /**
+     * Status of Shift key being pressed
+     */
+    shiftKey: boolean;
+
+    /**
+     * Delta of movement on X axis
+     */
+    webkitMovementX?: any;
+
+    /**
+     * Delta of movement on Y axis
+     */
+    webkitMovementY?: any;
+
+    /**
+     * Alias of clientX
+     */
+    x: number;
+
+    /**
+     * Alias of clientY
+     */
+    y: number;
+}
+
+/**
+ * Native friendly interface for PointerEvent Object
+ */
+export interface IPointerEvent extends IMouseEvent {
+    // Properties
+    /**
+     * Pointer Event ID
+     */
+    pointerId: number;
+
+    /**
+     * Type of pointer
+     */
+    pointerType: string;
+}
+
+/**
+ * Native friendly interface for WheelEvent Object
+ */
+export interface IWheelEvent extends IMouseEvent {
+    // Properties
+    /**
+     * Units for delta value
+     */
+    deltaMode: number;
+
+    /**
+     * Horizontal scroll delta
+     */
+    deltaX: number;
+
+    /**
+     * Vertical scroll delta
+     */
+    deltaY: number;
+
+    /**
+     * Z-Axis scroll delta
+     */
+    deltaZ: number;
+}
+
+/**
+ * Constants used for Events
+ */
+export class EventConstants {
+    /**
+     * Pixel delta for Wheel Events (Default)
+     */
+    public static DOM_DELTA_PIXEL = 0x00;
+
+    /**
+     * Line delta for Wheel Events
+     */
+    public static DOM_DELTA_LINE = 0x01;
+
+    /**
+     * Page delta for Wheel Events
+     */
+    public static DOM_DELTA_PAGE = 0x02;
+}

+ 2 - 1
src/Events/index.ts

@@ -1,3 +1,4 @@
 export * from "./keyboardEvents";
 export * from "./pointerEvents";
-export * from "./clipboardEvents";
+export * from "./clipboardEvents";
+export * from "./deviceInputEvents";

+ 4 - 2
src/Events/keyboardEvents.ts

@@ -1,3 +1,5 @@
+import { IKeyboardEvent } from "./deviceInputEvents";
+
 /**
  * Gather the list of keyboard event types as constants.
  */
@@ -30,7 +32,7 @@ export class KeyboardInfo {
         /**
          * Defines the related dom event
          */
-        public event: KeyboardEvent) {
+        public event: IKeyboardEvent) {
     }
 }
 
@@ -58,7 +60,7 @@ export class KeyboardInfoPre extends KeyboardInfo {
         /**
          * Defines the related dom event
          */
-        public event: KeyboardEvent) {
+        public event: IKeyboardEvent) {
         super(type, event);
         this.skipOnPointerObservable = false;
     }

+ 4 - 3
src/Events/pointerEvents.ts

@@ -1,6 +1,7 @@
 import { Nullable } from "../types";
 import { Vector2 } from "../Maths/math.vector";
 import { PickingInfo } from "../Collisions/pickingInfo";
+import { IMouseEvent } from "./deviceInputEvents";
 
 declare type Ray = import("../Culling/ray").Ray;
 
@@ -55,7 +56,7 @@ export class PointerInfoBase {
         /**
          * Defines the related dom event
          */
-        public event: PointerEvent | MouseWheelEvent) {
+        public event: IMouseEvent) {
     }
 }
 
@@ -86,7 +87,7 @@ export class PointerInfoPre extends PointerInfoBase {
      * @param localX Defines the local x coordinates of the pointer when the event occured
      * @param localY Defines the local y coordinates of the pointer when the event occured
      */
-    constructor(type: number, event: PointerEvent | MouseWheelEvent, localX: number, localY: number) {
+    constructor(type: number, event: IMouseEvent, localX: number, localY: number) {
         super(type, event);
         this.skipOnPointerObservable = false;
         this.localPosition = new Vector2(localX, localY);
@@ -105,7 +106,7 @@ export class PointerInfo extends PointerInfoBase {
      * @param pickInfo Defines the picking info associated to the info (if any)\
      */
     constructor(type: number,
-        event: PointerEvent | MouseWheelEvent,
+        event: IMouseEvent,
         /**
          * Defines the picking info associated to the info (if any)\
          */

+ 129 - 135
src/Inputs/scene.inputManager.ts

@@ -1,4 +1,4 @@
-import { Observable, Observer } from "../Misc/observable";
+import { Observable } from "../Misc/observable";
 import { PointerInfoPre, PointerInfo, PointerEventTypes } from "../Events/pointerEvents";
 import { Nullable } from "../types";
 import { AbstractActionManager } from "../Actions/abstractActionManager";
@@ -7,9 +7,10 @@ import { Vector2, Matrix } from "../Maths/math.vector";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Constants } from "../Engines/constants";
 import { ActionEvent } from "../Actions/actionEvent";
-import { Tools } from "../Misc/tools";
-import { Engine } from "../Engines/engine";
 import { KeyboardEventTypes, KeyboardInfoPre, KeyboardInfo } from "../Events/keyboardEvents";
+import { DeviceType, PointerInput } from '../DeviceInput/InputDevices/deviceEnums';
+import { EventConstants, IKeyboardEvent, IMouseEvent, IPointerEvent, IWheelEvent } from '../Events/deviceInputEvents';
+import { DeviceInputSystem } from '../DeviceInput/deviceInputSystem';
 
 declare type Scene = import("../scene").Scene;
 
@@ -65,12 +66,11 @@ export class InputManager {
     private _alreadyAttachedTo: HTMLElement;
 
     // Pointers
-    private _wheelEventName = "";
-    private _onPointerMove: (evt: PointerEvent) => void;
-    private _onPointerDown: (evt: PointerEvent) => void;
-    private _onPointerUp: (evt: PointerEvent) => void;
+    private _onPointerMove: (evt: IMouseEvent) => void;
+    private _onPointerDown: (evt: IPointerEvent) => void;
+    private _onPointerUp: (evt: IPointerEvent) => void;
 
-    private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
+    private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: IPointerEvent, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
     private _initActionManager: (act: Nullable<AbstractActionManager>, clickInfo: _ClickInfo) => Nullable<AbstractActionManager>;
     private _delayedSimpleClick: (btn: number, clickInfo: _ClickInfo, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
     private _delayedSimpleClickTimeout: number;
@@ -97,17 +97,14 @@ export class InputManager {
     private _startingPointerTime = 0;
     private _previousStartingPointerTime = 0;
     private _pointerCaptures: { [pointerId: number]: boolean } = {};
-
     private _meshUnderPointerId: Nullable<AbstractMesh>[] = [];
 
     // Keyboard
-    private _onKeyDown: (evt: KeyboardEvent) => void;
-    private _onKeyUp: (evt: KeyboardEvent) => void;
-    private _keyboardIsAttached = false;
-    private _onCanvasFocusObserver: Nullable<Observer<Engine>>;
-    private _onCanvasBlurObserver: Nullable<Observer<Engine>>;
+    private _onKeyDown: (evt: IKeyboardEvent) => void;
+    private _onKeyUp: (evt: IKeyboardEvent) => void;
 
     private _scene: Scene;
+    private _deviceInputSystem: DeviceInputSystem;
 
     /**
      * Creates a new InputManager
@@ -162,7 +159,7 @@ export class InputManager {
         this._pointerY = value;
     }
 
-    private _updatePointerPosition(evt: PointerEvent): void {
+    private _updatePointerPosition(evt: IPointerEvent): void {
         var canvasRect = this._scene.getEngine().getInputElementClientRect();
 
         if (!canvasRect) {
@@ -176,7 +173,7 @@ export class InputManager {
         this._unTranslatedPointerY = this._pointerY;
     }
 
-    private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent) {
+    private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: IPointerEvent) {
         let scene = this._scene;
         let engine = scene.getEngine();
         var canvas = engine.getInputElement();
@@ -214,7 +211,7 @@ export class InputManager {
         }
 
         if (pickResult) {
-            let type = evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
+            let type = evt.type === "wheel" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
 
             if (scene.onPointerMove) {
                 scene.onPointerMove(evt, pickResult, type);
@@ -238,7 +235,7 @@ export class InputManager {
         }
     }
 
-    private _checkPrePointerObservable(pickResult: Nullable<PickingInfo>, evt: PointerEvent, type: number) {
+    private _checkPrePointerObservable(pickResult: Nullable<PickingInfo>, evt: IPointerEvent, type: number) {
         let scene = this._scene;
         let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
         if (pickResult) {
@@ -283,7 +280,7 @@ export class InputManager {
         this._processPointerDown(pickResult, evt);
     }
 
-    private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): void {
+    private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: IPointerEvent): void {
         let scene = this._scene;
         if (pickResult && pickResult.hit && pickResult.pickedMesh) {
             this._pickedDownMesh = pickResult.pickedMesh;
@@ -309,7 +306,7 @@ export class InputManager {
                         var pickResult = scene.pick(
                             this._unTranslatedPointerX,
                             this._unTranslatedPointerY,
-                            (mesh: AbstractMesh): boolean => <boolean>(mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger) && mesh == this._pickedDownMesh),
+                            (mesh: AbstractMesh): boolean => <boolean>(mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger) && mesh === this._pickedDownMesh),
                             false,
                             scene.cameraToUseForPointers
                         );
@@ -373,7 +370,7 @@ export class InputManager {
         this._processPointerUp(pickResult, evt, clickInfo);
     }
 
-    private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: _ClickInfo): void {
+    private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: IPointerEvent, clickInfo: _ClickInfo): void {
         let scene = this._scene;
         if (pickResult && pickResult && pickResult.pickedMesh) {
             this._pickedUpMesh = pickResult.pickedMesh;
@@ -478,6 +475,8 @@ export class InputManager {
         this._alreadyAttachedTo = elementToAttachTo;
         let engine = scene.getEngine();
 
+        this._deviceInputSystem = DeviceInputSystem.Create(engine);
+
         this._initActionManager = (act: Nullable<AbstractActionManager>, clickInfo: _ClickInfo): Nullable<AbstractActionManager> => {
             if (!this._meshPickProceed) {
                 let pickResult = scene.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, scene.pointerDownPredicate, false, scene.cameraToUseForPointers);
@@ -500,7 +499,7 @@ export class InputManager {
             }
         };
 
-        this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void): void => {
+        this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: IPointerEvent, cb: (clickInfo: _ClickInfo, pickResult: Nullable<PickingInfo>) => void): void => {
             let clickInfo = new _ClickInfo();
             this._currentPickResult = null;
             let act: Nullable<AbstractActionManager> = null;
@@ -602,7 +601,7 @@ export class InputManager {
                             this._previousStartingPointerTime = this._startingPointerTime;
                             this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
                             this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
-                            this._previousButtonPressed = btn;
+                            this._previousButtonPressed = btn!;
                         }
                     }
                 }
@@ -613,16 +612,16 @@ export class InputManager {
             }
         };
 
-        this._onPointerMove = (evt: PointerEvent) => {
+        this._onPointerMove = (evt: IMouseEvent) => {
             // preserve compatibility with Safari when pointerId is not present
-            if (evt.pointerId === undefined) {
-                (evt as any).pointerId = 0;
+            if ((evt as IPointerEvent).pointerId === undefined) {
+                ((evt as IPointerEvent) as any).pointerId = 0;
             }
 
-            this._updatePointerPosition(evt);
+            this._updatePointerPosition((evt as IPointerEvent));
 
             // PreObservable support
-            if (this._checkPrePointerObservable(null, evt, evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
+            if (this._checkPrePointerObservable(null, (evt as IPointerEvent), evt.type === "wheel" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
                 return;
             }
 
@@ -636,17 +635,17 @@ export class InputManager {
                     mesh.isVisible &&
                     mesh.isReady() &&
                     mesh.isEnabled() &&
-                    (mesh.enablePointerMoveEvents || scene.constantlyUpdateMeshUnderPointer || mesh._getActionManagerForTrigger() != null) &&
+                    (mesh.enablePointerMoveEvents || scene.constantlyUpdateMeshUnderPointer || mesh._getActionManagerForTrigger() !== null) &&
                     (!scene.cameraToUseForPointers || (scene.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
             }
 
             // Meshes
             var pickResult = scene.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, scene.pointerMovePredicate, false, scene.cameraToUseForPointers);
 
-            this._processPointerMove(pickResult, evt);
+            this._processPointerMove(pickResult, (evt as IPointerEvent));
         };
 
-        this._onPointerDown = (evt: PointerEvent) => {
+        this._onPointerDown = (evt: IPointerEvent) => {
             this._totalPointersPressed++;
             this._pickedDownMesh = null;
             this._meshPickProceed = false;
@@ -658,8 +657,7 @@ export class InputManager {
 
             this._updatePointerPosition(evt);
 
-            if (scene.preventDefaultOnPointerDown && elementToAttachTo) {
-                evt.preventDefault();
+            if (scene.preventDefaultOnPointerDown && elementToAttachTo) { // TODO: DO WE NEED THIS?
                 elementToAttachTo.focus();
             }
 
@@ -691,7 +689,7 @@ export class InputManager {
             this._processPointerDown(pickResult, evt);
         };
 
-        this._onPointerUp = (evt: PointerEvent) => {
+        this._onPointerUp = (evt: IPointerEvent) => {
             if (this._totalPointersPressed === 0) {
                 // We are attaching the pointer up to windows because of a bug in FF
                 return; // So we need to test it the pointer down was pressed before.
@@ -708,8 +706,7 @@ export class InputManager {
 
             this._updatePointerPosition(evt);
 
-            if (scene.preventDefaultOnPointerUp && elementToAttachTo) {
-                evt.preventDefault();
+            if (scene.preventDefaultOnPointerUp && elementToAttachTo) { // TODO: DO WE NEED THIS?
                 elementToAttachTo.focus();
             }
 
@@ -764,7 +761,7 @@ export class InputManager {
             });
         };
 
-        this._onKeyDown = (evt: KeyboardEvent) => {
+        this._onKeyDown = (evt: IKeyboardEvent) => {
             let type = KeyboardEventTypes.KEYDOWN;
             if (scene.onPreKeyboardObservable.hasObservers()) {
                 let pi = new KeyboardInfoPre(type, evt);
@@ -784,7 +781,7 @@ export class InputManager {
             }
         };
 
-        this._onKeyUp = (evt: KeyboardEvent) => {
+        this._onKeyUp = (evt: IKeyboardEvent) => {
             let type = KeyboardEventTypes.KEYUP;
             if (scene.onPreKeyboardObservable.hasObservers()) {
                 let pi = new KeyboardInfoPre(type, evt);
@@ -804,84 +801,106 @@ export class InputManager {
             }
         };
 
-        let attachedFunction = () => {
-            if (!elementToAttachTo || this._keyboardIsAttached) {
-                return;
+        this._deviceInputSystem.onInputChanged = (deviceType, deviceSlot, inputIndex, previousState, currentState) => {
+            let isKeyboardActive = this._deviceInputSystem.isDeviceAvailable(DeviceType.Keyboard);
+
+            const altKey = (isKeyboardActive && this._deviceInputSystem.pollInput(DeviceType.Keyboard, 0, Constants.INPUT_ALT_KEY) === 1);
+            const ctrlKey = (isKeyboardActive && this._deviceInputSystem.pollInput(DeviceType.Keyboard, 0, Constants.INPUT_CTRL_KEY) === 1);
+            const metaKey = (isKeyboardActive && (this._deviceInputSystem.pollInput(DeviceType.Keyboard, 0, Constants.INPUT_META_KEY1) === 1
+                || this._deviceInputSystem.pollInput(DeviceType.Keyboard, 0, Constants.INPUT_META_KEY2) === 1
+                || this._deviceInputSystem.pollInput(DeviceType.Keyboard, 0, Constants.INPUT_META_KEY3) === 1));
+            const shiftKey = (isKeyboardActive && this._deviceInputSystem.pollInput(DeviceType.Keyboard, 0, Constants.INPUT_SHIFT_KEY) === 1);
+
+            const evt: {[k: string]: any} = {};
+
+            evt.target = elementToAttachTo;
+            evt.preventDefault = () => { },
+            evt.altKey = altKey;
+            evt.ctrlKey = ctrlKey;
+            evt.metaKey = metaKey;
+            evt.shiftKey = shiftKey;
+
+            // Keyboard Events
+            if (deviceType === DeviceType.Keyboard) {
+                evt.type = ((currentState === 1) ? "keydown" : "keyup");
+                evt.key = String.fromCharCode(inputIndex);
+                evt.keyCode = inputIndex;
+
+                if (currentState === 1) {
+                    this._onKeyDown((evt as IKeyboardEvent));
+                }
+
+                if (currentState === 0) {
+                    this._onKeyUp((evt as IKeyboardEvent));
+                }
             }
-            elementToAttachTo.addEventListener("keydown", this._onKeyDown, false);
-            elementToAttachTo.addEventListener("keyup", this._onKeyUp, false);
-            this._keyboardIsAttached = true;
-        };
 
-        // Keyboard events
-        this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(
-            (() => {
-                if (document.activeElement === elementToAttachTo) {
-                    attachedFunction();
+            // Pointer Events
+            if (deviceType === DeviceType.Mouse || deviceType === DeviceType.Touch) {
+                const pointerX = this._deviceInputSystem.pollInput(deviceType, deviceSlot, PointerInput.Horizontal);
+                const pointerY = this._deviceInputSystem.pollInput(deviceType, deviceSlot, PointerInput.Vertical);
+                // If dealing with a change to the delta, grab values for event init
+                const movementX = (inputIndex === PointerInput.DeltaHorizontal) ? currentState : 0;
+                const movementY = (inputIndex === PointerInput.DeltaVertical) ? currentState : 0;
+                // Get offsets from container
+                const offsetX = (inputIndex === PointerInput.DeltaHorizontal && elementToAttachTo) ? movementX! - elementToAttachTo.getBoundingClientRect().x : 0;
+                const offsetY = (inputIndex === PointerInput.DeltaVertical && elementToAttachTo) ? movementY! - elementToAttachTo.getBoundingClientRect().y : 0;
+
+                evt.pointerId = (deviceType === DeviceType.Mouse ? 1 : deviceSlot);
+                evt.clientX = pointerX;
+                evt.clientY = pointerY;
+                evt.movementX = movementX;
+                evt.movementY = movementY;
+                evt.offsetX = offsetX;
+                evt.offsetY = offsetY;
+                evt.x = pointerX;
+                evt.y = pointerY;
+
+                if (attachDown && inputIndex >= PointerInput.LeftClick && inputIndex <= PointerInput.RightClick && currentState === 1) {   // Pointer Down
+                    evt.type = "pointerdown";
+                    evt.button = (inputIndex - 2);
+
+                    this._onPointerDown((evt as IPointerEvent));
                 }
-                return attachedFunction;
-            })()
-        );
 
-        this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(() => {
-            if (!elementToAttachTo) {
-                return;
-            }
-            elementToAttachTo.removeEventListener("keydown", this._onKeyDown);
-            elementToAttachTo.removeEventListener("keyup", this._onKeyUp);
-            this._keyboardIsAttached = false;
-        });
-
-        attachedFunction();
-
-        // Pointer events
-        var eventPrefix = Tools.GetPointerPrefix(engine);
-
-        if (attachMove) {
-            elementToAttachTo.addEventListener(eventPrefix + "move", <any>this._onPointerMove, false);
-
-            // Wheel
-            this._wheelEventName =
-                "onwheel" in document.createElement("div")
-                    ? "wheel" // Modern browsers support "wheel"
-                    : (<any>document).onmousewheel !== undefined
-                    ? "mousewheel" // Webkit and IE support at least "mousewheel"
-                    : "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
-
-            // Chrome reports warning in console if wheel listener doesn't set an explicit passive option.
-            // IE11 only supports captureEvent:boolean, not options:object, and it defaults to false.
-            // Feature detection technique copied from: https://github.com/github/eventlistener-polyfill (MIT license)
-            // ----------
-            var passiveSupported = false;
-            var noop = function () {};
-            try {
-                var options: object = {
-                        passive: {
-                            get: function () {
-                                passiveSupported = true;
-                            }
-                        }
-                    };
-                elementToAttachTo.addEventListener("test", noop, options);
-                elementToAttachTo.removeEventListener("test", noop, options);
-            } catch (e) {
-                /* */
-            }
-            // ----------
+                if (attachUp && inputIndex >= PointerInput.LeftClick && inputIndex <= PointerInput.RightClick && currentState === 0) {   // Pointer Up
+                    evt.type = "pointerup";
+                    evt.button = (inputIndex - 2);
 
-            elementToAttachTo.addEventListener(this._wheelEventName, <any>this._onPointerMove, passiveSupported ? { passive: false } : false);
-        }
+                    this._onPointerUp((evt as IPointerEvent));
+                }
 
-        if (attachDown) {
-            elementToAttachTo.addEventListener(eventPrefix + "down", <any>this._onPointerDown, false);
-        }
+                if (attachMove) {
+                    if (inputIndex === PointerInput.Horizontal || inputIndex === PointerInput.Vertical || inputIndex === PointerInput.DeltaHorizontal || inputIndex === PointerInput.DeltaVertical) {
+                        evt.type = "pointermove";
 
-        if (attachUp) {
-            let hostWindow = scene.getEngine().getHostWindow();
-            if (hostWindow) {
-                hostWindow.addEventListener(eventPrefix + "up", <any>this._onPointerUp, false);
+                        this._onPointerMove((evt as IPointerEvent));
+                    }
+                    else if (inputIndex === PointerInput.MouseWheelX || inputIndex === PointerInput.MouseWheelY || inputIndex === PointerInput.MouseWheelZ) {
+                        /*
+                         * Since wheel inputs stay until they are read, we'll read everything at once.  We'll then fire off
+                         * a move event if any of them are not zero.  This will allow us to only fire off events with a proper
+                         * delta.
+                         */
+                        const deltaX = this._deviceInputSystem.pollInput(deviceType, deviceSlot, PointerInput.MouseWheelX);
+                        const deltaY = this._deviceInputSystem.pollInput(deviceType, deviceSlot, PointerInput.MouseWheelY);
+                        const deltaZ = this._deviceInputSystem.pollInput(deviceType, deviceSlot, PointerInput.MouseWheelZ);
+
+                        evt.type = "wheel";
+                        evt.deltaMode = EventConstants.DOM_DELTA_PIXEL;
+                        evt.deltaX = deltaX;
+                        evt.deltaY = deltaY;
+                        evt.deltaZ = deltaZ;
+
+                        // If we have a delta, use it.
+                        if (deltaX !== 0 || deltaY !== 0 || deltaZ !== 0) {
+                            this._onPointerMove((evt as IWheelEvent));
+                        }
+                    }
+                }
             }
-        }
+        };
+
         this._alreadyAttached = true;
     }
 
@@ -889,36 +908,11 @@ export class InputManager {
      * Detaches all event handlers
      */
     public detachControl() {
-        const engine = this._scene.getEngine();
-        const eventPrefix = Tools.GetPointerPrefix(engine);
-
-        if (!this._alreadyAttachedTo) {
+        if (!this._alreadyAttachedTo || !this._alreadyAttached) {
             return;
         }
 
-        if (!this._alreadyAttached) {
-            return;
-        }
-
-        // Pointer
-        this._alreadyAttachedTo.removeEventListener(eventPrefix + "move", <any>this._onPointerMove);
-        this._alreadyAttachedTo.removeEventListener(this._wheelEventName, <any>this._onPointerMove);
-        this._alreadyAttachedTo.removeEventListener(eventPrefix + "down", <any>this._onPointerDown);
-        window.removeEventListener(eventPrefix + "up", <any>this._onPointerUp);
-
-        // Blur / Focus
-        if (this._onCanvasBlurObserver) {
-            engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
-        }
-
-        if (this._onCanvasFocusObserver) {
-            engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
-        }
-
-        // Keyboard
-        this._alreadyAttachedTo.removeEventListener("keydown", this._onKeyDown);
-        this._alreadyAttachedTo.removeEventListener("keyup", this._onKeyUp);
-        this._keyboardIsAttached = false;
+        this._deviceInputSystem.dispose();
 
         // Cursor
         if (!this._scene.doNotHandleCursors) {

+ 3 - 2
src/Sprites/spriteSceneComponent.ts

@@ -9,6 +9,7 @@ import { PickingInfo } from "../Collisions/pickingInfo";
 import { ISceneComponent, SceneComponentConstants } from "../sceneComponent";
 import { ActionEvent } from "../Actions/actionEvent";
 import { Constants } from "../Engines/constants";
+import { IPointerEvent } from "../Events/deviceInputEvents";
 
 declare module "../scene" {
     export interface Scene {
@@ -337,7 +338,7 @@ export class SpriteSceneComponent implements ISceneComponent {
         return pickResult;
     }
 
-    private _pointerDown(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: PointerEvent): Nullable<PickingInfo> {
+    private _pointerDown(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: IPointerEvent): Nullable<PickingInfo> {
         var scene = this.scene;
         scene._pickedDownSprite = null;
         if (scene.spriteManagers.length > 0) {
@@ -367,7 +368,7 @@ export class SpriteSceneComponent implements ISceneComponent {
         return pickResult;
     }
 
-    private _pointerUp(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: PointerEvent): Nullable<PickingInfo> {
+    private _pointerUp(unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: IPointerEvent): Nullable<PickingInfo> {
         var scene = this.scene;
         if (scene.spriteManagers.length > 0) {
             let spritePickResult = scene.pickSprite(unTranslatedPointerX, unTranslatedPointerY, this._spritePredicate, false, scene.cameraToUseForPointers || undefined);

+ 5 - 4
src/scene.ts

@@ -55,6 +55,7 @@ import { Frustum } from './Maths/math.frustum';
 import { UniqueIdGenerator } from './Misc/uniqueIdGenerator';
 import { FileTools, LoadFileError, RequestFileError, ReadFileError } from './Misc/fileTools';
 import { IClipPlanesHolder } from './Misc/interfaces/iClipPlanesHolder';
+import { IPointerEvent } from "./Events/deviceInputEvents";
 
 declare type Ray = import("./Culling/ray").Ray;
 declare type TrianglePickingPredicate = import("./Culling/ray").TrianglePickingPredicate;
@@ -694,13 +695,13 @@ export class Scene extends AbstractScene implements IAnimatable, IClipPlanesHold
     public pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
 
     /** Callback called when a pointer move is detected */
-    public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
+    public onPointerMove: (evt: IPointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
     /** Callback called when a pointer down is detected  */
-    public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
+    public onPointerDown: (evt: IPointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
     /** Callback called when a pointer up is detected  */
-    public onPointerUp: (evt: PointerEvent, pickInfo: Nullable<PickingInfo>, type: PointerEventTypes) => void;
+    public onPointerUp: (evt: IPointerEvent, pickInfo: Nullable<PickingInfo>, type: PointerEventTypes) => void;
     /** Callback called when a pointer pick is detected */
-    public onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void;
+    public onPointerPick: (evt: IPointerEvent, pickInfo: PickingInfo) => void;
 
     /**
      * This observable event is triggered when any ponter event is triggered. It is registered during Scene.attachControl() and it is called BEFORE the 3D engine process anything (mesh/sprite picking for instance).

+ 2 - 1
src/sceneComponent.ts

@@ -8,6 +8,7 @@ import { Camera } from "./Cameras/camera";
 import { RenderTargetTexture } from "./Materials/Textures/renderTargetTexture";
 import { PickingInfo } from "./Collisions/pickingInfo";
 import { AbstractScene } from "./abstractScene";
+import { IPointerEvent } from "./Events/deviceInputEvents";
 
 declare type Mesh = import("./Meshes/mesh").Mesh;
 declare type Effect = import("./Materials/effect").Effect;
@@ -212,7 +213,7 @@ export type PointerMoveStageAction = (unTranslatedPointerX: number, unTranslated
 /**
  * Strong typing of a pointer up/down action.
  */
-export type PointerUpDownStageAction = (unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: PointerEvent) => Nullable<PickingInfo>;
+export type PointerUpDownStageAction = (unTranslatedPointerX: number, unTranslatedPointerY: number, pickResult: Nullable<PickingInfo>, evt: IPointerEvent) => Nullable<PickingInfo>;
 
 /**
  * Representation of a stage in the scene (Basically a list of ordered steps)