Build and deploy 小貓中文 DOS demo
Browse files- README.md +14 -8
- XIAOMAO.img +0 -3
- dos.b64.js +0 -0
- dos.zip +0 -0
- index.html +17 -6
- wdosbox.js +0 -0
- wdosbox.wasm.js +0 -0
README.md
CHANGED
|
@@ -8,16 +8,22 @@ sdk: static
|
|
| 8 |
|
| 9 |
# 小貓中文 DOS 6.22
|
| 10 |
|
| 11 |
-
「小貓中文」是
|
| 12 |
|
| 13 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
| 16 |
-
- `Ctrl+Space` 切換注音/英文輸入。
|
| 17 |
-
- 注音採相容倚天鍵位;輸入音節後按空白鍵選字,按 `1`–`9` 選候選字。
|
| 18 |
-
- `F1` 查看系統資訊;`Alt+X` 離開。
|
| 19 |
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
## 本機建置
|
| 23 |
|
|
@@ -29,7 +35,7 @@ HF_TOKEN=hf_... ./build.sh
|
|
| 29 |
|
| 30 |
若未設定 `HF_TOKEN`,腳本會產生本機發佈檔但略過 Hugging Face 上傳。可用 `DOS_BASE_IMAGE=/path/to/boot.img` 指定其他基底映像。上傳目標為 `HelloSun/c_dos`,token 僅從環境讀取,不寫入專案。
|
| 31 |
|
| 32 |
-
`dist/dos.
|
| 33 |
|
| 34 |
## 授權與來源
|
| 35 |
|
|
|
|
| 8 |
|
| 9 |
# 小貓中文 DOS 6.22
|
| 10 |
|
| 11 |
+
「小貓中文」是 DOS 常駐(TSR)的 Big5 中文顯示與注音輸入外掛,在瀏覽器的 js-dos 6.22 上執行;字型使用 GNU Unifont,詞庫由開放資料產生。載入後回到一般 DOS 提示字元,DOS 指令照常使用,並可直接輸入、顯示中文。
|
| 12 |
|
| 13 |
+
## 運作方式
|
| 14 |
+
|
| 15 |
+
- `XIAOMAO.EXE` 常駐約 10 KB 傳統記憶體(可用 `LH` 載入高記憶體);字型與詞庫放在 XMS(需要 `HIMEM.SYS`)。
|
| 16 |
+
- 載入時(及再次執行 `XIAOMAO`)才顯示常駐大小、可用傳統記憶體與 XMS(即時 MEM),沒有狀態列。
|
| 17 |
+
- 顯示:攔截 INT 29h,遇到 Big5 雙位元組時,把 16×16 字形拆成兩個 8×16 字塊寫入 VGA 字型,再用原本的 INT 29h 輸出,游標、換行與捲動由 DOS 處理。80×25 文字模式,切為 8 點寬字元。
|
| 18 |
+
- 輸入:攔截 INT 16h。`Ctrl+Space` 切換注音/英數;注音選字列顯示於畫面最底列,用完即還原。`Backspace` 一次刪一個中文字。
|
| 19 |
+
- INT 2Fh `AX=D7A0h` 防止重複載入。
|
| 20 |
|
| 21 |
+
## 操作方式
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
- 點選 DOS 畫面後使用實體鍵盤,或用畫面下方的虛擬鍵盤(含 Shift、`\`、`:`、Tab)。
|
| 24 |
+
- `Ctrl+Space` 切換注音/英數(網頁上有按鈕)。
|
| 25 |
+
- 注音採倚天鍵位;輸入音節後按聲調鍵(`6 3 4 7`)或空白鍵出候選字,按 `1`–`9` 或空白鍵選字。
|
| 26 |
+
- 試用:`TYPE DEMO.TXT`。限制:直接寫入顯示記憶體的程式不會顯示中文。
|
| 27 |
|
| 28 |
## 本機建置
|
| 29 |
|
|
|
|
| 35 |
|
| 36 |
若未設定 `HF_TOKEN`,腳本會產生本機發佈檔但略過 Hugging Face 上傳。可用 `DOS_BASE_IMAGE=/path/to/boot.img` 指定其他基底映像。上傳目標為 `HelloSun/c_dos`,token 僅從環境讀取,不寫入專案。
|
| 37 |
|
| 38 |
+
HF 靜態 Space 以無 CORS 的重新導向提供二進位檔,因此開機映像以 base64 文字放在 `dist/dos.b64.js`,頁面載入後轉為 Blob 交給 js-dos;DOSBox 核心(`wdosbox.js`)取自 js-dos.com。
|
| 39 |
|
| 40 |
## 授權與來源
|
| 41 |
|
XIAOMAO.img
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:4ad1f23262b00f3d36bd27dca929d207f5fee3500c294d9413a5e5d684411b89
|
| 3 |
-
size 1474560
|
|
|
|
|
|
|
|
|
|
|
|
dos.b64.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dos.zip
DELETED
|
Binary file (131 Bytes)
|
|
|
index.html
CHANGED
|
@@ -39,7 +39,7 @@
|
|
| 39 |
<body>
|
| 40 |
<header>
|
| 41 |
<strong>小貓中文 DOS 6.22</strong>
|
| 42 |
-
<span id="memory">DOS
|
| 43 |
</header>
|
| 44 |
<main>
|
| 45 |
<div id="screen-wrap"><canvas id="dosbox" width="640" height="480" aria-label="DOS emulator screen"></canvas></div>
|
|
@@ -59,11 +59,13 @@
|
|
| 59 |
<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>
|
| 60 |
<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>
|
| 61 |
<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>
|
|
|
|
| 62 |
<button type="button" data-key="112">F1</button><button id="alt-x" type="button" class="wide">Alt+X</button>
|
| 63 |
</section>
|
| 64 |
</main>
|
| 65 |
-
<footer>小貓中文 GPL-3.0 · OpenWatcom · GNU Unifont · Big5 注音 ·
|
| 66 |
<script src="js-dos.js"></script>
|
|
|
|
| 67 |
<script>
|
| 68 |
(() => {
|
| 69 |
const status = document.getElementById('message');
|
|
@@ -79,6 +81,9 @@
|
|
| 79 |
send(code, true);
|
| 80 |
window.setTimeout(() => send(code, false), 90);
|
| 81 |
};
|
|
|
|
|
|
|
|
|
|
| 82 |
const toggleIme = () => {
|
| 83 |
send(17, true);
|
| 84 |
tap(32);
|
|
@@ -94,7 +99,11 @@
|
|
| 94 |
button.addEventListener('pointerdown', (event) => {
|
| 95 |
event.preventDefault();
|
| 96 |
const code = Number(button.dataset.key);
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
button.classList.add('active');
|
| 99 |
});
|
| 100 |
button.addEventListener('pointerup', () => button.classList.remove('active'));
|
|
@@ -138,14 +147,16 @@
|
|
| 138 |
if (typeof Dos !== 'function') { status.textContent = 'js-dos 核心載入失敗'; return; }
|
| 139 |
Dos(host, { wdosboxUrl: 'https://js-dos.com/6.22/current/wdosbox.js' }).ready((fs, main) => {
|
| 140 |
status.textContent = '正在載入 DOS 開機磁碟…';
|
| 141 |
-
|
|
|
|
|
|
|
|
|
|
| 142 |
.then((ci) => {
|
| 143 |
controller = ci;
|
| 144 |
window.etController = ci;
|
| 145 |
canvas.tabIndex = 0;
|
| 146 |
status.textContent = 'DOS 6.22 已啟動;點選畫面輸入';
|
| 147 |
-
|
| 148 |
-
})
|
| 149 |
.catch((error) => { status.textContent = '啟動失敗:' + (error.message || error); });
|
| 150 |
});
|
| 151 |
})();
|
|
|
|
| 39 |
<body>
|
| 40 |
<header>
|
| 41 |
<strong>小貓中文 DOS 6.22</strong>
|
| 42 |
+
<span id="memory">載入時於 DOS 畫面顯示即時 MEM</span>
|
| 43 |
</header>
|
| 44 |
<main>
|
| 45 |
<div id="screen-wrap"><canvas id="dosbox" width="640" height="480" aria-label="DOS emulator screen"></canvas></div>
|
|
|
|
| 59 |
<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>
|
| 60 |
<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>
|
| 61 |
<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>
|
| 62 |
+
<button type="button" data-key="220">\</button><button type="button" data-key="186" data-shift="1">:</button><button type="button" data-key="9">Tab</button><button id="shift" type="button">Shift</button>
|
| 63 |
<button type="button" data-key="112">F1</button><button id="alt-x" type="button" class="wide">Alt+X</button>
|
| 64 |
</section>
|
| 65 |
</main>
|
| 66 |
+
<footer>小貓中文 GPL-3.0 · OpenWatcom · GNU Unifont · Big5 注音 · 載入時顯示即時 MEM · <a href="LICENSE">License</a></footer>
|
| 67 |
<script src="js-dos.js"></script>
|
| 68 |
+
<script src="dos.b64.js"></script>
|
| 69 |
<script>
|
| 70 |
(() => {
|
| 71 |
const status = document.getElementById('message');
|
|
|
|
| 81 |
send(code, true);
|
| 82 |
window.setTimeout(() => send(code, false), 90);
|
| 83 |
};
|
| 84 |
+
let shiftOn = false;
|
| 85 |
+
const setShift = (on) => { shiftOn = on; document.getElementById('shift').classList.toggle('active', on); };
|
| 86 |
+
document.getElementById('shift').addEventListener('click', () => setShift(!shiftOn));
|
| 87 |
const toggleIme = () => {
|
| 88 |
send(17, true);
|
| 89 |
tap(32);
|
|
|
|
| 99 |
button.addEventListener('pointerdown', (event) => {
|
| 100 |
event.preventDefault();
|
| 101 |
const code = Number(button.dataset.key);
|
| 102 |
+
if (button.dataset.shift || shiftOn) {
|
| 103 |
+
send(16, true);
|
| 104 |
+
window.setTimeout(() => { tap(code); window.setTimeout(() => send(16, false), 130); }, 40);
|
| 105 |
+
setShift(false);
|
| 106 |
+
} else tap(code);
|
| 107 |
button.classList.add('active');
|
| 108 |
});
|
| 109 |
button.addEventListener('pointerup', () => button.classList.remove('active'));
|
|
|
|
| 147 |
if (typeof Dos !== 'function') { status.textContent = 'js-dos 核心載入失敗'; return; }
|
| 148 |
Dos(host, { wdosboxUrl: 'https://js-dos.com/6.22/current/wdosbox.js' }).ready((fs, main) => {
|
| 149 |
status.textContent = '正在載入 DOS 開機磁碟…';
|
| 150 |
+
if (!window.XIAOMAO_B64) { status.textContent = '啟動失敗:dos.b64.js'; return; }
|
| 151 |
+
const bin = Uint8Array.from(atob(window.XIAOMAO_B64), (c) => c.charCodeAt(0));
|
| 152 |
+
const zipUrl = URL.createObjectURL(new Blob([bin], { type: 'application/zip' }));
|
| 153 |
+
fs.extract(zipUrl, '/').then(() => main(['-c', 'boot XIAOMAO.img']))
|
| 154 |
.then((ci) => {
|
| 155 |
controller = ci;
|
| 156 |
window.etController = ci;
|
| 157 |
canvas.tabIndex = 0;
|
| 158 |
status.textContent = 'DOS 6.22 已啟動;點選畫面輸入';
|
| 159 |
+
})
|
|
|
|
| 160 |
.catch((error) => { status.textContent = '啟動失敗:' + (error.message || error); });
|
| 161 |
});
|
| 162 |
})();
|
wdosbox.js
DELETED
|
The diff for this file is too large to render.
See raw diff
|
|
|
wdosbox.wasm.js
DELETED
|
Binary file (132 Bytes)
|
|
|