assemblykeyboardx86-16emu8086pong

Making a pong game in assembly, how do I get an input of multiple keystrokes at once?


I'm a beginner so this code probably isn't any good, I used int 16h for this but I don't know a lot about this int. I just found out you can't have multiple keystrokes at once; any help?
The problem with this code is that only one board can move at a time and I need both. How do I check for multiple inputs?

Here's the code for anyone who wants it:

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

Solution

  • The other answer deals with a multi-player game where none of the players keep pushing their dedicated keys and thus hogging the keyboard. Although this scenario is quite reasonable, you might want to allow the players to hold their key down for a longer period. To this effect we can substitute the keyboard handler that BIOS/DOS provides by a handler of our own.

    With each key on the keyboard is associated a unique 8-bit number we call the scancode.
    Whenever a key is pressed the keyboard makes the scancode of the concerned key available at port 60h. The keyboard also generates an interrupt 09h. A handler for this interrupt can examine the scancode and process it in any way it likes. That's what the below demonstration program does.
    When a key is pressed the scancode is a byte with its highest bit off. When a key is released the scancode is a byte with its highest bit on. The other 7 bits remain the same for both presses and releases.

    It should be noted that, although fine for the purpose of your pong game, the included substitution handler is a minimalistic one. A sophisticated handler would also take into account the extended scancodes that are prefixed with an E0h or E1h code.

    The program has additional comments so you can easily understand what's happening. The code uses FASM syntax. The demo runs OK in the real DOS environment and in the 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
    

    The program's KeyList records the current state of all of the keys on the keyboard. If a byte is 0, the key is not being pressed. If a byte is 1, that key is currently being pressed.