UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

237 lines (234 loc) 6.44 kB
import { InputSource } from '../input.js'; import { movementState } from '../utils.js'; const PASSIVE = { passive: false }; const KEY_CODES = { A: 0, B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10, L: 11, M: 12, N: 13, O: 14, P: 15, Q: 16, R: 17, S: 18, T: 19, U: 20, V: 21, W: 22, X: 23, Y: 24, Z: 25, '0': 26, '1': 27, '2': 28, '3': 29, '4': 30, '5': 31, '6': 32, '7': 33, '8': 34, '9': 35, UP: 36, DOWN: 37, LEFT: 38, RIGHT: 39, SPACE: 40, SHIFT: 41, CTRL: 42 }; const KEY_COUNT = Object.keys(KEY_CODES).length; const array = Array(KEY_COUNT).fill(0); class KeyboardMouseSource extends InputSource { static{ this.keyCode = KEY_CODES; } constructor({ pointerLock = false } = {}){ super({ key: Array(KEY_COUNT).fill(0), button: [ 0, 0, 0 ], mouse: [ 0, 0 ], wheel: [ 0 ] }), this._movementState = movementState(), this._pointerId = -1, this._keyMap = new Map(), this._keyPrev = Array(KEY_COUNT).fill(0), this._keyNow = Array(KEY_COUNT).fill(0), this._button = Array(3).fill(0); this._pointerLock = pointerLock ?? false; const { keyCode } = KeyboardMouseSource; for(let i = 0; i < 26; i++){ const code = `Key${String.fromCharCode('A'.charCodeAt(0) + i)}`; this._keyMap.set(code, keyCode.A + i); } for(let i = 0; i < 10; i++){ const code = `Digit${i}`; this._keyMap.set(code, keyCode['0'] + i); } this._keyMap.set('ArrowUp', keyCode.UP); this._keyMap.set('ArrowDown', keyCode.DOWN); this._keyMap.set('ArrowLeft', keyCode.LEFT); this._keyMap.set('ArrowRight', keyCode.RIGHT); this._keyMap.set('Space', keyCode.SPACE); this._keyMap.set('ShiftLeft', keyCode.SHIFT); this._keyMap.set('ShiftRight', keyCode.SHIFT); this._keyMap.set('ControlLeft', keyCode.CTRL); this._keyMap.set('ControlRight', keyCode.CTRL); this._onWheel = this._onWheel.bind(this); this._onPointerDown = this._onPointerDown.bind(this); this._onPointerMove = this._onPointerMove.bind(this); this._onPointerUp = this._onPointerUp.bind(this); this._onContextMenu = this._onContextMenu.bind(this); this._onKeyDown = this._onKeyDown.bind(this); this._onKeyUp = this._onKeyUp.bind(this); } _onWheel(event) { event.preventDefault(); this.deltas.wheel.append([ event.deltaY ]); } _onPointerDown(event) { this._movementState.down(event); if (event.pointerType !== 'mouse') { return; } if (this._pointerLock) { if (document.pointerLockElement !== this._element) { this._element?.requestPointerLock(); } } else { this._element?.setPointerCapture(event.pointerId); } this._clearButtons(); this._button[event.button] = 1; this.deltas.button.append(this._button); if (this._pointerId !== -1) { return; } this._pointerId = event.pointerId; } _onPointerMove(event) { const [movementX, movementY] = this._pointerLock && document.pointerLockElement === this._element ? [ event.movementX, event.movementY ] : this._movementState.move(event); if (event.pointerType !== 'mouse') { return; } if (event.target !== this._element) { return; } if (this._pointerLock) { if (document.pointerLockElement !== this._element) { return; } } else { if (this._pointerId !== event.pointerId) { return; } } this.deltas.mouse.append([ movementX, movementY ]); } _onPointerUp(event) { this._movementState.up(event); if (event.pointerType !== 'mouse') { return; } if (!this._pointerLock) { this._element?.releasePointerCapture(event.pointerId); } this._clearButtons(); this.deltas.button.append(this._button); if (this._pointerId !== event.pointerId) { return; } this._pointerId = -1; } _onContextMenu(event) { event.preventDefault(); } _onKeyDown(event) { if (this._pointerLock && document.pointerLockElement !== this._element) { return; } event.stopPropagation(); this._setKey(event.code, 1); } _onKeyUp(event) { event.stopPropagation(); this._setKey(event.code, 0); } _clearButtons() { for(let i = 0; i < this._button.length; i++){ if (this._button[i] === 1) { this._button[i] = -1; continue; } this._button[i] = 0; } } _setKey(code, value) { if (!this._keyMap.has(code)) { return; } this._keyNow[this._keyMap.get(code) ?? 0] = value; } attach(element) { super.attach(element); this._element = element; this._element.addEventListener('wheel', this._onWheel, PASSIVE); this._element.addEventListener('pointerdown', this._onPointerDown); this._element.addEventListener('pointermove', this._onPointerMove); this._element.addEventListener('pointerup', this._onPointerUp); this._element.addEventListener('pointercancel', this._onPointerUp); this._element.addEventListener('pointerleave', this._onPointerUp); this._element.addEventListener('contextmenu', this._onContextMenu); window.addEventListener('keydown', this._onKeyDown, false); window.addEventListener('keyup', this._onKeyUp, false); } detach() { if (!this._element) { return; } this._element.removeEventListener('wheel', this._onWheel, PASSIVE); this._element.removeEventListener('pointerdown', this._onPointerDown); this._element.removeEventListener('pointermove', this._onPointerMove); this._element.removeEventListener('pointerup', this._onPointerUp); this._element.removeEventListener('pointercancel', this._onPointerUp); this._element.removeEventListener('pointerleave', this._onPointerUp); this._element.removeEventListener('contextmenu', this._onContextMenu); window.removeEventListener('keydown', this._onKeyDown, false); window.removeEventListener('keyup', this._onKeyUp, false); this._keyNow.fill(0); this._keyPrev.fill(0); super.detach(); } read() { for(let i = 0; i < array.length; i++){ array[i] = this._keyNow[i] - this._keyPrev[i]; this._keyPrev[i] = this._keyNow[i]; } this.deltas.key.append(array); return super.read(); } } export { KeyboardMouseSource };