|
@@ -29,7 +29,7 @@ import { Light } from "./Lights/light";
|
|
|
import { PickingInfo } from "./Collisions/pickingInfo";
|
|
|
import { ICollisionCoordinator } from "./Collisions/collisionCoordinator";
|
|
|
import { PointerEventTypes, PointerInfoPre, PointerInfo } from "./Events/pointerEvents";
|
|
|
-import { KeyboardInfoPre, KeyboardInfo, KeyboardEventTypes } from "./Events/keyboardEvents";
|
|
|
+import { KeyboardInfoPre, KeyboardInfo } from "./Events/keyboardEvents";
|
|
|
import { ActionEvent } from "./Actions/actionEvent";
|
|
|
import { PostProcess } from "./PostProcesses/postProcess";
|
|
|
import { PostProcessManager } from "./PostProcesses/postProcessManager";
|
|
@@ -46,6 +46,7 @@ import { EngineStore } from "./Engines/engineStore";
|
|
|
import { AbstractActionManager } from './Actions/abstractActionManager';
|
|
|
import { _DevTools } from './Misc/devTools';
|
|
|
import { WebRequest } from './Misc/webRequest';
|
|
|
+import { InputManager } from './Inputs/scene.inputManager';
|
|
|
|
|
|
declare type Ray = import("./Culling/ray").Ray;
|
|
|
declare type TrianglePickingPredicate = import("./Culling/ray").TrianglePickingPredicate;
|
|
@@ -65,40 +66,6 @@ export interface IDisposable {
|
|
|
dispose(): void;
|
|
|
}
|
|
|
|
|
|
-/** @hidden */
|
|
|
-class ClickInfo {
|
|
|
- private _singleClick = false;
|
|
|
- private _doubleClick = false;
|
|
|
- private _hasSwiped = false;
|
|
|
- private _ignore = false;
|
|
|
-
|
|
|
- public get singleClick(): boolean {
|
|
|
- return this._singleClick;
|
|
|
- }
|
|
|
- public get doubleClick(): boolean {
|
|
|
- return this._doubleClick;
|
|
|
- }
|
|
|
- public get hasSwiped(): boolean {
|
|
|
- return this._hasSwiped;
|
|
|
- }
|
|
|
- public get ignore(): boolean {
|
|
|
- return this._ignore;
|
|
|
- }
|
|
|
-
|
|
|
- public set singleClick(b: boolean) {
|
|
|
- this._singleClick = b;
|
|
|
- }
|
|
|
- public set doubleClick(b: boolean) {
|
|
|
- this._doubleClick = b;
|
|
|
- }
|
|
|
- public set hasSwiped(b: boolean) {
|
|
|
- this._hasSwiped = b;
|
|
|
- }
|
|
|
- public set ignore(b: boolean) {
|
|
|
- this._ignore = b;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/** Interface defining initialization parameters for Scene class */
|
|
|
export interface SceneOptions {
|
|
|
/**
|
|
@@ -169,6 +136,12 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
// Members
|
|
|
|
|
|
/** @hidden */
|
|
|
+ public _inputManager = new InputManager(this);
|
|
|
+
|
|
|
+ /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
|
|
|
+ public cameraToUseForPointers: Nullable<Camera> = null;
|
|
|
+
|
|
|
+ /** @hidden */
|
|
|
public readonly _isScene = true;
|
|
|
|
|
|
/**
|
|
@@ -634,9 +607,6 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* Gets or sets a predicate used to select candidate meshes for a pointer move event
|
|
|
*/
|
|
|
public pointerMovePredicate: (Mesh: AbstractMesh) => boolean;
|
|
|
- private _onPointerMove: (evt: PointerEvent) => void;
|
|
|
- private _onPointerDown: (evt: PointerEvent) => void;
|
|
|
- private _onPointerUp: (evt: PointerEvent) => void;
|
|
|
|
|
|
/** Callback called when a pointer move is detected */
|
|
|
public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
|
|
@@ -662,47 +632,50 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* Gets the pointer coordinates without any translation (ie. straight out of the pointer event)
|
|
|
*/
|
|
|
public get unTranslatedPointer(): Vector2 {
|
|
|
- return new Vector2(this._unTranslatedPointerX, this._unTranslatedPointerY);
|
|
|
+ return this._inputManager.unTranslatedPointer;
|
|
|
}
|
|
|
|
|
|
- /** The distance in pixel that you have to move to prevent some events */
|
|
|
- public static DragMovementThreshold = 10; // in pixels
|
|
|
- /** Time in milliseconds to wait to raise long press events if button is still pressed */
|
|
|
- public static LongPressDelay = 500; // in milliseconds
|
|
|
- /** Time in milliseconds with two consecutive clicks will be considered as a double click */
|
|
|
- public static DoubleClickDelay = 300; // in milliseconds
|
|
|
- /** If you need to check double click without raising a single click at first click, enable this flag */
|
|
|
- public static ExclusiveDoubleClickMode = false;
|
|
|
+ /**
|
|
|
+ * Gets or sets the distance in pixel that you have to move to prevent some events. Default is 10 pixels
|
|
|
+ */
|
|
|
+ public static get DragMovementThreshold() {
|
|
|
+ return InputManager.DragMovementThreshold;
|
|
|
+ }
|
|
|
|
|
|
- private _initClickEvent: (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
|
|
|
- private _initActionManager: (act: Nullable<AbstractActionManager>, clickInfo: ClickInfo) => Nullable<AbstractActionManager>;
|
|
|
- private _delayedSimpleClick: (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void) => void;
|
|
|
- private _delayedSimpleClickTimeout: number;
|
|
|
- private _previousDelayedSimpleClickTimeout: number;
|
|
|
- private _meshPickProceed = false;
|
|
|
+ public static set DragMovementThreshold(value: number) {
|
|
|
+ InputManager.DragMovementThreshold = value;
|
|
|
+ }
|
|
|
|
|
|
- private _previousButtonPressed: number;
|
|
|
- private _currentPickResult: Nullable<PickingInfo> = null;
|
|
|
- private _previousPickResult: Nullable<PickingInfo> = null;
|
|
|
- private _totalPointersPressed = 0;
|
|
|
- private _doubleClickOccured = false;
|
|
|
+ /**
|
|
|
+ * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 500 ms
|
|
|
+ */
|
|
|
+ public static get LongPressDelay() {
|
|
|
+ return InputManager.LongPressDelay;
|
|
|
+ }
|
|
|
|
|
|
- /** Define this parameter if you are using multiple cameras and you want to specify which one should be used for pointer position */
|
|
|
- public cameraToUseForPointers: Nullable<Camera> = null;
|
|
|
- private _pointerX: number = 0;
|
|
|
- private _pointerY: number = 0;
|
|
|
- private _unTranslatedPointerX: number;
|
|
|
- private _unTranslatedPointerY: number;
|
|
|
- private _startingPointerPosition = new Vector2(0, 0);
|
|
|
- private _previousStartingPointerPosition = new Vector2(0, 0);
|
|
|
- private _startingPointerTime = 0;
|
|
|
- private _previousStartingPointerTime = 0;
|
|
|
- private _pointerCaptures: { [pointerId: number]: boolean } = {};
|
|
|
+ public static set LongPressDelay(value: number) {
|
|
|
+ InputManager.LongPressDelay = value;
|
|
|
+ }
|
|
|
|
|
|
- // Deterministic lockstep
|
|
|
- private _timeAccumulator: number = 0;
|
|
|
- private _currentStepId: number = 0;
|
|
|
- private _currentInternalStep: number = 0;
|
|
|
+ /**
|
|
|
+ * Time in milliseconds to wait to raise long press events if button is still pressed. Default is 300 ms
|
|
|
+ */
|
|
|
+ public static get DoubleClickDelay() {
|
|
|
+ return InputManager.DoubleClickDelay;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static set DoubleClickDelay(value: number) {
|
|
|
+ InputManager.DoubleClickDelay = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** If you need to check double click without raising a single click at first click, enable this flag */
|
|
|
+ public static get ExclusiveDoubleClickMode() {
|
|
|
+ return InputManager.ExclusiveDoubleClickMode;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static set ExclusiveDoubleClickMode(value: boolean) {
|
|
|
+ InputManager.ExclusiveDoubleClickMode = value;
|
|
|
+ }
|
|
|
|
|
|
// Mirror
|
|
|
/** @hidden */
|
|
@@ -720,10 +693,6 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* Observable event triggered each time an keyboard event is received from the hosting window
|
|
|
*/
|
|
|
public onKeyboardObservable = new Observable<KeyboardInfo>();
|
|
|
- private _onKeyDown: (evt: KeyboardEvent) => void;
|
|
|
- private _onKeyUp: (evt: KeyboardEvent) => void;
|
|
|
- private _onCanvasFocusObserver: Nullable<Observer<Engine>>;
|
|
|
- private _onCanvasBlurObserver: Nullable<Observer<Engine>>;
|
|
|
|
|
|
// Coordinates system
|
|
|
|
|
@@ -742,6 +711,11 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
return this._useRightHandedSystem;
|
|
|
}
|
|
|
|
|
|
+ // Deterministic lockstep
|
|
|
+ private _timeAccumulator: number = 0;
|
|
|
+ private _currentStepId: number = 0;
|
|
|
+ private _currentInternalStep: number = 0;
|
|
|
+
|
|
|
/**
|
|
|
* Sets the step Id used by deterministic lock step
|
|
|
* @see http://doc.babylonjs.com/babylon101/animations#deterministic-lockstep
|
|
@@ -1119,7 +1093,6 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
/** @hidden */
|
|
|
public _viewMatrix: Matrix;
|
|
|
private _projectionMatrix: Matrix;
|
|
|
- private _wheelEventName = "";
|
|
|
/** @hidden */
|
|
|
public _forcedViewPosition: Nullable<Vector3>;
|
|
|
|
|
@@ -1143,10 +1116,6 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
/** @hidden */
|
|
|
public readonly useClonedMeshhMap: boolean;
|
|
|
|
|
|
- private _pointerOverMesh: Nullable<AbstractMesh>;
|
|
|
-
|
|
|
- private _pickedDownMesh: Nullable<AbstractMesh>;
|
|
|
- private _pickedUpMesh: Nullable<AbstractMesh>;
|
|
|
private _externalData: StringDictionary<Object>;
|
|
|
private _uid: Nullable<string>;
|
|
|
|
|
@@ -1418,29 +1387,29 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* Gets the mesh that is currently under the pointer
|
|
|
*/
|
|
|
public get meshUnderPointer(): Nullable<AbstractMesh> {
|
|
|
- return this._pointerOverMesh;
|
|
|
+ return this._inputManager.meshUnderPointer;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Gets or sets the current on-screen X position of the pointer
|
|
|
*/
|
|
|
public get pointerX(): number {
|
|
|
- return this._pointerX;
|
|
|
+ return this._inputManager.pointerX;
|
|
|
}
|
|
|
|
|
|
public set pointerX(value: number) {
|
|
|
- this._pointerX = value;
|
|
|
+ this._inputManager.pointerX = value;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Gets or sets the current on-screen Y position of the pointer
|
|
|
*/
|
|
|
public get pointerY(): number {
|
|
|
- return this._pointerY;
|
|
|
+ return this._inputManager.pointerY;
|
|
|
}
|
|
|
|
|
|
public set pointerY(value: number) {
|
|
|
- this._pointerY = value;
|
|
|
+ this._inputManager.pointerY = value;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1587,35 +1556,12 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
this._renderId++;
|
|
|
}
|
|
|
|
|
|
- private _updatePointerPosition(evt: PointerEvent): void {
|
|
|
- var canvasRect = this._engine.getRenderingCanvasClientRect();
|
|
|
-
|
|
|
- if (!canvasRect) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this._pointerX = evt.clientX - canvasRect.left;
|
|
|
- this._pointerY = evt.clientY - canvasRect.top;
|
|
|
-
|
|
|
- this._unTranslatedPointerX = this._pointerX;
|
|
|
- this._unTranslatedPointerY = this._pointerY;
|
|
|
- }
|
|
|
-
|
|
|
private _createUbo(): void {
|
|
|
this._sceneUbo = new UniformBuffer(this._engine, undefined, true);
|
|
|
this._sceneUbo.addUniform("viewProjection", 16);
|
|
|
this._sceneUbo.addUniform("view", 16);
|
|
|
}
|
|
|
|
|
|
- // Pointers handling
|
|
|
- private _setRayOnPointerInfo(pointerInfo: PointerInfo) {
|
|
|
- if (pointerInfo.pickInfo && !pointerInfo.pickInfo._pickingUnavailable) {
|
|
|
- if (!pointerInfo.pickInfo.ray) {
|
|
|
- pointerInfo.pickInfo.ray = this.createPickingRay(pointerInfo.event.offsetX, pointerInfo.event.offsetY, Matrix.Identity(), this.activeCamera);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Use this method to simulate a pointer move on a mesh
|
|
|
* The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
|
|
@@ -1624,74 +1570,10 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @returns the current scene
|
|
|
*/
|
|
|
public simulatePointerMove(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene {
|
|
|
- let evt = new PointerEvent("pointermove", pointerEventInit);
|
|
|
-
|
|
|
- if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERMOVE)) {
|
|
|
- return this;
|
|
|
- }
|
|
|
- return this._processPointerMove(pickResult, evt);
|
|
|
- }
|
|
|
-
|
|
|
- private _processPointerMove(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
|
|
|
-
|
|
|
- var canvas = this._engine.getRenderingCanvas();
|
|
|
-
|
|
|
- if (!canvas) {
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- // Restore pointer
|
|
|
- canvas.style.cursor = this.defaultCursor;
|
|
|
-
|
|
|
- var isMeshPicked = (pickResult && pickResult.hit && pickResult.pickedMesh) ? true : false;
|
|
|
- if (isMeshPicked) {
|
|
|
- this.setPointerOverMesh(pickResult!.pickedMesh);
|
|
|
-
|
|
|
- if (this._pointerOverMesh && this._pointerOverMesh.actionManager && this._pointerOverMesh.actionManager.hasPointerTriggers) {
|
|
|
- if (this._pointerOverMesh.actionManager.hoverCursor) {
|
|
|
- canvas.style.cursor = this._pointerOverMesh.actionManager.hoverCursor;
|
|
|
- } else {
|
|
|
- canvas.style.cursor = this.hoverCursor;
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- this.setPointerOverMesh(null);
|
|
|
- }
|
|
|
-
|
|
|
- for (let step of this._pointerMoveStage) {
|
|
|
- pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, isMeshPicked, canvas);
|
|
|
- }
|
|
|
-
|
|
|
- if (pickResult) {
|
|
|
- let type = evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
|
|
|
-
|
|
|
- if (this.onPointerMove) {
|
|
|
- this.onPointerMove(evt, pickResult, type);
|
|
|
- }
|
|
|
-
|
|
|
- if (this.onPointerObservable.hasObservers()) {
|
|
|
- let pi = new PointerInfo(type, evt, pickResult);
|
|
|
- this._setRayOnPointerInfo(pi);
|
|
|
- this.onPointerObservable.notifyObservers(pi, type);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ this._inputManager.simulatePointerMove(pickResult, pointerEventInit);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- private _checkPrePointerObservable(pickResult: Nullable<PickingInfo>, evt: PointerEvent, type: number) {
|
|
|
- let pi = new PointerInfoPre(type, evt, this._unTranslatedPointerX, this._unTranslatedPointerY);
|
|
|
- if (pickResult) {
|
|
|
- pi.ray = pickResult.ray;
|
|
|
- }
|
|
|
- this.onPrePointerObservable.notifyObservers(pi, type);
|
|
|
- if (pi.skipOnPointerObservable) {
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Use this method to simulate a pointer down on a mesh
|
|
|
* The pickResult parameter can be obtained from a scene.pick or scene.pickWithRay
|
|
@@ -1700,73 +1582,7 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @returns the current scene
|
|
|
*/
|
|
|
public simulatePointerDown(pickResult: PickingInfo, pointerEventInit?: PointerEventInit): Scene {
|
|
|
- let evt = new PointerEvent("pointerdown", pointerEventInit);
|
|
|
-
|
|
|
- if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERDOWN)) {
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- return this._processPointerDown(pickResult, evt);
|
|
|
- }
|
|
|
-
|
|
|
- private _processPointerDown(pickResult: Nullable<PickingInfo>, evt: PointerEvent): Scene {
|
|
|
- if (pickResult && pickResult.hit && pickResult.pickedMesh) {
|
|
|
- this._pickedDownMesh = pickResult.pickedMesh;
|
|
|
- var actionManager = pickResult.pickedMesh.actionManager;
|
|
|
- if (actionManager) {
|
|
|
- if (actionManager.hasPickTriggers) {
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnPickDownTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- switch (evt.button) {
|
|
|
- case 0:
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnLeftPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnCenterPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnRightPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger)) {
|
|
|
- window.setTimeout(() => {
|
|
|
- var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY,
|
|
|
- (mesh: AbstractMesh): boolean => (<boolean>(mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.actionManager && mesh.actionManager.hasSpecificTrigger(Constants.ACTION_OnLongPressTrigger) && mesh == this._pickedDownMesh)),
|
|
|
- false, this.cameraToUseForPointers);
|
|
|
-
|
|
|
- if (pickResult && pickResult.hit && pickResult.pickedMesh && actionManager) {
|
|
|
- if (this._totalPointersPressed !== 0 &&
|
|
|
- ((Date.now() - this._startingPointerTime) > Scene.LongPressDelay) &&
|
|
|
- !this._isPointerSwiping()) {
|
|
|
- this._startingPointerTime = 0;
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnLongPressTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- }
|
|
|
- }
|
|
|
- }, Scene.LongPressDelay);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- for (let step of this._pointerDownStage) {
|
|
|
- pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (pickResult) {
|
|
|
- let type = PointerEventTypes.POINTERDOWN;
|
|
|
-
|
|
|
- if (this.onPointerDown) {
|
|
|
- this.onPointerDown(evt, pickResult, type);
|
|
|
- }
|
|
|
-
|
|
|
- if (this.onPointerObservable.hasObservers()) {
|
|
|
- let pi = new PointerInfo(type, evt, pickResult);
|
|
|
- this._setRayOnPointerInfo(pi);
|
|
|
- this.onPointerObservable.notifyObservers(pi, type);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ this._inputManager.simulatePointerDown(pickResult, pointerEventInit);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
@@ -1779,94 +1595,7 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @returns the current scene
|
|
|
*/
|
|
|
public simulatePointerUp(pickResult: PickingInfo, pointerEventInit?: PointerEventInit, doubleTap?: boolean): Scene {
|
|
|
- let evt = new PointerEvent("pointerup", pointerEventInit);
|
|
|
- let clickInfo = new ClickInfo();
|
|
|
-
|
|
|
- if (doubleTap) {
|
|
|
- clickInfo.doubleClick = true;
|
|
|
- } else {
|
|
|
- clickInfo.singleClick = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (this._checkPrePointerObservable(pickResult, evt, PointerEventTypes.POINTERUP)) {
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- return this._processPointerUp(pickResult, evt, clickInfo);
|
|
|
- }
|
|
|
-
|
|
|
- private _processPointerUp(pickResult: Nullable<PickingInfo>, evt: PointerEvent, clickInfo: ClickInfo): Scene {
|
|
|
- if (pickResult && pickResult && pickResult.pickedMesh) {
|
|
|
- this._pickedUpMesh = pickResult.pickedMesh;
|
|
|
- if (this._pickedDownMesh === this._pickedUpMesh) {
|
|
|
- if (this.onPointerPick) {
|
|
|
- this.onPointerPick(evt, pickResult);
|
|
|
- }
|
|
|
- if (clickInfo.singleClick && !clickInfo.ignore && this.onPointerObservable.hasObservers()) {
|
|
|
- let type = PointerEventTypes.POINTERPICK;
|
|
|
- let pi = new PointerInfo(type, evt, pickResult);
|
|
|
- this._setRayOnPointerInfo(pi);
|
|
|
- this.onPointerObservable.notifyObservers(pi, type);
|
|
|
- }
|
|
|
- }
|
|
|
- let actionManager = pickResult.pickedMesh._getActionManagerForTrigger();
|
|
|
- if (actionManager && !clickInfo.ignore) {
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnPickUpTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
-
|
|
|
- if (!clickInfo.hasSwiped && clickInfo.singleClick) {
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnPickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- }
|
|
|
-
|
|
|
- let doubleClickActionManager = pickResult.pickedMesh._getActionManagerForTrigger(Constants.ACTION_OnDoublePickTrigger);
|
|
|
- if (clickInfo.doubleClick && doubleClickActionManager) {
|
|
|
- doubleClickActionManager.processTrigger(Constants.ACTION_OnDoublePickTrigger, ActionEvent.CreateNew(pickResult.pickedMesh, evt));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else {
|
|
|
- if (!clickInfo.ignore) {
|
|
|
- for (let step of this._pointerUpStage) {
|
|
|
- pickResult = step.action(this._unTranslatedPointerX, this._unTranslatedPointerY, pickResult, evt);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (this._pickedDownMesh && this._pickedDownMesh !== this._pickedUpMesh) {
|
|
|
- let pickedDownActionManager = this._pickedDownMesh._getActionManagerForTrigger(Constants.ACTION_OnPickOutTrigger);
|
|
|
- if (pickedDownActionManager) {
|
|
|
- pickedDownActionManager.processTrigger(Constants.ACTION_OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let type = 0;
|
|
|
- if (this.onPointerObservable.hasObservers()) {
|
|
|
- if (!clickInfo.ignore && !clickInfo.hasSwiped) {
|
|
|
- if (clickInfo.singleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
|
|
|
- type = PointerEventTypes.POINTERTAP;
|
|
|
- }
|
|
|
- else if (clickInfo.doubleClick && this.onPointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
|
|
|
- type = PointerEventTypes.POINTERDOUBLETAP;
|
|
|
- }
|
|
|
- if (type) {
|
|
|
- let pi = new PointerInfo(type, evt, pickResult);
|
|
|
- this._setRayOnPointerInfo(pi);
|
|
|
- this.onPointerObservable.notifyObservers(pi, type);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!clickInfo.ignore) {
|
|
|
- type = PointerEventTypes.POINTERUP;
|
|
|
-
|
|
|
- let pi = new PointerInfo(type, evt, pickResult);
|
|
|
- this._setRayOnPointerInfo(pi);
|
|
|
- this.onPointerObservable.notifyObservers(pi, type);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (this.onPointerUp && !clickInfo.ignore) {
|
|
|
- this.onPointerUp(evt, pickResult, type);
|
|
|
- }
|
|
|
-
|
|
|
+ this._inputManager.simulatePointerUp(pickResult, pointerEventInit, doubleTap);
|
|
|
return this;
|
|
|
}
|
|
|
|
|
@@ -1876,13 +1605,7 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @returns true if the pointer was captured
|
|
|
*/
|
|
|
public isPointerCaptured(pointerId = 0): boolean {
|
|
|
- return this._pointerCaptures[pointerId];
|
|
|
- }
|
|
|
-
|
|
|
- /** @hidden */
|
|
|
- public _isPointerSwiping(): boolean {
|
|
|
- return Math.abs(this._startingPointerPosition.x - this._pointerX) > Scene.DragMovementThreshold ||
|
|
|
- Math.abs(this._startingPointerPosition.y - this._pointerY) > Scene.DragMovementThreshold;
|
|
|
+ return this._inputManager.isPointerCaptured(pointerId);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1892,393 +1615,12 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @param attachMove defines if you want to attach events to pointermove
|
|
|
*/
|
|
|
public attachControl(attachUp = true, attachDown = true, attachMove = true): void {
|
|
|
- this._initActionManager = (act: Nullable<AbstractActionManager>, clickInfo: ClickInfo): Nullable<AbstractActionManager> => {
|
|
|
- if (!this._meshPickProceed) {
|
|
|
- let pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
|
|
|
- this._currentPickResult = pickResult;
|
|
|
- if (pickResult) {
|
|
|
- act = (pickResult.hit && pickResult.pickedMesh) ? pickResult.pickedMesh._getActionManagerForTrigger() : null;
|
|
|
- }
|
|
|
- this._meshPickProceed = true;
|
|
|
- }
|
|
|
- return act;
|
|
|
- };
|
|
|
-
|
|
|
- this._delayedSimpleClick = (btn: number, clickInfo: ClickInfo, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void) => {
|
|
|
- // double click delay is over and that no double click has been raised since, or the 2 consecutive keys pressed are different
|
|
|
- if ((Date.now() - this._previousStartingPointerTime > Scene.DoubleClickDelay && !this._doubleClickOccured) ||
|
|
|
- btn !== this._previousButtonPressed) {
|
|
|
- this._doubleClickOccured = false;
|
|
|
- clickInfo.singleClick = true;
|
|
|
- clickInfo.ignore = false;
|
|
|
- cb(clickInfo, this._currentPickResult);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- this._initClickEvent = (obs1: Observable<PointerInfoPre>, obs2: Observable<PointerInfo>, evt: PointerEvent, cb: (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => void): void => {
|
|
|
- let clickInfo = new ClickInfo();
|
|
|
- this._currentPickResult = null;
|
|
|
- let act: Nullable<AbstractActionManager> = null;
|
|
|
-
|
|
|
- let 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);
|
|
|
- if (!checkPicking && AbstractActionManager) {
|
|
|
- act = this._initActionManager(act, clickInfo);
|
|
|
- if (act) {
|
|
|
- checkPicking = act.hasPickTriggers;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- let needToIgnoreNext = false;
|
|
|
-
|
|
|
- if (checkPicking) {
|
|
|
- let btn = evt.button;
|
|
|
- clickInfo.hasSwiped = this._isPointerSwiping();
|
|
|
-
|
|
|
- if (!clickInfo.hasSwiped) {
|
|
|
- let checkSingleClickImmediately = !Scene.ExclusiveDoubleClickMode;
|
|
|
-
|
|
|
- if (!checkSingleClickImmediately) {
|
|
|
- checkSingleClickImmediately = !obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) &&
|
|
|
- !obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
|
|
|
-
|
|
|
- if (checkSingleClickImmediately && !AbstractActionManager.HasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger)) {
|
|
|
- act = this._initActionManager(act, clickInfo);
|
|
|
- if (act) {
|
|
|
- checkSingleClickImmediately = !act.hasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (checkSingleClickImmediately) {
|
|
|
- // single click detected if double click delay is over or two different successive keys pressed without exclusive double click or no double click required
|
|
|
- if (Date.now() - this._previousStartingPointerTime > Scene.DoubleClickDelay ||
|
|
|
- btn !== this._previousButtonPressed) {
|
|
|
- clickInfo.singleClick = true;
|
|
|
- cb(clickInfo, this._currentPickResult);
|
|
|
- needToIgnoreNext = true;
|
|
|
- }
|
|
|
- }
|
|
|
- // at least one double click is required to be check and exclusive double click is enabled
|
|
|
- else {
|
|
|
- // wait that no double click has been raised during the double click delay
|
|
|
- this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
|
|
|
- this._delayedSimpleClickTimeout = window.setTimeout(this._delayedSimpleClick.bind(this, btn, clickInfo, cb), Scene.DoubleClickDelay);
|
|
|
- }
|
|
|
-
|
|
|
- let checkDoubleClick = obs1.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP) ||
|
|
|
- obs2.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP);
|
|
|
- if (!checkDoubleClick && AbstractActionManager.HasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger)) {
|
|
|
- act = this._initActionManager(act, clickInfo);
|
|
|
- if (act) {
|
|
|
- checkDoubleClick = act.hasSpecificTrigger(Constants.ACTION_OnDoublePickTrigger);
|
|
|
- }
|
|
|
- }
|
|
|
- if (checkDoubleClick) {
|
|
|
- // two successive keys pressed are equal, double click delay is not over and double click has not just occurred
|
|
|
- if (btn === this._previousButtonPressed &&
|
|
|
- Date.now() - this._previousStartingPointerTime < Scene.DoubleClickDelay &&
|
|
|
- !this._doubleClickOccured
|
|
|
- ) {
|
|
|
- // pointer has not moved for 2 clicks, it's a double click
|
|
|
- if (!clickInfo.hasSwiped &&
|
|
|
- !this._isPointerSwiping()) {
|
|
|
- this._previousStartingPointerTime = 0;
|
|
|
- this._doubleClickOccured = true;
|
|
|
- clickInfo.doubleClick = true;
|
|
|
- clickInfo.ignore = false;
|
|
|
- if (Scene.ExclusiveDoubleClickMode && this._previousDelayedSimpleClickTimeout) {
|
|
|
- clearTimeout(this._previousDelayedSimpleClickTimeout);
|
|
|
- }
|
|
|
- this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
|
|
|
- cb(clickInfo, this._currentPickResult);
|
|
|
- }
|
|
|
- // if the two successive clicks are too far, it's just two simple clicks
|
|
|
- else {
|
|
|
- this._doubleClickOccured = false;
|
|
|
- this._previousStartingPointerTime = this._startingPointerTime;
|
|
|
- this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
|
|
|
- this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
|
|
|
- this._previousButtonPressed = btn;
|
|
|
- if (Scene.ExclusiveDoubleClickMode) {
|
|
|
- if (this._previousDelayedSimpleClickTimeout) {
|
|
|
- clearTimeout(this._previousDelayedSimpleClickTimeout);
|
|
|
- }
|
|
|
- this._previousDelayedSimpleClickTimeout = this._delayedSimpleClickTimeout;
|
|
|
-
|
|
|
- cb(clickInfo, this._previousPickResult);
|
|
|
- }
|
|
|
- else {
|
|
|
- cb(clickInfo, this._currentPickResult);
|
|
|
- }
|
|
|
- }
|
|
|
- needToIgnoreNext = true;
|
|
|
- }
|
|
|
- // just the first click of the double has been raised
|
|
|
- else {
|
|
|
- this._doubleClickOccured = false;
|
|
|
- this._previousStartingPointerTime = this._startingPointerTime;
|
|
|
- this._previousStartingPointerPosition.x = this._startingPointerPosition.x;
|
|
|
- this._previousStartingPointerPosition.y = this._startingPointerPosition.y;
|
|
|
- this._previousButtonPressed = btn;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!needToIgnoreNext) {
|
|
|
- cb(clickInfo, this._currentPickResult);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- this._onPointerMove = (evt: PointerEvent) => {
|
|
|
-
|
|
|
- this._updatePointerPosition(evt);
|
|
|
-
|
|
|
- // PreObservable support
|
|
|
- if (this._checkPrePointerObservable(null, evt, evt.type === this._wheelEventName ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!this.cameraToUseForPointers && !this.activeCamera) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!this.pointerMovePredicate) {
|
|
|
- this.pointerMovePredicate = (mesh: AbstractMesh): boolean => (mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (mesh.enablePointerMoveEvents || this.constantlyUpdateMeshUnderPointer || (mesh.actionManager !== null && mesh.actionManager !== undefined)) && (!this.cameraToUseForPointers || (this.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0));
|
|
|
- }
|
|
|
-
|
|
|
- // Meshes
|
|
|
- var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerMovePredicate, false, this.cameraToUseForPointers);
|
|
|
-
|
|
|
- this._processPointerMove(pickResult, evt);
|
|
|
- };
|
|
|
-
|
|
|
- this._onPointerDown = (evt: PointerEvent) => {
|
|
|
- this._totalPointersPressed++;
|
|
|
- this._pickedDownMesh = null;
|
|
|
- this._meshPickProceed = false;
|
|
|
-
|
|
|
- this._updatePointerPosition(evt);
|
|
|
-
|
|
|
- if (this.preventDefaultOnPointerDown && canvas) {
|
|
|
- evt.preventDefault();
|
|
|
- canvas.focus();
|
|
|
- }
|
|
|
-
|
|
|
- this._startingPointerPosition.x = this._pointerX;
|
|
|
- this._startingPointerPosition.y = this._pointerY;
|
|
|
- this._startingPointerTime = Date.now();
|
|
|
-
|
|
|
- // PreObservable support
|
|
|
- if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERDOWN)) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!this.cameraToUseForPointers && !this.activeCamera) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this._pointerCaptures[evt.pointerId] = true;
|
|
|
-
|
|
|
- if (!this.pointerDownPredicate) {
|
|
|
- this.pointerDownPredicate = (mesh: AbstractMesh): boolean => {
|
|
|
- return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (!this.cameraToUseForPointers || (this.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- // Meshes
|
|
|
- this._pickedDownMesh = null;
|
|
|
- var pickResult = this.pick(this._unTranslatedPointerX, this._unTranslatedPointerY, this.pointerDownPredicate, false, this.cameraToUseForPointers);
|
|
|
-
|
|
|
- this._processPointerDown(pickResult, evt);
|
|
|
- };
|
|
|
-
|
|
|
- this._onPointerUp = (evt: PointerEvent) => {
|
|
|
- if (this._totalPointersPressed === 0) { // We are attaching the pointer up to windows because of a bug in FF
|
|
|
- return; // So we need to test it the pointer down was pressed before.
|
|
|
- }
|
|
|
-
|
|
|
- this._totalPointersPressed--;
|
|
|
- this._pickedUpMesh = null;
|
|
|
- this._meshPickProceed = false;
|
|
|
-
|
|
|
- this._updatePointerPosition(evt);
|
|
|
-
|
|
|
- if (this.preventDefaultOnPointerUp && canvas) {
|
|
|
- evt.preventDefault();
|
|
|
- canvas.focus();
|
|
|
- }
|
|
|
-
|
|
|
- this._initClickEvent(this.onPrePointerObservable, this.onPointerObservable, evt, (clickInfo: ClickInfo, pickResult: Nullable<PickingInfo>) => {
|
|
|
- // PreObservable support
|
|
|
- if (this.onPrePointerObservable.hasObservers()) {
|
|
|
- if (!clickInfo.ignore) {
|
|
|
- if (!clickInfo.hasSwiped) {
|
|
|
- if (clickInfo.singleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERTAP)) {
|
|
|
- if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERTAP)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- if (clickInfo.doubleClick && this.onPrePointerObservable.hasSpecificMask(PointerEventTypes.POINTERDOUBLETAP)) {
|
|
|
- if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERDOUBLETAP)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (this._checkPrePointerObservable(null, evt, PointerEventTypes.POINTERUP)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!this._pointerCaptures[evt.pointerId]) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- this._pointerCaptures[evt.pointerId] = false;
|
|
|
- if (!this.cameraToUseForPointers && !this.activeCamera) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!this.pointerUpPredicate) {
|
|
|
- this.pointerUpPredicate = (mesh: AbstractMesh): boolean => {
|
|
|
- return mesh.isPickable && mesh.isVisible && mesh.isReady() && mesh.isEnabled() && (!this.cameraToUseForPointers || (this.cameraToUseForPointers.layerMask & mesh.layerMask) !== 0);
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- // Meshes
|
|
|
- if (!this._meshPickProceed && (AbstractActionManager && AbstractActionManager.HasTriggers || this.onPointerObservable.hasObservers())) {
|
|
|
- this._initActionManager(null, clickInfo);
|
|
|
- }
|
|
|
- if (!pickResult) {
|
|
|
- pickResult = this._currentPickResult;
|
|
|
- }
|
|
|
-
|
|
|
- this._processPointerUp(pickResult, evt, clickInfo);
|
|
|
-
|
|
|
- this._previousPickResult = this._currentPickResult;
|
|
|
- });
|
|
|
- };
|
|
|
-
|
|
|
- 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) {
|
|
|
- this.actionManager.processTrigger(Constants.ACTION_OnKeyDownTrigger, ActionEvent.CreateNewFromScene(this, evt));
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- 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) {
|
|
|
- this.actionManager.processTrigger(Constants.ACTION_OnKeyUpTrigger, ActionEvent.CreateNewFromScene(this, evt));
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- let engine = this.getEngine();
|
|
|
- this._onCanvasFocusObserver = engine.onCanvasFocusObservable.add(() => {
|
|
|
- if (!canvas) {
|
|
|
- return;
|
|
|
- }
|
|
|
- canvas.addEventListener("keydown", this._onKeyDown, false);
|
|
|
- canvas.addEventListener("keyup", this._onKeyUp, false);
|
|
|
- });
|
|
|
-
|
|
|
- this._onCanvasBlurObserver = engine.onCanvasBlurObservable.add(() => {
|
|
|
- if (!canvas) {
|
|
|
- return;
|
|
|
- }
|
|
|
- canvas.removeEventListener("keydown", this._onKeyDown);
|
|
|
- canvas.removeEventListener("keyup", this._onKeyUp);
|
|
|
- });
|
|
|
-
|
|
|
- var eventPrefix = Tools.GetPointerPrefix();
|
|
|
- var canvas = this._engine.getRenderingCanvas();
|
|
|
-
|
|
|
- if (!canvas) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (attachMove) {
|
|
|
- canvas.addEventListener(eventPrefix + "move", <any>this._onPointerMove, false);
|
|
|
-
|
|
|
- // Wheel
|
|
|
- this._wheelEventName = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
|
|
|
- (<any>document).onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
|
|
|
- "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
|
|
|
-
|
|
|
- canvas.addEventListener(this._wheelEventName, <any>this._onPointerMove, false);
|
|
|
- }
|
|
|
-
|
|
|
- if (attachDown) {
|
|
|
- canvas.addEventListener(eventPrefix + "down", <any>this._onPointerDown, false);
|
|
|
- }
|
|
|
-
|
|
|
- if (attachUp) {
|
|
|
- window.addEventListener(eventPrefix + "up", <any>this._onPointerUp, false);
|
|
|
- }
|
|
|
-
|
|
|
- canvas.tabIndex = 1;
|
|
|
+ this._inputManager.attachControl(attachUp, attachDown, attachMove);
|
|
|
}
|
|
|
|
|
|
/** Detaches all event handlers*/
|
|
|
public detachControl() {
|
|
|
- let engine = this.getEngine();
|
|
|
- var eventPrefix = Tools.GetPointerPrefix();
|
|
|
- var canvas = engine.getRenderingCanvas();
|
|
|
-
|
|
|
- if (!canvas) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- canvas.removeEventListener(eventPrefix + "move", <any>this._onPointerMove);
|
|
|
- canvas.removeEventListener(eventPrefix + "down", <any>this._onPointerDown);
|
|
|
- window.removeEventListener(eventPrefix + "up", <any>this._onPointerUp);
|
|
|
-
|
|
|
- if (this._onCanvasBlurObserver) {
|
|
|
- engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
|
|
|
- }
|
|
|
-
|
|
|
- if (this._onCanvasFocusObserver) {
|
|
|
- engine.onCanvasFocusObservable.remove(this._onCanvasFocusObserver);
|
|
|
- }
|
|
|
-
|
|
|
- // Wheel
|
|
|
- canvas.removeEventListener(this._wheelEventName, <any>this._onPointerMove);
|
|
|
-
|
|
|
- // Keyboard
|
|
|
- canvas.removeEventListener("keydown", this._onKeyDown);
|
|
|
- canvas.removeEventListener("keyup", this._onKeyUp);
|
|
|
-
|
|
|
- // Cursor
|
|
|
- canvas.style.cursor = this.defaultCursor;
|
|
|
+ this._inputManager.detachControl();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -4875,25 +4217,7 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @param mesh defines the mesh to use
|
|
|
*/
|
|
|
public setPointerOverMesh(mesh: Nullable<AbstractMesh>): void {
|
|
|
- if (this._pointerOverMesh === mesh) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let actionManager: Nullable<AbstractActionManager>;
|
|
|
- if (this._pointerOverMesh) {
|
|
|
- actionManager = this._pointerOverMesh._getActionManagerForTrigger(Constants.ACTION_OnPointerOutTrigger);
|
|
|
- if (actionManager) {
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnPointerOutTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- this._pointerOverMesh = mesh;
|
|
|
- if (this._pointerOverMesh) {
|
|
|
- actionManager = this._pointerOverMesh._getActionManagerForTrigger(Constants.ACTION_OnPointerOverTrigger);
|
|
|
- if (actionManager) {
|
|
|
- actionManager.processTrigger(Constants.ACTION_OnPointerOverTrigger, ActionEvent.CreateNew(this._pointerOverMesh));
|
|
|
- }
|
|
|
- }
|
|
|
+ this._inputManager.setPointerOverMesh(mesh);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -4901,7 +4225,7 @@ export class Scene extends AbstractScene implements IAnimatable {
|
|
|
* @returns a Mesh or null if no mesh is under the pointer
|
|
|
*/
|
|
|
public getPointerOverMesh(): Nullable<AbstractMesh> {
|
|
|
- return this._pointerOverMesh;
|
|
|
+ return this._inputManager.getPointerOverMesh();
|
|
|
}
|
|
|
|
|
|
// Misc.
|