UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

145 lines 8.53 kB
import { PointerEventTypes } from "../Events/pointerEvents.js"; import { KeyboardEventTypes } from "../Events/keyboardEvents.js"; import { Observable } from "../Misc/observable.js"; import { _IsMacPlatform } from "./utils.js"; /** * This class is responsible for coordinating the events that are triggered in the scene. * It registers all observers needed to track certain events and triggers the blocks that are listening to them. * Abstracting the events from the class will allow us to easily change the events that are being listened to, and trigger them in any order. */ export class FlowGraphSceneEventCoordinator { constructor(scene) { /** * register to this observable to get flow graph event notifications. */ this.onEventTriggeredObservable = new Observable(); /** * Was scene-ready already triggered? */ this.sceneReadyTriggered = false; this._pointerUnderMeshState = {}; this._onBlurHandler = null; /** * The set of keys currently pressed, keyed by `event.code`. * Keyboard event blocks use this to determine whether a key is held. * * In addition to physical key codes, a virtual `"CommandOrControl"` entry * is maintained: it tracks Meta (Cmd) on macOS and Ctrl on Windows/Linux, * enabling platform-agnostic shortcut checks via the IsKeyPressed block. */ this.pressedKeys = new Set(); this._startingTime = 0; this._scene = scene; this._initialize(); } _initialize() { this._sceneReadyObserver = this._scene.onReadyObservable.addOnce(() => { if (!this.sceneReadyTriggered) { this.onEventTriggeredObservable.notifyObservers({ type: "SceneReady" /* FlowGraphEventType.SceneReady */ }); this.sceneReadyTriggered = true; } }); this._sceneDisposeObserver = this._scene.onDisposeObservable.add(() => { this.onEventTriggeredObservable.notifyObservers({ type: "SceneDispose" /* FlowGraphEventType.SceneDispose */ }); }); this._sceneOnBeforeRenderObserver = this._scene.onBeforeRenderObservable.add(() => { const deltaTime = this._scene.getEngine().getDeltaTime() / 1000; // set in seconds this.onEventTriggeredObservable.notifyObservers({ type: "SceneBeforeRender" /* FlowGraphEventType.SceneBeforeRender */, payload: { timeSinceStart: this._startingTime, deltaTime, }, }); this._startingTime += deltaTime; }); this._meshPickedObserver = this._scene.onPointerObservable.add((pointerInfo) => { this.onEventTriggeredObservable.notifyObservers({ type: "MeshPick" /* FlowGraphEventType.MeshPick */, payload: pointerInfo }); }, PointerEventTypes.POINTERPICK); // should it be pointerdown? this._pointerDownObserver = this._scene.onPointerObservable.add((pointerInfo) => { this.onEventTriggeredObservable.notifyObservers({ type: "PointerDown" /* FlowGraphEventType.PointerDown */, payload: pointerInfo }); }, PointerEventTypes.POINTERDOWN); this._pointerUpObserver = this._scene.onPointerObservable.add((pointerInfo) => { this.onEventTriggeredObservable.notifyObservers({ type: "PointerUp" /* FlowGraphEventType.PointerUp */, payload: pointerInfo }); }, PointerEventTypes.POINTERUP); this._pointerMoveObserver = this._scene.onPointerObservable.add((pointerInfo) => { this.onEventTriggeredObservable.notifyObservers({ type: "PointerMove" /* FlowGraphEventType.PointerMove */, payload: pointerInfo }); }, PointerEventTypes.POINTERMOVE); this._meshUnderPointerObserver = this._scene.onMeshUnderPointerUpdatedObservable.add((data) => { // check if the data has changed. Check the state of the last change and see if it is a mesh or null. // if it is a mesh and the previous state was null, trigger over event. If it is null and the previous state was a mesh, trigger out event. // if it is a mesh and the previous state was a mesh, trigger out from the old mesh and over the new mesh // if it is null and the previous state was null, do nothing. const pointerId = data.pointerId; const mesh = data.mesh; const previousState = this._pointerUnderMeshState[pointerId]; if (!previousState && mesh) { this.onEventTriggeredObservable.notifyObservers({ type: "PointerOver" /* FlowGraphEventType.PointerOver */, payload: { pointerId, mesh } }); } else if (previousState && !mesh) { this.onEventTriggeredObservable.notifyObservers({ type: "PointerOut" /* FlowGraphEventType.PointerOut */, payload: { pointerId, mesh: previousState } }); } else if (previousState && mesh && previousState !== mesh) { this.onEventTriggeredObservable.notifyObservers({ type: "PointerOut" /* FlowGraphEventType.PointerOut */, payload: { pointerId, mesh: previousState, over: mesh } }); this.onEventTriggeredObservable.notifyObservers({ type: "PointerOver" /* FlowGraphEventType.PointerOver */, payload: { pointerId, mesh, out: previousState } }); } this._pointerUnderMeshState[pointerId] = mesh; }, PointerEventTypes.POINTERMOVE); this._keyDownObserver = this._scene.onKeyboardObservable.add((keyboardInfo) => { const code = keyboardInfo.event.code; this.pressedKeys.add(code); if (FlowGraphSceneEventCoordinator._COMMAND_OR_CTRL_CODES.has(code)) { this.pressedKeys.add("CommandOrControl"); } this.onEventTriggeredObservable.notifyObservers({ type: "KeyDown" /* FlowGraphEventType.KeyDown */, payload: keyboardInfo }); }, KeyboardEventTypes.KEYDOWN); this._keyUpObserver = this._scene.onKeyboardObservable.add((keyboardInfo) => { const code = keyboardInfo.event.code; this.pressedKeys.delete(code); if (FlowGraphSceneEventCoordinator._COMMAND_OR_CTRL_CODES.has(code)) { // Only remove CommandOrControl if neither left nor right is still held let stillHeld = false; for (const c of Array.from(FlowGraphSceneEventCoordinator._COMMAND_OR_CTRL_CODES)) { if (c !== code && this.pressedKeys.has(c)) { stillHeld = true; break; } } if (!stillHeld) { this.pressedKeys.delete("CommandOrControl"); } } this.onEventTriggeredObservable.notifyObservers({ type: "KeyUp" /* FlowGraphEventType.KeyUp */, payload: keyboardInfo }); }, KeyboardEventTypes.KEYUP); // Clear all tracked keys when the window/tab loses focus. // Without this, held keys would appear "stuck" after an Alt-Tab // because the keyup event fires in the other window. const canvas = this._scene.getEngine().getRenderingCanvas(); if (canvas) { this._onBlurHandler = () => this.pressedKeys.clear(); canvas.addEventListener("blur", this._onBlurHandler); } } dispose() { this._sceneDisposeObserver?.remove(); this._sceneReadyObserver?.remove(); this._sceneOnBeforeRenderObserver?.remove(); this._meshPickedObserver?.remove(); this._meshUnderPointerObserver?.remove(); this._pointerDownObserver?.remove(); this._pointerUpObserver?.remove(); this._pointerMoveObserver?.remove(); this._keyDownObserver?.remove(); this._keyUpObserver?.remove(); if (this._onBlurHandler) { const canvas = this._scene.getEngine().getRenderingCanvas(); canvas?.removeEventListener("blur", this._onBlurHandler); this._onBlurHandler = null; } this.pressedKeys.clear(); this.onEventTriggeredObservable.clear(); } } /** The physical key codes that map to the virtual CommandOrControl key on this platform. */ FlowGraphSceneEventCoordinator._COMMAND_OR_CTRL_CODES = _IsMacPlatform ? new Set(["MetaLeft", "MetaRight"]) : new Set(["ControlLeft", "ControlRight"]); //# sourceMappingURL=flowGraphSceneEventCoordinator.js.map