2023-03-24 03:22:21 +01:00
|
|
|
import * as React from 'react';
|
|
|
|
import {HOME_BUTTON_IMAGE} from '/constants';
|
2023-03-25 15:20:18 +01:00
|
|
|
import {sendKeyDown} from '/packet';
|
2023-03-24 03:22:21 +01:00
|
|
|
|
|
|
|
export interface OverlayControlsProps {
|
|
|
|
firstMenuElement: React.RefObject<HTMLAnchorElement>,
|
|
|
|
setHiddenMenu: (c: boolean) => void,
|
2023-03-25 15:20:18 +01:00
|
|
|
webSocket: WebSocket | null;
|
2023-03-24 03:22:21 +01:00
|
|
|
};
|
|
|
|
|
2023-03-25 23:54:02 +01:00
|
|
|
interface ControlMap {
|
|
|
|
[id: string]: {key: number, ref: React.RefObject<HTMLAnchorElement>, sym: string, classes: string, transformX?: number, transformY?: number}
|
|
|
|
};
|
|
|
|
|
2023-03-25 15:20:18 +01:00
|
|
|
export default function OverlayControls({firstMenuElement, setHiddenMenu, webSocket}: OverlayControlsProps) {
|
2023-03-24 03:22:21 +01:00
|
|
|
function showOverlayMenu() {
|
|
|
|
setHiddenMenu(false);
|
2023-03-24 19:13:09 +01:00
|
|
|
setTimeout(() => {
|
|
|
|
if (firstMenuElement.current == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
firstMenuElement.current.focus();
|
|
|
|
}, 100);
|
2023-03-24 03:22:21 +01:00
|
|
|
}
|
2023-03-25 15:20:18 +01:00
|
|
|
const [onGoingTouches, setOnGoingTouches] = React.useState<{[id: string]: number}>({});
|
|
|
|
function mouseDown(e: React.MouseEvent<HTMLAnchorElement> | React.TouchEvent<HTMLAnchorElement>, key: number) {
|
|
|
|
e.preventDefault();
|
|
|
|
if (webSocket == null) {
|
|
|
|
console.log('There is not websocket');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sendKeyDown(webSocket, true, key);
|
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
|
|
|
|
function mouseUp(e: React.MouseEvent<HTMLAnchorElement> | React.TouchEvent<HTMLAnchorElement>, key: number) {
|
|
|
|
e.preventDefault();
|
|
|
|
if (webSocket == null) {
|
|
|
|
console.log('There is not websocket');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sendKeyDown(webSocket, false, key);
|
|
|
|
}
|
|
|
|
|
2023-03-25 23:54:02 +01:00
|
|
|
const controls: ControlMap = {};
|
2023-03-25 19:37:27 +01:00
|
|
|
controls.a = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 0,
|
|
|
|
sym: 'A',
|
2023-03-26 01:00:27 +01:00
|
|
|
classes: 'control-a control-button-a-b control control-button',
|
|
|
|
};
|
2023-03-25 19:37:27 +01:00
|
|
|
controls.b = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 1,
|
|
|
|
sym: 'B',
|
|
|
|
transformX: 50,
|
2023-03-26 01:00:27 +01:00
|
|
|
classes: 'control-b control-button-a-b control control-button',
|
|
|
|
};
|
|
|
|
controls.l = {
|
|
|
|
key: 2,
|
|
|
|
sym: 'L',
|
|
|
|
classes: 'control-l control-button-l-r control',
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
};
|
|
|
|
|
|
|
|
controls.r = {
|
|
|
|
key: 3,
|
|
|
|
sym: 'R',
|
|
|
|
classes: 'control-r control-button-l-r control',
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
};
|
|
|
|
controls.start = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 4,
|
|
|
|
sym: 'START',
|
|
|
|
classes: 'control-start control-button-start-select control',
|
|
|
|
transformX: 25,
|
|
|
|
};
|
|
|
|
controls.select = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 5,
|
|
|
|
sym: 'SEL',
|
|
|
|
classes: 'control-select control-button-start-select control',
|
|
|
|
transformX: -25,
|
|
|
|
};
|
2023-03-25 19:37:27 +01:00
|
|
|
controls.up = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 6,
|
|
|
|
sym: '^',
|
|
|
|
transformX: 100,
|
|
|
|
classes: 'control-up control control-pad-button',
|
|
|
|
}
|
|
|
|
controls.down = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 7,
|
|
|
|
sym: 'v',
|
|
|
|
transformX: 100,
|
|
|
|
classes: 'control-down control control-pad-button',
|
|
|
|
}
|
|
|
|
controls.left = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 8,
|
|
|
|
sym: '<',
|
|
|
|
classes: 'control-left control control-pad-button',
|
|
|
|
}
|
|
|
|
controls.right = {
|
|
|
|
ref: React.useRef<HTMLAnchorElement|null>(null),
|
|
|
|
key: 9,
|
|
|
|
sym: '>',
|
|
|
|
transformX: 200,
|
|
|
|
classes: 'control-right control control-pad-button',
|
|
|
|
}
|
2023-03-25 23:54:02 +01:00
|
|
|
|
|
|
|
function determineKey(e: React.TouchEvent<HTMLDivElement>, touch: React.Touch): number | null {
|
|
|
|
const x = touch.pageX;
|
|
|
|
const y = touch.pageY;
|
|
|
|
for (const control of Object.keys(controls)) {
|
|
|
|
const ref = controls[control].ref.current;
|
|
|
|
if (ref == null) {
|
|
|
|
console.log('No ref found');
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let top = ref.getBoundingClientRect().top + document.documentElement.scrollTop;
|
|
|
|
const currentControl = controls[control];
|
|
|
|
const transformX = currentControl.transformX;
|
|
|
|
const transformY = currentControl.transformY;
|
|
|
|
let offsetLeft = ref.offsetLeft;
|
|
|
|
const offsetWidth = ref.offsetWidth;
|
|
|
|
let offsetTop = top;
|
|
|
|
const offsetHeight = ref.offsetHeight;
|
|
|
|
if (transformX != null) {
|
|
|
|
offsetLeft += offsetWidth * (transformX / 100);
|
|
|
|
}
|
|
|
|
if (transformY != null) {
|
|
|
|
offsetTop += offsetHeight * (transformY / 100);
|
|
|
|
}
|
|
|
|
console.log(x, y, offsetLeft, offsetTop, offsetWidth, offsetHeight);
|
|
|
|
if (x >= offsetLeft && x <= offsetLeft + offsetWidth && y >= offsetTop && y <= offsetTop + offsetHeight) {
|
|
|
|
return controls[control].key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
function touchStartControls(e: React.TouchEvent<HTMLDivElement>) {
|
2023-03-25 15:20:18 +01:00
|
|
|
e.preventDefault();
|
|
|
|
if (webSocket == null) {
|
|
|
|
console.log('There is not websocket');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (let i = 0; i < e.changedTouches.length; i++) {
|
|
|
|
const touch = e.changedTouches[i];
|
2023-03-25 23:54:02 +01:00
|
|
|
let key: number|null = determineKey(e, touch);
|
2023-03-25 19:37:27 +01:00
|
|
|
if (key == null) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-03-25 15:20:18 +01:00
|
|
|
const idx = touch.identifier;
|
|
|
|
onGoingTouches[idx] = key;
|
|
|
|
sendKeyDown(webSocket, true, key);
|
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
return false;
|
2023-03-25 15:20:18 +01:00
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
function touchMoveControls(e: React.TouchEvent<HTMLDivElement>) {
|
2023-03-25 15:20:18 +01:00
|
|
|
e.preventDefault();
|
|
|
|
if (webSocket == null) {
|
|
|
|
console.log('There is not websocket');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (let i = 0; i < e.changedTouches.length; i++) {
|
|
|
|
const touch = e.changedTouches[i];
|
2023-03-25 23:54:02 +01:00
|
|
|
let key: number|null = determineKey(e, touch);
|
2023-03-25 15:20:18 +01:00
|
|
|
const idx = touch.identifier;
|
2023-03-25 23:54:02 +01:00
|
|
|
if (key == null) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
if (onGoingTouches[idx] != null) {
|
|
|
|
sendKeyDown(webSocket, false, onGoingTouches[idx]);
|
|
|
|
delete onGoingTouches[idx];
|
|
|
|
}
|
|
|
|
onGoingTouches[idx] = key;
|
|
|
|
sendKeyDown(webSocket, true, key);
|
2023-03-25 15:20:18 +01:00
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
return false;
|
2023-03-25 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
2023-03-25 19:37:27 +01:00
|
|
|
|
|
|
|
function touchEndControls(e: React.TouchEvent<HTMLDivElement>) {
|
2023-03-25 15:20:18 +01:00
|
|
|
e.preventDefault();
|
|
|
|
if (webSocket == null) {
|
|
|
|
console.log('There is not websocket');
|
|
|
|
return;
|
|
|
|
}
|
2023-03-25 19:37:27 +01:00
|
|
|
for (let i = 0; i < e.changedTouches.length; i++) {
|
|
|
|
const touch = e.changedTouches[i];
|
|
|
|
const idx = touch.identifier;
|
|
|
|
if (onGoingTouches[idx] == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sendKeyDown(webSocket, false, onGoingTouches[idx]);
|
|
|
|
delete onGoingTouches[idx];
|
|
|
|
}
|
|
|
|
return false;
|
2023-03-25 15:20:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
document.onselectstart = () => false;
|
2023-03-24 03:22:21 +01:00
|
|
|
return (
|
2023-03-25 19:37:27 +01:00
|
|
|
<div className="overlay">
|
2023-03-24 03:22:21 +01:00
|
|
|
<div className="vertical-padding">
|
|
|
|
</div>
|
2023-03-25 19:37:27 +01:00
|
|
|
<div className="controls" onTouchStart={touchStartControls} onTouchMove={touchMoveControls} onTouchEnd={touchEndControls}>
|
2023-03-25 15:20:18 +01:00
|
|
|
<a tabIndex={-1} className="gear control" onClick={showOverlayMenu} onTouchStart={showOverlayMenu}>
|
2023-03-24 03:22:21 +01:00
|
|
|
<img src={HOME_BUTTON_IMAGE} alt="Go to menu. (House icon)"/>
|
|
|
|
</a>
|
2023-03-25 19:37:27 +01:00
|
|
|
{
|
|
|
|
Object.keys(controls).map((key) =>
|
|
|
|
<a tabIndex={-1}
|
|
|
|
className={controls[key].classes}
|
|
|
|
ref={controls[key].ref}
|
|
|
|
key={key}
|
|
|
|
onMouseDown={(e: React.MouseEvent<HTMLAnchorElement>) => mouseDown(e, controls[key].key)}
|
|
|
|
onMouseUp={(e: React.MouseEvent<HTMLAnchorElement>) => mouseUp(e, controls[key].key)}>
|
|
|
|
{controls[key].sym}
|
|
|
|
</a>
|
|
|
|
)
|
|
|
|
}
|
2023-03-24 03:22:21 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|