在汇编中制作乒乓球游戏,如何一次输入多个击键?
Making a pong game in assembly, how do I get an input of multiple keystrokes at once?
我是初学者,所以这段代码可能没什么用,我用 int 16h
来做这个,但我对这个 int
了解不多。我刚刚发现你不能同时进行多次击键;有帮助吗?
这段代码的问题是一次只能移动一个板,我需要两个。如何检查多个输入?
这是供任何人使用的代码:
IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
; Your variables here
; --------------------------
line1X dw 80
line1Y dw 120
line1start dw 5
line1end dw 10
line2X dw 80
line2Y dw 120
line2start dw 310
line2end dw 315
CODESEG
proc startVideo ;creates video mode
mov al,13h
mov ah,0h
int 10h
ret
endp startVideo
proc clearScrean ;turns the screen black
mov ah, 0ch
xor al,al
mov dx,200
BlankLine:
mov cx,320
BlankColumn:
int 10h
Loop BlankColumn
dec dx
cmp dx,0
jne BlankLine
ret
endp clearScrean
proc drawboard ;creates the board
push bp
mov bp,sp
mov al,0fh
mov ah,0ch
beginning equ [bp+10]
fn equ [bp+8]
X equ [bp+6] ;boards start
Y equ [bp+4] ;boards end
mov dx,Y
drawrow:
mov cx,fn
drawcolumn:
int 10h
dec cx
cmp cx,beginning
jne drawcolumn
dec dx
cmp dx,X
jne drawrow
pop bp
ret 8
endp drawboard
proc drawall
push [line1start]
push [line1end]
push [line1X]
push [line1Y]
call drawboard
push [line2start]
push [line2end]
push [line2X]
push [line2Y]
call drawboard
ret
endp drawall
proc boardup
push bp
mov bp,sp
mov bx,[bp+4]
mov si,[bp+6]
cmp [word ptr bx],0 ;checks if board didnt get to border
je fn1
call clearScrean
sub [word ptr bx],5 ;3 pixels added to board
sub [word ptr si],5
call drawall ;prints both boards
fn1:
pop bp
ret 4
endp boardup
proc boarddown
push bp
mov bp,sp
mov bx,[bp+4]
mov si,[bp+6]
cmp [word ptr si],200 ;checks if board didnt get to border
je fn2
call clearScrean
add [word ptr bx],5 ;3 pixels added to board
add [word ptr si],5
call drawall ;prints both boards
fn2:
pop bp
ret 4
endp boarddown
start:
mov ax, @data
mov ds, ax
mov bh,0
call startVideo
call clearScrean
call drawall
checkskey: ;checks if key is being pressed
mov ah,1
int 16h
jz checkskey ;jumps if key isnt pressed
mov ah,0 ;checks which key is pressed
int 16h
cmp ah,11h ;if key pressed is w jump to upboard
je upboard1
cmp ah,01fh ;if key pressed is s jump to downboard
je downboard1
cmp ah,050h
je downboard2
cmp ah,048h
je upboard2
jmp checkskey ;if key isnt pressed jump to check key
upboard1: ;board 1 goes up
push offset line1Y
push offset line1X
call boardup
jmp checkskey
downboard1: ;board 1 goes down
push offset line1Y
push offset line1X
call boarddown
jmp checkskey
downboard2:
push offset line2Y
push offset line2X
call boarddown
jmp checkskey
upboard2:
push offset line2Y
push offset line2X
call boardup
jmp checkskey
exit:
mov ax, 4c00h
int 21h
END start
the problem with this code is that only one board can move at a time and i need both
同步感来自于快速,真正的快速。您计算机中的大多数东西都是串行工作的,但我们认为很多事情是并行发生的。
您的 checkskey 代码没问题。一块板使用 q 和 s 键,另一块板使用 up 和 向下键。
一旦某个键可用,键盘 BIOS 功能 00h 将立即检索它,您的程序将相应地更新图形。但是如果你的图形输出程序花的时间太长,那么玩家就会开始认为键盘呆滞了。
查看您的图形例程,我看到您使用视频 BIOS 功能 0Ch 将像素放在屏幕上。这很慢而且特别痛苦,因为你在最简单的图形屏幕上玩,你可以 MOV
一个字节来绘制一个像素。
在需要快速图形的程序中,将 ES
段寄存器永久指向视频缓冲区可能非常有利。
mov ax, 0A000h
mov es, ax
cld ; Because of the use of STOSB
这就是清除屏幕所需的全部:
ClearScreen:
xor di, di
mov cx, 64000
mov al, 0
rep stosb
ret
这是画水平线 (160,100)-(200,100) 的方法:
mov dl, 15 ; BrightWhite
mov cx, 51 ; 51 pixels from 160 to 200
mov bx, 160 ; X
mov ax, 100 ; Y
call DrawLine
...
DrawLine:
push dx
mov di, 320 ; BytesPerScanline
mul di
add ax, bx
mov di, ax ; Address DI = (Y * BPS) + X
pop ax ; Color AL
rep stosb
ret
另一个答案涉及多人游戏,其中 none 的玩家不断按下他们的专用键,从而占用键盘。尽管这种情况非常合理,但您可能希望让玩家按住按键的时间更长。为此,我们可以用我们自己的处理程序替换 BIOS/DOS 提供的键盘处理程序。
键盘上的每个键都关联一个唯一的 8 位数字,我们称之为扫描码。
每当按下一个键时,键盘都会在端口 60h 上提供相关键的扫描码。键盘也产生一个中断 09h。这个中断的处理程序可以检查扫描码并以任何它喜欢的方式处理它。这就是下面的演示程序所做的。
当按下一个键时,扫描码是一个最高位关闭的字节。当一个键被释放时,扫描码是一个字节,其最高位为开。其他 7 位在按下和释放时保持不变。
应该注意的是,虽然对于您的 乒乓球 游戏来说很好,但包含的替换处理程序是一个简约的处理程序。复杂的处理程序还会考虑以 E0h 或 E1h 代码为前缀的扩展扫描码。
该程序有额外的注释,因此您可以轻松了解正在发生的事情。该代码使用 FASM 语法。演示在真实DOS环境和DOSBox(0.74)下运行正常
; Multi-player Keyboard Input (c) 2021 Sep Roland
ORG 256 ; Output will be a .COM program
mov ax, 3509h ; DOS.GetInterruptVector
int 21h ; -> ES:BX
push es bx ; (1)
mov dx, Int09
mov ax, 2509h ; DOS.SetInterruptVector
int 21h
mov ax, 0013h ; BIOS.SetVideoMode 320x200 (256 colors)
int 10h
mov ax, 0A000h ; Video buffer
mov es, ax
cld ; So we can use the string primitive STOSB
Cont:
mov si, 160 ; Width
mov di, 100 ; Height
mov al, 0 ; Black
cmp [KeyList+48h], al ; Up
je .a
mov al, 2 ; Green
.a: mov cx, 160 ; X
mov dx, 0 ; Y
call Paint
mov al, 0 ; Black
cmp [KeyList+50h], al ; Down
je .b
mov al, 14 ; Yellow
.b: mov cx, 160 ; X
mov dx, 100 ; Y
call Paint
mov al, 0 ; Black
cmp [KeyList+11h], al ; aZerty / qWerty
je .c
mov al, 4 ; Red
.c: mov cx, 0 ; X
mov dx, 0 ; Y
call Paint
mov al, 0 ; Black
cmp [KeyList+1Fh], al ; S
je .d
mov al, 1 ; Blue
.d: mov cx, 0 ; X
mov dx, 100 ; Y
call Paint
cmp byte [KeyList+1], 0 ; ESC
je Cont
pop dx ds ; (1)
mov ax, 2509h ; DOS.SetInterruptVector
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
; --------------------------------------
Int09:
push ax bx
in al, 60h
mov ah, 0
mov bx, ax
and bx, 127 ; 7-bit scancode goes to BX
shl ax, 1 ; 1-bit press/release goes to AH
xor ah, 1 ; -> AH=1 Press, AH=0 Release
mov [cs:KeyList+bx], ah
mov al, 20h ; The non specific EOI (End Of Interrupt)
out 20h, al
pop bx ax
iret
; --------------------------------------
; IN (al,cx,dx,si,di)
Paint:
push cx dx di ; AL=Color CX=X DX=Y SI=Width DI=Height
push ax ; (1)
mov ax, 320 ; BytesPerScanline
mul dx
add ax, cx ; (Y * BPS) + X
mov dx, di
mov di, ax
pop ax ; (1)
.a: mov cx, si
rep stosb
sub di, si
add di, 320
dec dx
jnz .a
pop di dx cx
ret
; --------------------------------------
KeyList db 128 dup 0
KeyList db 128 dup 0
程序的KeyList记录了键盘上所有按键的当前状态。如果字节为 0,则表示未按下该键。如果字节为 1,则当前正在按下该键。
我把 Sep Roland 的精彩回答翻译成了 tasm
:
; filename: dots.asm
; Controls:
;
; Up/Down Arrows - Move Purple Dot
; W/S Keys - Move Cyan Dot
; Esc - Exit
IDEAL
MODEL small
STACK 100h
DATASEG
; postion of cyan dot
xCyanDot dw 107
yCyanDot dw 100
; position of purple dot
xPurpleDot dw 214
yPurpleDot dw 100
; keyboard scan codes we'll need
KeyEsc equ 01h
KeyW equ 11h
KeyS equ 1Fh
UpArrow equ 48h
DownArrow equ 50h
proc onKeyEvent ; custom handler for int 09h
push ax bx
in al, 60h
mov ah, 0
mov bx, ax
and bx, 127 ; 7-bit scancode goes to BX
shl ax, 1 ; 1-bit pressed/released goes to AH
xor ah, 1 ; -> AH=1 Pressed, AH=0 Released
mov [cs:KeyList+bx], ah
mov al, 20h ; The non specific EOI (End Of Interrupt)
out 20h, al
pop bx ax
iret
endp
CODESEG
proc sleepSomeTime
mov cx, 0
mov dx, 50000 ; 50ms
mov ah, 86h
int 15h ; param is cx:dx (in microseconds)
ret
endp
proc drawPurpleDot
mov al, 5
mov cx, [xPurpleDot]
mov dx, [yPurpleDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
proc coverPurpleDot
mov al, 0
mov cx, [xPurpleDot]
mov dx, [yPurpleDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
proc drawCyanDot
mov al, 3
mov cx, [xCyanDot]
mov dx, [yCyanDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
proc coverCyanDot
mov al, 0
mov cx, [xCyanDot]
mov dx, [yCyanDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
KeyList db 128 dup (0)
proc if_Up_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + UpArrow], 1
jne handleUp_end
call coverPurpleDot
mov ax, [yPurpleDot]
dec ax
mov [yPurpleDot], ax
call drawPurpleDot
handleUp_end:
ret
endp
proc if_Down_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + DownArrow], 1
jne handleDown_end
call coverPurpleDot
mov ax, [yPurpleDot]
inc ax
mov [yPurpleDot], ax
call drawPurpleDot
handleDown_end:
ret
endp
proc if_W_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + KeyW], 1
jne handleW_end
call coverCyanDot
mov ax, [yCyanDot]
dec ax
mov [yCyanDot], ax
call drawCyanDot
handleW_end:
ret
endp
proc if_S_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + KeyS], 1
jne handleS_end
call coverCyanDot
mov ax, [yCyanDot]
inc ax
mov [yCyanDot], ax
call drawCyanDot
handleS_end:
ret
endp
proc main
call drawPurpleDot
call drawCyanDot
mainLoop:
call sleepSomeTime
call if_Up_isPressedMoveDot
call if_Down_isPressedMoveDot
call if_W_isPressedMoveDot
call if_S_isPressedMoveDot
; if Esc is not pressed, jump back to mainLoop
mov bx, offset KeyList
cmp [byte bx + KeyEsc], 1
jne mainLoop
ret
endp
start:
mov ax, @data
mov ds, ax
; enter graphic mode
mov ax, 13h
int 10h
; get the address of the existing int09h handler
mov ax, 3509h ; Get Interrupt Vector
int 21h ; -> ES:BX
push es bx
; replace the existing int09h handler with ours
mov dx, offset onKeyEvent
mov ax, 2509h
int 21h
call main
; return to text mode
mov ah, 0
mov al, 2
int 10h
; restore the original int09h handler
pop dx ds
mov ax, 2509h
int 21h
exit:
mov ax, 4c00h
int 21h
end start
编译 & 运行:
tasm /zi dots.asm
tlink /v dots.obj
dots
奖励部分 - 以下是 int 09h 使用的键盘扫描码:
01h Esc 31h N
02h 1 ! 32h M
03h 2 @ 33h , 63h F16
04h 3 # 34h . 64h F17
05h 4 $ 35h / ? 65h F18
06h 5 % 36h RightShift 66h F19
07h 6 ^ 37h Grey* 67h F20
08h 7 & 38h Alt 68h F21
09h 8 * 39h SpaceBar 69h F22
0Ah 9 ( 3Ah CapsLock 6Ah F23
0Bh 0 ) 3Bh F1 6Bh F24
0Ch - _ 3Ch F2
0Dh = + 3Dh F3 6Dh EraseEOF
0Eh Backspace 3Eh F4
0Fh Tab 3Fh F5 6Fh Copy/Play
10h Q 40h F6
11h W 41h F7
12h E 42h F8 72h CrSel
13h R 43h F9
14h T 44h F10 74h ExSel
15h Y 45h NumLock
16h U 46h ScrollLock 76h Clear
17h I 47h Home
18h O 48h UpArrow
19h P 49h PgUp
1Ah [ { 4Ah Grey-
1Bh ] } 4Bh LeftArrow
1Ch Enter 4Ch Keypad 5
1Dh Ctrl 4Dh RightArrow
1Eh A 4Eh Grey+
1Fh S 4Fh End
20h D 50h DownArrow
21h F 51h PgDn
22h G 52h Ins
23h H 53h Del
24h J 54h SysReq
25h K
26h L 56h left | (102-key)
27h ; : 57h F11
28h ' " 58h F12 AAh self-test complete
29h ` ~ E0h prefix code
2Ah LeftShift 5Ah PA1 E1h prefix code
2Bh \ | 5Bh F13 EEh ECHO
2Ch Z 5Ch F14 F0h prefix code (key break)
2Dh X 5Dh F15 FAh ACK
2Eh C FDh diagnostic failure
2Fh V FEh RESEND
30h B FFh kbd error/buffer full
source: http://muruganad.com/8086/8086-Interrupt-List.html
我是初学者,所以这段代码可能没什么用,我用 int 16h
来做这个,但我对这个 int
了解不多。我刚刚发现你不能同时进行多次击键;有帮助吗?
这段代码的问题是一次只能移动一个板,我需要两个。如何检查多个输入?
这是供任何人使用的代码:
IDEAL MODEL small STACK 100h DATASEG ; -------------------------- ; Your variables here ; -------------------------- line1X dw 80 line1Y dw 120 line1start dw 5 line1end dw 10 line2X dw 80 line2Y dw 120 line2start dw 310 line2end dw 315 CODESEG proc startVideo ;creates video mode mov al,13h mov ah,0h int 10h ret endp startVideo proc clearScrean ;turns the screen black mov ah, 0ch xor al,al mov dx,200 BlankLine: mov cx,320 BlankColumn: int 10h Loop BlankColumn dec dx cmp dx,0 jne BlankLine ret endp clearScrean proc drawboard ;creates the board push bp mov bp,sp mov al,0fh mov ah,0ch beginning equ [bp+10] fn equ [bp+8] X equ [bp+6] ;boards start Y equ [bp+4] ;boards end mov dx,Y drawrow: mov cx,fn drawcolumn: int 10h dec cx cmp cx,beginning jne drawcolumn dec dx cmp dx,X jne drawrow pop bp ret 8 endp drawboard proc drawall push [line1start] push [line1end] push [line1X] push [line1Y] call drawboard push [line2start] push [line2end] push [line2X] push [line2Y] call drawboard ret endp drawall proc boardup push bp mov bp,sp mov bx,[bp+4] mov si,[bp+6] cmp [word ptr bx],0 ;checks if board didnt get to border je fn1 call clearScrean sub [word ptr bx],5 ;3 pixels added to board sub [word ptr si],5 call drawall ;prints both boards fn1: pop bp ret 4 endp boardup proc boarddown push bp mov bp,sp mov bx,[bp+4] mov si,[bp+6] cmp [word ptr si],200 ;checks if board didnt get to border je fn2 call clearScrean add [word ptr bx],5 ;3 pixels added to board add [word ptr si],5 call drawall ;prints both boards fn2: pop bp ret 4 endp boarddown start: mov ax, @data mov ds, ax mov bh,0 call startVideo call clearScrean call drawall checkskey: ;checks if key is being pressed mov ah,1 int 16h jz checkskey ;jumps if key isnt pressed mov ah,0 ;checks which key is pressed int 16h cmp ah,11h ;if key pressed is w jump to upboard je upboard1 cmp ah,01fh ;if key pressed is s jump to downboard je downboard1 cmp ah,050h je downboard2 cmp ah,048h je upboard2 jmp checkskey ;if key isnt pressed jump to check key upboard1: ;board 1 goes up push offset line1Y push offset line1X call boardup jmp checkskey downboard1: ;board 1 goes down push offset line1Y push offset line1X call boarddown jmp checkskey downboard2: push offset line2Y push offset line2X call boarddown jmp checkskey upboard2: push offset line2Y push offset line2X call boardup jmp checkskey exit: mov ax, 4c00h int 21h END start
the problem with this code is that only one board can move at a time and i need both
同步感来自于快速,真正的快速。您计算机中的大多数东西都是串行工作的,但我们认为很多事情是并行发生的。
您的 checkskey 代码没问题。一块板使用 q 和 s 键,另一块板使用 up 和 向下键。
一旦某个键可用,键盘 BIOS 功能 00h 将立即检索它,您的程序将相应地更新图形。但是如果你的图形输出程序花的时间太长,那么玩家就会开始认为键盘呆滞了。
查看您的图形例程,我看到您使用视频 BIOS 功能 0Ch 将像素放在屏幕上。这很慢而且特别痛苦,因为你在最简单的图形屏幕上玩,你可以 MOV
一个字节来绘制一个像素。
在需要快速图形的程序中,将 ES
段寄存器永久指向视频缓冲区可能非常有利。
mov ax, 0A000h
mov es, ax
cld ; Because of the use of STOSB
这就是清除屏幕所需的全部:
ClearScreen:
xor di, di
mov cx, 64000
mov al, 0
rep stosb
ret
这是画水平线 (160,100)-(200,100) 的方法:
mov dl, 15 ; BrightWhite
mov cx, 51 ; 51 pixels from 160 to 200
mov bx, 160 ; X
mov ax, 100 ; Y
call DrawLine
...
DrawLine:
push dx
mov di, 320 ; BytesPerScanline
mul di
add ax, bx
mov di, ax ; Address DI = (Y * BPS) + X
pop ax ; Color AL
rep stosb
ret
另一个答案涉及多人游戏,其中 none 的玩家不断按下他们的专用键,从而占用键盘。尽管这种情况非常合理,但您可能希望让玩家按住按键的时间更长。为此,我们可以用我们自己的处理程序替换 BIOS/DOS 提供的键盘处理程序。
键盘上的每个键都关联一个唯一的 8 位数字,我们称之为扫描码。
每当按下一个键时,键盘都会在端口 60h 上提供相关键的扫描码。键盘也产生一个中断 09h。这个中断的处理程序可以检查扫描码并以任何它喜欢的方式处理它。这就是下面的演示程序所做的。
当按下一个键时,扫描码是一个最高位关闭的字节。当一个键被释放时,扫描码是一个字节,其最高位为开。其他 7 位在按下和释放时保持不变。
应该注意的是,虽然对于您的 乒乓球 游戏来说很好,但包含的替换处理程序是一个简约的处理程序。复杂的处理程序还会考虑以 E0h 或 E1h 代码为前缀的扩展扫描码。
该程序有额外的注释,因此您可以轻松了解正在发生的事情。该代码使用 FASM 语法。演示在真实DOS环境和DOSBox(0.74)下运行正常
; Multi-player Keyboard Input (c) 2021 Sep Roland
ORG 256 ; Output will be a .COM program
mov ax, 3509h ; DOS.GetInterruptVector
int 21h ; -> ES:BX
push es bx ; (1)
mov dx, Int09
mov ax, 2509h ; DOS.SetInterruptVector
int 21h
mov ax, 0013h ; BIOS.SetVideoMode 320x200 (256 colors)
int 10h
mov ax, 0A000h ; Video buffer
mov es, ax
cld ; So we can use the string primitive STOSB
Cont:
mov si, 160 ; Width
mov di, 100 ; Height
mov al, 0 ; Black
cmp [KeyList+48h], al ; Up
je .a
mov al, 2 ; Green
.a: mov cx, 160 ; X
mov dx, 0 ; Y
call Paint
mov al, 0 ; Black
cmp [KeyList+50h], al ; Down
je .b
mov al, 14 ; Yellow
.b: mov cx, 160 ; X
mov dx, 100 ; Y
call Paint
mov al, 0 ; Black
cmp [KeyList+11h], al ; aZerty / qWerty
je .c
mov al, 4 ; Red
.c: mov cx, 0 ; X
mov dx, 0 ; Y
call Paint
mov al, 0 ; Black
cmp [KeyList+1Fh], al ; S
je .d
mov al, 1 ; Blue
.d: mov cx, 0 ; X
mov dx, 100 ; Y
call Paint
cmp byte [KeyList+1], 0 ; ESC
je Cont
pop dx ds ; (1)
mov ax, 2509h ; DOS.SetInterruptVector
int 21h
mov ax, 4C00h ; DOS.Terminate
int 21h
; --------------------------------------
Int09:
push ax bx
in al, 60h
mov ah, 0
mov bx, ax
and bx, 127 ; 7-bit scancode goes to BX
shl ax, 1 ; 1-bit press/release goes to AH
xor ah, 1 ; -> AH=1 Press, AH=0 Release
mov [cs:KeyList+bx], ah
mov al, 20h ; The non specific EOI (End Of Interrupt)
out 20h, al
pop bx ax
iret
; --------------------------------------
; IN (al,cx,dx,si,di)
Paint:
push cx dx di ; AL=Color CX=X DX=Y SI=Width DI=Height
push ax ; (1)
mov ax, 320 ; BytesPerScanline
mul dx
add ax, cx ; (Y * BPS) + X
mov dx, di
mov di, ax
pop ax ; (1)
.a: mov cx, si
rep stosb
sub di, si
add di, 320
dec dx
jnz .a
pop di dx cx
ret
; --------------------------------------
KeyList db 128 dup 0
KeyList db 128 dup 0
程序的KeyList记录了键盘上所有按键的当前状态。如果字节为 0,则表示未按下该键。如果字节为 1,则当前正在按下该键。
我把 Sep Roland 的精彩回答翻译成了 tasm
:
; filename: dots.asm
; Controls:
;
; Up/Down Arrows - Move Purple Dot
; W/S Keys - Move Cyan Dot
; Esc - Exit
IDEAL
MODEL small
STACK 100h
DATASEG
; postion of cyan dot
xCyanDot dw 107
yCyanDot dw 100
; position of purple dot
xPurpleDot dw 214
yPurpleDot dw 100
; keyboard scan codes we'll need
KeyEsc equ 01h
KeyW equ 11h
KeyS equ 1Fh
UpArrow equ 48h
DownArrow equ 50h
proc onKeyEvent ; custom handler for int 09h
push ax bx
in al, 60h
mov ah, 0
mov bx, ax
and bx, 127 ; 7-bit scancode goes to BX
shl ax, 1 ; 1-bit pressed/released goes to AH
xor ah, 1 ; -> AH=1 Pressed, AH=0 Released
mov [cs:KeyList+bx], ah
mov al, 20h ; The non specific EOI (End Of Interrupt)
out 20h, al
pop bx ax
iret
endp
CODESEG
proc sleepSomeTime
mov cx, 0
mov dx, 50000 ; 50ms
mov ah, 86h
int 15h ; param is cx:dx (in microseconds)
ret
endp
proc drawPurpleDot
mov al, 5
mov cx, [xPurpleDot]
mov dx, [yPurpleDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
proc coverPurpleDot
mov al, 0
mov cx, [xPurpleDot]
mov dx, [yPurpleDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
proc drawCyanDot
mov al, 3
mov cx, [xCyanDot]
mov dx, [yCyanDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
proc coverCyanDot
mov al, 0
mov cx, [xCyanDot]
mov dx, [yCyanDot]
mov bh, 0h
mov ah, 0ch
int 10h
ret
endp
KeyList db 128 dup (0)
proc if_Up_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + UpArrow], 1
jne handleUp_end
call coverPurpleDot
mov ax, [yPurpleDot]
dec ax
mov [yPurpleDot], ax
call drawPurpleDot
handleUp_end:
ret
endp
proc if_Down_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + DownArrow], 1
jne handleDown_end
call coverPurpleDot
mov ax, [yPurpleDot]
inc ax
mov [yPurpleDot], ax
call drawPurpleDot
handleDown_end:
ret
endp
proc if_W_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + KeyW], 1
jne handleW_end
call coverCyanDot
mov ax, [yCyanDot]
dec ax
mov [yCyanDot], ax
call drawCyanDot
handleW_end:
ret
endp
proc if_S_isPressedMoveDot
mov bx, offset KeyList
cmp [byte bx + KeyS], 1
jne handleS_end
call coverCyanDot
mov ax, [yCyanDot]
inc ax
mov [yCyanDot], ax
call drawCyanDot
handleS_end:
ret
endp
proc main
call drawPurpleDot
call drawCyanDot
mainLoop:
call sleepSomeTime
call if_Up_isPressedMoveDot
call if_Down_isPressedMoveDot
call if_W_isPressedMoveDot
call if_S_isPressedMoveDot
; if Esc is not pressed, jump back to mainLoop
mov bx, offset KeyList
cmp [byte bx + KeyEsc], 1
jne mainLoop
ret
endp
start:
mov ax, @data
mov ds, ax
; enter graphic mode
mov ax, 13h
int 10h
; get the address of the existing int09h handler
mov ax, 3509h ; Get Interrupt Vector
int 21h ; -> ES:BX
push es bx
; replace the existing int09h handler with ours
mov dx, offset onKeyEvent
mov ax, 2509h
int 21h
call main
; return to text mode
mov ah, 0
mov al, 2
int 10h
; restore the original int09h handler
pop dx ds
mov ax, 2509h
int 21h
exit:
mov ax, 4c00h
int 21h
end start
编译 & 运行:
tasm /zi dots.asm
tlink /v dots.obj
dots
奖励部分 - 以下是 int 09h 使用的键盘扫描码:
01h Esc 31h N
02h 1 ! 32h M
03h 2 @ 33h , 63h F16
04h 3 # 34h . 64h F17
05h 4 $ 35h / ? 65h F18
06h 5 % 36h RightShift 66h F19
07h 6 ^ 37h Grey* 67h F20
08h 7 & 38h Alt 68h F21
09h 8 * 39h SpaceBar 69h F22
0Ah 9 ( 3Ah CapsLock 6Ah F23
0Bh 0 ) 3Bh F1 6Bh F24
0Ch - _ 3Ch F2
0Dh = + 3Dh F3 6Dh EraseEOF
0Eh Backspace 3Eh F4
0Fh Tab 3Fh F5 6Fh Copy/Play
10h Q 40h F6
11h W 41h F7
12h E 42h F8 72h CrSel
13h R 43h F9
14h T 44h F10 74h ExSel
15h Y 45h NumLock
16h U 46h ScrollLock 76h Clear
17h I 47h Home
18h O 48h UpArrow
19h P 49h PgUp
1Ah [ { 4Ah Grey-
1Bh ] } 4Bh LeftArrow
1Ch Enter 4Ch Keypad 5
1Dh Ctrl 4Dh RightArrow
1Eh A 4Eh Grey+
1Fh S 4Fh End
20h D 50h DownArrow
21h F 51h PgDn
22h G 52h Ins
23h H 53h Del
24h J 54h SysReq
25h K
26h L 56h left | (102-key)
27h ; : 57h F11
28h ' " 58h F12 AAh self-test complete
29h ` ~ E0h prefix code
2Ah LeftShift 5Ah PA1 E1h prefix code
2Bh \ | 5Bh F13 EEh ECHO
2Ch Z 5Ch F14 F0h prefix code (key break)
2Dh X 5Dh F15 FAh ACK
2Eh C FDh diagnostic failure
2Fh V FEh RESEND
30h B FFh kbd error/buffer full
source: http://muruganad.com/8086/8086-Interrupt-List.html