Build and deploy ETEN DOS demo
Browse files- .gitattributes +1 -0
- ETEN.img +0 -0
- LICENSE +21 -0
- README.md +34 -5
- dos.zip +0 -0
- index.html +145 -138
.gitattributes
CHANGED
|
@@ -35,3 +35,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
dos622.iso filter=lfs diff=lfs merge=lfs -text
|
| 37 |
wdosbox.wasm.js filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
dos622.iso filter=lfs diff=lfs merge=lfs -text
|
| 37 |
wdosbox.wasm.js filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
ETEN.img filter=lfs diff=lfs merge=lfs -text
|
ETEN.img
ADDED
|
Binary file (132 Bytes). View file
|
|
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,10 +1,39 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: blue
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
| 7 |
-
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: 倚天中文 DOS 6.22 復刻
|
| 3 |
+
emoji: 🖥️
|
| 4 |
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
sdk: static
|
|
|
|
| 7 |
---
|
| 8 |
|
| 9 |
+
# 倚天中文 DOS 6.22 復刻
|
| 10 |
+
|
| 11 |
+
以瀏覽器執行 DOS 6.22 與倚天注音中文系統風格的互動示範。DOSBox 由 js-dos 6.22 提供;字型使用 GNU Unifont,詞庫由開放資料產生。
|
| 12 |
+
|
| 13 |
+
## 操作方式
|
| 14 |
+
|
| 15 |
+
- 點選 DOS 畫面後使用實體鍵盤,或用畫面下方的虛擬鍵盤。
|
| 16 |
+
- `Ctrl+Space` 切換注音/英文輸入。
|
| 17 |
+
- 注音使用標準倚天鍵位;輸入音節後按空白鍵選字,按 `1`–`9` 選候選字。
|
| 18 |
+
- `F1` 查看系統資訊;`Alt+X` 離開。
|
| 19 |
+
|
| 20 |
+
啟動時會顯示 DOS 狀態列中的傳統記憶體用量,目標為保留 600KB 以上。
|
| 21 |
+
|
| 22 |
+
## 本機建置
|
| 23 |
+
|
| 24 |
+
需求:OpenWatcom(預設 `/opt`,可用 `WATCOM` 指定)、NASM、mtools、curl、Python 3,以及可開機的 DOS 6.22 FAT12 映像(預設為 `dos/boot622.img`)。建置工具 `tools/genime.py` 需要 `pypinyin`、`jieba`、`opencc`;`tools/genfont.py` 預設讀取 `/usr/share/unifont/unifont.hex`。
|
| 25 |
+
|
| 26 |
+
```sh
|
| 27 |
+
HF_TOKEN=hf_... ./build.sh
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
若未設定 `HF_TOKEN`,腳本會產生本機發佈檔但略過 Hugging Face 上傳。可用 `DOS_BASE_IMAGE=/path/to/boot.img` 指定其他基底映像。上傳目標為 `HelloSun/c_dos`,token 僅從環境讀取,不寫入專案。
|
| 31 |
+
|
| 32 |
+
`dist/dos.zip` 內含 `ETEN.img`,供頁面中的 js-dos 啟動;`dist/ETEN.img` 可直接用於本機測試。
|
| 33 |
+
|
| 34 |
+
## 授權與來源
|
| 35 |
+
|
| 36 |
+
- GNU Unifont 字形:GPL-2.0-or-later,附 font embedding exception。GPL-2 授權文字可見 `/usr/share/common-licenses/GPL-2`。
|
| 37 |
+
- js-dos 6.22:使用其發佈檔案,請依上游授權條款使用。
|
| 38 |
+
- DOS 6.22 系統檔案:由使用者提供的 DOS 開機映像取得;建置時移除可選應用程式以騰出磁碟空間。
|
| 39 |
+
- 本專案 C/ASM、HTML 與生成工具:MIT License。
|
dos.zip
ADDED
|
Binary file (131 Bytes). View file
|
|
|
index.html
CHANGED
|
@@ -1,145 +1,152 @@
|
|
| 1 |
-
<!
|
| 2 |
<html lang="zh-Hant">
|
| 3 |
<head>
|
| 4 |
-
<meta charset="utf-8">
|
| 5 |
-
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 6 |
-
<
|
| 7 |
-
<
|
| 8 |
-
<
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
</head>
|
| 32 |
<body>
|
| 33 |
-
<header>
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
</header>
|
| 37 |
-
<main>
|
| 38 |
-
|
| 39 |
-
<div
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
<div id="log"></div>
|
| 45 |
-
<div class="prompt">C:\> <input id="cmd" autocomplete="off" spellcheck="false"></div>
|
| 46 |
-
</section>
|
| 47 |
-
<aside class="side">
|
| 48 |
-
<h3>輸入法狀態</h3>
|
| 49 |
-
<div id="ime" class="ime-status">EN</div>
|
| 50 |
-
<div>模式:<span id="imemode">英文</span></div>
|
| 51 |
-
<h3>注音對照</h3>
|
| 52 |
-
<div style="font-family:'Noto Sans TC',sans-serif;font-size:13px">
|
| 53 |
-
ㄅ b ㄆ p ㄇ m ㄈ f ㄉ d ㄊ t ㄋ n ㄌ l<br>
|
| 54 |
-
ㄍ g ㄎ k ㄏ h ㄐ j ㄑ q ㄒ x ㄓ zh ㄔ ch<br>
|
| 55 |
-
ㄕ sh ㄖ r ㄗ z ㄘ c ㄙ s ㄧ i ㄨ u ㄩ v<br>
|
| 56 |
-
ㄚ a ㄛ o ㄜ e ㄝ ei ㄞ ai ㄠ ao ㄢ an<br>
|
| 57 |
-
ㄣ en ㄤ ang ㄥ eng ㄦ er
|
| 58 |
</div>
|
| 59 |
-
<
|
| 60 |
-
<
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
</
|
| 64 |
-
<
|
| 65 |
-
|
| 66 |
-
<
|
| 67 |
-
<
|
| 68 |
-
//
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
};
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
const
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
(
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
</body>
|
| 145 |
</html>
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
<html lang="zh-Hant">
|
| 3 |
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
| 6 |
+
<meta name="theme-color" content="#05070a">
|
| 7 |
+
<title>倚天中文 DOS · js-dos 6.22</title>
|
| 8 |
+
<style>
|
| 9 |
+
:root { color-scheme: dark; font-family: system-ui, sans-serif; background: #05070a; color: #e7edf5; }
|
| 10 |
+
* { box-sizing: border-box; }
|
| 11 |
+
body { margin: 0; min-height: 100vh; display: flex; flex-direction: column; }
|
| 12 |
+
header, footer { padding: .7rem 1rem; background: #0c1118; border-color: #202a36; }
|
| 13 |
+
header { border-bottom: 1px solid #202a36; display: flex; justify-content: space-between; gap: 1rem; align-items: center; }
|
| 14 |
+
header strong { color: #80d8ff; }
|
| 15 |
+
#memory { color: #a7b8ca; font-size: .85rem; }
|
| 16 |
+
main { width: min(100%, 1060px); margin: auto; padding: 1rem; }
|
| 17 |
+
#screen-wrap { width: 100%; background: #000; border: 1px solid #263342; border-radius: 8px; overflow: hidden; }
|
| 18 |
+
#dosbox { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; background: #000; image-rendering: pixelated; touch-action: none; }
|
| 19 |
+
#message { min-height: 1.4em; padding: .35rem .15rem; color: #93a4b6; font: .8rem ui-monospace, monospace; }
|
| 20 |
+
.toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin: .4rem 0 .75rem; }
|
| 21 |
+
button { border: 1px solid #344457; border-radius: 6px; background: #141e2a; color: #e7edf5; min-height: 40px; padding: .45rem .75rem; font: inherit; cursor: pointer; touch-action: manipulation; }
|
| 22 |
+
button:active, button.active { background: #164467; border-color: #52b9ec; }
|
| 23 |
+
.spacer { flex: 1; }
|
| 24 |
+
.keypad { display: grid; grid-template-columns: repeat(10, minmax(0, 1fr)); gap: .35rem; }
|
| 25 |
+
.keypad button { min-width: 0; padding: .45rem .15rem; font-size: .9rem; }
|
| 26 |
+
.keypad .wide { grid-column: span 2; }
|
| 27 |
+
.hint { color: #9aabba; font-size: .82rem; line-height: 1.5; margin: .8rem 0; }
|
| 28 |
+
footer { border-top: 1px solid #202a36; font-size: .78rem; color: #9aabba; text-align: center; }
|
| 29 |
+
@media (max-width: 620px) {
|
| 30 |
+
main { padding: .55rem; }
|
| 31 |
+
header { padding: .6rem .7rem; align-items: flex-start; flex-direction: column; gap: .2rem; }
|
| 32 |
+
.keypad { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: .3rem; }
|
| 33 |
+
.keypad button { min-height: 42px; }
|
| 34 |
+
}
|
| 35 |
+
</style>
|
| 36 |
</head>
|
| 37 |
<body>
|
| 38 |
+
<header>
|
| 39 |
+
<strong>倚天中文 DOS 6.22 復刻</strong>
|
| 40 |
+
<span id="memory">DOS 啟動後顯示可用傳統記憶體</span>
|
| 41 |
+
</header>
|
| 42 |
+
<main>
|
| 43 |
+
<div id="screen-wrap"><canvas id="dosbox" width="640" height="480" aria-label="DOS emulator screen"></canvas></div>
|
| 44 |
+
<div class="toolbar">
|
| 45 |
+
<button id="ime-toggle" type="button">Ctrl+Space 注音切換</button>
|
| 46 |
+
<button id="fullscreen" type="button">全螢幕</button>
|
| 47 |
+
<span class="spacer"></span>
|
| 48 |
+
<span id="message" role="status">正在載入 DOS 6.22…</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
</div>
|
| 50 |
+
<p class="hint">點選 DOS 畫面後可使用實體鍵盤。手機可用下方按鍵輸入;注音鍵盤採標準倚天鍵位。F1 顯示系統資訊,Alt+X 離開。</p>
|
| 51 |
+
<section class="keypad" aria-label="虛擬鍵盤">
|
| 52 |
+
<button type="button" data-key="49">1 ㄅ</button><button type="button" data-key="81">Q ㄆ</button><button type="button" data-key="65">A ㄇ</button><button type="button" data-key="90">Z ㄈ</button><button type="button" data-key="50">2 ㄉ</button><button type="button" data-key="87">W ㄊ</button>
|
| 53 |
+
<button type="button" data-key="83">S ㄋ</button><button type="button" data-key="88">X ㄌ</button><button type="button" data-key="69">E ㄍ</button><button type="button" data-key="68">D ㄎ</button><button type="button" data-key="67">C ㄏ</button><button type="button" data-key="82">R ㄐ</button>
|
| 54 |
+
<button type="button" data-key="70">F ㄑ</button><button type="button" data-key="86">V ㄒ</button><button type="button" data-key="53">5 ㄓ</button><button type="button" data-key="84">T ㄔ</button><button type="button" data-key="71">G ㄕ</button><button type="button" data-key="66">B ㄖ</button>
|
| 55 |
+
<button type="button" data-key="89">Y ㄗ</button><button type="button" data-key="72">H ㄘ</button><button type="button" data-key="78">N ㄙ</button><button type="button" data-key="85">U ㄧ</button><button type="button" data-key="74">J ㄨ</button><button type="button" data-key="77">M ㄩ</button>
|
| 56 |
+
<button type="button" data-key="56">8 ㄚ</button><button type="button" data-key="73">I ㄛ</button><button type="button" data-key="75">K ㄜ</button><button type="button" data-key="188">, ㄝ</button><button type="button" data-key="57">9 ㄞ</button><button type="button" data-key="79">O ㄟ</button>
|
| 57 |
+
<button type="button" data-key="76">L ㄠ</button><button type="button" data-key="190">. ㄡ</button><button type="button" data-key="48">0 ㄢ</button><button type="button" data-key="80">P ㄣ</button><button type="button" data-key="186">; ㄤ</button><button type="button" data-key="191">/ ㄥ</button>
|
| 58 |
+
<button type="button" data-key="189">- ㄦ</button><button type="button" data-key="54">6 ˊ</button><button type="button" data-key="51">3 ˇ</button><button type="button" data-key="52">4 ˋ</button><button type="button" data-key="55">7 ˙</button><button type="button" data-key="8">⌫</button>
|
| 59 |
+
<button type="button" data-key="27">Esc</button><button type="button" data-key="13">Enter</button><button type="button" data-key="32" class="wide">Space</button><button type="button" data-key="37">←</button><button type="button" data-key="38">↑</button><button type="button" data-key="39">→</button><button type="button" data-key="40">↓</button>
|
| 60 |
+
<button type="button" data-key="112">F1</button><button id="alt-x" type="button" class="wide">Alt+X</button>
|
| 61 |
+
</section>
|
| 62 |
+
</main>
|
| 63 |
+
<footer>OpenWatcom · GNU Unifont · Big5 注音輸入 · 目標保留 600KB 以上傳統記憶體</footer>
|
| 64 |
+
<script src="js-dos.js"></script>
|
| 65 |
+
<script>
|
| 66 |
+
(() => {
|
| 67 |
+
const status = document.getElementById('message');
|
| 68 |
+
const memory = document.getElementById('memory');
|
| 69 |
+
const host = document.getElementById('dosbox');
|
| 70 |
+
let controller = null;
|
| 71 |
+
const canvas = host;
|
| 72 |
+
const send = (code, down) => {
|
| 73 |
+
if (!controller) return;
|
| 74 |
+
controller.simulateKeyEvent(code, down);
|
| 75 |
+
};
|
| 76 |
+
const tap = (code) => {
|
| 77 |
+
send(code, true);
|
| 78 |
+
window.setTimeout(() => send(code, false), 90);
|
| 79 |
+
};
|
| 80 |
+
const toggleIme = () => {
|
| 81 |
+
send(17, true);
|
| 82 |
+
tap(32);
|
| 83 |
+
window.setTimeout(() => send(17, false), 130);
|
| 84 |
+
};
|
| 85 |
+
window.etImeToggle = toggleIme;
|
| 86 |
+
document.getElementById('ime-toggle').addEventListener('click', toggleIme);
|
| 87 |
+
document.getElementById('fullscreen').addEventListener('click', () => controller && controller.fullscreen());
|
| 88 |
+
document.getElementById('alt-x').addEventListener('click', () => {
|
| 89 |
+
send(18, true); tap(88); window.setTimeout(() => send(18, false), 130);
|
| 90 |
+
});
|
| 91 |
+
document.querySelectorAll('.keypad [data-key]').forEach((button) => {
|
| 92 |
+
button.addEventListener('pointerdown', (event) => {
|
| 93 |
+
event.preventDefault();
|
| 94 |
+
const code = Number(button.dataset.key);
|
| 95 |
+
tap(code);
|
| 96 |
+
button.classList.add('active');
|
| 97 |
+
});
|
| 98 |
+
button.addEventListener('pointerup', () => button.classList.remove('active'));
|
| 99 |
+
button.addEventListener('pointercancel', () => button.classList.remove('active'));
|
| 100 |
+
button.addEventListener('pointerleave', () => button.classList.remove('active'));
|
| 101 |
+
});
|
| 102 |
+
canvas.tabIndex = 0;
|
| 103 |
+
canvas.addEventListener('pointerdown', () => canvas.focus());
|
| 104 |
+
document.addEventListener('keydown', (event) => {
|
| 105 |
+
if (!controller) return;
|
| 106 |
+
if (event.code === 'Space' && event.ctrlKey) {
|
| 107 |
+
if (canvas.contains(event.target)) return;
|
| 108 |
+
event.preventDefault();
|
| 109 |
+
toggleIme();
|
| 110 |
+
return;
|
| 111 |
+
}
|
| 112 |
+
if (canvas.contains(event.target)) {
|
| 113 |
+
if (event.isTrusted && event.key === 'x' && event.altKey) event.preventDefault();
|
| 114 |
+
return;
|
| 115 |
+
}
|
| 116 |
+
if (!event.isTrusted) return;
|
| 117 |
+
if (event.code === 'AltLeft' || event.code === 'AltRight') {
|
| 118 |
+
send(18, true);
|
| 119 |
+
return;
|
| 120 |
+
}
|
| 121 |
+
if (event.code === 'ControlLeft' || event.code === 'ControlRight') {
|
| 122 |
+
send(17, true);
|
| 123 |
+
return;
|
| 124 |
+
}
|
| 125 |
+
if (event.code === 'KeyX' && event.altKey) event.preventDefault();
|
| 126 |
+
if (!event.repeat) send(event.keyCode, true);
|
| 127 |
+
});
|
| 128 |
+
document.addEventListener('keyup', (event) => {
|
| 129 |
+
if (!controller) return;
|
| 130 |
+
if (canvas.contains(event.target)) return;
|
| 131 |
+
if (!event.isTrusted) return;
|
| 132 |
+
if (event.code === 'AltLeft' || event.code === 'AltRight') { send(18, false); return; }
|
| 133 |
+
if (event.code === 'ControlLeft' || event.code === 'ControlRight') { send(17, false); return; }
|
| 134 |
+
send(event.keyCode, false);
|
| 135 |
+
});
|
| 136 |
+
if (typeof Dos !== 'function') { status.textContent = 'js-dos 核心載入失敗'; return; }
|
| 137 |
+
Dos(host, { wdosboxUrl: 'wdosbox.js' }).ready((fs, main) => {
|
| 138 |
+
status.textContent = '正在載入 DOS 開機磁碟…';
|
| 139 |
+
fs.extract('dos.zip', '/').then(() => main(['-c', 'boot ETEN.img']))
|
| 140 |
+
.then((ci) => {
|
| 141 |
+
controller = ci;
|
| 142 |
+
window.etController = ci;
|
| 143 |
+
canvas.tabIndex = 0;
|
| 144 |
+
status.textContent = 'DOS 6.22 已啟動;點選畫面輸入';
|
| 145 |
+
memory.textContent = '倚天中文系統 · js-dos 6.22';
|
| 146 |
+
})
|
| 147 |
+
.catch((error) => { status.textContent = '啟動失敗:' + (error.message || error); });
|
| 148 |
+
});
|
| 149 |
+
})();
|
| 150 |
+
</script>
|
| 151 |
</body>
|
| 152 |
</html>
|