如何忽略多个按键?

How do I ignore multiple keypresses?

我用汇编语言编写了一个 DOS 程序,当您按下 space 时,它会跳转方块。

如果在方块跳跃时按住space,即使停止按下space,它也会继续跳跃。我怎样才能让它只关注 space 当正方形在地面上时被按下?

代码(使用 TASM 编译):

IDEAL
MODEL small
STACK 100h
DATASEG

X dw 0
Y dw 0
SquareX dw 20
SquareY dw 193
SquareSize dw 0
color db 1  ; default color is blue
FloorY dw 194
FloorX dw 0




CODESEG



    proc HalfSecondDelay
    push cx ;Backup
    push dx
    push ax
    
    MOV CX, 1H
    MOV DX, 3H
    MOV AH, 86H
    INT 15H
    
    pop ax ;Backup
    pop dx
    pop cx
    ret
    endp HalfSecondDelay

    
    proc WaitForSpace
    EnterSpace:  ;Wait until user presses Space
    mov ah,0
    int 16h
    cmp al,32
    jne EnterSpace
    ret
    endp WaitForSpace


    proc PlayerJump ;Makes The Square Jump
    push cx
    
    
    mov cx, 10
    MoveUp:
    Call HalfSecondDelay
    
    call RemovePlayerSquare
    sub [SquareY],4 ; Move Up
    call PaintPlayerSquare
    loop MoveUp
    
    mov cx, 10
    MoveDown:
    Call HalfSecondDelay
    call RemovePlayerSquare
    add [SquareY], 4 ; Move Down
    Call PaintPlayerSquare
    loop MoveDown

    pop cx
    ret
    endp PlayerJump


proc PaintFloorLine
    push bp
    mov bp,sp
    push cx


    
    mov cx, 320
LoopPaintFloorLine:
    call PaintPixel
    
    inc [X]
    loop loopPaintFloorLine
    

    pop cx
    pop bp
    ret
endp PaintFloorLine

proc PaintFloor ;Paints The Floor
    push bp
    mov bp,sp
    push cx
    
    mov [x], 0
    mov [y], 194
    mov [color], 0Ah
    
    mov cx, 7
    
loopPaintFloor:     
    call PaintFloorLine
    inc [Y]
    mov [x], 0
    loop loopPaintFloor
    
    
    pop cx
    pop bp
    ret
endp PaintFloor
    

proc PaintPixel
    push bp
    mov bp,sp

    push ax
    push bx
    push cx
    push dx 
    

    mov cx,[X]
    mov dx,[Y]
    mov al,[color]
    mov ah,0ch
    int 10h
    
    pop dx
    pop cx
    pop bx
    pop ax
    pop bp
    ret
endp PaintPixel

proc PaintLine
    push bp
    mov bp,sp
    push cx
    
    mov cx, [SquareSize]
    
loopPaintLine:  
    call PaintPixel
    inc [X]
    loop loopPaintLine
    
    mov cx, [SquareSize] ; Return The X
    sub [X], cx
    
    pop cx
    pop bp
    ret
endp PaintLine

    
proc PaintSquare ;Paints A Sqaure
    push bp
    mov bp,sp
    push cx
    
    mov cx, [SquareSize]
    
loopPrinSquare:     
    call PaintLine
    dec [Y]
    loop loopPrinSquare
    
    mov cx, [SquareSize] ; Return The Y
    add [Y], cx
    
    pop cx
    pop bp
    ret
endp PaintSquare

proc PaintPlayerSquare ; Paints The Player Square
    push bp
    mov bp,sp
    
    mov ax, [SquareX]
    mov [x], ax
    
    mov ax, [SquareY]
    mov [Y], ax
    
    mov [SquareSize], 25
    mov  [color], 1 ; blue color
    call PaintSquare ;  
    
    pop bp
    ret 
endp PaintPlayerSquare

proc RemovePlayerSquare ;Removes The Player Square
    push bp
    mov bp,sp
    
    push ax
    push bx
    push cx
    push dx 
    
    mov ax, [SquareX]
    mov [x], ax
    
    mov ax, [SquareY]
    mov [Y], ax
    
    mov  [color], 0 ; black color
    call PaintSquare ;  
    
    pop dx
    pop cx
    pop bx
    pop ax
    
    pop bp
    ret 
endp RemovePlayerSquare

proc GraphicsScreen
    mov al, 13h
    mov ah, 0
    int 10h
    ret
endp GraphicsScreen



    
start:
    mov ax, @data
    mov ds, ax
    
    Call GraphicsScreen
    Call PaintFloor
    Call PaintPlayerSquare

    
    loopSquareJump:
    Call WaitForSpace
    Call PlayerJump
    jmp loopSquareJump

    

exit:
    mov ax, 4c00h
    int 21h
END start

您的问题来自 Space 按键,但您不希望它们保留在键盘缓冲区中,导致它们被稍后处理。一种解决方案是在等待按下 Space 之前清除键盘缓冲区,如下所示:

proc ClearKeyboardBuffer
ClearKeyboardBuffer_loop:
mov ah,01h
int 16h                     ; is there a key pressed
jz ClearKeyboardBuffer_ret  ; if not, return
mov ah,00h
int 16h                     ; "handle" the key
jmp ClearKeyboardBuffer_loop

ClearKeyboardBuffer_ret:
ret
endp ClearKeyboardBuffer

然后像这样简单地修改你的循环:

loopSquareJump:
Call ClearKeyboardBuffer
Call WaitForSpace
Call PlayerJump
jmp loopSquareJump

但是,这不是一个好方法。根据Stephen Kitt's answer on Retrocomputing:

If you’re using BIOS functions to read from the keyboard in your game, the quickest way to clear the buffer is to make its tail equal to its head: read the value at 0x0041A and write it to 0x0041C (with interrupts disabled):

proc clearkeyboardbuffer
; AX is clobbered
    push ds
    mov ax, 0040h
    mov ds, ax
    mov ax, [001Ah]
    mov [001Ch], ax
    pop ds
    ret
endp clearkeyboardbuffer

(The BIOS keyboard buffer is a circular list starting at 0x0041E, and 0x0041A points at the buffer’s head, and 0x0041C at its tail. If both pointers are equal, the buffer is empty.)

阅读更多内容 on the original answer,如果您有兴趣。