x86匯編利用int 16h中斷實現偽多線程輸入
我們都知道,如果想讓一個程序,同時又干這個,又干那個,最好的辦法就是多線程。這個在高級語言里面已經用爛了。
但是,DOS是只有單線程的。我如果想讓程序在運行的同時,又能接受我鍵盤的輸入,那要怎么辦呢?
例如,我有一個DOS彩票開獎軟件。屏幕上有十個數字在滾動,當我按下空格鍵的時候,它會停止跳動,按別的鍵無效。那么要怎么操作?
首先,接收輸入最常用的是int 21h中斷里的7號功能調用。但是它是一個中斷輸入,也就是為了接收這個輸入,我的程序就暫停在這兒不動了。但是我彩票開獎數字一直在滾動,那要怎么辦啊?不能說我按一下它滾動一下吧。
於是請來了今天的主角,int16h中斷。
首先我們看看int 16h中斷有哪些功能?
BIOS提供了int 16h中斷例程供程序員調用,且功能是從軟件層面上實現鍵盤I/O功能中斷調用,功能號為0,1,2,並且必須把功能號放在ah寄存器中。
0號功能調用
mov ah,01h
int 16h
功能:從鍵盤讀入字符送進al寄存器,執行時,等待鍵盤輸入,一旦輸入,輸入字符的ASCII碼放入al中。若al為0,則ah為輸入的擴展碼。但是,如果鍵盤緩沖區已有數據,則會讀取鍵盤緩沖區數據,並且將其從緩沖區中刪除。
0號功能的工作流程為:
- 檢測鍵盤緩沖區是否有數據;
- 沒有則回到1;
- 讀取緩沖區第一個字單元中的鍵盤輸入;
- 將讀取的掃描碼送入ah,ASCII碼送入al;
- 將已讀取的鍵盤輸入從緩沖區中刪除
1號功能調用
mov ah,01h
int 16h
功能:用於查詢鍵盤緩沖區,對鍵盤掃描但是不等待(也就是不會中斷程序),並設置標志寄存器中的ZF。如果有鍵盤輸入(即鍵盤緩沖區不空),則ZF=0,AL存放的是當前輸入的ASCII碼,AH存放的是輸入字符的擴展碼。若無鍵盤操作,則標志位ZF=1。
2號功能調用
mov ah,02h
int 16h
功能:檢查鍵盤上各特殊功能鍵的狀態。執行后,各種特殊功能鍵的狀態放入AL寄存器中,這個狀態字記錄在內存0040H:0017H單元中,若對應位為“1”,表示該鍵狀態為“ON”,處於按下狀態;若對應位為“0”,表示該鍵狀態為“OFF”,處於斷開狀態。
mov ah,02h
int 16h ;從鍵盤輸入
and al,04h ;判斷是否按下Ctrl
jnz Ctrl_on
Ctrl_on:
......
了解了以上功能,我們來看如何實現偽多線程輸入。
mainLoop:
mov ah,01h ;檢測是否有輸入
int 16h
jz offKey ;jz是當zf=1時跳轉,也就是無輸入
;如果有輸入,沒有跳轉
mov ah,00h ;那么鍵盤緩沖區已不為空
int 16h
cmp al,32 ;和空格的ASCII碼比較
je spaceProc
...
spaceProc:
...
offKey:
...
這個框架簡單易懂,先從mainLoop中判斷是否有輸入:
- 如果沒有任何輸入,則直接執行offKey中的代碼內容;
- 如果有輸入,會調用0號功能對鍵盤緩沖區進行檢索。因為我們已知它有輸入(鍵盤緩沖區不為空),所以不會中斷程序。
- 如果鍵盤輸入為空格,就跳轉到spaceProc,否則再加別的代碼。
- 當然,我們可以利用這個做很多事情,不只是判斷空格。
這樣,利用int 16h中斷中0號功能和1號功能的聯動,我們實現了在只支持單線程的DOS中,實現了偽多線程的輸入判斷。