Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: optimization structure & support any type of input #1359

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
124 changes: 79 additions & 45 deletions packages/core/src/input/InputManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { PointerManager } from "./pointer/PointerManager";
import { PointerButton, _pointerBin2DecMap } from "./enums/PointerButton";
import { WheelManager } from "./wheel/WheelManager";
import { Vector3 } from "@oasis-engine/math";
import { IInput } from "./interface/IInput";
import { InputType } from "./enums/InputType";

/**
* InputManager manages device input such as mouse, touch, keyboard, etc.
Expand All @@ -14,34 +16,54 @@ export class InputManager {
private _engine: Engine;
/** Sometimes the input module will not be initialized, such as off-screen rendering. */
private _initialized: boolean = false;
private _wheelManager: WheelManager;
private _pointerManager: PointerManager;
private _keyboardManager: KeyboardManager;
private _inputInstances: IInput[] = new Array(InputType.length);

/**
* Pointer list.
*/
get pointers(): Readonly<Pointer[]> {
return this._initialized ? this._pointerManager._pointers : [];
const pointerManager = this.getInput<PointerManager>(InputType.Pointer);
return pointerManager ? pointerManager._pointers : [];
}

/**
* Whether to handle multi-pointer.
*/
get multiPointerEnabled(): boolean {
return this._initialized ? this._pointerManager._multiPointerEnabled : false;
const pointerManager = this.getInput<PointerManager>(InputType.Pointer);
return pointerManager ? pointerManager._multiPointerEnabled : false;
}

set multiPointerEnabled(enabled: boolean) {
this._initialized && (this._pointerManager._multiPointerEnabled = enabled);
const pointerManager = this.getInput<PointerManager>(InputType.Pointer);
pointerManager && (pointerManager._multiPointerEnabled = enabled);
}

/**
* Get the change of the scroll wheel on the x-axis.
* @returns Change value
*/
get wheelDelta(): Readonly<Vector3 | null> {
return this._initialized ? this._wheelManager._delta : null;
const wheelManager = this.getInput<WheelManager>(InputType.Wheel);
return wheelManager ? wheelManager._delta : null;
}

/**
* Get an instance of this input type.
* @param inputType - The type of this input
* @returns Instance of this input
*/
getInput<T>(inputType: InputType): T {
return this._inputInstances[inputType] as T;
}

/**
* Add an instance of an input type
* @param inputType - The type of this input
* @param input - An instance of this input type
*/
addInput(inputType: InputType, input: IInput): void {
this._inputInstances[inputType] = input;
}

