Skip to content
This repository has been archived by the owner on Mar 5, 2021. It is now read-only.

Cross platform multi touch fixes #44 #174

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions SupEngine/SupEngine.d.ts
Original file line number Diff line number Diff line change
@@ -173,9 +173,8 @@ declare namespace SupEngine {
}

class Input {
static maxTouches: number;

exited: boolean;

canvas: HTMLCanvasElement;

mouseButtons: MouseButtonState[];
@@ -186,7 +185,12 @@ declare namespace SupEngine {
newScrollDelta: number;

touches: TouchState[];
touchesDown: boolean[];
touchesDown: number[];
touchesStarted: number[];
touchesEnded: number[];
touchesMoved: number[];
mouseTouchIdentifier: number;
touchEmulatesMouse: boolean;

keyboardButtons: KeyState[];
keyboardButtonsDown: boolean[];
122 changes: 96 additions & 26 deletions SupEngine/src/Input.ts
Original file line number Diff line number Diff line change
@@ -18,7 +18,9 @@ interface TouchState {
isDown: boolean;
wasStarted: boolean;
wasEnded: boolean;
wasMoved: boolean;
position: { x: number; y: number; };
identifier: number;
}

interface GamepadButtonState {
@@ -45,8 +47,6 @@ interface GamepadAutoRepeat {
}

export default class Input extends EventEmitter {
static maxTouches = 10;

canvas: HTMLCanvasElement;

mouseButtons: MouseButtonState[] = [];
@@ -58,7 +58,12 @@ export default class Input extends EventEmitter {
newScrollDelta: number;

touches: TouchState[] = [];
touchesDown: boolean[] = [];
touchesDown: number[] = [];
touchesStarted: number[] = [];
touchesEnded: number[] = [];
touchesMoved: number[] = [];
mouseTouchIdentifier: number = null;
touchEmulatesMouse = false;

keyboardButtons: KeyState[] = [];
keyboardButtonsDown: boolean[] = [];
@@ -193,10 +198,12 @@ export default class Input extends EventEmitter {
this.newMouseDelta.y = 0;

// Touch
for (let i = 0; i < Input.maxTouches; i++) {
this.touches[i] = { isDown: false, wasStarted: false, wasEnded: false, position: { x: 0, y: 0} };
this.touchesDown[i] = false;
}
this.touchesDown = [];
this.touches = [];
this.touchesEnded = [];
this.touchesStarted = [];
this.touchesMoved = [];
this.mouseTouchIdentifier = null;

// Keyboard
for (let i = 0; i <= 255; i++) {
@@ -371,43 +378,74 @@ export default class Input extends EventEmitter {
private onTouchStart = (event: any) => {
event.preventDefault();

if (this.touchEmulatesMouse && this.mouseTouchIdentifier == null &&
this.touchesDown.length === 0 && event.changedTouches.length > 0) {
// track first touch as mouse
this.mouseTouchIdentifier = event.changedTouches[0].identifier;
}

const rect = event.target.getBoundingClientRect();
const changedTouchesArray: any[] = [];

for (let i = 0; i < event.changedTouches.length; i++) {
const touch = event.changedTouches[i];
this.touches[touch.identifier].position.x = touch.clientX - rect.left;
this.touches[touch.identifier].position.y = touch.clientY - rect.top;
changedTouchesArray.push(event.changedTouches[i]);
}

this.touchesDown[touch.identifier] = true;
changedTouchesArray.forEach(touch => {
const touchInput: TouchState =
{ identifier: touch.identifier, wasStarted: true, wasEnded: false, wasMoved: false, isDown: false, position: { x: touch.clientX - rect.left, y: touch.clientY - rect.top } };

if (touch.identifier === 0) {
this.newMousePosition = { x: touch.clientX - rect.left, y: touch.clientY - rect.top };
this.touches.push(touchInput);

if (this.touchEmulatesMouse && touch.identifier === this.mouseTouchIdentifier) {
this.newMousePosition = touch.position;
this.mouseButtonsDown[0] = true;
}
}
});
};

private onTouchEnd = (event: any) => {
event.preventDefault();

const rect = event.target.getBoundingClientRect();
const touchUpdates: any[] = [];

for (let i = 0; i < event.changedTouches.length; i++) {
const touch = event.changedTouches[i];
this.touchesDown[touch.identifier] = false;
if (touch.identifier === 0) this.mouseButtonsDown[0] = false;
touchUpdates.push(touch);
}

touchUpdates.forEach(touch => {
const touchesToChange = this.touches.filter(t => t.identifier === touch.identifier);
touchesToChange.forEach(t => {
t.wasEnded = true;
t.position.x = touch.clientX - rect.left;
t.position.y = touch.clientY - rect.top;
if (this.touchEmulatesMouse && t.identifier === this.mouseTouchIdentifier) this.mouseButtonsDown[0] = false;
});
});
};

private onTouchMove = (event: any) => {
event.preventDefault();

const rect = event.target.getBoundingClientRect();
const touchUpdates: any[] = [];

for (let i = 0; i < event.changedTouches.length; i++) {
const touch = event.changedTouches[i];
this.touches[touch.identifier].position.x = touch.clientX - rect.left;
this.touches[touch.identifier].position.y = touch.clientY - rect.top;

if (touch.identifier === 0) this.newMousePosition = { x: touch.clientX - rect.left, y: touch.clientY - rect.top };
touchUpdates.push(touch);
}

touchUpdates.forEach(touch => {
const touchesToChange = this.touches.filter(t => t.identifier === touch.identifier);
touchesToChange.forEach(t => {
t.wasMoved = true;
t.position.x = touch.clientX - rect.left;
t.position.y = touch.clientY - rect.top;
if (this.touchEmulatesMouse && t.identifier === this.mouseTouchIdentifier) this.mousePosition = t.position;
});
});
};

// TODO: stop using keyCode when KeyboardEvent.code is supported more widely
@@ -474,15 +512,47 @@ export default class Input extends EventEmitter {
mouseButton.wasJustReleased = wasDown && !mouseButton.isDown;
}

for (let i = 0; i < this.touches.length; i++) {
const touch = this.touches[i];
const wasDown = touch.isDown;
touch.isDown = this.touchesDown[i];
const touchesToRemove: TouchState[] = [];
this.touchesEnded = [];
this.touchesStarted = [];
this.touchesMoved = [];
this.touchesDown = [];

if(this.touches.length > 0) {
this.touches.forEach(touch => {
touch.wasStarted = touch.wasStarted && !touch.isDown;
touch.isDown = (touch.wasStarted || touch.isDown);

if(touch.isDown){
this.touchesDown.push(touch.identifier);
}

if (touch.wasStarted) {
this.touchesStarted.push(touch.identifier);
}

if(touch.wasMoved){
this.touchesMoved.push(touch.identifier);
}

touch.wasStarted = !wasDown && touch.isDown;
touch.wasEnded = wasDown && !touch.isDown;
if (touch.wasEnded) {
if (touch.isDown) {
this.touchesEnded.push(touch.identifier);
}
else {
touchesToRemove.push(touch);
}
touch.isDown = false;
}
});
}

touchesToRemove.forEach(ti => {
console.log(`Removing touch: ${ti.identifier}`);
const indexToRemove = this.touches.indexOf(ti);
if (indexToRemove > -1) this.touches.splice(indexToRemove, 1);
});

for (let i = 0; i < this.keyboardButtons.length; i++) {
const keyboardButton = this.keyboardButtons[i];
const wasDown = keyboardButton.isDown;
15 changes: 11 additions & 4 deletions plugins/default/typescript/typescriptAPI/Sup.Input.d.ts.txt
Original file line number Diff line number Diff line change
@@ -26,10 +26,17 @@ declare namespace Sup {
function wasMouseButtonJustPressed(button: number): boolean;
function wasMouseButtonJustReleased(button: number): boolean;

function getTouchPosition(index: number): Math.Vector2;
function isTouchDown(index: number): boolean;
function wasTouchStarted(index: number): boolean;
function wasTouchEnded(index: number): boolean;
function setTouchEmulatesMouse(emulate: boolean);
function getTouchPosition(identifier: number): Math.Vector2;
function isTouchDown(identifier?: number): boolean;
function wasTouchJustStarted(identifier?: number): boolean;
function wasTouchJustEnded(identifier?: number): boolean;
function wasTouchJustMoved(identifier?: number): boolean;
function getTouchesStarted(): number[];
function getTouchesEnded(): number[];
function getTouchesMoved(): number[];
function getTouchesDown(): number[];

function vibrate(pattern: number|number[]): void;

// Valid key names (based on window.KeyEvent.DOM_VK_*):
57 changes: 46 additions & 11 deletions plugins/default/typescript/typescriptAPI/Sup.Input.ts.txt
Original file line number Diff line number Diff line change
@@ -56,25 +56,60 @@ namespace Sup {
return player.gameInstance.input.mouseButtons[button].wasJustReleased;
}

export function setTouchEmulatesMouse(emulate: boolean) {
player.gameInstance.input.touchEmulatesMouse = emulate;
}

export function getTouchPosition(index) {
var position = player.gameInstance.input.touches[index].position;
export function getTouchPosition(identifier: number): Math.Vector2 {
let activeTouches = player.gameInstance.input.touches.filter(t=>t.identifier === identifier);
if(activeTouches.length === 0) throw new Error("Invalid touch identifier");
//default to first touch - more than one touch is actually an error...
let position = activeTouches[0].position;
return new Math.Vector2(position.x / player.canvas.clientWidth * 2 - 1, (position.y / player.canvas.clientHeight * 2 - 1) * -1);
}

export function isTouchDown(index) {
if (player.gameInstance.input.touches[index] == null) { throw new Error("Invalid touch index"); }
return player.gameInstance.input.touches[index].isDown;
export function isTouchDown(identifier?: number): boolean {
if(identifier != null)
return player.gameInstance.input.touchesDown.indexOf(identifier) > -1;
else
return player.gameInstance.input.touchesDown.length > 0;
}

export function wasTouchJustStarted(identifier?: number): boolean {
if(identifier != null)
return player.gameInstance.input.touchesStarted.indexOf(identifier) > -1;
else
return player.gameInstance.input.touchesStarted.length > 0;
}

export function wasTouchJustEnded(identifier?: number): boolean {
if(identifier != null)
return player.gameInstance.input.touchesEnded.indexOf(identifier) > -1;
else
return player.gameInstance.input.touchesEnded.length > 0;
}

export function wasTouchJustMoved(identifier?: number): boolean {
if(identifier != null)
return player.gameInstance.input.touchesMoved.indexOf(identifier) > -1;
else
return player.gameInstance.input.touchesMoved.length > 0;
}

export function getTouchesStarted(): number[] {
return player.gameInstance.input.touchesStarted;
}

export function getTouchesEnded(): number[] {
return player.gameInstance.input.touchesEnded;
}

export function wasTouchStarted(index) {
if (player.gameInstance.input.touches[index] == null) { throw new Error("Invalid touch index"); }
return player.gameInstance.input.touches[index].wasStarted;
export function getTouchesMoved(): number[] {
return player.gameInstance.input.touchesMoved;
}

export function wasTouchEnded(index) {
if (player.gameInstance.input.touches[index] == null) { throw new Error("Invalid touch index"); }
return player.gameInstance.input.touches[index].wasEnded;
export function getTouchesDown(): number[] {
return player.gameInstance.input.touchesDown;
}

export function vibrate(pattern) { window.navigator.vibrate(pattern); }