# Bug 修復報告：全形"～"在 GTWVT 顯示為「口」

**日期**：2026-04-21  
**修復者**：Claude AI  
**狀態**：已修復、BUILD OK、驗證通過

---

## 一、問題現象

在報表查詢對話框（`AskGeneralRept`）中，用來分隔「起始鍵值」與「結束鍵值」的全形波浪號"～"，
在 GTWVT 控制台視窗中顯示為「口」字，而非預期的"～"（全形波浪號）。

同樣問題也出現在日期範圍字串（`cDateRange`）的組合：
```
日期範圍: 2026/01/01口2026/12/31
```
應顯示為：
```
日期範圍: 2026/01/01～2026/12/31
```

---

## 二、相關檔案

| 檔案 | 路徑 |
|------|------|
| 字元解碼 hook | `E:\ConvertFW\HBSTK\compat\usrfont.prg` |
| 查詢對話框來源 | `E:\ConvertFW\HBSTK\source\REPORT.PRG` |

---

## 三、根本原因分析

### 3.1 字元編碼

| 字元 | Unicode | CP950 bytes | 顯示 |
|------|---------|-------------|------|
| 全形"～" | U+FF5E FULLWIDTH TILDE | `0xA1 0xE3` | ～ |
| 「口」 | U+53E3 | `0xA4 0xE3` | 口 |

REPORT.PRG 使用 CP950（Windows BIG5 超集）編碼，`0xA1E3` = U+FF5E（全形"～"）。

### 3.2 Harbour 內建 BIG5 碼表的錯誤映射

GTWVT 的字元渲染路徑為：

```
PRG 字串 (BIG5 bytes)
  → Harbour codepage wcharGet()
  → Unicode WCHAR
  → usrfont_wcharGet() hook（usrfont.prg）
  → ScanAndDrawUda()
  → TextOutW()（華康楷書W5A 字型）
```

`usrfont_wcharGet` 對不在特殊攔截範圍（`0x7F`、`0xFA-0xFE`）內的字元，
直接轉交 Harbour 原始 BIG5 handler（`s_pOrigWcharGet`）處理。

**問題所在**：Harbour 內建 BIG5 碼表（符號區 `0xA1xx`）與 Windows CP950 在部分符號字元的映射不一致：

| Handler | 0xA1E3 映射目標 |
|---------|----------------|
| Windows CP950 | U+FF5E（全形"～"）[OK] |
| Harbour 內建 BIG5 | U+53E3（「口」）[NG] |

結果：U+53E3 被傳入 `ScanAndDrawUda`，以「口」渲染輸出。

---

## 四、修改內容

### 4.1 usrfont.prg — 新增 `0xA1E3` 攔截

**位置**：`usrfont_wcharGet()` 函式，`0x7F` 攔截之後、lead byte boundary 檢查之前

**修改前**：
```c
      /* Big5 lead byte boundary: A1-FE with no trail byte -> half-width space */
      if( hi >= 0xA1 && hi <= 0xFE && nLen > 1 && *pnIndex + 1 >= nLen )
      ...
```

**修改後**（新增攔截段）：
```c
      /* CP950 A1E3 = FULLWIDTH TILDE (U+FF5E)                                    */
      /* Harbour Big5 maps this to U+53E3 (口); intercept for correct Unicode */
      if( hi == 0xA1 && *pnIndex + 1 < nLen &&
          ( unsigned char ) pSrc[ *pnIndex + 1 ] == 0xE3 )
      {
         *wc = 0xFF5E;   /* U+FF5E FULLWIDTH TILDE ～ */
         *pnIndex += 2;
         return HB_TRUE;
      }

      /* Big5 lead byte boundary: A1-FE with no trail byte -> half-width space */
      if( hi >= 0xA1 && hi <= 0xFE && nLen > 1 && *pnIndex + 1 >= nLen )
      ...
```

**備份**：`usrfont.prg.bak_a1e3_20260421_0717`

---

### 4.2 REPORT.PRG — 確認字元正確（不改字元，保留 0xA1E3）

REPORT.PRG 中共 3 處使用全形"～"（`0xA1E3`）：

| 行號 | 用途 | 內容 |
|------|------|------|
| L874 | 查詢條件結束欄位標題 | `"～   "` |
| L1197 | 文字型日期範圍字串 | `... + "～" + ...` |
| L1199 | 日期型日期範圍字串 | `... + "～" + ...` |

> **注意**：修復過程中曾嘗試將"～"替換為"到"作為臨時措施，
> 最終確認正確做法為修改渲染端（usrfont.prg），REPORT.PRG 保留原始 `0xA1E3` bytes。

---

## 五、驗證

- BUILD OK（`hbmk2 stk32.hbp -comp=bcc`）
- 程式啟動正常
- 報表查詢對話框預期顯示：`客戶代號: [____] ～ [____]`（全形波浪號）

---

## 六、設計備注

此修復採用**最小影響**原則：僅攔截 `0xA1E3` 一個特定 byte pair，
不影響其他 BIG5 A1xx 符號字元的原有映射行為。

若未來發現其他 CP950 vs Harbour BIG5 碼表不一致的符號字元（同類問題），
可在 `usrfont_wcharGet` 的同一位置以相同模式擴充攔截。

---

*備份檔案*：
- `usrfont.prg.bak_a1e3_20260421_????`
- `REPORT.PRG.bak_tilde_20260421_????`
- `REPORT.PRG.bak_restore_20260421_????`
