2019-04-28 23:45:03 -05:00
|
|
|
import {compose, EventEmitter} from '@avocado/core';
|
2019-04-28 23:30:56 -05:00
|
|
|
|
|
|
|
const decorate = compose(
|
|
|
|
EventEmitter,
|
|
|
|
);
|
|
|
|
|
2019-05-23 04:52:20 -05:00
|
|
|
class PointerEvent {
|
|
|
|
|
|
|
|
constructor(event) {
|
|
|
|
this.nativeEvent = event;
|
|
|
|
if (window.PointerEvent && event instanceof window.PointerEvent) {
|
|
|
|
this.position = [
|
|
|
|
event.clientX,
|
|
|
|
event.clientY,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
else if (window.TouchEvent && event instanceof window.TouchEvent) {
|
|
|
|
const touches = event.changedTouches;
|
|
|
|
const touch = touches[0];
|
|
|
|
this.position = [
|
|
|
|
touch.clientX,
|
|
|
|
touch.clientY,
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-28 23:30:56 -05:00
|
|
|
export class InputNormalizer extends decorate(class{}) {
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
// Track events.
|
|
|
|
this.target = undefined;
|
|
|
|
this.targetForKeyUp = undefined;
|
|
|
|
// Handle lame OS input event behavior. See: https://mzl.la/2Ob0WQE
|
|
|
|
this.keysDown = {};
|
|
|
|
this.keyUpDelays = {};
|
|
|
|
// Bind event handlers.
|
|
|
|
this.onBlur = this.onBlur.bind(this);
|
|
|
|
this.onKeyDown = this.onKeyDown.bind(this);
|
|
|
|
this.onKeyUp = this.onKeyUp.bind(this);
|
2019-05-23 04:52:20 -05:00
|
|
|
this.onPointerDown = this.onPointerDown.bind(this);
|
|
|
|
this.onPointerMove = this.onPointerMove.bind(this);
|
|
|
|
this.onPointerUp = this.onPointerUp.bind(this);
|
|
|
|
this.onTouchStart = this.onTouchStart.bind(this);
|
|
|
|
this.onTouchMove = this.onTouchMove.bind(this);
|
|
|
|
this.onTouchEnd = this.onTouchEnd.bind(this);
|
2019-05-23 05:38:46 -05:00
|
|
|
this.onWheel = this.onWheel.bind(this);
|
2019-04-28 23:30:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
actionForKey(key) {
|
|
|
|
return this.mapKeyToAction[key];
|
|
|
|
}
|
|
|
|
|
2019-05-23 04:52:20 -05:00
|
|
|
destroy() {
|
|
|
|
this.stopListening();
|
|
|
|
}
|
|
|
|
|
2019-04-28 23:30:56 -05:00
|
|
|
listen(target = window.document, targetForKeyUp = window.document) {
|
|
|
|
// Only listen once.
|
|
|
|
if (this.target) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.target = target;
|
|
|
|
this.targetForKeyUp = targetForKeyUp;
|
|
|
|
this.target.addEventListener('blur', this.onBlur);
|
|
|
|
this.target.addEventListener('keydown', this.onKeyDown);
|
|
|
|
this.targetForKeyUp.addEventListener('keyup', this.onKeyUp);
|
2019-05-23 04:52:20 -05:00
|
|
|
// Listen for pointer events if they exist.
|
|
|
|
if ('undefined' !== typeof window.PointerEvent) {
|
|
|
|
this.target.addEventListener('pointerdown', this.onPointerDown);
|
|
|
|
this.target.addEventListener('pointermove', this.onPointerMove);
|
|
|
|
window.addEventListener('pointerup', this.onPointerUp);
|
|
|
|
}
|
|
|
|
// Otherwise, use touch events. (lol Apple)
|
|
|
|
else {
|
|
|
|
this.target.addEventListener('touchstart', this.onTouchStart);
|
|
|
|
this.target.addEventListener('touchmove', this.onTouchMove);
|
|
|
|
window.addEventListener('touchend', this.onTouchEnd);
|
|
|
|
}
|
2019-05-23 05:38:46 -05:00
|
|
|
this.target.addEventListener('wheel', this.onWheel);
|
2019-04-28 23:30:56 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
onBlur(event) {
|
|
|
|
this.setAllKeysUp();
|
|
|
|
}
|
|
|
|
|
|
|
|
onKeyDown(event) {
|
|
|
|
const {key} = event;
|
|
|
|
if (this.keysDown[key]) {
|
|
|
|
if (this.keyUpDelays[key]) {
|
|
|
|
clearTimeout(this.keyUpDelays[key]);
|
|
|
|
delete this.keyUpDelays[key];
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.keysDown[key] = true;
|
|
|
|
this.emit('keyDown', key);
|
|
|
|
}
|
|
|
|
|
|
|
|
onKeyUp(event) {
|
|
|
|
const {key} = event;
|
|
|
|
this.keyUpDelays[key] = setTimeout(() => {
|
|
|
|
delete this.keyUpDelays[key];
|
|
|
|
delete this.keysDown[key];
|
|
|
|
this.emit('keyUp', key);
|
|
|
|
}, 20);
|
|
|
|
}
|
|
|
|
|
2019-05-23 04:52:20 -05:00
|
|
|
onPointerDown(event) {
|
|
|
|
this.emit('pointerDown', new PointerEvent(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
onPointerMove(event) {
|
|
|
|
this.emit('pointerMove', new PointerEvent(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
onPointerUp(event) {
|
|
|
|
this.emit('pointerUp', new PointerEvent(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
onTouchStart(event) {
|
|
|
|
this.emit('pointerDown', new PointerEvent(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
onTouchMove(event) {
|
|
|
|
this.emit('pointerMove', new PointerEvent(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
onTouchEnd(event) {
|
|
|
|
this.emit('pointerUp', new PointerEvent(event));
|
|
|
|
}
|
|
|
|
|
2019-05-23 05:38:46 -05:00
|
|
|
onWheel(event) {
|
|
|
|
this.emit('wheel', event);
|
|
|
|
}
|
|
|
|
|
2019-04-28 23:30:56 -05:00
|
|
|
setAllKeysUp() {
|
|
|
|
this.keysDown = {};
|
|
|
|
for (const key in this.keyUpDelays) {
|
|
|
|
const handle = this.keyUpDelays[key];
|
|
|
|
clearTimeout(handle);
|
|
|
|
this.emit('keyUp', key);
|
|
|
|
}
|
|
|
|
this.keyUpDelays = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
stopListening() {
|
|
|
|
this.setAllKeysUp();
|
|
|
|
if (!this.target) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.target.removeEventListener('blur', this.onBlur);
|
|
|
|
this.target.removeEventListener('keydown', this.onKeyDown);
|
|
|
|
this.targetForKeyUp.removeEventListener('keyup', this.onKeyUp);
|
2019-05-23 04:52:20 -05:00
|
|
|
// Listen for pointer events if they exist.
|
|
|
|
if ('undefined' !== typeof window.PointerEvent) {
|
|
|
|
this.target.removeEventListener('pointerdown', this.onPointerDown);
|
|
|
|
this.target.removeEventListener('pointermove', this.onPointerMove);
|
|
|
|
window.removeEventListener('pointerup', this.onPointerUp);
|
|
|
|
}
|
|
|
|
// Otherwise, use touch events. (lol Apple)
|
|
|
|
else {
|
|
|
|
this.target.removeEventListener('touchstart', this.onTouchStart);
|
|
|
|
this.target.removeEventListener('touchmove', this.onTouchMove);
|
|
|
|
window.removeEventListener('touchend', this.onTouchEnd);
|
|
|
|
}
|
2019-05-23 05:38:46 -05:00
|
|
|
this.target.removeEventListener('wheel', this.onWheel);
|
2019-04-28 23:30:56 -05:00
|
|
|
this.target = undefined;
|
|
|
|
this.targetForKeyUp = undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|