UNPKG

mz700-js

Version:
823 lines (754 loc) 30 kB
"use strict"; /* tslint:disable: no-var-requires no-console */ require("fullscrn"); import BBox from "b-box"; import dock_n_liquid from "dock-n-liquid"; import MZ700 from "./mz700"; import mz700scrn from "../lib/mz700-scrn"; import MZBeep from "../lib/mz-beep"; import MZ_Tape from "../lib/mz-tape"; import MZ_TapeHeader from "../lib/mz-tape-header"; import Z80 from "../Z80/Z80.js"; import Z80_assemble from "../Z80/assembler"; import NumberUtil from "../lib/number-util"; import parseAddress from "../lib/parse-addr"; import parseRequest from "../lib/parse-request"; import requestJsonp from "../lib/jsonp"; import {getDeviceType} from "../lib/user-agent-util"; require("../lib/jquery-plugin/jquery.mz700-kb.js"); require("../lib/jquery-plugin/jquery.Z80-reg.js"); require("../lib/jquery-plugin/jquery.asmview.js"); require("../lib/jquery-plugin/jquery.asmlist.js"); require("../lib/jquery-plugin/jquery.tabview.js"); require("../lib/jquery-plugin/jquery.Z80-mem.js"); require("../lib/jquery-plugin/jquery.mz700-img-button.js"); require("../lib/jquery-plugin/jquery.mz700-scrn.js"); require("../lib/jquery-plugin/jquery.mz-sound-control.js"); require("../lib/jquery-plugin/jquery.emu-speed-control.js"); require("../lib/jquery-plugin/jquery.mz-data-recorder.js"); require("../lib/jquery-plugin/jquery.toggle-button.js"); require("../lib/jquery-plugin/jquery.tool-window.js"); type MZ700ImgButton = JQuery<HTMLElement> & { MZ700ImgButton: (method:string, ...any) => MZ700ImgButton }; type mz700keyboard = JQuery<HTMLElement> & { mz700keyboard: (method:string, ...any) => mz700keyboard }; type ToggleButton = JQuery<HTMLElement> & { ToggleButton: (method:string, ...any) => ToggleButton }; type MZSoundControl = JQuery<HTMLElement> & { MZSoundControl: (method:string, ...any) => MZSoundControl }; type EmuSpeedControl = JQuery<HTMLElement> & { EmuSpeedControl: (method:string, ...any) => EmuSpeedControl }; type MZDataRecorder = JQuery<HTMLElement> & { MZDataRecorder: (method:string, ...any) => MZDataRecorder }; type Z80RegView = JQuery<HTMLElement> & { Z80RegView: (method:string, ...any) => Z80RegView }; type ToolWindow = JQuery<HTMLElement> & { ToolWindow: (method:string, ...any) => ToolWindow }; type dumplist = JQuery<HTMLElement> & { dumplist: (method:string, ...any) => dumplist }; type asmview = JQuery<HTMLElement> & { asmview: (method:string, ...any) => asmview, asmlist: (method:string, ...any) => asmview, }; /** * MONITOR ROM を読み込む。 * @param {string} filename ROM filename * @return {Array<number>} Uint8Arrayを配列に変換したもの */ async function loadMonitorROM(filename):Promise<number[]> { const monitorRom = await new Promise(resolve => { const xhr = new XMLHttpRequest(); xhr.open("GET", `./mz_newmon/ROMS/${filename}`, true); xhr.responseType = "arraybuffer"; xhr.onload = () => { const arrayBuffer = xhr.response; if (arrayBuffer) { const byteArray = Array.from(new Uint8Array(arrayBuffer)); resolve(byteArray); } }; xhr.send(null); }) as number[]; return monitorRom; } /** * Load an IMG element. * @param {string} src source attribute value. * @param {string|null} alt alt attribute value. * @param {any} width (Optional) Width attribute value. * @param {any} height (Optional) Height attibute value. * @returns {Promise<Image>} a promise to be resolved by image element. */ function loadImage(src, alt, width?, height?) { return new Promise((resolve, reject) => { const image = new Image(width, height); image.onload = () => { resolve(image); }; image.onerror = () => { reject(new Error(`Fail to load an image from ${src}`)); }; image.src = src; image.setAttribute("alt", alt); image.setAttribute("title", alt); }); } async function loadPackageJson():Promise<{name:string, version:string, description:string}> { const response = await fetch("/mz700-js/package.json"); if(!response.ok) { throw new Error("Fail to load package.json"); } return await response.json(); } async function createUI(mz700js, mz700screen, canvas) { const pageRequest = parseRequest(); mz700screen = $(mz700screen); const [ packageJson, monitorRom, imgBtnResetOff, imgBtnResetOn, imgBtnRunOff, imgBtnRunOn, imgBtnStopOff, imgBtnStopOn, imgBtnStepOff, imgBtnStepOn, imgBtnStepDi, imgBtnScrnKbOff, imgBtnScrnKbOn, imgBtnFullScrnOff, imgBtnFullScrnOn, ] = await Promise.all([ loadPackageJson(), loadMonitorROM("NEWMON7.ROM"), loadImage("image/btnReset-off.png", "Reset"), loadImage("image/btnReset-on.png", "Reset"), loadImage("image/btnRun-off.png", "[Ctrl]+[F9] Run"), loadImage("image/btnRun-on.png", "[Ctrl]+[F9] Run"), loadImage("image/btnStop-off.png", "[Ctrl]+[F9] Stop"), loadImage("image/btnStop-on.png", "[Ctrl]+[F9] Stop"), loadImage("image/btnStepIn-off.png", "[F9] Step"), loadImage("image/btnStepIn-on.png", "[F9] Step"), loadImage("image/btnStepIn-disabled.png", "[F9] Step"), loadImage("image/btnKeyboard-off.png", "Open Keyboard"), loadImage("image/btnKeyboard-on.png", "Close Keyboard"), loadImage("image/btnFullscreen-off.png", "Fullscreen"), loadImage("image/btnFullscreen-on.png", "Cancel Fullscreen"), ]); // Set module version to the page title { const {name, version, description} = packageJson as {name:string, version:string, description:string}; const pageTitle = `${description}(${name}@${version})`; $("title").html(pageTitle); $("h1 .mz700scrn").html(pageTitle); } mz700js.setMonitorRom(monitorRom); // Stop on break point mz700js.subscribe("onBreak", ()=> mz700js.stop()); // MZ-700 Beep sound const mzBeep = new MZBeep(); mz700js.subscribe("startSound", freq => mzBeep.startSound(freq[0])); mz700js.subscribe("stopSound", () => mzBeep.stopSound()); // Control panel const mz700container = $("#mz700container"); const ctrlPanel = $("<div/>").attr("id", "control-panel").css("display", "none"); mz700container.append(ctrlPanel); const resizeScreen = () => { dock_n_liquid.select($("#liquid-panel-MZ-700").get(0)).layout(); const bboxContainer = new BBox(mz700container.get(0)); const bboxScreen = new BBox(mz700screen.get(0)); const containerSize = bboxContainer.getSize(); containerSize._h -= bboxScreen.px("border-top-width"); containerSize._h -= bboxScreen.px("border-bottom-width"); const orgSize = new BBox.Size(320,200); const innerSize = containerSize.getMaxInscribedSize(orgSize); const margin = new BBox.Size((containerSize._w - innerSize._w) / 2, 0); if(margin._w < 0) { margin._w = 0; } mz700screen .css("margin-left", margin._w + "px") .css("margin-top", margin._h + "px") .css("width", innerSize._w + "px") .css("height", innerSize._h + "px"); if(ctrlPanel.is(":visible")) { const phifBBox = new BBox(ctrlPanel.get(0)); const phifSize = phifBBox.getSize(); const phifMargin = new BBox.Size( (containerSize._w - phifSize._w) / 2, innerSize._h - phifSize._h); if(phifMargin._w < 0) { phifMargin._w = 0; } if(phifMargin._h < 0) { phifMargin._h = 0; } ctrlPanel.css("margin-left", phifMargin._w + "px") .css("margin-top", phifMargin._h + "px"); } }; /** * Show the panel to operate MZ-700. * @param {Function} resize resize handler. * @returns {undefined} */ const showCtrlPanel = () => { if(!ctrlPanel.is(":visible")) { ctrlPanel.addClass("hover"); ctrlPanel.show(0, () => { resizeScreen(); }); } }; /** * Hide the panel to operate MZ-700. * @param {Function} resize resize handler. * @returns {undefined} */ const hideCtrlPanel = () => { if(ctrlPanel.is(":visible")) { ctrlPanel.removeClass("hover"); ctrlPanel.hide(0, ()=> { resizeScreen(); }); } }; let tidHideCtrlPanel = null; const installHideCtrlPanelTimer = () => { tidHideCtrlPanel = setTimeout(() => { hideCtrlPanel(); tidHideCtrlPanel = null; }, 1000); }; const cancelHideCtrlPanelTimer = () => { if(tidHideCtrlPanel) { clearTimeout(tidHideCtrlPanel); tidHideCtrlPanel = null; } }; const deviceType = getDeviceType(); if(deviceType === "pc") { mz700container.mouseenter(() => { cancelHideCtrlPanelTimer(); showCtrlPanel(); installHideCtrlPanelTimer(); }).mouseleave(() => { cancelHideCtrlPanelTimer(); hideCtrlPanel(); }); ctrlPanel.mouseenter(event => { event.stopPropagation(); cancelHideCtrlPanelTimer(); }).mouseleave(event =>{ event.stopPropagation(); cancelHideCtrlPanelTimer(); installHideCtrlPanelTimer(); }); } // Reset Button const btnReset = ($("<button/>") as MZ700ImgButton).MZ700ImgButton("create", { img: imgBtnResetOff, }).click(async () => { await mz700js.stop(); await mz700js.reset(); await mz700js.start(); await dataRecorder.MZDataRecorder("updateCmtSlot"); }).hover( () => btnReset.MZ700ImgButton("setImg", imgBtnResetOn), () => btnReset.MZ700ImgButton("setImg", imgBtnResetOff) ); // MZ-700 Running status let _isRunning = false; // Run/Stop/Step Button const btnStart = ($("<button/>") as MZ700ImgButton).MZ700ImgButton("create", { img: imgBtnRunOff, }).click(() => { _isRunning ? mz700js.stop() : mz700js.start(); }).hover( () => btnStart.MZ700ImgButton("setImg", _isRunning ? imgBtnStopOn : imgBtnRunOn), () => btnStart.MZ700ImgButton("setImg", _isRunning ? imgBtnStopOff : imgBtnRunOff), ); const btnStep = ($("<button/>") as MZ700ImgButton).MZ700ImgButton("create", { img: imgBtnStepOff, }).click( () => mz700js.step() ).hover( () => { if(!_isRunning) { btnStep.MZ700ImgButton("setImg", imgBtnStepOn); } }, () => { if(!_isRunning) { btnStep.MZ700ImgButton("setImg", imgBtnStepOff); } } ); // Operate the emulation state by key window.addEventListener("keyup", async event => { if(event.code === "F9") { if(event.ctrlKey) { event.stopPropagation(); _isRunning ? mz700js.stop() : mz700js.start(); } else if(!event.shiftKey) { event.stopPropagation(); _isRunning ? mz700js.stop() : mz700js.step(); } } }); // Emulation started mz700js.subscribe("start", async () => { if(!_isRunning && regVisibility) { await Z80RegViewAutoUpdate(true); } _isRunning = true; $(".MZ-700").addClass("running"); btnStart.MZ700ImgButton("setImg", imgBtnStopOff); btnStep.prop('disabled', 'disabled') btnStep.MZ700ImgButton("setImg", imgBtnStepDi); asmView.asmview("clearCurrentLine"); btnExecImm.prop("disabled", true); }); // Emulation stopped mz700js.subscribe("stop", async () => { if(_isRunning && regVisibility) { await Z80RegViewAutoUpdate(false); } _isRunning = false; $(".MZ-700").removeClass("running"); btnStart.MZ700ImgButton("setImg", imgBtnRunOff); btnStep.prop('disabled', ''); btnStep.MZ700ImgButton("setImg", imgBtnStepOff); const [reg] = await mz700js.getRegister(); asmView.asmview("currentLine", reg.PC); btnExecImm.prop("disabled", false); }); // Software keyboard const keyboard = $("<div/>").css("display", "none").addClass("keyboard") as mz700keyboard; ctrlPanel.append(keyboard); (keyboard as mz700keyboard).mz700keyboard("create", mz700js); if(getDeviceType() === "pc") { mz700container.mouseenter(() => { keyboard.mz700keyboard("acceptKey", true); }).mouseleave(() => { keyboard.mz700keyboard("acceptKey", false); }); ctrlPanel.mouseenter(event => { event.stopPropagation(); keyboard.mz700keyboard("acceptKey", true); }); } // Create Screen keyboard button. const screenKbButton = ($("<button/>") as ToggleButton).ToggleButton("create", { img: imgBtnScrnKbOff, imgOff: imgBtnScrnKbOff, imgOn: imgBtnScrnKbOn, alt: "Keyboard", on: ()=>keyboard.show(0, resizeScreen), off: ()=>keyboard.hide(0, resizeScreen), }); // Create Full screen button. const fullscreenButton = ($("<button/>") as ToggleButton).ToggleButton("create", { img: imgBtnFullScrnOff, imgOff: imgBtnFullScrnOff, imgOn: imgBtnFullScrnOn, autoState: false, on: async ()=>{ if(document.fullscreenElement !== document.body) { await document.body.requestFullscreen(); keyboard.mz700keyboard("acceptKey", true); } }, off: ()=>{ if(document.fullscreenElement === document.body) { document.exitFullscreen(); } }, }); const emulationPanel = $("<div/>").addClass("emulation-panel"); emulationPanel .append(($("<span/>") as MZSoundControl).MZSoundControl("create", mzBeep)) .append(btnStart).append(btnReset).append(btnStep) .append(($("<span/>") as EmuSpeedControl).EmuSpeedControl( "create", mz700js, MZ700.Z80_CLOCK)) .append(screenKbButton) .append(fullscreenButton); ctrlPanel.append(emulationPanel) // Data Recorder UI const dataRecorder = ($("<div/>") as MZDataRecorder).MZDataRecorder("create", { mz700js, onRecPushed: ()=>mz700js.dataRecorder_pushRec(), onPlayPushed: ()=>mz700js.dataRecorder_pushPlay(), onStopPushed: ()=>mz700js.dataRecorder_pushStop(), onEjectPushed: ()=>mz700js.dataRecorder_ejectCmt(), }); // Events handling mz700js.subscribe("onStartDataRecorder", ()=>dataRecorder.MZDataRecorder("start")); mz700js.subscribe("onStopDataRecorder", ()=>dataRecorder.MZDataRecorder("stop")); ctrlPanel.append(dataRecorder) const mztButtons = await new Promise( resolve => { requestJsonp("mztList", "https://takamin.github.io/MZ-700/mzt/mzt-list.js", files => { const div = $("<div/>"); files.forEach(mzt => { div.append( $("<button/>").attr("type", "button") .css("padding", 0).css("height", "24px") .css("border", "solid 0px transparent") .css("padding", 0).css("margin", "4px 2px") .append($("<span/>").addClass("mz700scrn") .attr("charSize", "8").attr("padding", "1") .attr("color", mzt.mz700_buttonStyle.color) .attr("bgColor", mzt.mz700_buttonStyle.bgColor) .html(mzt.name)) .click(() => { window.location.href = pageRequest.path + "?mzt=" + mzt.path; })); }); resolve(div); }); }); ctrlPanel.append(mztButtons as JQuery<HTMLElement>); const dockPanelRight = $("#dock-panel-right").css("display", "none"); // Register View const regview = ($("<div/>") as Z80RegView).Z80RegView("create"); const wndRegView = $("<div class='register-monitor tool-window close' title='REGISTER'/>"); dockPanelRight.append(wndRegView); let regUpdTid = null; let regVisibility = false; const Z80RegViewUpdateRegister = async () => { const [reg, _reg] = await mz700js.getRegister(); regview.Z80RegView("updateRegister", [reg, _reg]); } const Z80RegViewAutoUpdate = async status => { if(status) { if(!regUpdTid) { regUpdTid = setInterval(()=>Z80RegViewUpdateRegister(), 50); } } else { if(regUpdTid) { clearInterval(regUpdTid); regUpdTid = null; } await Z80RegViewUpdateRegister(); } }; const Z80RegViewVisibility = async status => { if(regVisibility !== status) { regVisibility = status; if(_isRunning) { if(regVisibility) { await Z80RegViewAutoUpdate(true); } else { await Z80RegViewAutoUpdate(false); } } } }; (wndRegView .append($("<div/>").css("display", "inline-block").append(regview)) as ToolWindow) .ToolWindow("create", { onOpened: () => Z80RegViewVisibility(true), onClosed: () => Z80RegViewVisibility(false), }); // Create dump list const dumplist = ($("<div/>") as dumplist).dumplist("init", {mz700js}); const wndDumpList = $("<div class='tool-window memory open' title='MEMORY'/>"); dockPanelRight.append(wndDumpList); (wndDumpList .append(dumplist.dumplist("addrSpecifier")) .append(dumplist) as ToolWindow).ToolWindow("create"); // Create assemble list const asmView = ($("<div/>") as asmview).asmview("create", { onSetBreak: async (addr, size, state) => (state ? await mz700js.addBreak(addr, size) : await mz700js.removeBreak(addr, size)) }); const wndAsmList = $("<div class='tool-window open' title='Z80 ASM'/>"); dockPanelRight.append(wndAsmList); (wndAsmList.append(asmView) as ToolWindow).ToolWindow("create"); const asmlistAssemble = async (asmlistObj, asmsrc) => { asmlistObj.asmlist("text", asmsrc); const shouldBeResumed = _isRunning; if(shouldBeResumed) { await mz700js.stop(); } const assembled = Z80_assemble.assemble([asmsrc]).obj[0]; await mz700js.writeAsmCode( assembled ); asmlistObj.asmlist("writeList", assembled.list, await mz700js.getBreakPoints()); if(shouldBeResumed) { await mz700js.start(); } }; // Show a sample assemble source const asmlistMzt = asmView.asmview("newAsmList", "mzt", "PCG-700 sample"); const asmlistSrc = await new Promise(resolve => $.get("./MZ-700/pcg700-sample.asm", {}, resolve)); await asmlistAssemble(asmlistMzt, asmlistSrc); // Disassemble MONITOR ROM and show that source. const getText = (url:string):Promise<string> => { return new Promise(resolve => $.get(url, {}, resolve)); }; const readme = await getText("./mz_newmon/newmon_readme.txt"); console.log(readme); const commandHelp = await getText("./mz_newmon/newmon_command.txt"); console.log(commandHelp); const comment = [ ";;;", ";;; This is a disassembled list of the MZ-NEW MONITOR", ";;; provided from the Marukun's website 'MZ-Memories'", ";;; ( http://retropc.net/mz-memories/mz700/ ).", ";;; ", ";----", ...commandHelp.split(/\r*\n/).map(line => `;${line}`), ";----", ].join("\n"); const source = comment + "\n" + Z80.dasmlines(Z80.dasm( monitorRom as number[], 0x0000, 0x1000, 0x0000 )).join("\n") + "\n"; const monRom = asmView.asmview("newAsmList", "monitor-rom", "MZ-700 NEW MONITOR"); await asmlistAssemble(monRom, source); // 直接実行ボタン const btnExecImm = $("<button/>").attr("type", "button").html("Execute") .click(async function() { const par = $(this).parent(); const addrToken = par.find("input.address").val() as string; const addr = parseAddress.parseAddress(addrToken); if(addr != null) { let src = 'ORG ' + NumberUtil.HEX(addr, 4) + "H\r\n"; src += par.find("input.mnemonic").val() + "\r\n"; const bin = Z80_assemble.assemble([src]).obj[0]; const [reg] = await mz700js.getRegister(); const execAddr = await mz700js.writeAsmCode( bin ); await mz700js.setPC(execAddr); await mz700js.step(); await mz700js.setPC(reg.PC); } }); const wndImmExec = $("<div class='tool-window' title='IMM.EXEC.'/>"); dockPanelRight.append(wndImmExec); (wndImmExec.append( $("<div/>").addClass("imm-exec") .css("padding","15px 5px") .append($("<label/>") .css("display","inline-block").css("width", "80px") .css("text-align", "right").css("padding-right", "10px") .html("Address")) .append($("<input/>") .attr("type", "text").attr("value", "CF00h") .addClass("address")) .append($("<br/>")) .append($("<label/>") .css("display","inline-block").css("width", "80px") .css("text-align", "right").css("padding-right", "10px") .html("Mnemonic")) .append($("<input/>") .attr("type", "text").attr("value", "NOP") .addClass("mnemonic")) .append(btnExecImm) .append($("<br/>")) ) as ToolWindow).ToolWindow("create"); // Layout const dockPanelHeader = $("#dock-panel-header"); window.addEventListener("resize", resizeScreen); document.addEventListener("fullscreenchange", async () => { if(document.fullscreenElement == null) { dockPanelHeader.show(0, () => fullscreenButton.ToggleButton("setOff")); if(deviceType === "pc") { await new Promise( resolve => dockPanelRight.show(0, resolve)); if((wndRegView as ToolWindow).ToolWindow("isOpen")) { await Z80RegViewVisibility(true); } } } else { dockPanelHeader.hide(0, () => fullscreenButton.ToggleButton("setOn")); if(deviceType === "pc") { await new Promise( resolve => dockPanelRight.hide(0, resolve)); if((wndRegView as ToolWindow).ToolWindow("isOpen")) { await Z80RegViewVisibility(false); } } } resizeScreen(); }); // Accept MZT file to drop to the data recorder and MZ-700 screen const readBinFile = (file:Blob):Promise<ArrayBuffer> => { return new Promise((resolve, reject) => { try { const reader = new FileReader(); reader.onload = () => { resolve(reader.result as ArrayBuffer); }; reader.readAsArrayBuffer(file); } catch(err) { reject(err); } }); }; const readTextFile = (file:Blob):Promise<string|ArrayBuffer> => { return new Promise((resolve, reject) => { try { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.readAsText(file); } catch(err) { reject(err); } }); }; const getOnLoadHandler = (filename, onloadHandlers) => { const ext = filename.replace(/^.*\./, "").toLowerCase(); const types = Object.keys(onloadHandlers); const index = types.map(type => type.toLowerCase()).indexOf(ext); if(index >= 0) { const type = types[index]; return onloadHandlers[type]; } return null; }; // Set a cassette tape to data recorder of MZ-700 and // load the MZT to memory directly. const setMztData = async (mz700, tapeData, execAddr) => { await mz700.stop(); await mz700.setCassetteTape(tapeData); await mz700.loadCassetteTape(); await mz700.setPC(execAddr); await mz700.start(); }; // Disassemble MZTape array const showMztDisasm = async (mztArray) => { const name = MZ_TapeHeader.get1stFilename(mztArray) || "(empty)"; const result = MZ700.disassemble(mztArray); asmView.asmview("name", "mzt", name); asmlistMzt.asmlist("text", result.outbuf); asmlistMzt.asmlist("writeList", result.asmlist, await mz700js.getBreakPoints()); await dataRecorder.MZDataRecorder("updateCmtSlot"); }; const setMztAndRun = async tapeData => { const mztArray = MZ_Tape.parseMZT(tapeData); await showMztDisasm(mztArray); await setMztData(mz700js, tapeData, mztArray[0].header.addrExec); }; const setupDragDrop = (element, onloadHandlers) => { element.addEventListener("dragenter", async event => { event.stopPropagation(); event.preventDefault(); event.dataTransfer.dropEffect = "copy"; }, false); element.addEventListener('drop', async event => { event.stopPropagation(); event.preventDefault(); try { const file = Array.from(event.dataTransfer.files).shift() as File; if(file) { const onload = getOnLoadHandler(file.name, onloadHandlers); if(onload) { await onload(file); } } } catch(err) { console.error(`Error: ${err.stack}`); } }, false); }; if (window.File && window.FileReader && window.FileList && window.Blob) { setupDragDrop(dataRecorder.get(0), { "MZT": async tapeData => await mz700js.setCassetteTape(tapeData), }); const mztFileLoader = async file => { try { const arrayBuffer = await readBinFile(file); if(arrayBuffer) { const mzt = new Uint8Array(arrayBuffer); await setMztAndRun(Array.from(mzt)); } } catch(err) { console.error(`Error: Loading file ${file.name} ${err.message}`); } }; const asmFileLoader = async (file:File):Promise<undefined> => { try { const src = await readTextFile(file) as string; const obj = Z80_assemble.assemble([src]); const hdr = MZ_TapeHeader.createNew(); hdr.setFilename(file.name); hdr.setAddrLoad(obj.minAddr); hdr.setAddrExec(obj.minAddr); hdr.setFilesize(obj.buffer.length); const mzt = Buffer.from(hdr.buffer.concat(obj.buffer)); await setMztAndRun(Array.from(mzt)); } catch(err) { console.error(`Error: Loading file ${file.name} ${err.message}`); } return; }; setupDragDrop(canvas, { "MZT": mztFileLoader, "M12": mztFileLoader, "ASM": asmFileLoader, }); } fullscreenButton.ToggleButton("off"); switch(deviceType) { case "mobile": screenKbButton.ToggleButton("on"); dockPanelRight.remove(); break; case "tablet": ctrlPanel.click(event => { event.stopPropagation(); if(ctrlPanel.is(":visible")) { hideCtrlPanel(); } else { showCtrlPanel(); } }); screenKbButton.ToggleButton("off"); mz700screen.click(event => { event.stopPropagation(); if(ctrlPanel.is(":visible")) { hideCtrlPanel(); } else { showCtrlPanel(); } }); dockPanelRight.remove(); break; case "pc": screenKbButton.ToggleButton("off"); mz700screen.mousemove(event => { event.stopPropagation(); keyboard.mz700keyboard("acceptKey", true); showCtrlPanel(); }); await new Promise(resolve => dockPanelRight.show(0, resolve)); break; } // Convert MZ-700 character for(const element of document.querySelectorAll("span.mz700scrn")) { mz700scrn.convert(element as HTMLElement); } await new Promise(resolve => mz700screen.show(0, resolve)); resizeScreen(); await mz700js.reset(); await mz700js.start(); // Load MZT file when the filename is included in URL if("mzt" in pageRequest.parameters) { /* tslint:disable:no-string-literal */ const filename = pageRequest.parameters["mzt"]; const url = `https://takamin.github.io/MZ-700/mzt/${filename}.js`; const tapeData = await requestJsonp("loadMZT", url); if(tapeData) { await setMztAndRun(tapeData); } } } export default module.exports = { loadMonitorROM, createUI, };