소스 검색

Keyboard is now handled with observables.

David Catuhe 8 년 전
부모
커밋
59d5e27302

+ 2 - 0
Tools/Gulp/config.json

@@ -45,6 +45,8 @@
         "core" :
         "core" :
         {
         {
             "files":[
             "files":[
+                "../../src/Events/babylon.keyboardEvents.js",
+                "../../src/Events/babylon.pointerEvents.js",
                 "../../src/Math/babylon.math.js",
                 "../../src/Math/babylon.math.js",
                 "../../src/Math/babylon.math.scalar.js",
                 "../../src/Math/babylon.math.scalar.js",
                 "../../src/babylon.mixins.js",
                 "../../src/babylon.mixins.js",

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1885 - 1838
dist/preview release/babylon.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 32 - 32
dist/preview release/babylon.js


+ 351 - 227
dist/preview release/babylon.max.js

@@ -14,7 +14,164 @@ var __extends = (this && this.__extends) || (function () {
                 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
                 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
             };
             };
         })();
         })();
-        var BABYLON;
+        
+var BABYLON;
+(function (BABYLON) {
+    var KeyboardEventTypes = (function () {
+        function KeyboardEventTypes() {
+        }
+        Object.defineProperty(KeyboardEventTypes, "KEYDOWN", {
+            get: function () {
+                return KeyboardEventTypes._KEYDOWN;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(KeyboardEventTypes, "KEYUP", {
+            get: function () {
+                return KeyboardEventTypes._KEYUP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        KeyboardEventTypes._KEYDOWN = 0x01;
+        KeyboardEventTypes._KEYUP = 0x02;
+        return KeyboardEventTypes;
+    }());
+    BABYLON.KeyboardEventTypes = KeyboardEventTypes;
+    var KeyboardInfo = (function () {
+        function KeyboardInfo(type, event) {
+            this.type = type;
+            this.event = event;
+        }
+        return KeyboardInfo;
+    }());
+    BABYLON.KeyboardInfo = KeyboardInfo;
+    /**
+     * This class is used to store keyboard related info for the onPreKeyboardObservable event.
+     * Set the skipOnKeyboardObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onKeyboardObservable
+     */
+    var KeyboardInfoPre = (function (_super) {
+        __extends(KeyboardInfoPre, _super);
+        function KeyboardInfoPre(type, event) {
+            var _this = _super.call(this, type, event) || this;
+            _this.skipOnPointerObservable = false;
+            return _this;
+        }
+        return KeyboardInfoPre;
+    }(KeyboardInfo));
+    BABYLON.KeyboardInfoPre = KeyboardInfoPre;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.keyboardEvents.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
+    var PointerEventTypes = (function () {
+        function PointerEventTypes() {
+        }
+        Object.defineProperty(PointerEventTypes, "POINTERDOWN", {
+            get: function () {
+                return PointerEventTypes._POINTERDOWN;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERUP", {
+            get: function () {
+                return PointerEventTypes._POINTERUP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERMOVE", {
+            get: function () {
+                return PointerEventTypes._POINTERMOVE;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERWHEEL", {
+            get: function () {
+                return PointerEventTypes._POINTERWHEEL;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERPICK", {
+            get: function () {
+                return PointerEventTypes._POINTERPICK;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERTAP", {
+            get: function () {
+                return PointerEventTypes._POINTERTAP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERDOUBLETAP", {
+            get: function () {
+                return PointerEventTypes._POINTERDOUBLETAP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PointerEventTypes._POINTERDOWN = 0x01;
+        PointerEventTypes._POINTERUP = 0x02;
+        PointerEventTypes._POINTERMOVE = 0x04;
+        PointerEventTypes._POINTERWHEEL = 0x08;
+        PointerEventTypes._POINTERPICK = 0x10;
+        PointerEventTypes._POINTERTAP = 0x20;
+        PointerEventTypes._POINTERDOUBLETAP = 0x40;
+        return PointerEventTypes;
+    }());
+    BABYLON.PointerEventTypes = PointerEventTypes;
+    var PointerInfoBase = (function () {
+        function PointerInfoBase(type, event) {
+            this.type = type;
+            this.event = event;
+        }
+        return PointerInfoBase;
+    }());
+    BABYLON.PointerInfoBase = PointerInfoBase;
+    /**
+     * This class is used to store pointer related info for the onPrePointerObservable event.
+     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
+     */
+    var PointerInfoPre = (function (_super) {
+        __extends(PointerInfoPre, _super);
+        function PointerInfoPre(type, event, localX, localY) {
+            var _this = _super.call(this, type, event) || this;
+            _this.skipOnPointerObservable = false;
+            _this.localPosition = new BABYLON.Vector2(localX, localY);
+            return _this;
+        }
+        return PointerInfoPre;
+    }(PointerInfoBase));
+    BABYLON.PointerInfoPre = PointerInfoPre;
+    /**
+     * This type contains all the data related to a pointer event in Babylon.js.
+     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
+     */
+    var PointerInfo = (function (_super) {
+        __extends(PointerInfo, _super);
+        function PointerInfo(type, event, pickInfo) {
+            var _this = _super.call(this, type, event) || this;
+            _this.pickInfo = pickInfo;
+            return _this;
+        }
+        return PointerInfo;
+    }(PointerInfoBase));
+    BABYLON.PointerInfo = PointerInfo;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.pointerEvents.js.map
+
+var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     BABYLON.ToGammaSpace = 1 / 2.2;
     BABYLON.ToGammaSpace = 1 / 2.2;
     BABYLON.ToLinearSpace = 2.2;
     BABYLON.ToLinearSpace = 2.2;
@@ -7459,9 +7616,17 @@ var BABYLON;
              */
              */
             this.onResizeObservable = new BABYLON.Observable();
             this.onResizeObservable = new BABYLON.Observable();
             /**
             /**
-             * Observable event triggered each time the canvas lost focus
+             * Observable event triggered each time the canvas loses focus
              */
              */
             this.onCanvasBlurObservable = new BABYLON.Observable();
             this.onCanvasBlurObservable = new BABYLON.Observable();
+            /**
+             * Observable event triggered each time the canvas gains focus
+             */
+            this.onCanvasFocusObservable = new BABYLON.Observable();
+            /**
+             * Observable event triggered each time the canvas receives pointerout event
+             */
+            this.onCanvasPointerOutObservable = new BABYLON.Observable();
             // Uniform buffers list
             // Uniform buffers list
             this.disableUniformBuffers = false;
             this.disableUniformBuffers = false;
             this._uniformBuffers = new Array();
             this._uniformBuffers = new Array();
@@ -7580,24 +7745,34 @@ var BABYLON;
                 if (!this._gl) {
                 if (!this._gl) {
                     throw new Error("WebGL not supported");
                     throw new Error("WebGL not supported");
                 }
                 }
+                this._onCanvasFocus = function () {
+                    _this.onCanvasFocusObservable.notifyObservers(_this);
+                };
+                this._onCanvasBlur = function () {
+                    _this.onCanvasBlurObservable.notifyObservers(_this);
+                };
+                canvas.addEventListener("focus", this._onCanvasFocus);
+                canvas.addEventListener("blur", this._onCanvasBlur);
                 this._onBlur = function () {
                 this._onBlur = function () {
                     if (_this.disablePerformanceMonitorInBackground) {
                     if (_this.disablePerformanceMonitorInBackground) {
                         _this._performanceMonitor.disable();
                         _this._performanceMonitor.disable();
                     }
                     }
                     _this._windowIsBackground = true;
                     _this._windowIsBackground = true;
+                    _this.onCanvasBlurObservable.notifyObservers(_this);
                 };
                 };
                 this._onFocus = function () {
                 this._onFocus = function () {
                     if (_this.disablePerformanceMonitorInBackground) {
                     if (_this.disablePerformanceMonitorInBackground) {
                         _this._performanceMonitor.enable();
                         _this._performanceMonitor.enable();
                     }
                     }
                     _this._windowIsBackground = false;
                     _this._windowIsBackground = false;
+                    _this.onCanvasFocusObservable.notifyObservers(_this);
                 };
                 };
-                this._onCanvasBlur = function () {
-                    _this.onCanvasBlurObservable.notifyObservers(_this);
+                this._onCanvasPointerOut = function () {
+                    _this.onCanvasPointerOutObservable.notifyObservers(_this);
                 };
                 };
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("focus", this._onFocus);
                 window.addEventListener("focus", this._onFocus);
-                canvas.addEventListener("pointerout", this._onCanvasBlur);
+                canvas.addEventListener("pointerout", this._onCanvasPointerOut);
             }
             }
             else {
             else {
                 this._gl = canvasOrContext;
                 this._gl = canvasOrContext;
@@ -10911,6 +11086,8 @@ var BABYLON;
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
+            this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
+            this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
             if (!this._doNotHandleContextLost) {
             if (!this._doNotHandleContextLost) {
                 this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
                 this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
@@ -10936,6 +11113,8 @@ var BABYLON;
             this._currentProgram = null;
             this._currentProgram = null;
             this.onResizeObservable.clear();
             this.onResizeObservable.clear();
             this.onCanvasBlurObservable.clear();
             this.onCanvasBlurObservable.clear();
+            this.onCanvasFocusObservable.clear();
+            this.onCanvasPointerOutObservable.clear();
             BABYLON.Effect.ResetCache();
             BABYLON.Effect.ResetCache();
         };
         };
         // Loading screen
         // Loading screen
@@ -16125,7 +16304,6 @@ var BABYLON;
 
 
 //# sourceMappingURL=babylon.renderingGroup.js.map
 //# sourceMappingURL=babylon.renderingGroup.js.map
 
 
-
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     var ClickInfo = (function () {
     var ClickInfo = (function () {
@@ -16177,105 +16355,6 @@ var BABYLON;
         });
         });
         return ClickInfo;
         return ClickInfo;
     }());
     }());
-    var PointerEventTypes = (function () {
-        function PointerEventTypes() {
-        }
-        Object.defineProperty(PointerEventTypes, "POINTERDOWN", {
-            get: function () {
-                return PointerEventTypes._POINTERDOWN;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERUP", {
-            get: function () {
-                return PointerEventTypes._POINTERUP;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERMOVE", {
-            get: function () {
-                return PointerEventTypes._POINTERMOVE;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERWHEEL", {
-            get: function () {
-                return PointerEventTypes._POINTERWHEEL;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERPICK", {
-            get: function () {
-                return PointerEventTypes._POINTERPICK;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERTAP", {
-            get: function () {
-                return PointerEventTypes._POINTERTAP;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERDOUBLETAP", {
-            get: function () {
-                return PointerEventTypes._POINTERDOUBLETAP;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        PointerEventTypes._POINTERDOWN = 0x01;
-        PointerEventTypes._POINTERUP = 0x02;
-        PointerEventTypes._POINTERMOVE = 0x04;
-        PointerEventTypes._POINTERWHEEL = 0x08;
-        PointerEventTypes._POINTERPICK = 0x10;
-        PointerEventTypes._POINTERTAP = 0x20;
-        PointerEventTypes._POINTERDOUBLETAP = 0x40;
-        return PointerEventTypes;
-    }());
-    BABYLON.PointerEventTypes = PointerEventTypes;
-    var PointerInfoBase = (function () {
-        function PointerInfoBase(type, event) {
-            this.type = type;
-            this.event = event;
-        }
-        return PointerInfoBase;
-    }());
-    BABYLON.PointerInfoBase = PointerInfoBase;
-    /**
-     * This class is used to store pointer related info for the onPrePointerObservable event.
-     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
-     */
-    var PointerInfoPre = (function (_super) {
-        __extends(PointerInfoPre, _super);
-        function PointerInfoPre(type, event, localX, localY) {
-            var _this = _super.call(this, type, event) || this;
-            _this.skipOnPointerObservable = false;
-            _this.localPosition = new BABYLON.Vector2(localX, localY);
-            return _this;
-        }
-        return PointerInfoPre;
-    }(PointerInfoBase));
-    BABYLON.PointerInfoPre = PointerInfoPre;
-    /**
-     * This type contains all the data related to a pointer event in Babylon.js.
-     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
-     */
-    var PointerInfo = (function (_super) {
-        __extends(PointerInfo, _super);
-        function PointerInfo(type, event, pickInfo) {
-            var _this = _super.call(this, type, event) || this;
-            _this.pickInfo = pickInfo;
-            return _this;
-        }
-        return PointerInfo;
-    }(PointerInfoBase));
-    BABYLON.PointerInfo = PointerInfo;
     /**
     /**
      * This class is used by the onRenderingGroupObservable
      * This class is used by the onRenderingGroupObservable
      */
      */
@@ -16419,8 +16498,8 @@ var BABYLON;
             // Animations
             // Animations
             this.animations = [];
             this.animations = [];
             /**
             /**
-             * This observable event is triggered when any mouse event registered during Scene.attach() is called BEFORE the 3D engine to process anything (mesh/sprite picking for instance).
-             * You have the possibility to skip the 3D Engine process and the call to onPointerObservable by setting PointerInfoBase.skipOnPointerObservable to true
+             * 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).
+             * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
              */
              */
             this.onPrePointerObservable = new BABYLON.Observable();
             this.onPrePointerObservable = new BABYLON.Observable();
             /**
             /**
@@ -16443,6 +16522,16 @@ var BABYLON;
             this._timeAccumulator = 0;
             this._timeAccumulator = 0;
             this._currentStepId = 0;
             this._currentStepId = 0;
             this._currentInternalStep = 0;
             this._currentInternalStep = 0;
+            // Keyboard
+            /**
+             * This observable event is triggered when any keyboard event si raised and registered during Scene.attachControl()
+             * You have the possibility to skip the process and the call to onKeyboardObservable by setting KeyboardInfoPre.skipOnPointerObservable to true
+             */
+            this.onPreKeyboardObservable = new BABYLON.Observable();
+            /**
+             * Observable event triggered each time an keyboard event is received from the hosting window
+             */
+            this.onKeyboardObservable = new BABYLON.Observable();
             // Coordinate system
             // Coordinate system
             /**
             /**
             * use right-handed coordinate system on this scene.
             * use right-handed coordinate system on this scene.
@@ -17137,9 +17226,9 @@ var BABYLON;
                 var clickInfo = new ClickInfo();
                 var clickInfo = new ClickInfo();
                 _this._currentPickResult = null;
                 _this._currentPickResult = null;
                 var act;
                 var act;
-                var checkPicking = obs1.hasSpecificMask(PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(PointerEventTypes.POINTERPICK)
-                    || obs1.hasSpecificMask(PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERTAP)
-                    || obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                var checkPicking = obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERPICK)
+                    || obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)
+                    || obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP);
                 if (!checkPicking && BABYLON.ActionManager && BABYLON.ActionManager.HasPickTriggers) {
                 if (!checkPicking && BABYLON.ActionManager && BABYLON.ActionManager.HasPickTriggers) {
                     act = _this._initActionManager(act, clickInfo);
                     act = _this._initActionManager(act, clickInfo);
                     if (act)
                     if (act)
@@ -17152,8 +17241,8 @@ var BABYLON;
                     if (!clickInfo.hasSwiped) {
                     if (!clickInfo.hasSwiped) {
                         var checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
                         var checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
                         if (!checkSingleClickImmediately) {
                         if (!checkSingleClickImmediately) {
-                            checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
-                                !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                            checkSingleClickImmediately = !obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP) &&
+                                !obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP);
                             if (checkSingleClickImmediately && !BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                             if (checkSingleClickImmediately && !BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                                 act = _this._initActionManager(act, clickInfo);
                                 act = _this._initActionManager(act, clickInfo);
                                 if (act)
                                 if (act)
@@ -17173,8 +17262,8 @@ var BABYLON;
                             _this._previousDelayedSimpleClickTimeout = _this._delayedSimpleClickTimeout;
                             _this._previousDelayedSimpleClickTimeout = _this._delayedSimpleClickTimeout;
                             _this._delayedSimpleClickTimeout = window.setTimeout(_this._delayedSimpleClick.bind(_this, btn, clickInfo, cb), Scene.DoubleClickDelay);
                             _this._delayedSimpleClickTimeout = window.setTimeout(_this._delayedSimpleClick.bind(_this, btn, clickInfo, cb), Scene.DoubleClickDelay);
                         }
                         }
-                        var checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
-                            obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                        var checkDoubleClick = obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP) ||
+                            obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP);
                         if (!checkDoubleClick && BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                         if (!checkDoubleClick && BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                             act = _this._initActionManager(act, clickInfo);
                             act = _this._initActionManager(act, clickInfo);
                             if (act)
                             if (act)
@@ -17238,8 +17327,8 @@ var BABYLON;
                 _this._updatePointerPosition(evt);
                 _this._updatePointerPosition(evt);
                 // PreObservable support
                 // PreObservable support
                 if (_this.onPrePointerObservable.hasObservers()) {
                 if (_this.onPrePointerObservable.hasObservers()) {
-                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
-                    var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
+                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
+                    var pi = new BABYLON.PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     if (pi.skipOnPointerObservable) {
                     if (pi.skipOnPointerObservable) {
                         return;
                         return;
@@ -17292,8 +17381,8 @@ var BABYLON;
                     _this.onPointerMove(evt, pickResult);
                     _this.onPointerMove(evt, pickResult);
                 }
                 }
                 if (_this.onPointerObservable.hasObservers()) {
                 if (_this.onPointerObservable.hasObservers()) {
-                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
-                    var pi = new PointerInfo(type, evt, pickResult);
+                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                     _this.onPointerObservable.notifyObservers(pi, type);
                     _this.onPointerObservable.notifyObservers(pi, type);
                 }
                 }
             };
             };
@@ -17304,8 +17393,8 @@ var BABYLON;
                 _this._updatePointerPosition(evt);
                 _this._updatePointerPosition(evt);
                 // PreObservable support
                 // PreObservable support
                 if (_this.onPrePointerObservable.hasObservers()) {
                 if (_this.onPrePointerObservable.hasObservers()) {
-                    var type = PointerEventTypes.POINTERDOWN;
-                    var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
+                    var type = BABYLON.PointerEventTypes.POINTERDOWN;
+                    var pi = new BABYLON.PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     if (pi.skipOnPointerObservable) {
                     if (pi.skipOnPointerObservable) {
                         return;
                         return;
@@ -17364,8 +17453,8 @@ var BABYLON;
                     _this.onPointerDown(evt, pickResult);
                     _this.onPointerDown(evt, pickResult);
                 }
                 }
                 if (_this.onPointerObservable.hasObservers()) {
                 if (_this.onPointerObservable.hasObservers()) {
-                    var type = PointerEventTypes.POINTERDOWN;
-                    var pi = new PointerInfo(type, evt, pickResult);
+                    var type = BABYLON.PointerEventTypes.POINTERDOWN;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                     _this.onPointerObservable.notifyObservers(pi, type);
                     _this.onPointerObservable.notifyObservers(pi, type);
                 }
                 }
                 // Sprites
                 // Sprites
@@ -17403,17 +17492,17 @@ var BABYLON;
                     if (this.onPrePointerObservable.hasObservers()) {
                     if (this.onPrePointerObservable.hasObservers()) {
                         if (!clickInfo.ignore) {
                         if (!clickInfo.ignore) {
                             if (!clickInfo.hasSwiped) {
                             if (!clickInfo.hasSwiped) {
-                                if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                                    var type = PointerEventTypes.POINTERTAP;
-                                    var pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                                if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERTAP;
+                                    var pi = new BABYLON.PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     if (pi.skipOnPointerObservable) {
                                     if (pi.skipOnPointerObservable) {
                                         return;
                                         return;
                                     }
                                     }
                                 }
                                 }
-                                if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                                    var type = PointerEventTypes.POINTERDOUBLETAP;
-                                    var pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                                if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
+                                    var pi = new BABYLON.PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     if (pi.skipOnPointerObservable) {
                                     if (pi.skipOnPointerObservable) {
                                         return;
                                         return;
@@ -17422,8 +17511,8 @@ var BABYLON;
                             }
                             }
                         }
                         }
                         else {
                         else {
-                            var type = PointerEventTypes.POINTERUP;
-                            var pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                            var type = BABYLON.PointerEventTypes.POINTERUP;
+                            var pi = new BABYLON.PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
                             this.onPrePointerObservable.notifyObservers(pi, type);
                             this.onPrePointerObservable.notifyObservers(pi, type);
                             if (pi.skipOnPointerObservable) {
                             if (pi.skipOnPointerObservable) {
                                 return;
                                 return;
@@ -17452,8 +17541,8 @@ var BABYLON;
                                 this.onPointerPick(evt, pickResult);
                                 this.onPointerPick(evt, pickResult);
                             }
                             }
                             if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
                             if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
-                                var type = PointerEventTypes.POINTERPICK;
-                                var pi = new PointerInfo(type, evt, pickResult);
+                                var type = BABYLON.PointerEventTypes.POINTERPICK;
+                                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                                 this.onPointerObservable.notifyObservers(pi, type);
                                 this.onPointerObservable.notifyObservers(pi, type);
                             }
                             }
                         }
                         }
@@ -17481,21 +17570,21 @@ var BABYLON;
                     if (this.onPointerObservable.hasObservers()) {
                     if (this.onPointerObservable.hasObservers()) {
                         if (!clickInfo.ignore) {
                         if (!clickInfo.ignore) {
                             if (!clickInfo.hasSwiped) {
                             if (!clickInfo.hasSwiped) {
-                                if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                                    var type = PointerEventTypes.POINTERTAP;
-                                    var pi = new PointerInfo(type, evt, pickResult);
+                                if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERTAP;
+                                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                 }
                                 }
-                                if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                                    var type = PointerEventTypes.POINTERDOUBLETAP;
-                                    var pi = new PointerInfo(type, evt, pickResult);
+                                if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
+                                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                 }
                                 }
                             }
                             }
                         }
                         }
                         else {
                         else {
-                            var type = PointerEventTypes.POINTERUP;
-                            var pi = new PointerInfo(type, evt, pickResult);
+                            var type = BABYLON.PointerEventTypes.POINTERUP;
+                            var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                             this.onPointerObservable.notifyObservers(pi, type);
                             this.onPointerObservable.notifyObservers(pi, type);
                         }
                         }
                     }
                     }
@@ -17520,15 +17609,48 @@ var BABYLON;
                 }).bind(_this));
                 }).bind(_this));
             };
             };
             this._onKeyDown = function (evt) {
             this._onKeyDown = function (evt) {
+                var type = BABYLON.KeyboardEventTypes.KEYDOWN;
+                if (_this.onPreKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfoPre(type, evt);
+                    _this.onPreKeyboardObservable.notifyObservers(pi, type);
+                    if (pi.skipOnPointerObservable) {
+                        return;
+                    }
+                }
+                if (_this.onKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfo(type, evt);
+                    _this.onKeyboardObservable.notifyObservers(pi, type);
+                }
                 if (_this.actionManager) {
                 if (_this.actionManager) {
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyDownTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyDownTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                 }
                 }
             };
             };
             this._onKeyUp = function (evt) {
             this._onKeyUp = function (evt) {
+                var type = BABYLON.KeyboardEventTypes.KEYUP;
+                if (_this.onPreKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfoPre(type, evt);
+                    _this.onPreKeyboardObservable.notifyObservers(pi, type);
+                    if (pi.skipOnPointerObservable) {
+                        return;
+                    }
+                }
+                if (_this.onKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfo(type, evt);
+                    _this.onKeyboardObservable.notifyObservers(pi, type);
+                }
                 if (_this.actionManager) {
                 if (_this.actionManager) {
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyUpTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyUpTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                 }
                 }
             };
             };
+            var engine = this.getEngine();
+            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(function () {
+                canvas.addEventListener("keydown", _this._onKeyDown, false);
+                canvas.addEventListener("keyup", _this._onKeyUp, false);
+            });
+            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(function () {
+                canvas.removeEventListener("keydown", _this._onKeyDown);
+                canvas.removeEventListener("keyup", _this._onKeyUp);
+            });
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
             var canvas = this._engine.getRenderingCanvas();
             var canvas = this._engine.getRenderingCanvas();
             if (attachMove) {
             if (attachMove) {
@@ -17544,20 +17666,27 @@ var BABYLON;
                 canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false);
                 canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false);
             }
             }
             canvas.tabIndex = 1;
             canvas.tabIndex = 1;
-            canvas.addEventListener("keydown", this._onKeyDown, false);
-            canvas.addEventListener("keyup", this._onKeyUp, false);
         };
         };
         Scene.prototype.detachControl = function () {
         Scene.prototype.detachControl = function () {
+            var engine = this.getEngine();
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
-            var canvas = this._engine.getRenderingCanvas();
+            var canvas = engine.getRenderingCanvas();
             canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
             canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
             canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
             canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
             canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
             canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
+            engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+            engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
             // Wheel
             // Wheel
             canvas.removeEventListener('mousewheel', this._onPointerMove);
             canvas.removeEventListener('mousewheel', this._onPointerMove);
             canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
             canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
+            // Keyboard
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keyup", this._onKeyUp);
             canvas.removeEventListener("keyup", this._onKeyUp);
+            // Observables
+            this.onKeyboardObservable.clear();
+            this.onPreKeyboardObservable.clear();
+            this.onPointerObservable.clear();
+            this.onPrePointerObservable.clear();
         };
         };
         // Ready
         // Ready
         Scene.prototype.isReady = function () {
         Scene.prototype.isReady = function () {
@@ -34122,9 +34251,17 @@ var BABYLON;
         }
         }
         FreeCameraKeyboardMoveInput.prototype.attachControl = function (element, noPreventDefault) {
         FreeCameraKeyboardMoveInput.prototype.attachControl = function (element, noPreventDefault) {
             var _this = this;
             var _this = this;
-            if (!this._onKeyDown) {
-                element.tabIndex = 1;
-                this._onKeyDown = function (evt) {
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(function () {
+                _this._keys = [];
+            });
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(function (info) {
+                var evt = info.event;
+                if (info.type === BABYLON.KeyboardEventTypes.KEYDOWN) {
                     if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
                     if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
                         _this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         _this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                         _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
@@ -34137,8 +34274,8 @@ var BABYLON;
                             evt.preventDefault();
                             evt.preventDefault();
                         }
                         }
                     }
                     }
-                };
-                this._onKeyUp = function (evt) {
+                }
+                else {
                     if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
                     if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
                         _this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         _this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                         _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
@@ -34151,28 +34288,20 @@ var BABYLON;
                             evt.preventDefault();
                             evt.preventDefault();
                         }
                         }
                     }
                     }
-                };
-                element.addEventListener("keydown", this._onKeyDown, false);
-                element.addEventListener("keyup", this._onKeyUp, false);
-                BABYLON.Tools.RegisterTopRootEvents([
-                    { name: "blur", handler: this._onLostFocus }
-                ]);
-            }
+                }
+            });
         };
         };
         FreeCameraKeyboardMoveInput.prototype.detachControl = function (element) {
         FreeCameraKeyboardMoveInput.prototype.detachControl = function (element) {
-            if (this._onKeyDown) {
-                element.removeEventListener("keydown", this._onKeyDown);
-                element.removeEventListener("keyup", this._onKeyUp);
-                BABYLON.Tools.UnregisterTopRootEvents([
-                    { name: "blur", handler: this._onLostFocus }
-                ]);
-                this._keys = [];
-                this._onKeyDown = null;
-                this._onKeyUp = null;
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
+            this._keys = [];
         };
         };
         FreeCameraKeyboardMoveInput.prototype.checkInputs = function () {
         FreeCameraKeyboardMoveInput.prototype.checkInputs = function () {
-            if (this._onKeyDown) {
+            if (this._onKeyboardObserver) {
                 var camera = this.camera;
                 var camera = this.camera;
                 // Keyboard
                 // Keyboard
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {
@@ -34797,77 +34926,64 @@ var BABYLON;
         }
         }
         ArcRotateCameraKeyboardMoveInput.prototype.attachControl = function (element, noPreventDefault) {
         ArcRotateCameraKeyboardMoveInput.prototype.attachControl = function (element, noPreventDefault) {
             var _this = this;
             var _this = this;
-            element.tabIndex = 1;
-            this._onKeyDown = function (evt) {
-                _this._ctrlPressed = evt.ctrlKey;
-                if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = _this._keys.indexOf(evt.keyCode);
-                    if (index === -1) {
-                        _this._keys.push(evt.keyCode);
-                    }
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(function () {
+                _this._keys = [];
+            });
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(function (info) {
+                var evt = info.event;
+                if (info.type === BABYLON.KeyboardEventTypes.KEYDOWN) {
+                    _this._ctrlPressed = evt.ctrlKey;
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
+                        if (index === -1) {
+                            _this._keys.push(evt.keyCode);
+                        }
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
-            };
-            this._onKeyUp = function (evt) {
-                if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = _this._keys.indexOf(evt.keyCode);
-                    if (index >= 0) {
-                        _this._keys.splice(index, 1);
-                    }
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                else {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
+                        if (index >= 0) {
+                            _this._keys.splice(index, 1);
+                        }
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
-            };
-            this._onLostFocus = function () {
-                _this._keys = [];
-            };
-            this._onFocus = function () {
-                element.addEventListener("keydown", _this._onKeyDown, false);
-                element.addEventListener("keyup", _this._onKeyUp, false);
-            };
-            this._onBlur = function () {
-                element.removeEventListener("keydown", _this._onKeyDown);
-                element.removeEventListener("keyup", _this._onKeyUp);
-            };
-            element.addEventListener("focus", this._onFocus);
-            element.addEventListener("blur", this._onBlur);
-            BABYLON.Tools.RegisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            });
         };
         };
         ArcRotateCameraKeyboardMoveInput.prototype.detachControl = function (element) {
         ArcRotateCameraKeyboardMoveInput.prototype.detachControl = function (element) {
-            if (element && this._onBlur) {
-                this._onBlur();
-                element.removeEventListener("focus", this._onFocus);
-                element.removeEventListener("blur", this._onBlur);
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
-            BABYLON.Tools.UnregisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
             this._keys = [];
             this._keys = [];
-            this._onKeyDown = null;
-            this._onKeyUp = null;
-            this._onLostFocus = null;
-            this._onBlur = null;
-            this._onFocus = null;
         };
         };
         ArcRotateCameraKeyboardMoveInput.prototype.checkInputs = function () {
         ArcRotateCameraKeyboardMoveInput.prototype.checkInputs = function () {
-            if (this._onKeyDown) {
+            if (this._onKeyboardObserver) {
                 var camera = this.camera;
                 var camera = this.camera;
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {
                     var keyCode = this._keys[index];
                     var keyCode = this._keys[index];
@@ -66115,9 +66231,17 @@ var BABYLON;
                                 if (!_this._lightOnControllers) {
                                 if (!_this._lightOnControllers) {
                                     _this._lightOnControllers = new BABYLON.HemisphericLight("vrControllersLight", new BABYLON.Vector3(0, 1, 0), _this.getScene());
                                     _this._lightOnControllers = new BABYLON.HemisphericLight("vrControllersLight", new BABYLON.Vector3(0, 1, 0), _this.getScene());
                                 }
                                 }
-                                loadedMesh.getChildren().forEach(function (mesh) {
-                                    _this._lightOnControllers.includedOnlyMeshes.push(mesh);
-                                });
+                                var activateLightOnSubMeshes_1 = function (mesh, light) {
+                                    var children = mesh.getChildren();
+                                    if (children.length !== 0) {
+                                        children.forEach(function (mesh) {
+                                            light.includedOnlyMeshes.push(mesh);
+                                            activateLightOnSubMeshes_1(mesh, light);
+                                        });
+                                    }
+                                };
+                                _this._lightOnControllers.includedOnlyMeshes.push(loadedMesh);
+                                activateLightOnSubMeshes_1(loadedMesh, _this._lightOnControllers);
                             }
                             }
                         });
                         });
                     }
                     }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1885 - 1838
dist/preview release/babylon.module.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 36 - 36
dist/preview release/babylon.worker.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 8420 - 8373
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 33 - 33
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 318 - 202
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -14,7 +14,164 @@ var __extends = (this && this.__extends) || (function () {
                 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
                 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
             };
             };
         })();
         })();
-        var BABYLON;
+        
+var BABYLON;
+(function (BABYLON) {
+    var KeyboardEventTypes = (function () {
+        function KeyboardEventTypes() {
+        }
+        Object.defineProperty(KeyboardEventTypes, "KEYDOWN", {
+            get: function () {
+                return KeyboardEventTypes._KEYDOWN;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(KeyboardEventTypes, "KEYUP", {
+            get: function () {
+                return KeyboardEventTypes._KEYUP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        KeyboardEventTypes._KEYDOWN = 0x01;
+        KeyboardEventTypes._KEYUP = 0x02;
+        return KeyboardEventTypes;
+    }());
+    BABYLON.KeyboardEventTypes = KeyboardEventTypes;
+    var KeyboardInfo = (function () {
+        function KeyboardInfo(type, event) {
+            this.type = type;
+            this.event = event;
+        }
+        return KeyboardInfo;
+    }());
+    BABYLON.KeyboardInfo = KeyboardInfo;
+    /**
+     * This class is used to store keyboard related info for the onPreKeyboardObservable event.
+     * Set the skipOnKeyboardObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onKeyboardObservable
+     */
+    var KeyboardInfoPre = (function (_super) {
+        __extends(KeyboardInfoPre, _super);
+        function KeyboardInfoPre(type, event) {
+            var _this = _super.call(this, type, event) || this;
+            _this.skipOnPointerObservable = false;
+            return _this;
+        }
+        return KeyboardInfoPre;
+    }(KeyboardInfo));
+    BABYLON.KeyboardInfoPre = KeyboardInfoPre;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.keyboardEvents.js.map
+
+
+var BABYLON;
+(function (BABYLON) {
+    var PointerEventTypes = (function () {
+        function PointerEventTypes() {
+        }
+        Object.defineProperty(PointerEventTypes, "POINTERDOWN", {
+            get: function () {
+                return PointerEventTypes._POINTERDOWN;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERUP", {
+            get: function () {
+                return PointerEventTypes._POINTERUP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERMOVE", {
+            get: function () {
+                return PointerEventTypes._POINTERMOVE;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERWHEEL", {
+            get: function () {
+                return PointerEventTypes._POINTERWHEEL;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERPICK", {
+            get: function () {
+                return PointerEventTypes._POINTERPICK;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERTAP", {
+            get: function () {
+                return PointerEventTypes._POINTERTAP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(PointerEventTypes, "POINTERDOUBLETAP", {
+            get: function () {
+                return PointerEventTypes._POINTERDOUBLETAP;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        PointerEventTypes._POINTERDOWN = 0x01;
+        PointerEventTypes._POINTERUP = 0x02;
+        PointerEventTypes._POINTERMOVE = 0x04;
+        PointerEventTypes._POINTERWHEEL = 0x08;
+        PointerEventTypes._POINTERPICK = 0x10;
+        PointerEventTypes._POINTERTAP = 0x20;
+        PointerEventTypes._POINTERDOUBLETAP = 0x40;
+        return PointerEventTypes;
+    }());
+    BABYLON.PointerEventTypes = PointerEventTypes;
+    var PointerInfoBase = (function () {
+        function PointerInfoBase(type, event) {
+            this.type = type;
+            this.event = event;
+        }
+        return PointerInfoBase;
+    }());
+    BABYLON.PointerInfoBase = PointerInfoBase;
+    /**
+     * This class is used to store pointer related info for the onPrePointerObservable event.
+     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
+     */
+    var PointerInfoPre = (function (_super) {
+        __extends(PointerInfoPre, _super);
+        function PointerInfoPre(type, event, localX, localY) {
+            var _this = _super.call(this, type, event) || this;
+            _this.skipOnPointerObservable = false;
+            _this.localPosition = new BABYLON.Vector2(localX, localY);
+            return _this;
+        }
+        return PointerInfoPre;
+    }(PointerInfoBase));
+    BABYLON.PointerInfoPre = PointerInfoPre;
+    /**
+     * This type contains all the data related to a pointer event in Babylon.js.
+     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
+     */
+    var PointerInfo = (function (_super) {
+        __extends(PointerInfo, _super);
+        function PointerInfo(type, event, pickInfo) {
+            var _this = _super.call(this, type, event) || this;
+            _this.pickInfo = pickInfo;
+            return _this;
+        }
+        return PointerInfo;
+    }(PointerInfoBase));
+    BABYLON.PointerInfo = PointerInfo;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.pointerEvents.js.map
+
+var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     BABYLON.ToGammaSpace = 1 / 2.2;
     BABYLON.ToGammaSpace = 1 / 2.2;
     BABYLON.ToLinearSpace = 2.2;
     BABYLON.ToLinearSpace = 2.2;
@@ -7459,9 +7616,17 @@ var BABYLON;
              */
              */
             this.onResizeObservable = new BABYLON.Observable();
             this.onResizeObservable = new BABYLON.Observable();
             /**
             /**
-             * Observable event triggered each time the canvas lost focus
+             * Observable event triggered each time the canvas loses focus
              */
              */
             this.onCanvasBlurObservable = new BABYLON.Observable();
             this.onCanvasBlurObservable = new BABYLON.Observable();
+            /**
+             * Observable event triggered each time the canvas gains focus
+             */
+            this.onCanvasFocusObservable = new BABYLON.Observable();
+            /**
+             * Observable event triggered each time the canvas receives pointerout event
+             */
+            this.onCanvasPointerOutObservable = new BABYLON.Observable();
             // Uniform buffers list
             // Uniform buffers list
             this.disableUniformBuffers = false;
             this.disableUniformBuffers = false;
             this._uniformBuffers = new Array();
             this._uniformBuffers = new Array();
@@ -7580,24 +7745,34 @@ var BABYLON;
                 if (!this._gl) {
                 if (!this._gl) {
                     throw new Error("WebGL not supported");
                     throw new Error("WebGL not supported");
                 }
                 }
+                this._onCanvasFocus = function () {
+                    _this.onCanvasFocusObservable.notifyObservers(_this);
+                };
+                this._onCanvasBlur = function () {
+                    _this.onCanvasBlurObservable.notifyObservers(_this);
+                };
+                canvas.addEventListener("focus", this._onCanvasFocus);
+                canvas.addEventListener("blur", this._onCanvasBlur);
                 this._onBlur = function () {
                 this._onBlur = function () {
                     if (_this.disablePerformanceMonitorInBackground) {
                     if (_this.disablePerformanceMonitorInBackground) {
                         _this._performanceMonitor.disable();
                         _this._performanceMonitor.disable();
                     }
                     }
                     _this._windowIsBackground = true;
                     _this._windowIsBackground = true;
+                    _this.onCanvasBlurObservable.notifyObservers(_this);
                 };
                 };
                 this._onFocus = function () {
                 this._onFocus = function () {
                     if (_this.disablePerformanceMonitorInBackground) {
                     if (_this.disablePerformanceMonitorInBackground) {
                         _this._performanceMonitor.enable();
                         _this._performanceMonitor.enable();
                     }
                     }
                     _this._windowIsBackground = false;
                     _this._windowIsBackground = false;
+                    _this.onCanvasFocusObservable.notifyObservers(_this);
                 };
                 };
-                this._onCanvasBlur = function () {
-                    _this.onCanvasBlurObservable.notifyObservers(_this);
+                this._onCanvasPointerOut = function () {
+                    _this.onCanvasPointerOutObservable.notifyObservers(_this);
                 };
                 };
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("focus", this._onFocus);
                 window.addEventListener("focus", this._onFocus);
-                canvas.addEventListener("pointerout", this._onCanvasBlur);
+                canvas.addEventListener("pointerout", this._onCanvasPointerOut);
             }
             }
             else {
             else {
                 this._gl = canvasOrContext;
                 this._gl = canvasOrContext;
@@ -10911,6 +11086,8 @@ var BABYLON;
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
+            this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
+            this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
             if (!this._doNotHandleContextLost) {
             if (!this._doNotHandleContextLost) {
                 this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
                 this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
@@ -10936,6 +11113,8 @@ var BABYLON;
             this._currentProgram = null;
             this._currentProgram = null;
             this.onResizeObservable.clear();
             this.onResizeObservable.clear();
             this.onCanvasBlurObservable.clear();
             this.onCanvasBlurObservable.clear();
+            this.onCanvasFocusObservable.clear();
+            this.onCanvasPointerOutObservable.clear();
             BABYLON.Effect.ResetCache();
             BABYLON.Effect.ResetCache();
         };
         };
         // Loading screen
         // Loading screen
@@ -16125,7 +16304,6 @@ var BABYLON;
 
 
 //# sourceMappingURL=babylon.renderingGroup.js.map
 //# sourceMappingURL=babylon.renderingGroup.js.map
 
 
-
 var BABYLON;
 var BABYLON;
 (function (BABYLON) {
 (function (BABYLON) {
     var ClickInfo = (function () {
     var ClickInfo = (function () {
@@ -16177,105 +16355,6 @@ var BABYLON;
         });
         });
         return ClickInfo;
         return ClickInfo;
     }());
     }());
-    var PointerEventTypes = (function () {
-        function PointerEventTypes() {
-        }
-        Object.defineProperty(PointerEventTypes, "POINTERDOWN", {
-            get: function () {
-                return PointerEventTypes._POINTERDOWN;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERUP", {
-            get: function () {
-                return PointerEventTypes._POINTERUP;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERMOVE", {
-            get: function () {
-                return PointerEventTypes._POINTERMOVE;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERWHEEL", {
-            get: function () {
-                return PointerEventTypes._POINTERWHEEL;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERPICK", {
-            get: function () {
-                return PointerEventTypes._POINTERPICK;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERTAP", {
-            get: function () {
-                return PointerEventTypes._POINTERTAP;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        Object.defineProperty(PointerEventTypes, "POINTERDOUBLETAP", {
-            get: function () {
-                return PointerEventTypes._POINTERDOUBLETAP;
-            },
-            enumerable: true,
-            configurable: true
-        });
-        PointerEventTypes._POINTERDOWN = 0x01;
-        PointerEventTypes._POINTERUP = 0x02;
-        PointerEventTypes._POINTERMOVE = 0x04;
-        PointerEventTypes._POINTERWHEEL = 0x08;
-        PointerEventTypes._POINTERPICK = 0x10;
-        PointerEventTypes._POINTERTAP = 0x20;
-        PointerEventTypes._POINTERDOUBLETAP = 0x40;
-        return PointerEventTypes;
-    }());
-    BABYLON.PointerEventTypes = PointerEventTypes;
-    var PointerInfoBase = (function () {
-        function PointerInfoBase(type, event) {
-            this.type = type;
-            this.event = event;
-        }
-        return PointerInfoBase;
-    }());
-    BABYLON.PointerInfoBase = PointerInfoBase;
-    /**
-     * This class is used to store pointer related info for the onPrePointerObservable event.
-     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
-     */
-    var PointerInfoPre = (function (_super) {
-        __extends(PointerInfoPre, _super);
-        function PointerInfoPre(type, event, localX, localY) {
-            var _this = _super.call(this, type, event) || this;
-            _this.skipOnPointerObservable = false;
-            _this.localPosition = new BABYLON.Vector2(localX, localY);
-            return _this;
-        }
-        return PointerInfoPre;
-    }(PointerInfoBase));
-    BABYLON.PointerInfoPre = PointerInfoPre;
-    /**
-     * This type contains all the data related to a pointer event in Babylon.js.
-     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
-     */
-    var PointerInfo = (function (_super) {
-        __extends(PointerInfo, _super);
-        function PointerInfo(type, event, pickInfo) {
-            var _this = _super.call(this, type, event) || this;
-            _this.pickInfo = pickInfo;
-            return _this;
-        }
-        return PointerInfo;
-    }(PointerInfoBase));
-    BABYLON.PointerInfo = PointerInfo;
     /**
     /**
      * This class is used by the onRenderingGroupObservable
      * This class is used by the onRenderingGroupObservable
      */
      */
@@ -16419,8 +16498,8 @@ var BABYLON;
             // Animations
             // Animations
             this.animations = [];
             this.animations = [];
             /**
             /**
-             * This observable event is triggered when any mouse event registered during Scene.attach() is called BEFORE the 3D engine to process anything (mesh/sprite picking for instance).
-             * You have the possibility to skip the 3D Engine process and the call to onPointerObservable by setting PointerInfoBase.skipOnPointerObservable to true
+             * 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).
+             * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
              */
              */
             this.onPrePointerObservable = new BABYLON.Observable();
             this.onPrePointerObservable = new BABYLON.Observable();
             /**
             /**
@@ -16443,6 +16522,16 @@ var BABYLON;
             this._timeAccumulator = 0;
             this._timeAccumulator = 0;
             this._currentStepId = 0;
             this._currentStepId = 0;
             this._currentInternalStep = 0;
             this._currentInternalStep = 0;
+            // Keyboard
+            /**
+             * This observable event is triggered when any keyboard event si raised and registered during Scene.attachControl()
+             * You have the possibility to skip the process and the call to onKeyboardObservable by setting KeyboardInfoPre.skipOnPointerObservable to true
+             */
+            this.onPreKeyboardObservable = new BABYLON.Observable();
+            /**
+             * Observable event triggered each time an keyboard event is received from the hosting window
+             */
+            this.onKeyboardObservable = new BABYLON.Observable();
             // Coordinate system
             // Coordinate system
             /**
             /**
             * use right-handed coordinate system on this scene.
             * use right-handed coordinate system on this scene.
@@ -17137,9 +17226,9 @@ var BABYLON;
                 var clickInfo = new ClickInfo();
                 var clickInfo = new ClickInfo();
                 _this._currentPickResult = null;
                 _this._currentPickResult = null;
                 var act;
                 var act;
-                var checkPicking = obs1.hasSpecificMask(PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(PointerEventTypes.POINTERPICK)
-                    || obs1.hasSpecificMask(PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERTAP)
-                    || obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                var checkPicking = obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERPICK) || obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERPICK)
+                    || obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP) || obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)
+                    || obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP) || obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP);
                 if (!checkPicking && BABYLON.ActionManager && BABYLON.ActionManager.HasPickTriggers) {
                 if (!checkPicking && BABYLON.ActionManager && BABYLON.ActionManager.HasPickTriggers) {
                     act = _this._initActionManager(act, clickInfo);
                     act = _this._initActionManager(act, clickInfo);
                     if (act)
                     if (act)
@@ -17152,8 +17241,8 @@ var BABYLON;
                     if (!clickInfo.hasSwiped) {
                     if (!clickInfo.hasSwiped) {
                         var checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
                         var checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
                         if (!checkSingleClickImmediately) {
                         if (!checkSingleClickImmediately) {
-                            checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
-                                !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                            checkSingleClickImmediately = !obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP) &&
+                                !obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP);
                             if (checkSingleClickImmediately && !BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                             if (checkSingleClickImmediately && !BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                                 act = _this._initActionManager(act, clickInfo);
                                 act = _this._initActionManager(act, clickInfo);
                                 if (act)
                                 if (act)
@@ -17173,8 +17262,8 @@ var BABYLON;
                             _this._previousDelayedSimpleClickTimeout = _this._delayedSimpleClickTimeout;
                             _this._previousDelayedSimpleClickTimeout = _this._delayedSimpleClickTimeout;
                             _this._delayedSimpleClickTimeout = window.setTimeout(_this._delayedSimpleClick.bind(_this, btn, clickInfo, cb), Scene.DoubleClickDelay);
                             _this._delayedSimpleClickTimeout = window.setTimeout(_this._delayedSimpleClick.bind(_this, btn, clickInfo, cb), Scene.DoubleClickDelay);
                         }
                         }
-                        var checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
-                            obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
+                        var checkDoubleClick = obs1.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP) ||
+                            obs2.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP);
                         if (!checkDoubleClick && BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                         if (!checkDoubleClick && BABYLON.ActionManager.HasSpecificTrigger(BABYLON.ActionManager.OnDoublePickTrigger)) {
                             act = _this._initActionManager(act, clickInfo);
                             act = _this._initActionManager(act, clickInfo);
                             if (act)
                             if (act)
@@ -17238,8 +17327,8 @@ var BABYLON;
                 _this._updatePointerPosition(evt);
                 _this._updatePointerPosition(evt);
                 // PreObservable support
                 // PreObservable support
                 if (_this.onPrePointerObservable.hasObservers()) {
                 if (_this.onPrePointerObservable.hasObservers()) {
-                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
-                    var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
+                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
+                    var pi = new BABYLON.PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     if (pi.skipOnPointerObservable) {
                     if (pi.skipOnPointerObservable) {
                         return;
                         return;
@@ -17292,8 +17381,8 @@ var BABYLON;
                     _this.onPointerMove(evt, pickResult);
                     _this.onPointerMove(evt, pickResult);
                 }
                 }
                 if (_this.onPointerObservable.hasObservers()) {
                 if (_this.onPointerObservable.hasObservers()) {
-                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
-                    var pi = new PointerInfo(type, evt, pickResult);
+                    var type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? BABYLON.PointerEventTypes.POINTERWHEEL : BABYLON.PointerEventTypes.POINTERMOVE;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                     _this.onPointerObservable.notifyObservers(pi, type);
                     _this.onPointerObservable.notifyObservers(pi, type);
                 }
                 }
             };
             };
@@ -17304,8 +17393,8 @@ var BABYLON;
                 _this._updatePointerPosition(evt);
                 _this._updatePointerPosition(evt);
                 // PreObservable support
                 // PreObservable support
                 if (_this.onPrePointerObservable.hasObservers()) {
                 if (_this.onPrePointerObservable.hasObservers()) {
-                    var type = PointerEventTypes.POINTERDOWN;
-                    var pi = new PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
+                    var type = BABYLON.PointerEventTypes.POINTERDOWN;
+                    var pi = new BABYLON.PointerInfoPre(type, evt, _this._unTranslatedPointerX, _this._unTranslatedPointerY);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     _this.onPrePointerObservable.notifyObservers(pi, type);
                     if (pi.skipOnPointerObservable) {
                     if (pi.skipOnPointerObservable) {
                         return;
                         return;
@@ -17364,8 +17453,8 @@ var BABYLON;
                     _this.onPointerDown(evt, pickResult);
                     _this.onPointerDown(evt, pickResult);
                 }
                 }
                 if (_this.onPointerObservable.hasObservers()) {
                 if (_this.onPointerObservable.hasObservers()) {
-                    var type = PointerEventTypes.POINTERDOWN;
-                    var pi = new PointerInfo(type, evt, pickResult);
+                    var type = BABYLON.PointerEventTypes.POINTERDOWN;
+                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                     _this.onPointerObservable.notifyObservers(pi, type);
                     _this.onPointerObservable.notifyObservers(pi, type);
                 }
                 }
                 // Sprites
                 // Sprites
@@ -17403,17 +17492,17 @@ var BABYLON;
                     if (this.onPrePointerObservable.hasObservers()) {
                     if (this.onPrePointerObservable.hasObservers()) {
                         if (!clickInfo.ignore) {
                         if (!clickInfo.ignore) {
                             if (!clickInfo.hasSwiped) {
                             if (!clickInfo.hasSwiped) {
-                                if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                                    var type = PointerEventTypes.POINTERTAP;
-                                    var pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                                if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERTAP;
+                                    var pi = new BABYLON.PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     if (pi.skipOnPointerObservable) {
                                     if (pi.skipOnPointerObservable) {
                                         return;
                                         return;
                                     }
                                     }
                                 }
                                 }
-                                if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                                    var type = PointerEventTypes.POINTERDOUBLETAP;
-                                    var pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                                if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
+                                    var pi = new BABYLON.PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     this.onPrePointerObservable.notifyObservers(pi, type);
                                     if (pi.skipOnPointerObservable) {
                                     if (pi.skipOnPointerObservable) {
                                         return;
                                         return;
@@ -17422,8 +17511,8 @@ var BABYLON;
                             }
                             }
                         }
                         }
                         else {
                         else {
-                            var type = PointerEventTypes.POINTERUP;
-                            var pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
+                            var type = BABYLON.PointerEventTypes.POINTERUP;
+                            var pi = new BABYLON.PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
                             this.onPrePointerObservable.notifyObservers(pi, type);
                             this.onPrePointerObservable.notifyObservers(pi, type);
                             if (pi.skipOnPointerObservable) {
                             if (pi.skipOnPointerObservable) {
                                 return;
                                 return;
@@ -17452,8 +17541,8 @@ var BABYLON;
                                 this.onPointerPick(evt, pickResult);
                                 this.onPointerPick(evt, pickResult);
                             }
                             }
                             if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
                             if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
-                                var type = PointerEventTypes.POINTERPICK;
-                                var pi = new PointerInfo(type, evt, pickResult);
+                                var type = BABYLON.PointerEventTypes.POINTERPICK;
+                                var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                                 this.onPointerObservable.notifyObservers(pi, type);
                                 this.onPointerObservable.notifyObservers(pi, type);
                             }
                             }
                         }
                         }
@@ -17481,21 +17570,21 @@ var BABYLON;
                     if (this.onPointerObservable.hasObservers()) {
                     if (this.onPointerObservable.hasObservers()) {
                         if (!clickInfo.ignore) {
                         if (!clickInfo.ignore) {
                             if (!clickInfo.hasSwiped) {
                             if (!clickInfo.hasSwiped) {
-                                if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
-                                    var type = PointerEventTypes.POINTERTAP;
-                                    var pi = new PointerInfo(type, evt, pickResult);
+                                if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERTAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERTAP;
+                                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                 }
                                 }
-                                if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
-                                    var type = PointerEventTypes.POINTERDOUBLETAP;
-                                    var pi = new PointerInfo(type, evt, pickResult);
+                                if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(BABYLON.PointerEventTypes.POINTERDOUBLETAP)) {
+                                    var type = BABYLON.PointerEventTypes.POINTERDOUBLETAP;
+                                    var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                     this.onPointerObservable.notifyObservers(pi, type);
                                 }
                                 }
                             }
                             }
                         }
                         }
                         else {
                         else {
-                            var type = PointerEventTypes.POINTERUP;
-                            var pi = new PointerInfo(type, evt, pickResult);
+                            var type = BABYLON.PointerEventTypes.POINTERUP;
+                            var pi = new BABYLON.PointerInfo(type, evt, pickResult);
                             this.onPointerObservable.notifyObservers(pi, type);
                             this.onPointerObservable.notifyObservers(pi, type);
                         }
                         }
                     }
                     }
@@ -17520,15 +17609,48 @@ var BABYLON;
                 }).bind(_this));
                 }).bind(_this));
             };
             };
             this._onKeyDown = function (evt) {
             this._onKeyDown = function (evt) {
+                var type = BABYLON.KeyboardEventTypes.KEYDOWN;
+                if (_this.onPreKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfoPre(type, evt);
+                    _this.onPreKeyboardObservable.notifyObservers(pi, type);
+                    if (pi.skipOnPointerObservable) {
+                        return;
+                    }
+                }
+                if (_this.onKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfo(type, evt);
+                    _this.onKeyboardObservable.notifyObservers(pi, type);
+                }
                 if (_this.actionManager) {
                 if (_this.actionManager) {
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyDownTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyDownTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                 }
                 }
             };
             };
             this._onKeyUp = function (evt) {
             this._onKeyUp = function (evt) {
+                var type = BABYLON.KeyboardEventTypes.KEYUP;
+                if (_this.onPreKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfoPre(type, evt);
+                    _this.onPreKeyboardObservable.notifyObservers(pi, type);
+                    if (pi.skipOnPointerObservable) {
+                        return;
+                    }
+                }
+                if (_this.onKeyboardObservable.hasObservers()) {
+                    var pi = new BABYLON.KeyboardInfo(type, evt);
+                    _this.onKeyboardObservable.notifyObservers(pi, type);
+                }
                 if (_this.actionManager) {
                 if (_this.actionManager) {
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyUpTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                     _this.actionManager.processTrigger(BABYLON.ActionManager.OnKeyUpTrigger, BABYLON.ActionEvent.CreateNewFromScene(_this, evt));
                 }
                 }
             };
             };
+            var engine = this.getEngine();
+            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(function () {
+                canvas.addEventListener("keydown", _this._onKeyDown, false);
+                canvas.addEventListener("keyup", _this._onKeyUp, false);
+            });
+            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(function () {
+                canvas.removeEventListener("keydown", _this._onKeyDown);
+                canvas.removeEventListener("keyup", _this._onKeyUp);
+            });
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
             var canvas = this._engine.getRenderingCanvas();
             var canvas = this._engine.getRenderingCanvas();
             if (attachMove) {
             if (attachMove) {
@@ -17544,20 +17666,27 @@ var BABYLON;
                 canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false);
                 canvas.addEventListener(eventPrefix + "up", this._onPointerUp, false);
             }
             }
             canvas.tabIndex = 1;
             canvas.tabIndex = 1;
-            canvas.addEventListener("keydown", this._onKeyDown, false);
-            canvas.addEventListener("keyup", this._onKeyUp, false);
         };
         };
         Scene.prototype.detachControl = function () {
         Scene.prototype.detachControl = function () {
+            var engine = this.getEngine();
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
             var eventPrefix = BABYLON.Tools.GetPointerPrefix();
-            var canvas = this._engine.getRenderingCanvas();
+            var canvas = engine.getRenderingCanvas();
             canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
             canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
             canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
             canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
             canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
             canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
+            engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+            engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
             // Wheel
             // Wheel
             canvas.removeEventListener('mousewheel', this._onPointerMove);
             canvas.removeEventListener('mousewheel', this._onPointerMove);
             canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
             canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
+            // Keyboard
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keyup", this._onKeyUp);
             canvas.removeEventListener("keyup", this._onKeyUp);
+            // Observables
+            this.onKeyboardObservable.clear();
+            this.onPreKeyboardObservable.clear();
+            this.onPointerObservable.clear();
+            this.onPrePointerObservable.clear();
         };
         };
         // Ready
         // Ready
         Scene.prototype.isReady = function () {
         Scene.prototype.isReady = function () {
@@ -31889,77 +32018,64 @@ var BABYLON;
         }
         }
         ArcRotateCameraKeyboardMoveInput.prototype.attachControl = function (element, noPreventDefault) {
         ArcRotateCameraKeyboardMoveInput.prototype.attachControl = function (element, noPreventDefault) {
             var _this = this;
             var _this = this;
-            element.tabIndex = 1;
-            this._onKeyDown = function (evt) {
-                _this._ctrlPressed = evt.ctrlKey;
-                if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = _this._keys.indexOf(evt.keyCode);
-                    if (index === -1) {
-                        _this._keys.push(evt.keyCode);
-                    }
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(function () {
+                _this._keys = [];
+            });
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(function (info) {
+                var evt = info.event;
+                if (info.type === BABYLON.KeyboardEventTypes.KEYDOWN) {
+                    _this._ctrlPressed = evt.ctrlKey;
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
+                        if (index === -1) {
+                            _this._keys.push(evt.keyCode);
+                        }
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
-            };
-            this._onKeyUp = function (evt) {
-                if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    _this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = _this._keys.indexOf(evt.keyCode);
-                    if (index >= 0) {
-                        _this._keys.splice(index, 1);
-                    }
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                else {
+                    if (_this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        _this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = _this._keys.indexOf(evt.keyCode);
+                        if (index >= 0) {
+                            _this._keys.splice(index, 1);
+                        }
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
-            };
-            this._onLostFocus = function () {
-                _this._keys = [];
-            };
-            this._onFocus = function () {
-                element.addEventListener("keydown", _this._onKeyDown, false);
-                element.addEventListener("keyup", _this._onKeyUp, false);
-            };
-            this._onBlur = function () {
-                element.removeEventListener("keydown", _this._onKeyDown);
-                element.removeEventListener("keyup", _this._onKeyUp);
-            };
-            element.addEventListener("focus", this._onFocus);
-            element.addEventListener("blur", this._onBlur);
-            BABYLON.Tools.RegisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            });
         };
         };
         ArcRotateCameraKeyboardMoveInput.prototype.detachControl = function (element) {
         ArcRotateCameraKeyboardMoveInput.prototype.detachControl = function (element) {
-            if (element && this._onBlur) {
-                this._onBlur();
-                element.removeEventListener("focus", this._onFocus);
-                element.removeEventListener("blur", this._onBlur);
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
-            BABYLON.Tools.UnregisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
             this._keys = [];
             this._keys = [];
-            this._onKeyDown = null;
-            this._onKeyUp = null;
-            this._onLostFocus = null;
-            this._onBlur = null;
-            this._onFocus = null;
         };
         };
         ArcRotateCameraKeyboardMoveInput.prototype.checkInputs = function () {
         ArcRotateCameraKeyboardMoveInput.prototype.checkInputs = function () {
-            if (this._onKeyDown) {
+            if (this._onKeyboardObserver) {
                 var camera = this.camera;
                 var camera = this.camera;
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {
                     var keyCode = this._keys[index];
                     var keyCode = this._keys[index];

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 8420 - 8373
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 2 - 2
dist/preview release/gui/babylon.gui.d.ts

@@ -6,7 +6,7 @@ declare module BABYLON.GUI {
         private _resizeObserver;
         private _resizeObserver;
         private _pointerMoveObserver;
         private _pointerMoveObserver;
         private _pointerObserver;
         private _pointerObserver;
-        private _canvasBlurObserver;
+        private _canvasPointerOutObserver;
         private _background;
         private _background;
         _rootContainer: Container;
         _rootContainer: Container;
         _lastControlOver: Control;
         _lastControlOver: Control;
@@ -39,7 +39,7 @@ declare module BABYLON.GUI {
         private _doPicking(x, y, type);
         private _doPicking(x, y, type);
         attach(): void;
         attach(): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
-        private _attachToOnBlur(scene);
+        private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
     }
     }

+ 6 - 6
dist/preview release/gui/babylon.gui.js

@@ -146,8 +146,8 @@ var BABYLON;
                 if (this._pointerObserver) {
                 if (this._pointerObserver) {
                     this.getScene().onPointerObservable.remove(this._pointerObserver);
                     this.getScene().onPointerObservable.remove(this._pointerObserver);
                 }
                 }
-                if (this._canvasBlurObserver) {
-                    this.getScene().getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
+                if (this._canvasPointerOutObserver) {
+                    this.getScene().getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
                 }
                 }
                 if (this._layerToDispose) {
                 if (this._layerToDispose) {
                     this._layerToDispose.texture = null;
                     this._layerToDispose.texture = null;
@@ -281,7 +281,7 @@ var BABYLON;
                     _this._doPicking(x, y, pi.type);
                     _this._doPicking(x, y, pi.type);
                     pi.skipOnPointerObservable = _this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
                     pi.skipOnPointerObservable = _this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
                 });
                 });
-                this._attachToOnBlur(scene);
+                this._attachToOnPointerOut(scene);
             };
             };
             AdvancedDynamicTexture.prototype.attachToMesh = function (mesh, supportPointerMove) {
             AdvancedDynamicTexture.prototype.attachToMesh = function (mesh, supportPointerMove) {
                 var _this = this;
                 var _this = this;
@@ -312,11 +312,11 @@ var BABYLON;
                     }
                     }
                 });
                 });
                 mesh.enablePointerMoveEvents = supportPointerMove;
                 mesh.enablePointerMoveEvents = supportPointerMove;
-                this._attachToOnBlur(scene);
+                this._attachToOnPointerOut(scene);
             };
             };
-            AdvancedDynamicTexture.prototype._attachToOnBlur = function (scene) {
+            AdvancedDynamicTexture.prototype._attachToOnPointerOut = function (scene) {
                 var _this = this;
                 var _this = this;
-                this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(function () {
+                this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(function () {
                     if (_this._lastControlOver) {
                     if (_this._lastControlOver) {
                         _this._lastControlOver._onPointerOut();
                         _this._lastControlOver._onPointerOut();
                     }
                     }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


+ 2 - 2
dist/preview release/gui/babylon.gui.module.d.ts

@@ -6,7 +6,7 @@ declare module BABYLON.GUI {
         private _resizeObserver;
         private _resizeObserver;
         private _pointerMoveObserver;
         private _pointerMoveObserver;
         private _pointerObserver;
         private _pointerObserver;
-        private _canvasBlurObserver;
+        private _canvasPointerOutObserver;
         private _background;
         private _background;
         _rootContainer: Container;
         _rootContainer: Container;
         _lastControlOver: Control;
         _lastControlOver: Control;
@@ -39,7 +39,7 @@ declare module BABYLON.GUI {
         private _doPicking(x, y, type);
         private _doPicking(x, y, type);
         attach(): void;
         attach(): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
         attachToMesh(mesh: AbstractMesh, supportPointerMove?: boolean): void;
-        private _attachToOnBlur(scene);
+        private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Scene): AdvancedDynamicTexture;
     }
     }

+ 7 - 7
gui/src/advancedDynamicTexture.ts

@@ -7,7 +7,7 @@ module BABYLON.GUI {
         private _resizeObserver: Observer<Engine>;
         private _resizeObserver: Observer<Engine>;
         private _pointerMoveObserver: Observer<PointerInfoPre>;
         private _pointerMoveObserver: Observer<PointerInfoPre>;
         private _pointerObserver: Observer<PointerInfo>;
         private _pointerObserver: Observer<PointerInfo>;
-        private _canvasBlurObserver: Observer<Engine>;
+        private _canvasPointerOutObserver: Observer<Engine>;
         private _background: string;
         private _background: string;
         public _rootContainer = new Container("root");
         public _rootContainer = new Container("root");
         public _lastControlOver: Control;
         public _lastControlOver: Control;
@@ -145,8 +145,8 @@ module BABYLON.GUI {
                 this.getScene().onPointerObservable.remove(this._pointerObserver);
                 this.getScene().onPointerObservable.remove(this._pointerObserver);
             }
             }
 
 
-            if (this._canvasBlurObserver) {
-                this.getScene().getEngine().onCanvasBlurObservable.remove(this._canvasBlurObserver);
+            if (this._canvasPointerOutObserver) {
+                this.getScene().getEngine().onCanvasPointerOutObservable.remove(this._canvasPointerOutObserver);
             }
             }
 
 
             if (this._layerToDispose) {
             if (this._layerToDispose) {
@@ -309,7 +309,7 @@ module BABYLON.GUI {
                 pi.skipOnPointerObservable = this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
                 pi.skipOnPointerObservable = this._shouldBlockPointer && pi.type !== BABYLON.PointerEventTypes.POINTERUP;
             });
             });
 
 
-            this._attachToOnBlur(scene);
+            this._attachToOnPointerOut(scene);
         }
         }
 
 
         public attachToMesh(mesh: AbstractMesh, supportPointerMove = true): void {
         public attachToMesh(mesh: AbstractMesh, supportPointerMove = true): void {
@@ -339,11 +339,11 @@ module BABYLON.GUI {
             });
             });
 
 
             mesh.enablePointerMoveEvents = supportPointerMove;
             mesh.enablePointerMoveEvents = supportPointerMove;
-            this._attachToOnBlur(scene);
+            this._attachToOnPointerOut(scene);
         }
         }
 
 
-        private _attachToOnBlur(scene: Scene): void {
-            this._canvasBlurObserver = scene.getEngine().onCanvasBlurObservable.add(() => {
+        private _attachToOnPointerOut(scene: Scene): void {
+            this._canvasPointerOutObserver = scene.getEngine().onCanvasPointerOutObservable.add(() => {
                 if (this._lastControlOver) {
                 if (this._lastControlOver) {
                     this._lastControlOver._onPointerOut();
                     this._lastControlOver._onPointerOut();
                 }            
                 }            

+ 57 - 78
src/Cameras/Inputs/babylon.arcRotateCameraKeyboardMoveInput.ts

@@ -2,11 +2,6 @@ module BABYLON {
     export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateCamera> {
     export class ArcRotateCameraKeyboardMoveInput implements ICameraInput<ArcRotateCamera> {
         camera: ArcRotateCamera;
         camera: ArcRotateCamera;
         private _keys = [];
         private _keys = [];
-        private _onKeyDown: (e: KeyboardEvent) => any;
-        private _onKeyUp: (e: KeyboardEvent) => any;
-        private _onLostFocus: (e: FocusEvent) => any;
-        private _onFocus: () => void;
-        private _onBlur: () => void;
         
         
         @serialize()
         @serialize()
         public keysUp = [38];
         public keysUp = [38];
@@ -27,97 +22,81 @@ module BABYLON {
         public panningSensibility: number = 50.0;        
         public panningSensibility: number = 50.0;        
 
 
         private _ctrlPressed: boolean;
         private _ctrlPressed: boolean;
+        private _onCanvasBlurObserver: Observer<Engine>;
+        private _onKeyboardObserver: Observer<KeyboardInfo>;
+        private _engine: Engine;
+        private _scene: Scene;
 
 
         public attachControl(element: HTMLElement, noPreventDefault?: boolean) {
         public attachControl(element: HTMLElement, noPreventDefault?: boolean) {
-            element.tabIndex = 1;
-
-            this._onKeyDown = evt => {
-
-                this._ctrlPressed = evt.ctrlKey;
-
-                if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = this._keys.indexOf(evt.keyCode);
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+            
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
 
 
-                    if (index === -1) {
-                        this._keys.push(evt.keyCode);
-                    }
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(()=>{
+                this._keys = [];
+            });
+
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(info => {
+                let evt = info.event;
+
+                if (info.type === KeyboardEventTypes.KEYDOWN) {
+                    this._ctrlPressed = evt.ctrlKey;
+                    
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+
+                        if (index === -1) {
+                            this._keys.push(evt.keyCode);
+                        }
 
 
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
-                }
-            };
-
-            this._onKeyUp = evt => {
-                
-                if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
-                    this.keysDown.indexOf(evt.keyCode) !== -1 ||
-                    this.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                    this.keysRight.indexOf(evt.keyCode) !== -1 ||
-                    this.keysReset.indexOf(evt.keyCode) !== -1) {
-                    var index = this._keys.indexOf(evt.keyCode);
-
-                    if (index >= 0) {
-                        this._keys.splice(index, 1);
-                    }
-
-                    if (evt.preventDefault) {
-                        if (!noPreventDefault) {
-                            evt.preventDefault();
+                } else {
+                    if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
+                        this.keysDown.indexOf(evt.keyCode) !== -1 ||
+                        this.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                        this.keysRight.indexOf(evt.keyCode) !== -1 ||
+                        this.keysReset.indexOf(evt.keyCode) !== -1) {
+                        var index = this._keys.indexOf(evt.keyCode);
+    
+                        if (index >= 0) {
+                            this._keys.splice(index, 1);
+                        }
+    
+                        if (evt.preventDefault) {
+                            if (!noPreventDefault) {
+                                evt.preventDefault();
+                            }
                         }
                         }
                     }
                     }
                 }
                 }
-            };
-
-            this._onLostFocus = () => {
-                this._keys = [];
-            };
-
-            this._onFocus = () => {
-                element.addEventListener("keydown", this._onKeyDown, false);
-                element.addEventListener("keyup", this._onKeyUp, false);   
-            }
-
-            this._onBlur = () => {
-                element.removeEventListener("keydown", this._onKeyDown);
-                element.removeEventListener("keyup", this._onKeyUp);
-            }
-
-            element.addEventListener("focus", this._onFocus);
-            element.addEventListener("blur", this._onBlur);
-
-            Tools.RegisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
+            });    
         }
         }
 
 
         public detachControl(element: HTMLElement) {
         public detachControl(element: HTMLElement) {
-            if (element && this._onBlur) {
-                this._onBlur();
-                element.removeEventListener("focus", this._onFocus);
-                element.removeEventListener("blur", this._onBlur);
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
 
 
-            Tools.UnregisterTopRootEvents([
-                { name: "blur", handler: this._onLostFocus }
-            ]);
-            
             this._keys = [];
             this._keys = [];
-            this._onKeyDown = null;
-            this._onKeyUp = null;
-            this._onLostFocus = null;
-            this._onBlur = null;
-            this._onFocus = null;
         }
         }
 
 
         public checkInputs() {
         public checkInputs() {
-            if (this._onKeyDown){
+            if (this._onKeyboardObserver){
                 var camera = this.camera;
                 var camera = this.camera;
 
 
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {

+ 28 - 28
src/Cameras/Inputs/babylon.freeCameraKeyboardMoveInput.ts

@@ -2,8 +2,10 @@ module BABYLON {
     export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
     export class FreeCameraKeyboardMoveInput implements ICameraInput<FreeCamera> {
         camera: FreeCamera;
         camera: FreeCamera;
         private _keys = [];
         private _keys = [];
-        private _onKeyDown: (e: KeyboardEvent) => any;
-        private _onKeyUp: (e: KeyboardEvent) => any;
+        private _onCanvasBlurObserver: Observer<Engine>;
+        private _onKeyboardObserver: Observer<KeyboardInfo>;
+        private _engine: Engine;
+        private _scene: Scene;        
 
 
         @serialize()
         @serialize()
         public keysUp = [38];
         public keysUp = [38];
@@ -18,10 +20,21 @@ module BABYLON {
         public keysRight = [39];
         public keysRight = [39];
 
 
         attachControl(element : HTMLElement, noPreventDefault?: boolean) {
         attachControl(element : HTMLElement, noPreventDefault?: boolean) {
-            if (!this._onKeyDown) {
-                element.tabIndex = 1;
+            if (this._onCanvasBlurObserver) {
+                return;
+            }
+
+            this._scene = this.camera.getScene();
+            this._engine = this._scene.getEngine();
+
+            this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(()=>{
+                this._keys = [];
+            });
 
 
-                this._onKeyDown = evt => {
+            this._onKeyboardObserver = this._scene.onKeyboardObservable.add(info => {
+                let evt = info.event;
+
+                if (info.type === KeyboardEventTypes.KEYDOWN) {
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
@@ -35,9 +48,7 @@ module BABYLON {
                             evt.preventDefault();
                             evt.preventDefault();
                         }
                         }
                     }
                     }
-                };
-
-                this._onKeyUp = evt => {
+                } else {
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                     if (this.keysUp.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysDown.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
                         this.keysLeft.indexOf(evt.keyCode) !== -1 ||
@@ -51,33 +62,22 @@ module BABYLON {
                             evt.preventDefault();
                             evt.preventDefault();
                         }
                         }
                     }
                     }
-                };
-
-                element.addEventListener("keydown", this._onKeyDown, false);
-                element.addEventListener("keyup", this._onKeyUp, false);
-
-                Tools.RegisterTopRootEvents([
-                    { name: "blur", handler: this._onLostFocus }
-                ]);
-            }
+                }
+            });     
         }
         }
 
 
         detachControl(element : HTMLElement) {
         detachControl(element : HTMLElement) {
-            if (this._onKeyDown) {
-                element.removeEventListener("keydown", this._onKeyDown);
-                element.removeEventListener("keyup", this._onKeyUp);
-
-                Tools.UnregisterTopRootEvents([
-                    { name: "blur", handler: this._onLostFocus }
-                ]);
-                this._keys = [];
-                this._onKeyDown = null;
-                this._onKeyUp = null;
+            if (this._scene) {
+                this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
+                this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+                this._onKeyboardObserver = null;
+                this._onCanvasBlurObserver = null;
             }
             }
+            this._keys = [];
         }
         }
         
         
         public checkInputs() {
         public checkInputs() {
-            if (this._onKeyDown){
+            if (this._onKeyboardObserver){
                 var camera = this.camera;
                 var camera = this.camera;
                 // Keyboard
                 // Keyboard
                 for (var index = 0; index < this._keys.length; index++) {
                 for (var index = 0; index < this._keys.length; index++) {

+ 33 - 0
src/Events/babylon.keyboardEvents.ts

@@ -0,0 +1,33 @@
+module BABYLON {
+    
+    export class KeyboardEventTypes {
+        static _KEYDOWN = 0x01;
+        static _KEYUP = 0x02;
+
+        public static get KEYDOWN(): number {
+            return KeyboardEventTypes._KEYDOWN;
+        }
+
+        public static get KEYUP(): number {
+            return KeyboardEventTypes._KEYUP;
+        }
+    }
+
+    export class KeyboardInfo {
+        constructor(public type: number, public event: KeyboardEvent) {
+        }
+    }
+
+    /**
+     * This class is used to store keyboard related info for the onPreKeyboardObservable event.
+     * Set the skipOnKeyboardObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onKeyboardObservable
+     */
+    export class KeyboardInfoPre extends KeyboardInfo {
+        constructor(type: number, event: KeyboardEvent) {
+            super(type, event);
+            this.skipOnPointerObservable = false;
+        }
+
+        public skipOnPointerObservable: boolean;
+    }   
+}

+ 69 - 0
src/Events/babylon.pointerEvents.ts

@@ -0,0 +1,69 @@
+module BABYLON {
+    export class PointerEventTypes {
+        static _POINTERDOWN = 0x01;
+        static _POINTERUP = 0x02;
+        static _POINTERMOVE = 0x04;
+        static _POINTERWHEEL = 0x08;
+        static _POINTERPICK = 0x10;
+        static _POINTERTAP = 0x20;
+        static _POINTERDOUBLETAP = 0x40;
+
+        public static get POINTERDOWN(): number {
+            return PointerEventTypes._POINTERDOWN;
+        }
+
+        public static get POINTERUP(): number {
+            return PointerEventTypes._POINTERUP;
+        }
+
+        public static get POINTERMOVE(): number {
+            return PointerEventTypes._POINTERMOVE;
+        }
+
+        public static get POINTERWHEEL(): number {
+            return PointerEventTypes._POINTERWHEEL;
+        }
+
+        public static get POINTERPICK(): number {
+            return PointerEventTypes._POINTERPICK;
+        }
+
+        public static get POINTERTAP(): number {
+            return PointerEventTypes._POINTERTAP;
+        }
+
+        public static get POINTERDOUBLETAP(): number {
+            return PointerEventTypes._POINTERDOUBLETAP;
+        }
+    }
+
+    export class PointerInfoBase {
+        constructor(public type: number, public event: PointerEvent | MouseWheelEvent) {
+        }
+    }
+
+    /**
+     * This class is used to store pointer related info for the onPrePointerObservable event.
+     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
+     */
+    export class PointerInfoPre extends PointerInfoBase {
+        constructor(type: number, event: PointerEvent | MouseWheelEvent, localX, localY) {
+            super(type, event);
+            this.skipOnPointerObservable = false;
+            this.localPosition = new Vector2(localX, localY);
+        }
+
+        public localPosition: Vector2;
+        public skipOnPointerObservable: boolean;
+    }
+
+    /**
+     * This type contains all the data related to a pointer event in Babylon.js.
+     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
+     */
+    export class PointerInfo extends PointerInfoBase {
+        constructor(type: number, event: PointerEvent | MouseWheelEvent, public pickInfo: PickingInfo) {
+            super(type, event);
+        }
+    }    
+}

+ 39 - 7
src/babylon.engine.ts

@@ -539,10 +539,20 @@
         public onResizeObservable = new Observable<Engine>();
         public onResizeObservable = new Observable<Engine>();
 
 
         /**
         /**
-         * Observable event triggered each time the canvas lost focus
+         * Observable event triggered each time the canvas loses focus
          */
          */
         public onCanvasBlurObservable = new Observable<Engine>();
         public onCanvasBlurObservable = new Observable<Engine>();
 
 
+        /**
+         * Observable event triggered each time the canvas gains focus
+         */
+        public onCanvasFocusObservable = new Observable<Engine>();        
+
+        /**
+         * Observable event triggered each time the canvas receives pointerout event
+         */
+        public onCanvasPointerOutObservable = new Observable<Engine>();
+
         //WebVR
         //WebVR
 
 
         //The new WebVR uses promises.
         //The new WebVR uses promises.
@@ -584,9 +594,14 @@
 
 
         public static audioEngine: AudioEngine;
         public static audioEngine: AudioEngine;
 
 
-        private _onCanvasBlur: () => void;
-        private _onBlur: () => void;
+        
+        // Focus
         private _onFocus: () => void;
         private _onFocus: () => void;
+        private _onBlur: () => void;       
+        private _onCanvasPointerOut: () => void;
+        private _onCanvasBlur: () => void;
+        private _onCanvasFocus: () => void;
+        
         private _onFullscreenChange: () => void;
         private _onFullscreenChange: () => void;
         private _onPointerLockChange: () => void;
         private _onPointerLockChange: () => void;
 
 
@@ -780,12 +795,24 @@
                 if (!this._gl) {
                 if (!this._gl) {
                     throw new Error("WebGL not supported");
                     throw new Error("WebGL not supported");
                 }
                 }
-
+    
+                this._onCanvasFocus = () => {
+                    this.onCanvasFocusObservable.notifyObservers(this);
+                }
+    
+                this._onCanvasBlur = () => {
+                    this.onCanvasBlurObservable.notifyObservers(this);
+                }
+    
+                canvas.addEventListener("focus", this._onCanvasFocus);
+                canvas.addEventListener("blur", this._onCanvasBlur);
+    
                 this._onBlur = () => {
                 this._onBlur = () => {
                     if (this.disablePerformanceMonitorInBackground) {
                     if (this.disablePerformanceMonitorInBackground) {
                         this._performanceMonitor.disable();
                         this._performanceMonitor.disable();
                     }
                     }
                     this._windowIsBackground = true;
                     this._windowIsBackground = true;
+                    this.onCanvasBlurObservable.notifyObservers(this);
                 };
                 };
 
 
                 this._onFocus = () => {
                 this._onFocus = () => {
@@ -793,16 +820,17 @@
                         this._performanceMonitor.enable();
                         this._performanceMonitor.enable();
                     }
                     }
                     this._windowIsBackground = false;
                     this._windowIsBackground = false;
+                    this.onCanvasFocusObservable.notifyObservers(this);
                 };
                 };
 
 
-                this._onCanvasBlur = () => {
-                    this.onCanvasBlurObservable.notifyObservers(this);
+                this._onCanvasPointerOut = () => {
+                    this.onCanvasPointerOutObservable.notifyObservers(this);
                 };
                 };
 
 
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("blur", this._onBlur);
                 window.addEventListener("focus", this._onFocus);
                 window.addEventListener("focus", this._onFocus);
 
 
-                canvas.addEventListener("pointerout", this._onCanvasBlur);
+                canvas.addEventListener("pointerout", this._onCanvasPointerOut);
             } else {
             } else {
                 this._gl = <WebGLRenderingContext>canvasOrContext;
                 this._gl = <WebGLRenderingContext>canvasOrContext;
                 this._renderingCanvas = this._gl.canvas
                 this._renderingCanvas = this._gl.canvas
@@ -4315,6 +4343,8 @@
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
+            this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
+            this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);            
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
 
 
             if (!this._doNotHandleContextLost) {
             if (!this._doNotHandleContextLost) {
@@ -4345,6 +4375,8 @@
 
 
             this.onResizeObservable.clear();
             this.onResizeObservable.clear();
             this.onCanvasBlurObservable.clear();
             this.onCanvasBlurObservable.clear();
+            this.onCanvasFocusObservable.clear();
+            this.onCanvasPointerOutObservable.clear();
 
 
             BABYLON.Effect.ResetCache();
             BABYLON.Effect.ResetCache();
         }
         }

+ 67 - 77
src/babylon.scene.ts

@@ -36,75 +36,6 @@
         }
         }
     }
     }
 
 
-    export class PointerEventTypes {
-        static _POINTERDOWN = 0x01;
-        static _POINTERUP = 0x02;
-        static _POINTERMOVE = 0x04;
-        static _POINTERWHEEL = 0x08;
-        static _POINTERPICK = 0x10;
-        static _POINTERTAP = 0x20;
-        static _POINTERDOUBLETAP = 0x40;
-
-        public static get POINTERDOWN(): number {
-            return PointerEventTypes._POINTERDOWN;
-        }
-
-        public static get POINTERUP(): number {
-            return PointerEventTypes._POINTERUP;
-        }
-
-        public static get POINTERMOVE(): number {
-            return PointerEventTypes._POINTERMOVE;
-        }
-
-        public static get POINTERWHEEL(): number {
-            return PointerEventTypes._POINTERWHEEL;
-        }
-
-        public static get POINTERPICK(): number {
-            return PointerEventTypes._POINTERPICK;
-        }
-
-        public static get POINTERTAP(): number {
-            return PointerEventTypes._POINTERTAP;
-        }
-
-        public static get POINTERDOUBLETAP(): number {
-            return PointerEventTypes._POINTERDOUBLETAP;
-        }
-    }
-
-    export class PointerInfoBase {
-        constructor(public type: number, public event: PointerEvent | MouseWheelEvent) {
-        }
-
-    }
-
-    /**
-     * This class is used to store pointer related info for the onPrePointerObservable event.
-     * Set the skipOnPointerObservable property to true if you want the engine to stop any process after this event is triggered, even not calling onPointerObservable
-     */
-    export class PointerInfoPre extends PointerInfoBase {
-        constructor(type: number, event: PointerEvent | MouseWheelEvent, localX, localY) {
-            super(type, event);
-            this.skipOnPointerObservable = false;
-            this.localPosition = new Vector2(localX, localY);
-        }
-
-        public localPosition: Vector2;
-        public skipOnPointerObservable: boolean;
-    }
-
-    /**
-     * This type contains all the data related to a pointer event in Babylon.js.
-     * The event member is an instance of PointerEvent for all types except PointerWheel and is of type MouseWheelEvent when type equals PointerWheel. The different event types can be found in the PointerEventTypes class.
-     */
-    export class PointerInfo extends PointerInfoBase {
-        constructor(type: number, event: PointerEvent | MouseWheelEvent, public pickInfo: PickingInfo) {
-            super(type, event);
-        }
-    }
-
     /**
     /**
      * This class is used by the onRenderingGroupObservable
      * This class is used by the onRenderingGroupObservable
      */
      */
@@ -434,8 +365,8 @@
         }
         }
 
 
         /**
         /**
-         * This observable event is triggered when any mouse event registered during Scene.attach() is called BEFORE the 3D engine to process anything (mesh/sprite picking for instance).
-         * You have the possibility to skip the 3D Engine process and the call to onPointerObservable by setting PointerInfoBase.skipOnPointerObservable to true
+         * 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).
+         * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
          */
          */
         public onPrePointerObservable = new Observable<PointerInfoPre>();
         public onPrePointerObservable = new Observable<PointerInfoPre>();
 
 
@@ -491,8 +422,21 @@
         public _mirroredCameraPosition: Vector3;
         public _mirroredCameraPosition: Vector3;
 
 
         // Keyboard
         // Keyboard
+
+        /**
+         * This observable event is triggered when any keyboard event si raised and registered during Scene.attachControl()
+         * You have the possibility to skip the process and the call to onKeyboardObservable by setting KeyboardInfoPre.skipOnPointerObservable to true
+         */
+        public onPreKeyboardObservable = new Observable<KeyboardInfoPre>();
+        
+        /**
+         * Observable event triggered each time an keyboard event is received from the hosting window
+         */
+        public onKeyboardObservable = new Observable<KeyboardInfo>();
         private _onKeyDown: (evt: Event) => void;
         private _onKeyDown: (evt: Event) => void;
         private _onKeyUp: (evt: Event) => void;
         private _onKeyUp: (evt: Event) => void;
+        private _onCanvasFocusObserver: Observer<Engine>;
+        private _onCanvasBlurObserver: Observer<Engine>;
 
 
         // Coordinate system
         // Coordinate system
         /**
         /**
@@ -1537,18 +1481,56 @@
                 }).bind(this));
                 }).bind(this));
             };
             };
 
 
-            this._onKeyDown = (evt: Event) => {
+            this._onKeyDown = (evt: KeyboardEvent) => {
+                let type = KeyboardEventTypes.KEYDOWN;
+                if (this.onPreKeyboardObservable.hasObservers()) {
+                    let pi = new KeyboardInfoPre(type, evt);
+                    this.onPreKeyboardObservable.notifyObservers(pi, type);
+                    if (pi.skipOnPointerObservable) {
+                        return;
+                    }
+                }
+
+                if (this.onKeyboardObservable.hasObservers()) {
+                    let pi = new KeyboardInfo(type, evt);
+                    this.onKeyboardObservable.notifyObservers(pi, type);
+                }
+
                 if (this.actionManager) {
                 if (this.actionManager) {
                     this.actionManager.processTrigger(ActionManager.OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
                     this.actionManager.processTrigger(ActionManager.OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
                 }
                 }
             };
             };
 
 
-            this._onKeyUp = (evt: Event) => {
+            this._onKeyUp = (evt: KeyboardEvent) => {
+                let type = KeyboardEventTypes.KEYUP;
+                if (this.onPreKeyboardObservable.hasObservers()) {
+                    let pi = new KeyboardInfoPre(type, evt);
+                    this.onPreKeyboardObservable.notifyObservers(pi, type);
+                    if (pi.skipOnPointerObservable) {
+                        return;
+                    }
+                }
+
+                if (this.onKeyboardObservable.hasObservers()) {
+                    let pi = new KeyboardInfo(type, evt);
+                    this.onKeyboardObservable.notifyObservers(pi, type);
+                }
+
                 if (this.actionManager) {
                 if (this.actionManager) {
                     this.actionManager.processTrigger(ActionManager.OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
                     this.actionManager.processTrigger(ActionManager.OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
                 }
                 }
             };
             };
 
 
+            let engine = this.getEngine();
+            this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(()=>{
+                canvas.addEventListener("keydown", this._onKeyDown, false);
+                canvas.addEventListener("keyup", this._onKeyUp, false);   
+            });
+
+            this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(()=>{                
+                canvas.removeEventListener("keydown", this._onKeyDown);
+                canvas.removeEventListener("keyup", this._onKeyUp);
+            });
 
 
             var eventPrefix = Tools.GetPointerPrefix();
             var eventPrefix = Tools.GetPointerPrefix();
             var canvas = this._engine.getRenderingCanvas();
             var canvas = this._engine.getRenderingCanvas();
@@ -1568,25 +1550,33 @@
             }
             }
 
 
             canvas.tabIndex = 1;
             canvas.tabIndex = 1;
-
-            canvas.addEventListener("keydown", this._onKeyDown, false);
-            canvas.addEventListener("keyup", this._onKeyUp, false);
         }
         }
 
 
         public detachControl() {
         public detachControl() {
+            let engine = this.getEngine();
             var eventPrefix = Tools.GetPointerPrefix();
             var eventPrefix = Tools.GetPointerPrefix();
-            var canvas = this._engine.getRenderingCanvas();
+            var canvas = engine.getRenderingCanvas();
 
 
             canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
             canvas.removeEventListener(eventPrefix + "move", this._onPointerMove);
             canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
             canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
             canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
             canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
 
 
+            engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
+            engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
+
             // Wheel
             // Wheel
             canvas.removeEventListener('mousewheel', this._onPointerMove);
             canvas.removeEventListener('mousewheel', this._onPointerMove);
             canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
             canvas.removeEventListener('DOMMouseScroll', this._onPointerMove);
 
 
+            // Keyboard
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keydown", this._onKeyDown);
             canvas.removeEventListener("keyup", this._onKeyUp);
             canvas.removeEventListener("keyup", this._onKeyUp);
+
+            // Observables
+            this.onKeyboardObservable.clear();
+            this.onPreKeyboardObservable.clear();
+            this.onPointerObservable.clear();
+            this.onPrePointerObservable.clear();     
         }
         }
 
 
         // Ready
         // Ready