import * as React from 'react' import { HOME_BUTTON_IMAGE } from '@msgba/constants' import { sendKeyDown } from '@msgba/packet' export interface OverlayControlsProps { firstMenuElement: React.RefObject controlsRef: React.RefObject setHiddenMenu: (c: boolean) => void webSocket: WebSocket | null }; interface ControlValue { key: number ref: React.RefObject sym: string classes: string transformX?: number transformY?: number } type ControlMap = Record export default function OverlayControls ({ firstMenuElement, setHiddenMenu, webSocket, controlsRef }: OverlayControlsProps): JSX.Element { function showOverlayMenu (): void { setHiddenMenu(false) } const onGoingTouches = new Map() function mouseDown (e: React.MouseEvent, key: number): void { e.preventDefault() if (webSocket == null) { console.log('There is not websocket') return } sendKeyDown(webSocket, true, key) } function mouseUp (e: React.MouseEvent, key: number): void { e.preventDefault() if (webSocket == null) { console.log('There is not websocket') return } sendKeyDown(webSocket, false, key) } const controls: ControlMap = {} controls.a = { ref: React.useRef(null), key: 0, sym: 'A', classes: 'control-a control-button-a-b control control-button' } controls.b = { ref: React.useRef(null), key: 1, sym: 'B', transformX: 50, 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(null) } controls.r = { key: 3, sym: 'R', classes: 'control-r control-button-l-r control', ref: React.useRef(null) } controls.start = { key: 4, sym: 'START', classes: 'control-start control-button-start-select control', transformX: 25, ref: React.useRef(null) } controls.select = { key: 5, sym: 'SEL', classes: 'control-select control-button-start-select control', transformX: -25, ref: React.useRef(null) } controls.up = { key: 6, sym: '^', transformX: 100, classes: 'control-up control control-pad-button', ref: React.useRef(null) } controls.down = { key: 7, sym: 'v', transformX: 100, classes: 'control-down control control-pad-button', ref: React.useRef(null) } controls.left = { key: 8, sym: '<', classes: 'control-left control control-pad-button', ref: React.useRef(null) } controls.right = { key: 9, sym: '>', transformX: 200, classes: 'control-right control control-pad-button', ref: React.useRef(null) } function determineKey (e: React.TouchEvent, 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 } const 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) } if (x >= offsetLeft && x <= offsetLeft + offsetWidth && y >= offsetTop && y <= offsetTop + offsetHeight) { return controls[control].key } } return null } function touchStartControls (e: React.TouchEvent): boolean { e.preventDefault() if (webSocket == null) { console.log('There is not websocket') return false } for (let i = 0; i < e.changedTouches.length; i++) { const touch = e.changedTouches[i] const key: number | null = determineKey(e, touch) if (key == null) { continue } const idx = touch.identifier onGoingTouches.set(idx, key) sendKeyDown(webSocket, true, key) } return false } function touchMoveControls (e: React.TouchEvent): boolean { e.preventDefault() if (webSocket == null) { console.log('There is not websocket') return false } for (let i = 0; i < e.changedTouches.length; i++) { const touch = e.changedTouches[i] const key: number | null = determineKey(e, touch) const idx = touch.identifier if (key == null) { continue } const oldKey = onGoingTouches.get(idx) if (oldKey != null) { sendKeyDown(webSocket, false, oldKey) onGoingTouches.delete(idx) } onGoingTouches.set(idx, key) sendKeyDown(webSocket, true, key) } return false } function touchEndControls (e: React.TouchEvent): boolean { e.preventDefault() if (webSocket == null) { console.log('There is not websocket') return false } for (let i = 0; i < e.changedTouches.length; i++) { const touch = e.changedTouches[i] const idx = touch.identifier const oldKey = onGoingTouches.get(idx) if (oldKey == null) { return false } sendKeyDown(webSocket, false, oldKey) onGoingTouches.delete(idx) } return false } const keyMap: string[] = ['KeyZ', 'KeyX', 'KeyA', 'KeyS', 'Enter', 'Space', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'] function onPressControl (e: React.KeyboardEvent): void { if (e.code === 'Escape') { e.preventDefault() showOverlayMenu() return } if (webSocket == null) { console.log('There is not websocket') return } const key = keyMap.findIndex((c: string) => c === e.code) if (key !== -1) { e.preventDefault() sendKeyDown(webSocket, true, key) } } function onUnpressControl (e: React.KeyboardEvent): void { if (webSocket == null) { console.log('There is not websocket') return } const key = keyMap.findIndex((c: string) => c === e.code) if (key !== -1) { e.preventDefault() sendKeyDown(webSocket, false, key) } } document.onselectstart = () => false return ( ) }