/**
Expand All @@ -50,11 +72,12 @@ export class InputManager {
* @returns Whether the key is being held down
*/
isKeyHeldDown(key?: Keys): boolean {
if (this._initialized) {
const keyboardManager = this.getInput<KeyboardManager>(InputType.Keyboard);
if (keyboardManager) {
if (key === undefined) {
return this._keyboardManager._curFrameHeldDownList.length > 0;
return keyboardManager._curFrameHeldDownList.length > 0;
} else {
return this._keyboardManager._curHeldDownKeyToIndexMap[key] != null;
return keyboardManager._curHeldDownKeyToIndexMap[key] != null;
}
} else {
return false;
Expand All @@ -67,11 +90,12 @@ export class InputManager {
* @returns Whether the key starts to be pressed down during the current frame
*/
isKeyDown(key?: Keys): boolean {
if (this._initialized) {
const keyboardManager = this.getInput<KeyboardManager>(InputType.Keyboard);
if (keyboardManager) {
if (key === undefined) {
return this._keyboardManager._curFrameDownList.length > 0;
return keyboardManager._curFrameDownList.length > 0;
} else {
return this._keyboardManager._downKeyToFrameCountMap[key] === this._engine.time.frameCount;
return keyboardManager._downKeyToFrameCountMap[key] === this._engine.time._frameCount;
}
} else {
return false;
Expand All @@ -84,11 +108,12 @@ export class InputManager {
* @returns Whether the key is released during the current frame
*/
isKeyUp(key?: Keys): boolean {
if (this._initialized) {
const keyboardManager = this.getInput<KeyboardManager>(InputType.Keyboard);
if (keyboardManager) {
if (key === undefined) {
return this._keyboardManager._curFrameUpList.length > 0;
return keyboardManager._curFrameUpList.length > 0;
} else {
return this._keyboardManager._upKeyToFrameCountMap[key] === this._engine.time.frameCount;
return keyboardManager._upKeyToFrameCountMap[key] === this._engine.time._frameCount;
}
} else {
return false;
Expand All @@ -101,11 +126,12 @@ export class InputManager {
* @returns Whether the pointer is being held down
*/
isPointerHeldDown(pointerButton?: PointerButton): boolean {
if (this._initialized) {
const pointerManager = this.getInput<PointerManager>(InputType.Pointer);
if (pointerManager) {
if (pointerButton === undefined) {
return this._pointerManager._buttons !== 0;
return pointerManager._buttons !== 0;
} else {
return (this._pointerManager._buttons & pointerButton) !== 0;
return (pointerManager._buttons & pointerButton) !== 0;
}
} else {
return false;
Expand All @@ -118,11 +144,12 @@ export class InputManager {
* @returns Whether the pointer starts to be pressed down during the current frame
*/
isPointerDown(pointerButton?: PointerButton): boolean {
if (this._initialized) {
const pointerManager = this.getInput<PointerManager>(InputType.Pointer);
if (pointerManager) {
if (pointerButton === undefined) {
return this._pointerManager._downList.length > 0;
return pointerManager._downList.length > 0;
} else {
return this._pointerManager._downMap[_pointerBin2DecMap[pointerButton]] === this._engine.time.frameCount;
return pointerManager._downMap[_pointerBin2DecMap[pointerButton]] === this._engine.time._frameCount;
}
} else {
return false;
Expand All @@ -135,11 +162,12 @@ export class InputManager {
* @returns Whether the pointer is released during the current frame
*/
isPointerUp(pointerButton?: PointerButton): boolean {
if (this._initialized) {
const pointerManager = this.getInput<PointerManager>(InputType.Pointer);
if (pointerManager) {
if (pointerButton === undefined) {
return this._pointerManager._upList.length > 0;
return pointerManager._upList.length > 0;
} else {
return this._pointerManager._upMap[_pointerBin2DecMap[pointerButton]] === this._engine.time.frameCount;
return pointerManager._upMap[_pointerBin2DecMap[pointerButton]] === this._engine.time._frameCount;
}
} else {
return false;
Expand All @@ -152,11 +180,11 @@ export class InputManager {
constructor(engine: Engine) {
this._engine = engine;
// @ts-ignore
const canvas = engine._canvas._webCanvas;
const canvas = engine.canvas._webCanvas;
if (typeof OffscreenCanvas === "undefined" || !(canvas instanceof OffscreenCanvas)) {
this._wheelManager = new WheelManager(engine);
this._pointerManager = new PointerManager(engine);
this._keyboardManager = new KeyboardManager(engine);
this.addInput(InputType.Wheel, new WheelManager(engine));
this.addInput(InputType.Pointer, new PointerManager(engine));
this.addInput(InputType.Keyboard, new KeyboardManager(engine));
this._onBlur = this._onBlur.bind(this);
window.addEventListener("blur", this._onBlur);
this._onFocus = this._onFocus.bind(this);
Expand All @@ -169,35 +197,41 @@ export class InputManager {
* @internal
*/
_update(): void {
if (this._initialized) {
this._wheelManager._update();
this._pointerManager._update();
this._keyboardManager._update();
if (!this._initialized) {
return;
}
const { _inputInstances: inputInstances } = this;
for (let i = 0, l = InputType.length; i < l; i++) {
inputInstances[i]?._update();
}
}

/**
* @internal
*/
_destroy(): void {
if (this._initialized) {
window.removeEventListener("blur", this._onBlur);
window.removeEventListener("focus", this._onFocus);
this._wheelManager._destroy();
this._pointerManager._destroy();
this._keyboardManager._destroy();
if (!this._initialized) {
return;
}
window.removeEventListener("blur", this._onBlur);
window.removeEventListener("focus", this._onFocus);
const { _inputInstances: inputInstances } = this;
for (let i = 0, l = InputType.length; i < l; i++) {
inputInstances[i]?._destroy();
}
}

private _onBlur(): void {
this._wheelManager._onBlur();
this._pointerManager._onBlur();
this._keyboardManager._onBlur();
const { _inputInstances: inputInstances } = this;
for (let i = 0, l = InputType.length; i < l; i++) {
inputInstances[i] && (inputInstances[i].focus = false);
}
}

private _onFocus(): void {
this._wheelManager._onFocus();
this._pointerManager._onFocus();
this._keyboardManager._onFocus();
const { _inputInstances: inputInstances } = this;
for (let i = 0, l = InputType.length; i < l; i++) {
inputInstances[i] && (inputInstances[i].focus = true);
}
}
}
33 changes: 33 additions & 0 deletions packages/core/src/input/enums/InputType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Several known input types and other types to be extended.
*/
export enum InputType {
/** The pointer input will be triggered when the user touches (such as a mouse, pen or contact point on a touch-enable surface). */
Pointer = 0,
/** The wheel input fires when the user scrolls the mouse wheel or similar hardware device. */
Wheel = 1,
/** The keyboard input fires when the user presses or lifts a keyboard key. */
Keyboard = 2,
/** Input to be expanded. */
XInput1 = 3,
/** Input to be expanded. */
XInput2 = 4,
/** Input to be expanded. */
XInput3 = 5,
/** Input to be expanded. */
XInput4 = 6,
/** Input to be expanded. */
XInput5 = 7,
/** Input to be expanded. */
XInput6 = 8,
/** Input to be expanded. */
XInput7 = 9,
/** Input to be expanded. */
XInput8 = 10,
/** Input to be expanded. */
XInput9 = 11,
/** Input to be expanded. */
XInput10 = 12,
/** The maximum count of inputs at the same time. */
length = 13
}
3 changes: 3 additions & 0 deletions packages/core/src/input/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ export { Pointer } from "./pointer/Pointer";
export { InputManager } from "./InputManager";
export { Keys } from "./enums/Keys";
export { PointerButton } from "./enums/PointerButton";
export { WheelManager } from "./wheel/WheelManager";
export { PointerManager } from "./pointer/PointerManager";
export { KeyboardManager } from "./keyboard/KeyBoardManager";
13 changes: 5 additions & 8 deletions packages/core/src/input/interface/IInput.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export interface IInput {
/**
* If the input has focus.
*/
get focus(): boolean;
set focus(value: boolean);
/**
* Handler function updated every frame.
*/
Expand All @@ -7,12 +12,4 @@ export interface IInput {
* Function called when the engine is destroyed.
*/
_destroy(): void;
/**
* Function called when focused.
*/
_onFocus(): void;
/**
* Function called when focus is lost.
*/
_onBlur(): void;
}