From 27f0eb84b2b3eabf9766bf10f6a54795e39459e7 Mon Sep 17 00:00:00 2001 From: Sergiotarxz Date: Mon, 3 Apr 2023 13:21:59 +0200 Subject: [PATCH] Fixing keyboard navigation bug. --- js-src/components/overlay-controls.tsx | 3 +-- js-src/components/overlay-menu.tsx | 8 ++++---- js-src/components/page.tsx | 18 +++++++++++++----- public/js/bundle.js | 6 +++--- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/js-src/components/overlay-controls.tsx b/js-src/components/overlay-controls.tsx index ce1f9c8..189a966 100644 --- a/js-src/components/overlay-controls.tsx +++ b/js-src/components/overlay-controls.tsx @@ -3,7 +3,6 @@ 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 @@ -20,7 +19,7 @@ interface ControlValue { type ControlMap = Record -export default function OverlayControls ({ firstMenuElement, setHiddenMenu, webSocket, controlsRef }: OverlayControlsProps): JSX.Element { +export default function OverlayControls ({ setHiddenMenu, webSocket, controlsRef }: OverlayControlsProps): JSX.Element { function showOverlayMenu (): void { setHiddenMenu(false) } diff --git a/js-src/components/overlay-menu.tsx b/js-src/components/overlay-menu.tsx index dc07f2c..6c830da 100644 --- a/js-src/components/overlay-menu.tsx +++ b/js-src/components/overlay-menu.tsx @@ -10,7 +10,7 @@ export interface OverlayMenuProps { screenRef: React.RefObject isFullscreen: boolean setIsFullscreen: (c: boolean) => void - firstMenuElement: React.RefObject + overlayMenu: React.RefObject websocket: WebSocket | null onSaveResponseLambdas: Map void> }; @@ -20,7 +20,7 @@ type Style = Record export default function OverlayMenu ({ hiddenMenu, setHiddenMenu, emulationStarted, setHiddenFormSelectFiles, screenRef, isFullscreen, setIsFullscreen, - firstMenuElement, websocket, onSaveResponseLambdas + overlayMenu, websocket, onSaveResponseLambdas }: OverlayMenuProps): JSX.Element { function exitMenu (): void { setHiddenMenu(true) @@ -101,9 +101,9 @@ export default function OverlayMenu ({
-
+
    -
  • Select rom
  • +
  • Select rom
  • Save
  • {toggleFullscreenText}
  • Exit
  • diff --git a/js-src/components/page.tsx b/js-src/components/page.tsx index 252e1f9..42babc7 100644 --- a/js-src/components/page.tsx +++ b/js-src/components/page.tsx @@ -102,8 +102,16 @@ export default function Page (): JSX.Element { return } if (!hiddenMenu) { - if (firstMenuElement.current != null) { - firstMenuElement.current.focus() + if (overlayMenu.current == null) { + return + } + const allAnchors = overlayMenu.current.querySelectorAll('a') + for (const anchor of allAnchors) { + if (anchor.style.display === 'none') { + continue + } + anchor.focus() + break } return } @@ -177,18 +185,18 @@ export default function Page (): JSX.Element { const onStartEmulation = (e: React.MouseEvent): void => { handleClickStartEmulationButton(e) } - const firstMenuElement = React.useRef(null) + const overlayMenu = React.useRef(null) const screenRef = React.useRef(null) const [isFullscreen, setIsFullscreen] = React.useState(false) return (
    - { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ OverlayControls)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _msgba_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @msgba/constants */ \"./js-src/constants.ts\");\n/* harmony import */ var _msgba_packet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @msgba/packet */ \"./js-src/packet.ts\");\n\n\n\n;\nfunction OverlayControls({ firstMenuElement, setHiddenMenu, webSocket, controlsRef }) {\n function showOverlayMenu() {\n setHiddenMenu(false);\n }\n const onGoingTouches = new Map();\n function mouseDown(e, key) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n function mouseUp(e, key) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, key);\n }\n const controls = {};\n controls.a = {\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null),\n key: 0,\n sym: 'A',\n classes: 'control-a control-button-a-b control control-button'\n };\n controls.b = {\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null),\n key: 1,\n sym: 'B',\n transformX: 50,\n classes: 'control-b control-button-a-b control control-button'\n };\n controls.l = {\n key: 2,\n sym: 'L',\n classes: 'control-l control-button-l-r control',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.r = {\n key: 3,\n sym: 'R',\n classes: 'control-r control-button-l-r control',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.start = {\n key: 4,\n sym: 'START',\n classes: 'control-start control-button-start-select control',\n transformX: 25,\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.select = {\n key: 5,\n sym: 'SEL',\n classes: 'control-select control-button-start-select control',\n transformX: -25,\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.up = {\n key: 6,\n sym: '^',\n transformX: 100,\n classes: 'control-up control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.down = {\n key: 7,\n sym: 'v',\n transformX: 100,\n classes: 'control-down control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.left = {\n key: 8,\n sym: '<',\n classes: 'control-left control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.right = {\n key: 9,\n sym: '>',\n transformX: 200,\n classes: 'control-right control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n function determineKey(e, touch) {\n const x = touch.pageX;\n const y = touch.pageY;\n for (const control of Object.keys(controls)) {\n const ref = controls[control].ref.current;\n if (ref == null) {\n console.log('No ref found');\n continue;\n }\n const top = ref.getBoundingClientRect().top + document.documentElement.scrollTop;\n const currentControl = controls[control];\n const transformX = currentControl.transformX;\n const transformY = currentControl.transformY;\n let offsetLeft = ref.offsetLeft;\n const offsetWidth = ref.offsetWidth;\n let offsetTop = top;\n const offsetHeight = ref.offsetHeight;\n if (transformX != null) {\n offsetLeft += offsetWidth * (transformX / 100);\n }\n if (transformY != null) {\n offsetTop += offsetHeight * (transformY / 100);\n }\n if (x >= offsetLeft && x <= offsetLeft + offsetWidth && y >= offsetTop && y <= offsetTop + offsetHeight) {\n return controls[control].key;\n }\n }\n return null;\n }\n function touchStartControls(e) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return false;\n }\n for (let i = 0; i < e.changedTouches.length; i++) {\n const touch = e.changedTouches[i];\n const key = determineKey(e, touch);\n if (key == null) {\n continue;\n }\n const idx = touch.identifier;\n onGoingTouches.set(idx, key);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n return false;\n }\n function touchMoveControls(e) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return false;\n }\n for (let i = 0; i < e.changedTouches.length; i++) {\n const touch = e.changedTouches[i];\n const key = determineKey(e, touch);\n const idx = touch.identifier;\n if (key == null) {\n continue;\n }\n const oldKey = onGoingTouches.get(idx);\n if (oldKey != null) {\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, oldKey);\n onGoingTouches.delete(idx);\n }\n onGoingTouches.set(idx, key);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n return false;\n }\n function touchEndControls(e) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return false;\n }\n for (let i = 0; i < e.changedTouches.length; i++) {\n const touch = e.changedTouches[i];\n const idx = touch.identifier;\n const oldKey = onGoingTouches.get(idx);\n if (oldKey == null) {\n return false;\n }\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, oldKey);\n onGoingTouches.delete(idx);\n }\n return false;\n }\n const keyMap = ['KeyZ', 'KeyX', 'KeyA', 'KeyS',\n 'Enter', 'Space', 'ArrowUp', 'ArrowDown',\n 'ArrowLeft', 'ArrowRight'];\n function onPressControl(e) {\n if (e.code === 'Escape') {\n e.preventDefault();\n showOverlayMenu();\n return;\n }\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n const key = keyMap.findIndex((c) => c === e.code);\n if (key !== -1) {\n e.preventDefault();\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n }\n function onUnpressControl(e) {\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n const key = keyMap.findIndex((c) => c === e.code);\n if (key !== -1) {\n e.preventDefault();\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, key);\n }\n }\n document.onselectstart = () => false;\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { ref: controlsRef, tabIndex: -1, className: \"overlay\", onKeyDown: onPressControl, onKeyUp: onUnpressControl },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"vertical-padding\" }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"controls\", onTouchStart: touchStartControls, onTouchMove: touchMoveControls, onTouchEnd: touchEndControls },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { tabIndex: -1, className: \"gear control\", onClick: showOverlayMenu, onTouchStart: showOverlayMenu },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"img\", { src: _msgba_constants__WEBPACK_IMPORTED_MODULE_1__.HOME_BUTTON_IMAGE, alt: \"Go to menu. (House icon)\" })),\n Object.keys(controls).map((key) => react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { tabIndex: -1, className: controls[key].classes, ref: controls[key].ref, key: key, onMouseDown: (e) => { mouseDown(e, controls[key].key); }, onMouseUp: (e) => { mouseUp(e, controls[key].key); } }, controls[key].sym)))));\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/overlay-controls.tsx?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ OverlayControls)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _msgba_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @msgba/constants */ \"./js-src/constants.ts\");\n/* harmony import */ var _msgba_packet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @msgba/packet */ \"./js-src/packet.ts\");\n\n\n\n;\nfunction OverlayControls({ setHiddenMenu, webSocket, controlsRef }) {\n function showOverlayMenu() {\n setHiddenMenu(false);\n }\n const onGoingTouches = new Map();\n function mouseDown(e, key) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n function mouseUp(e, key) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, key);\n }\n const controls = {};\n controls.a = {\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null),\n key: 0,\n sym: 'A',\n classes: 'control-a control-button-a-b control control-button'\n };\n controls.b = {\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null),\n key: 1,\n sym: 'B',\n transformX: 50,\n classes: 'control-b control-button-a-b control control-button'\n };\n controls.l = {\n key: 2,\n sym: 'L',\n classes: 'control-l control-button-l-r control',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.r = {\n key: 3,\n sym: 'R',\n classes: 'control-r control-button-l-r control',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.start = {\n key: 4,\n sym: 'START',\n classes: 'control-start control-button-start-select control',\n transformX: 25,\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.select = {\n key: 5,\n sym: 'SEL',\n classes: 'control-select control-button-start-select control',\n transformX: -25,\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.up = {\n key: 6,\n sym: '^',\n transformX: 100,\n classes: 'control-up control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.down = {\n key: 7,\n sym: 'v',\n transformX: 100,\n classes: 'control-down control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.left = {\n key: 8,\n sym: '<',\n classes: 'control-left control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n controls.right = {\n key: 9,\n sym: '>',\n transformX: 200,\n classes: 'control-right control control-pad-button',\n ref: react__WEBPACK_IMPORTED_MODULE_0__.useRef(null)\n };\n function determineKey(e, touch) {\n const x = touch.pageX;\n const y = touch.pageY;\n for (const control of Object.keys(controls)) {\n const ref = controls[control].ref.current;\n if (ref == null) {\n console.log('No ref found');\n continue;\n }\n const top = ref.getBoundingClientRect().top + document.documentElement.scrollTop;\n const currentControl = controls[control];\n const transformX = currentControl.transformX;\n const transformY = currentControl.transformY;\n let offsetLeft = ref.offsetLeft;\n const offsetWidth = ref.offsetWidth;\n let offsetTop = top;\n const offsetHeight = ref.offsetHeight;\n if (transformX != null) {\n offsetLeft += offsetWidth * (transformX / 100);\n }\n if (transformY != null) {\n offsetTop += offsetHeight * (transformY / 100);\n }\n if (x >= offsetLeft && x <= offsetLeft + offsetWidth && y >= offsetTop && y <= offsetTop + offsetHeight) {\n return controls[control].key;\n }\n }\n return null;\n }\n function touchStartControls(e) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return false;\n }\n for (let i = 0; i < e.changedTouches.length; i++) {\n const touch = e.changedTouches[i];\n const key = determineKey(e, touch);\n if (key == null) {\n continue;\n }\n const idx = touch.identifier;\n onGoingTouches.set(idx, key);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n return false;\n }\n function touchMoveControls(e) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return false;\n }\n for (let i = 0; i < e.changedTouches.length; i++) {\n const touch = e.changedTouches[i];\n const key = determineKey(e, touch);\n const idx = touch.identifier;\n if (key == null) {\n continue;\n }\n const oldKey = onGoingTouches.get(idx);\n if (oldKey != null) {\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, oldKey);\n onGoingTouches.delete(idx);\n }\n onGoingTouches.set(idx, key);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n return false;\n }\n function touchEndControls(e) {\n e.preventDefault();\n if (webSocket == null) {\n console.log('There is not websocket');\n return false;\n }\n for (let i = 0; i < e.changedTouches.length; i++) {\n const touch = e.changedTouches[i];\n const idx = touch.identifier;\n const oldKey = onGoingTouches.get(idx);\n if (oldKey == null) {\n return false;\n }\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, oldKey);\n onGoingTouches.delete(idx);\n }\n return false;\n }\n const keyMap = ['KeyZ', 'KeyX', 'KeyA', 'KeyS',\n 'Enter', 'Space', 'ArrowUp', 'ArrowDown',\n 'ArrowLeft', 'ArrowRight'];\n function onPressControl(e) {\n if (e.code === 'Escape') {\n e.preventDefault();\n showOverlayMenu();\n return;\n }\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n const key = keyMap.findIndex((c) => c === e.code);\n if (key !== -1) {\n e.preventDefault();\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, true, key);\n }\n }\n function onUnpressControl(e) {\n if (webSocket == null) {\n console.log('There is not websocket');\n return;\n }\n const key = keyMap.findIndex((c) => c === e.code);\n if (key !== -1) {\n e.preventDefault();\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendKeyDown)(webSocket, false, key);\n }\n }\n document.onselectstart = () => false;\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { ref: controlsRef, tabIndex: -1, className: \"overlay\", onKeyDown: onPressControl, onKeyUp: onUnpressControl },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"vertical-padding\" }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"controls\", onTouchStart: touchStartControls, onTouchMove: touchMoveControls, onTouchEnd: touchEndControls },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { tabIndex: -1, className: \"gear control\", onClick: showOverlayMenu, onTouchStart: showOverlayMenu },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"img\", { src: _msgba_constants__WEBPACK_IMPORTED_MODULE_1__.HOME_BUTTON_IMAGE, alt: \"Go to menu. (House icon)\" })),\n Object.keys(controls).map((key) => react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { tabIndex: -1, className: controls[key].classes, ref: controls[key].ref, key: key, onMouseDown: (e) => { mouseDown(e, controls[key].key); }, onMouseUp: (e) => { mouseUp(e, controls[key].key); } }, controls[key].sym)))));\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/overlay-controls.tsx?"); /***/ }), @@ -136,7 +136,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ OverlayMenu)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _msgba_components_close_button__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @msgba/components/close-button */ \"./js-src/components/close-button.tsx\");\n/* harmony import */ var _msgba_packet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @msgba/packet */ \"./js-src/packet.ts\");\n\n\n\n;\nfunction OverlayMenu({ hiddenMenu, setHiddenMenu, emulationStarted, setHiddenFormSelectFiles, screenRef, isFullscreen, setIsFullscreen, firstMenuElement, websocket, onSaveResponseLambdas }) {\n function exitMenu() {\n setHiddenMenu(true);\n }\n function openSelectFilesMenu() {\n setHiddenFormSelectFiles(false);\n }\n function toggleFullscreen() {\n if (isFullscreen) {\n document.exitFullscreen().catch((c) => { console.log(c); });\n setIsFullscreen(false);\n }\n if (screenRef.current != null) {\n screenRef.current.requestFullscreen().then(() => {\n setIsFullscreen(true);\n }).catch((error) => {\n console.log(error);\n });\n }\n }\n const styleSelectRom = {};\n if (emulationStarted) {\n styleSelectRom.display = 'none';\n }\n const styleMenu = {};\n if (hiddenMenu) {\n styleMenu.display = 'none';\n }\n let toggleFullscreenText = 'Set fullscreen';\n if (isFullscreen) {\n toggleFullscreenText = 'End fullscreen';\n }\n const saveButton = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const [saveIdentifier, setSaveidentifier] = react__WEBPACK_IMPORTED_MODULE_0__.useState(0n);\n function onSave() {\n if (websocket == null) {\n console.log('No websocket still');\n return;\n }\n const currentSave = saveIdentifier;\n setSaveidentifier((c) => c + 1n);\n console.log('Reachs here');\n onSaveResponseLambdas.set(currentSave, (saveFile) => {\n const anchor = document.createElement('a');\n const blobSaveResponseFile = new Blob([saveFile.buffer]);\n const fileReader = new FileReader();\n fileReader.onload = () => {\n if (typeof fileReader.result === 'string') {\n anchor.style.display = 'none';\n document.body.appendChild(anchor);\n anchor.href = fileReader.result;\n anchor.download = 'ruby.ss1';\n anchor.click();\n return true;\n }\n return false;\n };\n fileReader.readAsDataURL(blobSaveResponseFile);\n });\n console.log(onSaveResponseLambdas);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendSaveRequest)(websocket, currentSave);\n }\n const styleSave = {};\n if (!emulationStarted) {\n styleSave.display = 'none';\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { style: styleMenu, className: \"overlay-menu-div\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"overlay-menu-div-header\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_close_button__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { onClick: exitMenu })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"overlay-menu\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"ul\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { ref: firstMenuElement, style: styleSelectRom, onClick: openSelectFilesMenu, href: \"#\" }, \"Select rom\")),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { ref: saveButton, style: styleSave, onClick: onSave, href: \"#\" }, \"Save\")),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { onClick: toggleFullscreen, href: \"#\" }, toggleFullscreenText)),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { href: \"#\", onClick: exitMenu }, \"Exit\"))))));\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/overlay-menu.tsx?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ OverlayMenu)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _msgba_components_close_button__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @msgba/components/close-button */ \"./js-src/components/close-button.tsx\");\n/* harmony import */ var _msgba_packet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @msgba/packet */ \"./js-src/packet.ts\");\n\n\n\n;\nfunction OverlayMenu({ hiddenMenu, setHiddenMenu, emulationStarted, setHiddenFormSelectFiles, screenRef, isFullscreen, setIsFullscreen, overlayMenu, websocket, onSaveResponseLambdas }) {\n function exitMenu() {\n setHiddenMenu(true);\n }\n function openSelectFilesMenu() {\n setHiddenFormSelectFiles(false);\n }\n function toggleFullscreen() {\n if (isFullscreen) {\n document.exitFullscreen().catch((c) => { console.log(c); });\n setIsFullscreen(false);\n }\n if (screenRef.current != null) {\n screenRef.current.requestFullscreen().then(() => {\n setIsFullscreen(true);\n }).catch((error) => {\n console.log(error);\n });\n }\n }\n const styleSelectRom = {};\n if (emulationStarted) {\n styleSelectRom.display = 'none';\n }\n const styleMenu = {};\n if (hiddenMenu) {\n styleMenu.display = 'none';\n }\n let toggleFullscreenText = 'Set fullscreen';\n if (isFullscreen) {\n toggleFullscreenText = 'End fullscreen';\n }\n const saveButton = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const [saveIdentifier, setSaveidentifier] = react__WEBPACK_IMPORTED_MODULE_0__.useState(0n);\n function onSave() {\n if (websocket == null) {\n console.log('No websocket still');\n return;\n }\n const currentSave = saveIdentifier;\n setSaveidentifier((c) => c + 1n);\n console.log('Reachs here');\n onSaveResponseLambdas.set(currentSave, (saveFile) => {\n const anchor = document.createElement('a');\n const blobSaveResponseFile = new Blob([saveFile.buffer]);\n const fileReader = new FileReader();\n fileReader.onload = () => {\n if (typeof fileReader.result === 'string') {\n anchor.style.display = 'none';\n document.body.appendChild(anchor);\n anchor.href = fileReader.result;\n anchor.download = 'ruby.ss1';\n anchor.click();\n return true;\n }\n return false;\n };\n fileReader.readAsDataURL(blobSaveResponseFile);\n });\n console.log(onSaveResponseLambdas);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_2__.sendSaveRequest)(websocket, currentSave);\n }\n const styleSave = {};\n if (!emulationStarted) {\n styleSave.display = 'none';\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { style: styleMenu, className: \"overlay-menu-div\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"overlay-menu-div-header\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_close_button__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { onClick: exitMenu })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"overlay-menu\", ref: overlayMenu },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"ul\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { style: styleSelectRom, onClick: openSelectFilesMenu, href: \"#\" }, \"Select rom\")),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { ref: saveButton, style: styleSave, onClick: onSave, href: \"#\" }, \"Save\")),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { onClick: toggleFullscreen, href: \"#\" }, toggleFullscreenText)),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"li\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { href: \"#\", onClick: exitMenu }, \"Exit\"))))));\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/overlay-menu.tsx?"); /***/ }), @@ -156,7 +156,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Page)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _msgba_components_center_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @msgba/components/center-element */ \"./js-src/components/center-element.tsx\");\n/* harmony import */ var _msgba_components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @msgba/components/canvas-gba-emulator */ \"./js-src/components/canvas-gba-emulator.tsx\");\n/* harmony import */ var _msgba_components_overlay_controls__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @msgba/components/overlay-controls */ \"./js-src/components/overlay-controls.tsx\");\n/* harmony import */ var _msgba_components_overlay_menu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @msgba/components/overlay-menu */ \"./js-src/components/overlay-menu.tsx\");\n/* harmony import */ var _msgba_components_overlay_select_files__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @msgba/components/overlay-select-files */ \"./js-src/components/overlay-select-files.tsx\");\n/* harmony import */ var _msgba_packet__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @msgba/packet */ \"./js-src/packet.ts\");\n/* harmony import */ var _msgba_endian__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @msgba/endian */ \"./js-src/endian.ts\");\n/* harmony import */ var _msgba_constants__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @msgba/constants */ \"./js-src/constants.ts\");\n\n\n\n\n\n\n\n\n\nfunction onWebSocketPacket(event, canvas, ctx, isGBC, setIsGBC, onSaveResponseLambdas) {\n const buffer = event.data;\n let packetU8 = new Uint8Array(buffer);\n const id = _msgba_endian__WEBPACK_IMPORTED_MODULE_7__[\"default\"].byteArrayToU64BigEndian(packetU8.slice(0, 8));\n packetU8 = packetU8.slice(8, packetU8.length);\n const size = _msgba_endian__WEBPACK_IMPORTED_MODULE_7__[\"default\"].byteArrayToU64BigEndian(packetU8.slice(0, 8));\n console.log(size);\n const rawData = packetU8.slice(8, Number(size) + 8);\n console.log(rawData.length);\n packetU8 = null;\n handlePacket(id, rawData, canvas, setIsGBC, onSaveResponseLambdas).catch((error) => {\n console.log('Error handling packet', error);\n });\n}\nasync function handlePacket(id, rawData, canvas, setIsGBC, onSaveResponseLambdas) {\n switch (id) {\n case _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.PACKET_ID_SEND_FRAME:\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_6__.handleSendFrame)(rawData, canvas, setIsGBC);\n break;\n case _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.PACKET_ID_SAVE_RESPONSE:\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_6__.handleSaveResponse)(rawData, canvas, onSaveResponseLambdas);\n break;\n default:\n throw new Error(`Received unknown packet ${id}`);\n }\n}\nfunction Page() {\n const [isGBC, setIsGBC] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n const screenDimensions = useScreenDimensions(isGBC);\n const emulatorDimensions = calculateSizeEmulator(screenDimensions, isGBC);\n const canvasRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n function resizeCanvas() {\n const canvas = canvasRef.current;\n if (canvas == null) {\n return;\n }\n if (emulatorDimensions.width === undefined || emulatorDimensions.height === undefined) {\n return;\n }\n canvas.width = emulatorDimensions.width;\n canvas.height = emulatorDimensions.height;\n const ctx = canvas.getContext('2d');\n if (ctx == null) {\n return;\n }\n fillBlack(canvas, ctx);\n }\n const [hiddenFormSelectFiles, setHiddenFormSelectFiles] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(resizeCanvas, [emulatorDimensions]);\n const refInputRom = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const refInputSaveState = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const [emulationStarted, setEmulationStarted] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n const [hiddenMenu, setHiddenMenu] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);\n const [webSocket, setWebSocket] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [onSaveResponseLambdas] = react__WEBPACK_IMPORTED_MODULE_0__.useState(new Map());\n const controlsRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {\n console.log('Focusing the main screen');\n setTimeout(() => {\n if (!hiddenFormSelectFiles) {\n if (refInputRom.current != null) {\n refInputRom.current.focus();\n }\n return;\n }\n if (!hiddenMenu) {\n if (firstMenuElement.current != null) {\n firstMenuElement.current.focus();\n }\n return;\n }\n if (controlsRef.current != null && hiddenMenu) {\n controlsRef.current.focus();\n }\n }, 100);\n }, [hiddenMenu, hiddenFormSelectFiles]);\n function handleClickStartEmulationButton(e) {\n e.preventDefault();\n if (canvasRef.current == null) {\n alert('Canvas does not exists?');\n return;\n }\n const ctx = canvasRef.current.getContext('2d');\n if (ctx == null) {\n alert('Unable to create canvas context, doing nothing');\n return;\n }\n const inputRom = refInputRom.current;\n const inputSaveState = refInputSaveState.current;\n if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {\n alert('Unable to read the files ');\n return;\n }\n if (inputRom.files.length === 0) {\n alert('There is no rom still');\n return;\n }\n if (inputSaveState.files.length === 0) {\n alert('There is no savestate still');\n return;\n }\n const romFile = inputRom.files[0];\n const savestateFile = inputSaveState.files[0];\n romFile.arrayBuffer().then((romBuffer) => {\n savestateFile.arrayBuffer().then((savestateBuffer) => {\n const romArray = new Uint8Array(romBuffer);\n const savestateArray = new Uint8Array(savestateBuffer);\n const locationProtocol = window.location.protocol;\n if (locationProtocol == null) {\n return;\n }\n const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws';\n const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`);\n setWebSocket(webSocket);\n webSocket.binaryType = 'arraybuffer';\n webSocket.onclose = (message) => {\n setEmulationStarted(false);\n console.log('Closing websocket.');\n setWebSocket(null);\n };\n webSocket.onopen = () => {\n console.log('Opened websocket.');\n setEmulationStarted(true);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_6__.sendHello)(webSocket, romArray, savestateArray);\n setHiddenMenu(true);\n setHiddenFormSelectFiles(true);\n };\n webSocket.addEventListener('message', (event) => {\n onWebSocketPacket(event, canvasRef.current, ctx, isGBC, setIsGBC, onSaveResponseLambdas);\n });\n }).catch((c) => {\n console.log('Unable to convert file to array_buffer');\n });\n }).catch((c) => {\n console.log('Unable to convert file to array_buffer');\n });\n }\n const onStartEmulation = (e) => {\n handleClickStartEmulationButton(e);\n };\n const firstMenuElement = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const screenRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const [isFullscreen, setIsFullscreen] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { ref: screenRef },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_overlay_controls__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { controlsRef: controlsRef, firstMenuElement: firstMenuElement, setHiddenMenu: setHiddenMenu, webSocket: webSocket }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_overlay_menu__WEBPACK_IMPORTED_MODULE_4__[\"default\"], { hiddenMenu: hiddenMenu, setHiddenMenu: setHiddenMenu, emulationStarted: emulationStarted, setHiddenFormSelectFiles: setHiddenFormSelectFiles, screenRef: screenRef, isFullscreen: isFullscreen, setIsFullscreen: setIsFullscreen, firstMenuElement: firstMenuElement, websocket: webSocket, onSaveResponseLambdas: onSaveResponseLambdas }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_overlay_select_files__WEBPACK_IMPORTED_MODULE_5__[\"default\"], { hiddenFormSelectFiles: hiddenFormSelectFiles, setHiddenFormSelectFiles: setHiddenFormSelectFiles, refInputRom: refInputRom, refInputSaveState: refInputSaveState, onStartEmulation: onStartEmulation }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { full: true },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { canvasRef: canvasRef })))));\n}\nfunction getScreenDimensions() {\n return {\n width: document.body.clientWidth,\n height: document.body.clientHeight\n };\n}\nfunction useScreenDimensions(isGBC) {\n const [screenDimensions, setScreenDimensions] = react__WEBPACK_IMPORTED_MODULE_0__.useState(getScreenDimensions());\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {\n function onResize() {\n setScreenDimensions(getScreenDimensions());\n }\n window.addEventListener('resize', onResize);\n return () => {\n window.removeEventListener('resize', onResize);\n };\n }, [isGBC]);\n return screenDimensions;\n}\nfunction fillBlack(canvas, ctx) {\n ctx.beginPath();\n ctx.rect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#0E0E10';\n ctx.fill();\n}\n;\nfunction calculateSizeEmulator(screenDimensions, isGBC) {\n if (screenDimensions.width === undefined || screenDimensions.height === undefined) {\n console.error(screenDimensions, 'screenDimensions has undefined fields');\n return {};\n }\n const width = screenDimensions.width;\n const height = screenDimensions.height;\n const emulatorDimensions = {};\n const minWidth = !isGBC ? _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_WIDTH_GBA : _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_WIDTH_GBC;\n const minHeight = !isGBC ? _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_HEIGHT_GBA : _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_HEIGHT_GBC;\n if (width < minWidth || height < minHeight) {\n return {\n width: minWidth,\n height: minHeight\n };\n }\n const ratioWidth = width / minWidth;\n const ratioHeight = height / minHeight;\n if (ratioWidth < ratioHeight) {\n emulatorDimensions.width = minWidth * ratioWidth;\n emulatorDimensions.height = minHeight * ratioWidth;\n }\n else {\n emulatorDimensions.height = minHeight * ratioHeight;\n emulatorDimensions.width = minWidth * ratioHeight;\n }\n return emulatorDimensions;\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/page.tsx?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Page)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _msgba_components_center_element__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @msgba/components/center-element */ \"./js-src/components/center-element.tsx\");\n/* harmony import */ var _msgba_components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @msgba/components/canvas-gba-emulator */ \"./js-src/components/canvas-gba-emulator.tsx\");\n/* harmony import */ var _msgba_components_overlay_controls__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @msgba/components/overlay-controls */ \"./js-src/components/overlay-controls.tsx\");\n/* harmony import */ var _msgba_components_overlay_menu__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @msgba/components/overlay-menu */ \"./js-src/components/overlay-menu.tsx\");\n/* harmony import */ var _msgba_components_overlay_select_files__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @msgba/components/overlay-select-files */ \"./js-src/components/overlay-select-files.tsx\");\n/* harmony import */ var _msgba_packet__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @msgba/packet */ \"./js-src/packet.ts\");\n/* harmony import */ var _msgba_endian__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @msgba/endian */ \"./js-src/endian.ts\");\n/* harmony import */ var _msgba_constants__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @msgba/constants */ \"./js-src/constants.ts\");\n\n\n\n\n\n\n\n\n\nfunction onWebSocketPacket(event, canvas, ctx, isGBC, setIsGBC, onSaveResponseLambdas) {\n const buffer = event.data;\n let packetU8 = new Uint8Array(buffer);\n const id = _msgba_endian__WEBPACK_IMPORTED_MODULE_7__[\"default\"].byteArrayToU64BigEndian(packetU8.slice(0, 8));\n packetU8 = packetU8.slice(8, packetU8.length);\n const size = _msgba_endian__WEBPACK_IMPORTED_MODULE_7__[\"default\"].byteArrayToU64BigEndian(packetU8.slice(0, 8));\n console.log(size);\n const rawData = packetU8.slice(8, Number(size) + 8);\n console.log(rawData.length);\n packetU8 = null;\n handlePacket(id, rawData, canvas, setIsGBC, onSaveResponseLambdas).catch((error) => {\n console.log('Error handling packet', error);\n });\n}\nasync function handlePacket(id, rawData, canvas, setIsGBC, onSaveResponseLambdas) {\n switch (id) {\n case _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.PACKET_ID_SEND_FRAME:\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_6__.handleSendFrame)(rawData, canvas, setIsGBC);\n break;\n case _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.PACKET_ID_SAVE_RESPONSE:\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_6__.handleSaveResponse)(rawData, canvas, onSaveResponseLambdas);\n break;\n default:\n throw new Error(`Received unknown packet ${id}`);\n }\n}\nfunction Page() {\n const [isGBC, setIsGBC] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n const screenDimensions = useScreenDimensions(isGBC);\n const emulatorDimensions = calculateSizeEmulator(screenDimensions, isGBC);\n const canvasRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n function resizeCanvas() {\n const canvas = canvasRef.current;\n if (canvas == null) {\n return;\n }\n if (emulatorDimensions.width === undefined || emulatorDimensions.height === undefined) {\n return;\n }\n canvas.width = emulatorDimensions.width;\n canvas.height = emulatorDimensions.height;\n const ctx = canvas.getContext('2d');\n if (ctx == null) {\n return;\n }\n fillBlack(canvas, ctx);\n }\n const [hiddenFormSelectFiles, setHiddenFormSelectFiles] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(resizeCanvas, [emulatorDimensions]);\n const refInputRom = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const refInputSaveState = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const [emulationStarted, setEmulationStarted] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n const [hiddenMenu, setHiddenMenu] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);\n const [webSocket, setWebSocket] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [onSaveResponseLambdas] = react__WEBPACK_IMPORTED_MODULE_0__.useState(new Map());\n const controlsRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {\n console.log('Focusing the main screen');\n setTimeout(() => {\n if (!hiddenFormSelectFiles) {\n if (refInputRom.current != null) {\n refInputRom.current.focus();\n }\n return;\n }\n if (!hiddenMenu) {\n if (overlayMenu.current == null) {\n return;\n }\n const allAnchors = overlayMenu.current.querySelectorAll('a');\n for (const anchor of allAnchors) {\n if (anchor.style.display === 'none') {\n continue;\n }\n anchor.focus();\n break;\n }\n return;\n }\n if (controlsRef.current != null && hiddenMenu) {\n controlsRef.current.focus();\n }\n }, 100);\n }, [hiddenMenu, hiddenFormSelectFiles]);\n function handleClickStartEmulationButton(e) {\n e.preventDefault();\n if (canvasRef.current == null) {\n alert('Canvas does not exists?');\n return;\n }\n const ctx = canvasRef.current.getContext('2d');\n if (ctx == null) {\n alert('Unable to create canvas context, doing nothing');\n return;\n }\n const inputRom = refInputRom.current;\n const inputSaveState = refInputSaveState.current;\n if (inputRom == null || inputSaveState == null || inputRom.files == null || inputSaveState.files == null) {\n alert('Unable to read the files ');\n return;\n }\n if (inputRom.files.length === 0) {\n alert('There is no rom still');\n return;\n }\n if (inputSaveState.files.length === 0) {\n alert('There is no savestate still');\n return;\n }\n const romFile = inputRom.files[0];\n const savestateFile = inputSaveState.files[0];\n romFile.arrayBuffer().then((romBuffer) => {\n savestateFile.arrayBuffer().then((savestateBuffer) => {\n const romArray = new Uint8Array(romBuffer);\n const savestateArray = new Uint8Array(savestateBuffer);\n const locationProtocol = window.location.protocol;\n if (locationProtocol == null) {\n return;\n }\n const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws';\n const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`);\n setWebSocket(webSocket);\n webSocket.binaryType = 'arraybuffer';\n webSocket.onclose = (message) => {\n setEmulationStarted(false);\n console.log('Closing websocket.');\n setWebSocket(null);\n };\n webSocket.onopen = () => {\n console.log('Opened websocket.');\n setEmulationStarted(true);\n (0,_msgba_packet__WEBPACK_IMPORTED_MODULE_6__.sendHello)(webSocket, romArray, savestateArray);\n setHiddenMenu(true);\n setHiddenFormSelectFiles(true);\n };\n webSocket.addEventListener('message', (event) => {\n onWebSocketPacket(event, canvasRef.current, ctx, isGBC, setIsGBC, onSaveResponseLambdas);\n });\n }).catch((c) => {\n console.log('Unable to convert file to array_buffer');\n });\n }).catch((c) => {\n console.log('Unable to convert file to array_buffer');\n });\n }\n const onStartEmulation = (e) => {\n handleClickStartEmulationButton(e);\n };\n const overlayMenu = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const screenRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const [isFullscreen, setIsFullscreen] = react__WEBPACK_IMPORTED_MODULE_0__.useState(false);\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { ref: screenRef },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_overlay_controls__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { controlsRef: controlsRef, setHiddenMenu: setHiddenMenu, webSocket: webSocket }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_overlay_menu__WEBPACK_IMPORTED_MODULE_4__[\"default\"], { hiddenMenu: hiddenMenu, setHiddenMenu: setHiddenMenu, emulationStarted: emulationStarted, setHiddenFormSelectFiles: setHiddenFormSelectFiles, screenRef: screenRef, isFullscreen: isFullscreen, setIsFullscreen: setIsFullscreen, overlayMenu: overlayMenu, websocket: webSocket, onSaveResponseLambdas: onSaveResponseLambdas }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_overlay_select_files__WEBPACK_IMPORTED_MODULE_5__[\"default\"], { hiddenFormSelectFiles: hiddenFormSelectFiles, setHiddenFormSelectFiles: setHiddenFormSelectFiles, refInputRom: refInputRom, refInputSaveState: refInputSaveState, onStartEmulation: onStartEmulation }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_center_element__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { full: true },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_msgba_components_canvas_gba_emulator__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { canvasRef: canvasRef })))));\n}\nfunction getScreenDimensions() {\n return {\n width: document.body.clientWidth,\n height: document.body.clientHeight\n };\n}\nfunction useScreenDimensions(isGBC) {\n const [screenDimensions, setScreenDimensions] = react__WEBPACK_IMPORTED_MODULE_0__.useState(getScreenDimensions());\n react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {\n function onResize() {\n setScreenDimensions(getScreenDimensions());\n }\n window.addEventListener('resize', onResize);\n return () => {\n window.removeEventListener('resize', onResize);\n };\n }, [isGBC]);\n return screenDimensions;\n}\nfunction fillBlack(canvas, ctx) {\n ctx.beginPath();\n ctx.rect(0, 0, canvas.width, canvas.height);\n ctx.fillStyle = '#0E0E10';\n ctx.fill();\n}\n;\nfunction calculateSizeEmulator(screenDimensions, isGBC) {\n if (screenDimensions.width === undefined || screenDimensions.height === undefined) {\n console.error(screenDimensions, 'screenDimensions has undefined fields');\n return {};\n }\n const width = screenDimensions.width;\n const height = screenDimensions.height;\n const emulatorDimensions = {};\n const minWidth = !isGBC ? _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_WIDTH_GBA : _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_WIDTH_GBC;\n const minHeight = !isGBC ? _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_HEIGHT_GBA : _msgba_constants__WEBPACK_IMPORTED_MODULE_8__.MIN_HEIGHT_GBC;\n if (width < minWidth || height < minHeight) {\n return {\n width: minWidth,\n height: minHeight\n };\n }\n const ratioWidth = width / minWidth;\n const ratioHeight = height / minHeight;\n if (ratioWidth < ratioHeight) {\n emulatorDimensions.width = minWidth * ratioWidth;\n emulatorDimensions.height = minHeight * ratioWidth;\n }\n else {\n emulatorDimensions.height = minHeight * ratioHeight;\n emulatorDimensions.width = minWidth * ratioHeight;\n }\n return emulatorDimensions;\n}\n\n\n//# sourceURL=webpack://MSGBA-Web/./js-src/components/page.tsx?"); /***/ }),