基於基本 TSR 架構,開發鍵盤擴充程式:將特定按鍵替換為預定字串序列,減少用戶擊鍵。核心挑戰:攔截 INT 16H(鍵盤 BIOS 服務)、識別擴充鍵、管理擴充字串輸出狀態、欺騙 DOS 鍵盤狀態檢查。
普通字母數字作擴充鍵易衝突;控制碼被 DOS 佔用(如 Ctrl+H)。IBM PC 擴充鍵(功能鍵 F1-F10、Alt 組合、Shift/Ctrl 組合)雙碼編碼(首碼 0),DOS 易分辨,且不影響正常操作。附表列出 1-132 號擴充碼對應鍵位(如 59=F1, 60=F2... 84=Shift+F1... 104=Alt+F1...)。
CR (0DH):邏輯直觀但難表達多行。$:DOS 系統呼叫常用作結尾,字串中不可含 $。使用指標 current 指向下一個待輸出字元:
current = 0:無擴充進行,正常讀取鍵盤。current ≠ 0:擴充中,依序輸出字串字元,遇 0 歸零並恢復讀取真實鍵盤。關鍵點:INT 16H AH=1(狀態檢查)必須在擴充時強制回傳「有字元」(ZF=0)。IRET 會從堆疊恢復旗標,故須用 RET 2 丟棄中斷進入時自動壓入的旗標,以保留修改後的 ZF。
; 關鍵變數
current dw 0
string db 'DIR', 0dh, 0
; KeyRead 核心邏輯
KeyRead proc
cmp cs:current, 0
jne ExpandChar
ReadChar:
mov cs:current, 0
pushf
call Old_Keyboard_IO
cmp al, 0
je Extended
ret
Extended:
cmp ah, 59 ; F1 擴充碼
jne ReadDone
mov cs:current, offset string
ExpandChar:
push si
mov si, cs:current
mov al, cs:[si]
inc cs:current
pop si
cmp al, 0
je ReadChar
ret
KeyRead endp
; KeyStat:擴充中強制 ZF=0
KeyStat proc
cmp cs:current, 0
jne FakeStat
pushf
call Old_Keyboard_IO
ret
FakeStat:
mov bx, 1
cmp bx, 0 ; 清 ZF
ret
KeyStat endp
注意:mov cs:current, offset string 取位址,非 mov cs:current, string(後者錯誤移動字元內容)。記憶體存取必須基於 CS(cs:current),因進入 TSR 時 DS 不可知且必須保留給被中斷程式。
單鍵獨立 TSR 疊加層層攔截,128 鍵需 13KB 代碼。改用單一 TSR 內建查表:
db 擴充碼, dw 字串位址,以 db 0 結束。KeyRead 掃描鍵表比對 AH,命中則載入對應字串位址至 current。初始化時可從設定檔載入鍵表,載入代碼執行後可丟棄,不佔駐留空間。
Mactab.asm 完整架構包含:New_Keyboard_IO(主攔截器)、KeyRead(查表+狀態機)、KeyStat(偽裝狀態)、Initialize(攔截 INT 16H、TSR 駐留)、鍵表與字串資料區。代碼結構清晰,易於擴展維護。